Title: [196864] trunk/Source/WebCore
Revision
196864
Author
[email protected]
Date
2016-02-20 10:29:40 -0800 (Sat, 20 Feb 2016)

Log Message

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: trunk/Source/WebCore/ChangeLog (196863 => 196864)


--- trunk/Source/WebCore/ChangeLog	2016-02-20 18:16:37 UTC (rev 196863)
+++ trunk/Source/WebCore/ChangeLog	2016-02-20 18:29:40 UTC (rev 196864)
@@ -1,3 +1,73 @@
+2016-02-20  Antti Koivisto  <[email protected]>
+
+        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-20  Andreas Kling  <[email protected]>
 
         REGRESSION(r196780): Fake memory handler takes too long to run now.

Modified: trunk/Source/WebCore/css/StyleInvalidationAnalysis.cpp (196863 => 196864)


--- trunk/Source/WebCore/css/StyleInvalidationAnalysis.cpp	2016-02-20 18:16:37 UTC (rev 196863)
+++ trunk/Source/WebCore/css/StyleInvalidationAnalysis.cpp	2016-02-20 18:29:40 UTC (rev 196864)
@@ -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: trunk/Source/WebCore/dom/ComposedTreeIterator.cpp (196863 => 196864)


--- trunk/Source/WebCore/dom/ComposedTreeIterator.cpp	2016-02-20 18:16:37 UTC (rev 196863)
+++ trunk/Source/WebCore/dom/ComposedTreeIterator.cpp	2016-02-20 18:29:40 UTC (rev 196864)
@@ -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: trunk/Source/WebCore/dom/ComposedTreeIterator.h (196863 => 196864)


--- trunk/Source/WebCore/dom/ComposedTreeIterator.h	2016-02-20 18:16:37 UTC (rev 196863)
+++ trunk/Source/WebCore/dom/ComposedTreeIterator.h	2016-02-20 18:29:40 UTC (rev 196864)
@@ -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: trunk/Source/WebCore/dom/PseudoElement.h (196863 => 196864)


--- trunk/Source/WebCore/dom/PseudoElement.h	2016-02-20 18:16:37 UTC (rev 196863)
+++ trunk/Source/WebCore/dom/PseudoElement.h	2016-02-20 18:29:40 UTC (rev 196864)
@@ -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: trunk/Source/WebCore/style/StyleTreeResolver.cpp (196863 => 196864)


--- trunk/Source/WebCore/style/StyleTreeResolver.cpp	2016-02-20 18:16:37 UTC (rev 196863)
+++ trunk/Source/WebCore/style/StyleTreeResolver.cpp	2016-02-20 18:29:40 UTC (rev 196864)
@@ -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: trunk/Source/WebCore/style/StyleTreeResolver.h (196863 => 196864)


--- trunk/Source/WebCore/style/StyleTreeResolver.h	2016-02-20 18:16:37 UTC (rev 196863)
+++ trunk/Source/WebCore/style/StyleTreeResolver.h	2016-02-20 18:29:40 UTC (rev 196864)
@@ -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
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to