Add infrastructure for :before and :after in DOM
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 5 Dec 2012 21:00:54 +0000 (21:00 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 5 Dec 2012 21:00:54 +0000 (21:00 +0000)
https://bugs.webkit.org/show_bug.cgi?id=103705

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

Add all infrastructure for reimplementing generated content :before and
:after as DOM Elements. Now ElementRareData has two pointers to PseudoElements
for the generated content and Node has methods for traversing the tree
including generated content.

This will allow 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 ifecycle of generated content.

Instead of attempting to land both the infrastructure and enable it at
the same time which has proven problematic due to how drastic this change
is, this patch contains only the support code so a much smaller future
patch can be used to switch it on.

No new behavior, this is just the infrastructure.

* 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::~Element):
(WebCore::Element::detach):
(WebCore::Element::updatePseudoElement):
(WebCore::Element::createPseudoElementIfNeeded):
(WebCore::Element::beforePseudoElement):
(WebCore::Element::afterPseudoElement):
* dom/Element.h:
(Element):
* dom/ElementRareData.h:
(ElementRareData):
(WebCore::ElementRareData::ElementRareData):
(WebCore::ElementRareData::~ElementRareData):
(WebCore::ElementRareData::setPseudoElement):
(WebCore::ElementRareData::pseudoElement):
(WebCore::ElementRareData::releasePseudoElement):
* dom/Node.cpp:
(WebCore::Node::pseudoAwarePreviousSibling):
(WebCore::Node::pseudoAwareNextSibling):
(WebCore::Node::rendererIsEditable):
(WebCore::checkAcceptChild):
* dom/Node.h:
(Node):
(WebCore::Node::isPseudoElement):
(WebCore::Node::isBeforePseudoElement):
(WebCore::Node::isAfterPseudoElement):
(WebCore::Node::pseudoId):
(WebCore::Node::customPseudoId):
* dom/NodeRenderingContext.cpp:
(WebCore::NodeRenderingContext::nextRenderer):
(WebCore::NodeRenderingContext::previousRenderer):
* dom/Position.cpp:
(WebCore::Position::hasRenderedNonAnonymousDescendantsWithHeight):
* dom/PseudoElement.cpp: Added.
(WebCore::pseudoElementTagName):
(WebCore::PseudoElement::PseudoElement):
(WebCore::PseudoElement::customStyleForRenderer):
(WebCore::PseudoElement::attach):
(WebCore::PseudoElement::rendererIsNeeded):
(WebCore::PseudoElement::updateChildStyle):
(WebCore::PseudoElement::didRecalcStyle):
* dom/PseudoElement.h: Added.
(PseudoElement):
(WebCore::PseudoElement::create):
(WebCore::pseudoElementIsNeeded):
* editing/visible_units.cpp:
(WebCore::logicallyPreviousBox):
(WebCore::logicallyNextBox):
(WebCore::startPositionForLine):
(WebCore::endPositionForLine):
* page/animation/AnimationController.cpp:
(WebCore::AnimationController::updateAnimations):
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::setInnerNode):
(WebCore::HitTestResult::setInnerNonSharedNode):
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::isSelectionRoot):
(WebCore::RenderBlock::renderName):
* rendering/RenderCounter.cpp:
(WebCore::RenderCounter::originalText):
* rendering/RenderDeprecatedFlexibleBox.cpp:
(WebCore::RenderDeprecatedFlexibleBox::renderName):
* rendering/RenderInline.cpp:
(WebCore::RenderInline::renderName):
* rendering/RenderMultiColumnBlock.cpp:
(WebCore::RenderMultiColumnBlock::renderName):
* rendering/RenderObject.cpp:
(WebCore::RenderObject::createObject):
(WebCore::RenderObject::setPseudoStyle):
(WebCore::RenderObject::createVisiblePosition):
* rendering/RenderObject.h:
(WebCore::RenderObject::isPseudoElement):
(RenderObject):
(WebCore::RenderObject::generatingNode):
* rendering/RenderTableCell.h:
(WebCore::RenderTableCell::renderName):
* rendering/RenderTableRow.h:
(WebCore::RenderTableRow::renderName):
* rendering/RenderTableSection.h:
(WebCore::RenderTableSection::renderName):
* rendering/RenderTreeAsText.cpp:
(WebCore::RenderTreeAsText::writeRenderObject):
* rendering/style/ContentData.cpp:
(WebCore::ImageContentData::createRenderer):
(WebCore::TextContentData::createRenderer):
(WebCore::CounterContentData::createRenderer):
(WebCore::QuoteContentData::createRenderer):

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

