Title: [197078] releases/WebKitGTK/webkit-2.12/Source/WebCore
Revision
197078
Author
carlo...@webkit.org
Date
2016-02-25 02:00:32 -0800 (Thu, 25 Feb 2016)

Log Message

Merge r196864 - Resolve style iteratively
https://bugs.webkit.org/show_bug.cgi?id=154355

Reviewed by Andreas Kling.

Instead of a set of recursive functions use ComposedTreeIterator for traversing the DOM
tree in composed tree order.

This, along with maintaining explicit parent stack makes style resolve code more tractable
for future work.

It also makes the ComposedTreeIterator the definite authority for the shape of the composed tree
instead of duplicating it as a set of recursive style resolve functions. This eliminates
a significant source of bugs and confusion.

The render tree building code path remains recursive for now.

* css/StyleInvalidationAnalysis.cpp:
(WebCore::StyleInvalidationAnalysis::invalidateIfNeeded):

    Invalidate the host element instead of the shadow root. This reduces need for special handling for shadow roots.

* dom/ComposedTreeIterator.cpp:
(WebCore::ComposedTreeIterator::initializeContextStack):
(WebCore::ComposedTreeIterator::dropAssertions):

    Add support for dropping DOM mutation assertions.

(WebCore::ComposedTreeIterator::traverseShadowRoot):
* dom/ComposedTreeIterator.h:
(WebCore::ComposedTreeIterator::context):
(WebCore::ComposedTreeIterator::current):
* dom/PseudoElement.h:
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::TreeResolver):
(WebCore::Style::TreeResolver::Scope::Scope):
(WebCore::Style::TreeResolver::Parent::Parent):
(WebCore::Style::TreeResolver::pushScope):
(WebCore::Style::resetStyleForNonRenderedDescendants):
(WebCore::Style::pseudoStyleCacheIsInvalid):
(WebCore::Style::TreeResolver::resolveElement):
(WebCore::Style::resolveTextNode):
(WebCore::Style::TreeResolver::resolveBeforeOrAfterPseudoElement):
(WebCore::Style::TreeResolver::pushParent):
(WebCore::Style::TreeResolver::popParent):
(WebCore::Style::TreeResolver::popParentsToDepth):

    Maintain explicit parent stack.

(WebCore::Style::TreeResolver::resolveComposedTree):

    The main loop that iterates over the composed tree and computes style for dirty elements.

(WebCore::Style::TreeResolver::resolve):
(WebCore::Style::detachRenderTree):
(WebCore::Style::TreeResolver::resolveLocally): Deleted.
(WebCore::Style::TreeResolver::resolveChildAtShadowBoundary): Deleted.
(WebCore::Style::TreeResolver::resolveShadowTree): Deleted.
(WebCore::Style::TreeResolver::resolveChildren): Deleted.
(WebCore::Style::TreeResolver::resolveSlotAssignees): Deleted.
(WebCore::Style::TreeResolver::resolveRecursively): Deleted.

    Recursive functions go away.

* style/StyleTreeResolver.h:
(WebCore::Style::TreeResolver::scope):
(WebCore::Style::TreeResolver::parent):

Modified Paths

Diff

Modified: releases/WebKitGTK/webkit-2.12/Source/WebCore/ChangeLog (197077 => 197078)


