| Index: third_party/WebKit/WebCore/rendering/RenderObjectChildList.cpp | 
| =================================================================== | 
| --- third_party/WebKit/WebCore/rendering/RenderObjectChildList.cpp	(revision 9118) | 
| +++ third_party/WebKit/WebCore/rendering/RenderObjectChildList.cpp	(working copy) | 
| @@ -25,10 +25,29 @@ | 
|  | 
| #include "config.h" | 
| #include "RenderObjectChildList.h" | 
| -#include "RenderObject.h" | 
|  | 
| +#include "AXObjectCache.h" | 
| +#include "RenderBlock.h" | 
| +#include "RenderCounter.h" | 
| +#include "RenderImageGeneratedContent.h" | 
| +#include "RenderInline.h" | 
| +#include "RenderLayer.h" | 
| +#include "RenderListItem.h" | 
| +#include "RenderStyle.h" | 
| +#include "RenderTextFragment.h" | 
| +#include "RenderView.h" | 
| + | 
| namespace WebCore { | 
|  | 
| +static void updateListMarkerNumbers(RenderObject* child) | 
| +{ | 
| +    for (RenderObject* r = child; r; r = r->nextSibling()) { | 
| +        if (r->isListItem()) | 
| +            static_cast<RenderListItem*>(r)->updateValue(); | 
| +    } | 
| +} | 
| + | 
| + | 
| void RenderObjectChildList::destroyLeftoverChildren() | 
| { | 
| while (firstChild()) { | 
| @@ -43,4 +62,364 @@ | 
| } | 
| } | 
|  | 
| +RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove) | 
| +{ | 
| +    ASSERT(oldChild->parent() == owner); | 
| + | 
| +    // 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 (!owner->documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) { | 
| +        oldChild->setNeedsLayoutAndPrefWidthsRecalc(); | 
| +        oldChild->repaint(); | 
| +    } | 
| + | 
| +    // If we have a line box wrapper, delete it. | 
| +    oldChild->deleteLineBoxWrapper(); | 
| + | 
| +    if (!owner->documentBeingDestroyed() && fullRemove) { | 
| +        // if we remove visible child from an invisible parent, we don't know the layer visibility any more | 
| +        RenderLayer* layer = 0; | 
| +        if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) { | 
| +            layer = owner->enclosingLayer(); | 
| +            layer->dirtyVisibleContentStatus(); | 
| +        } | 
| + | 
| +         // Keep our layer hierarchy updated. | 
| +        if (oldChild->firstChild() || oldChild->hasLayer()) { | 
| +            if (!layer) | 
| +                layer = owner->enclosingLayer(); | 
| +            oldChild->removeLayers(layer); | 
| +        } | 
| + | 
| +        // renumber ordered lists | 
| +        if (oldChild->isListItem()) | 
| +            updateListMarkerNumbers(oldChild->nextSibling()); | 
| + | 
| +        if (oldChild->isPositioned() && owner->childrenInline()) | 
| +            owner->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 (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder()) | 
| +        owner->view()->clearSelection(); | 
| + | 
| +    // remove the child | 
| +    if (oldChild->previousSibling()) | 
| +        oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); | 
| +    if (oldChild->nextSibling()) | 
| +        oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); | 
| + | 
| +    if (firstChild() == oldChild) | 
| +        setFirstChild(oldChild->nextSibling()); | 
| +    if (lastChild() == oldChild) | 
| +        setLastChild(oldChild->previousSibling()); | 
| + | 
| +    oldChild->setPreviousSibling(0); | 
| +    oldChild->setNextSibling(0); | 
| +    oldChild->setParent(0); | 
| + | 
| +    if (AXObjectCache::accessibilityEnabled()) | 
| +        owner->document()->axObjectCache()->childrenChanged(owner); | 
| + | 
| +    return oldChild; | 
| } | 
| + | 
| +void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend) | 
| +{ | 
| +    ASSERT(newChild->parent() == 0); | 
| +    ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell())); | 
| + | 
| +    newChild->setParent(owner); | 
| +    RenderObject* lChild = lastChild(); | 
| + | 
| +    if (lChild) { | 
| +        newChild->setPreviousSibling(lChild); | 
| +        lChild->setNextSibling(newChild); | 
| +    } else | 
| +        setFirstChild(newChild); | 
| + | 
| +    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 = owner->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 (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) { | 
| +            if (!layer) | 
| +                layer = owner->enclosingLayer(); | 
| +            if (layer) | 
| +                layer->setHasVisibleContent(true); | 
| +        } | 
| + | 
| +        if (!newChild->isFloatingOrPositioned() && owner->childrenInline()) | 
| +            owner->dirtyLinesFromChangedChild(newChild); | 
| +    } | 
| + | 
| +    newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy. | 
| +    if (!owner->normalChildNeedsLayout()) | 
| +        owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. | 
| + | 
| +    if (AXObjectCache::accessibilityEnabled()) | 
| +        owner->document()->axObjectCache()->childrenChanged(owner); | 
| +} | 
| + | 
| +void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert) | 
| +{ | 
| +    if (!beforeChild) { | 
| +        appendChildNode(owner, child); | 
| +        return; | 
| +    } | 
| + | 
| +    ASSERT(!child->parent()); | 
| +    while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock()) | 
| +        beforeChild = beforeChild->parent(); | 
| +    ASSERT(beforeChild->parent() == owner); | 
| + | 
| +    ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell())); | 
| + | 
| +    if (beforeChild == firstChild()) | 
| +        setFirstChild(child); | 
| + | 
| +    RenderObject* prev = beforeChild->previousSibling(); | 
| +    child->setNextSibling(beforeChild); | 
| +    beforeChild->setPreviousSibling(child); | 
| +    if (prev) | 
| +        prev->setNextSibling(child); | 
| +    child->setPreviousSibling(prev); | 
| + | 
| +    child->setParent(owner); | 
| + | 
| +    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 = owner->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 (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) { | 
| +            if (!layer) | 
| +                layer = owner->enclosingLayer(); | 
| +            if (layer) | 
| +                layer->setHasVisibleContent(true); | 
| +        } | 
| + | 
| + | 
| +        if (!child->isFloating() && owner->childrenInline()) | 
| +            owner->dirtyLinesFromChangedChild(child); | 
| +    } | 
| + | 
| +    child->setNeedsLayoutAndPrefWidthsRecalc(); | 
| +    if (!owner->normalChildNeedsLayout()) | 
| +        owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child. | 
| + | 
| +    if (AXObjectCache::accessibilityEnabled()) | 
| +        owner->document()->axObjectCache()->childrenChanged(owner); | 
| +} | 
| + | 
| +static RenderObject* beforeAfterContainer(RenderObject* container, RenderStyle::PseudoId type) | 
| +{ | 
| +    if (type == RenderStyle::BEFORE) { | 
| +        RenderObject* first = container; | 
| +        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 = container; | 
| +        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; | 
| +} | 
| + | 
| +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; | 
| +} | 
| + | 
| +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 RenderObjectChildList::invalidateCounters(RenderObject* owner) | 
| +{ | 
| +    ASSERT(!owner->documentBeingDestroyed()); | 
| +    invalidateCountersInContainer(beforeAfterContainer(owner, RenderStyle::BEFORE)); | 
| +    invalidateCountersInContainer(beforeAfterContainer(owner, RenderStyle::AFTER)); | 
| +} | 
| + | 
| +void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, RenderStyle::PseudoId type, RenderObject* styledObject) | 
| +{ | 
| +    // Double check that the document did in fact use generated content rules.  Otherwise we should not have been called. | 
| +    ASSERT(owner->document()->usesBeforeAfterRules()); | 
| + | 
| +    // In CSS2, before/after pseudo-content cannot nest.  Check this first. | 
| +    if (owner->style()->styleType() == RenderStyle::BEFORE || owner->style()->styleType() == RenderStyle::AFTER) | 
| +        return; | 
| + | 
| +    if (!styledObject) | 
| +        styledObject = owner; | 
| + | 
| +    RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type); | 
| +    RenderObject* child = beforeAfterContainer(owner, 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 && owner->isRenderInline() && toRenderInline(owner)->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 && owner->isRenderInline() && toRenderInline(owner)->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) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->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 (owner->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) ? owner->virtualChildren()->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 (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->m_content.m_text); | 
| +                renderer->setStyle(pseudoElementStyle); | 
| +                break; | 
| +            case CONTENT_OBJECT: { | 
| +                RenderImageGeneratedContent* image = new (owner->renderArena()) RenderImageGeneratedContent(owner->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 (owner->renderArena()) RenderCounter(owner->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(owner->document(), pseudoElementStyle); | 
| +                generatedContentContainer->setStyle(pseudoElementStyle); | 
| +                owner->addChild(generatedContentContainer, insertBefore); | 
| +            } | 
| +            generatedContentContainer->addChild(renderer); | 
| +        } | 
| +    } | 
| +} | 
| + | 
| +} // namespace WebCore | 
|  |