33 files changed:
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/ContainerNode.cpp
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/Position.cpp
Source/WebCore/dom/PseudoElement.cpp [new file with mode: 0644]
Source/WebCore/dom/PseudoElement.h [new file with mode: 0644]
Source/WebCore/editing/visible_units.cpp
Source/WebCore/page/animation/AnimationController.cpp
Source/WebCore/rendering/HitTestResult.cpp
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderCounter.cpp
Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp
Source/WebCore/rendering/RenderInline.cpp
Source/WebCore/rendering/RenderMultiColumnBlock.cpp
Source/WebCore/rendering/RenderObject.cpp
Source/WebCore/rendering/RenderObject.h
Source/WebCore/rendering/RenderTableCell.h
Source/WebCore/rendering/RenderTableRow.h
Source/WebCore/rendering/RenderTableSection.h
Source/WebCore/rendering/RenderTreeAsText.cpp
Source/WebCore/rendering/style/ContentData.cpp

index 9087844..5e10a91 100644 (file)
@@ -1205,6 +1205,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 be4bab4..e6d661f 100644 (file)
@@ -1,3 +1,121 @@
+2012-12-05  Elliott Sprehn  <esprehn@chromium.org>
+
+        Add infrastructure for :before and :after in DOM
+        https://bugs.webkit.org/show_bug.cgi?id=103705
+
+        Reviewed by Eric Seidel.
+
+        Add all infrastructure for reimplementing generated content :before and
+        :after as DOM Elements. Now ElementRareData has two pointers to PseudoElements
+        for the generated content and Node has methods for traversing the tree
+        including generated content.
+
+        This will allow 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 ifecycle of generated content.
+
+        Instead of attempting to land both the infrastructure and enable it at
+        the same time which has proven problematic due to how drastic this change
+        is, this patch contains only the support code so a much smaller future
+        patch can be used to switch it on.
+
+        No new behavior, this is just the infrastructure.
+
+        * 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::~Element):
+        (WebCore::Element::detach):
+        (WebCore::Element::updatePseudoElement):
+        (WebCore::Element::createPseudoElementIfNeeded):
+        (WebCore::Element::beforePseudoElement):
+        (WebCore::Element::afterPseudoElement):
+        * dom/Element.h:
+        (Element):
+        * dom/ElementRareData.h:
+        (ElementRareData):
+        (WebCore::ElementRareData::ElementRareData):
+        (WebCore::ElementRareData::~ElementRareData):
+        (WebCore::ElementRareData::setPseudoElement):
+        (WebCore::ElementRareData::pseudoElement):
+        (WebCore::ElementRareData::releasePseudoElement):
+        * dom/Node.cpp:
+        (WebCore::Node::pseudoAwarePreviousSibling):
+        (WebCore::Node::pseudoAwareNextSibling):
+        (WebCore::Node::rendererIsEditable):
+        (WebCore::checkAcceptChild):
+        * dom/Node.h:
+        (Node):
+        (WebCore::Node::isPseudoElement):
+        (WebCore::Node::isBeforePseudoElement):
+        (WebCore::Node::isAfterPseudoElement):
+        (WebCore::Node::pseudoId):
+        (WebCore::Node::customPseudoId):
+        * dom/NodeRenderingContext.cpp:
+        (WebCore::NodeRenderingContext::nextRenderer):
+        (WebCore::NodeRenderingContext::previousRenderer):
+        * dom/Position.cpp:
+        (WebCore::Position::hasRenderedNonAnonymousDescendantsWithHeight):
+        * dom/PseudoElement.cpp: Added.
+        (WebCore::pseudoElementTagName):
+        (WebCore::PseudoElement::PseudoElement):
+        (WebCore::PseudoElement::customStyleForRenderer):
+        (WebCore::PseudoElement::attach):
+        (WebCore::PseudoElement::rendererIsNeeded):
+        (WebCore::PseudoElement::updateChildStyle):
+        (WebCore::PseudoElement::didRecalcStyle):
+        * dom/PseudoElement.h: Added.
+        (PseudoElement):
+        (WebCore::PseudoElement::create):
+        (WebCore::pseudoElementIsNeeded):
+        * editing/visible_units.cpp:
+        (WebCore::logicallyPreviousBox):
+        (WebCore::logicallyNextBox):
+        (WebCore::startPositionForLine):
+        (WebCore::endPositionForLine):
+        * page/animation/AnimationController.cpp:
+        (WebCore::AnimationController::updateAnimations):
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestResult::setInnerNode):
+        (WebCore::HitTestResult::setInnerNonSharedNode):
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::isSelectionRoot):
+        (WebCore::RenderBlock::renderName):
+        * rendering/RenderCounter.cpp:
+        (WebCore::RenderCounter::originalText):
+        * rendering/RenderDeprecatedFlexibleBox.cpp:
+        (WebCore::RenderDeprecatedFlexibleBox::renderName):
+        * rendering/RenderInline.cpp:
+        (WebCore::RenderInline::renderName):
+        * rendering/RenderMultiColumnBlock.cpp:
+        (WebCore::RenderMultiColumnBlock::renderName):
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::createObject):
+        (WebCore::RenderObject::setPseudoStyle):
+        (WebCore::RenderObject::createVisiblePosition):
+        * rendering/RenderObject.h:
+        (WebCore::RenderObject::isPseudoElement):
+        (RenderObject):
+        (WebCore::RenderObject::generatingNode):
+        * rendering/RenderTableCell.h:
+        (WebCore::RenderTableCell::renderName):
+        * rendering/RenderTableRow.h:
+        (WebCore::RenderTableRow::renderName):
+        * rendering/RenderTableSection.h:
+        (WebCore::RenderTableSection::renderName):
+        * rendering/RenderTreeAsText.cpp:
+        (WebCore::RenderTreeAsText::writeRenderObject):
+        * rendering/style/ContentData.cpp:
+        (WebCore::ImageContentData::createRenderer):
+        (WebCore::TextContentData::createRenderer):
+        (WebCore::CounterContentData::createRenderer):
+        (WebCore::QuoteContentData::createRenderer):
+
 2012-12-05  Justin Novosad  <junov@google.com>
 
         Use of uninitialized variable in WebCore::RenderBox::paintFillLayers