--- releases/WebKitGTK/webkit-2.12/Source/WebCore/ChangeLog	2016-02-25 10:00:13 UTC (rev 197077)
+++ releases/WebKitGTK/webkit-2.12/Source/WebCore/ChangeLog	2016-02-25 10:00:32 UTC (rev 197078)
@@ -1,3 +1,73 @@
+2016-02-20  Antti Koivisto  <an...@apple.com>
+
+        Resolve style iteratively
+        https://bugs.webkit.org/show_bug.cgi?id=154355
+
+        Reviewed by Andreas Kling.
+
+        Instead of a set of recursive functions use ComposedTreeIterator for traversing the DOM
+        tree in composed tree order.
+
+        This, along with maintaining explicit parent stack makes style resolve code more tractable
+        for future work.
+
+        It also makes the ComposedTreeIterator the definite authority for the shape of the composed tree
+        instead of duplicating it as a set of recursive style resolve functions. This eliminates
+        a significant source of bugs and confusion.
+
+        The render tree building code path remains recursive for now.
+
+        * css/StyleInvalidationAnalysis.cpp:
+        (WebCore::StyleInvalidationAnalysis::invalidateIfNeeded):
+
+            Invalidate the host element instead of the shadow root. This reduces need for special handling for shadow roots.
+
+        * dom/ComposedTreeIterator.cpp:
+        (WebCore::ComposedTreeIterator::initializeContextStack):
+        (WebCore::ComposedTreeIterator::dropAssertions):
+
+            Add support for dropping DOM mutation assertions.
+
+        (WebCore::ComposedTreeIterator::traverseShadowRoot):
+        * dom/ComposedTreeIterator.h:
+        (WebCore::ComposedTreeIterator::context):
+        (WebCore::ComposedTreeIterator::current):
+        * dom/PseudoElement.h:
+        * style/StyleTreeResolver.cpp:
+        (WebCore::Style::TreeResolver::TreeResolver):
+        (WebCore::Style::TreeResolver::Scope::Scope):
+        (WebCore::Style::TreeResolver::Parent::Parent):
+        (WebCore::Style::TreeResolver::pushScope):
+        (WebCore::Style::resetStyleForNonRenderedDescendants):
+        (WebCore::Style::pseudoStyleCacheIsInvalid):
+        (WebCore::Style::TreeResolver::resolveElement):
+        (WebCore::Style::resolveTextNode):
+        (WebCore::Style::TreeResolver::resolveBeforeOrAfterPseudoElement):
+        (WebCore::Style::TreeResolver::pushParent):
+        (WebCore::Style::TreeResolver::popParent):
+        (WebCore::Style::TreeResolver::popParentsToDepth):
+
+            Maintain explicit parent stack.
+
+        (WebCore::Style::TreeResolver::resolveComposedTree):
+
+            The main loop that iterates over the composed tree and computes style for dirty elements.
+
+        (WebCore::Style::TreeResolver::resolve):
+        (WebCore::Style::detachRenderTree):
+        (WebCore::Style::TreeResolver::resolveLocally): Deleted.
+        (WebCore::Style::TreeResolver::resolveChildAtShadowBoundary): Deleted.
+        (WebCore::Style::TreeResolver::resolveShadowTree): Deleted.
+        (WebCore::Style::TreeResolver::resolveChildren): Deleted.
+        (WebCore::Style::TreeResolver::resolveSlotAssignees): Deleted.
+        (WebCore::Style::TreeResolver::resolveRecursively): Deleted.
+
+            Recursive functions go away.
+
+        * style/StyleTreeResolver.h:
+        (WebCore::Style::TreeResolver::scope):
+        (WebCore::Style::TreeResolver::parent):
+
 2016-02-19  Antti Koivisto  <an...@apple.com>
 
         ComposedTreeIterator traverses normal children for elements with empty shadow root

Modified: releases/WebKitGTK/webkit-2.12/Source/WebCore/css/StyleInvalidationAnalysis.cpp (197077 => 197078)


