Move :before and :after into the DOM
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Oct 2012 03:17:42 +0000 (03:17 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 11 Oct 2012 03:17:42 +0000 (03:17 +0000)
https://bugs.webkit.org/show_bug.cgi?id=95117

Patch by Elliott Sprehn <esprehn@chromium.org> on 2012-10-10
Reviewed by Eric Seidel.

Source/WebCore:

Reimplement generated content :before and :after as DOM Elements. Now ElementRareData has
two RefPtrs to PseudoElements for the generated content and Node has methods for traversing
the tree including generated content.

This allows the generated content to be treated as real nodes instead of anonymous and take
part in the usual recalcStyle and attach flow which fixes many bugs and vastly simplifies the
lifecycle of generated content.

No new tests needed for now.

* CMakeLists.txt:
* GNUmakefile.list.am:
* Target.pri:
* WebCore.gypi:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* dom/DOMAllInOne.cpp:
* dom/Element.cpp:
(WebCore::Element::attach): Add generated content if needed.
(WebCore::Element::detach): Remove all child generated content.
(WebCore::Element::recalcStyle): Add or remove generated content based on the new style.
(WebCore::Element::updatePseudoElement): Updates pseudo content based on a pseudoId.
(WebCore):
(WebCore::Element::createPseudoElementIfNeeded):
(WebCore::Element::beforePseudoElement):
(WebCore::Element::afterPseudoElement):
* dom/Element.h:
(WebCore):
(Element):
* dom/ElementRareData.h:
(ElementRareData):
(WebCore::ElementRareData::setPseudoElement):
(WebCore):
(WebCore::ElementRareData::pseudoElement):
* dom/Node.cpp:
(WebCore::Node::pseudoAwarePreviousSibling):
(WebCore):
(WebCore::Node::pseudoAwareNextSibling):
(WebCore::checkAcceptChild): Forbid moving PseudoElements for sanity. The code never does this.
* dom/Node.h:
(Node):
(WebCore::Node::isPseudoElement):
(WebCore::Node::pseudoId): Fast path that only calls virtualPseudoId if the node has custom callbacks so isPseudoElement is fast.
(WebCore::Node::virtualPseudoId):
(WebCore::Node::isBeforePseudoElement):
(WebCore::Node::isAfterPseudoElement):
* dom/NodeRenderingContext.cpp:
(WebCore::NodeRenderingContext::nextRenderer): Changed to find the next sibling of pseudos for insertion.
* dom/PseudoElement.cpp: Added.
(WebCore):
(WebCore::pseudoElementName):
(WebCore::PseudoElement::PseudoElement):
(WebCore::PseudoElement::pseudoRendererIsNeeded):
(WebCore::PseudoElement::customStyleForRenderer):
(WebCore::PseudoElement::attach):
(WebCore::PseudoElement::rendererIsNeeded):
(WebCore::PseudoElement::updateChildStyle): Propagates the style downward into the anonymous renderers for the content.
(WebCore::PseudoElement::didRecalcStyle):
(WebCore::PseudoElement::createRendererForContent): Refactored from RenderObjectChildList.
* dom/PseudoElement.h: Added.
(WebCore):
(PseudoElement):
(WebCore::PseudoElement::create):
(WebCore::toPseudoElement):
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::setInnerNode): Hit testing a PseudoElement should really hit the parent.
(WebCore::HitTestResult::setInnerNonSharedNode): Same as above.
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::styleDidChange): Remove old generated content code, same for below.
(WebCore::RenderBlock::splitBlocks):
(WebCore::RenderBlock::addChildIgnoringAnonymousColumnBlocks):
(WebCore::RenderBlock::createReplacementRunIn):
(WebCore::RenderBlock::renderName):
* rendering/RenderBlock.h:
(RenderBlock):
* rendering/RenderButton.cpp:
* rendering/RenderButton.h:
(RenderButton):
* rendering/RenderCounter.cpp:
(WebCore::RenderCounter::originalText):
* rendering/RenderDeprecatedFlexibleBox.cpp:
(WebCore::RenderDeprecatedFlexibleBox::renderName):
* rendering/RenderGrid.cpp:
(WebCore::RenderGrid::renderName):
* rendering/RenderInline.cpp:
(WebCore::RenderInline::styleDidChange):
(WebCore::RenderInline::addChildIgnoringContinuation):
(WebCore::RenderInline::splitInlines):
(WebCore::RenderInline::renderName):
* rendering/RenderListItem.cpp:
(WebCore::RenderListItem::updateMarkerLocation):
* rendering/RenderMultiColumnBlock.cpp:
(WebCore::RenderMultiColumnBlock::renderName):
* rendering/RenderObject.cpp:
(WebCore::RenderObject::createObject):
* rendering/RenderObject.h:
(WebCore::RenderObject::isPseudoElement):
(RenderObject):
(WebCore::RenderObject::generatingNode):
* rendering/RenderObjectChildList.cpp:
* rendering/RenderObjectChildList.h:
(RenderObjectChildList):
* rendering/RenderRubyText.cpp:
* rendering/RenderRubyText.h:
(RenderRubyText):
* rendering/RenderTableCell.h:
(WebCore::RenderTableCell::renderName):
* rendering/RenderTableRow.cpp:
(WebCore::RenderTableRow::styleDidChange):
* rendering/RenderTableRow.h:
(WebCore::RenderTableRow::renderName):
* rendering/RenderTableSection.cpp:
(WebCore::RenderTableSection::addChild):
* rendering/RenderTableSection.h:
(WebCore::RenderTableSection::renderName):
* rendering/RenderTreeAsText.cpp:
(WebCore::RenderTreeAsText::writeRenderObject):

LayoutTests:

Regenerated some baselines for tests given the new generated content architecture and disabled
tests that are testing generated content on inputs which were wrong.

* fast/css-generated-content/before-content-continuation-chain-expected.txt:
* platform/chromium-mac/fast/css-generated-content/table-row-group-to-inline-expected.png:
* platform/chromium/TestExpectations: Disable the tests for generated content on inputs. A follow up CL with remove these tests.
* platform/mac/fast/css-generated-content/table-row-group-to-inline-expected.png:
* platform/mac/fast/css-generated-content/table-row-group-to-inline-expected.txt:
   This test always produced wrong output because we leave an anonymous RenderTable in the tree,
   and now that generated content is handled like DOM nodes this test renders differently since the
   content ends up after the left over RenderTable. Both outputs are wrong until Bug 86261 is fixed.

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

45 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css-generated-content/before-content-continuation-chain-expected.txt
LayoutTests/platform/chromium-mac/fast/css-generated-content/table-row-group-to-inline-expected.png
LayoutTests/platform/chromium/TestExpectations
LayoutTests/platform/mac/fast/css-generated-content/table-row-group-to-inline-expected.png
LayoutTests/platform/mac/fast/css-generated-content/table-row-group-to-inline-expected.txt
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Target.pri
Source/WebCore/WebCore.gypi
Source/WebCore/WebCore.vcproj/WebCore.vcproj
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/DOMAllInOne.cpp
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Element.h
Source/WebCore/dom/ElementRareData.h
Source/WebCore/dom/Node.cpp
Source/WebCore/dom/Node.h
Source/WebCore/dom/NodeRenderingContext.cpp
Source/WebCore/dom/PseudoElement.cpp [new file with mode: 0644]
Source/WebCore/dom/PseudoElement.h [new file with mode: 0644]
Source/WebCore/rendering/HitTestResult.cpp
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBlock.h
Source/WebCore/rendering/RenderButton.cpp
Source/WebCore/rendering/RenderButton.h
Source/WebCore/rendering/RenderCounter.cpp
Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp
Source/WebCore/rendering/RenderGrid.cpp
Source/WebCore/rendering/RenderInline.cpp
Source/WebCore/rendering/RenderListItem.cpp
Source/WebCore/rendering/RenderMultiColumnBlock.cpp
Source/WebCore/rendering/RenderObject.cpp
Source/WebCore/rendering/RenderObject.h
Source/WebCore/rendering/RenderObjectChildList.cpp
Source/WebCore/rendering/RenderObjectChildList.h
Source/WebCore/rendering/RenderRubyText.cpp
Source/WebCore/rendering/RenderRubyText.h
Source/WebCore/rendering/RenderTableCell.h
Source/WebCore/rendering/RenderTableRow.cpp
Source/WebCore/rendering/RenderTableRow.h
Source/WebCore/rendering/RenderTableSection.cpp
Source/WebCore/rendering/RenderTableSection.h
Source/WebCore/rendering/RenderTreeAsText.cpp

index e72fded..1df96f0 100644 (file)
@@ -1,3 +1,22 @@
+2012-10-10  Elliott Sprehn  <esprehn@chromium.org>
+
+        Move :before and :after into the DOM        
+        https://bugs.webkit.org/show_bug.cgi?id=95117
+
+        Reviewed by Eric Seidel.
+
+        Regenerated some baselines for tests given the new generated content architecture and disabled
+        tests that are testing generated content on inputs which were wrong.
+
+        * fast/css-generated-content/before-content-continuation-chain-expected.txt:
+        * platform/chromium-mac/fast/css-generated-content/table-row-group-to-inline-expected.png:
+        * platform/chromium/TestExpectations: Disable the tests for generated content on inputs. A follow up CL with remove these tests.
+        * platform/mac/fast/css-generated-content/table-row-group-to-inline-expected.png:
+        * platform/mac/fast/css-generated-content/table-row-group-to-inline-expected.txt:
+           This test always produced wrong output because we leave an anonymous RenderTable in the tree,
+           and now that generated content is handled like DOM nodes this test renders differently since the
+           content ends up after the left over RenderTable. Both outputs are wrong until Bug 86261 is fixed.
+
 2012-10-10  Levi Weintraub  <leviw@chromium.org>
 
         Tests failure on Chromium Mac after r130821
