<!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>[196281] 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/196281">196281</a></dd>
<dt>Author</dt> <dd>antti@apple.com</dd>
<dt>Date</dt> <dd>2016-02-08 17:15:52 -0800 (Mon, 08 Feb 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Implement ComposedTreeIterator in terms of ElementAndTextDescendantIterator
https://bugs.webkit.org/show_bug.cgi?id=154003

Reviewed by Darin Adler.

Currently ComposedTreeIterator implements tree traversal using NodeTraversal. This makes it overly complicated.
It can also return nodes other than Element and Text which should not be part of the composed tree.

This patch adds a new iterator type, ElementAndTextDescendantIterator, similar to the existing ElementDescendantIterator.
ComposedTreeIterator is then implemented using this new iterator.

When entering a shadow tree or a slot the local iterator is pushed along with the context stack and a new local
iterator is initialized for the new context. When leaving a shadow tree the context stack is popped and the previous
local iterator becomes active.

* WebCore.xcodeproj/project.pbxproj:
* dom/ComposedTreeIterator.cpp:
(WebCore::ComposedTreeIterator::ComposedTreeIterator):
(WebCore::ComposedTreeIterator::initializeContextStack):
(WebCore::ComposedTreeIterator::pushContext):
(WebCore::ComposedTreeIterator::traverseNextInShadowTree):
(WebCore::ComposedTreeIterator::traverseNextLeavingContext):
(WebCore::ComposedTreeIterator::advanceInSlot):
(WebCore::ComposedTreeIterator::traverseSiblingInSlot):
(WebCore::ComposedTreeIterator::initializeShadowStack): Deleted.
(WebCore::ComposedTreeIterator::traverseParentInShadowTree): Deleted.
(WebCore::ComposedTreeIterator::traverseNextSiblingSlot): Deleted.
(WebCore::ComposedTreeIterator::traversePreviousSiblingSlot): Deleted.
* dom/ComposedTreeIterator.h:
(WebCore::ComposedTreeIterator::operator*):
(WebCore::ComposedTreeIterator::operator-&gt;):
(WebCore::ComposedTreeIterator::operator==):
(WebCore::ComposedTreeIterator::operator!=):
(WebCore::ComposedTreeIterator::operator++):
(WebCore::ComposedTreeIterator::Context::Context):
(WebCore::ComposedTreeIterator::context):
(WebCore::ComposedTreeIterator::current):
(WebCore::ComposedTreeIterator::ComposedTreeIterator):
(WebCore::ComposedTreeIterator::traverseNext):
(WebCore::ComposedTreeIterator::traverseNextSkippingChildren):
(WebCore::ComposedTreeIterator::traverseNextSibling):
(WebCore::ComposedTreeIterator::traversePreviousSibling):
(WebCore::ComposedTreeDescendantAdapter::ComposedTreeDescendantAdapter):
(WebCore::ComposedTreeDescendantAdapter::begin):
(WebCore::ComposedTreeDescendantAdapter::end):
(WebCore::ComposedTreeDescendantAdapter::at):
(WebCore::ComposedTreeChildAdapter::Iterator::Iterator):
(WebCore::ComposedTreeChildAdapter::ComposedTreeChildAdapter):
(WebCore::ComposedTreeChildAdapter::begin):
(WebCore::ComposedTreeChildAdapter::end):
(WebCore::ComposedTreeChildAdapter::at):
(WebCore::ComposedTreeIterator::ShadowContext::ShadowContext): Deleted.
(WebCore::ComposedTreeIterator::traverseParent): Deleted.
* dom/ElementAndTextDescendantIterator.h: Added.

    New iterator type that traverses Element and Text nodes (that is renderable nodes only).
    It also tracks depth for future use.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</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="#trunkSourceWebCoredomElementIteratorAssertionsh">trunk/Source/WebCore/dom/ElementIteratorAssertions.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoredomElementAndTextDescendantIteratorh">trunk/Source/WebCore/dom/ElementAndTextDescendantIterator.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (196280 => 196281)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-02-09 01:06:23 UTC (rev 196280)
+++ trunk/Source/WebCore/ChangeLog        2016-02-09 01:15:52 UTC (rev 196281)
</span><span class="lines">@@ -1,3 +1,63 @@
</span><ins>+2016-02-08  Antti Koivisto  &lt;antti@apple.com&gt;
+
+        Implement ComposedTreeIterator in terms of ElementAndTextDescendantIterator
+        https://bugs.webkit.org/show_bug.cgi?id=154003
+
+        Reviewed by Darin Adler.
+
+        Currently ComposedTreeIterator implements tree traversal using NodeTraversal. This makes it overly complicated.
+        It can also return nodes other than Element and Text which should not be part of the composed tree.
+
+        This patch adds a new iterator type, ElementAndTextDescendantIterator, similar to the existing ElementDescendantIterator.
+        ComposedTreeIterator is then implemented using this new iterator.
+
+        When entering a shadow tree or a slot the local iterator is pushed along with the context stack and a new local
+        iterator is initialized for the new context. When leaving a shadow tree the context stack is popped and the previous
+        local iterator becomes active.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/ComposedTreeIterator.cpp:
+        (WebCore::ComposedTreeIterator::ComposedTreeIterator):
+        (WebCore::ComposedTreeIterator::initializeContextStack):
+        (WebCore::ComposedTreeIterator::pushContext):
+        (WebCore::ComposedTreeIterator::traverseNextInShadowTree):
+        (WebCore::ComposedTreeIterator::traverseNextLeavingContext):
+        (WebCore::ComposedTreeIterator::advanceInSlot):
+        (WebCore::ComposedTreeIterator::traverseSiblingInSlot):
+        (WebCore::ComposedTreeIterator::initializeShadowStack): Deleted.
+        (WebCore::ComposedTreeIterator::traverseParentInShadowTree): Deleted.
+        (WebCore::ComposedTreeIterator::traverseNextSiblingSlot): Deleted.
+        (WebCore::ComposedTreeIterator::traversePreviousSiblingSlot): Deleted.
+        * dom/ComposedTreeIterator.h:
+        (WebCore::ComposedTreeIterator::operator*):
+        (WebCore::ComposedTreeIterator::operator-&gt;):
+        (WebCore::ComposedTreeIterator::operator==):
+        (WebCore::ComposedTreeIterator::operator!=):
+        (WebCore::ComposedTreeIterator::operator++):
+        (WebCore::ComposedTreeIterator::Context::Context):
+        (WebCore::ComposedTreeIterator::context):
+        (WebCore::ComposedTreeIterator::current):
+        (WebCore::ComposedTreeIterator::ComposedTreeIterator):
+        (WebCore::ComposedTreeIterator::traverseNext):
+        (WebCore::ComposedTreeIterator::traverseNextSkippingChildren):
+        (WebCore::ComposedTreeIterator::traverseNextSibling):
+        (WebCore::ComposedTreeIterator::traversePreviousSibling):
+        (WebCore::ComposedTreeDescendantAdapter::ComposedTreeDescendantAdapter):
+        (WebCore::ComposedTreeDescendantAdapter::begin):
+        (WebCore::ComposedTreeDescendantAdapter::end):
+        (WebCore::ComposedTreeDescendantAdapter::at):
+        (WebCore::ComposedTreeChildAdapter::Iterator::Iterator):
+        (WebCore::ComposedTreeChildAdapter::ComposedTreeChildAdapter):
+        (WebCore::ComposedTreeChildAdapter::begin):
+        (WebCore::ComposedTreeChildAdapter::end):
+        (WebCore::ComposedTreeChildAdapter::at):
+        (WebCore::ComposedTreeIterator::ShadowContext::ShadowContext): Deleted.
+        (WebCore::ComposedTreeIterator::traverseParent): Deleted.
+        * dom/ElementAndTextDescendantIterator.h: Added.
+
+            New iterator type that traverses Element and Text nodes (that is renderable nodes only).
+            It also tracks depth for future use.
+
</ins><span class="cx"> 2016-02-08  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: copy({x:1}) should copy &quot;{x:1}&quot;, not &quot;[object Object]&quot;
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (196280 => 196281)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2016-02-09 01:06:23 UTC (rev 196280)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2016-02-09 01:15:52 UTC (rev 196281)
</span><span class="lines">@@ -6530,6 +6530,7 @@
</span><span class="cx">                 E43A023D17EB3713004CDD25 /* RenderElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E43A023C17EB3713004CDD25 /* RenderElement.cpp */; };
</span><span class="cx">                 E43AF8E61AC5B7E800CA717E /* CacheValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E43AF8E41AC5B7DD00CA717E /* CacheValidation.cpp */; };
</span><span class="cx">                 E43AF8E71AC5B7EC00CA717E /* CacheValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = E43AF8E51AC5B7DD00CA717E /* CacheValidation.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                E440AA961C68420800A265CC /* ElementAndTextDescendantIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E440AA951C68420800A265CC /* ElementAndTextDescendantIterator.h */; };
</ins><span class="cx">                 E44613A10CD6331000FADA75 /* HTMLAudioElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E446138F0CD6331000FADA75 /* HTMLAudioElement.cpp */; };
</span><span class="cx">                 E44613A20CD6331000FADA75 /* HTMLAudioElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E44613900CD6331000FADA75 /* HTMLAudioElement.h */; };
</span><span class="cx">                 E44613A40CD6331000FADA75 /* HTMLMediaElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E44613920CD6331000FADA75 /* HTMLMediaElement.cpp */; };
</span><span class="lines">@@ -14508,6 +14509,7 @@
</span><span class="cx">                 E43A023C17EB3713004CDD25 /* RenderElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderElement.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E43AF8E41AC5B7DD00CA717E /* CacheValidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CacheValidation.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E43AF8E51AC5B7DD00CA717E /* CacheValidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CacheValidation.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                E440AA951C68420800A265CC /* ElementAndTextDescendantIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementAndTextDescendantIterator.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 E446138F0CD6331000FADA75 /* HTMLAudioElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTMLAudioElement.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E44613900CD6331000FADA75 /* HTMLAudioElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLAudioElement.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E44613910CD6331000FADA75 /* HTMLAudioElement.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HTMLAudioElement.idl; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -24091,6 +24093,7 @@
</span><span class="cx">                                 A8C4A7F509D563270003AC8D /* Element.h */,
</span><span class="cx">                                 93EEC1EA09C2877700C515D1 /* Element.idl */,
</span><span class="cx">                                 E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */,
</span><ins>+                                E440AA951C68420800A265CC /* ElementAndTextDescendantIterator.h */,
</ins><span class="cx">                                 E46A2B1D17CA76B1000DBCD8 /* ElementChildIterator.h */,
</span><span class="cx">                                 B5B7A16F17C1080600E4AA0A /* ElementData.cpp */,
</span><span class="cx">                                 B5B7A16E17C1048000E4AA0A /* ElementData.h */,
</span><span class="lines">@@ -25850,6 +25853,7 @@
</span><span class="cx">                                 93309E0E099E64920056E581 /* FrameSelection.h in Headers */,
</span><span class="cx">                                 C4CD629B18383766007EBAF1 /* FrameSnapshotting.h in Headers */,
</span><span class="cx">                                 65A21485097A3F5300B9050A /* FrameTree.h in Headers */,
</span><ins>+                                E440AA961C68420800A265CC /* ElementAndTextDescendantIterator.h in Headers */,
</ins><span class="cx">                                 65CBFEFA0974F607001DAC25 /* FrameView.h in Headers */,
</span><span class="cx">                                 97205AB0123928CA00B17380 /* FTPDirectoryDocument.h in Headers */,
</span><span class="cx">                                 51C81B8A0C4422F70019ECE3 /* FTPDirectoryParser.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceWebCoredomComposedTreeIteratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ComposedTreeIterator.cpp (196280 => 196281)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/ComposedTreeIterator.cpp        2016-02-09 01:06:23 UTC (rev 196280)
+++ trunk/Source/WebCore/dom/ComposedTreeIterator.cpp        2016-02-09 01:15:52 UTC (rev 196281)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -30,163 +30,153 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><del>-void ComposedTreeIterator::initializeShadowStack()
</del><ins>+ComposedTreeIterator::ComposedTreeIterator(ContainerNode&amp; root)
</ins><span class="cx"> {
</span><ins>+    ASSERT(!is&lt;ShadowRoot&gt;(root));
+
+#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
+    if (is&lt;HTMLSlotElement&gt;(root)) {
+        auto&amp; slot = downcast&lt;HTMLSlotElement&gt;(root);
+        if (auto* assignedNodes = slot.assignedNodes()) {
+            initializeContextStack(root, *assignedNodes-&gt;at(0));
+            return;
+        }
+    }
+#endif
+    auto&amp; effectiveRoot = root.shadowRoot() ? *root.shadowRoot() : root;
+    m_contextStack.uncheckedAppend(Context(effectiveRoot));
+}
+
+ComposedTreeIterator::ComposedTreeIterator(ContainerNode&amp; root, Node&amp; current)
+{
+    ASSERT(!is&lt;ShadowRoot&gt;(root));
+    ASSERT(!is&lt;ShadowRoot&gt;(current));
+
+    bool mayNeedShadowStack = root.shadowRoot() || (&amp;current != &amp;root &amp;&amp; current.parentNode() != &amp;root);
+    if (mayNeedShadowStack)
+        initializeContextStack(root, current);
+    else
+        m_contextStack.uncheckedAppend(Context(root, current));
+}
+
+void ComposedTreeIterator::initializeContextStack(ContainerNode&amp; root, Node&amp; current)
+{
</ins><span class="cx">     // This code sets up the iterator for arbitrary node/root pair. It is not needed in common cases
</span><span class="cx">     // or completes fast because node and root are close (like in composedTreeChildren(*parent).at(node) case).
</span><del>-    auto* node = m_current;
-    while (node != &amp;m_root) {
</del><ins>+    auto* node = &amp;current;
+    auto* contextCurrent = node;
+    size_t currentSlotNodeIndex = notFound;
+    while (node != &amp;root) {
</ins><span class="cx">         auto* parent = node-&gt;parentNode();
</span><span class="cx">         if (!parent) {
</span><del>-            m_current = nullptr;
</del><ins>+            *this = { };
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         if (is&lt;ShadowRoot&gt;(*parent)) {
</span><span class="cx">             auto&amp; shadowRoot = downcast&lt;ShadowRoot&gt;(*parent);
</span><del>-            if (m_shadowStack.isEmpty() || m_shadowStack.last().host != shadowRoot.host())
-                m_shadowStack.append(shadowRoot.host());
</del><ins>+            m_contextStack.append(Context(shadowRoot, *contextCurrent, currentSlotNodeIndex));
</ins><span class="cx">             node = shadowRoot.host();
</span><ins>+            contextCurrent = node;
+            currentSlotNodeIndex = notFound;
</ins><span class="cx">             continue;
</span><span class="cx">         }
</span><span class="cx">         if (auto* shadowRoot = parent-&gt;shadowRoot()) {
</span><span class="cx"> #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
</span><del>-            m_shadowStack.append(shadowRoot-&gt;host());
</del><ins>+            m_contextStack.append(Context(*parent, *contextCurrent, currentSlotNodeIndex));
</ins><span class="cx">             auto* assignedSlot = shadowRoot-&gt;findAssignedSlot(*node);
</span><span class="cx">             if (assignedSlot) {
</span><del>-                size_t index = assignedSlot-&gt;assignedNodes()-&gt;find(node);
-                ASSERT(index != notFound);
-
-                m_shadowStack.last().currentSlot = assignedSlot;
-                m_shadowStack.last().currentSlotNodeIndex = index;
</del><ins>+                currentSlotNodeIndex = assignedSlot-&gt;assignedNodes()-&gt;find(node);
+                ASSERT(currentSlotNodeIndex != notFound);
</ins><span class="cx">                 node = assignedSlot;
</span><ins>+                contextCurrent = assignedSlot;
</ins><span class="cx">                 continue;
</span><span class="cx">             }
</span><span class="cx">             // The node is not part of the composed tree.
</span><span class="cx"> #else
</span><span class="cx">             UNUSED_PARAM(shadowRoot);
</span><del>-            m_current = nullptr;
-            return;
</del><span class="cx"> #endif
</span><ins>+            *this = { };
+            return;
</ins><span class="cx">         }
</span><span class="cx">         node = parent;
</span><span class="cx">     }
</span><del>-    m_shadowStack.reverse();
</del><ins>+    m_contextStack.append(Context(root, *contextCurrent, currentSlotNodeIndex));
+
+    m_contextStack.reverse();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool ComposedTreeIterator::pushContext(ShadowRoot&amp; shadowRoot)
+{
+    Context shadowContext(shadowRoot);
+    if (!shadowContext.iterator)
+        return false;
+    m_contextStack.append(WTFMove(shadowContext));
+    return true;
+}
+
</ins><span class="cx"> void ComposedTreeIterator::traverseNextInShadowTree()
</span><span class="cx"> {
</span><del>-    ASSERT(!m_shadowStack.isEmpty());
</del><ins>+    ASSERT(m_contextStack.size() &gt; 1);
</ins><span class="cx"> 
</span><del>-    auto* shadowContext = &amp;m_shadowStack.last();
-
</del><span class="cx"> #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
</span><del>-    if (is&lt;HTMLSlotElement&gt;(*m_current) &amp;&amp; !shadowContext-&gt;currentSlot) {
-        auto&amp; slot = downcast&lt;HTMLSlotElement&gt;(*m_current);
</del><ins>+    if (is&lt;HTMLSlotElement&gt;(current())) {
+        auto&amp; slot = downcast&lt;HTMLSlotElement&gt;(current());
</ins><span class="cx">         if (auto* assignedNodes = slot.assignedNodes()) {
</span><del>-            shadowContext-&gt;currentSlot = &amp;slot;
-            shadowContext-&gt;currentSlotNodeIndex = 0;
-            m_current = assignedNodes-&gt;at(0);
</del><ins>+            context().slotNodeIndex = 0;
+            auto* assignedNode = assignedNodes-&gt;at(0);
+            m_contextStack.append(Context(*assignedNode-&gt;parentElement(), *assignedNode));
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    m_current = NodeTraversal::next(*m_current, shadowContext-&gt;host);
</del><ins>+    context().iterator.traverseNext();
</ins><span class="cx"> 
</span><del>-    while (!m_current) {
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-        if (auto* slot = shadowContext-&gt;currentSlot) {
-            bool nextNodeInSameSlot = ++shadowContext-&gt;currentSlotNodeIndex &lt; slot-&gt;assignedNodes()-&gt;size();
-            if (nextNodeInSameSlot) {
-                m_current = slot-&gt;assignedNodes()-&gt;at(shadowContext-&gt;currentSlotNodeIndex);
-                return;
-            }
-            m_current = NodeTraversal::nextSkippingChildren(*slot, shadowContext-&gt;host);
-            shadowContext-&gt;currentSlot = nullptr;
-            continue;
-        }
-#endif
-        auto&amp; previousHost = *shadowContext-&gt;host;
-        m_shadowStack.removeLast();
-
-        if (m_shadowStack.isEmpty()) {
-            m_current = NodeTraversal::nextSkippingChildren(previousHost, &amp;m_root);
-            return;
-        }
-        shadowContext = &amp;m_shadowStack.last();
-        m_current = NodeTraversal::nextSkippingChildren(previousHost, shadowContext-&gt;host);
-    }
</del><ins>+    if (!context().iterator)
+        traverseNextLeavingContext();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ComposedTreeIterator::traverseParentInShadowTree()
</del><ins>+void ComposedTreeIterator::traverseNextLeavingContext()
</ins><span class="cx"> {
</span><del>-    ASSERT(!m_shadowStack.isEmpty());
</del><ins>+    ASSERT(m_contextStack.size() &gt; 1);
</ins><span class="cx"> 
</span><del>-    auto&amp; shadowContext = m_shadowStack.last();
-
-    auto* parent = m_current-&gt;parentNode();
-    if (is&lt;ShadowRoot&gt;(parent)) {
-        ASSERT(shadowContext.host == downcast&lt;ShadowRoot&gt;(*parent).host());
-
-        m_current = shadowContext.host;
-        m_shadowStack.removeLast();
-        return;
-    }
-    if (parent-&gt;shadowRoot()) {
</del><ins>+    while (!context().iterator &amp;&amp; m_contextStack.size() &gt; 1) {
+        m_contextStack.removeLast();
+        if (!context().iterator)
+            return;
</ins><span class="cx"> #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
</span><del>-        ASSERT(shadowContext.host == parent);
-
-        auto* slot = shadowContext.currentSlot;
-        ASSERT(slot-&gt;assignedNodes()-&gt;at(shadowContext.currentSlotNodeIndex) == m_current);
-
-        m_current = slot;
-        shadowContext.currentSlot = nullptr;
-        return;
-#else
-        m_current = nullptr;
-        return;
</del><ins>+        if (is&lt;HTMLSlotElement&gt;(current()) &amp;&amp; advanceInSlot(1))
+            return;
</ins><span class="cx"> #endif
</span><ins>+        context().iterator.traverseNextSkippingChildren();
</ins><span class="cx">     }
</span><del>-    m_current = parent;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
</span><del>-void ComposedTreeIterator::traverseNextSiblingSlot()
</del><ins>+bool ComposedTreeIterator::advanceInSlot(int direction)
</ins><span class="cx"> {
</span><del>-    ASSERT(m_current-&gt;parentNode()-&gt;shadowRoot());
-    ASSERT(!m_shadowStack.isEmpty());
-    ASSERT(m_shadowStack.last().host == m_current-&gt;parentNode());
</del><ins>+    ASSERT(context().slotNodeIndex != notFound);
</ins><span class="cx"> 
</span><del>-    auto&amp; shadowContext = m_shadowStack.last();
</del><ins>+    auto&amp; assignedNodes = *downcast&lt;HTMLSlotElement&gt;(current()).assignedNodes();
+    // It is fine to underflow this.
+    context().slotNodeIndex += direction;
+    if (context().slotNodeIndex &gt;= assignedNodes.size())
+        return false;
</ins><span class="cx"> 
</span><del>-    if (!shadowContext.currentSlot) {
-        m_current = nullptr;
-        return;
-    }
-    auto* slotNodes = shadowContext.currentSlot-&gt;assignedNodes();
-    ASSERT(slotNodes-&gt;at(shadowContext.currentSlotNodeIndex) == m_current);
-
-    bool nextNodeInSameSlot = ++shadowContext.currentSlotNodeIndex &lt; slotNodes-&gt;size();
-    m_current = nextNodeInSameSlot ? slotNodes-&gt;at(shadowContext.currentSlotNodeIndex) : nullptr;
</del><ins>+    auto* slotNode = assignedNodes.at(context().slotNodeIndex);
+    m_contextStack.append(Context(*slotNode-&gt;parentElement(), *slotNode));
+    return true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ComposedTreeIterator::traversePreviousSiblingSlot()
</del><ins>+void ComposedTreeIterator::traverseSiblingInSlot(int direction)
</ins><span class="cx"> {
</span><del>-    ASSERT(m_current-&gt;parentNode()-&gt;shadowRoot());
-    ASSERT(!m_shadowStack.isEmpty());
-    ASSERT(m_shadowStack.last().host == m_current-&gt;parentNode());
</del><ins>+    ASSERT(m_contextStack.size() &gt; 1);
+    ASSERT(current().parentNode()-&gt;shadowRoot());
</ins><span class="cx"> 
</span><del>-    auto&amp; shadowContext = m_shadowStack.last();
</del><ins>+    m_contextStack.removeLast();
</ins><span class="cx"> 
</span><del>-    if (!shadowContext.currentSlot) {
-        m_current = nullptr;
-        return;
-    }
-    auto* slotNodes = shadowContext.currentSlot-&gt;assignedNodes();
-    ASSERT(slotNodes-&gt;at(shadowContext.currentSlotNodeIndex) == m_current);
-
-    bool previousNodeInSameSlot = shadowContext.currentSlotNodeIndex &gt; 0;
-    m_current = previousNodeInSameSlot ? slotNodes-&gt;at(--shadowContext.currentSlotNodeIndex) : nullptr;
</del><ins>+    if (!advanceInSlot(direction))
+        *this = { };
</ins><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoredomComposedTreeIteratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ComposedTreeIterator.h (196280 => 196281)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/ComposedTreeIterator.h        2016-02-09 01:06:23 UTC (rev 196280)
+++ trunk/Source/WebCore/dom/ComposedTreeIterator.h        2016-02-09 01:15:52 UTC (rev 196281)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -23,7 +23,7 @@
</span><span class="cx">  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-#include &quot;NodeTraversal.h&quot;
</del><ins>+#include &quot;ElementAndTextDescendantIterator.h&quot;
</ins><span class="cx"> #include &quot;ShadowRoot.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #ifndef ComposedTreeIterator_h
</span><span class="lines">@@ -35,115 +35,118 @@
</span><span class="cx"> 
</span><span class="cx"> class ComposedTreeIterator {
</span><span class="cx"> public:
</span><ins>+    ComposedTreeIterator();
</ins><span class="cx">     ComposedTreeIterator(ContainerNode&amp; root);
</span><span class="cx">     ComposedTreeIterator(ContainerNode&amp; root, Node&amp; current);
</span><span class="cx"> 
</span><del>-    Node&amp; operator*() { return *m_current; }
-    Node* operator-&gt;() { return m_current; }
</del><ins>+    Node&amp; operator*() { return current(); }
+    Node* operator-&gt;() { return &amp;current(); }
</ins><span class="cx"> 
</span><del>-    bool operator==(const ComposedTreeIterator&amp; other) const { return m_current == other.m_current; }
-    bool operator!=(const ComposedTreeIterator&amp; other) const { return m_current != other.m_current; }
</del><ins>+    bool operator==(const ComposedTreeIterator&amp; other) const { return context().iterator == other.context().iterator; }
+    bool operator!=(const ComposedTreeIterator&amp; other) const { return context().iterator != other.context().iterator; }
</ins><span class="cx"> 
</span><del>-    ComposedTreeIterator&amp; operator++() { return traverseNextSibling(); }
</del><ins>+    ComposedTreeIterator&amp; operator++() { return traverseNext(); }
</ins><span class="cx"> 
</span><span class="cx">     ComposedTreeIterator&amp; traverseNext();
</span><ins>+    ComposedTreeIterator&amp; traverseNextSkippingChildren();
</ins><span class="cx">     ComposedTreeIterator&amp; traverseNextSibling();
</span><span class="cx">     ComposedTreeIterator&amp; traversePreviousSibling();
</span><del>-    ComposedTreeIterator&amp; traverseParent();
</del><span class="cx"> 
</span><ins>+    unsigned depth() const;
+
</ins><span class="cx"> private:
</span><del>-    void initializeShadowStack();
</del><ins>+    void initializeContextStack(ContainerNode&amp; root, Node&amp; current);
</ins><span class="cx">     void traverseNextInShadowTree();
</span><del>-    void traverseParentInShadowTree();
</del><ins>+    void traverseNextLeavingContext();
+    bool pushContext(ShadowRoot&amp;);
</ins><span class="cx"> #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
</span><del>-    void traverseNextSiblingSlot();
-    void traversePreviousSiblingSlot();
</del><ins>+    bool advanceInSlot(int direction);
+    void traverseSiblingInSlot(int direction);
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    ContainerNode&amp; m_root;
-    Node* m_current { 0 };
-
-    struct ShadowContext {
-        ShadowContext(Element* host)
-            : host(host)
</del><ins>+    struct Context {
+        Context() { }
+        explicit Context(ContainerNode&amp; root)
+            : iterator(root)
</ins><span class="cx">         { }
</span><ins>+        Context(ContainerNode&amp; root, Node&amp; node, size_t slotNodeIndex = notFound)
+            : iterator(root, &amp;node)
+            , slotNodeIndex(slotNodeIndex)
+        { }
</ins><span class="cx"> 
</span><del>-        Element* host;
</del><ins>+        ElementAndTextDescendantIterator iterator;
</ins><span class="cx"> #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
</span><del>-        HTMLSlotElement* currentSlot { nullptr };
-        unsigned currentSlotNodeIndex { 0 };
</del><ins>+        size_t slotNodeIndex { notFound };
</ins><span class="cx"> #endif
</span><span class="cx">     };
</span><del>-    Vector&lt;ShadowContext, 4&gt; m_shadowStack;
</del><ins>+    Context&amp; context() { return m_contextStack.last(); }
+    const Context&amp; context() const { return m_contextStack.last(); }
+    Node&amp; current() { return *context().iterator; }
+
+    Vector&lt;Context, 4&gt; m_contextStack;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-inline ComposedTreeIterator::ComposedTreeIterator(ContainerNode&amp; root)
-    : m_root(root)
</del><ins>+inline ComposedTreeIterator::ComposedTreeIterator()
+    : m_contextStack({ { } })
</ins><span class="cx"> {
</span><del>-    ASSERT(!is&lt;ShadowRoot&gt;(m_root));
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline ComposedTreeIterator::ComposedTreeIterator(ContainerNode&amp; root, Node&amp; current)
-    : m_root(root)
-    , m_current(&amp;current)
-{
-    ASSERT(!is&lt;ShadowRoot&gt;(m_root));
-    ASSERT(!is&lt;ShadowRoot&gt;(m_current));
-
-    bool mayNeedShadowStack = m_root.shadowRoot() || (m_current != &amp;m_root &amp;&amp; current.parentNode() != &amp;m_root);
-    if (mayNeedShadowStack)
-        initializeShadowStack();
-}
-
</del><span class="cx"> inline ComposedTreeIterator&amp; ComposedTreeIterator::traverseNext()
</span><span class="cx"> {
</span><del>-    if (auto* shadowRoot = m_current-&gt;shadowRoot()) {
-        m_shadowStack.append(shadowRoot-&gt;host());
-        m_current = shadowRoot;
</del><ins>+    if (auto* shadowRoot = context().iterator-&gt;shadowRoot()) {
+        if (pushContext(*shadowRoot))
+            return *this;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (m_shadowStack.isEmpty())
-        m_current = NodeTraversal::next(*m_current, &amp;m_root);
-    else
</del><ins>+    if (m_contextStack.size() &gt; 1) {
</ins><span class="cx">         traverseNextInShadowTree();
</span><ins>+        return *this;
+    }
</ins><span class="cx"> 
</span><ins>+    context().iterator.traverseNext();
</ins><span class="cx">     return *this;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline ComposedTreeIterator&amp; ComposedTreeIterator::traverseNextSkippingChildren()
+{
+    context().iterator.traverseNextSkippingChildren();
+
+    if (!context().iterator &amp;&amp; m_contextStack.size() &gt; 1)
+        traverseNextLeavingContext();
+    
+    return *this;
+}
+
</ins><span class="cx"> inline ComposedTreeIterator&amp; ComposedTreeIterator::traverseNextSibling()
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
</span><del>-    bool isAssignedToSlot = !m_shadowStack.isEmpty() &amp;&amp; m_current-&gt;parentNode()-&gt;shadowRoot();
-    if (isAssignedToSlot) {
-        traverseNextSiblingSlot();
</del><ins>+    if (current().parentNode()-&gt;shadowRoot()) {
+        traverseSiblingInSlot(1);
</ins><span class="cx">         return *this;
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><del>-    m_current = m_current-&gt;nextSibling();
</del><ins>+    context().iterator.traverseNextSibling();
</ins><span class="cx">     return *this;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline ComposedTreeIterator&amp; ComposedTreeIterator::traversePreviousSibling()
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
</span><del>-    bool isAssignedToSlot = !m_shadowStack.isEmpty() &amp;&amp; m_current-&gt;parentNode()-&gt;shadowRoot();
-    if (isAssignedToSlot) {
-        traversePreviousSiblingSlot();
</del><ins>+    if (current().parentNode()-&gt;shadowRoot()) {
+        traverseSiblingInSlot(-1);
</ins><span class="cx">         return *this;
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><del>-    m_current = m_current-&gt;previousSibling();
</del><ins>+    context().iterator.traversePreviousSibling();
</ins><span class="cx">     return *this;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline ComposedTreeIterator&amp; ComposedTreeIterator::traverseParent()
</del><ins>+inline unsigned ComposedTreeIterator::depth() const
</ins><span class="cx"> {
</span><del>-    if (m_shadowStack.isEmpty())
-        m_current = m_current-&gt;parentNode();
-    else
-        traverseParentInShadowTree();
-
-    return *this;
</del><ins>+    unsigned depth = 0;
+    for (auto&amp; context : m_contextStack)
+        depth += context.iterator.depth();
+    return depth;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> class ComposedTreeDescendantAdapter {
</span><span class="lines">@@ -152,8 +155,8 @@
</span><span class="cx">         : m_parent(parent)
</span><span class="cx">     { }
</span><span class="cx"> 
</span><del>-    ComposedTreeIterator begin() { return ComposedTreeIterator(m_parent, m_parent).traverseNext(); }
-    ComposedTreeIterator end() { return ComposedTreeIterator(m_parent); }
</del><ins>+    ComposedTreeIterator begin() { return ComposedTreeIterator(m_parent); }
+    ComposedTreeIterator end() { return { }; }
</ins><span class="cx">     ComposedTreeIterator at(const Node&amp; child) { return ComposedTreeIterator(m_parent, const_cast&lt;Node&amp;&gt;(child)); }
</span><span class="cx">     
</span><span class="cx"> private:
</span><span class="lines">@@ -164,7 +167,8 @@
</span><span class="cx"> public:
</span><span class="cx">     class Iterator : public ComposedTreeIterator {
</span><span class="cx">     public:
</span><del>-        Iterator(ContainerNode&amp; root)
</del><ins>+        Iterator() = default;
+        explicit Iterator(ContainerNode&amp; root)
</ins><span class="cx">             : ComposedTreeIterator(root)
</span><span class="cx">         { }
</span><span class="cx">         Iterator(ContainerNode&amp; root, Node&amp; current)
</span><span class="lines">@@ -179,8 +183,8 @@
</span><span class="cx">         : m_parent(parent)
</span><span class="cx">     { }
</span><span class="cx"> 
</span><del>-    Iterator begin() { return static_cast&lt;Iterator&amp;&gt;(Iterator(m_parent, m_parent).traverseNext()); }
-    Iterator end() { return Iterator(m_parent); }
</del><ins>+    Iterator begin() { return Iterator(m_parent); }
+    Iterator end() { return { }; }
</ins><span class="cx">     Iterator at(const Node&amp; child) { return Iterator(m_parent, const_cast&lt;Node&amp;&gt;(child)); }
</span><span class="cx"> 
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceWebCoredomElementAndTextDescendantIteratorh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/dom/ElementAndTextDescendantIterator.h (0 => 196281)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/ElementAndTextDescendantIterator.h                                (rev 0)
+++ trunk/Source/WebCore/dom/ElementAndTextDescendantIterator.h        2016-02-09 01:15:52 UTC (rev 196281)
</span><span class="lines">@@ -0,0 +1,320 @@
</span><ins>+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ElementAndTextDescendantIterator_h
+#define ElementAndTextDescendantIterator_h
+
+#include &quot;Element.h&quot;
+#include &quot;ElementIteratorAssertions.h&quot;
+#include &quot;Text.h&quot;
+#include &lt;wtf/Vector.h&gt;
+
+namespace WebCore {
+
+class ElementAndTextDescendantIterator {
+public:
+    ElementAndTextDescendantIterator();
+    explicit ElementAndTextDescendantIterator(ContainerNode&amp; root);
+    ElementAndTextDescendantIterator(ContainerNode&amp; root, Node* current);
+
+    ElementAndTextDescendantIterator&amp; operator++() { return traverseNext(); }
+
+    Node&amp; operator*();
+    Node* operator-&gt;();
+    const Node&amp; operator*() const;
+    const Node* operator-&gt;() const;
+
+    bool operator==(const ElementAndTextDescendantIterator&amp; other) const;
+    bool operator!=(const ElementAndTextDescendantIterator&amp; other) const;
+
+    bool operator!() const { return !m_current; }
+    explicit operator bool() const { return m_current; }
+
+    void dropAssertions();
+
+    ElementAndTextDescendantIterator&amp; traverseNext();
+    ElementAndTextDescendantIterator&amp; traverseNextSkippingChildren();
+    ElementAndTextDescendantIterator&amp; traverseNextSibling();
+    ElementAndTextDescendantIterator&amp; traversePreviousSibling();
+
+    unsigned depth() const { return m_depth; }
+
+private:
+    static bool isElementOrText(const Node&amp; node) { return is&lt;Element&gt;(node) || is&lt;Text&gt;(node); }
+    static Node* firstChild(Node&amp;);
+    static Node* nextSibling(Node&amp;);
+    static Node* previousSibling(Node&amp;);
+
+    void popAncestorSiblingStack();
+
+    Node* m_current;
+    struct AncestorSibling {
+        Node* node;
+        unsigned depth;
+    };
+    Vector&lt;AncestorSibling, 16&gt; m_ancestorSiblingStack;
+    unsigned m_depth { 0 };
+
+#if !ASSERT_DISABLED
+    ElementIteratorAssertions m_assertions;
+#endif
+};
+
+class ElementAndTextDescendantIteratorAdapter {
+public:
+    explicit ElementAndTextDescendantIteratorAdapter(ContainerNode&amp; root);
+    ElementAndTextDescendantIterator begin();
+    ElementAndTextDescendantIterator end();
+
+private:
+    ContainerNode&amp; m_root;
+};
+
+ElementAndTextDescendantIteratorAdapter elementAndTextDescendants(ContainerNode&amp;);
+
+// ElementAndTextDescendantIterator
+
+inline ElementAndTextDescendantIterator::ElementAndTextDescendantIterator()
+    : m_current(nullptr)
+{
+}
+
+inline ElementAndTextDescendantIterator::ElementAndTextDescendantIterator(ContainerNode&amp; root)
+    : m_current(firstChild(root))
+#if !ASSERT_DISABLED
+    , m_assertions(m_current)
+#endif
+{
+    if (!m_current)
+        return;
+    m_ancestorSiblingStack.uncheckedAppend({ nullptr, 0 });
+    m_depth = 1;
+}
+
+inline ElementAndTextDescendantIterator::ElementAndTextDescendantIterator(ContainerNode&amp; root, Node* current)
+    : m_current(current != &amp;root ? current : nullptr)
+#if !ASSERT_DISABLED
+    , m_assertions(m_current)
+#endif
+{
+    if (!m_current)
+        return;
+    ASSERT(isElementOrText(*m_current));
+
+    Vector&lt;Node*, 20&gt; ancestorStack;
+    auto* ancestor = m_current-&gt;parentNode();
+    while (ancestor != &amp;root) {
+        ancestorStack.append(ancestor);
+        ancestor = ancestor-&gt;parentNode();
+    }
+
+    m_ancestorSiblingStack.uncheckedAppend({ nullptr, 0 });
+    for (unsigned i = ancestorStack.size(); i; --i) {
+        if (auto* sibling = nextSibling(*ancestorStack[i - 1]))
+            m_ancestorSiblingStack.append({ sibling, i });
+    }
+
+    m_depth = ancestorStack.size() + 1;
+}
+
+inline void ElementAndTextDescendantIterator::dropAssertions()
+{
+#if !ASSERT_DISABLED
+    m_assertions.clear();
+#endif
+}
+
+inline Node* ElementAndTextDescendantIterator::firstChild(Node&amp; current)
+{
+    auto* node = current.firstChild();
+    while (node &amp;&amp; !isElementOrText(*node))
+        node = node-&gt;nextSibling();
+    return node;
+}
+
+inline Node* ElementAndTextDescendantIterator::nextSibling(Node&amp; current)
+{
+    auto* node = current.nextSibling();
+    while (node &amp;&amp; !isElementOrText(*node))
+        node = node-&gt;nextSibling();
+    return node;
+}
+
+inline Node* ElementAndTextDescendantIterator::previousSibling(Node&amp; current)
+{
+    auto* node = current.previousSibling();
+    while (node &amp;&amp; !isElementOrText(*node))
+        node = node-&gt;previousSibling();
+    return node;
+}
+
+inline void ElementAndTextDescendantIterator::popAncestorSiblingStack()
+{
+    m_current = m_ancestorSiblingStack.last().node;
+    m_depth = m_ancestorSiblingStack.last().depth;
+    m_ancestorSiblingStack.removeLast();
+
+#if !ASSERT_DISABLED
+    // Drop the assertion when the iterator reaches the end.
+    if (!m_current)
+        m_assertions.dropEventDispatchAssertion();
+#endif
+}
+
+inline ElementAndTextDescendantIterator&amp; ElementAndTextDescendantIterator::traverseNext()
+{
+    ASSERT(m_current);
+    ASSERT(!m_assertions.domTreeHasMutated());
+
+    auto* firstChild = ElementAndTextDescendantIterator::firstChild(*m_current);
+    auto* nextSibling = ElementAndTextDescendantIterator::nextSibling(*m_current);
+    if (firstChild) {
+        if (nextSibling)
+            m_ancestorSiblingStack.append({ nextSibling, m_depth });
+        ++m_depth;
+        m_current = firstChild;
+        return *this;
+    }
+    if (!nextSibling) {
+        popAncestorSiblingStack();
+        return *this;
+    }
+
+    m_current = nextSibling;
+    return *this;
+}
+
+inline ElementAndTextDescendantIterator&amp; ElementAndTextDescendantIterator::traverseNextSkippingChildren()
+{
+    ASSERT(m_current);
+    ASSERT(!m_assertions.domTreeHasMutated());
+
+    auto* nextSibling = ElementAndTextDescendantIterator::nextSibling(*m_current);
+    if (!nextSibling) {
+        popAncestorSiblingStack();
+        return *this;
+    }
+
+    m_current = nextSibling;
+    return *this;
+}
+
+inline ElementAndTextDescendantIterator&amp; ElementAndTextDescendantIterator::traverseNextSibling()
+{
+    ASSERT(m_current);
+    ASSERT(!m_assertions.domTreeHasMutated());
+
+    m_current = nextSibling(*m_current);
+
+#if !ASSERT_DISABLED
+    if (!m_current)
+        m_assertions.dropEventDispatchAssertion();
+#endif
+    return *this;
+}
+
+inline ElementAndTextDescendantIterator&amp; ElementAndTextDescendantIterator::traversePreviousSibling()
+{
+    ASSERT(m_current);
+    ASSERT(!m_assertions.domTreeHasMutated());
+
+    m_current = previousSibling(*m_current);
+
+#if !ASSERT_DISABLED
+    if (!m_current)
+        m_assertions.dropEventDispatchAssertion();
+#endif
+    return *this;
+}
+
+inline Node&amp; ElementAndTextDescendantIterator::operator*()
+{
+    ASSERT(m_current);
+    ASSERT(isElementOrText(*m_current));
+    ASSERT(!m_assertions.domTreeHasMutated());
+    return *m_current;
+}
+
+inline Node* ElementAndTextDescendantIterator::operator-&gt;()
+{
+    ASSERT(m_current);
+    ASSERT(isElementOrText(*m_current));
+    ASSERT(!m_assertions.domTreeHasMutated());
+    return m_current;
+}
+
+inline const Node&amp; ElementAndTextDescendantIterator::operator*() const
+{
+    ASSERT(m_current);
+    ASSERT(isElementOrText(*m_current));
+    ASSERT(!m_assertions.domTreeHasMutated());
+    return *m_current;
+}
+
+inline const Node* ElementAndTextDescendantIterator::operator-&gt;() const
+{
+    ASSERT(m_current);
+    ASSERT(isElementOrText(*m_current));
+    ASSERT(!m_assertions.domTreeHasMutated());
+    return m_current;
+}
+
+inline bool ElementAndTextDescendantIterator::operator==(const ElementAndTextDescendantIterator&amp; other) const
+{
+    ASSERT(!m_assertions.domTreeHasMutated());
+    return m_current == other.m_current;
+}
+
+inline bool ElementAndTextDescendantIterator::operator!=(const ElementAndTextDescendantIterator&amp; other) const
+{
+    return !(*this == other);
+}
+
+// ElementAndTextDescendantIteratorAdapter
+
+inline ElementAndTextDescendantIteratorAdapter::ElementAndTextDescendantIteratorAdapter(ContainerNode&amp; root)
+    : m_root(root)
+{
+}
+
+inline ElementAndTextDescendantIterator ElementAndTextDescendantIteratorAdapter::begin()
+{
+    return ElementAndTextDescendantIterator(m_root);
+}
+
+inline ElementAndTextDescendantIterator ElementAndTextDescendantIteratorAdapter::end()
+{
+    return { };
+}
+
+// Standalone functions
+
+inline ElementAndTextDescendantIteratorAdapter elementAndTextDescendants(ContainerNode&amp; root)
+{
+    return ElementAndTextDescendantIteratorAdapter(root);
+}
+
+}
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebCoredomElementIteratorAssertionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ElementIteratorAssertions.h (196280 => 196281)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/ElementIteratorAssertions.h        2016-02-09 01:06:23 UTC (rev 196280)
+++ trunk/Source/WebCore/dom/ElementIteratorAssertions.h        2016-02-09 01:15:52 UTC (rev 196281)
</span><span class="lines">@@ -32,7 +32,7 @@
</span><span class="cx"> 
</span><span class="cx"> class ElementIteratorAssertions {
</span><span class="cx"> public:
</span><del>-    ElementIteratorAssertions(const Element* first = nullptr);
</del><ins>+    ElementIteratorAssertions(const Node* first = nullptr);
</ins><span class="cx">     bool domTreeHasMutated() const;
</span><span class="cx">     void dropEventDispatchAssertion();
</span><span class="cx">     void clear();
</span><span class="lines">@@ -45,7 +45,7 @@
</span><span class="cx"> 
</span><span class="cx"> // FIXME: No real point in doing these as inlines; they are for debugging and we usually turn off inlining in debug builds.
</span><span class="cx"> 
</span><del>-inline ElementIteratorAssertions::ElementIteratorAssertions(const Element* first)
</del><ins>+inline ElementIteratorAssertions::ElementIteratorAssertions(const Node* first)
</ins><span class="cx">     : m_document(first ? &amp;first-&gt;document() : nullptr)
</span><span class="cx">     , m_initialDOMTreeVersion(first ? m_document-&gt;domTreeVersion() : 0)
</span><span class="cx"> {
</span></span></pre>
</div>
</div>

</body>
</html>