<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[196864] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/196864">196864</a></dd>
<dt>Author</dt> <dd>antti@apple.com</dd>
<dt>Date</dt> <dd>2016-02-20 10:29:40 -0800 (Sat, 20 Feb 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>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):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecssStyleInvalidationAnalysiscpp">trunk/Source/WebCore/css/StyleInvalidationAnalysis.cpp</a></li>
<li><a href="#trunkSourceWebCoredomComposedTreeIteratorcpp">trunk/Source/WebCore/dom/ComposedTreeIterator.cpp</a></li>
<li><a href="#trunkSourceWebCoredomComposedTreeIteratorh">trunk/Source/WebCore/dom/ComposedTreeIterator.h</a></li>
<li><a href="#trunkSourceWebCoredomPseudoElementh">trunk/Source/WebCore/dom/PseudoElement.h</a></li>
<li><a href="#trunkSourceWebCorestyleStyleTreeResolvercpp">trunk/Source/WebCore/style/StyleTreeResolver.cpp</a></li>
<li><a href="#trunkSourceWebCorestyleStyleTreeResolverh">trunk/Source/WebCore/style/StyleTreeResolver.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (196863 => 196864)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,3 +1,73 @@
</span><ins>+2016-02-20  Antti Koivisto  &lt;antti@apple.com&gt;
+
+        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):
+
</ins><span class="cx"> 2016-02-20  Andreas Kling  &lt;akling@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION(r196780): Fake memory handler takes too long to run now.
</span></span></pre></div>
<a id="trunkSourceWebCorecssStyleInvalidationAnalysiscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/css/StyleInvalidationAnalysis.cpp (196863 => 196864)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -99,8 +99,8 @@
</span><span class="cx"> {
</span><span class="cx">     if (m_hasShadowPseudoElementRulesInAuthorSheet) {
</span><span class="cx">         // FIXME: This could do actual rule matching too.
</span><del>-        if (auto* shadowRoot = element.shadowRoot())
-            shadowRoot-&gt;setNeedsStyleRecalc();
</del><ins>+        if (element.shadowRoot())
+            element.setNeedsStyleRecalc();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     switch (element.styleChangeType()) {
</span></span></pre></div>
<a id="trunkSourceWebCoredomComposedTreeIteratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ComposedTreeIterator.cpp (196863 => 196864)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -106,6 +106,13 @@
</span><span class="cx">     m_contextStack.reverse();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void ComposedTreeIterator::dropAssertions()
+{
+    for (auto&amp; context : m_contextStack)
+        context.iterator.dropAssertions();
+    m_didDropAssertions = true;
+}
+
</ins><span class="cx"> void ComposedTreeIterator::traverseShadowRoot(ShadowRoot&amp; shadowRoot)
</span><span class="cx"> {
</span><span class="cx">     Context shadowContext(shadowRoot);
</span><span class="lines">@@ -115,6 +122,9 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (m_didDropAssertions)
+        shadowContext.iterator.dropAssertions();
+
</ins><span class="cx">     m_contextStack.append(WTFMove(shadowContext));
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoredomComposedTreeIteratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ComposedTreeIterator.h (196863 => 196864)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -54,6 +54,8 @@
</span><span class="cx"> 
</span><span class="cx">     unsigned depth() const;
</span><span class="cx"> 
</span><ins>+    void dropAssertions();
+
</ins><span class="cx"> private:
</span><span class="cx">     void initializeContextStack(ContainerNode&amp; root, Node&amp; current);
</span><span class="cx">     void traverseNextInShadowTree();
</span><span class="lines">@@ -81,6 +83,7 @@
</span><span class="cx">     const Context&amp; context() const { return m_contextStack.last(); }
</span><span class="cx">     Node&amp; current() { return *context().iterator; }
</span><span class="cx"> 
</span><ins>+    bool m_didDropAssertions { false };
</ins><span class="cx">     Vector&lt;Context, 4&gt; m_contextStack;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoredomPseudoElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/PseudoElement.h (196863 => 196864)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -47,6 +47,7 @@
</span><span class="cx"> 
</span><span class="cx">     virtual RefPtr&lt;RenderStyle&gt; customStyleForRenderer(RenderStyle&amp; parentStyle) override;
</span><span class="cx">     virtual void didAttachRenderers() override;
</span><ins>+    virtual void didRecalcStyle(Style::Change) override;
</ins><span class="cx">     virtual bool rendererIsNeeded(const RenderStyle&amp;) override;
</span><span class="cx"> 
</span><span class="cx">     // As per http://dev.w3.org/csswg/css3-regions/#flow-into, pseudo-elements such as ::first-line, ::first-letter, ::before or ::after
</span><span class="lines">@@ -63,7 +64,6 @@
</span><span class="cx"> private:
</span><span class="cx">     PseudoElement(Element&amp;, PseudoId);
</span><span class="cx"> 
</span><del>-    virtual void didRecalcStyle(Style::Change) override;
</del><span class="cx">     virtual PseudoId customPseudoId() const override { return m_pseudoId; }
</span><span class="cx"> 
</span><span class="cx">     Element* m_hostElement;
</span></span></pre></div>
<a id="trunkSourceWebCorestyleStyleTreeResolvercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/style/StyleTreeResolver.cpp (196863 => 196864)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -112,8 +112,6 @@
</span><span class="cx">     : m_document(document)
</span><span class="cx"> {
</span><span class="cx">     ensurePlaceholderStyle(document);
</span><del>-
-    m_scopeStack.append(adoptRef(*new Scope(document)));
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> TreeResolver::Scope::Scope(Document&amp; document)
</span><span class="lines">@@ -130,6 +128,22 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+TreeResolver::Parent::Parent(Document&amp; document, Change change)
+    : element(nullptr)
+    , style(*document.renderStyle())
+    , renderTreePosition(*document.renderView())
+    , change(change)
+{
+}
+
+TreeResolver::Parent::Parent(Element&amp; element, RenderStyle&amp; style, RenderTreePosition renderTreePosition, Change change)
+    : element(&amp;element)
+    , style(style)
+    , renderTreePosition(renderTreePosition)
+    , change(change)
+{
+}
+
</ins><span class="cx"> void TreeResolver::pushScope(ShadowRoot&amp; shadowRoot)
</span><span class="cx"> {
</span><span class="cx">     m_scopeStack.append(adoptRef(*new Scope(shadowRoot, scope())));
</span><span class="lines">@@ -425,20 +439,18 @@
</span><span class="cx"> 
</span><span class="cx"> static void resetStyleForNonRenderedDescendants(Element&amp; current)
</span><span class="cx"> {
</span><ins>+    // FIXME: This is not correct with shadow trees. This should be done with ComposedTreeIterator.
</ins><span class="cx">     ASSERT(!current.renderer());
</span><span class="cx">     bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
</span><span class="cx">     for (auto&amp; child : childrenOfType&lt;Element&gt;(current)) {
</span><span class="cx">         ASSERT(!child.renderer());
</span><del>-        if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
-            if (child.styleIsAffectedByPreviousSibling())
-                child.setNeedsStyleRecalc();
</del><ins>+        bool affectedByPreviousSibling = child.styleIsAffectedByPreviousSibling() &amp;&amp; elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
+        if (child.needsStyleRecalc() || elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
</ins><span class="cx">             elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
</span><del>-        }
</del><span class="cx"> 
</span><del>-        if (child.needsStyleRecalc()) {
</del><ins>+        if (child.needsStyleRecalc() || affectedByPreviousSibling) {
</ins><span class="cx">             child.resetComputedStyle();
</span><span class="cx">             child.clearNeedsStyleRecalc();
</span><del>-            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = child.affectsNextSiblingElementStyle();
</del><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (child.childNeedsStyleRecalc()) {
</span><span class="lines">@@ -652,28 +664,32 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Change TreeResolver::resolveLocally(Element&amp; current, RenderStyle&amp; inheritedStyle, RenderTreePosition&amp; renderTreePosition, Change inheritedChange)
</del><ins>+Change TreeResolver::resolveElement(Element&amp; current)
</ins><span class="cx"> {
</span><span class="cx">     Change localChange = Detach;
</span><span class="cx">     RefPtr&lt;RenderStyle&gt; newStyle;
</span><span class="cx">     RefPtr&lt;RenderStyle&gt; currentStyle = current.renderStyle();
</span><span class="cx"> 
</span><span class="cx">     if (currentStyle &amp;&amp; current.styleChangeType() != ReconstructRenderTree) {
</span><del>-        Ref&lt;RenderStyle&gt; style(styleForElement(current, inheritedStyle));
</del><ins>+        Ref&lt;RenderStyle&gt; style(styleForElement(current, parent().style));
</ins><span class="cx">         newStyle = style.ptr();
</span><span class="cx">         localChange = determineChange(*currentStyle, style);
</span><span class="cx">     }
</span><span class="cx">     if (localChange == Detach) {
</span><span class="cx">         if (current.renderer() || current.isNamedFlowContentNode())
</span><span class="cx">             detachRenderTree(current, ReattachDetach);
</span><del>-        createRenderTreeRecursively(current, inheritedStyle, renderTreePosition, newStyle.release());
</del><ins>+#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
+        else if (is&lt;HTMLSlotElement&gt;(current))
+            detachRenderTree(current, ReattachDetach);
+#endif
+        createRenderTreeRecursively(current, parent().style, parent().renderTreePosition, newStyle.release());
</ins><span class="cx">         invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(current);
</span><span class="cx"> 
</span><span class="cx">         return Detach;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (RenderElement* renderer = current.renderer()) {
</span><del>-        if (localChange != NoChange || pseudoStyleCacheIsInvalid(renderer, newStyle.get()) || (inheritedChange == Force &amp;&amp; renderer-&gt;requiresForcedStyleRecalcPropagation()) || current.styleChangeType() == SyntheticStyleChange)
</del><ins>+        if (localChange != NoChange || pseudoStyleCacheIsInvalid(renderer, newStyle.get()) || (parent().change == Force &amp;&amp; renderer-&gt;requiresForcedStyleRecalcPropagation()) || current.styleChangeType() == SyntheticStyleChange)
</ins><span class="cx">             renderer-&gt;setAnimatableStyle(*newStyle, current.styleChangeType() == SyntheticStyleChange ? StyleDifferenceRecompositeLayer : StyleDifferenceEqual);
</span><span class="cx">         else if (current.needsStyleRecalc()) {
</span><span class="cx">             // Although no change occurred, we use the new style so that the cousin style sharing code won't get
</span><span class="lines">@@ -689,10 +705,8 @@
</span><span class="cx">         scope().styleResolver.invalidateMatchedPropertiesCache();
</span><span class="cx">         return Force;
</span><span class="cx">     }
</span><del>-    if (inheritedChange == Force)
</del><ins>+    if (parent().change == Force || current.styleChangeType() &gt;= FullStyleChange)
</ins><span class="cx">         return Force;
</span><del>-    if (current.styleChangeType() &gt;= FullStyleChange)
-        return Force;
</del><span class="cx"> 
</span><span class="cx">     return localChange;
</span><span class="cx"> }
</span><span class="lines">@@ -716,48 +730,28 @@
</span><span class="cx">     invalidateWhitespaceOnlyTextSiblingsAfterAttachIfNeeded(text);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void TreeResolver::resolveChildAtShadowBoundary(Node&amp; child, RenderStyle&amp; inheritedStyle, RenderTreePosition&amp; renderTreePosition, Style::Change change)
</del><ins>+void TreeResolver::resolveBeforeOrAfterPseudoElement(Element&amp; current, Change change, PseudoId pseudoId, RenderTreePosition&amp; renderTreePosition)
</ins><span class="cx"> {
</span><del>-    if (auto* renderer = child.renderer())
-        renderTreePosition.invalidateNextSibling(*renderer);
-
-    if (is&lt;Text&gt;(child) &amp;&amp; child.needsStyleRecalc()) {
-        resolveTextNode(downcast&lt;Text&gt;(child), renderTreePosition);
</del><ins>+    if (!current.renderer())
</ins><span class="cx">         return;
</span><ins>+    PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId);
+    if (!existingPseudoElement) {
+        createRenderTreeForBeforeOrAfterPseudoElement(current, pseudoId, renderTreePosition);
+        return;
</ins><span class="cx">     }
</span><del>-    if (is&lt;Element&gt;(child))
-        resolveRecursively(downcast&lt;Element&gt;(child), inheritedStyle, renderTreePosition, change);
-}
</del><span class="cx"> 
</span><del>-void TreeResolver::resolveShadowTree(Style::Change change, RenderStyle&amp; inheritedStyle)
-{
-    ASSERT(scope().shadowRoot);
-    auto&amp; host = *scope().shadowRoot-&gt;host();
-    ASSERT(host.renderer());
-    if (scope().shadowRoot-&gt;styleChangeType() &gt;= FullStyleChange)
-        change = Force;
-    RenderTreePosition renderTreePosition(*host.renderer());
-    for (auto* child = scope().shadowRoot-&gt;firstChild(); child; child = child-&gt;nextSibling())
-        resolveChildAtShadowBoundary(*child, inheritedStyle, renderTreePosition, change);
</del><ins>+    if (existingPseudoElement-&gt;renderer())
+        renderTreePosition.invalidateNextSibling(*existingPseudoElement-&gt;renderer());
</ins><span class="cx"> 
</span><del>-    scope().shadowRoot-&gt;clearNeedsStyleRecalc();
-    scope().shadowRoot-&gt;clearChildNeedsStyleRecalc();
-}
</del><ins>+    if (change == NoChange &amp;&amp; !existingPseudoElement-&gt;needsStyleRecalc())
+        return;
</ins><span class="cx"> 
</span><del>-void TreeResolver::resolveBeforeOrAfterPseudoElement(Element&amp; current, Change change, PseudoId pseudoId, RenderTreePosition&amp; renderTreePosition)
-{
-    ASSERT(current.renderer());
-    if (PseudoElement* existingPseudoElement = beforeOrAfterPseudoElement(current, pseudoId)) {
-        if (existingPseudoElement-&gt;renderer())
-            renderTreePosition.invalidateNextSibling(*existingPseudoElement-&gt;renderer());
-
-        if (needsPseudoElement(current, pseudoId))
-            resolveRecursively(*existingPseudoElement, current.renderer()-&gt;style(), renderTreePosition, current.needsStyleRecalc() ? Force : change);
-        else
-            clearBeforeOrAfterPseudoElement(current, pseudoId);
-        return;
-    }
-    createRenderTreeForBeforeOrAfterPseudoElement(current, pseudoId, renderTreePosition);
</del><ins>+    if (needsPseudoElement(current, pseudoId)) {
+        auto change = resolveElement(*existingPseudoElement);
+        existingPseudoElement-&gt;didRecalcStyle(change);
+        existingPseudoElement-&gt;clearNeedsStyleRecalc();
+    } else
+        clearBeforeOrAfterPseudoElement(current, pseudoId);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="lines">@@ -814,112 +808,155 @@
</span><span class="cx"> };
</span><span class="cx"> #endif // PLATFORM(IOS)
</span><span class="cx"> 
</span><del>-void TreeResolver::resolveChildren(Element&amp; current, RenderStyle&amp; inheritedStyle, Change change, RenderTreePosition&amp; childRenderTreePosition)
</del><ins>+void TreeResolver::pushParent(Element&amp; element, RenderStyle&amp; style, RenderTreePosition renderTreePosition, Change change)
</ins><span class="cx"> {
</span><del>-    SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, current, SelectorFilterPusher::NoPush);
</del><ins>+    scope().selectorFilter.pushParent(&amp;element);
</ins><span class="cx"> 
</span><del>-    bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle = false;
-    for (Node* child = current.firstChild(); child; child = child-&gt;nextSibling()) {
-        if (RenderObject* childRenderer = child-&gt;renderer())
-            childRenderTreePosition.invalidateNextSibling(*childRenderer);
-        if (is&lt;Text&gt;(*child) &amp;&amp; child-&gt;needsStyleRecalc()) {
-            resolveTextNode(downcast&lt;Text&gt;(*child), childRenderTreePosition);
-            continue;
-        }
-        if (!is&lt;Element&gt;(*child))
-            continue;
</del><ins>+    Parent parent(element, style, renderTreePosition, change);
</ins><span class="cx"> 
</span><del>-        Element&amp; childElement = downcast&lt;Element&gt;(*child);
-        if (elementNeedingStyleRecalcAffectsNextSiblingElementStyle) {
-            if (childElement.styleIsAffectedByPreviousSibling())
-                childElement.setNeedsStyleRecalc();
-            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
-        } else if (childElement.needsStyleRecalc())
-            elementNeedingStyleRecalcAffectsNextSiblingElementStyle = childElement.affectsNextSiblingElementStyle();
-        if (change &gt;= Inherit || childElement.childNeedsStyleRecalc() || childElement.needsStyleRecalc()) {
-            selectorFilterPusher.push();
-            resolveRecursively(childElement, inheritedStyle, childRenderTreePosition, change);
-        }
</del><ins>+    if (auto* shadowRoot = element.shadowRoot()) {
+        pushScope(*shadowRoot);
+        parent.didPushScope = true;
</ins><span class="cx">     }
</span><ins>+#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
+    else if (is&lt;HTMLSlotElement&gt;(element) &amp;&amp; downcast&lt;HTMLSlotElement&gt;(element).assignedNodes()) {
+        pushEnclosingScope();
+        parent.didPushScope = true;
+    }
+#endif
+
+    m_parentStack.append(WTFMove(parent));
+
+    resolveBeforeOrAfterPseudoElement(element, change, BEFORE, renderTreePosition);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-void TreeResolver::resolveSlotAssignees(HTMLSlotElement&amp; slot, RenderStyle&amp; inheritedStyle, RenderTreePosition&amp; renderTreePosition, Change change)
</del><ins>+void TreeResolver::popParent()
</ins><span class="cx"> {
</span><del>-    if (auto* assignedNodes = slot.assignedNodes()) {
-        pushEnclosingScope();
-        for (auto* child : *assignedNodes)
-            resolveChildAtShadowBoundary(*child, inheritedStyle, renderTreePosition, change);
</del><ins>+    auto&amp; parentElement = *parent().element;
+
+    resolveBeforeOrAfterPseudoElement(parentElement, parent().change, AFTER, parent().renderTreePosition);
+
+    parentElement.clearNeedsStyleRecalc();
+    parentElement.clearChildNeedsStyleRecalc();
+
+    if (parent().didPushScope)
</ins><span class="cx">         popScope();
</span><del>-    } else
-        resolveChildren(slot, inheritedStyle, change, renderTreePosition);
</del><span class="cx"> 
</span><del>-    slot.clearNeedsStyleRecalc();
-    slot.clearChildNeedsStyleRecalc();
</del><ins>+    scope().selectorFilter.popParent();
+
+    m_parentStack.removeLast();
</ins><span class="cx"> }
</span><del>-#endif
</del><span class="cx"> 
</span><del>-void TreeResolver::resolveRecursively(Element&amp; current, RenderStyle&amp; inheritedStyle, RenderTreePosition&amp; renderTreePosition, Change change)
</del><ins>+void TreeResolver::popParentsToDepth(unsigned depth)
</ins><span class="cx"> {
</span><del>-    ASSERT(change != Detach);
</del><ins>+    ASSERT(depth);
+    ASSERT(m_parentStack.size() &gt;= depth);
</ins><span class="cx"> 
</span><del>-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    if (is&lt;HTMLSlotElement&gt;(current)) {
-        resolveSlotAssignees(downcast&lt;HTMLSlotElement&gt;(current), inheritedStyle, renderTreePosition, change);
-        return;
-    }
-#endif
</del><ins>+    while (m_parentStack.size() &gt; depth)
+        popParent();
+}
</ins><span class="cx"> 
</span><del>-    if (current.hasCustomStyleResolveCallbacks()) {
-        if (!current.willRecalcStyle(change))
-            return;
-    }
</del><ins>+void TreeResolver::resolveComposedTree()
+{
+    ASSERT(m_parentStack.size() == 1);
+    ASSERT(m_scopeStack.size() == 1);
</ins><span class="cx"> 
</span><ins>+    auto descendants = composedTreeDescendants(m_document);
+    auto it = descendants.begin();
+    auto end = descendants.end();
+
+    // FIXME: SVG &lt;use&gt; element may cause tree mutations during style recalc.
+    it.dropAssertions();
+
+    while (it != end) {
+        popParentsToDepth(it.depth());
+
+        auto&amp; node = *it;
+        auto&amp; parent = this-&gt;parent();
+
+        ASSERT(node.containingShadowRoot() == scope().shadowRoot);
+        ASSERT(node.parentElement() == parent.element || is&lt;ShadowRoot&gt;(node.parentNode()) || node.parentElement()-&gt;shadowRoot());
+
+        if (auto* existingRenderer = node.renderer())
+            parent.renderTreePosition.invalidateNextSibling(*existingRenderer);
+
+        if (is&lt;Text&gt;(node)) {
+            if (node.needsStyleRecalc())
+                resolveTextNode(downcast&lt;Text&gt;(node), parent.renderTreePosition);
+            it.traverseNextSkippingChildren();
+            continue;
+        }
+
+        auto&amp; element = downcast&lt;Element&gt;(node);
+
+        // FIXME: We should deal with this during style invalidation.
+        bool affectedByPreviousSibling = element.styleIsAffectedByPreviousSibling() &amp;&amp; parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle;
+        if (element.needsStyleRecalc() || parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle)
+            parent.elementNeedingStyleRecalcAffectsNextSiblingElementStyle = element.affectsNextSiblingElementStyle();
+
+        Change change = NoChange;
+
+        bool shouldResolve = parent.change &gt;= Inherit || element.needsStyleRecalc() || affectedByPreviousSibling;
+        if (shouldResolve) {
</ins><span class="cx"> #if PLATFORM(IOS)
</span><del>-    CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&amp;current, current.renderStyle());
</del><ins>+            CheckForVisibilityChangeOnRecalcStyle checkForVisibilityChange(&amp;element, element.renderStyle());
</ins><span class="cx"> #endif
</span><ins>+            element.resetComputedStyle();
</ins><span class="cx"> 
</span><del>-    if (change &gt; NoChange || current.needsStyleRecalc())
-        current.resetComputedStyle();
</del><ins>+            if (element.hasCustomStyleResolveCallbacks()) {
+                if (!element.willRecalcStyle(parent.change)) {
+                    it.traverseNextSkippingChildren();
+                    continue;
+                }
+            }
+            change = resolveElement(element);
</ins><span class="cx"> 
</span><del>-    if (change &gt;= Inherit || current.needsStyleRecalc())
-        change = resolveLocally(current, inheritedStyle, renderTreePosition, change);
</del><ins>+            element.clearNeedsStyleRecalc();
</ins><span class="cx"> 
</span><del>-    auto* renderer = current.renderer();
</del><ins>+            if (element.hasCustomStyleResolveCallbacks())
+                element.didRecalcStyle(change);
</ins><span class="cx"> 
</span><del>-    if (change != Detach &amp;&amp; renderer) {
-        auto* shadowRoot = current.shadowRoot();
-        if (shadowRoot &amp;&amp; (change &gt;= Inherit || shadowRoot-&gt;childNeedsStyleRecalc() || shadowRoot-&gt;needsStyleRecalc())) {
-            SelectorFilterPusher selectorFilterPusher(scope().selectorFilter, current);
</del><ins>+            if (change == Detach) {
+                it.traverseNextSkippingChildren();
+                continue;
+            }
</ins><span class="cx"> 
</span><del>-            pushScope(*shadowRoot);
-            resolveShadowTree(change, renderer-&gt;style());
-            popScope();
</del><ins>+            if (affectedByPreviousSibling)
+                change = Force;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        RenderTreePosition childRenderTreePosition(*renderer);
-        resolveBeforeOrAfterPseudoElement(current, change, BEFORE, childRenderTreePosition);
</del><ins>+#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
+        if (is&lt;HTMLSlotElement&gt;(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();
+        }
</ins><span class="cx"> 
</span><del>-        bool skipChildren = shadowRoot;
-        if (!skipChildren)
-            resolveChildren(current, renderer-&gt;style(), change, childRenderTreePosition);
</del><ins>+        bool shouldIterateChildren = renderer &amp;&amp; (element.childNeedsStyleRecalc() || change != NoChange);
+        if (!shouldIterateChildren) {
+            it.traverseNextSkippingChildren();
+            continue;
+        }
</ins><span class="cx"> 
</span><del>-        resolveBeforeOrAfterPseudoElement(current, change, AFTER, childRenderTreePosition);
</del><ins>+        pushParent(element, renderer-&gt;style(), RenderTreePosition(*renderer), change);
+
+        it.traverseNext();
</ins><span class="cx">     }
</span><del>-    if (change != Detach &amp;&amp; !renderer)
-        resetStyleForNonRenderedDescendants(current);
</del><span class="cx"> 
</span><del>-    current.clearNeedsStyleRecalc();
-    current.clearChildNeedsStyleRecalc();
-    
-    if (current.hasCustomStyleResolveCallbacks())
-        current.didRecalcStyle(change);
</del><ins>+    popParentsToDepth(1);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void TreeResolver::resolve(Change change)
</span><span class="cx"> {
</span><del>-    ASSERT(!scope().shadowRoot);
-
</del><span class="cx">     auto&amp; renderView = *m_document.renderView();
</span><span class="cx"> 
</span><span class="cx">     Element* documentElement = m_document.documentElement();
</span><span class="lines">@@ -928,15 +965,21 @@
</span><span class="cx">     if (change != Force &amp;&amp; !documentElement-&gt;childNeedsStyleRecalc() &amp;&amp; !documentElement-&gt;needsStyleRecalc())
</span><span class="cx">         return;
</span><span class="cx"> 
</span><ins>+    m_scopeStack.append(adoptRef(*new Scope(m_document)));
+
</ins><span class="cx">     // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
</span><span class="cx">     renderView.setUsesFirstLineRules(renderView.usesFirstLineRules() || scope().styleResolver.usesFirstLineRules());
</span><span class="cx">     renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || scope().styleResolver.usesFirstLetterRules());
</span><span class="cx"> 
</span><del>-    RenderTreePosition renderTreePosition(renderView);
-    resolveRecursively(*documentElement, *m_document.renderStyle(), renderTreePosition, change);
</del><ins>+    m_parentStack.append(Parent(m_document, change));
</ins><span class="cx"> 
</span><ins>+    resolveComposedTree();
+
</ins><span class="cx">     renderView.setUsesFirstLineRules(scope().styleResolver.usesFirstLineRules());
</span><span class="cx">     renderView.setUsesFirstLetterRules(scope().styleResolver.usesFirstLetterRules());
</span><ins>+
+    m_parentStack.clear();
+    m_scopeStack.clear();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void detachRenderTree(Element&amp; element)
</span></span></pre></div>
<a id="trunkSourceWebCorestyleStyleTreeResolverh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/style/StyleTreeResolver.h (196863 => 196864)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> #define StyleTreeResolver_h
</span><span class="cx"> 
</span><span class="cx"> #include &quot;RenderStyleConstants.h&quot;
</span><ins>+#include &quot;RenderTreePosition.h&quot;
</ins><span class="cx"> #include &quot;SelectorFilter.h&quot;
</span><span class="cx"> #include &quot;StyleChange.h&quot;
</span><span class="cx"> #include &quot;StyleSharingResolver.h&quot;
</span><span class="lines">@@ -41,7 +42,6 @@
</span><span class="cx"> class HTMLSlotElement;
</span><span class="cx"> class Node;
</span><span class="cx"> class RenderStyle;
</span><del>-class RenderTreePosition;
</del><span class="cx"> class Settings;
</span><span class="cx"> class ShadowRoot;
</span><span class="cx"> class StyleResolver;
</span><span class="lines">@@ -56,14 +56,10 @@
</span><span class="cx">     void resolve(Change);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    void resolveShadowTree(Change, RenderStyle&amp; inheritedStyle);
-
</del><span class="cx">     Ref&lt;RenderStyle&gt; styleForElement(Element&amp;, RenderStyle&amp; inheritedStyle);
</span><span class="cx"> 
</span><del>-    void resolveRecursively(Element&amp;, RenderStyle&amp; inheritedStyle, RenderTreePosition&amp;, Change);
-    Change resolveLocally(Element&amp;, RenderStyle&amp; inheritedStyle, RenderTreePosition&amp;, Change inheritedChange);
-    void resolveChildren(Element&amp;, RenderStyle&amp;, Change, RenderTreePosition&amp;);
-    void resolveChildAtShadowBoundary(Node&amp;, RenderStyle&amp; inheritedStyle, RenderTreePosition&amp;, Change);
</del><ins>+    void resolveComposedTree();
+    Change resolveElement(Element&amp;);
</ins><span class="cx">     void resolveBeforeOrAfterPseudoElement(Element&amp;, Change, PseudoId, RenderTreePosition&amp;);
</span><span class="cx"> 
</span><span class="cx">     void createRenderTreeRecursively(Element&amp;, RenderStyle&amp;, RenderTreePosition&amp;, RefPtr&lt;RenderStyle&gt;&amp;&amp; resolvedStyle);
</span><span class="lines">@@ -73,7 +69,6 @@
</span><span class="cx">     void createRenderTreeForShadowRoot(ShadowRoot&amp;);
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
</span><del>-    void resolveSlotAssignees(HTMLSlotElement&amp;, RenderStyle&amp; inheritedStyle, RenderTreePosition&amp;, Change);
</del><span class="cx">     void createRenderTreeForSlotAssignees(HTMLSlotElement&amp;, RenderStyle&amp; inheritedStyle, RenderTreePosition&amp;);
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="lines">@@ -87,13 +82,33 @@
</span><span class="cx">         Scope(Document&amp;);
</span><span class="cx">         Scope(ShadowRoot&amp;, Scope&amp; enclosingScope);
</span><span class="cx">     };
</span><ins>+
+    struct Parent {
+        Element* element;
+        Ref&lt;RenderStyle&gt; style;
+        RenderTreePosition renderTreePosition;
+        Change change;
+        bool didPushScope { false };
+        bool elementNeedingStyleRecalcAffectsNextSiblingElementStyle { false };
+
+        Parent(Document&amp;, Change);
+        Parent(Element&amp;, RenderStyle&amp;, RenderTreePosition, Change);
+    };
+
</ins><span class="cx">     Scope&amp; scope() { return m_scopeStack.last(); }
</span><ins>+    Parent&amp; parent() { return m_parentStack.last(); }
+
</ins><span class="cx">     void pushScope(ShadowRoot&amp;);
</span><span class="cx">     void pushEnclosingScope();
</span><span class="cx">     void popScope();
</span><span class="cx"> 
</span><ins>+    void pushParent(Element&amp;, RenderStyle&amp;, RenderTreePosition, Change);
+    void popParent();
+    void popParentsToDepth(unsigned depth);
+
</ins><span class="cx">     Document&amp; m_document;
</span><span class="cx">     Vector&lt;Ref&lt;Scope&gt;, 4&gt; m_scopeStack;
</span><ins>+    Vector&lt;Parent, 32&gt; m_parentStack;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> void detachRenderTree(Element&amp;);
</span></span></pre>
</div>
</div>

</body>
</html>