Title: [196281] trunk/Source/WebCore
Revision
196281
Author
an...@apple.com
Date
2016-02-08 17:15:52 -0800 (Mon, 08 Feb 2016)

Log Message

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->):
(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.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (196280 => 196281)


--- 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)
@@ -1,3 +1,63 @@
+2016-02-08  Antti Koivisto  <an...@apple.com>
+
+        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->):
+        (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.
+
 2016-02-08  Joseph Pecoraro  <pecor...@apple.com>
 
         Web Inspector: copy({x:1}) should copy "{x:1}", not "[object Object]"

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (196280 => 196281)


--- 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)
@@ -6530,6 +6530,7 @@
 		E43A023D17EB3713004CDD25 /* RenderElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E43A023C17EB3713004CDD25 /* RenderElement.cpp */; };
 		E43AF8E61AC5B7E800CA717E /* CacheValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E43AF8E41AC5B7DD00CA717E /* CacheValidation.cpp */; };
 		E43AF8E71AC5B7EC00CA717E /* CacheValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = E43AF8E51AC5B7DD00CA717E /* CacheValidation.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		E440AA961C68420800A265CC /* ElementAndTextDescendantIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E440AA951C68420800A265CC /* ElementAndTextDescendantIterator.h */; };
 		E44613A10CD6331000FADA75 /* HTMLAudioElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E446138F0CD6331000FADA75 /* HTMLAudioElement.cpp */; };
 		E44613A20CD6331000FADA75 /* HTMLAudioElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E44613900CD6331000FADA75 /* HTMLAudioElement.h */; };
 		E44613A40CD6331000FADA75 /* HTMLMediaElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E44613920CD6331000FADA75 /* HTMLMediaElement.cpp */; };
@@ -14508,6 +14509,7 @@
 		E43A023C17EB3713004CDD25 /* RenderElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderElement.cpp; sourceTree = "<group>"; };
 		E43AF8E41AC5B7DD00CA717E /* CacheValidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CacheValidation.cpp; sourceTree = "<group>"; };
 		E43AF8E51AC5B7DD00CA717E /* CacheValidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CacheValidation.h; sourceTree = "<group>"; };
+		E440AA951C68420800A265CC /* ElementAndTextDescendantIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementAndTextDescendantIterator.h; sourceTree = "<group>"; };
 		E446138F0CD6331000FADA75 /* HTMLAudioElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTMLAudioElement.cpp; sourceTree = "<group>"; };
 		E44613900CD6331000FADA75 /* HTMLAudioElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLAudioElement.h; sourceTree = "<group>"; };
 		E44613910CD6331000FADA75 /* HTMLAudioElement.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = HTMLAudioElement.idl; sourceTree = "<group>"; };
@@ -24091,6 +24093,7 @@
 				A8C4A7F509D563270003AC8D /* Element.h */,
 				93EEC1EA09C2877700C515D1 /* Element.idl */,
 				E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */,
+				E440AA951C68420800A265CC /* ElementAndTextDescendantIterator.h */,
 				E46A2B1D17CA76B1000DBCD8 /* ElementChildIterator.h */,
 				B5B7A16F17C1080600E4AA0A /* ElementData.cpp */,
 				B5B7A16E17C1048000E4AA0A /* ElementData.h */,
@@ -25850,6 +25853,7 @@
 				93309E0E099E64920056E581 /* FrameSelection.h in Headers */,
 				C4CD629B18383766007EBAF1 /* FrameSnapshotting.h in Headers */,
 				65A21485097A3F5300B9050A /* FrameTree.h in Headers */,
+				E440AA961C68420800A265CC /* ElementAndTextDescendantIterator.h in Headers */,
 				65CBFEFA0974F607001DAC25 /* FrameView.h in Headers */,
 				97205AB0123928CA00B17380 /* FTPDirectoryDocument.h in Headers */,
 				51C81B8A0C4422F70019ECE3 /* FTPDirectoryParser.h in Headers */,

Modified: trunk/Source/WebCore/dom/ComposedTreeIterator.cpp (196280 => 196281)