--- releases/WebKitGTK/webkit-2.12/Source/WebCore/css/StyleInvalidationAnalysis.cpp	2016-02-25 10:00:13 UTC (rev 197077)
+++ releases/WebKitGTK/webkit-2.12/Source/WebCore/css/StyleInvalidationAnalysis.cpp	2016-02-25 10:00:32 UTC (rev 197078)
@@ -99,8 +99,8 @@
 {
     if (m_hasShadowPseudoElementRulesInAuthorSheet) {
         // FIXME: This could do actual rule matching too.
-        if (auto* shadowRoot = element.shadowRoot())
-            shadowRoot->setNeedsStyleRecalc();
+        if (element.shadowRoot())
+            element.setNeedsStyleRecalc();
     }
 
     switch (element.styleChangeType()) {

Modified: releases/WebKitGTK/webkit-2.12/Source/WebCore/dom/ComposedTreeIterator.cpp (197077 => 197078)


--- releases/WebKitGTK/webkit-2.12/Source/WebCore/dom/ComposedTreeIterator.cpp	2016-02-25 10:00:13 UTC (rev 197077)
+++ releases/WebKitGTK/webkit-2.12/Source/WebCore/dom/ComposedTreeIterator.cpp	2016-02-25 10:00:32 UTC (rev 197078)
@@ -106,6 +106,13 @@
     m_contextStack.reverse();
 }
 
+void ComposedTreeIterator::dropAssertions()
+{
+    for (auto& context : m_contextStack)
+        context.iterator.dropAssertions();
+    m_didDropAssertions = true;
+}
+
 void ComposedTreeIterator::traverseShadowRoot(ShadowRoot& shadowRoot)
 {
     Context shadowContext(shadowRoot);
@@ -115,6 +122,9 @@
         return;
     }
 
+    if (m_didDropAssertions)
+        shadowContext.iterator.dropAssertions();
+
     m_contextStack.append(WTFMove(shadowContext));
 }
 

Modified: releases/WebKitGTK/webkit-2.12/Source/WebCore/dom/ComposedTreeIterator.h (197077 => 197078)


--- releases/WebKitGTK/webkit-2.12/Source/WebCore/dom/ComposedTreeIterator.h	2016-02-25 10:00:13 UTC (rev 197077)
+++ releases/WebKitGTK/webkit-2.12/Source/WebCore/dom/ComposedTreeIterator.h	2016-02-25 10:00:32 UTC (rev 197078)
@@ -54,6 +54,8 @@
 
     unsigned depth() const;
 
+    void dropAssertions();
+
 private:
     void initializeContextStack(ContainerNode& root, Node& current);
     void traverseNextInShadowTree();
@@ -81,6 +83,7 @@
     const Context& context() const { return m_contextStack.last(); }
     Node& current() { return *context().iterator; }
 
+    bool m_didDropAssertions { false };
     Vector<Context, 4> m_contextStack;
 };
 

Modified: releases/WebKitGTK/webkit-2.12/Source/WebCore/dom/PseudoElement.h (197077 => 197078)


--- releases/WebKitGTK/webkit-2.12/Source/WebCore/dom/PseudoElement.h	2016-02-25 10:00:13 UTC (rev 197077)
+++ releases/WebKitGTK/webkit-2.12/Source/WebCore/dom/PseudoElement.h	2016-02-25 10:00:32 UTC (rev 197078)
@@ -47,6 +47,7 @@
 
     virtual RefPtr<RenderStyle> customStyleForRenderer(RenderStyle& parentStyle) override;
     virtual void didAttachRenderers() override;
+    virtual void didRecalcStyle(Style::Change) override;
     virtual bool rendererIsNeeded(const RenderStyle&) override;
 
     // As per http://dev.w3.org/csswg/css3-regions/#flow-into, pseudo-elements such as ::first-line, ::first-letter, ::before or ::after
@@ -63,7 +64,6 @@
 private:
     PseudoElement(Element&, PseudoId);
 
-    virtual void didRecalcStyle(Style::Change) override;
     virtual PseudoId customPseudoId() const override { return m_pseudoId; }
 
     Element* m_hostElement;

Modified: releases/WebKitGTK/webkit-2.12/Source/WebCore/style/StyleTreeResolver.cpp (197077 => 197078)


--- releases/WebKitGTK/webkit-2.12/Source/WebCore/style/StyleTreeResolver.cpp	2016-02-25 10:00:13 UTC (rev 197077)
+++ releases/WebKitGTK/webkit-2.12/Source/WebCore/style/StyleTreeResolver.cpp	2016-02-25 10:00:32 UTC (rev 197078)
@@ -112,8 +112,6 @@
     : m_document(document)
 {
     ensurePlaceholderStyle(document);
-
-    m_scopeStack.append(adoptRef(*new Scope(document)));
 }
 
 TreeResolver::Scope::Scope(Document& document)
@@ -130,6 +128,22 @@
 {
 }
 
