| Index: third_party/WebKit/WebCore/rendering/RenderContainer.cpp
|
| ===================================================================
|
| --- third_party/WebKit/WebCore/rendering/RenderContainer.cpp (revision 9118)
|
| +++ third_party/WebKit/WebCore/rendering/RenderContainer.cpp (working copy)
|
| @@ -96,7 +96,7 @@
|
| table->addChild(newChild);
|
| } else {
|
| // just add it...
|
| - insertChildNode(newChild, beforeChild);
|
| + children()->insertChildNode(this, newChild, beforeChild);
|
| }
|
|
|
| if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) {
|
| @@ -106,481 +106,15 @@
|
| }
|
| }
|
|
|
| -RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild, bool fullRemove)
|
| -{
|
| - ASSERT(oldChild->parent() == this);
|
| -
|
| - // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
|
| - // that a positioned child got yanked). We also repaint, so that the area exposed when the child
|
| - // disappears gets repainted properly.
|
| - if (!documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) {
|
| - oldChild->setNeedsLayoutAndPrefWidthsRecalc();
|
| - oldChild->repaint();
|
| - }
|
| -
|
| - // If we have a line box wrapper, delete it.
|
| - oldChild->deleteLineBoxWrapper();
|
| -
|
| - if (!documentBeingDestroyed() && fullRemove) {
|
| - // if we remove visible child from an invisible parent, we don't know the layer visibility any more
|
| - RenderLayer* layer = 0;
|
| - if (m_style->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) {
|
| - layer = enclosingLayer();
|
| - layer->dirtyVisibleContentStatus();
|
| - }
|
| -
|
| - // Keep our layer hierarchy updated.
|
| - if (oldChild->firstChild() || oldChild->hasLayer()) {
|
| - if (!layer) layer = enclosingLayer();
|
| - oldChild->removeLayers(layer);
|
| - }
|
| -
|
| - // renumber ordered lists
|
| - if (oldChild->isListItem())
|
| - updateListMarkerNumbers(oldChild->nextSibling());
|
| -
|
| - if (oldChild->isPositioned() && childrenInline())
|
| - dirtyLinesFromChangedChild(oldChild);
|
| - }
|
| -
|
| - // If oldChild is the start or end of the selection, then clear the selection to
|
| - // avoid problems of invalid pointers.
|
| - // FIXME: The SelectionController should be responsible for this when it
|
| - // is notified of DOM mutations.
|
| - if (!documentBeingDestroyed() && oldChild->isSelectionBorder())
|
| - view()->clearSelection();
|
| -
|
| - // remove the child
|
| - if (oldChild->previousSibling())
|
| - oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
|
| - if (oldChild->nextSibling())
|
| - oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
|
| -
|
| - if (children()->firstChild() == oldChild)
|
| - children()->setFirstChild(oldChild->nextSibling());
|
| - if (children()->lastChild() == oldChild)
|
| - children()->setLastChild(oldChild->previousSibling());
|
| -
|
| - oldChild->setPreviousSibling(0);
|
| - oldChild->setNextSibling(0);
|
| - oldChild->setParent(0);
|
| -
|
| - if (AXObjectCache::accessibilityEnabled())
|
| - document()->axObjectCache()->childrenChanged(this);
|
| -
|
| - return oldChild;
|
| -}
|
| -
|
| void RenderContainer::removeChild(RenderObject* oldChild)
|
| {
|
| // We do this here instead of in removeChildNode, since the only extremely low-level uses of remove/appendChildNode
|
| // cannot affect the positioned object list, and the floating object list is irrelevant (since the list gets cleared on
|
| // layout anyway).
|
| oldChild->removeFromObjectLists();
|
| -
|
| - removeChildNode(oldChild);
|
| + m_children.removeChildNode(this, oldChild);
|
| }
|
|
|
| -RenderObject* RenderContainer::beforeAfterContainer(RenderStyle::PseudoId type)
|
| -{
|
| - if (type == RenderStyle::BEFORE) {
|
| - RenderObject* first = this;
|
| - do {
|
| - // Skip list markers.
|
| - first = first->firstChild();
|
| - while (first && first->isListMarker())
|
| - first = first->nextSibling();
|
| - } while (first && first->isAnonymous() && first->style()->styleType() == RenderStyle::NOPSEUDO);
|
| - if (first && first->style()->styleType() != type)
|
| - return 0;
|
| - return first;
|
| - }
|
| - if (type == RenderStyle::AFTER) {
|
| - RenderObject* last = this;
|
| - do {
|
| - last = last->lastChild();
|
| - } while (last && last->isAnonymous() && last->style()->styleType() == RenderStyle::NOPSEUDO && !last->isListMarker());
|
| - if (last && last->style()->styleType() != type)
|
| - return 0;
|
| - return last;
|
| - }
|
| -
|
| - ASSERT_NOT_REACHED();
|
| - return 0;
|
| -}
|
| -
|
| -void RenderContainer::updateBeforeAfterContent(RenderStyle::PseudoId type)
|
| -{
|
| - // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
|
| - if (parent() && parent()->createsAnonymousWrapper())
|
| - return;
|
| - updateBeforeAfterContentForContainer(type, this);
|
| -}
|
| -
|
| -static RenderObject* findBeforeAfterParent(RenderObject* object)
|
| -{
|
| - // Only table parts need to search for the :before or :after parent
|
| - if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
|
| - return object;
|
| -
|
| - RenderObject* beforeAfterParent = object;
|
| - while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage()))
|
| - beforeAfterParent = beforeAfterParent->firstChild();
|
| - return beforeAfterParent;
|
| -}
|
| -
|
| -void RenderContainer::updateBeforeAfterContentForContainer(RenderStyle::PseudoId type, RenderContainer* styledObject)
|
| -{
|
| - // Double check that the document did in fact use generated content rules. Otherwise we should not have been called.
|
| - ASSERT(document()->usesBeforeAfterRules());
|
| -
|
| - // In CSS2, before/after pseudo-content cannot nest. Check this first.
|
| - if (style()->styleType() == RenderStyle::BEFORE || style()->styleType() == RenderStyle::AFTER)
|
| - return;
|
| -
|
| - RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
|
| - RenderObject* child = beforeAfterContainer(type);
|
| -
|
| - // Whether or not we currently have generated content attached.
|
| - bool oldContentPresent = child;
|
| -
|
| - // Whether or not we now want generated content.
|
| - bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
|
| -
|
| - // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
|
| - // :after content and not :before content.
|
| - if (newContentWanted && type == RenderStyle::BEFORE && isRenderInline() && toRenderInline(this)->isInlineContinuation())
|
| - newContentWanted = false;
|
| -
|
| - // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
|
| - // then we don't generate the :after content.
|
| - if (newContentWanted && type == RenderStyle::AFTER && isRenderInline() && toRenderInline(this)->continuation())
|
| - newContentWanted = false;
|
| -
|
| - // If we don't want generated content any longer, or if we have generated content, but it's no longer
|
| - // identical to the new content data we want to build render objects for, then we nuke all
|
| - // of the old generated content.
|
| - if (!newContentWanted || (oldContentPresent && Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) {
|
| - // Nuke the child.
|
| - if (child && child->style()->styleType() == type) {
|
| - oldContentPresent = false;
|
| - child->destroy();
|
| - child = (type == RenderStyle::BEFORE) ? children()->firstChild() : children()->lastChild();
|
| - }
|
| - }
|
| -
|
| - // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
|
| - // have no generated content and can now return.
|
| - if (!newContentWanted)
|
| - return;
|
| -
|
| - if (isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE &&
|
| - !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
|
| - // According to the CSS2 spec (the end of section 12.1), the only allowed
|
| - // display values for the pseudo style are NONE and INLINE for inline flows.
|
| - // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
|
| - // For now we at least relax the restriction to allow all inline types like inline-block
|
| - // and inline-table.
|
| - pseudoElementStyle->setDisplay(INLINE);
|
| -
|
| - if (oldContentPresent) {
|
| - if (child && child->style()->styleType() == type) {
|
| - // We have generated content present still. We want to walk this content and update our
|
| - // style information with the new pseudo-element style.
|
| - child->setStyle(pseudoElementStyle);
|
| -
|
| - RenderObject* beforeAfterParent = findBeforeAfterParent(child);
|
| - if (!beforeAfterParent)
|
| - return;
|
| -
|
| - // Note that if we ever support additional types of generated content (which should be way off
|
| - // in the future), this code will need to be patched.
|
| - for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
|
| - if (genChild->isText())
|
| - // Generated text content is a child whose style also needs to be set to the pseudo-element style.
|
| - genChild->setStyle(pseudoElementStyle);
|
| - else if (genChild->isImage()) {
|
| - // Images get an empty style that inherits from the pseudo.
|
| - RefPtr<RenderStyle> style = RenderStyle::create();
|
| - style->inheritFrom(pseudoElementStyle);
|
| - genChild->setStyle(style.release());
|
| - } else
|
| - // Must be a first-letter container. updateFirstLetter() will take care of it.
|
| - ASSERT(genChild->style()->styleType() == RenderStyle::FIRST_LETTER);
|
| - }
|
| - }
|
| - return; // We've updated the generated content. That's all we needed to do.
|
| - }
|
| -
|
| - RenderObject* insertBefore = (type == RenderStyle::BEFORE) ? children()->firstChild() : 0;
|
| -
|
| - // Generated content consists of a single container that houses multiple children (specified
|
| - // by the content property). This generated content container gets the pseudo-element style set on it.
|
| - RenderObject* generatedContentContainer = 0;
|
| -
|
| - // Walk our list of generated content and create render objects for each.
|
| - for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->m_next) {
|
| - RenderObject* renderer = 0;
|
| - switch (content->m_type) {
|
| - case CONTENT_NONE:
|
| - break;
|
| - case CONTENT_TEXT:
|
| - renderer = new (renderArena()) RenderTextFragment(document() /* anonymous object */, content->m_content.m_text);
|
| - renderer->setStyle(pseudoElementStyle);
|
| - break;
|
| - case CONTENT_OBJECT: {
|
| - RenderImageGeneratedContent* image = new (renderArena()) RenderImageGeneratedContent(document()); // anonymous object
|
| - RefPtr<RenderStyle> style = RenderStyle::create();
|
| - style->inheritFrom(pseudoElementStyle);
|
| - image->setStyle(style.release());
|
| - if (StyleImage* styleImage = content->m_content.m_image)
|
| - image->setStyleImage(styleImage);
|
| - renderer = image;
|
| - break;
|
| - }
|
| - case CONTENT_COUNTER:
|
| - renderer = new (renderArena()) RenderCounter(document(), *content->m_content.m_counter);
|
| - renderer->setStyle(pseudoElementStyle);
|
| - break;
|
| - }
|
| -
|
| - if (renderer) {
|
| - if (!generatedContentContainer) {
|
| - // Make a generated box that might be any display type now that we are able to drill down into children
|
| - // to find the original content properly.
|
| - generatedContentContainer = RenderObject::createObject(document(), pseudoElementStyle);
|
| - generatedContentContainer->setStyle(pseudoElementStyle);
|
| - addChild(generatedContentContainer, insertBefore);
|
| - }
|
| - generatedContentContainer->addChild(renderer);
|
| - }
|
| - }
|
| -}
|
| -
|
| -bool RenderContainer::isAfterContent(RenderObject* child) const
|
| -{
|
| - if (!child)
|
| - return false;
|
| - if (child->style()->styleType() != RenderStyle::AFTER)
|
| - return false;
|
| - // Text nodes don't have their own styles, so ignore the style on a text node.
|
| - if (child->isText() && !child->isBR())
|
| - return false;
|
| - return true;
|
| -}
|
| -
|
| -static void invalidateCountersInContainer(RenderObject* container)
|
| -{
|
| - if (!container)
|
| - return;
|
| - container = findBeforeAfterParent(container);
|
| - if (!container)
|
| - return;
|
| - for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
|
| - if (content->isCounter())
|
| - static_cast<RenderCounter*>(content)->invalidate();
|
| - }
|
| -}
|
| -
|
| -void RenderContainer::invalidateCounters()
|
| -{
|
| - if (documentBeingDestroyed())
|
| - return;
|
| -
|
| - invalidateCountersInContainer(beforeAfterContainer(RenderStyle::BEFORE));
|
| - invalidateCountersInContainer(beforeAfterContainer(RenderStyle::AFTER));
|
| -}
|
| -
|
| -void RenderContainer::appendChildNode(RenderObject* newChild, bool fullAppend)
|
| -{
|
| - ASSERT(newChild->parent() == 0);
|
| - ASSERT(!isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
|
| -
|
| - newChild->setParent(this);
|
| - RenderObject* lChild = children()->lastChild();
|
| -
|
| - if (lChild) {
|
| - newChild->setPreviousSibling(lChild);
|
| - lChild->setNextSibling(newChild);
|
| - } else
|
| - children()->setFirstChild(newChild);
|
| -
|
| - children()->setLastChild(newChild);
|
| -
|
| - if (fullAppend) {
|
| - // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
|
| - // and don't have a layer attached to ourselves.
|
| - RenderLayer* layer = 0;
|
| - if (newChild->firstChild() || newChild->hasLayer()) {
|
| - layer = enclosingLayer();
|
| - newChild->addLayers(layer, newChild);
|
| - }
|
| -
|
| - // if the new child is visible but this object was not, tell the layer it has some visible content
|
| - // that needs to be drawn and layer visibility optimization can't be used
|
| - if (style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
|
| - if (!layer)
|
| - layer = enclosingLayer();
|
| - if (layer)
|
| - layer->setHasVisibleContent(true);
|
| - }
|
| -
|
| - if (!newChild->isFloatingOrPositioned() && childrenInline())
|
| - dirtyLinesFromChangedChild(newChild);
|
| - }
|
| -
|
| - newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
|
| - if (!normalChildNeedsLayout())
|
| - setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
|
| -
|
| - if (AXObjectCache::accessibilityEnabled())
|
| - document()->axObjectCache()->childrenChanged(this);
|
| -}
|
| -
|
| -void RenderContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild, bool fullInsert)
|
| -{
|
| - if (!beforeChild) {
|
| - appendChildNode(child);
|
| - return;
|
| - }
|
| -
|
| - ASSERT(!child->parent());
|
| - while (beforeChild->parent() != this && beforeChild->parent()->isAnonymousBlock())
|
| - beforeChild = beforeChild->parent();
|
| - ASSERT(beforeChild->parent() == this);
|
| -
|
| - ASSERT(!isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
|
| -
|
| - if (beforeChild == children()->firstChild())
|
| - children()->setFirstChild(child);
|
| -
|
| - RenderObject* prev = beforeChild->previousSibling();
|
| - child->setNextSibling(beforeChild);
|
| - beforeChild->setPreviousSibling(child);
|
| - if(prev) prev->setNextSibling(child);
|
| - child->setPreviousSibling(prev);
|
| -
|
| - child->setParent(this);
|
| -
|
| - if (fullInsert) {
|
| - // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
|
| - // and don't have a layer attached to ourselves.
|
| - RenderLayer* layer = 0;
|
| - if (child->firstChild() || child->hasLayer()) {
|
| - layer = enclosingLayer();
|
| - child->addLayers(layer, child);
|
| - }
|
| -
|
| - // if the new child is visible but this object was not, tell the layer it has some visible content
|
| - // that needs to be drawn and layer visibility optimization can't be used
|
| - if (style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
|
| - if (!layer)
|
| - layer = enclosingLayer();
|
| - if (layer)
|
| - layer->setHasVisibleContent(true);
|
| - }
|
| -
|
| -
|
| - if (!child->isFloating() && childrenInline())
|
| - dirtyLinesFromChangedChild(child);
|
| - }
|
| -
|
| - child->setNeedsLayoutAndPrefWidthsRecalc();
|
| - if (!normalChildNeedsLayout())
|
| - setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
|
| -
|
| - if (AXObjectCache::accessibilityEnabled())
|
| - document()->axObjectCache()->childrenChanged(this);
|
| -}
|
| -
|
| -VisiblePosition RenderContainer::positionForCoordinates(int xPos, int yPos)
|
| -{
|
| - // no children...return this render object's element, if there is one, and offset 0
|
| - if (!children()->firstChild())
|
| - return VisiblePosition(element(), 0, DOWNSTREAM);
|
| -
|
| - if (isTable() && element()) {
|
| - int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft();
|
| - int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom();
|
| -
|
| - if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) {
|
| - if (xPos <= right / 2)
|
| - return VisiblePosition(Position(element(), 0));
|
| - else
|
| - return VisiblePosition(Position(element(), maxDeepOffset(element())));
|
| - }
|
| - }
|
| -
|
| - // Pass off to the closest child.
|
| - int minDist = INT_MAX;
|
| - RenderBox* closestRenderer = 0;
|
| - int newX = xPos;
|
| - int newY = yPos;
|
| - if (isTableRow()) {
|
| - newX += x();
|
| - newY += y();
|
| - }
|
| - for (RenderObject* renderObject = children()->firstChild(); renderObject; renderObject = renderObject->nextSibling()) {
|
| - if (!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isBlockFlow()
|
| - || renderObject->style()->visibility() != VISIBLE)
|
| - continue;
|
| -
|
| - if (!renderObject->isBox())
|
| - continue;
|
| -
|
| - RenderBox* renderer = toRenderBox(renderObject);
|
| -
|
| - int top = borderTop() + paddingTop() + (isTableRow() ? 0 : renderer->y());
|
| - int bottom = top + renderer->contentHeight();
|
| - int left = borderLeft() + paddingLeft() + (isTableRow() ? 0 : renderer->x());
|
| - int right = left + renderer->contentWidth();
|
| -
|
| - if (xPos <= right && xPos >= left && yPos <= top && yPos >= bottom) {
|
| - if (renderer->isTableRow())
|
| - return renderer->positionForCoordinates(xPos + newX - renderer->x(), yPos + newY - renderer->y());
|
| - return renderer->positionForCoordinates(xPos - renderer->x(), yPos - renderer->y());
|
| - }
|
| -
|
| - // Find the distance from (x, y) to the box. Split the space around the box into 8 pieces
|
| - // and use a different compare depending on which piece (x, y) is in.
|
| - IntPoint cmp;
|
| - if (xPos > right) {
|
| - if (yPos < top)
|
| - cmp = IntPoint(right, top);
|
| - else if (yPos > bottom)
|
| - cmp = IntPoint(right, bottom);
|
| - else
|
| - cmp = IntPoint(right, yPos);
|
| - } else if (xPos < left) {
|
| - if (yPos < top)
|
| - cmp = IntPoint(left, top);
|
| - else if (yPos > bottom)
|
| - cmp = IntPoint(left, bottom);
|
| - else
|
| - cmp = IntPoint(left, yPos);
|
| - } else {
|
| - if (yPos < top)
|
| - cmp = IntPoint(xPos, top);
|
| - else
|
| - cmp = IntPoint(xPos, bottom);
|
| - }
|
| -
|
| - int x1minusx2 = cmp.x() - xPos;
|
| - int y1minusy2 = cmp.y() - yPos;
|
| -
|
| - int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
|
| - if (dist < minDist) {
|
| - closestRenderer = renderer;
|
| - minDist = dist;
|
| - }
|
| - }
|
| -
|
| - if (closestRenderer)
|
| - return closestRenderer->positionForCoordinates(newX - closestRenderer->x(), newY - closestRenderer->y());
|
| -
|
| - return VisiblePosition(element(), 0, DOWNSTREAM);
|
| -}
|
| -
|
| void RenderContainer::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigned end, bool)
|
| {
|
| if (!children()->firstChild() && (isInline() || isAnonymousBlock())) {
|
|
|