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