WebCore/dom/NodeIterator.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
       
     3  * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
       
     4  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
       
     5  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
       
     6  * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
       
     7  *
       
     8  * This library is free software; you can redistribute it and/or
       
     9  * modify it under the terms of the GNU Library General Public
       
    10  * License as published by the Free Software Foundation; either
       
    11  * version 2 of the License, or (at your option) any later version.
       
    12  *
       
    13  * This library is distributed in the hope that it will be useful,
       
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16  * Library General Public License for more details.
       
    17  *
       
    18  * You should have received a copy of the GNU Library General Public License
       
    19  * along with this library; see the file COPYING.LIB.  If not, write to
       
    20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    21  * Boston, MA 02110-1301, USA.
       
    22  *
       
    23  */
       
    24 
       
    25 #include "config.h"
       
    26 #include "NodeIterator.h"
       
    27 
       
    28 #include "Document.h"
       
    29 #include "ExceptionCode.h"
       
    30 #include "NodeFilter.h"
       
    31 #include "ScriptState.h"
       
    32 
       
    33 namespace WebCore {
       
    34 
       
    35 NodeIterator::NodePointer::NodePointer()
       
    36 {
       
    37 }
       
    38 
       
    39 NodeIterator::NodePointer::NodePointer(PassRefPtr<Node> n, bool b)
       
    40     : node(n)
       
    41     , isPointerBeforeNode(b)
       
    42 {
       
    43 }
       
    44 
       
    45 void NodeIterator::NodePointer::clear()
       
    46 {
       
    47     node.clear();
       
    48 }
       
    49 
       
    50 bool NodeIterator::NodePointer::moveToNext(Node* root)
       
    51 {
       
    52     if (!node)
       
    53         return false;
       
    54     if (isPointerBeforeNode) {
       
    55         isPointerBeforeNode = false;
       
    56         return true;
       
    57     }
       
    58     node = node->traverseNextNode(root);
       
    59     return node;
       
    60 }
       
    61 
       
    62 bool NodeIterator::NodePointer::moveToPrevious(Node* root)
       
    63 {
       
    64     if (!node)
       
    65         return false;
       
    66     if (!isPointerBeforeNode) {
       
    67         isPointerBeforeNode = true;
       
    68         return true;
       
    69     }
       
    70     node = node->traversePreviousNode(root);
       
    71     return node;
       
    72 }
       
    73 
       
    74 NodeIterator::NodeIterator(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
       
    75     : Traversal(rootNode, whatToShow, filter, expandEntityReferences)
       
    76     , m_referenceNode(root(), true)
       
    77     , m_detached(false)
       
    78 {
       
    79     root()->document()->attachNodeIterator(this);
       
    80 }
       
    81 
       
    82 NodeIterator::~NodeIterator()
       
    83 {
       
    84     root()->document()->detachNodeIterator(this);
       
    85 }
       
    86 
       
    87 PassRefPtr<Node> NodeIterator::nextNode(ScriptState* state, ExceptionCode& ec)
       
    88 {
       
    89     if (m_detached) {
       
    90         ec = INVALID_STATE_ERR;
       
    91         return 0;
       
    92     }
       
    93 
       
    94     RefPtr<Node> result;
       
    95 
       
    96     m_candidateNode = m_referenceNode;
       
    97     while (m_candidateNode.moveToNext(root())) {
       
    98         // NodeIterators treat the DOM tree as a flat list of nodes.
       
    99         // In other words, FILTER_REJECT does not pass over descendants
       
   100         // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
       
   101         RefPtr<Node> provisionalResult = m_candidateNode.node;
       
   102         bool nodeWasAccepted = acceptNode(state, provisionalResult.get()) == NodeFilter::FILTER_ACCEPT;
       
   103         if (state && state->hadException())
       
   104             break;
       
   105         if (nodeWasAccepted) {
       
   106             m_referenceNode = m_candidateNode;
       
   107             result = provisionalResult.release();
       
   108             break;
       
   109         }
       
   110     }
       
   111 
       
   112     m_candidateNode.clear();
       
   113     return result.release();
       
   114 }
       
   115 
       
   116 PassRefPtr<Node> NodeIterator::previousNode(ScriptState* state, ExceptionCode& ec)
       
   117 {
       
   118     if (m_detached) {
       
   119         ec = INVALID_STATE_ERR;
       
   120         return 0;
       
   121     }
       
   122 
       
   123     RefPtr<Node> result;
       
   124 
       
   125     m_candidateNode = m_referenceNode;
       
   126     while (m_candidateNode.moveToPrevious(root())) {
       
   127         // NodeIterators treat the DOM tree as a flat list of nodes.
       
   128         // In other words, FILTER_REJECT does not pass over descendants
       
   129         // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
       
   130         RefPtr<Node> provisionalResult = m_candidateNode.node;
       
   131         bool nodeWasAccepted = acceptNode(state, provisionalResult.get()) == NodeFilter::FILTER_ACCEPT;
       
   132         if (state && state->hadException())
       
   133             break;
       
   134         if (nodeWasAccepted) {
       
   135             m_referenceNode = m_candidateNode;
       
   136             result = provisionalResult.release();
       
   137             break;
       
   138         }
       
   139     }
       
   140 
       
   141     m_candidateNode.clear();
       
   142     return result.release();
       
   143 }
       
   144 
       
   145 void NodeIterator::detach()
       
   146 {
       
   147     root()->document()->detachNodeIterator(this);
       
   148     m_detached = true;
       
   149     m_referenceNode.node.clear();
       
   150 }
       
   151 
       
   152 void NodeIterator::nodeWillBeRemoved(Node* removedNode)
       
   153 {
       
   154     updateForNodeRemoval(removedNode, m_candidateNode);
       
   155     updateForNodeRemoval(removedNode, m_referenceNode);
       
   156 }
       
   157 
       
   158 void NodeIterator::updateForNodeRemoval(Node* removedNode, NodePointer& referenceNode) const
       
   159 {
       
   160     ASSERT(!m_detached);
       
   161     ASSERT(removedNode);
       
   162     ASSERT(root()->document() == removedNode->document());
       
   163 
       
   164     // Iterator is not affected if the removed node is the reference node and is the root.
       
   165     // or if removed node is not the reference node, or the ancestor of the reference node.
       
   166     if (!removedNode->isDescendantOf(root()))
       
   167         return;
       
   168     bool willRemoveReferenceNode = removedNode == referenceNode.node;
       
   169     bool willRemoveReferenceNodeAncestor = referenceNode.node && referenceNode.node->isDescendantOf(removedNode);
       
   170     if (!willRemoveReferenceNode && !willRemoveReferenceNodeAncestor)
       
   171         return;
       
   172 
       
   173     if (referenceNode.isPointerBeforeNode) {
       
   174         Node* node = removedNode->traverseNextNode(root());
       
   175         if (node) {
       
   176             // Move out from under the node being removed if the reference node is
       
   177             // a descendant of the node being removed.
       
   178             if (willRemoveReferenceNodeAncestor) {
       
   179                 while (node && node->isDescendantOf(removedNode))
       
   180                     node = node->traverseNextNode(root());
       
   181             }
       
   182             if (node)
       
   183                 referenceNode.node = node;
       
   184         } else {
       
   185             node = removedNode->traversePreviousNode(root());
       
   186             if (node) {
       
   187                 // Move out from under the node being removed if the reference node is
       
   188                 // a descendant of the node being removed.
       
   189                 if (willRemoveReferenceNodeAncestor) {
       
   190                     while (node && node->isDescendantOf(removedNode))
       
   191                         node = node->traversePreviousNode(root());
       
   192                 }
       
   193                 if (node) {
       
   194                     // Removing last node.
       
   195                     // Need to move the pointer after the node preceding the 
       
   196                     // new reference node.
       
   197                     referenceNode.node = node;
       
   198                     referenceNode.isPointerBeforeNode = false;
       
   199                 }
       
   200             }
       
   201         }
       
   202     } else {
       
   203         Node* node = removedNode->traversePreviousNode(root());
       
   204         if (node) {
       
   205             // Move out from under the node being removed if the reference node is
       
   206             // a descendant of the node being removed.
       
   207             if (willRemoveReferenceNodeAncestor) {
       
   208                 while (node && node->isDescendantOf(removedNode))
       
   209                     node = node->traversePreviousNode(root());
       
   210             }
       
   211             if (node)
       
   212                 referenceNode.node = node;
       
   213         } else {
       
   214             node = removedNode->traverseNextNode(root());
       
   215             // Move out from under the node being removed if the reference node is
       
   216             // a descendant of the node being removed.
       
   217             if (willRemoveReferenceNodeAncestor) {
       
   218                 while (node && node->isDescendantOf(removedNode))
       
   219                     node = node->traversePreviousNode(root());
       
   220             }
       
   221             if (node)
       
   222                 referenceNode.node = node;
       
   223         }
       
   224     }
       
   225 }
       
   226 
       
   227 
       
   228 } // namespace WebCore