2009-02-02 David Hyatt <hyatt@apple.com>
authorhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Feb 2009 04:33:23 +0000 (04:33 +0000)
committerhyatt@apple.com <hyatt@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Feb 2009 04:33:23 +0000 (04:33 +0000)
        Refactor the handling of before/after content and generated content.  Move most of the functions from
        RenderContainer into RenderObjectChildList.

        Reviewed by Sam Weinig

        * rendering/RenderBlock.cpp:
        (WebCore::RenderBlock::updateBeforeAfterContent):
        * rendering/RenderBlock.h:
        * rendering/RenderBox.cpp:
        (WebCore::RenderBox::isAfterContent):
        * rendering/RenderBox.h:
        * rendering/RenderButton.cpp:
        (WebCore::RenderButton::updateBeforeAfterContent):
        * rendering/RenderContainer.cpp:
        * rendering/RenderContainer.h:
        * rendering/RenderCounter.cpp:
        (WebCore::destroyCounterNodeChildren):
        * rendering/RenderInline.cpp:
        (WebCore::RenderInline::styleDidChange):
        (WebCore::RenderInline::addChildIgnoringContinuation):
        (WebCore::RenderInline::splitInlines):
        * rendering/RenderObject.h:
        * rendering/RenderObjectChildList.cpp:
        (WebCore::beforeAfterContainer):
        (WebCore::findBeforeAfterParent):
        (WebCore::invalidateCountersInContainer):
        (WebCore::RenderObjectChildList::invalidateCounters):
        (WebCore::RenderObjectChildList::updateBeforeAfterContent):
        * rendering/RenderObjectChildList.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@40518 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
WebCore/ChangeLog
WebCore/rendering/RenderBlock.cpp
WebCore/rendering/RenderBlock.h
WebCore/rendering/RenderBox.cpp
WebCore/rendering/RenderBox.h
WebCore/rendering/RenderButton.cpp
WebCore/rendering/RenderContainer.cpp
WebCore/rendering/RenderContainer.h
WebCore/rendering/RenderCounter.cpp
WebCore/rendering/RenderInline.cpp
WebCore/rendering/RenderObject.h
WebCore/rendering/RenderObjectChildList.cpp
WebCore/rendering/RenderObjectChildList.h

index f3d17db8dbb0a23247f44154964fa903d9e2230a..81cca097a2b687ff2bb73a023acf9f393c8aa8a6 100644 (file)
@@ -1,3 +1,35 @@
+2009-02-02  David Hyatt  <hyatt@apple.com>
+
+        Refactor the handling of before/after content and generated content.  Move most of the functions from
+        RenderContainer into RenderObjectChildList.
+
+        Reviewed by Sam Weinig
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::updateBeforeAfterContent):
+        * rendering/RenderBlock.h:
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::isAfterContent):
+        * rendering/RenderBox.h:
+        * rendering/RenderButton.cpp:
+        (WebCore::RenderButton::updateBeforeAfterContent):
+        * rendering/RenderContainer.cpp:
+        * rendering/RenderContainer.h:
+        * rendering/RenderCounter.cpp:
+        (WebCore::destroyCounterNodeChildren):
+        * rendering/RenderInline.cpp:
+        (WebCore::RenderInline::styleDidChange):
+        (WebCore::RenderInline::addChildIgnoringContinuation):
+        (WebCore::RenderInline::splitInlines):
+        * rendering/RenderObject.h:
+        * rendering/RenderObjectChildList.cpp:
+        (WebCore::beforeAfterContainer):
+        (WebCore::findBeforeAfterParent):
+        (WebCore::invalidateCountersInContainer):
+        (WebCore::RenderObjectChildList::invalidateCounters):
+        (WebCore::RenderObjectChildList::updateBeforeAfterContent):
+        * rendering/RenderObjectChildList.h:
+
 2009-02-02  Dmitry Titov  <dimich@chromium.org>
 
         Reviewed by Darin Adler.
index 7eee3a04a6079fe9f888381d445f80198db37357..99758308ea731099e412d6125b9d3ef86e736e10 100644 (file)
@@ -245,6 +245,14 @@ void RenderBlock::styleDidChange(RenderStyle::Diff diff, const RenderStyle* oldS
     updateFirstLetter();
 }
 