index 0493aa1..baa8293 100644 (file)
@@ -3,13 +3,13 @@ layer at (0,0) size 800x600
 layer at (0,0) size 800x416
   RenderBlock {HTML} at (0,0) size 800x416
     RenderBody {BODY} at (8,8) size 784x400
+      RenderBlock (anonymous) at (0,0) size 784x0
+        RenderInline {SPAN} at (0,0) size 0x0 [color=#008000]
       RenderBlock (anonymous) at (0,0) size 784x200
-        RenderInline {SPAN} at (0,0) size 200x200 [color=#008000]
-          RenderInline (generated) at (0,0) size 200x200 [color=#0000FF]
-            RenderText at (0,0) size 200x200
-              text run at (0,0) width 200: "A"
-      RenderBlock (anonymous) at (0,200) size 784x0
-        RenderBlock {DIV} at (0,0) size 784x0 [color=#008000]
+        RenderBlock (generated) at (0,0) size 784x200 [color=#0000FF]
+          RenderText at (0,0) size 200x200
+            text run at (0,0) width 200: "A"
+        RenderBlock {DIV} at (0,200) size 784x0 [color=#008000]
       RenderBlock (anonymous) at (0,200) size 784x200
         RenderInline {SPAN} at (0,0) size 200x200 [color=#008000]
           RenderText {#text} at (0,0) size 200x200
index d53dda2..12fd80b 100644 (file)
Binary files a/LayoutTests/platform/chromium-mac/fast/css-generated-content/table-row-group-to-inline-expected.png and b/LayoutTests/platform/chromium-mac/fast/css-generated-content/table-row-group-to-inline-expected.png differ
index 3385297..0887839 100644 (file)
@@ -3614,6 +3614,15 @@ webkit.org/b/91620 css3/filters/blur-filter-page-scroll-self.html [ ImageOnlyFai
 # Needs rebaseline after bug 97217 is fixed
 webkit.org/b/97325 css3/masking/clip-path-circle-relative-overflow.html [ ImageOnlyFailure Pass ]
 
+# Needs rebaseline after bug 95117 is fixed
+webkit.org/b/98687 fast/css-generated-content/table-row-group-to-inline.html [ Failure Pass ]
+
+# Should not be testing for generated content in inputs yet.
+webkit.org/b/98836 fast/forms/time-multiple-fields/time-multiple-fields-appearance-pseudo-elements.html [ Skip ]
+webkit.org/b/98836 fast/forms/month-multiple-fields/month-multiple-fields-appearance-pseudo-elements.html [ Skip ]
+webkit.org/b/98836 fast/forms/week-multiple-fields/week-multiple-fields-appearance-pseudo-elements.html [ Skip ]
+webkit.org/b/98836 fast/forms/date-multiple-fields/date-multiple-fields-appearance-pseudo-elements.html [ Skip ]
+
 webkit.org/b/91544 media/media-continues-playing-after-replace-source.html [ Pass Timeout ]
 
 webkit.org/b/92019 fast/text/international/inline-plaintext-relayout-with-leading-neutrals.html [ ImageOnlyFailure Pass ]
index ace20cc..12fd80b 100644 (file)
Binary files a/LayoutTests/platform/mac/fast/css-generated-content/table-row-group-to-inline-expected.png and b/LayoutTests/platform/mac/fast/css-generated-content/table-row-group-to-inline-expected.png differ
index d023f3a..7fc67f9 100644 (file)
@@ -14,10 +14,10 @@ layer at (0,0) size 800x600
         RenderListItem {LI} at (40,0) size 744x36
           RenderBlock (anonymous) at (0,0) size 744x18
             RenderListMarker at (-17,0) size 7x18: bullet
+          RenderTable at (0,18) size 0x0
+          RenderBlock (anonymous) at (0,18) size 744x18
             RenderInline (generated) at (0,0) size 31x18
               RenderText at (0,0) size 31x18
                 text run at (0,0) width 31: "hello"
-          RenderTable at (0,18) size 0x0
-          RenderBlock (anonymous) at (0,18) size 744x18
-            RenderText {#text} at (0,0) size 21x18
-              text run at (0,0) width 21: "test"
+            RenderText {#text} at (31,0) size 21x18
+              text run at (31,0) width 21: "test"
index 5e0333e..25dc1e5 100644 (file)
@@ -1196,6 +1196,7 @@ SET(WebCore_SOURCES
     dom/ProcessingInstruction.cpp
     dom/ProgressEvent.cpp
     dom/PropertyNodeList.cpp
+    dom/PseudoElement.cpp
     dom/QualifiedName.cpp
     dom/Range.cpp
     dom/RangeException.cpp
index ac36f2b..8b025e9 100644 (file)
@@ -1,3 +1,128 @@
+2012-10-10  Elliott Sprehn  <esprehn@chromium.org>
+
+        Move :before and :after into the DOM        
+        https://bugs.webkit.org/show_bug.cgi?id=95117
+
+        Reviewed by Eric Seidel.
+
+        Reimplement generated content :before and :after as DOM Elements. Now ElementRareData has
+        two RefPtrs to PseudoElements for the generated content and Node has methods for traversing
+        the tree including generated content.
+
+        This allows the generated content to be treated as real nodes instead of anonymous and take
+        part in the usual recalcStyle and attach flow which fixes many bugs and vastly simplifies the
+        lifecycle of generated content.
+
+        No new tests needed for now.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * Target.pri:
+        * WebCore.gypi:
+        * WebCore.vcproj/WebCore.vcproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/DOMAllInOne.cpp:
+        * dom/Element.cpp:
+        (WebCore::Element::attach): Add generated content if needed.
+        (WebCore::Element::detach): Remove all child generated content.
+        (WebCore::Element::recalcStyle): Add or remove generated content based on the new style.
+        (WebCore::Element::updatePseudoElement): Updates pseudo content based on a pseudoId.
+        (WebCore):
+        (WebCore::Element::createPseudoElementIfNeeded):
+        (WebCore::Element::beforePseudoElement):
+        (WebCore::Element::afterPseudoElement):
+        * dom/Element.h:
+        (WebCore):
+        (Element):
+        * dom/ElementRareData.h:
+        (ElementRareData):
+        (WebCore::ElementRareData::setPseudoElement):
+        (WebCore):
+        (WebCore::ElementRareData::pseudoElement):
+        * dom/Node.cpp:
+        (WebCore::Node::pseudoAwarePreviousSibling):
+        (WebCore):
+        (WebCore::Node::pseudoAwareNextSibling):
+        (WebCore::checkAcceptChild): Forbid moving PseudoElements for sanity. The code never does this.
+        * dom/Node.h:
+        (Node):
+        (WebCore::Node::isPseudoElement):
+        (WebCore::Node::pseudoId): Fast path that only calls virtualPseudoId if the node has custom callbacks so isPseudoElement is fast.
+        (WebCore::Node::virtualPseudoId):
+        (WebCore::Node::isBeforePseudoElement):
+        (WebCore::Node::isAfterPseudoElement):
+        * dom/NodeRenderingContext.cpp:
+        (WebCore::NodeRenderingContext::nextRenderer): Changed to find the next sibling of pseudos for insertion.
+        * dom/PseudoElement.cpp: Added.
+        (WebCore):
+        (WebCore::pseudoElementName):
+        (WebCore::PseudoElement::PseudoElement):
+        (WebCore::PseudoElement::pseudoRendererIsNeeded):
+        (WebCore::PseudoElement::customStyleForRenderer):
+        (WebCore::PseudoElement::attach):
+        (WebCore::PseudoElement::rendererIsNeeded):
+        (WebCore::PseudoElement::updateChildStyle): Propagates the style downward into the anonymous renderers for the content.
+        (WebCore::PseudoElement::didRecalcStyle):
+        (WebCore::PseudoElement::createRendererForContent): Refactored from RenderObjectChildList.
+        * dom/PseudoElement.h: Added.
+        (WebCore):
+        (PseudoElement):
+        (WebCore::PseudoElement::create):
+        (WebCore::toPseudoElement):
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestResult::setInnerNode): Hit testing a PseudoElement should really hit the parent.
+        (WebCore::HitTestResult::setInnerNonSharedNode): Same as above.
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::styleDidChange): Remove old generated content code, same for below.
+        (WebCore::RenderBlock::splitBlocks):
+        (WebCore::RenderBlock::addChildIgnoringAnonymousColumnBlocks):
+        (WebCore::RenderBlock::createReplacementRunIn):
+        (WebCore::RenderBlock::renderName):
+        * rendering/RenderBlock.h:
+        (RenderBlock):
+        * rendering/RenderButton.cpp:
+        * rendering/RenderButton.h:
+        (RenderButton):
+        * rendering/RenderCounter.cpp:
+        (WebCore::RenderCounter::originalText):
+        * rendering/RenderDeprecatedFlexibleBox.cpp:
+        (WebCore::RenderDeprecatedFlexibleBox::renderName):
+        * rendering/RenderGrid.cpp:
+        (WebCore::RenderGrid::renderName):
+        * rendering/RenderInline.cpp:
+        (WebCore::RenderInline::styleDidChange):
+        (WebCore::RenderInline::addChildIgnoringContinuation):
+        (WebCore::RenderInline::splitInlines):
+        (WebCore::RenderInline::renderName):
+        * rendering/RenderListItem.cpp:
+        (WebCore::RenderListItem::updateMarkerLocation):
+        * rendering/RenderMultiColumnBlock.cpp:
+        (WebCore::RenderMultiColumnBlock::renderName):
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::createObject):
+        * rendering/RenderObject.h:
+        (WebCore::RenderObject::isPseudoElement):
+        (RenderObject):
+        (WebCore::RenderObject::generatingNode):
+        * rendering/RenderObjectChildList.cpp:
+        * rendering/RenderObjectChildList.h:
+        (RenderObjectChildList):
+        * rendering/RenderRubyText.cpp:
+        * rendering/RenderRubyText.h:
+        (RenderRubyText):
+        * rendering/RenderTableCell.h:
+        (WebCore::RenderTableCell::renderName):
+        * rendering/RenderTableRow.cpp:
+        (WebCore::RenderTableRow::styleDidChange):
+        * rendering/RenderTableRow.h:
+        (WebCore::RenderTableRow::renderName):
+        * rendering/RenderTableSection.cpp:
+        (WebCore::RenderTableSection::addChild):
+        * rendering/RenderTableSection.h:
+        (WebCore::RenderTableSection::renderName):
+        * rendering/RenderTreeAsText.cpp:
+        (WebCore::RenderTreeAsText::writeRenderObject):
+
 2012-10-10  Sam Weinig  <sam@webkit.org>
 
         Add more Objective-C WebKit2 DOM API skeletons.
index 5cfb7e3..0991804 100644 (file)
@@ -2890,6 +2890,8 @@ webcore_sources += \
        Source/WebCore/dom/ProgressEvent.h \
        Source/WebCore/dom/PropertyNodeList.cpp \
        Source/WebCore/dom/PropertyNodeList.h \
+       Source/WebCore/dom/PseudoElement.cpp \
+       Source/WebCore/dom/PseudoElement.h \
        Source/WebCore/dom/QualifiedName.cpp \
        Source/WebCore/dom/QualifiedName.h \
        Source/WebCore/dom/RangeBoundaryPoint.h \
index 100610e..284cbe0 100644 (file)
@@ -438,6 +438,7 @@ SOURCES += \
     dom/ProcessingInstruction.cpp \
     dom/ProgressEvent.cpp \
     dom/PropertyNodeList.cpp \
+    dom/PseudoElement.cpp \
     dom/QualifiedName.cpp \
     dom/Range.cpp \
     dom/RangeException.cpp \
@@ -1598,6 +1599,7 @@ HEADERS += \
     dom/ProcessingInstruction.h \
     dom/ProgressEvent.h \
     dom/PropertyNodeList.h \
+    dom/PseudoElement.h \
     dom/QualifiedName.h \
     dom/Range.h \
     dom/RegisteredEventListener.h \
index 6f794b6..5df0a23 100644 (file)
             'dom/NodeList.h',
             'dom/PendingScript.h',
             'dom/Position.h',
+            'dom/PseudoElement.h',
             'dom/QualifiedName.h',
             'dom/Range.h',
             'dom/RangeBoundaryPoint.h',
             'dom/ProgressEvent.h',
             'dom/PropertyNodeList.cpp',
             'dom/PropertyNodeList.h',
+            'dom/PseudoElement.cpp',
             'dom/QualifiedName.cpp',
             'dom/Range.cpp',
             'dom/RangeException.cpp',
index 746f313..71a22ab 100755 (executable)
                                </FileConfiguration>
                        </File>
                        <File
+                               RelativePath="..\dom\PseudoElement.h"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\dom\PseudoElement.cpp"
+                               >
+                               <FileConfiguration
+                                       Name="Debug|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug_Cairo_CFLite|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Release_Cairo_CFLite|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Debug_All|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                               <FileConfiguration
+                                       Name="Production|Win32"
+                                       ExcludedFromBuild="true"
+                                       >
+                                       <Tool
+                                               Name="VCCLCompilerTool"
+                                       />
+                               </FileConfiguration>
+                       </File>
+                       <File
                                RelativePath="..\dom\PropertyNodeList.h"
                                >
                        </File>
index 38b0576..63d7c73 100644 (file)
                FE80DA660E9C4703000D6F75 /* JSGeoposition.h in Headers */ = {isa = PBXBuildFile; fileRef = FE80DA620E9C4703000D6F75 /* JSGeoposition.h */; };
                FE80DA710E9C472F000D6F75 /* JSPositionError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE80DA6D0E9C472F000D6F75 /* JSPositionError.cpp */; };
                FE80DA720E9C472F000D6F75 /* JSPositionError.h in Headers */ = {isa = PBXBuildFile; fileRef = FE80DA6E0E9C472F000D6F75 /* JSPositionError.h */; };
+               FF945ECB161F7F3600971BC8 /* PseudoElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FF945EC9161F7F3600971BC8 /* PseudoElement.cpp */; };
+               FF945ECC161F7F3600971BC8 /* PseudoElement.h in Headers */ = {isa = PBXBuildFile; fileRef = FF945ECA161F7F3600971BC8 /* PseudoElement.h */; };
                FFD5B97A135CC97800D5E92A /* PageVisibilityState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FFD5B977135CC97800D5E92A /* PageVisibilityState.cpp */; };
                FFD5B97B135CC97800D5E92A /* PageVisibilityState.h in Headers */ = {isa = PBXBuildFile; fileRef = FFD5B978135CC97800D5E92A /* PageVisibilityState.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FFD86E7815F9583600047233 /* JSDependentRetained.h in Headers */ = {isa = PBXBuildFile; fileRef = FFD86E7715F9583600047233 /* JSDependentRetained.h */; };
                FE80DA620E9C4703000D6F75 /* JSGeoposition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGeoposition.h; sourceTree = "<group>"; };
                FE80DA6D0E9C472F000D6F75 /* JSPositionError.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPositionError.cpp; sourceTree = "<group>"; };
                FE80DA6E0E9C472F000D6F75 /* JSPositionError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPositionError.h; sourceTree = "<group>"; };
+               FF945EC9161F7F3600971BC8 /* PseudoElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PseudoElement.cpp; sourceTree = "<group>"; };
+               FF945ECA161F7F3600971BC8 /* PseudoElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PseudoElement.h; sourceTree = "<group>"; };
                FFD5B977135CC97800D5E92A /* PageVisibilityState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageVisibilityState.cpp; sourceTree = "<group>"; };
                FFD5B978135CC97800D5E92A /* PageVisibilityState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PageVisibilityState.h; sourceTree = "<group>"; };
                FFD86E7715F9583600047233 /* JSDependentRetained.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDependentRetained.h; sourceTree = "<group>"; };
                                1059459615B42A8E004D37FD /* PropertyNodeList.cpp */,
                                1059459815B42AA0004D37FD /* PropertyNodeList.h */,
                                1059459A15B42AC0004D37FD /* PropertyNodeList.idl */,
+                               FF945EC9161F7F3600971BC8 /* PseudoElement.cpp */,
+                               FF945ECA161F7F3600971BC8 /* PseudoElement.h */,
                                550A0BC7085F6039007353D6 /* QualifiedName.cpp */,
                                550A0BC8085F6039007353D6 /* QualifiedName.h */,
                                F523D30302DE4476018635CA /* Range.cpp */,
                                514C76750CE923A1007EF3CD /* ProtectionSpace.h in Headers */,
                                51A052561058874000CC9E95 /* ProtectionSpaceHash.h in Headers */,
                                1AF8E11A1256592600230FF7 /* ProxyServer.h in Headers */,
+                               FF945ECC161F7F3600971BC8 /* PseudoElement.h in Headers */,
                                10FB084B14E15C7E00A3DB98 /* PublicURLManager.h in Headers */,
                                E4D687790ED7AE4F006EA978 /* PurgeableBuffer.h in Headers */,
                                7E33CD01127F340D00BE8F17 /* PurgePriority.h in Headers */,
                                514C76740CE923A1007EF3CD /* ProtectionSpace.cpp in Sources */,
                                1AF8E13312565A4400230FF7 /* ProxyServer.cpp in Sources */,
                                1AF8E1C3125673E000230FF7 /* ProxyServerCFNet.cpp in Sources */,
+                               FF945ECB161F7F3600971BC8 /* PseudoElement.cpp in Sources */,
                                E4D687770ED7AE3D006EA978 /* PurgeableBufferMac.cpp in Sources */,
                                550A0BC9085F6039007353D6 /* QualifiedName.cpp in Sources */,
                                379E371613736A6600B9E919 /* QuotedPrintable.cpp in Sources */,
index fcb5695..3a179b8 100644 (file)
 #include "PositionIterator.cpp"
 #include "ProcessingInstruction.cpp"
 #include "ProgressEvent.cpp"
+#include "PseudoElement.cpp"
 #include "Range.cpp"
 #include "RangeException.cpp"
 #include "RegisteredEventListener.cpp"
index dd13168..59dfe6d 100644 (file)
@@ -61,6 +61,7 @@
 #include "NodeRenderingContext.h"
 #include "Page.h"
 #include "PointerLockController.h"
+#include "PseudoElement.h"
 #include "RenderRegion.h"
 #include "RenderView.h"
 #include "RenderWidget.h"
@@ -1016,7 +1017,9 @@ void Element::attach()
     } else {
         if (firstChild())
             parentPusher.push();
+        updatePseudoElement(BEFORE);
         ContainerNode::attach();
+        updatePseudoElement(AFTER);
     }
 
     if (hasRareData()) {   
@@ -1046,6 +1049,8 @@ void Element::detach()
     cancelFocusAppearanceUpdate();
     if (hasRareData()) {
         ElementRareData* data = elementRareData();
+        data->setPseudoElement(BEFORE, 0);
+        data->setPseudoElement(AFTER, 0);
         data->setIsInCanvasSubtree(false);
         data->resetComputedStyle();
     }
@@ -1197,6 +1202,8 @@ void Element::recalcStyle(StyleChange change)
         }
     }
 
+    updatePseudoElement(BEFORE, change);
+
     // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
     // For now we will just worry about the common case, since it's a lot trickier to get the second case right
     // without doing way too much re-resolution.
@@ -1221,6 +1228,8 @@ void Element::recalcStyle(StyleChange change)
         forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
     }
 
+    updatePseudoElement(AFTER, change);
+
     clearNeedsStyleRecalc();
     clearChildNeedsStyleRecalc();
     
@@ -1803,6 +1812,47 @@ void Element::normalizeAttributes()
     }
 }
 
+void Element::updatePseudoElement(PseudoId pseudoId, StyleChange change)
+{
+    PseudoElement* existing = hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
+    if (existing) {
+        // PseudoElement styles hang off the parent element's style so we need to manually tell
+        // the pseudo element it's style has changed (or we could pass Force).
+        existing->setNeedsStyleRecalc();
+        existing->recalcStyle(change);
+        if (!existing->renderer())
+            elementRareData()->setPseudoElement(pseudoId, 0);
+    } else if (RefPtr<PseudoElement> element = createPseudoElementIfNeeded(pseudoId)) {
+        element->attach();
+        ensureElementRareData()->setPseudoElement(pseudoId, element);
+    }
+}
+
+PassRefPtr<PseudoElement> Element::createPseudoElementIfNeeded(PseudoId pseudoId)
+{
+    if (!document()->styleSheetCollection()->usesBeforeAfterRules())
+        return 0;
+
+    if (isPseudoElement() || !renderer() || !renderer()->canHaveGeneratedChildren())
+        return 0;
+
+    RenderStyle* style = renderer()->getCachedPseudoStyle(pseudoId);
+    if (!style || !PseudoElement::pseudoRendererIsNeeded(style))
+        return 0;
+
+    return PseudoElement::create(this, pseudoId);
+}
+
+PseudoElement* Element::beforePseudoElement() const
+{
+    return hasRareData() ? elementRareData()->pseudoElement(BEFORE) : 0;
+}
+
+PseudoElement* Element::afterPseudoElement() const
+{
+    return hasRareData() ? elementRareData()->pseudoElement(AFTER) : 0;
+}
+
 // ElementTraversal API
 Element* Element::firstElementChild() const
 {
index c708775..d9b8c49 100644 (file)
@@ -43,6 +43,7 @@ class ElementRareData;
 class ElementShadow;
 class IntSize;
 class Localizer;
+class PseudoElement;
 class RenderRegion;
 class ShadowRoot;
 class WebKitAnimationList;
@@ -345,6 +346,9 @@ public:
     virtual void finishParsingChildren();
     virtual void beginParsingChildren();
 
+    PseudoElement* beforePseudoElement() const;
+    PseudoElement* afterPseudoElement() const;
+
     // ElementTraversal API
     Element* firstElementChild() const;
     Element* lastElementChild() const;
@@ -475,6 +479,9 @@ protected:
     void classAttributeChanged(const AtomicString& newClassString);
 
 private:
+    void updatePseudoElement(PseudoId, StyleChange = NoChange);
+    PassRefPtr<PseudoElement> createPseudoElementIfNeeded(PseudoId);
+
     void updateInvalidAttributes() const;
 
     void scrollByUnits(int units, ScrollGranularity);
index b4bc8e2..68738d1 100644 (file)
@@ -29,6 +29,7 @@
 #include "HTMLCollection.h"
 #include "NamedNodeMap.h"
 #include "NodeRareData.h"
+#include "PseudoElement.h"
 #include "StyleInheritedData.h"
 #include <wtf/OwnPtr.h>
 
@@ -41,6 +42,9 @@ public:
     ElementRareData();
     virtual ~ElementRareData();
 
+    void setPseudoElement(PseudoId, PassRefPtr<PseudoElement>);
+    PseudoElement* pseudoElement(PseudoId) const;
+
     void resetComputedStyle();
 
     using NodeRareData::needsFocusAppearanceUpdateSoonAfterAttach;
@@ -119,6 +123,9 @@ public:
     OwnPtr<ElementShadow> m_shadow;
     OwnPtr<NamedNodeMap> m_attributeMap;
 
+    RefPtr<PseudoElement> m_generatedBefore;
+    RefPtr<PseudoElement> m_generatedAfter;
+
     IntSize m_savedLayerScrollOffset;
 };
 
@@ -137,6 +144,33 @@ inline ElementRareData::~ElementRareData()
     ASSERT(!m_shadow);
 }
 
+inline void ElementRareData::setPseudoElement(PseudoId pseudoId, PassRefPtr<PseudoElement> element)
+{
+    switch (pseudoId) {
+    case BEFORE:
+        m_generatedBefore = element;
+        break;
+    case AFTER:
+        m_generatedAfter = element;
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+}
+
+inline PseudoElement* ElementRareData::pseudoElement(PseudoId pseudoId) const
+{
+    switch (pseudoId) {
+    case BEFORE:
+        return m_generatedBefore.get();
+    case AFTER:
+        return m_generatedAfter.get();
+    default:
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
+
 inline void ElementRareData::resetComputedStyle()
 {
     m_computedStyle.clear();
index 14086b3..145527e 100644 (file)
@@ -466,6 +466,34 @@ TreeScope* Node::treeScope() const
     return scope ? scope : m_document;
 }
 
+Node* Node::pseudoAwarePreviousSibling() const
+{
+    if (isElementNode() && !previousSibling()) {
+        Element* parent = parentOrHostElement();
+        if (!parent)
+            return 0;
+        if (isAfterPseudoElement() && parent->lastChild())
+            return parent->lastChild();
+        if (!isBeforePseudoElement())
+            return parent->beforePseudoElement();
+    }
+    return previousSibling();
+}
+
+Node* Node::pseudoAwareNextSibling() const
+{
+    if (isElementNode() && !nextSibling()) {
+        Element* parent = parentOrHostElement();
+        if (!parent)
+            return 0;
+        if (isBeforePseudoElement() && parent->firstChild())
+            return parent->firstChild();
+        if (!isAfterPseudoElement())
+            return parent->afterPseudoElement();
+    }
+    return nextSibling();
+}
+
 NodeRareData* Node::rareData() const
 {
     ASSERT(hasRareData());
@@ -1183,7 +1211,15 @@ static void checkAcceptChild(Node* newParent, Node* newChild, ExceptionCode& ec)
         ec = NOT_FOUND_ERR;
         return;
     }
-    
+
+    // Assert because this should never happen, but also protect non-debug builds
+    // from tree corruption.
+    ASSERT(!newChild->isPseudoElement());
+    if (newChild->isPseudoElement()) {
+        ec = HIERARCHY_REQUEST_ERR;
+        return;
+    }
+
     if (newParent->isReadOnlyNode()) {
         ec = NO_MODIFICATION_ALLOWED_ERR;
         return;
index 5d8640c..1f225b5 100644 (file)
@@ -172,6 +172,9 @@ public:
     bool hasAttributes() const;
     NamedNodeMap* attributes() const;
 
+    Node* pseudoAwarePreviousSibling() const;
+    Node* pseudoAwareNextSibling() const;
+
     virtual KURL baseURI() const;
     
     void getSubresourceURLs(ListHashSet<KURL>&) const;
@@ -216,6 +219,19 @@ public:
     bool isHTMLElement() const { return getFlag(IsHTMLFlag); }
     bool isSVGElement() const { return getFlag(IsSVGFlag); }
 
+    bool isPseudoElement() const
+    {
+        return pseudoId() != NOPSEUDO;
+    }
+
+    PseudoId pseudoId() const
+    {
+        return (isElementNode() && hasCustomCallbacks()) ? virtualPseudoId() : NOPSEUDO;
+    }
+
+    virtual PseudoId virtualPseudoId() const { return NOPSEUDO; }
+    bool isBeforePseudoElement() const { return pseudoId() == BEFORE; }
+    bool isAfterPseudoElement() const { return pseudoId() == AFTER; }
     virtual bool isMediaControlElement() const { return false; }
     virtual bool isMediaControls() const { return false; }
     bool isStyledElement() const { return getFlag(IsStyledElementFlag); }
index 21f1c3f..3a281a7 100644 (file)
@@ -35,6 +35,7 @@
 #include "HTMLNames.h"
 #include "HTMLShadowElement.h"
 #include "Node.h"
+#include "PseudoElement.h"
 #include "RenderFullScreen.h"
 #include "RenderNamedFlowThread.h"
 #include "RenderObject.h"
@@ -93,6 +94,14 @@ RenderObject* NodeRenderingContext::nextRenderer() const
     if (m_parentDetails.node() && !m_parentDetails.node()->attached())
         return 0;
 
+    // FIXME: This is wrong when the next sibling was actually moved around by shadow insertion points.
+    if (m_node->isPseudoElement()) {
+        Node* sibling = m_node->pseudoAwareNextSibling();
+        while (sibling && !sibling->renderer())
+            sibling = sibling->pseudoAwareNextSibling();
+        return sibling ? sibling->renderer() : 0;
+    }
+
     ComposedShadowTreeWalker walker(m_node);
     do {
         walker.nextSibling();
diff --git a/Source/WebCore/dom/PseudoElement.cpp b/Source/WebCore/dom/PseudoElement.cpp
new file mode 100644 (file)
index 0000000..ad5e0cf
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "PseudoElement.h"
+
+#include "ContentData.h"
+#include "NodeRenderStyle.h"
+#include "NodeRenderingContext.h"
+#include "RenderCounter.h"
+#include "RenderImage.h"
+#include "RenderImageResourceStyleImage.h"
+#include "RenderQuote.h"
+#include "RenderTextFragment.h"
+#include "StyleInheritedData.h"
+#include "Text.h"
+
+namespace WebCore {
+
+const QualifiedName& pseudoElementName()
+{
+    DEFINE_STATIC_LOCAL(QualifiedName, name, (nullAtom, "<generated>", nullAtom));
+    return name;
+}
+
+PseudoElement::PseudoElement(Element* parent, PseudoId pseudoId)
+    : Element(pseudoElementName(), parent->document(), CreateElement)
+    , m_pseudoId(pseudoId)
+{
+    setParentOrHostNode(parent);
+    setHasCustomCallbacks();
+}
+
+bool PseudoElement::pseudoRendererIsNeeded(RenderStyle* style)
+{
+    // Renderers are only needed if there is non empty (or none) content, or if this
+    // is a region thread it could also have content flowed into it.
+    bool hasContent = style->contentData() && style->contentData()->type() != CONTENT_NONE;
+    bool hasRegionThread = !style->regionThread().isEmpty();
+    return hasContent || hasRegionThread;
+}
+
+PassRefPtr<RenderStyle> PseudoElement::customStyleForRenderer()
+{
+    return parentOrHostElement()->renderer()->getCachedPseudoStyle(pseudoId());
+}
+
+void PseudoElement::attach()
+{
+    ASSERT(!renderer());
+
+    Element::attach();
+
+    RenderObject* renderer = this->renderer();
+    if (!renderer || !renderer->style()->regionThread().isEmpty())
+        return;
+
+    ASSERT(renderStyle()->contentData());
+
+    for (const ContentData* content = renderStyle()->contentData(); content; content = content->next()) {
+        RenderObject* child = createRendererForContent(content);
+        if (!child)
+            continue;
+        if (renderer->isChildAllowed(child, renderStyle()))
+            renderer->addChild(child);
+        else
+            child->destroy();
+    }
+}
+
+bool PseudoElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    return Element::rendererIsNeeded(context) && pseudoRendererIsNeeded(context.style());
+}
+
+void PseudoElement::updateChildStyle(RenderObject* child) const
+{
+    // We only manage the style for the generated content which must be text or images.
+    if (!child->isText() && !child->isImage())
+        return;
+
+    // The style for the RenderTextFragment for first letter is managed by an enclosing block, not by us.
+    if (child->style() && child->style()->styleType() == FIRST_LETTER)
+        return;
+
+    // Fast path for text where we can share the style. For images we must take the slower
+    // inherit path so the width/height of the pseudo element doesn't change the size of the
+    // image.
+    if (child->isText()) {
+        child->setStyle(renderStyle());
+        return;
+    }
+
+    RefPtr<RenderStyle> style = RenderStyle::create();
+    style->inheritFrom(renderStyle());
+    child->setStyle(style.release());
+}
+
+void PseudoElement::didRecalcStyle(StyleChange)
+{
+    if (!renderer())
+        return;
+
+    // The renderers inside pseudo elements are anonymous so they don't get notified of recalcStyle and must have
+    // the stylr propagated downward manually similar to RenderObject::propagateStyleToAnonymousChildren.
+    RenderObject* renderer = this->renderer();
+    for (RenderObject* child = renderer->nextInPreOrder(renderer); child; child = child->nextInPreOrder(renderer))
+        updateChildStyle(child);
+}
+
+RenderObject* PseudoElement::createRendererForContent(const ContentData* content) const
+{
+    RenderArena* arena = this->renderer()->renderArena();
+    RenderObject* renderer = 0;
+
+    switch (content->type()) {
+    case CONTENT_NONE:
+        ASSERT_NOT_REACHED();
+        return 0;
+    case CONTENT_TEXT:
+        renderer = new (arena) RenderTextFragment(document(), static_cast<const TextContentData*>(content)->text().impl());
+        break;
+    case CONTENT_OBJECT: {
+        RenderImage* image = new (arena) RenderImage(document());
+        // FIXME: This might be wrong since it causes a style change. See RenderObject::createObject.
+        updateChildStyle(image);
+        if (const StyleImage* styleImage = static_cast<const ImageContentData*>(content)->image())
+            image->setImageResource(RenderImageResourceStyleImage::create(const_cast<StyleImage*>(styleImage)));
+        else
+            image->setImageResource(RenderImageResource::create());
+        return image;
+    }
+    case CONTENT_COUNTER:
+        renderer = new (arena) RenderCounter(document(), *static_cast<const CounterContentData*>(content)->counter());
+        break;
+    case CONTENT_QUOTE:
+        renderer = new (arena) RenderQuote(document(), static_cast<const QuoteContentData*>(content)->quote());
+        break;
+    }
+
+    ASSERT(renderer);
+    updateChildStyle(renderer);
+
+    return renderer;
+}
+
+} // namespace
diff --git a/Source/WebCore/dom/PseudoElement.h b/Source/WebCore/dom/PseudoElement.h
new file mode 100644 (file)
index 0000000..926866d
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PseudoElement_h
+#define PseudoElement_h
+
+#include "Element.h"
+#include "RenderStyleConstants.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class ContentData;
+
+class PseudoElement : public Element {
+public:
+    static PassRefPtr<PseudoElement> create(Element* parent, PseudoId pseudoId)
+    {
+        return adoptRef(new PseudoElement(parent, pseudoId));
+    }
+
+    static bool pseudoRendererIsNeeded(RenderStyle*);
+
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
+    virtual void attach() OVERRIDE;
+    virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE;
+    virtual PseudoId virtualPseudoId() const OVERRIDE { return m_pseudoId; }
+
+private:
+    PseudoElement(Element*, PseudoId);
+    virtual void didRecalcStyle(StyleChange) OVERRIDE;
+    void updateChildStyle(RenderObject*) const;
+    RenderObject* createRendererForContent(const ContentData*) const;
+
+    PseudoId m_pseudoId;
+};
+
+inline PseudoElement* toPseudoElement(Node* node)
+{
+    ASSERT(!node || node->isPseudoElement());
+    return static_cast<PseudoElement*>(node);
+}
+
+inline const PseudoElement* toPseudoElement(const Node* node)
+{
+    ASSERT(!node || node->isPseudoElement());
+    return static_cast<const PseudoElement*>(node);
+}
+
+// This will catch anyone doing an unnecessary cast.
+void toPseudoElement(const Element*);
+
+const QualifiedName& pseudoElementName();
+
+} // namespace
+
+#endif
index cc39056..140f24a 100644 (file)
@@ -261,11 +261,15 @@ void HitTestResult::setToNonShadowAncestor()
 
 void HitTestResult::setInnerNode(Node* n)
 {
+    if (n && n->isPseudoElement())
+        n = n->parentOrHostNode();
     m_innerNode = n;
 }
     
 void HitTestResult::setInnerNonSharedNode(Node* n)
 {
+    if (n && n->isPseudoElement())
+        n = n->parentOrHostNode();
     m_innerNonSharedNode = n;
 }
 
index 89c4c04..fb1ece3 100755 (executable)
@@ -346,12 +346,6 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
     propagateStyleToAnonymousChildren(true);    
     m_lineHeight = -1;
 
-    // Update pseudos for :before and :after now.
-    if (!isAnonymous() && document()->styleSheetCollection()->usesBeforeAfterRules() && canHaveGeneratedChildren()) {
-        updateBeforeAfterContent(BEFORE);
-        updateBeforeAfterContent(AFTER);
-    }
-
     // After our style changed, if we lose our ability to propagate floats into next sibling
     // blocks, then we need to find the top most parent containing that overhanging float and
     // then mark its descendants with floats for layout and clear all floats from its next
@@ -383,14 +377,6 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty
     }
 }
 
-void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId)
-{
-    // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
-    if (parent() && parent()->createsAnonymousWrapper())
-        return;
-    children()->updateBeforeAfterContent(this, pseudoId);
-}
-
 RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
 {
     if (beforeChild && beforeChild->parent() == this)
@@ -602,13 +588,7 @@ void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
     RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
     RenderBoxModelObject* currChild = this;
     RenderObject* currChildNextSibling = currChild->nextSibling();
-    bool documentUsesBeforeAfterRules = document()->styleSheetCollection()->usesBeforeAfterRules();
 
-    // Note: |this| can be destroyed inside this loop if it is an empty anonymous
-    // block and we try to call updateBeforeAfterContent inside which removes the
-    // generated content and additionally cleans up |this| empty anonymous block.
-    // See RenderBlock::removeChild(). DO NOT reference any local variables to |this|
-    // after this point.
     while (curr && curr != fromBlock) {
         ASSERT(curr->isRenderBlock());
         
@@ -631,16 +611,6 @@ void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
             cloneBlock->setContinuation(oldCont);
         }
 
-        // Someone may have indirectly caused a <q> to split.  When this happens, the :after content
-        // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that the inline's :after
-        // content gets properly destroyed.
-        bool isLastChild = (currChildNextSibling == blockCurr->lastChild());
-        if (documentUsesBeforeAfterRules)
-            blockCurr->children()->updateBeforeAfterContent(blockCurr, AFTER);
-        if (isLastChild && currChildNextSibling != blockCurr->lastChild())
-            currChildNextSibling = 0; // We destroyed the last child, so now we need to update
-                                      // the value of currChildNextSibling.
-
         // Now we need to take all of the children starting from the first child
         // *after* currChild and append them all to the clone.
         blockCurr->moveChildrenTo(cloneBlock, currChildNextSibling, 0, true);
@@ -872,23 +842,6 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild,
             if (!isAnonymousBlock())
                 setContinuation(newBox);
 
-            // Someone may have put a <p> inside a <q>, causing a split.  When this happens, the :after content
-            // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that our :after
-            // content gets properly destroyed.
-            bool isFirstChild = (beforeChild == firstChild());
-            bool isLastChild = (beforeChild == lastChild());
-            if (document()->styleSheetCollection()->usesBeforeAfterRules())
-                children()->updateBeforeAfterContent(this, AFTER);
-            if (isLastChild && beforeChild != lastChild()) {
-                // We destroyed the last child, so now we need to update our insertion
-                // point to be 0. It's just a straight append now.
-                beforeChild = 0;
-            } else if (isFirstChild && beforeChild != firstChild()) {
-                // If beforeChild was the last anonymous block that collapsed,
-                // then we need to update its value.
-                beforeChild = firstChild();
-            }
-
             splitFlow(beforeChild, newBox, newChild, oldContinuation);
             return;
         }
@@ -1865,16 +1818,6 @@ RenderBoxModelObject* RenderBlock::createReplacementRunIn(RenderBoxModelObject*
 {
     ASSERT(runIn->isRunIn());
 
-    // First we destroy any :before/:after content. It will be regenerated by the new run-in.
-    // Exception is if the run-in itself is generated.
-    if (runIn->style()->styleType() != BEFORE && runIn->style()->styleType() != AFTER) {
-        RenderObject* generatedContent;
-        if (runIn->getCachedPseudoStyle(BEFORE) && (generatedContent = runIn->beforePseudoElementRenderer()))
-            generatedContent->destroy();
-        if (runIn->getCachedPseudoStyle(AFTER) && (generatedContent = runIn->afterPseudoElementRenderer()))
-            generatedContent->destroy();
-    }
-
     bool newRunInShouldBeBlock = !runIn->isRenderBlock();
     Node* runInNode = runIn->node();
     RenderBoxModelObject* newRunIn = 0;
@@ -7429,7 +7372,10 @@ const char* RenderBlock::renderName() const
         return "RenderBlock (anonymous multi-column span)";
     if (isAnonymousBlock())
         return "RenderBlock (anonymous)";
-    else if (isAnonymous())
+    if (isAnonymous())
+        return "RenderBlock (generated)";
+    // FIXME: Temporary hack while the new generated content system is being implemented.
+    if (isPseudoElement())
         return "RenderBlock (generated)";
     if (isRelPositioned())
         return "RenderBlock (relative positioned)";
index 6e7ee63..3969555 100644 (file)
@@ -542,8 +542,6 @@ private:
     static void removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*&, TrackedContainerMap*&);
 
     virtual void borderFitAdjust(LayoutRect&) const; // Shrink the box in which the border paints if border-fit is set.
-
-    virtual void updateBeforeAfterContent(PseudoId);
     
     virtual RootInlineBox* createRootInlineBox(); // Subclassed by SVG and Ruby.
 
index 7103e6e..f7eaf06 100644 (file)
@@ -149,14 +149,6 @@ bool RenderButton::canHaveGeneratedChildren() const
     return !node()->hasTagName(inputTag);
 }
 
-void RenderButton::updateBeforeAfterContent(PseudoId type)
-{
-    if (m_inner)
-        m_inner->children()->updateBeforeAfterContent(m_inner, type, this);
-    else
-        children()->updateBeforeAfterContent(this, type);
-}
-
 LayoutRect RenderButton::controlClipRect(const LayoutPoint& additionalOffset) const
 {
     // Clip to the padding box to at least give content the extra padding space.
index 5be62b0..a7afb5d 100644 (file)
@@ -50,8 +50,6 @@ public:
     void setupInnerStyle(RenderStyle*);
     virtual void updateFromElement();
 
-    virtual void updateBeforeAfterContent(PseudoId);
-
     virtual bool canHaveGeneratedChildren() const OVERRIDE;
     virtual bool hasControlClip() const { return true; }
     virtual LayoutRect controlClipRect(const LayoutPoint&) const;
index 24c8633..b233c49 100644 (file)
@@ -501,7 +501,7 @@ PassRefPtr<StringImpl> RenderCounter::originalText() const
         while (true) {
             if (!beforeAfterContainer)
                 return 0;
-            if (!beforeAfterContainer->isAnonymous())
+            if (!beforeAfterContainer->isAnonymous() && !beforeAfterContainer->isPseudoElement())
                 return 0; // RenderCounters are restricted to before and after pseudo elements
             PseudoId containerStyle = beforeAfterContainer->style()->styleType();
             if ((containerStyle == BEFORE) || (containerStyle == AFTER))
index 05aecae..a701622 100644 (file)
@@ -1085,6 +1085,10 @@ LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool
 
 const char *RenderDeprecatedFlexibleBox::renderName() const
 {
+    // FIXME: Temporary hack while the new generated content system is being implemented.
+    if (isPseudoElement())
+        return "RenderDeprecatedFlexibleBox (generated)";
+
     if (isFloating())
         return "RenderDeprecatedFlexibleBox (floating)";
     if (isOutOfFlowPositioned())
index 6e293cc..a76f3a7 100644 (file)
@@ -203,6 +203,10 @@ LayoutPoint RenderGrid::findChildLogicalPosition(RenderBox* child, const Vector<
 
 const char* RenderGrid::renderName() const
 {
+    // FIXME: Temporary hack while the new generated content system is being implemented.
+    if (isPseudoElement())
+        return "RenderGrid (generated)";
+
     if (isFloating())
         return "RenderGrid (floating)";
     if (isOutOfFlowPositioned())
index c9f8d7b..24a6cb8 100644 (file)
@@ -40,8 +40,6 @@
 #include "TransformState.h"
 #include "VisiblePosition.h"
 
-#include <wtf/TemporaryChange.h>
-
 #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(WIDGET_REGION)
 #include "Frame.h"
 #endif
@@ -169,18 +167,11 @@ void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
     // need to pass its style on to anyone else.
     RenderStyle* newStyle = style();
     RenderInline* continuation = inlineElementContinuation();
-    {
-        TemporaryChange<bool> enableAfter(RenderObjectChildList::s_enableUpdateBeforeAfterContent, false);
-        RenderInline* nextInlineElementCont = 0;
-        for (RenderInline* currCont = continuation; currCont; currCont = nextInlineElementCont) {
-            nextInlineElementCont = currCont->inlineElementContinuation();
-            // We need to update :after content for the last continuation in the chain.
-            RenderObjectChildList::s_enableUpdateBeforeAfterContent = !nextInlineElementCont;
-            RenderBoxModelObject* nextCont = currCont->continuation();
-            currCont->setContinuation(0);
-            currCont->setStyle(newStyle);
-            currCont->setContinuation(nextCont);
-        }
+    for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineElementContinuation()) {
+        RenderBoxModelObject* nextCont = currCont->continuation();
+        currCont->setContinuation(0);
+        currCont->setStyle(newStyle);
+        currCont->setContinuation(nextCont);
     }
 
     // If an inline's in-flow positioning has changed then any descendant blocks will need to change their in-flow positioning accordingly.
@@ -201,12 +192,6 @@ void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
         }
         m_alwaysCreateLineBoxes = alwaysCreateLineBoxes;
     }
-
-    // Update pseudos for :before and :after now.
-    if (!isAnonymous() && document()->styleSheetCollection()->usesBeforeAfterRules()) {
-        children()->updateBeforeAfterContent(this, BEFORE);
-        children()->updateBeforeAfterContent(this, AFTER);
-    }
 }
 
 void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout)
@@ -329,16 +314,6 @@ void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderOb
         RenderBoxModelObject* oldContinuation = continuation();
         setContinuation(newBox);
 
-        // Someone may have put a <p> inside a <q>, causing a split.  When this happens, the :after content
-        // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that our :after
-        // content gets properly destroyed.
-        bool isLastChild = (beforeChild == lastChild());
-        if (document()->styleSheetCollection()->usesBeforeAfterRules())
-            children()->updateBeforeAfterContent(this, 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.
-
         splitFlow(beforeChild, newBox, newChild, oldContinuation);
         return;
     }
@@ -405,12 +380,6 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
             inlineCurr->setContinuation(cloneInline);
             cloneInline->setContinuation(oldCont);
 
-            // Someone may have indirectly caused a <q> to split.  When this happens, the :after content
-            // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that the inline's :after
-            // content gets properly destroyed.
-            if (document()->styleSheetCollection()->usesBeforeAfterRules())
-                inlineCurr->children()->updateBeforeAfterContent(inlineCurr, AFTER);
-
             // Now we need to take all of the children starting from the first child
             // *after* currChild and append them all to the clone.
             o = currChild->nextSibling();
@@ -763,6 +732,9 @@ const char* RenderInline::renderName() const
         return "RenderInline (sticky positioned)";
     if (isAnonymous())
         return "RenderInline (generated)";
+    // FIXME: Temporary hack while the new generated content system is being implemented.
+    if (isPseudoElement())
+        return "RenderInline (generated)";
     if (isRunIn())
         return "RenderInline (run-in)";
     return "RenderInline";
index 89d99b3..3af4104 100644 (file)
@@ -268,7 +268,6 @@ void RenderListItem::updateMarkerLocation()
             if (m_marker->preferredLogicalWidthsDirty())
                 m_marker->computePreferredLogicalWidths();
             // If markerPar is an anonymous block that has lost all its children, destroy it.
-            // Extraneous anonymous blocks can cause problems for RenderBlock::updateBeforeAfterContent.
             if (markerPar && markerPar->isAnonymousBlock() && !markerPar->firstChild() && !toRenderBlock(markerPar)->continuation())
                 markerPar->destroy();
         }
index 221cb4d..aada440 100644 (file)
@@ -146,6 +146,10 @@ void RenderMultiColumnBlock::ensureColumnSets()
 
 const char* RenderMultiColumnBlock::renderName() const
 {    
+    // FIXME: Temporary hack while the new generated content system is being implemented.
+    if (isPseudoElement())
+        return "RenderMultiColumnBlock (generated)";
+
     if (isFloating())
         return "RenderMultiColumnBlock (floating)";
     if (isOutOfFlowPositioned())
index ef6e784..330589e 100755 (executable)
@@ -130,7 +130,7 @@ RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
     // Works only if we have exactly one piece of content and it's a URL.
     // Otherwise acts as if we didn't support this feature.
     const ContentData* contentData = style->contentData();
-    if (contentData && !contentData->next() && contentData->isImage() && doc != node) {
+    if (contentData && !contentData->next() && contentData->isImage() && doc != node && !node->isPseudoElement()) {
         RenderImage* image = new (arena) RenderImage(node);
         // RenderImageResourceStyleImage requires a style being present on the image but we don't want to
         // trigger a style change now as the node is not fully attached. Moving this code to style change
index 408788e..3f2b544 100644 (file)
@@ -317,6 +317,8 @@ private:
 public:
     RenderArena* renderArena() const { return document()->renderArena(); }
 
+    bool isPseudoElement() const { return node() && node()->isPseudoElement(); }
+
     virtual bool isBR() const { return false; }
     virtual bool isBlockFlow() const { return false; }
     virtual bool isBoxModelObject() const { return false; }
@@ -609,7 +611,14 @@ public:
     // Returns the styled node that caused the generation of this renderer.
     // This is the same as node() except for renderers of :before and :after
     // pseudo elements for which their parent node is returned.
-    Node* generatingNode() const { return m_node == document() ? 0 : m_node; }
+    Node* generatingNode() const
+    {
+        // FIXME: Fix the DOM traversals in RenderCounter and remove the use of generatingNode().
+        Node* node = m_node == document() ? 0 : m_node;
+        if (node && node->isPseudoElement())
+            return node->parentOrHostNode();
+        return node;
+    }
     void setNode(Node* node) { m_node = node; }
 
     Document* document() const { return m_node->document(); }
index fec10c1..be34e8f 100644 (file)
@@ -45,8 +45,6 @@
 
 namespace WebCore {
 
-bool RenderObjectChildList::s_enableUpdateBeforeAfterContent = true;
-
 void RenderObjectChildList::destroyLeftoverChildren()
 {
     while (firstChild()) {
@@ -197,23 +195,6 @@ void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* c
         owner->document()->axObjectCache()->childrenChanged(owner);
 }
 
-static RenderObject* findBeforeAfterParent(RenderObject* object)
-{
-    // Only table parts and flex-boxes need to search for the :before or :after parent
-    // FIXME: We could likely get away without this check and always look for the right parent.
-    if (!(object->isTable() || object->isTableSection() || object->isTableRow() || object->isFlexibleBoxIncludingDeprecated()))
-        return object;
-
-    // If there is a :first-letter style applied on the :before or :after content,
-    // then we want the parent of the first-letter block
-    RenderObject* beforeAfterParent = object;
-    while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage())
-        && (beforeAfterParent->style()->styleType() != FIRST_LETTER))
-        beforeAfterParent = beforeAfterParent->firstChild();
-
-    return beforeAfterParent ? beforeAfterParent->parent() : 0;
-}
-
 RenderObject* RenderObjectChildList::beforePseudoElementRenderer(const RenderObject* owner) const
 {
     // An anonymous (generated) inline run-in that has PseudoId BEFORE must come from a grandparent.
@@ -260,239 +241,4 @@ RenderObject* RenderObjectChildList::afterPseudoElementRenderer(const RenderObje
     return last;
 }
 
-void RenderObjectChildList::updateBeforeAfterStyle(RenderObject* child, PseudoId type, RenderStyle* pseudoElementStyle)
-{
-    if (!child || child->style()->styleType() != type)
-        return;
-
-    // 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;
-
-    // When beforeAfterParent is not equal to child (e.g. in tables),
-    // we need to create new styles inheriting from pseudoElementStyle
-    // on all the intermediate parents (leaving their display same).
-    if (beforeAfterParent != child) {
-        RenderObject* curr = beforeAfterParent;
-        while (curr && curr != child) {
-            ASSERT(curr->isAnonymous());
-            RefPtr<RenderStyle> newStyle = RenderStyle::create();
-            newStyle->inheritFrom(pseudoElementStyle);
-            newStyle->setDisplay(curr->style()->display());
-            newStyle->setStyleType(curr->style()->styleType());
-            curr->setStyle(newStyle);
-            curr = curr->parent();
-        }
-    }
-
-    // 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 {
-            // RenderListItem may insert a list marker here. We do not need to care about this case.
-            // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
-            ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
-        }
-    }
-}
-
-static RenderObject* createRendererForBeforeAfterContent(RenderObject* owner, const ContentData* content, RenderStyle* pseudoElementStyle)
-{
-    RenderObject* renderer = 0;
-    switch (content->type()) {
-    case CONTENT_NONE:
-        break;
-    case CONTENT_TEXT:
-        renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, static_cast<const TextContentData*>(content)->text().impl());
-        renderer->setStyle(pseudoElementStyle);
-        break;
-    case CONTENT_OBJECT: {
-        RenderImage* image = new (owner->renderArena()) RenderImage(owner->document()); // anonymous object
-        RefPtr<RenderStyle> style = RenderStyle::create();
-        style->inheritFrom(pseudoElementStyle);
-        image->setStyle(style.release());
-        if (const StyleImage* styleImage = static_cast<const ImageContentData*>(content)->image())
-            image->setImageResource(RenderImageResourceStyleImage::create(const_cast<StyleImage*>(styleImage)));
-        else
-            image->setImageResource(RenderImageResource::create());
-        renderer = image;
-        break;
-    }
-    case CONTENT_COUNTER:
-        renderer = new (owner->renderArena()) RenderCounter(owner->document(), *static_cast<const CounterContentData*>(content)->counter());
-        renderer->setStyle(pseudoElementStyle);
-        break;
-    case CONTENT_QUOTE:
-        renderer = new (owner->renderArena()) RenderQuote(owner->document(), static_cast<const QuoteContentData*>(content)->quote());
-        renderer->setStyle(pseudoElementStyle);
-        break;
-    }
-    return renderer;
-}
-
-static RenderObject* ensureBeforeAfterContainer(RenderObject* owner, PseudoId type, RenderStyle* pseudoElementStyle, Node* generatingNode, RenderObject* insertBefore)
-{
-    // 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.
-    RenderObject* generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
-    ASSERT(generatingNode); // The styled object cannot be anonymous or else it could not have ':before' or ':after' pseudo elements.
-    generatedContentContainer->setNode(generatingNode); // This allows access to the generatingNode.
-    generatedContentContainer->setStyle(pseudoElementStyle);
-    if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) {
-        // The generated content container is not allowed here -> abort.
-        generatedContentContainer->destroy();
-        return 0;
-    }
-
-    // When we don't have a first child and are part of a continuation chain,
-    // insertBefore is incorrectly set to zero above, which causes the :before
-    // child to end up at the end of continuation chain.
-    // See https://bugs.webkit.org/show_bug.cgi?id=78380.
-    if (!insertBefore && type == BEFORE && owner->virtualContinuation())
-        owner->addChildIgnoringContinuation(generatedContentContainer, 0);
-    else
-        owner->addChild(generatedContentContainer, insertBefore);
-
-    return generatedContentContainer;
-}
-
-void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject)
-{
-    // Double check that the document did in fact use generated content rules.  Otherwise we should not have been called.
-    ASSERT(owner->document()->styleSheetCollection()->usesBeforeAfterRules());
-
-    // In CSS2, before/after pseudo-content cannot nest.  Check this first.
-    if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
-        return;
-    if (!s_enableUpdateBeforeAfterContent)
-        return;
-    
-    if (!styledObject)
-        styledObject = owner;
-
-    RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
-    RenderObject* child;
-    switch (type) {
-    case BEFORE:
-        child = beforePseudoElementRenderer(owner);
-        break;
-    case AFTER:
-        child = afterPseudoElementRenderer(owner);
-        break;
-    default:
-        ASSERT_NOT_REACHED();
-        return;
-    }
-
-    // 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 == BEFORE && owner->isElementContinuation())
-        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 == AFTER && owner->virtualContinuation())
-        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 (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle, owner->document()) == Node::Detach)) {
-        // Nuke the child. 
-        if (child->style()->styleType() == type) {
-            oldContentPresent = false;
-            child->destroy();
-            child = (type == 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->isFloating() &&
-        !pseudoElementStyle->hasOutOfFlowPosition())
-        // 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) {
-        updateBeforeAfterStyle(child, type, pseudoElementStyle);
-        return; // We've updated the generated content. That's all we needed to do.
-    }
-    
-    RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
-    if (insertBefore && insertBefore->isAnonymousBlock() && insertBefore->childrenInline() && !insertBefore->isEmpty()) {
-        // We are going to add the "before" element. We have to check whether the "insertBefore" element
-        // is an anonymous block with inline children. If it is, then we should insert the "before" element
-        // before the first inline child of the anonymous block, otherwise we will end up with the "before"
-        // element in a different block. We do this only when the anonymous block has children, otherwise
-        // we end up with the before element in a wrong block.
-        insertBefore = insertBefore->firstChild();
-    }
-
-    // Nothing goes before the intruded run-in, not even generated content.
-    if (insertBefore && insertBefore->isRunIn() && owner->isRenderBlock()
-        && toRenderBlock(owner)->runInIsPlacedIntoSiblingBlock(insertBefore))
-        insertBefore = insertBefore->nextSibling();
-
-    // 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.
-    // For pseudo-elements that are regions, the container is the RenderRegion.
-    RenderObject* generatedContentContainer = 0;
-
-    if (!pseudoElementStyle->regionThread().isEmpty())
-        generatedContentContainer = ensureBeforeAfterContainer(owner, type, pseudoElementStyle, styledObject->node(), insertBefore);
-    else {
-        // Walk our list of generated content and create render objects for each.
-        for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
-            RenderObject* renderer = createRendererForBeforeAfterContent(owner, content, pseudoElementStyle);
-
-            if (renderer) {
-                if (!generatedContentContainer) {
-                    generatedContentContainer = ensureBeforeAfterContainer(owner, type, pseudoElementStyle, styledObject->node(), insertBefore);
-                    if (!generatedContentContainer) {
-                        renderer->destroy();
-                        return;
-                    }
-                }
-                if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
-                    generatedContentContainer->addChild(renderer);
-                else
-                    renderer->destroy();
-            }
-        }
-    }
-
-    if (!generatedContentContainer)
-        return;
-
-    // Handle placement of run-ins. We do the run-in placement at the end since generatedContentContainer can get destroyed.
-    RenderObject* generatedContentContainerImmediateParent = generatedContentContainer->parent();
-    if (generatedContentContainerImmediateParent->isRenderBlock())
-        toRenderBlock(generatedContentContainerImmediateParent)->placeRunInIfNeeded(generatedContentContainer, PlaceGeneratedRunIn);
-}
-
 } // namespace WebCore