--- 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)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-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
@@ -30,163 +30,153 @@
 
 namespace WebCore {
 
-void ComposedTreeIterator::initializeShadowStack()
+ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root)
 {
+    ASSERT(!is<ShadowRoot>(root));
+
+#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
+    if (is<HTMLSlotElement>(root)) {
+        auto& slot = downcast<HTMLSlotElement>(root);
+        if (auto* assignedNodes = slot.assignedNodes()) {
+            initializeContextStack(root, *assignedNodes->at(0));
+            return;
+        }
+    }
+#endif
+    auto& effectiveRoot = root.shadowRoot() ? *root.shadowRoot() : root;
+    m_contextStack.uncheckedAppend(Context(effectiveRoot));
+}
+
+ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root, Node& current)
+{
+    ASSERT(!is<ShadowRoot>(root));
+    ASSERT(!is<ShadowRoot>(current));
+
+    bool mayNeedShadowStack = root.shadowRoot() || (&current != &root && current.parentNode() != &root);
+    if (mayNeedShadowStack)
+        initializeContextStack(root, current);
+    else
+        m_contextStack.uncheckedAppend(Context(root, current));
+}
+
+void ComposedTreeIterator::initializeContextStack(ContainerNode& root, Node& current)
+{
     // This code sets up the iterator for arbitrary node/root pair. It is not needed in common cases
     // or completes fast because node and root are close (like in composedTreeChildren(*parent).at(node) case).
-    auto* node = m_current;
-    while (node != &m_root) {
+    auto* node = &current;
+    auto* contextCurrent = node;
+    size_t currentSlotNodeIndex = notFound;
+    while (node != &root) {
         auto* parent = node->parentNode();
         if (!parent) {
-            m_current = nullptr;
+            *this = { };
             return;
         }
         if (is<ShadowRoot>(*parent)) {
             auto& shadowRoot = downcast<ShadowRoot>(*parent);
-            if (m_shadowStack.isEmpty() || m_shadowStack.last().host != shadowRoot.host())
-                m_shadowStack.append(shadowRoot.host());
+            m_contextStack.append(Context(shadowRoot, *contextCurrent, currentSlotNodeIndex));
             node = shadowRoot.host();
+            contextCurrent = node;
+            currentSlotNodeIndex = notFound;
             continue;
         }
         if (auto* shadowRoot = parent->shadowRoot()) {
 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-            m_shadowStack.append(shadowRoot->host());
+            m_contextStack.append(Context(*parent, *contextCurrent, currentSlotNodeIndex));
             auto* assignedSlot = shadowRoot->findAssignedSlot(*node);
             if (assignedSlot) {
-                size_t index = assignedSlot->assignedNodes()->find(node);
-                ASSERT(index != notFound);
-
-                m_shadowStack.last().currentSlot = assignedSlot;
-                m_shadowStack.last().currentSlotNodeIndex = index;
+                currentSlotNodeIndex = assignedSlot->assignedNodes()->find(node);
+                ASSERT(currentSlotNodeIndex != notFound);
                 node = assignedSlot;
+                contextCurrent = assignedSlot;
                 continue;
             }
             // The node is not part of the composed tree.
 #else
             UNUSED_PARAM(shadowRoot);
-            m_current = nullptr;
-            return;
 #endif
+            *this = { };
+            return;
         }
         node = parent;
     }
-    m_shadowStack.reverse();
+    m_contextStack.append(Context(root, *contextCurrent, currentSlotNodeIndex));
+
+    m_contextStack.reverse();
 }
 
+bool ComposedTreeIterator::pushContext(ShadowRoot& shadowRoot)
+{
+    Context shadowContext(shadowRoot);
+    if (!shadowContext.iterator)
+        return false;
+    m_contextStack.append(WTFMove(shadowContext));
+    return true;
+}
+
 void ComposedTreeIterator::traverseNextInShadowTree()
 {
-    ASSERT(!m_shadowStack.isEmpty());
+    ASSERT(m_contextStack.size() > 1);
 
-    auto* shadowContext = &m_shadowStack.last();
-
 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    if (is<HTMLSlotElement>(*m_current) && !shadowContext->currentSlot) {
-        auto& slot = downcast<HTMLSlotElement>(*m_current);
+    if (is<HTMLSlotElement>(current())) {
+        auto& slot = downcast<HTMLSlotElement>(current());
         if (auto* assignedNodes = slot.assignedNodes()) {
-            shadowContext->currentSlot = &slot;
-            shadowContext->currentSlotNodeIndex = 0;
-            m_current = assignedNodes->at(0);
+            context().slotNodeIndex = 0;
+            auto* assignedNode = assignedNodes->at(0);
+            m_contextStack.append(Context(*assignedNode->parentElement(), *assignedNode));
             return;
         }
     }
 #endif
 
-    m_current = NodeTraversal::next(*m_current, shadowContext->host);
+    context().iterator.traverseNext();
 
-    while (!m_current) {
-#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-        if (auto* slot = shadowContext->currentSlot) {
-            bool nextNodeInSameSlot = ++shadowContext->currentSlotNodeIndex < slot->assignedNodes()->size();
-            if (nextNodeInSameSlot) {
-                m_current = slot->assignedNodes()->at(shadowContext->currentSlotNodeIndex);
-                return;
-            }
-            m_current = NodeTraversal::nextSkippingChildren(*slot, shadowContext->host);
-            shadowContext->currentSlot = nullptr;
-            continue;
-        }
-#endif
-        auto& previousHost = *shadowContext->host;
-        m_shadowStack.removeLast();
-
-        if (m_shadowStack.isEmpty()) {
-            m_current = NodeTraversal::nextSkippingChildren(previousHost, &m_root);
-            return;
-        }
-        shadowContext = &m_shadowStack.last();
-        m_current = NodeTraversal::nextSkippingChildren(previousHost, shadowContext->host);
-    }
+    if (!context().iterator)
+        traverseNextLeavingContext();
 }
 
-void ComposedTreeIterator::traverseParentInShadowTree()
+void ComposedTreeIterator::traverseNextLeavingContext()
 {
-    ASSERT(!m_shadowStack.isEmpty());
+    ASSERT(m_contextStack.size() > 1);
 
-    auto& shadowContext = m_shadowStack.last();
-
-    auto* parent = m_current->parentNode();
-    if (is<ShadowRoot>(parent)) {
-        ASSERT(shadowContext.host == downcast<ShadowRoot>(*parent).host());
-
-        m_current = shadowContext.host;
-        m_shadowStack.removeLast();
-        return;
-    }
-    if (parent->shadowRoot()) {
+    while (!context().iterator && m_contextStack.size() > 1) {
+        m_contextStack.removeLast();
+        if (!context().iterator)
+            return;
 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-        ASSERT(shadowContext.host == parent);
-
-        auto* slot = shadowContext.currentSlot;
-        ASSERT(slot->assignedNodes()->at(shadowContext.currentSlotNodeIndex) == m_current);
-
-        m_current = slot;
-        shadowContext.currentSlot = nullptr;
-        return;
-#else
-        m_current = nullptr;
-        return;
+        if (is<HTMLSlotElement>(current()) && advanceInSlot(1))
+            return;
 #endif
+        context().iterator.traverseNextSkippingChildren();
     }
-    m_current = parent;
 }
 
 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-void ComposedTreeIterator::traverseNextSiblingSlot()
+bool ComposedTreeIterator::advanceInSlot(int direction)
 {
-    ASSERT(m_current->parentNode()->shadowRoot());
-    ASSERT(!m_shadowStack.isEmpty());
-    ASSERT(m_shadowStack.last().host == m_current->parentNode());
+    ASSERT(context().slotNodeIndex != notFound);
 
-    auto& shadowContext = m_shadowStack.last();
+    auto& assignedNodes = *downcast<HTMLSlotElement>(current()).assignedNodes();
+    // It is fine to underflow this.
+    context().slotNodeIndex += direction;
+    if (context().slotNodeIndex >= assignedNodes.size())
+        return false;
 
-    if (!shadowContext.currentSlot) {
-        m_current = nullptr;
-        return;
-    }
-    auto* slotNodes = shadowContext.currentSlot->assignedNodes();
-    ASSERT(slotNodes->at(shadowContext.currentSlotNodeIndex) == m_current);
-
-    bool nextNodeInSameSlot = ++shadowContext.currentSlotNodeIndex < slotNodes->size();
-    m_current = nextNodeInSameSlot ? slotNodes->at(shadowContext.currentSlotNodeIndex) : nullptr;
+    auto* slotNode = assignedNodes.at(context().slotNodeIndex);
+    m_contextStack.append(Context(*slotNode->parentElement(), *slotNode));
+    return true;
 }
 
-void ComposedTreeIterator::traversePreviousSiblingSlot()
+void ComposedTreeIterator::traverseSiblingInSlot(int direction)
 {
-    ASSERT(m_current->parentNode()->shadowRoot());
-    ASSERT(!m_shadowStack.isEmpty());
-    ASSERT(m_shadowStack.last().host == m_current->parentNode());
+    ASSERT(m_contextStack.size() > 1);
+    ASSERT(current().parentNode()->shadowRoot());
 
-    auto& shadowContext = m_shadowStack.last();
+    m_contextStack.removeLast();
 
-    if (!shadowContext.currentSlot) {
-        m_current = nullptr;
-        return;
-    }
-    auto* slotNodes = shadowContext.currentSlot->assignedNodes();
-    ASSERT(slotNodes->at(shadowContext.currentSlotNodeIndex) == m_current);
-
-    bool previousNodeInSameSlot = shadowContext.currentSlotNodeIndex > 0;
-    m_current = previousNodeInSameSlot ? slotNodes->at(--shadowContext.currentSlotNodeIndex) : nullptr;
+    if (!advanceInSlot(direction))
+        *this = { };
 }
 #endif
 

Modified: trunk/Source/WebCore/dom/ComposedTreeIterator.h (196280 => 196281)


--- 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)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-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
@@ -23,7 +23,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "NodeTraversal.h"
+#include "ElementAndTextDescendantIterator.h"
 #include "ShadowRoot.h"
 
 #ifndef ComposedTreeIterator_h
@@ -35,115 +35,118 @@
 
 class ComposedTreeIterator {
 public:
+    ComposedTreeIterator();
     ComposedTreeIterator(ContainerNode& root);
     ComposedTreeIterator(ContainerNode& root, Node& current);
 
-    Node& operator*() { return *m_current; }
-    Node* operator->() { return m_current; }
+    Node& operator*() { return current(); }
+    Node* operator->() { return &current(); }
 
-    bool operator==(const ComposedTreeIterator& other) const { return m_current == other.m_current; }
-    bool operator!=(const ComposedTreeIterator& other) const { return m_current != other.m_current; }
+    bool operator==(const ComposedTreeIterator& other) const { return context().iterator == other.context().iterator; }
+    bool operator!=(const ComposedTreeIterator& other) const { return context().iterator != other.context().iterator; }
 
-    ComposedTreeIterator& operator++() { return traverseNextSibling(); }
+    ComposedTreeIterator& operator++() { return traverseNext(); }
 
     ComposedTreeIterator& traverseNext();
+    ComposedTreeIterator& traverseNextSkippingChildren();
     ComposedTreeIterator& traverseNextSibling();
     ComposedTreeIterator& traversePreviousSibling();
-    ComposedTreeIterator& traverseParent();
 
+    unsigned depth() const;
+
 private:
-    void initializeShadowStack();
+    void initializeContextStack(ContainerNode& root, Node& current);
     void traverseNextInShadowTree();
-    void traverseParentInShadowTree();
+    void traverseNextLeavingContext();
+    bool pushContext(ShadowRoot&);
 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    void traverseNextSiblingSlot();
-    void traversePreviousSiblingSlot();
+    bool advanceInSlot(int direction);
+    void traverseSiblingInSlot(int direction);
 #endif
 
-    ContainerNode& m_root;
-    Node* m_current { 0 };
-
-    struct ShadowContext {
-        ShadowContext(Element* host)
-            : host(host)
+    struct Context {
+        Context() { }
+        explicit Context(ContainerNode& root)
+            : iterator(root)
         { }
+        Context(ContainerNode& root, Node& node, size_t slotNodeIndex = notFound)
+            : iterator(root, &node)
+            , slotNodeIndex(slotNodeIndex)
+        { }
 
-        Element* host;
+        ElementAndTextDescendantIterator iterator;
 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-        HTMLSlotElement* currentSlot { nullptr };
-        unsigned currentSlotNodeIndex { 0 };
+        size_t slotNodeIndex { notFound };
 #endif
     };
-    Vector<ShadowContext, 4> m_shadowStack;
+    Context& context() { return m_contextStack.last(); }
+    const Context& context() const { return m_contextStack.last(); }
+    Node& current() { return *context().iterator; }
+
+    Vector<Context, 4> m_contextStack;
 };
 
-inline ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root)
-    : m_root(root)
+inline ComposedTreeIterator::ComposedTreeIterator()
+    : m_contextStack({ { } })
 {
-    ASSERT(!is<ShadowRoot>(m_root));
 }
 
-inline ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root, Node& current)
-    : m_root(root)
-    , m_current(&current)
-{
-    ASSERT(!is<ShadowRoot>(m_root));
-    ASSERT(!is<ShadowRoot>(m_current));
-
-    bool mayNeedShadowStack = m_root.shadowRoot() || (m_current != &m_root && current.parentNode() != &m_root);
-    if (mayNeedShadowStack)
-        initializeShadowStack();
-}
-
 inline ComposedTreeIterator& ComposedTreeIterator::traverseNext()
 {
-    if (auto* shadowRoot = m_current->shadowRoot()) {
-        m_shadowStack.append(shadowRoot->host());
-        m_current = shadowRoot;
+    if (auto* shadowRoot = context().iterator->shadowRoot()) {
+        if (pushContext(*shadowRoot))
+            return *this;
     }
 
-    if (m_shadowStack.isEmpty())
-        m_current = NodeTraversal::next(*m_current, &m_root);
-    else
+    if (m_contextStack.size() > 1) {
         traverseNextInShadowTree();
+        return *this;
+    }
 
+    context().iterator.traverseNext();
     return *this;
 }
 
+inline ComposedTreeIterator& ComposedTreeIterator::traverseNextSkippingChildren()
+{
+    context().iterator.traverseNextSkippingChildren();
+
+    if (!context().iterator && m_contextStack.size() > 1)
+        traverseNextLeavingContext();
+    
+    return *this;
+}
+
 inline ComposedTreeIterator& ComposedTreeIterator::traverseNextSibling()
 {
 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    bool isAssignedToSlot = !m_shadowStack.isEmpty() && m_current->parentNode()->shadowRoot();
-    if (isAssignedToSlot) {
-        traverseNextSiblingSlot();
+    if (current().parentNode()->shadowRoot()) {
+        traverseSiblingInSlot(1);
         return *this;
     }
 #endif
-    m_current = m_current->nextSibling();
+    context().iterator.traverseNextSibling();
     return *this;
 }
 
 inline ComposedTreeIterator& ComposedTreeIterator::traversePreviousSibling()
 {
 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
-    bool isAssignedToSlot = !m_shadowStack.isEmpty() && m_current->parentNode()->shadowRoot();
-    if (isAssignedToSlot) {
-        traversePreviousSiblingSlot();
+    if (current().parentNode()->shadowRoot()) {
+        traverseSiblingInSlot(-1);
         return *this;
     }
 #endif
-    m_current = m_current->previousSibling();
+    context().iterator.traversePreviousSibling();
     return *this;
 }
 
-inline ComposedTreeIterator& ComposedTreeIterator::traverseParent()
+inline unsigned ComposedTreeIterator::depth() const
 {
-    if (m_shadowStack.isEmpty())
-        m_current = m_current->parentNode();
-    else
-        traverseParentInShadowTree();
-
-    return *this;
+    unsigned depth = 0;
+    for (auto& context : m_contextStack)
+        depth += context.iterator.depth();
+    return depth;
 }
 
 class ComposedTreeDescendantAdapter {
@@ -152,8 +155,8 @@
         : m_parent(parent)
     { }
 
-    ComposedTreeIterator begin() { return ComposedTreeIterator(m_parent, m_parent).traverseNext(); }
-    ComposedTreeIterator end() { return ComposedTreeIterator(m_parent); }
+    ComposedTreeIterator begin() { return ComposedTreeIterator(m_parent); }
+    ComposedTreeIterator end() { return { }; }
     ComposedTreeIterator at(const Node& child) { return ComposedTreeIterator(m_parent, const_cast<Node&>(child)); }
     
 private:
@@ -164,7 +167,8 @@
 public:
     class Iterator : public ComposedTreeIterator {
     public:
-        Iterator(ContainerNode& root)
+        Iterator() = default;
+        explicit Iterator(ContainerNode& root)
             : ComposedTreeIterator(root)
         { }
         Iterator(ContainerNode& root, Node& current)
@@ -179,8 +183,8 @@
         : m_parent(parent)
     { }
 
-    Iterator begin() { return static_cast<Iterator&>(Iterator(m_parent, m_parent).traverseNext()); }
-    Iterator end() { return Iterator(m_parent); }
+    Iterator begin() { return Iterator(m_parent); }
+    Iterator end() { return { }; }
     Iterator at(const Node& child) { return Iterator(m_parent, const_cast<Node&>(child)); }
 
 private:

Added: trunk/Source/WebCore/dom/ElementAndTextDescendantIterator.h (0 => 196281)


--- trunk/Source/WebCore/dom/ElementAndTextDescendantIterator.h	                        (rev 0)
+++ trunk/Source/WebCore/dom/ElementAndTextDescendantIterator.h	2016-02-09 01:15:52 UTC (rev 196281)
@@ -0,0 +1,320 @@
+/*
+ * 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 "Element.h"
+#include "ElementIteratorAssertions.h"
+#include "Text.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class ElementAndTextDescendantIterator {
+public:
+    ElementAndTextDescendantIterator();
+    explicit ElementAndTextDescendantIterator(ContainerNode& root);
+    ElementAndTextDescendantIterator(ContainerNode& root, Node* current);
+
+    ElementAndTextDescendantIterator& operator++() { return traverseNext(); }
+
+    Node& operator*();
+    Node* operator->();
+    const Node& operator*() const;
+    const Node* operator->() const;
+
+    bool operator==(const ElementAndTextDescendantIterator& other) const;
+    bool operator!=(const ElementAndTextDescendantIterator& other) const;
+
+    bool operator!() const { return !m_current; }
+    explicit operator bool() const { return m_current; }
+
+    void dropAssertions();
+
+    ElementAndTextDescendantIterator& traverseNext();
+    ElementAndTextDescendantIterator& traverseNextSkippingChildren();
+    ElementAndTextDescendantIterator& traverseNextSibling();
+    ElementAndTextDescendantIterator& traversePreviousSibling();
+
+    unsigned depth() const { return m_depth; }
+
+private:
+    static bool isElementOrText(const Node& node) { return is<Element>(node) || is<Text>(node); }
+    static Node* firstChild(Node&);
+    static Node* nextSibling(Node&);
+    static Node* previousSibling(Node&);
+
+    void popAncestorSiblingStack();
+
+    Node* m_current;
+    struct AncestorSibling {
+        Node* node;
+        unsigned depth;
+    };
+    Vector<AncestorSibling, 16> m_ancestorSiblingStack;
+    unsigned m_depth { 0 };
+
+#if !ASSERT_DISABLED
+    ElementIteratorAssertions m_assertions;
+#endif
+};
+
+class ElementAndTextDescendantIteratorAdapter {
+public:
+    explicit ElementAndTextDescendantIteratorAdapter(ContainerNode& root);
+    ElementAndTextDescendantIterator begin();
+    ElementAndTextDescendantIterator end();
+
+private:
+    ContainerNode& m_root;
+};
+
+ElementAndTextDescendantIteratorAdapter elementAndTextDescendants(ContainerNode&);
+
+// ElementAndTextDescendantIterator
+
+inline ElementAndTextDescendantIterator::ElementAndTextDescendantIterator()
+    : m_current(nullptr)
+{
+}
+
+inline ElementAndTextDescendantIterator::ElementAndTextDescendantIterator(ContainerNode& 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& root, Node* current)
+    : m_current(current != &root ? current : nullptr)
+#if !ASSERT_DISABLED
+    , m_assertions(m_current)
+#endif
+{
+    if (!m_current)
+        return;
+    ASSERT(isElementOrText(*m_current));
+
+    Vector<Node*, 20> ancestorStack;
+    auto* ancestor = m_current->parentNode();
+    while (ancestor != &root) {
+        ancestorStack.append(ancestor);
+        ancestor = ancestor->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& current)
+{
+    auto* node = current.firstChild();
+    while (node && !isElementOrText(*node))
+        node = node->nextSibling();
+    return node;
+}
+
+inline Node* ElementAndTextDescendantIterator::nextSibling(Node& current)
+{
+    auto* node = current.nextSibling();
+    while (node && !isElementOrText(*node))
+        node = node->nextSibling();
+    return node;
+}
+
+inline Node* ElementAndTextDescendantIterator::previousSibling(Node& current)
+{
+    auto* node = current.previousSibling();
+    while (node && !isElementOrText(*node))
+        node = node->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& 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& 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& 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& 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& ElementAndTextDescendantIterator::operator*()
+{
+    ASSERT(m_current);
+    ASSERT(isElementOrText(*m_current));
+    ASSERT(!m_assertions.domTreeHasMutated());
+    return *m_current;
+}
+
+inline Node* ElementAndTextDescendantIterator::operator->()
+{
+    ASSERT(m_current);
+    ASSERT(isElementOrText(*m_current));
+    ASSERT(!m_assertions.domTreeHasMutated());
+    return m_current;
+}
+
+inline const Node& ElementAndTextDescendantIterator::operator*() const
+{
+    ASSERT(m_current);
+    ASSERT(isElementOrText(*m_current));
+    ASSERT(!m_assertions.domTreeHasMutated());
+    return *m_current;
+}
+
+inline const Node* ElementAndTextDescendantIterator::operator->() const
+{
+    ASSERT(m_current);
+    ASSERT(isElementOrText(*m_current));
+    ASSERT(!m_assertions.domTreeHasMutated());
+    return m_current;
+}
+
+inline bool ElementAndTextDescendantIterator::operator==(const ElementAndTextDescendantIterator& other) const
+{
+    ASSERT(!m_assertions.domTreeHasMutated());
+    return m_current == other.m_current;
+}
+
+inline bool ElementAndTextDescendantIterator::operator!=(const ElementAndTextDescendantIterator& other) const
+{
+    return !(*this == other);
+}
+
+// ElementAndTextDescendantIteratorAdapter
+
+inline ElementAndTextDescendantIteratorAdapter::ElementAndTextDescendantIteratorAdapter(ContainerNode& root)
+    : m_root(root)
+{
+}
+
+inline ElementAndTextDescendantIterator ElementAndTextDescendantIteratorAdapter::begin()
+{
+    return ElementAndTextDescendantIterator(m_root);
+}
+
+inline ElementAndTextDescendantIterator ElementAndTextDescendantIteratorAdapter::end()
+{
+    return { };
+}
+
+// Standalone functions
+
+inline ElementAndTextDescendantIteratorAdapter elementAndTextDescendants(ContainerNode& root)
+{
+    return ElementAndTextDescendantIteratorAdapter(root);
+}
+
+}
+#endif

Modified: trunk/Source/WebCore/dom/ElementIteratorAssertions.h (196280 => 196281)


--- 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)
@@ -32,7 +32,7 @@
 
 class ElementIteratorAssertions {
 public:
-    ElementIteratorAssertions(const Element* first = nullptr);
+    ElementIteratorAssertions(const Node* first = nullptr);
     bool domTreeHasMutated() const;
     void dropEventDispatchAssertion();
     void clear();
@@ -45,7 +45,7 @@
 
 // FIXME: No real point in doing these as inlines; they are for debugging and we usually turn off inlining in debug builds.
 
-inline ElementIteratorAssertions::ElementIteratorAssertions(const Element* first)
+inline ElementIteratorAssertions::ElementIteratorAssertions(const Node* first)
     : m_document(first ? &first->document() : nullptr)
     , m_initialDOMTreeVersion(first ? m_document->domTreeVersion() : 0)
 {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to