Home | History | Annotate | Download | only in shadow
      1 /*
      2  * Copyright (C) 2012 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Neither the name of Google Inc. nor the names of its
     11  * contributors may be used to endorse or promote products derived from
     12  * this software without specific prior written permission.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     15  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     17  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     18  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #ifndef ComposedShadowTreeWalker_h
     28 #define ComposedShadowTreeWalker_h
     29 
     30 #include "core/dom/NodeRenderingTraversal.h"
     31 #include "core/dom/shadow/InsertionPoint.h"
     32 #include "core/dom/shadow/ShadowRoot.h"
     33 
     34 namespace WebCore {
     35 
     36 class Node;
     37 class ShadowRoot;
     38 
     39 // FIXME: Make some functions inline to optimise the performance.
     40 // https://bugs.webkit.org/show_bug.cgi?id=82702
     41 class ComposedShadowTreeWalker {
     42 public:
     43     typedef NodeRenderingTraversal::ParentDetails ParentTraversalDetails;
     44 
     45     enum Policy {
     46         CrossUpperBoundary,
     47         DoNotCrossUpperBoundary,
     48     };
     49 
     50     enum StartPolicy {
     51         CanStartFromShadowBoundary,
     52         CannotStartFromShadowBoundary
     53     };
     54 
     55     ComposedShadowTreeWalker(const Node*, Policy = CrossUpperBoundary, StartPolicy = CannotStartFromShadowBoundary);
     56 
     57     Node* get() const { return const_cast<Node*>(m_node); }
     58 
     59     void firstChild();
     60     void lastChild();
     61 
     62     void nextSibling();
     63     void previousSibling();
     64 
     65     void parent();
     66 
     67     void next();
     68     void previous();
     69 
     70     Node* traverseParent(const Node*, ParentTraversalDetails* = 0) const;
     71 
     72 private:
     73     ComposedShadowTreeWalker(const Node*, ParentTraversalDetails*);
     74 
     75     enum TraversalDirection {
     76         TraversalDirectionForward,
     77         TraversalDirectionBackward
     78     };
     79 
     80     bool canCrossUpperBoundary() const { return m_policy == CrossUpperBoundary; }
     81 
     82     void assertPrecondition() const
     83     {
     84 #ifndef NDEBUG
     85         ASSERT(m_node);
     86         if (canCrossUpperBoundary())
     87             ASSERT(!m_node->isShadowRoot());
     88         else
     89             ASSERT(!m_node->isShadowRoot() || toShadowRoot(m_node)->isYoungest());
     90         ASSERT(!isActiveInsertionPoint(m_node));
     91 #endif
     92     }
     93 
     94     void assertPostcondition() const
     95     {
     96 #ifndef NDEBUG
     97         if (m_node)
     98             assertPrecondition();
     99 #endif
    100     }
    101 
    102     static Node* traverseNode(const Node*, TraversalDirection);
    103     static Node* traverseLightChildren(const Node*, TraversalDirection);
    104 
    105     Node* traverseFirstChild(const Node*) const;
    106     Node* traverseLastChild(const Node*) const;
    107     Node* traverseChild(const Node*, TraversalDirection) const;
    108 
    109     static Node* traverseNextSibling(const Node*);
    110     static Node* traversePreviousSibling(const Node*);
    111 
    112     static Node* traverseSiblingOrBackToInsertionPoint(const Node*, TraversalDirection);
    113     static Node* traverseSiblingInCurrentTree(const Node*, TraversalDirection);
    114 
    115     static Node* traverseSiblings(const Node*, TraversalDirection);
    116     static Node* traverseDistributedNodes(const Node*, const InsertionPoint*, TraversalDirection);
    117 
    118     static Node* traverseBackToYoungerShadowRoot(const Node*, TraversalDirection);
    119     static Node* escapeFallbackContentElement(const Node*, TraversalDirection);
    120 
    121     Node* traverseNodeEscapingFallbackContents(const Node*, ParentTraversalDetails* = 0) const;
    122     Node* traverseParentInCurrentTree(const Node*, ParentTraversalDetails* = 0) const;
    123     Node* traverseParentBackToYoungerShadowRootOrHost(const ShadowRoot*, ParentTraversalDetails* = 0) const;
    124 
    125     const Node* m_node;
    126     Policy m_policy;
    127 };
    128 
    129 inline ComposedShadowTreeWalker::ComposedShadowTreeWalker(const Node* node, Policy policy, StartPolicy startPolicy)
    130     : m_node(node)
    131     , m_policy(policy)
    132 {
    133     UNUSED_PARAM(startPolicy);
    134 #ifndef NDEBUG
    135     if (m_node && startPolicy == CannotStartFromShadowBoundary)
    136         assertPrecondition();
    137 #endif
    138 }
    139 
    140 inline void ComposedShadowTreeWalker::parent()
    141 {
    142     assertPrecondition();
    143     m_node = traverseParent(m_node);
    144     assertPostcondition();
    145 }
    146 
    147 inline void ComposedShadowTreeWalker::nextSibling()
    148 {
    149     assertPrecondition();
    150     m_node = traverseSiblingOrBackToInsertionPoint(m_node, TraversalDirectionForward);
    151     assertPostcondition();
    152 }
    153 
    154 inline void ComposedShadowTreeWalker::previousSibling()
    155 {
    156     assertPrecondition();
    157     m_node = traverseSiblingOrBackToInsertionPoint(m_node, TraversalDirectionBackward);
    158     assertPostcondition();
    159 }
    160 
    161 inline void ComposedShadowTreeWalker::next()
    162 {
    163     assertPrecondition();
    164     if (Node* next = traverseFirstChild(m_node)) {
    165         m_node = next;
    166     } else {
    167         while (m_node) {
    168             if (Node* sibling = traverseNextSibling(m_node)) {
    169                 m_node = sibling;
    170                 break;
    171             }
    172             m_node = traverseParent(m_node);
    173         }
    174     }
    175     assertPostcondition();
    176 }
    177 
    178 inline void ComposedShadowTreeWalker::previous()
    179 {
    180     assertPrecondition();
    181     if (Node* previous = traversePreviousSibling(m_node)) {
    182         while (Node* child = traverseLastChild(previous))
    183             previous = child;
    184         m_node = previous;
    185     } else {
    186         parent();
    187     }
    188     assertPostcondition();
    189 }
    190 
    191 inline void ComposedShadowTreeWalker::firstChild()
    192 {
    193     assertPrecondition();
    194     m_node = traverseChild(m_node, TraversalDirectionForward);
    195     assertPostcondition();
    196 }
    197 
    198 inline void ComposedShadowTreeWalker::lastChild()
    199 {
    200     assertPrecondition();
    201     m_node = traverseLastChild(m_node);
    202     assertPostcondition();
    203 }
    204 
    205 inline Node* ComposedShadowTreeWalker::traverseNextSibling(const Node* node)
    206 {
    207     ASSERT(node);
    208     return traverseSiblingOrBackToInsertionPoint(node, TraversalDirectionForward);
    209 }
    210 
    211 inline Node* ComposedShadowTreeWalker::traversePreviousSibling(const Node* node)
    212 {
    213     ASSERT(node);
    214     return traverseSiblingOrBackToInsertionPoint(node, TraversalDirectionBackward);
    215 }
    216 
    217 inline Node* ComposedShadowTreeWalker::traverseFirstChild(const Node* node) const
    218 {
    219     ASSERT(node);
    220     return traverseChild(node, TraversalDirectionForward);
    221 }
    222 
    223 inline Node* ComposedShadowTreeWalker::traverseLastChild(const Node* node) const
    224 {
    225     ASSERT(node);
    226     return traverseChild(node, TraversalDirectionBackward);
    227 }
    228 
    229 } // namespace
    230 
    231 #endif
    232