index 3f606db..6d19c70 100644 (file)
@@ -56,16 +56,10 @@ public:
     void appendChildNode(RenderObject* owner, RenderObject*, bool notifyRenderer = true);
     void insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* before, bool notifyRenderer = true);
 
-    void updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject = 0);
     RenderObject* beforePseudoElementRenderer(const RenderObject* owner) const;
     RenderObject* afterPseudoElementRenderer(const RenderObject* owner) const;
 
-public:
-    static bool s_enableUpdateBeforeAfterContent;
-
 private:
-    void updateBeforeAfterStyle(RenderObject* child, PseudoId type, RenderStyle* pseudoElementStyle);
-
     RenderObject* m_firstChild;
     RenderObject* m_lastChild;
 };
index e9765f2..be8313b 100644 (file)
@@ -88,15 +88,4 @@ bool RenderRubyText::avoidsFloats() const
     return true;
 }
 
-void RenderRubyText::updateBeforeAfterContent(PseudoId pseudoId)
-{
-    // RenderRubyText manages its own :before and :after content
-    // and is not handled by its anonymous wrappers RenderRubyRun
-    // and RenderRuby. This contrasts with other ruby children, which
-    // are enclosed in RenderRubyBase and hence they are able to
-    // update their :before, :after content (since RenderRubyBase
-    // is not a anonymous wrapper).
-    return children()->updateBeforeAfterContent(this, pseudoId);
-}
-
 } // namespace WebCore
