Home | History | Annotate | Download | only in shadow
      1 
      2 /*
      3  * Copyright (C) 2012 Google Inc. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  *     * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *     * Neither the name of Google Inc. nor the names of its
     12  * contributors may be used to endorse or promote products derived from
     13  * this software without specific prior written permission.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "config.h"
     29 #include "core/dom/shadow/ComposedTreeWalker.h"
     30 
     31 #include "core/dom/Element.h"
     32 #include "core/dom/shadow/ElementShadow.h"
     33 #include "core/html/shadow/HTMLContentElement.h"
     34 #include "core/html/shadow/HTMLShadowElement.h"
     35 
     36 namespace WebCore {
     37 
     38 static inline ElementShadow* shadowFor(const Node* node)
     39 {
     40     if (node && node->isElementNode())
     41         return toElement(node)->shadow();
     42     return 0;
     43 }
     44 
     45 Node* ComposedTreeWalker::traverseChild(const Node* node, TraversalDirection direction) const
     46 {
     47     ASSERT(node);
     48     ElementShadow* shadow = shadowFor(node);
     49     return shadow ? traverseLightChildren(shadow->youngestShadowRoot(), direction)
     50             : traverseLightChildren(node, direction);
     51 }
     52 
     53 Node* ComposedTreeWalker::traverseLightChildren(const Node* node, TraversalDirection direction)
     54 {
     55     ASSERT(node);
     56     return traverseSiblings(direction == TraversalDirectionForward ? node->firstChild() : node->lastChild(), direction);
     57 }
     58 
     59 Node* ComposedTreeWalker::traverseSiblings(const Node* node, TraversalDirection direction)
     60 {
     61     for (const Node* sibling = node; sibling; sibling = (direction == TraversalDirectionForward ? sibling->nextSibling() : sibling->previousSibling())) {
     62         if (Node* found = traverseNode(sibling, direction))
     63             return found;
     64     }
     65     return 0;
     66 }
     67 
     68 Node* ComposedTreeWalker::traverseNode(const Node* node, TraversalDirection direction)
     69 {
     70     ASSERT(node);
     71     if (!isActiveInsertionPoint(*node))
     72         return const_cast<Node*>(node);
     73     const InsertionPoint* insertionPoint = toInsertionPoint(node);
     74     if (Node* found = traverseDistributedNodes(direction == TraversalDirectionForward ? insertionPoint->first() : insertionPoint->last(), insertionPoint, direction))
     75         return found;
     76     ASSERT(isHTMLShadowElement(node) || (isHTMLContentElement(node) && !node->hasChildNodes()));
     77     return 0;
     78 }
     79 
     80 Node* ComposedTreeWalker::traverseDistributedNodes(const Node* node, const InsertionPoint* insertionPoint, TraversalDirection direction)
     81 {
     82     for (const Node* next = node; next; next = (direction == TraversalDirectionForward ? insertionPoint->nextTo(next) : insertionPoint->previousTo(next))) {
     83         if (Node* found = traverseNode(next, direction))
     84             return found;
     85     }
     86     return 0;
     87 }
     88 
     89 Node* ComposedTreeWalker::traverseSiblingOrBackToInsertionPoint(const Node* node, TraversalDirection direction)
     90 {
     91     ASSERT(node);
     92 
     93     if (!shadowWhereNodeCanBeDistributed(*node))
     94         return traverseSiblingInCurrentTree(node, direction);
     95 
     96     const InsertionPoint* insertionPoint = resolveReprojection(node);
     97     if (!insertionPoint)
     98         return traverseSiblingInCurrentTree(node, direction);
     99 
    100     if (Node* found = traverseDistributedNodes(direction == TraversalDirectionForward ? insertionPoint->nextTo(node) : insertionPoint->previousTo(node), insertionPoint, direction))
    101         return found;
    102     return traverseSiblingOrBackToInsertionPoint(insertionPoint, direction);
    103 }
    104 
    105 Node* ComposedTreeWalker::traverseSiblingInCurrentTree(const Node* node, TraversalDirection direction)
    106 {
    107     ASSERT(node);
    108     if (Node* found = traverseSiblings(direction == TraversalDirectionForward ? node->nextSibling() : node->previousSibling(), direction))
    109         return found;
    110     if (Node* next = traverseBackToYoungerShadowRoot(node, direction))
    111         return next;
    112     return 0;
    113 }
    114 
    115 Node* ComposedTreeWalker::traverseBackToYoungerShadowRoot(const Node* node, TraversalDirection direction)
    116 {
    117     ASSERT(node);
    118     if (node->parentNode() && node->parentNode()->isShadowRoot()) {
    119         ShadowRoot* parentShadowRoot = toShadowRoot(node->parentNode());
    120         if (!parentShadowRoot->isYoungest()) {
    121             HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadowInsertionPointOfYoungerShadowRoot();
    122             ASSERT(assignedInsertionPoint);
    123             return traverseSiblingInCurrentTree(assignedInsertionPoint, direction);
    124         }
    125     }
    126     return 0;
    127 }
    128 
    129 // FIXME: Use an iterative algorithm so that it can be inlined.
    130 // https://bugs.webkit.org/show_bug.cgi?id=90415
    131 Node* ComposedTreeWalker::traverseParent(const Node* node, ParentTraversalDetails* details) const
    132 {
    133     if (node->isPseudoElement())
    134         return node->parentOrShadowHostNode();
    135 
    136     if (shadowWhereNodeCanBeDistributed(*node)) {
    137         if (const InsertionPoint* insertionPoint = resolveReprojection(node)) {
    138             if (details)
    139                 details->didTraverseInsertionPoint(insertionPoint);
    140             // The node is distributed. But the distribution was stopped at this insertion point.
    141             if (shadowWhereNodeCanBeDistributed(*insertionPoint))
    142                 return 0;
    143             return traverseParentOrHost(insertionPoint, details);
    144         }
    145         return 0;
    146     }
    147     return traverseParentOrHost(node, details);
    148 }
    149 
    150 inline Node* ComposedTreeWalker::traverseParentOrHost(const Node* node, ParentTraversalDetails* details) const
    151 {
    152     Node* parent = node->parentNode();
    153     if (!parent)
    154         return 0;
    155     if (!parent->isShadowRoot())
    156         return parent;
    157     ShadowRoot* shadowRoot = toShadowRoot(parent);
    158     ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot());
    159     if (!shadowRoot->isYoungest())
    160         return 0;
    161     if (details)
    162         details->didTraverseShadowRoot(shadowRoot);
    163     return shadowRoot->host();
    164 }
    165 
    166 } // namespace
    167