+TreeResolver::Parent::Parent(Document& document, Change change)
+    : element(nullptr)
+    , style(*document.renderStyle())
+    , renderTreePosition(*document.renderView())
+    , change(change)
+{
+}
+
+TreeResolver::Parent::Parent(Element& element, RenderStyle& style, RenderTreePosition renderTreePosition, Change change)
+    : element(&element)
+    , style(style)
+    , renderTreePosition(renderTreePosition)
+    , change(change)
+{
+}
+
 void TreeResolver::pushScope(ShadowRoot& shadowRoot)
 {
     m_scopeStack.append(adoptRef(*new Scope(shadowRoot, scope())));
@@ -425,20 +439,18 @@
 
 static void resetStyleForNonRenderedDescendants(Element& current)
 {
+    // FIXME: This is not correct with shadow trees. This should be done with ComposedTreeIterator.
     ASSERT(!current.renderer());
     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
     for (auto& child : childrenOfType<Element>(current)) {
         ASSERT(!child.renderer());
-        if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
-            if (child.styleIsAffectedByPreviousSibling())
-                child.setNeedsStyleRecalc();
+        bool affectedByPreviousSibling = child.styleIsAffectedByPreviousSibling() && elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
+        if (child.needsStyleRecalc() || elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
-        }
 
-        if (child.needsStyleRecalc()) {
+        if (child.needsStyleRecalc() || affectedByPreviousSibling) {
             child.resetComputedStyle();
             child.clearNeedsStyleRecalc();
-            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
         }
 
         if (child.childNeedsStyleRecalc()) {
@@ -652,28 +664,32 @@
     return false;
 }
 
-Change TreeResolver::resolveLocally(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change inheritedChange)
+Change TreeResolver::resolveElement(Element& current)
 {
     Change localChange = Detach;
     RefPtr<RenderStyle> newStyle;
     RefPtr<RenderStyle> currentStyle = current.renderStyle();
 
     if (currentStyle && current.styleChangeType() != ReconstructRenderTree) {
-        Ref<RenderStyle> style(styleForElement(current, inheritedStyle));
+        Ref<RenderStyle> style(styleForElement(current, parent().style));
         newStyle = style.ptr();
         localChange = determineChange(*currentStyle, style);
     }
     if (localChange == Detach) {
         if (current.renderer() || current.isNamedFlowContentNode())
             detachRenderTree(current, ReattachDetach);
-        createRenderTreeRecursively(current, inheritedStyle, renderTreePosition, newStyle.release());
+#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
+        else if (is<HTMLSlotElement>(current))
+            detachRenderTree(current, ReattachDetach);
+#endif
+        createRenderTreeRecursively(current, parent().style, parent().renderTreePosition, newStyle.release());
         invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(current);
 
         return Detach;
     }
 
     if (RenderElement* renderer = current.renderer()) {
-        if (localChange != NoChange || pseudoStyleCacheIsInvalid(renderer, newStyle.get()) || (inheritedChange == Force && renderer->requiresForcedStyleRecalcPropagation()) || current.styleChangeType() == SyntheticStyleChange)
+        if (localChange != NoChange || pseudoStyleCacheIsInvalid(renderer, newStyle.get()) || (parent().change == Force && renderer->requiresForcedStyleRecalcPropagation()) || current.styleChangeType() == SyntheticStyleChange)
             renderer->setAnimatableStyle(*newStyle, current.styleChangeType() == SyntheticStyleChange ? StyleDifferenceRecompositeLayer : StyleDifferenceEqual);
         else if (current.needsStyleRecalc()) {
             // Although no change occurred, we use the new style so that the cousin style sharing code won't get
@@ -689,10 +705,8 @@
         scope().styleResolver.invalidateMatchedPropertiesCache();
         return Force;
     }
-    if (inheritedChange == Force)
+    if (parent().change == Force || current.styleChangeType() >= FullStyleChange)
         return Force;
-    if (current.styleChangeType() >= FullStyleChange)
-        return Force;
 
     return localChange;
 }
@@ -716,48 +730,28 @@
     invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
 }
 
-void TreeResolver::resolveChildAtShadowBoundary(Node& child, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Style::Change change)
+void TreeResolver::resolveBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
 {
-    if (auto* renderer = child.renderer())
-        renderTreePosition.invalidateNextSibling(*renderer);
-
-    if (is<Text>(child) && child.needsStyleRecalc()) {
-        resolveTextNode(downcast<Text>(child), renderTreePosition);
+    if (!current.renderer())
         return;
+    PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId);
+    if (!existingPseudoElement) {
+        createRenderTreeForBeforeOrAfterPseudoElement(current, pseudoId, renderTreePosition);
+        return;
     }
-    if (is<Element>(child))
-        resolveRecursively(downcast<Element>(child), inheritedStyle, renderTreePosition, change);
-}
 
-void TreeResolver::resolveShadowTree(Style::Change change, RenderStyle& inheritedStyle)
-{
-    ASSERT(scope().shadowRoot);
-    auto& host = *scope().shadowRoot->host();
-    ASSERT(host.renderer());
-    if (scope().shadowRoot->styleChangeType() >= FullStyleChange)
-        change = Force;
-    RenderTreePosition renderTreePosition(*host.renderer());
-    for (auto* child = scope().shadowRoot->firstChild(); child; child = child->nextSibling())
-        resolveChildAtShadowBoundary(*child, inheritedStyle, renderTreePosition, change);
+    if (existingPseudoElement->renderer())
+        renderTreePosition.invalidateNextSibling(*existingPseudoElement->renderer());
 
-    scope().shadowRoot->clearNeedsStyleRecalc();
-    scope().shadowRoot->clearChildNeedsStyleRecalc();
-}
+    if (change == NoChange && !existingPseudoElement->needsStyleRecalc())
+        return;
 
-void TreeResolver::resolveBeforeOrAfterPseudoElement(Element& current, Change change, PseudoId pseudoId, RenderTreePosition& renderTreePosition)
-{
-    ASSERT(current.renderer());
-    if (PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId)) {
-        if (existingPseudoElement->renderer())
-            renderTreePosition.invalidateNextSibling(*existingPseudoElement->renderer());
-
-        if (needsPseudoElement(current, pseudoId))
-            resolveRecursively(*existingPseudoElement, current.renderer()->style(), renderTreePosition, current.needsStyleRecalc() ? Force : change);
-        else
-            clearBeforeOrAfterPseudoElement(current, pseudoId);
-        return;
-    }
-    createRenderTreeForBeforeOrAfterPseudoElement(current, pseudoId, renderTreePosition);
+    if (needsPseudoElement(current, pseudoId)) {
+        auto change = resolveElement(*existingPseudoElement);
+        existingPseudoElement->didRecalcStyle(change);
+        existingPseudoElement->clearNeedsStyleRecalc();
+    } else
+        clearBeforeOrAfterPseudoElement(current, pseudoId);
 }
 
 #if PLATFORM(IOS)
@@ -814,112 +808,155 @@
 };
 #endif // PLATFORM(IOS)
 
-void TreeResolver::resolveChildren(Element& current, RenderStyle& inheritedStyle, Change change, RenderTreePosition& childRenderTreePosition)
+void TreeResolver::pushParent(Element& element, RenderStyle& style, RenderTreePosition renderTreePosition, Change change)
 {
-    SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, current, SelectorFilterPusher::NoPush);
+    scope().selectorFilter.pushParent(&element);
 
-    bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
-    for (Node* child = current.firstChild(); child; child = child->nextSibling()) {
-        if (RenderObject* childRenderer = child->renderer())
-            childRenderTreePosition.invalidateNextSibling(*childRenderer);
-        if (is<Text>(*child) && child->needsStyleRecalc()) {
-            resolveTextNode(downcast<Text>(*child), childRenderTreePosition);
-            continue;
-        }
-        if (!is<Element>(*child))
-            continue;
+    Parent parent(element, style, renderTreePosition, change);
 
-        Element& childElement = downcast<Element>(*child);
-        if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
-            if (childElement.styleIsAffectedByPreviousSibling())
-                childElement.setNeedsStyleRecalc();
-            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
-        } else if (childElement.needsStyleRecalc())
-            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
-        if (change >= Inherit || childElement.childNeedsStyleRecalc() || childElement.needsStyleRecalc()) {
-            selectorFilterPusher.push();
-            resolveRecursively(childElement, inheritedStyle, childRenderTreePosition, change);
-        }
+    if (auto* shadowRoot = element.shadowRoot()) {
+        pushScope(*shadowRoot);
+        parent.didPushScope = true;
     }
+#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
+    else if (is<HTMLSlotElement>(element) && downcast<HTMLSlotElement>(element).assignedNodes()) {
+        pushEnclosingScope();
+        parent.didPushScope = true;
+    }
+#endif
+
+    m_parentStack.append(WTFMove(parent));
+
+    resolveBeforeOrAfterPseudoElement(element, change, BEFORE, renderTreePosition);
 }
 
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-void TreeResolver::resolveSlotAssignees(HTMLSlotElement& slot, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change change)
+void TreeResolver::popParent()
 {
-    if (auto* assignedNodes = slot.assignedNodes()) {
-        pushEnclosingScope();
-        for (auto* child : *assignedNodes)
-            resolveChildAtShadowBoundary(*child, inheritedStyle, renderTreePosition, change);
+    auto& parentElement = *parent().element;
+
+    resolveBeforeOrAfterPseudoElement(parentElement, parent().change, AFTER, parent().renderTreePosition);
+
+    parentElement.clearNeedsStyleRecalc();
+    parentElement.clearChildNeedsStyleRecalc();
+
+    if (parent().didPushScope)
         popScope();
-    } else
-        resolveChildren(slot, inheritedStyle, change, renderTreePosition);
 
-    slot.clearNeedsStyleRecalc();
-    slot.clearChildNeedsStyleRecalc();
+    scope().selectorFilter.popParent();
+
+    m_parentStack.removeLast();
 }
-#endif
 
-void TreeResolver::resolveRecursively(Element& current, RenderStyle& inheritedStyle, RenderTreePosition& renderTreePosition, Change change)
+void TreeResolver::popParentsToDepth(unsigned depth)
 {
-    ASSERT(change != Detach);
+    ASSERT(depth);
+    ASSERT(m_parentStack.size() >= depth);
 
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    if (is<HTMLSlotElement>(current)) {
-        resolveSlotAssignees(downcast<HTMLSlotElement>(current), inheritedStyle, renderTreePosition, change);
-        return;
-    }
-#endif
+    while (m_parentStack.size() > depth)
+        popParent();
+}
 
-    if (current.hasCustomStyleResolveCallbacks()) {
-        if (!current.willRecalcStyle(change))
-            return;
-    }
+void TreeResolver::resolveComposedTree()
+{
+    ASSERT(m_parentStack.size() == 1);
+    ASSERT(m_scopeStack.size() == 1);
 
+    auto descendants = composedTreeDescendants(m_document);
+    auto it = descendants.begin();
+    auto end = descendants.end();
+
+    // FIXME: SVG <use> element may cause tree mutations during style recalc.
+    it.dropAssertions();
+
+    while (it != end) {
+        popParentsToDepth(it.depth());
+
+        auto& node = *it;
+        auto& parent = this->parent();
+
+        ASSERT(node.containingShadowRoot() == scope().shadowRoot);
+        ASSERT(node.parentElement() == parent.element || is<ShadowRoot>(node.parentNode()) || node.parentElement()->shadowRoot());
+
+        if (auto* existingRenderer = node.renderer())
+            parent.renderTreePosition.invalidateNextSibling(*existingRenderer);
+
+        if (is<Text>(node)) {
+            if (node.needsStyleRecalc())
+                resolveTextNode(downcast<Text>(node), parent.renderTreePosition);
+            it.traverseNextSkippingChildren();
+            continue;
+        }
+
+        auto& element = downcast<Element>(node);
+
+        // FIXME: We should deal with this during style invalidation.
+        bool affectedByPreviousSibling = element.styleIsAffectedByPreviousSibling() && parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
+        if (element.needsStyleRecalc() || parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
+            parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle = element.affectsNextSiblingElementStyle();
+
+        Change change = NoChange;
+
+        bool shouldResolve = parent.change >= Inherit || element.needsStyleRecalc() || affectedByPreviousSibling;
+        if (shouldResolve) {
 #if PLATFORM(IOS)
-    CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&current, current.renderStyle());
+            CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&element, element.renderStyle());
 #endif
+            element.resetComputedStyle();
 
-    if (change > NoChange || current.needsStyleRecalc())
-        current.resetComputedStyle();
+            if (element.hasCustomStyleResolveCallbacks()) {
+                if (!element.willRecalcStyle(parent.change)) {
+                    it.traverseNextSkippingChildren();
+                    continue;
+                }
+            }
+            change = resolveElement(element);
 
-    if (change >= Inherit || current.needsStyleRecalc())
-        change = resolveLocally(current, inheritedStyle, renderTreePosition, change);
+            element.clearNeedsStyleRecalc();
 
-    auto* renderer = current.renderer();
+            if (element.hasCustomStyleResolveCallbacks())
+                element.didRecalcStyle(change);
 
-    if (change != Detach && renderer) {
-        auto* shadowRoot = current.shadowRoot();
-        if (shadowRoot && (change >= Inherit || shadowRoot->childNeedsStyleRecalc() || shadowRoot->needsStyleRecalc())) {
-            SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, current);
+            if (change == Detach) {
+                it.traverseNextSkippingChildren();
+                continue;
+            }
 
-            pushScope(*shadowRoot);
-            resolveShadowTree(change, renderer->style());
-            popScope();
+            if (affectedByPreviousSibling)
+                change = Force;
         }
 
-        RenderTreePosition childRenderTreePosition(*renderer);
-        resolveBeforeOrAfterPseudoElement(current, change, BEFORE, childRenderTreePosition);
+#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
+        if (is<HTMLSlotElement>(element)) {
+            // FIXME: We should compute style for the slot and use it as parent style.
+            // FIXME: This should be display:contents check.
+            // Duplicate the style and render tree position from the current context.
+            pushParent(element, parent.style.get(), parent.renderTreePosition, change);
+            it.traverseNext();
+            continue;
+        }
+#endif
+        auto* renderer = element.renderer();
+        if (!renderer) {
+            resetStyleForNonRenderedDescendants(element);
+            element.clearChildNeedsStyleRecalc();
+        }
 
-        bool skipChildren = shadowRoot;
-        if (!skipChildren)
-            resolveChildren(current, renderer->style(), change, childRenderTreePosition);
+        bool shouldIterateChildren = renderer && (element.childNeedsStyleRecalc() || change != NoChange);
+        if (!shouldIterateChildren) {
+            it.traverseNextSkippingChildren();
+            continue;
+        }
 
-        resolveBeforeOrAfterPseudoElement(current, change, AFTER, childRenderTreePosition);
+        pushParent(element, renderer->style(), RenderTreePosition(*renderer), change);
+
+        it.traverseNext();
     }
-    if (change != Detach && !renderer)
-        resetStyleForNonRenderedDescendants(current);
 
-    current.clearNeedsStyleRecalc();
-    current.clearChildNeedsStyleRecalc();
-    
-    if (current.hasCustomStyleResolveCallbacks())
-        current.didRecalcStyle(change);
+    popParentsToDepth(1);
 }
 
 void TreeResolver::resolve(Change change)
 {
-    ASSERT(!scope().shadowRoot);
-
     auto& renderView = *m_document.renderView();
 
     Element* documentElement = m_document.documentElement();
@@ -928,15 +965,21 @@
     if (change != Force && !documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
         return;
 
+    m_scopeStack.append(adoptRef(*new Scope(m_document)));
+
     // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
     renderView.setUsesFirstLineRules(renderView.usesFirstLineRules() || scope().styleResolver.usesFirstLineRules());
     renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || scope().styleResolver.usesFirstLetterRules());
 
-    RenderTreePosition renderTreePosition(renderView);
-    resolveRecursively(*documentElement, *m_document.renderStyle(), renderTreePosition, change);
+    m_parentStack.append(Parent(m_document, change));
 
+    resolveComposedTree();
+
     renderView.setUsesFirstLineRules(scope().styleResolver.usesFirstLineRules());
     renderView.setUsesFirstLetterRules(scope().styleResolver.usesFirstLetterRules());
+
+    m_parentStack.clear();
+    m_scopeStack.clear();
 }
 
 void detachRenderTree(Element& element)

Modified: releases/WebKitGTK/webkit-2.12/Source/WebCore/style/StyleTreeResolver.h (197077 => 197078)


--- releases/WebKitGTK/webkit-2.12/Source/WebCore/style/StyleTreeResolver.h	2016-02-25 10:00:13 UTC (rev 197077)
+++ releases/WebKitGTK/webkit-2.12/Source/WebCore/style/StyleTreeResolver.h	2016-02-25 10:00:32 UTC (rev 197078)
@@ -27,6 +27,7 @@
 #define StyleTreeResolver_h
 
 #include "RenderStyleConstants.h"
+#include "RenderTreePosition.h"
 #include "SelectorFilter.h"
 #include "StyleChange.h"
 #include "StyleSharingResolver.h"
@@ -41,7 +42,6 @@
 class HTMLSlotElement;
 class Node;
 class RenderStyle;
-class RenderTreePosition;
 class Settings;
 class ShadowRoot;
 class StyleResolver;
@@ -56,14 +56,10 @@
     void resolve(Change);
 
 private:
-    void resolveShadowTree(Change, RenderStyle& inheritedStyle);
-
     Ref<RenderStyle> styleForElement(Element&, RenderStyle& inheritedStyle);
 
-    void resolveRecursively(Element&, RenderStyle& inheritedStyle, RenderTreePosition&, Change);
-    Change resolveLocally(Element&, RenderStyle& inheritedStyle, RenderTreePosition&, Change inheritedChange);
-    void resolveChildren(Element&, RenderStyle&, Change, RenderTreePosition&);
-    void resolveChildAtShadowBoundary(Node&, RenderStyle& inheritedStyle, RenderTreePosition&, Change);
+    void resolveComposedTree();
+    Change resolveElement(Element&);
     void resolveBeforeOrAfterPseudoElement(Element&, Change, PseudoId, RenderTreePosition&);
 
     void createRenderTreeRecursively(Element&, RenderStyle&, RenderTreePosition&, RefPtr<RenderStyle>&& resolvedStyle);
@@ -73,7 +69,6 @@
     void createRenderTreeForShadowRoot(ShadowRoot&);
 
 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    void resolveSlotAssignees(HTMLSlotElement&, RenderStyle& inheritedStyle, RenderTreePosition&, Change);
     void createRenderTreeForSlotAssignees(HTMLSlotElement&, RenderStyle& inheritedStyle, RenderTreePosition&);
 #endif
 
@@ -87,13 +82,33 @@
         Scope(Document&);
         Scope(ShadowRoot&, Scope& enclosingScope);
     };
+
+    struct Parent {
+        Element* element;
+        Ref<RenderStyle> style;
+        RenderTreePosition renderTreePosition;
+        Change change;
+        bool didPushScope { false };
+        bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle { false };
+
+        Parent(Document&, Change);
+        Parent(Element&, RenderStyle&, RenderTreePosition, Change);
+    };
+
     Scope& scope() { return m_scopeStack.last(); }
+    Parent& parent() { return m_parentStack.last(); }
+
     void pushScope(ShadowRoot&);
     void pushEnclosingScope();
     void popScope();
 
+    void pushParent(Element&, RenderStyle&, RenderTreePosition, Change);
+    void popParent();
+    void popParentsToDepth(unsigned depth);
+
     Document& m_document;
     Vector<Ref<Scope>, 4> m_scopeStack;
+    Vector<Parent, 32> m_parentStack;
 };
 
 void detachRenderTree(Element&);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to