+void RenderBlock::updateBeforeAfterContent(RenderStyle::PseudoId pseudoId)
+{
+    // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
+    if (parent() && parent()->createsAnonymousWrapper())
+        return;
+    return children()->updateBeforeAfterContent(this, pseudoId);
+}
+    
 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
 {
     // Make sure we don't append things after :after-generated content if we have it.
index d51b8500451b0df22dcbd2b1596c75c11f90deca..8e5cf72264ef2283ba18ad40f2a5d877d961ddf3 100644 (file)
@@ -132,6 +132,8 @@ public:
 
     virtual void borderFitAdjust(int& x, int& w) const; // Shrink the box in which the border paints if border-fit is set.
 
+    virtual void updateBeforeAfterContent(RenderStyle::PseudoId pseudoId);
+
     virtual InlineBox* createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun=false);
 
     // Called to lay out the legend for a fieldset.
index d61160f79fd5143ca4d2ab3713677181fd39c8df..4e688846089376dd6a43a08912e2e37aabfaa5a2 100644 (file)
@@ -3130,6 +3130,11 @@ int RenderBox::leftmostPosition(bool /*includeOverflowInterior*/, bool includeSe
     return left;
 }
 
+bool RenderBox::isAfterContent(RenderObject* child) const
+{
+    return (child && child->style()->styleType() == RenderStyle::AFTER && (!child->isText() || child->isBR()));
+}
+
 #if ENABLE(SVG)
 
 TransformationMatrix RenderBox::localTransform() const
index 0003141bf22ce6a090b428d60caa33204165e02d..5b00b737f7c1b36814c335206912ab39f690057b 100644 (file)
@@ -356,6 +356,9 @@ private:
     // These include tables, positioned objects, floats and flexible boxes.
     virtual void calcPrefWidths() { setPrefWidthsDirty(false); }
 
+protected:
+    bool isAfterContent(RenderObject* child) const;
+
 private:
     // The width/height of the contents + borders + padding.  The x/y location is relative to our container (which is not always our parent).
     IntRect m_frameRect;
index f7ccd0c79787eaa71da3003cbe339472748e1451..f7bf7e27e1a6d78c646d22584978931a785019dc 100644 (file)
@@ -164,9 +164,9 @@ void RenderButton::setText(const String& str)
 void RenderButton::updateBeforeAfterContent(RenderStyle::PseudoId type)
 {
     if (m_inner)
-        m_inner->updateBeforeAfterContentForContainer(type, this);
+        m_inner->children()->updateBeforeAfterContent(m_inner, type, this);
     else
-        updateBeforeAfterContentForContainer(type, this);
+        children()->updateBeforeAfterContent(this, type);
 }
 
 IntRect RenderButton::controlClipRect(int tx, int ty) const
index 6522db816cafa3f96bdc96e2a864774734a731d8..0bad6b7df5f3c2310a30aa96b160862ae142f1cd 100644 (file)
@@ -181,216 +181,6 @@ void RenderContainer::removeChild(RenderObject* oldChild)
     removeChildNode(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);
index 8e2fa750b87086f360139251c1f413ebe852c6d4..2c310ad9351df54b9858922c20b8381892adc5e3 100644 (file)
@@ -48,12 +48,6 @@ public:
     // change in parentage is not going to affect anything.
     virtual void moveChildNode(RenderObject* child) { appendChildNode(child->parent()->removeChildNode(child, false), false); }
 
-    RenderObject* beforeAfterContainer(RenderStyle::PseudoId);
-    virtual void updateBeforeAfterContent(RenderStyle::PseudoId);
-    void updateBeforeAfterContentForContainer(RenderStyle::PseudoId, RenderContainer*);
-    bool isAfterContent(RenderObject* child) const;
-    virtual void invalidateCounters();
-
     virtual VisiblePosition positionForCoordinates(int x, int y);
 
     virtual void addLineBoxRects(Vector<IntRect>&, unsigned startOffset = 0, unsigned endOffset = UINT_MAX, bool useSelectionHeight = false);