index f47304c..3a67926 100644 (file)
@@ -46,8 +46,6 @@ public:
 
     virtual bool isChildAllowed(RenderObject*, RenderStyle*) const;
 
-    virtual void updateBeforeAfterContent(PseudoId);
-
 private:
     virtual bool avoidsFloats() const;
 
index a873a51..3a1c7cd 100644 (file)
@@ -209,7 +209,7 @@ protected:
     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
 
 private:
-    virtual const char* renderName() const { return isAnonymous() ? "RenderTableCell (anonymous)" : "RenderTableCell"; }
+    virtual const char* renderName() const { return (isAnonymous() || isPseudoElement()) ? "RenderTableCell (anonymous)" : "RenderTableCell"; }
 
     virtual bool isTableCell() const { return true; }
 
index c86f14c..de61dcd 100644 (file)
@@ -53,14 +53,6 @@ void RenderTableRow::willBeRemovedFromTree()
     section()->setNeedsCellRecalc();
 }
 
-void RenderTableRow::updateBeforeAndAfterContent()
-{
-    if (!isAnonymous() && document()->styleSheetCollection()->usesBeforeAfterRules()) {
-        children()->updateBeforeAfterContent(this, BEFORE);
-        children()->updateBeforeAfterContent(this, AFTER);
-    }
-}
-
 void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
 {
     ASSERT(style()->display() == TABLE_ROW);
@@ -68,9 +60,6 @@ void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* old
     RenderBox::styleDidChange(diff, oldStyle);
     propagateStyleToAnonymousChildren();
 
-    if (parent())
-        updateBeforeAndAfterContent();
-
     if (section() && oldStyle && style()->logicalHeight() != oldStyle->logicalHeight())
         section()->rowLogicalHeightChanged(rowIndex());
 
index 80d4c17..f6d4ff2 100644 (file)
@@ -42,7 +42,6 @@ public:
     RenderTableSection* section() const { return toRenderTableSection(parent()); }
     RenderTable* table() const { return toRenderTable(parent()->parent()); }
 
-    void updateBeforeAndAfterContent();
     void paintOutlineForRowIfNeeded(PaintInfo&, const LayoutPoint&);
 
     static RenderTableRow* createAnonymousWithParentRenderer(const RenderObject*);
@@ -89,7 +88,7 @@ private:
     virtual RenderObjectChildList* virtualChildren() { return children(); }
     virtual const RenderObjectChildList* virtualChildren() const { return children(); }
 
-    virtual const char* renderName() const { return isAnonymous() ? "RenderTableRow (anonymous)" : "RenderTableRow"; }
+    virtual const char* renderName() const { return (isAnonymous() || isPseudoElement()) ? "RenderTableRow (anonymous)" : "RenderTableRow"; }
 
     virtual bool isTableRow() const { return true; }
 
index a9e1667..1408f6c 100644 (file)
@@ -186,7 +186,6 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild
 
     ASSERT(!beforeChild || beforeChild->isTableRow());
     RenderBox::addChild(child, beforeChild);
-    toRenderTableRow(child)->updateBeforeAndAfterContent();
 }
 
 void RenderTableSection::ensureRows(unsigned numRows)
index 02a5299..56c8e17 100644 (file)
@@ -200,7 +200,7 @@ private:
     virtual RenderObjectChildList* virtualChildren() { return children(); }
     virtual const RenderObjectChildList* virtualChildren() const { return children(); }
 
-    virtual const char* renderName() const { return isAnonymous() ? "RenderTableSection (anonymous)" : "RenderTableSection"; }
+    virtual const char* renderName() const { return (isAnonymous() || isPseudoElement()) ? "RenderTableSection (anonymous)" : "RenderTableSection"; }
 
     virtual bool isTableSection() const { return true; }
 
index ac6bd34..cb53a22 100644 (file)
@@ -221,6 +221,9 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o,
 
     if (o.node()) {
         String tagName = getTagName(o.node());
+        // FIXME: Temporary hack to make tests pass by simulating the old generated content output.
+        if (o.isPseudoElement() || (o.parent() && o.parent()->isPseudoElement()))
+            tagName = emptyAtom;
         if (!tagName.isEmpty()) {
             ts << " {" << tagName << "}";
             // flag empty or unstyled AppleStyleSpan because we never