index ad2966d..d1c860a 100644 (file)
@@ -2907,6 +2907,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 095b2bb..d4b50cb 100644 (file)
@@ -441,6 +441,7 @@ SOURCES += \
     dom/ProcessingInstruction.cpp \
     dom/ProgressEvent.cpp \
     dom/PropertyNodeList.cpp \
+    dom/PseudoElement.cpp \
     dom/QualifiedName.cpp \
     dom/Range.cpp \
     dom/RangeException.cpp \
@@ -1618,6 +1619,7 @@ HEADERS += \
     dom/ProcessingInstruction.h \
     dom/ProgressEvent.h \
     dom/PropertyNodeList.h \
+    dom/PseudoElement.h \
     dom/QualifiedName.h \
     dom/Range.h \
     dom/RegisteredEventListener.h \
index 045239d..00bd15f 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 a8af90f..347bfe5 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 2d81ce6..855a8b2 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 dd541a6..5c27958 100644 (file)
@@ -142,7 +142,7 @@ static inline ExceptionCode checkAcceptChild(ContainerNode* newParent, Node* new
     if (!newChild)
         return NOT_FOUND_ERR;
 
-    // Goes common casae fast path if possible.
+    // Use common case fast path if possible.
     if ((newChild->isElementNode() || newChild->isTextNode()) && newParent->isElementNode()) {
         ASSERT(!newParent->isReadOnlyNode());
         ASSERT(!newParent->isDocumentTypeNode());
@@ -152,6 +152,11 @@ static inline ExceptionCode checkAcceptChild(ContainerNode* newParent, Node* new
         return 0;
     }
 
+    // This should never happen, but also protect release builds from tree corruption.
+    ASSERT(!newChild->isPseudoElement());
+    if (newChild->isPseudoElement())
+        return HIERARCHY_REQUEST_ERR;
+
     if (newParent->isReadOnlyNode())
         return NO_MODIFICATION_ALLOWED_ERR;
     if (newChild->inDocument() && newChild->isDocumentTypeNode())
index 2593e59..1db422d 100644 (file)
 #include "PositionIterator.cpp"
 #include "ProcessingInstruction.cpp"
 #include "ProgressEvent.cpp"
+#include "PseudoElement.cpp"
 #include "Range.cpp"
 #include "RangeException.cpp"
 #include "RegisteredEventListener.cpp"
index 98a7215..1f77523 100644 (file)
@@ -64,6 +64,7 @@
 #include "NodeRenderingContext.h"
 #include "Page.h"
 #include "PointerLockController.h"
+#include "PseudoElement.h"
 #include "RenderRegion.h"
 #include "RenderView.h"
 #include "RenderWidget.h"
@@ -188,6 +189,12 @@ Element::~Element()
     }
 #endif
 
+    if (hasRareData()) {
+        ElementRareData* data = elementRareData();
+        data->setPseudoElement(BEFORE, 0);
+        data->setPseudoElement(AFTER, 0);
+    }
+
     if (ElementShadow* elementShadow = shadow()) {
         elementShadow->removeAllShadowRoots();
         elementRareData()->setShadow(nullptr);
@@ -1184,6 +1191,8 @@ void Element::detach()
     cancelFocusAppearanceUpdate();
     if (hasRareData()) {
         ElementRareData* data = elementRareData();
+        data->setPseudoElement(BEFORE, 0);
+        data->setPseudoElement(AFTER, 0);
         data->setIsInCanvasSubtree(false);
         data->resetComputedStyle();
         data->resetDynamicRestyleObservations();
@@ -2057,6 +2066,53 @@ void Element::normalizeAttributes()
     }
 }
 
+void Element::updatePseudoElement(PseudoId pseudoId, StyleChange change)
+{
+    PseudoElement* existing = hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
+    if (existing) {
+        // PseudoElement styles hang off their parent element's style so if we needed
+        // a style recalc we should Force one on the pseudo.
+        existing->recalcStyle(needsStyleRecalc() ? Force : change);
+
+        // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
+        // is false, otherwise we could continously create and destroy PseudoElements
+        // when RenderObject::isChildAllowed on our parent returns false for the
+        // PseudoElement's renderer for each style recalc.
+        if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
+            elementRareData()->setPseudoElement(pseudoId, 0);
+    } else if (RefPtr<PseudoElement> element = createPseudoElementIfNeeded(pseudoId)) {
+        element->attach();
+        ensureElementRareData()->setPseudoElement(pseudoId, element.release());
+    }
+}
+
+PassRefPtr<PseudoElement> Element::createPseudoElementIfNeeded(PseudoId pseudoId)
+{
+    if (!document()->styleSheetCollection()->usesBeforeAfterRules())
+        return 0;
+
+    if (!renderer() || !renderer()->canHaveGeneratedChildren())
+        return 0;
+
+    if (isPseudoElement())
+        return 0;
+
+    if (!pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
+        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 109c85d..0218cbc 100644 (file)
@@ -43,6 +43,7 @@ class ElementRareData;
 class ElementShadow;
 class IntSize;
 class Locale;
+class PseudoElement;
 class RenderRegion;
 class ShadowRoot;
 class WebKitAnimationList;
@@ -365,6 +366,9 @@ public:
     virtual void finishParsingChildren();
     virtual void beginParsingChildren();
 
+    PseudoElement* beforePseudoElement() const;
+    PseudoElement* afterPseudoElement() const;
+
     // ElementTraversal API
     Element* firstElementChild() const;
     Element* lastElementChild() const;
@@ -493,6 +497,9 @@ protected:
     void classAttributeChanged(const AtomicString& newClassString);
 
 private:
+    void updatePseudoElement(PseudoId, StyleChange = NoChange);
+    PassRefPtr<PseudoElement> createPseudoElementIfNeeded(PseudoId);
+
     // FIXME: Remove the need for Attr to call willModifyAttribute/didModifyAttribute.
     friend class Attr;
 
index 8a01d9b..7905cb5 100644 (file)
@@ -27,6 +27,7 @@
 #include "ElementShadow.h"
 #include "NamedNodeMap.h"
 #include "NodeRareData.h"
+#include "PseudoElement.h"
 #include "StyleInheritedData.h"
 #include <wtf/OwnPtr.h>
 
@@ -37,6 +38,9 @@ public:
     ElementRareData(Document*);
     virtual ~ElementRareData();
 
+    void setPseudoElement(PseudoId, PassRefPtr<PseudoElement>);
+    PseudoElement* pseudoElement(PseudoId) const;
+
     void resetComputedStyle();
     void resetDynamicRestyleObservations();
 
@@ -112,7 +116,13 @@ private:
     OwnPtr<ElementShadow> m_shadow;
     OwnPtr<NamedNodeMap> m_attributeMap;
 
+    RefPtr<PseudoElement> m_generatedBefore;
+    RefPtr<PseudoElement> m_generatedAfter;
+
     IntSize m_savedLayerScrollOffset;
+
+private:
+    void releasePseudoElement(PseudoElement*);
 };
 
 inline IntSize defaultMinimumSizeForResizing()
@@ -123,12 +133,59 @@ inline IntSize defaultMinimumSizeForResizing()
 inline ElementRareData::ElementRareData(Document* document)
     : NodeRareData(document)
     , m_minimumSizeForResizing(defaultMinimumSizeForResizing())
+    , m_generatedBefore(0)
+    , m_generatedAfter(0)
 {
 }
 
 inline ElementRareData::~ElementRareData()
 {
     ASSERT(!m_shadow);
+    ASSERT(!m_generatedBefore);
+    ASSERT(!m_generatedAfter);
+}
+
+inline void ElementRareData::setPseudoElement(PseudoId pseudoId, PassRefPtr<PseudoElement> element)
+{
+    switch (pseudoId) {
+    case BEFORE:
+        releasePseudoElement(m_generatedBefore.get());
+        m_generatedBefore = element;
+        break;
+    case AFTER:
+        releasePseudoElement(m_generatedAfter.get());
+        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::releasePseudoElement(PseudoElement* element)
+{
+    if (!element)
+        return;
+
+    if (element->attached())
+        element->detach();
+
+    ASSERT(!element->nextSibling());
+    ASSERT(!element->previousSibling());
+
+    element->setParentOrHostNode(0);
 }
 
 inline void ElementRareData::resetComputedStyle()
index a85592d..584dbe9 100644 (file)
@@ -447,6 +447,34 @@ void Node::setTreeScope(TreeScope* scope)
     ensureRareData()->setTreeScope(scope);
 }
 
+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());
@@ -705,6 +733,9 @@ bool Node::rendererIsEditable(EditableLevel editableLevel, UserSelectAllTreatmen
     if (document()->frame() && document()->frame()->page() && document()->frame()->page()->isEditable() && !shadowRoot())
         return true;
 
+    if (isPseudoElement())
+        return false;
+
     // Ideally we'd call ASSERT(!needsStyleRecalc()) here, but
     // ContainerNode::setFocus() calls setNeedsStyleRecalc(), so the assertion
     // would fire in the middle of Document::setFocusedNode().
index 41dabc3..7a470ee 100644 (file)
@@ -190,6 +190,9 @@ public:
     bool hasAttributes() const;
     NamedNodeMap* attributes() const;
 
+    Node* pseudoAwarePreviousSibling() const;
+    Node* pseudoAwareNextSibling() const;
+
     virtual KURL baseURI() const;
     
     void getSubresourceURLs(ListHashSet<KURL>&) const;
@@ -234,6 +237,11 @@ public:
     bool isHTMLElement() const { return getFlag(IsHTMLFlag); }
     bool isSVGElement() const { return getFlag(IsSVGFlag); }
 
+    bool isPseudoElement() const { return pseudoId() != NOPSEUDO; }
+    bool isBeforePseudoElement() const { return pseudoId() == BEFORE; }
+    bool isAfterPseudoElement() const { return pseudoId() == AFTER; }
+    PseudoId pseudoId() const { return (isElementNode() && hasCustomCallbacks()) ? customPseudoId() : NOPSEUDO; }
+
     virtual bool isMediaControlElement() const { return false; }
     virtual bool isMediaControls() const { return false; }
     bool isStyledElement() const { return getFlag(IsStyledElementFlag); }
@@ -742,6 +750,7 @@ protected:
         CreateText = DefaultNodeFlags | IsTextFlag,
         CreateContainer = DefaultNodeFlags | IsContainerFlag, 
         CreateElement = CreateContainer | IsElementFlag, 
+        CreatePseudoElement =  CreateElement | InDocumentFlag,
         CreateShadowRoot = CreateContainer | IsDocumentFragmentFlag,
         CreateDocumentFragment = CreateContainer | IsDocumentFragmentFlag,
         CreateStyledElement = CreateElement | IsStyledElementFlag, 
@@ -754,6 +763,12 @@ protected:
     };
     Node(Document*, ConstructionType);
 
+    virtual PseudoId customPseudoId() const
+    {
+        ASSERT(hasCustomCallbacks());
+        return NOPSEUDO;
+    }
+
     virtual void didMoveToNewDocument(Document* oldDocument);
     
     virtual void addSubresourceAttributeURLs(ListHashSet<KURL>&) const { }
index 1482fc4..4646cd8 100644 (file)
@@ -83,6 +83,15 @@ 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()) {
+        for (Node* sibling = m_node->pseudoAwareNextSibling(); sibling; sibling = sibling->pseudoAwareNextSibling()) {
+            if (RenderObject* renderer = sibling->renderer())
+                return renderer;
+        }
+        return 0;
+    }
+
     ComposedShadowTreeWalker walker(m_node);
     for (walker.nextSibling(); walker.get(); walker.nextSibling()) {
         if (RenderObject* renderer = walker.get()->renderer()) {
@@ -101,6 +110,10 @@ RenderObject* NodeRenderingContext::previousRenderer() const
     if (RenderObject* renderer = m_node->renderer())
         return renderer->previousSibling();
 
+    // FIXME: This method doesn't support pseudo elements since nothing needs
+    // previousRenderer() support for them yet.
+    ASSERT(!m_node->isPseudoElement());
+
     if (m_parentFlowRenderer)
         return m_parentFlowRenderer->previousRendererForNode(m_node);
 
index cb60700..a1c0b01 100644 (file)
@@ -840,7 +840,7 @@ bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* render
 {
     RenderObject* stop = renderer->nextInPreOrderAfterChildren();
     for (RenderObject *o = renderer->firstChild(); o && o != stop; o = o->nextInPreOrder())
-        if (o->node()) {
+        if (o->node() && !o->node()->isPseudoElement()) {
             if ((o->isText() && toRenderText(o)->linesBoundingBox().height()) ||
                 (o->isBox() && toRenderBox(o)->borderBoundingBox().height()))
                 return true;
diff --git a/Source/WebCore/dom/PseudoElement.cpp b/Source/WebCore/dom/PseudoElement.cpp
new file mode 100644 (file)
index 0000000..c77a295
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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 "NodeRenderingContext.h"
+#include "RenderObject.h"
+
+namespace WebCore {
+
+const QualifiedName& pseudoElementTagName()
+{
+    DEFINE_STATIC_LOCAL(QualifiedName, name, (nullAtom, "<pseudo>", nullAtom));
+    return name;
+}
+
+PseudoElement::PseudoElement(Element* parent, PseudoId pseudoId)
+    : Element(pseudoElementTagName(), parent->document(), CreatePseudoElement)
+    , m_pseudoId(pseudoId)
+{
+    ASSERT(parent->inDocument());
+    setParentOrHostNode(parent);
+    setHasCustomCallbacks();
+}
+
+PassRefPtr<RenderStyle> PseudoElement::customStyleForRenderer()
+{
+    return parentOrHostElement()->renderer()->getCachedPseudoStyle(m_pseudoId);
+}
+
+void PseudoElement::attach()
+{
+    ASSERT(!renderer());
+
+    Element::attach();
+
+    RenderObject* renderer = this->renderer();
+    if (!renderer || !renderer->style()->regionThread().isEmpty())
+        return;
+
+    RenderStyle* style = renderer->style();
+    ASSERT(style->contentData());
+
+    for (const ContentData* content = style->contentData(); content; content = content->next()) {
+        RenderObject* child = content->createRenderer(document(), style);
+        if (renderer->isChildAllowed(child, style))
+            renderer->addChild(child);
+        else
+            child->destroy();
+    }
+}
+
+bool PseudoElement::rendererIsNeeded(const NodeRenderingContext& context)
+{
+    return pseudoElementRendererIsNeeded(context.style());
+}
+
+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 style propagated downward manually similar to RenderObject::propagateStyleToAnonymousChildren.
+    RenderObject* renderer = this->renderer();
+    for (RenderObject* child = renderer->nextInPreOrder(renderer); child; child = child->nextInPreOrder(renderer)) {
+        // We only manage the style for the generated content which must be images or text.
+        if (!child->isText() && !child->isImage())
+            continue;
+
+        // The style for the RenderTextFragment for first letter is managed by an enclosing block, not by us.
+        if (child->style()->styleType() == FIRST_LETTER)
+            continue;
+
+        child->setPseudoStyle(renderer->style());
+    }
+}
+
+} // namespace
diff --git a/Source/WebCore/dom/PseudoElement.h b/Source/WebCore/dom/PseudoElement.h
new file mode 100644 (file)
index 0000000..1ac5749
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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 "RenderStyle.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class PseudoElement : public Element {
+public:
+    static PassRefPtr<PseudoElement> create(Element* parent, PseudoId pseudoId)
+    {
+        return adoptRef(new PseudoElement(parent, pseudoId));
+    }
+
+    virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE;
+    virtual void attach() OVERRIDE;
+    virtual bool rendererIsNeeded(const NodeRenderingContext&) OVERRIDE;
+
+    virtual bool canStartSelection() const OVERRIDE { return false; }
+    virtual bool canContainRangeEndPoint() const OVERRIDE { return false; }
+
+private:
+    PseudoElement(Element*, PseudoId);
+
+    virtual void didRecalcStyle(StyleChange) OVERRIDE;
+    virtual PseudoId customPseudoId() const OVERRIDE { return m_pseudoId; }
+
+    PseudoId m_pseudoId;
+};
+
+const QualifiedName& pseudoElementTagName();
+
+inline bool pseudoElementRendererIsNeeded(const RenderStyle* style)
+{
+    return style && style->display() != NONE && (style->contentData() || !style->regionThread().isEmpty());
+}
+
+} // namespace
+
+#endif
index 6ecb77c..2b6e948 100644 (file)
@@ -215,7 +215,7 @@ static const InlineTextBox* logicallyPreviousBox(const VisiblePosition& visibleP
 
     while (1) {
         Node* startNode = startBox->renderer() ? startBox->renderer()->node() : 0;
-        if (!startNode)
+        if (!startNode || startNode->isPseudoElement())
             break;
 
         Position position = previousRootInlineBoxCandidatePosition(startNode, visiblePosition, ContentIsEditable);
@@ -256,7 +256,7 @@ static const InlineTextBox* logicallyNextBox(const VisiblePosition& visiblePosit
 
     while (1) {
         Node* startNode = startBox->renderer() ? startBox->renderer()->node() : 0;
-        if (!startNode)
+        if (!startNode || startNode->isPseudoElement())
             break;
 
         Position position = nextRootInlineBoxCandidatePosition(startNode, visiblePosition, ContentIsEditable);
@@ -744,7 +744,7 @@ static VisiblePosition startPositionForLine(const VisiblePosition& c, LineEndpoi
                 return VisiblePosition();
 
             startNode = startRenderer->node();
-            if (startNode)
+            if (startNode && !startNode->isPseudoElement())
                 break;
 
             startBox = startBox->nextLeafChild();
@@ -816,7 +816,7 @@ static VisiblePosition endPositionForLine(const VisiblePosition& c, LineEndpoint
                 return VisiblePosition();
 
             endNode = endRenderer->node();
-            if (endNode)
+            if (endNode && !endNode->isPseudoElement())
                 break;
             
             endBox = endBox->prevLeafChild();
index 221ed7d..12bfc4a 100644 (file)
@@ -521,6 +521,10 @@ PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* rend
     if (!renderer->document() || renderer->document()->inPageCache())
         return newStyle;
 
+    // FIXME: We do not animate generated content yet.
+    if (renderer->isPseudoElement())
+        return newStyle;
+
     RenderStyle* oldStyle = renderer->style();
 
     if ((!oldStyle || (!oldStyle->animations() && !oldStyle->transitions())) && (!newStyle->animations() && !newStyle->transitions()))
@@ -534,7 +538,7 @@ PassRefPtr<RenderStyle> AnimationController::updateAnimations(RenderObject* rend
     // against the animations in the style and make sure we're in sync.  If destination values
     // have changed, we reset the animation.  We then do a blend to get new values and we return
     // a new style.
-    ASSERT(renderer->node()); // FIXME: We do not animate generated content yet.
+    ASSERT(renderer->node() && !renderer->isPseudoElement()); // FIXME: We do not animate generated content yet.
 
     RefPtr<CompositeAnimation> rendererAnimations = m_data->accessCompositeAnimation(renderer);
     RefPtr<RenderStyle> blendedStyle = rendererAnimations->animate(renderer, oldStyle, newStyle);
index 38f1f67..cffdf78 100644 (file)
@@ -267,11 +267,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 33e8589..6702707 100644 (file)
@@ -3235,7 +3235,7 @@ bool RenderBlock::shouldPaintSelectionGaps() const
 
 bool RenderBlock::isSelectionRoot() const
 {
-    if (!node())
+    if (!node() || isPseudoElement())
         return false;
         
     // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
@@ -7471,7 +7471,10 @@ const char* RenderBlock::renderName() const
         return "RenderBlock (anonymous multi-column span)";
     if (isAnonymousBlock())
         return "RenderBlock (anonymous)";
-    else if (isAnonymous())
+    // FIXME: Temporary hack while the new generated content system is being implemented.
+    if (isPseudoElement())
+        return "RenderBlock (generated)";
+    if (isAnonymous())
         return "RenderBlock (generated)";
     if (isRelPositioned())
         return "RenderBlock (relative positioned)";
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 3323986..6950a14 100644 (file)
@@ -1083,12 +1083,15 @@ LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool
     return 0;
 }
 
-const char *RenderDeprecatedFlexibleBox::renderName() const
+const charRenderDeprecatedFlexibleBox::renderName() const
 {
     if (isFloating())
         return "RenderDeprecatedFlexibleBox (floating)";
     if (isOutOfFlowPositioned())
         return "RenderDeprecatedFlexibleBox (positioned)";
+    // FIXME: Temporary hack while the new generated content system is being implemented.
+    if (isPseudoElement())
+        return "RenderDeprecatedFlexibleBox (generated)";
     if (isAnonymous())
         return "RenderDeprecatedFlexibleBox (generated)";
     if (isRelPositioned())
index db1b185..0e1cda3 100644 (file)
@@ -762,6 +762,9 @@ const char* RenderInline::renderName() const
         return "RenderInline (relative positioned)";
     if (isStickyPositioned())
         return "RenderInline (sticky positioned)";
+    // FIXME: Temporary hack while the new generated content system is being implemented.
+    if (isPseudoElement())
+        return "RenderInline (generated)";
     if (isAnonymous())
         return "RenderInline (generated)";
     if (isRunIn())
index ba3ccd9..2311da1 100644 (file)
@@ -145,13 +145,16 @@ void RenderMultiColumnBlock::ensureColumnSets()
 }
 
 const char* RenderMultiColumnBlock::renderName() const
-{    
+{
     if (isFloating())
         return "RenderMultiColumnBlock (floating)";
     if (isOutOfFlowPositioned())
         return "RenderMultiColumnBlock (positioned)";
     if (isAnonymousBlock())
         return "RenderMultiColumnBlock (anonymous)";
+    // FIXME: Temporary hack while the new generated content system is being implemented.
+    if (isPseudoElement())
+        return "RenderMultiColumnBlock (generated)";
     if (isAnonymous())
         return "RenderMultiColumnBlock (generated)";
     if (isRelPositioned())
index 3c0d673..9ffc853 100644 (file)
@@ -142,7 +142,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
@@ -1756,6 +1756,23 @@ StyleDifference RenderObject::adjustStyleDifference(StyleDifference diff, unsign
     return diff;
 }
 
+void RenderObject::setPseudoStyle(PassRefPtr<RenderStyle> pseudoStyle)
+{
+    ASSERT(pseudoStyle->styleType() == BEFORE || pseudoStyle->styleType() == AFTER);
+
+    // Images are special and must inherit the pseudoStyle so the width and height of
+    // the pseudo element doesn't change the size of the image. In all other cases we
+    // can just share the style.
+    if (isImage()) {
+        RefPtr<RenderStyle> style = RenderStyle::create();
+        style->inheritFrom(pseudoStyle.get());
+        setStyle(style.release());
+        return;
+    }
+
+    setStyle(pseudoStyle);
+}
+
 void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
 {
     if (m_style == style) {
@@ -2972,7 +2989,8 @@ RenderBoxModelObject* RenderObject::offsetParent() const
 VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affinity)
 {
     // If this is a non-anonymous renderer in an editable area, then it's simple.
-    if (Node* node = this->node()) {
+    if (node() && !isPseudoElement()) {
+        Node* node = this->node();
         if (!node->rendererIsEditable()) {
             // If it can be found, we prefer a visually equivalent position that is editable. 
             Position position = createLegacyEditingPosition(node, offset);
@@ -2998,8 +3016,8 @@ VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affini
         // Find non-anonymous content after.
         RenderObject* renderer = child;
         while ((renderer = renderer->nextInPreOrder(parent))) {
-            if (Node* node = renderer->node())
-                return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
+            if (renderer->node() && !renderer->isPseudoElement())
+                return VisiblePosition(firstPositionInOrBeforeNode(renderer->node()), DOWNSTREAM);
         }
 
         // Find non-anonymous content before.
@@ -3007,13 +3025,13 @@ VisiblePosition RenderObject::createVisiblePosition(int offset, EAffinity affini
         while ((renderer = renderer->previousInPreOrder())) {
             if (renderer == parent)
                 break;
-            if (Node* node = renderer->node())
-                return VisiblePosition(lastPositionInOrAfterNode(node), DOWNSTREAM);
+            if (renderer->node() && !renderer->isPseudoElement())
+                return VisiblePosition(lastPositionInOrAfterNode(renderer->node()), DOWNSTREAM);
         }
 
         // Use the parent itself unless it too is anonymous.
-        if (Node* node = parent->node())
-            return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
+        if (parent->node() && !isPseudoElement())
+            return VisiblePosition(firstPositionInOrBeforeNode(parent->node()), DOWNSTREAM);
 
         // Repeat at the next level up.
         child = parent;
index 4792f73..b010337 100644 (file)
@@ -330,6 +330,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; }
@@ -623,7 +625,12 @@ 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
+    {
+        if (isPseudoElement())
+            return node()->parentOrHostNode();
+        return m_node == document() ? 0 : m_node;
+    }
     void setNode(Node* node) { m_node = node; }
 
     Document* document() const { return m_node->document(); }
@@ -713,6 +720,9 @@ public:
     // Set the style of the object and update the state of the object accordingly.
     virtual void setStyle(PassRefPtr<RenderStyle>);
 
+    // Set the style of the object if it's generated content.
+    void setPseudoStyle(PassRefPtr<RenderStyle>);
+
     // Updates only the local style ptr of the object.  Does not update the state of the object,
     // and so only should be called when the style is known not to have changed (or from setStyle).
     void setStyleInternal(PassRefPtr<RenderStyle> style) { m_style = style; }
index 2dd26a2..65773ca 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 6f195d3..c05f44b 100644 (file)
@@ -92,7 +92,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 79cdd4a..6399f7c 100644 (file)
@@ -202,7 +202,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 5b4eb73..e83898e 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
index 9cac254..e184b9b 100644 (file)
@@ -70,12 +70,7 @@ PassOwnPtr<ContentData> ContentData::clone() const
 RenderObject* ImageContentData::createRenderer(Document* doc, RenderStyle* pseudoStyle) const
 {
     RenderImage* image = new (doc->renderArena()) RenderImage(doc);
-    // Images are special and must inherit the pseudoStyle so the width and height of
-    // the pseudo element don't change the size of the image. In all other cases we
-    // can just share the style.
-    RefPtr<RenderStyle> style = RenderStyle::create();
-    style->inheritFrom(pseudoStyle);
-    image->setStyle(style.release());
+    image->setPseudoStyle(pseudoStyle);
     if (m_image)
         image->setImageResource(RenderImageResourceStyleImage::create(m_image.get()));
     else
@@ -86,21 +81,21 @@ RenderObject* ImageContentData::createRenderer(Document* doc, RenderStyle* pseud
 RenderObject* TextContentData::createRenderer(Document* doc, RenderStyle* pseudoStyle) const
 {
     RenderObject* renderer = new (doc->renderArena()) RenderTextFragment(doc, m_text.impl());
-    renderer->setStyle(pseudoStyle);
+    renderer->setPseudoStyle(pseudoStyle);
     return renderer;
 }
 
 RenderObject* CounterContentData::createRenderer(Document* doc, RenderStyle* pseudoStyle) const
 {
     RenderObject* renderer = new (doc->renderArena()) RenderCounter(doc, *m_counter);
-    renderer->setStyle(pseudoStyle);
+    renderer->setPseudoStyle(pseudoStyle);
     return renderer;
 }
 
 RenderObject* QuoteContentData::createRenderer(Document* doc, RenderStyle* pseudoStyle) const
 {
     RenderObject* renderer = new (doc->renderArena()) RenderQuote(doc, m_quote);
-    renderer->setStyle(pseudoStyle);
+    renderer->setPseudoStyle(pseudoStyle);
     return renderer;
 }