Changeset 196281 in webkit


Ignore:
Timestamp:
Feb 8, 2016, 5:15:52 PM (10 years ago)
Author:
Antti Koivisto
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.

Location:
trunk/Source/WebCore
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r196270 r196281  
     12016-02-08  Antti Koivisto  <antti@apple.com>
     2
     3        Implement ComposedTreeIterator in terms of ElementAndTextDescendantIterator
     4        https://bugs.webkit.org/show_bug.cgi?id=154003
     5
     6        Reviewed by Darin Adler.
     7
     8        Currently ComposedTreeIterator implements tree traversal using NodeTraversal. This makes it overly complicated.
     9        It can also return nodes other than Element and Text which should not be part of the composed tree.
     10
     11        This patch adds a new iterator type, ElementAndTextDescendantIterator, similar to the existing ElementDescendantIterator.
     12        ComposedTreeIterator is then implemented using this new iterator.
     13
     14        When entering a shadow tree or a slot the local iterator is pushed along with the context stack and a new local
     15        iterator is initialized for the new context. When leaving a shadow tree the context stack is popped and the previous
     16        local iterator becomes active.
     17
     18        * WebCore.xcodeproj/project.pbxproj:
     19        * dom/ComposedTreeIterator.cpp:
     20        (WebCore::ComposedTreeIterator::ComposedTreeIterator):
     21        (WebCore::ComposedTreeIterator::initializeContextStack):
     22        (WebCore::ComposedTreeIterator::pushContext):
     23        (WebCore::ComposedTreeIterator::traverseNextInShadowTree):
     24        (WebCore::ComposedTreeIterator::traverseNextLeavingContext):
     25        (WebCore::ComposedTreeIterator::advanceInSlot):
     26        (WebCore::ComposedTreeIterator::traverseSiblingInSlot):
     27        (WebCore::ComposedTreeIterator::initializeShadowStack): Deleted.
     28        (WebCore::ComposedTreeIterator::traverseParentInShadowTree): Deleted.
     29        (WebCore::ComposedTreeIterator::traverseNextSiblingSlot): Deleted.
     30        (WebCore::ComposedTreeIterator::traversePreviousSiblingSlot): Deleted.
     31        * dom/ComposedTreeIterator.h:
     32        (WebCore::ComposedTreeIterator::operator*):
     33        (WebCore::ComposedTreeIterator::operator->):
     34        (WebCore::ComposedTreeIterator::operator==):
     35        (WebCore::ComposedTreeIterator::operator!=):
     36        (WebCore::ComposedTreeIterator::operator++):
     37        (WebCore::ComposedTreeIterator::Context::Context):
     38        (WebCore::ComposedTreeIterator::context):
     39        (WebCore::ComposedTreeIterator::current):
     40        (WebCore::ComposedTreeIterator::ComposedTreeIterator):
     41        (WebCore::ComposedTreeIterator::traverseNext):
     42        (WebCore::ComposedTreeIterator::traverseNextSkippingChildren):
     43        (WebCore::ComposedTreeIterator::traverseNextSibling):
     44        (WebCore::ComposedTreeIterator::traversePreviousSibling):
     45        (WebCore::ComposedTreeDescendantAdapter::ComposedTreeDescendantAdapter):
     46        (WebCore::ComposedTreeDescendantAdapter::begin):
     47        (WebCore::ComposedTreeDescendantAdapter::end):
     48        (WebCore::ComposedTreeDescendantAdapter::at):
     49        (WebCore::ComposedTreeChildAdapter::Iterator::Iterator):
     50        (WebCore::ComposedTreeChildAdapter::ComposedTreeChildAdapter):
     51        (WebCore::ComposedTreeChildAdapter::begin):
     52        (WebCore::ComposedTreeChildAdapter::end):
     53        (WebCore::ComposedTreeChildAdapter::at):
     54        (WebCore::ComposedTreeIterator::ShadowContext::ShadowContext): Deleted.
     55        (WebCore::ComposedTreeIterator::traverseParent): Deleted.
     56        * dom/ElementAndTextDescendantIterator.h: Added.
     57
     58            New iterator type that traverses Element and Text nodes (that is renderable nodes only).
     59            It also tracks depth for future use.
     60
    1612016-02-08  Joseph Pecoraro  <pecoraro@apple.com>
    262
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r196246 r196281  
    65316531                E43AF8E61AC5B7E800CA717E /* CacheValidation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E43AF8E41AC5B7DD00CA717E /* CacheValidation.cpp */; };
    65326532                E43AF8E71AC5B7EC00CA717E /* CacheValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = E43AF8E51AC5B7DD00CA717E /* CacheValidation.h */; settings = {ATTRIBUTES = (Private, ); }; };
     6533                E440AA961C68420800A265CC /* ElementAndTextDescendantIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = E440AA951C68420800A265CC /* ElementAndTextDescendantIterator.h */; };
    65336534                E44613A10CD6331000FADA75 /* HTMLAudioElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E446138F0CD6331000FADA75 /* HTMLAudioElement.cpp */; };
    65346535                E44613A20CD6331000FADA75 /* HTMLAudioElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E44613900CD6331000FADA75 /* HTMLAudioElement.h */; };
     
    1450914510                E43AF8E41AC5B7DD00CA717E /* CacheValidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CacheValidation.cpp; sourceTree = "<group>"; };
    1451014511                E43AF8E51AC5B7DD00CA717E /* CacheValidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CacheValidation.h; sourceTree = "<group>"; };
     14512                E440AA951C68420800A265CC /* ElementAndTextDescendantIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementAndTextDescendantIterator.h; sourceTree = "<group>"; };
    1451114513                E446138F0CD6331000FADA75 /* HTMLAudioElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTMLAudioElement.cpp; sourceTree = "<group>"; };
    1451214514                E44613900CD6331000FADA75 /* HTMLAudioElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLAudioElement.h; sourceTree = "<group>"; };
     
    2409224094                                93EEC1EA09C2877700C515D1 /* Element.idl */,
    2409324095                                E4AE7C1917D232350009FB31 /* ElementAncestorIterator.h */,
     24096                                E440AA951C68420800A265CC /* ElementAndTextDescendantIterator.h */,
    2409424097                                E46A2B1D17CA76B1000DBCD8 /* ElementChildIterator.h */,
    2409524098                                B5B7A16F17C1080600E4AA0A /* ElementData.cpp */,
     
    2585125854                                C4CD629B18383766007EBAF1 /* FrameSnapshotting.h in Headers */,
    2585225855                                65A21485097A3F5300B9050A /* FrameTree.h in Headers */,
     25856                                E440AA961C68420800A265CC /* ElementAndTextDescendantIterator.h in Headers */,
    2585325857                                65CBFEFA0974F607001DAC25 /* FrameView.h in Headers */,
    2585425858                                97205AB0123928CA00B17380 /* FTPDirectoryDocument.h in Headers */,
  • trunk/Source/WebCore/dom/ComposedTreeIterator.cpp

    r191127 r196281  
    11/*
    2  * Copyright (C) 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3131namespace WebCore {
    3232
    33 void ComposedTreeIterator::initializeShadowStack()
     33ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root)
     34{
     35    ASSERT(!is<ShadowRoot>(root));
     36
     37#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
     38    if (is<HTMLSlotElement>(root)) {
     39        auto& slot = downcast<HTMLSlotElement>(root);
     40        if (auto* assignedNodes = slot.assignedNodes()) {
     41            initializeContextStack(root, *assignedNodes->at(0));
     42            return;
     43        }
     44    }
     45#endif
     46    auto& effectiveRoot = root.shadowRoot() ? *root.shadowRoot() : root;
     47    m_contextStack.uncheckedAppend(Context(effectiveRoot));
     48}
     49
     50ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root, Node& current)
     51{
     52    ASSERT(!is<ShadowRoot>(root));
     53    ASSERT(!is<ShadowRoot>(current));
     54
     55    bool mayNeedShadowStack = root.shadowRoot() || (&current != &root && current.parentNode() != &root);
     56    if (mayNeedShadowStack)
     57        initializeContextStack(root, current);
     58    else
     59        m_contextStack.uncheckedAppend(Context(root, current));
     60}
     61
     62void ComposedTreeIterator::initializeContextStack(ContainerNode& root, Node& current)
    3463{
    3564    // This code sets up the iterator for arbitrary node/root pair. It is not needed in common cases
    3665    // or completes fast because node and root are close (like in composedTreeChildren(*parent).at(node) case).
    37     auto* node = m_current;
    38     while (node != &m_root) {
     66    auto* node = &current;
     67    auto* contextCurrent = node;
     68    size_t currentSlotNodeIndex = notFound;
     69    while (node != &root) {
    3970        auto* parent = node->parentNode();
    4071        if (!parent) {
    41             m_current = nullptr;
     72            *this = { };
    4273            return;
    4374        }
    4475        if (is<ShadowRoot>(*parent)) {
    4576            auto& shadowRoot = downcast<ShadowRoot>(*parent);
    46             if (m_shadowStack.isEmpty() || m_shadowStack.last().host != shadowRoot.host())
    47                 m_shadowStack.append(shadowRoot.host());
     77            m_contextStack.append(Context(shadowRoot, *contextCurrent, currentSlotNodeIndex));
    4878            node = shadowRoot.host();
     79            contextCurrent = node;
     80            currentSlotNodeIndex = notFound;
    4981            continue;
    5082        }
    5183        if (auto* shadowRoot = parent->shadowRoot()) {
    5284#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    53             m_shadowStack.append(shadowRoot->host());
     85            m_contextStack.append(Context(*parent, *contextCurrent, currentSlotNodeIndex));
    5486            auto* assignedSlot = shadowRoot->findAssignedSlot(*node);
    5587            if (assignedSlot) {
    56                 size_t index = assignedSlot->assignedNodes()->find(node);
    57                 ASSERT(index != notFound);
    58 
    59                 m_shadowStack.last().currentSlot = assignedSlot;
    60                 m_shadowStack.last().currentSlotNodeIndex = index;
     88                currentSlotNodeIndex = assignedSlot->assignedNodes()->find(node);
     89                ASSERT(currentSlotNodeIndex != notFound);
    6190                node = assignedSlot;
     91                contextCurrent = assignedSlot;
    6292                continue;
    6393            }
     
    6595#else
    6696            UNUSED_PARAM(shadowRoot);
    67             m_current = nullptr;
     97#endif
     98            *this = { };
    6899            return;
    69 #endif
    70100        }
    71101        node = parent;
    72102    }
    73     m_shadowStack.reverse();
     103    m_contextStack.append(Context(root, *contextCurrent, currentSlotNodeIndex));
     104
     105    m_contextStack.reverse();
     106}
     107
     108bool ComposedTreeIterator::pushContext(ShadowRoot& shadowRoot)
     109{
     110    Context shadowContext(shadowRoot);
     111    if (!shadowContext.iterator)
     112        return false;
     113    m_contextStack.append(WTFMove(shadowContext));
     114    return true;
    74115}
    75116
    76117void ComposedTreeIterator::traverseNextInShadowTree()
    77118{
    78     ASSERT(!m_shadowStack.isEmpty());
    79 
    80     auto* shadowContext = &m_shadowStack.last();
     119    ASSERT(m_contextStack.size() > 1);
    81120
    82121#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    83     if (is<HTMLSlotElement>(*m_current) && !shadowContext->currentSlot) {
    84         auto& slot = downcast<HTMLSlotElement>(*m_current);
     122    if (is<HTMLSlotElement>(current())) {
     123        auto& slot = downcast<HTMLSlotElement>(current());
    85124        if (auto* assignedNodes = slot.assignedNodes()) {
    86             shadowContext->currentSlot = &slot;
    87             shadowContext->currentSlotNodeIndex = 0;
    88             m_current = assignedNodes->at(0);
     125            context().slotNodeIndex = 0;
     126            auto* assignedNode = assignedNodes->at(0);
     127            m_contextStack.append(Context(*assignedNode->parentElement(), *assignedNode));
    89128            return;
    90129        }
     
    92131#endif
    93132
    94     m_current = NodeTraversal::next(*m_current, shadowContext->host);
     133    context().iterator.traverseNext();
    95134
    96     while (!m_current) {
     135    if (!context().iterator)
     136        traverseNextLeavingContext();
     137}
     138
     139void ComposedTreeIterator::traverseNextLeavingContext()
     140{
     141    ASSERT(m_contextStack.size() > 1);
     142
     143    while (!context().iterator && m_contextStack.size() > 1) {
     144        m_contextStack.removeLast();
     145        if (!context().iterator)
     146            return;
    97147#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    98         if (auto* slot = shadowContext->currentSlot) {
    99             bool nextNodeInSameSlot = ++shadowContext->currentSlotNodeIndex < slot->assignedNodes()->size();
    100             if (nextNodeInSameSlot) {
    101                 m_current = slot->assignedNodes()->at(shadowContext->currentSlotNodeIndex);
    102                 return;
    103             }
    104             m_current = NodeTraversal::nextSkippingChildren(*slot, shadowContext->host);
    105             shadowContext->currentSlot = nullptr;
    106             continue;
    107         }
     148        if (is<HTMLSlotElement>(current()) && advanceInSlot(1))
     149            return;
    108150#endif
    109         auto& previousHost = *shadowContext->host;
    110         m_shadowStack.removeLast();
    111 
    112         if (m_shadowStack.isEmpty()) {
    113             m_current = NodeTraversal::nextSkippingChildren(previousHost, &m_root);
    114             return;
    115         }
    116         shadowContext = &m_shadowStack.last();
    117         m_current = NodeTraversal::nextSkippingChildren(previousHost, shadowContext->host);
     151        context().iterator.traverseNextSkippingChildren();
    118152    }
    119153}
    120154
    121 void ComposedTreeIterator::traverseParentInShadowTree()
     155#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
     156bool ComposedTreeIterator::advanceInSlot(int direction)
    122157{
    123     ASSERT(!m_shadowStack.isEmpty());
     158    ASSERT(context().slotNodeIndex != notFound);
    124159
    125     auto& shadowContext = m_shadowStack.last();
     160    auto& assignedNodes = *downcast<HTMLSlotElement>(current()).assignedNodes();
     161    // It is fine to underflow this.
     162    context().slotNodeIndex += direction;
     163    if (context().slotNodeIndex >= assignedNodes.size())
     164        return false;
    126165
    127     auto* parent = m_current->parentNode();
    128     if (is<ShadowRoot>(parent)) {
    129         ASSERT(shadowContext.host == downcast<ShadowRoot>(*parent).host());
    130 
    131         m_current = shadowContext.host;
    132         m_shadowStack.removeLast();
    133         return;
    134     }
    135     if (parent->shadowRoot()) {
    136 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    137         ASSERT(shadowContext.host == parent);
    138 
    139         auto* slot = shadowContext.currentSlot;
    140         ASSERT(slot->assignedNodes()->at(shadowContext.currentSlotNodeIndex) == m_current);
    141 
    142         m_current = slot;
    143         shadowContext.currentSlot = nullptr;
    144         return;
    145 #else
    146         m_current = nullptr;
    147         return;
    148 #endif
    149     }
    150     m_current = parent;
     166    auto* slotNode = assignedNodes.at(context().slotNodeIndex);
     167    m_contextStack.append(Context(*slotNode->parentElement(), *slotNode));
     168    return true;
    151169}
    152170
    153 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    154 void ComposedTreeIterator::traverseNextSiblingSlot()
     171void ComposedTreeIterator::traverseSiblingInSlot(int direction)
    155172{
    156     ASSERT(m_current->parentNode()->shadowRoot());
    157     ASSERT(!m_shadowStack.isEmpty());
    158     ASSERT(m_shadowStack.last().host == m_current->parentNode());
     173    ASSERT(m_contextStack.size() > 1);
     174    ASSERT(current().parentNode()->shadowRoot());
    159175
    160     auto& shadowContext = m_shadowStack.last();
     176    m_contextStack.removeLast();
    161177
    162     if (!shadowContext.currentSlot) {
    163         m_current = nullptr;
    164         return;
    165     }
    166     auto* slotNodes = shadowContext.currentSlot->assignedNodes();
    167     ASSERT(slotNodes->at(shadowContext.currentSlotNodeIndex) == m_current);
    168 
    169     bool nextNodeInSameSlot = ++shadowContext.currentSlotNodeIndex < slotNodes->size();
    170     m_current = nextNodeInSameSlot ? slotNodes->at(shadowContext.currentSlotNodeIndex) : nullptr;
    171 }
    172 
    173 void ComposedTreeIterator::traversePreviousSiblingSlot()
    174 {
    175     ASSERT(m_current->parentNode()->shadowRoot());
    176     ASSERT(!m_shadowStack.isEmpty());
    177     ASSERT(m_shadowStack.last().host == m_current->parentNode());
    178 
    179     auto& shadowContext = m_shadowStack.last();
    180 
    181     if (!shadowContext.currentSlot) {
    182         m_current = nullptr;
    183         return;
    184     }
    185     auto* slotNodes = shadowContext.currentSlot->assignedNodes();
    186     ASSERT(slotNodes->at(shadowContext.currentSlotNodeIndex) == m_current);
    187 
    188     bool previousNodeInSameSlot = shadowContext.currentSlotNodeIndex > 0;
    189     m_current = previousNodeInSameSlot ? slotNodes->at(--shadowContext.currentSlotNodeIndex) : nullptr;
     178    if (!advanceInSlot(direction))
     179        *this = { };
    190180}
    191181#endif
  • trunk/Source/WebCore/dom/ComposedTreeIterator.h

    r191112 r196281  
    11/*
    2  * Copyright (C) 2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 #include "NodeTraversal.h"
     26#include "ElementAndTextDescendantIterator.h"
    2727#include "ShadowRoot.h"
    2828
     
    3636class ComposedTreeIterator {
    3737public:
     38    ComposedTreeIterator();
    3839    ComposedTreeIterator(ContainerNode& root);
    3940    ComposedTreeIterator(ContainerNode& root, Node& current);
    4041
    41     Node& operator*() { return *m_current; }
    42     Node* operator->() { return m_current; }
    43 
    44     bool operator==(const ComposedTreeIterator& other) const { return m_current == other.m_current; }
    45     bool operator!=(const ComposedTreeIterator& other) const { return m_current != other.m_current; }
    46 
    47     ComposedTreeIterator& operator++() { return traverseNextSibling(); }
     42    Node& operator*() { return current(); }
     43    Node* operator->() { return &current(); }
     44
     45    bool operator==(const ComposedTreeIterator& other) const { return context().iterator == other.context().iterator; }
     46    bool operator!=(const ComposedTreeIterator& other) const { return context().iterator != other.context().iterator; }
     47
     48    ComposedTreeIterator& operator++() { return traverseNext(); }
    4849
    4950    ComposedTreeIterator& traverseNext();
     51    ComposedTreeIterator& traverseNextSkippingChildren();
    5052    ComposedTreeIterator& traverseNextSibling();
    5153    ComposedTreeIterator& traversePreviousSibling();
    52     ComposedTreeIterator& traverseParent();
     54
     55    unsigned depth() const;
    5356
    5457private:
    55     void initializeShadowStack();
     58    void initializeContextStack(ContainerNode& root, Node& current);
    5659    void traverseNextInShadowTree();
    57     void traverseParentInShadowTree();
    58 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    59     void traverseNextSiblingSlot();
    60     void traversePreviousSiblingSlot();
    61 #endif
    62 
    63     ContainerNode& m_root;
    64     Node* m_current { 0 };
    65 
    66     struct ShadowContext {
    67         ShadowContext(Element* host)
    68             : host(host)
    69         { }
    70 
    71         Element* host;
    72 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    73         HTMLSlotElement* currentSlot { nullptr };
    74         unsigned currentSlotNodeIndex { 0 };
     60    void traverseNextLeavingContext();
     61    bool pushContext(ShadowRoot&);
     62#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
     63    bool advanceInSlot(int direction);
     64    void traverseSiblingInSlot(int direction);
     65#endif
     66
     67    struct Context {
     68        Context() { }
     69        explicit Context(ContainerNode& root)
     70            : iterator(root)
     71        { }
     72        Context(ContainerNode& root, Node& node, size_t slotNodeIndex = notFound)
     73            : iterator(root, &node)
     74            , slotNodeIndex(slotNodeIndex)
     75        { }
     76
     77        ElementAndTextDescendantIterator iterator;
     78#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
     79        size_t slotNodeIndex { notFound };
    7580#endif
    7681    };
    77     Vector<ShadowContext, 4> m_shadowStack;
     82    Context& context() { return m_contextStack.last(); }
     83    const Context& context() const { return m_contextStack.last(); }
     84    Node& current() { return *context().iterator; }
     85
     86    Vector<Context, 4> m_contextStack;
    7887};
    7988
    80 inline ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root)
    81     : m_root(root)
    82 {
    83     ASSERT(!is<ShadowRoot>(m_root));
    84 }
    85 
    86 inline ComposedTreeIterator::ComposedTreeIterator(ContainerNode& root, Node& current)
    87     : m_root(root)
    88     , m_current(&current)
    89 {
    90     ASSERT(!is<ShadowRoot>(m_root));
    91     ASSERT(!is<ShadowRoot>(m_current));
    92 
    93     bool mayNeedShadowStack = m_root.shadowRoot() || (m_current != &m_root && current.parentNode() != &m_root);
    94     if (mayNeedShadowStack)
    95         initializeShadowStack();
     89inline ComposedTreeIterator::ComposedTreeIterator()
     90    : m_contextStack({ { } })
     91{
    9692}
    9793
    9894inline ComposedTreeIterator& ComposedTreeIterator::traverseNext()
    9995{
    100     if (auto* shadowRoot = m_current->shadowRoot()) {
    101         m_shadowStack.append(shadowRoot->host());
    102         m_current = shadowRoot;
    103     }
    104 
    105     if (m_shadowStack.isEmpty())
    106         m_current = NodeTraversal::next(*m_current, &m_root);
    107     else
     96    if (auto* shadowRoot = context().iterator->shadowRoot()) {
     97        if (pushContext(*shadowRoot))
     98            return *this;
     99    }
     100
     101    if (m_contextStack.size() > 1) {
    108102        traverseNextInShadowTree();
    109 
     103        return *this;
     104    }
     105
     106    context().iterator.traverseNext();
     107    return *this;
     108}
     109
     110inline ComposedTreeIterator& ComposedTreeIterator::traverseNextSkippingChildren()
     111{
     112    context().iterator.traverseNextSkippingChildren();
     113
     114    if (!context().iterator && m_contextStack.size() > 1)
     115        traverseNextLeavingContext();
     116   
    110117    return *this;
    111118}
     
    114121{
    115122#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    116     bool isAssignedToSlot = !m_shadowStack.isEmpty() && m_current->parentNode()->shadowRoot();
    117     if (isAssignedToSlot) {
    118         traverseNextSiblingSlot();
     123    if (current().parentNode()->shadowRoot()) {
     124        traverseSiblingInSlot(1);
    119125        return *this;
    120126    }
    121127#endif
    122     m_current = m_current->nextSibling();
     128    context().iterator.traverseNextSibling();
    123129    return *this;
    124130}
     
    127133{
    128134#if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)
    129     bool isAssignedToSlot = !m_shadowStack.isEmpty() && m_current->parentNode()->shadowRoot();
    130     if (isAssignedToSlot) {
    131         traversePreviousSiblingSlot();
     135    if (current().parentNode()->shadowRoot()) {
     136        traverseSiblingInSlot(-1);
    132137        return *this;
    133138    }
    134139#endif
    135     m_current = m_current->previousSibling();
    136     return *this;
    137 }
    138 
    139 inline ComposedTreeIterator& ComposedTreeIterator::traverseParent()
    140 {
    141     if (m_shadowStack.isEmpty())
    142         m_current = m_current->parentNode();
    143     else
    144         traverseParentInShadowTree();
    145 
    146     return *this;
     140    context().iterator.traversePreviousSibling();
     141    return *this;
     142}
     143
     144inline unsigned ComposedTreeIterator::depth() const
     145{
     146    unsigned depth = 0;
     147    for (auto& context : m_contextStack)
     148        depth += context.iterator.depth();
     149    return depth;
    147150}
    148151
     
    153156    { }
    154157
    155     ComposedTreeIterator begin() { return ComposedTreeIterator(m_parent, m_parent).traverseNext(); }
    156     ComposedTreeIterator end() { return ComposedTreeIterator(m_parent); }
     158    ComposedTreeIterator begin() { return ComposedTreeIterator(m_parent); }
     159    ComposedTreeIterator end() { return { }; }
    157160    ComposedTreeIterator at(const Node& child) { return ComposedTreeIterator(m_parent, const_cast<Node&>(child)); }
    158161   
     
    165168    class Iterator : public ComposedTreeIterator {
    166169    public:
    167         Iterator(ContainerNode& root)
     170        Iterator() = default;
     171        explicit Iterator(ContainerNode& root)
    168172            : ComposedTreeIterator(root)
    169173        { }
     
    180184    { }
    181185
    182     Iterator begin() { return static_cast<Iterator&>(Iterator(m_parent, m_parent).traverseNext()); }
    183     Iterator end() { return Iterator(m_parent); }
     186    Iterator begin() { return Iterator(m_parent); }
     187    Iterator end() { return { }; }
    184188    Iterator at(const Node& child) { return Iterator(m_parent, const_cast<Node&>(child)); }
    185189
  • trunk/Source/WebCore/dom/ElementIteratorAssertions.h

    r188520 r196281  
    3333class ElementIteratorAssertions {
    3434public:
    35     ElementIteratorAssertions(const Element* first = nullptr);
     35    ElementIteratorAssertions(const Node* first = nullptr);
    3636    bool domTreeHasMutated() const;
    3737    void dropEventDispatchAssertion();
     
    4646// FIXME: No real point in doing these as inlines; they are for debugging and we usually turn off inlining in debug builds.
    4747
    48 inline ElementIteratorAssertions::ElementIteratorAssertions(const Element* first)
     48inline ElementIteratorAssertions::ElementIteratorAssertions(const Node* first)
    4949    : m_document(first ? &first->document() : nullptr)
    5050    , m_initialDOMTreeVersion(first ? m_document->domTreeVersion() : 0)
Note: See TracChangeset for help on using the changeset viewer.