index 598f40d747dc8a00aee6aa7f0418c5cd302a1518..ce3a8f36b320dff3682d5af912a1eba415e51777 100644 (file)
@@ -278,7 +278,11 @@ static void destroyCounterNodeChildren(AtomicStringImpl* identifier, CounterNode
         child->parent()->removeChild(child);
         ASSERT(counterMaps().get(child->renderer())->get(identifier) == child);
         counterMaps().get(child->renderer())->remove(identifier);
-        child->renderer()->invalidateCounters();
+        if (!child->renderer()->documentBeingDestroyed()) {
+            RenderObjectChildList* children = child->renderer()->virtualChildren();
+            if (children)
+                children->invalidateCounters(child->renderer());
+        }
         delete child;
     }
 }
index 920b12b6978699eb28c2fe45a79f56a54e83abcb..bd8cd6b48ca0a4a12888e04eab1389a18691e1bf 100644 (file)
@@ -118,8 +118,8 @@ void RenderInline::styleDidChange(RenderStyle::Diff diff, const RenderStyle* old
 
     // Update pseudos for :before and :after now.
     if (!isAnonymous() && document()->usesBeforeAfterRules()) {
-        updateBeforeAfterContent(RenderStyle::BEFORE);
-        updateBeforeAfterContent(RenderStyle::AFTER);
+        children()->updateBeforeAfterContent(this, RenderStyle::BEFORE);
+        children()->updateBeforeAfterContent(this, RenderStyle::AFTER);
     }
 }
 
@@ -199,7 +199,7 @@ void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderOb
         // content gets properly destroyed.
         bool isLastChild = (beforeChild == lastChild());
         if (document()->usesBeforeAfterRules())
-            updateBeforeAfterContent(RenderStyle::AFTER);
+            children()->updateBeforeAfterContent(this, RenderStyle::AFTER);
         if (isLastChild && beforeChild != lastChild())
             beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
                              // point to be 0.  It's just a straight append now.
@@ -273,7 +273,7 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
             // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that the inline's :after
             // content gets properly destroyed.
             if (document()->usesBeforeAfterRules())
-                curr->updateBeforeAfterContent(RenderStyle::AFTER);
+                inlineCurr->children()->updateBeforeAfterContent(this, RenderStyle::AFTER);
 
             // Now we need to take all of the children starting from the first child
             // *after* currChild and append them all to the clone.
index a0225926bc11db8412e67e7d5776aeb95cd8b6a1..2bd9bcf6246f8d9b0092c7622765e16d4902c0c1 100644 (file)
@@ -384,7 +384,6 @@ public:
     void setNeedsPositionedMovementLayout();
     void setPrefWidthsDirty(bool, bool markParents = true);
     void invalidateContainerPrefWidths();
-    virtual void invalidateCounters() { }
     
     void setNeedsLayoutAndPrefWidthsRecalc()
     {
index 71b549e3d188c81f9b1b05d5954b54e8464563df..1189e4b434118330ba555a363b943d3abd7323b1 100644 (file)
 
 #include "config.h"
 #include "RenderObjectChildList.h"
-#include "RenderObject.h"
+
+#include "RenderBlock.h"
+#include "RenderCounter.h"
+#include "RenderImageGeneratedContent.h"
+#include "RenderInline.h"
+#include "RenderTextFragment.h"
 
 namespace WebCore {
 
@@ -43,4 +48,195 @@ void RenderObjectChildList::destroyLeftoverChildren()
     }
 }
 
+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);
+        }
+    }
+}
+
 }
index 4807e91ac82297aab8e5973df910120d1545bebf..9759659665464ce3b5584dfdc8ce9082519b02fd 100644 (file)
@@ -26,6 +26,8 @@
 #ifndef RenderObjectChildList_h
 #define RenderObjectChildList_h
 
+#include "RenderStyle.h"
+
 namespace WebCore {
 
 class RenderObject;
@@ -48,6 +50,9 @@ public:
     
     void destroyLeftoverChildren();
 
+    void updateBeforeAfterContent(RenderObject* owner, RenderStyle::PseudoId type, RenderObject* styledObject = 0);
+    void invalidateCounters(RenderObject* owner);
+
 private:
     RenderObject* m_firstChild;
     RenderObject* m_lastChild;