Home | History | Annotate | Download | only in dom
      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 #include "config.h"
     28 #include "core/dom/NodeRenderingTraversal.h"
     29 
     30 #include "core/HTMLNames.h"
     31 #include "core/dom/PseudoElement.h"
     32 #include "core/dom/shadow/ComposedTreeWalker.h"
     33 #include "core/rendering/RenderObject.h"
     34 
     35 namespace blink {
     36 
     37 namespace NodeRenderingTraversal {
     38 
     39 static bool isRendererReparented(const RenderObject* renderer)
     40 {
     41     if (!renderer->node()->isElementNode())
     42         return false;
     43     if (toElement(renderer->node())->isInTopLayer())
     44         return true;
     45     return false;
     46 }
     47 
     48 void ParentDetails::didTraverseInsertionPoint(const InsertionPoint* insertionPoint)
     49 {
     50     if (!m_insertionPoint) {
     51         m_insertionPoint = insertionPoint;
     52     }
     53 }
     54 
     55 ContainerNode* parent(const Node* node, ParentDetails* details)
     56 {
     57     ASSERT(node);
     58     ASSERT(!node->document().childNeedsDistributionRecalc());
     59     if (isActiveInsertionPoint(*node))
     60         return 0;
     61     ComposedTreeWalker walker(node, ComposedTreeWalker::CanStartFromShadowBoundary);
     62     return toContainerNode(walker.traverseParent(walker.get(), details));
     63 }
     64 
     65 bool contains(const ContainerNode* container, const Node* node)
     66 {
     67     while (node) {
     68         if (node == container)
     69             return true;
     70         node = NodeRenderingTraversal::parent(node);
     71     }
     72     return false;
     73 }
     74 
     75 Node* nextSibling(const Node* node)
     76 {
     77     ComposedTreeWalker walker(node);
     78     if (node->isBeforePseudoElement()) {
     79         walker.parent();
     80         walker.firstChild();
     81     } else
     82         walker.nextSibling();
     83 
     84     if (walker.get() || node->isAfterPseudoElement())
     85         return walker.get();
     86 
     87     Node* parent = walker.traverseParent(node);
     88     if (parent && parent->isElementNode())
     89         return toElement(parent)->pseudoElement(AFTER);
     90 
     91     return 0;
     92 }
     93 
     94 Node* previousSibling(const Node* node)
     95 {
     96     ComposedTreeWalker walker(node);
     97     if (node->isAfterPseudoElement()) {
     98         walker.parent();
     99         walker.lastChild();
    100     } else
    101         walker.previousSibling();
    102 
    103     if (walker.get() || node->isBeforePseudoElement())
    104         return walker.get();
    105 
    106     Node* parent = walker.traverseParent(node);
    107     if (parent && parent->isElementNode())
    108         return toElement(parent)->pseudoElement(BEFORE);
    109 
    110     return 0;
    111 }
    112 
    113 static Node* lastChild(const Node* node)
    114 {
    115     ComposedTreeWalker walker(node);
    116     walker.lastChild();
    117     return walker.get();
    118 }
    119 
    120 static Node* pseudoAwarePreviousSibling(const Node* node)
    121 {
    122     Node* previousNode = previousSibling(node);
    123     Node* parentNode = parent(node);
    124 
    125     if (parentNode && parentNode->isElementNode() && !previousNode) {
    126         if (node->isAfterPseudoElement()) {
    127             if (Node* child = lastChild(parentNode))
    128                 return child;
    129         }
    130         if (!node->isBeforePseudoElement())
    131             return toElement(parentNode)->pseudoElement(BEFORE);
    132     }
    133     return previousNode;
    134 }
    135 
    136 static Node* pseudoAwareLastChild(const Node* node)
    137 {
    138     if (node->isElementNode()) {
    139         const Element* currentElement = toElement(node);
    140         Node* last = currentElement->pseudoElement(AFTER);
    141         if (last)
    142             return last;
    143 
    144         last = lastChild(currentElement);
    145         if (!last)
    146             last = currentElement->pseudoElement(BEFORE);
    147         return last;
    148     }
    149 
    150     return lastChild(node);
    151 }
    152 
    153 Node* previous(const Node* node, const Node* stayWithin)
    154 {
    155     if (node == stayWithin)
    156         return 0;
    157 
    158     if (Node* previousNode = pseudoAwarePreviousSibling(node)) {
    159         while (Node* previousLastChild = pseudoAwareLastChild(previousNode))
    160             previousNode = previousLastChild;
    161         return previousNode;
    162     }
    163     return parent(node);
    164 }
    165 
    166 static Node* firstChild(const Node* node)
    167 {
    168     ComposedTreeWalker walker(node);
    169     walker.firstChild();
    170     return walker.get();
    171 }
    172 
    173 static Node* pseudoAwareNextSibling(const Node* node)
    174 {
    175     Node* parentNode = parent(node);
    176     Node* nextNode = nextSibling(node);
    177 
    178     if (parentNode && parentNode->isElementNode() && !nextNode) {
    179         if (node->isBeforePseudoElement()) {
    180             if (Node* child = firstChild(parentNode))
    181                 return child;
    182         }
    183         if (!node->isAfterPseudoElement())
    184             return toElement(parentNode)->pseudoElement(AFTER);
    185     }
    186     return nextNode;
    187 }
    188 
    189 static Node* pseudoAwareFirstChild(const Node* node)
    190 {
    191     if (node->isElementNode()) {
    192         const Element* currentElement = toElement(node);
    193         Node* first = currentElement->pseudoElement(BEFORE);
    194         if (first)
    195             return first;
    196         first = firstChild(currentElement);
    197         if (!first)
    198             first = currentElement->pseudoElement(AFTER);
    199         return first;
    200     }
    201 
    202     return firstChild(node);
    203 }
    204 
    205 Node* next(const Node* node, const Node* stayWithin)
    206 {
    207     if (Node* child = pseudoAwareFirstChild(node))
    208         return child;
    209     if (node == stayWithin)
    210         return 0;
    211     if (Node* nextNode = pseudoAwareNextSibling(node))
    212         return nextNode;
    213     for (Node* parentNode = parent(node); parentNode; parentNode = parent(parentNode)) {
    214         if (parentNode == stayWithin)
    215             return 0;
    216         if (Node* nextNode = pseudoAwareNextSibling(parentNode))
    217             return nextNode;
    218     }
    219     return 0;
    220 }
    221 
    222 RenderObject* nextSiblingRenderer(const Node* node)
    223 {
    224     for (Node* sibling = NodeRenderingTraversal::nextSibling(node); sibling; sibling = NodeRenderingTraversal::nextSibling(sibling)) {
    225         RenderObject* renderer = sibling->renderer();
    226         if (renderer && !isRendererReparented(renderer))
    227             return renderer;
    228     }
    229     return 0;
    230 }
    231 
    232 RenderObject* previousSiblingRenderer(const Node* node)
    233 {
    234     for (Node* sibling = NodeRenderingTraversal::previousSibling(node); sibling; sibling = NodeRenderingTraversal::previousSibling(sibling)) {
    235         RenderObject* renderer = sibling->renderer();
    236         if (renderer && !isRendererReparented(renderer))
    237             return renderer;
    238     }
    239     return 0;
    240 }
    241 
    242 RenderObject* nextInTopLayer(const Element* element)
    243 {
    244     if (!element->isInTopLayer())
    245         return 0;
    246     const WillBeHeapVector<RefPtrWillBeMember<Element> >& topLayerElements = element->document().topLayerElements();
    247     size_t position = topLayerElements.find(element);
    248     ASSERT(position != kNotFound);
    249     for (size_t i = position + 1; i < topLayerElements.size(); ++i) {
    250         if (RenderObject* renderer = topLayerElements[i]->renderer())
    251             return renderer;
    252     }
    253     return 0;
    254 }
    255 
    256 }
    257 
    258 } // namespace
    259