content/base/src/NodeIterator.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * Implementation of DOM Traversal's nsIDOMNodeIterator
     9  */
    11 #include "mozilla/dom/NodeIterator.h"
    13 #include "nsIDOMNode.h"
    14 #include "nsError.h"
    16 #include "nsIContent.h"
    17 #include "nsIDocument.h"
    18 #include "nsContentUtils.h"
    19 #include "nsCOMPtr.h"
    20 #include "mozilla/dom/NodeIteratorBinding.h"
    22 namespace mozilla {
    23 namespace dom {
    25 /*
    26  * NodePointer implementation
    27  */
    28 NodeIterator::NodePointer::NodePointer(nsINode *aNode, bool aBeforeNode) :
    29     mNode(aNode),
    30     mBeforeNode(aBeforeNode)
    31 {
    32 }
    34 bool NodeIterator::NodePointer::MoveToNext(nsINode *aRoot)
    35 {
    36     if (!mNode)
    37       return false;
    39     if (mBeforeNode) {
    40         mBeforeNode = false;
    41         return true;
    42     }
    44     nsINode* child = mNode->GetFirstChild();
    45     if (child) {
    46         mNode = child;
    47         return true;
    48     }
    50     return MoveForward(aRoot, mNode);
    51 }
    53 bool NodeIterator::NodePointer::MoveToPrevious(nsINode *aRoot)
    54 {
    55     if (!mNode)
    56       return false;
    58     if (!mBeforeNode) {
    59         mBeforeNode = true;
    60         return true;
    61     }
    63     if (mNode == aRoot)
    64         return false;
    66     MoveBackward(mNode->GetParentNode(), mNode->GetPreviousSibling());
    68     return true;
    69 }
    71 void NodeIterator::NodePointer::AdjustAfterRemoval(nsINode *aRoot,
    72                                                    nsINode *aContainer,
    73                                                    nsIContent *aChild,
    74                                                    nsIContent *aPreviousSibling)
    75 {
    76     // If mNode is null or the root there is nothing to do.
    77     if (!mNode || mNode == aRoot)
    78         return;
    80     // check if ancestor was removed
    81     if (!nsContentUtils::ContentIsDescendantOf(mNode, aChild))
    82         return;
    84     if (mBeforeNode) {
    86         // Try the next sibling
    87         nsINode *nextSibling = aPreviousSibling ? aPreviousSibling->GetNextSibling()
    88                                                 : aContainer->GetFirstChild();
    90         if (nextSibling) {
    91             mNode = nextSibling;
    92             return;
    93         }
    95         // Next try siblings of ancestors
    96         if (MoveForward(aRoot, aContainer))
    97             return;
    99         // No suitable node was found so try going backwards
   100         mBeforeNode = false;
   101     }
   103     MoveBackward(aContainer, aPreviousSibling);
   104 }
   106 bool NodeIterator::NodePointer::MoveForward(nsINode *aRoot, nsINode *aNode)
   107 {
   108     while (1) {
   109         if (aNode == aRoot)
   110             break;
   112         nsINode *sibling = aNode->GetNextSibling();
   113         if (sibling) {
   114             mNode = sibling;
   115             return true;
   116         }
   117         aNode = aNode->GetParentNode();
   118     }
   120     return false;
   121 }
   123 void NodeIterator::NodePointer::MoveBackward(nsINode *aParent, nsINode *aNode)
   124 {
   125     if (aNode) {
   126         do {
   127             mNode = aNode;
   128             aNode = aNode->GetLastChild();
   129         } while (aNode);
   130     } else {
   131         mNode = aParent;
   132     }
   133 }
   135 /*
   136  * Factories, constructors and destructors
   137  */
   139 NodeIterator::NodeIterator(nsINode *aRoot,
   140                            uint32_t aWhatToShow,
   141                            const NodeFilterHolder &aFilter) :
   142     nsTraversal(aRoot, aWhatToShow, aFilter),
   143     mPointer(mRoot, true)
   144 {
   145     aRoot->AddMutationObserver(this);
   146 }
   148 NodeIterator::~NodeIterator()
   149 {
   150     /* destructor code */
   151     if (mRoot)
   152         mRoot->RemoveMutationObserver(this);
   153 }
   155 /*
   156  * nsISupports and cycle collection stuff
   157  */
   159 NS_IMPL_CYCLE_COLLECTION_CLASS(NodeIterator)
   161 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(NodeIterator)
   162     if (tmp->mRoot)
   163         tmp->mRoot->RemoveMutationObserver(tmp);
   164   NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
   165   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilter)
   166 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   167 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NodeIterator)
   168   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
   169   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilter)
   170 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   172 // QueryInterface implementation for NodeIterator
   173 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NodeIterator)
   174     NS_INTERFACE_MAP_ENTRY(nsIDOMNodeIterator)
   175     NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   176     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMNodeIterator)
   177 NS_INTERFACE_MAP_END
   179 NS_IMPL_CYCLE_COLLECTING_ADDREF(NodeIterator)
   180 NS_IMPL_CYCLE_COLLECTING_RELEASE(NodeIterator)
   182 /* readonly attribute nsIDOMNode root; */
   183 NS_IMETHODIMP NodeIterator::GetRoot(nsIDOMNode * *aRoot)
   184 {
   185     NS_ADDREF(*aRoot = Root()->AsDOMNode());
   186     return NS_OK;
   187 }
   189 /* readonly attribute unsigned long whatToShow; */
   190 NS_IMETHODIMP NodeIterator::GetWhatToShow(uint32_t *aWhatToShow)
   191 {
   192     *aWhatToShow = WhatToShow();
   193     return NS_OK;
   194 }
   196 /* readonly attribute nsIDOMNodeFilter filter; */
   197 NS_IMETHODIMP NodeIterator::GetFilter(nsIDOMNodeFilter **aFilter)
   198 {
   199     NS_ENSURE_ARG_POINTER(aFilter);
   201     *aFilter = mFilter.ToXPCOMCallback().take();
   203     return NS_OK;
   204 }
   206 /* nsIDOMNode nextNode ()  raises (DOMException); */
   207 NS_IMETHODIMP NodeIterator::NextNode(nsIDOMNode **_retval)
   208 {
   209     return ImplNodeGetter(&NodeIterator::NextNode, _retval);
   210 }
   212 /* nsIDOMNode previousNode ()  raises (DOMException); */
   213 NS_IMETHODIMP NodeIterator::PreviousNode(nsIDOMNode **_retval)
   214 {
   215     return ImplNodeGetter(&NodeIterator::PreviousNode, _retval);
   216 }
   218 already_AddRefed<nsINode>
   219 NodeIterator::NextOrPrevNode(NodePointer::MoveToMethodType aMove,
   220                              ErrorResult& aResult)
   221 {
   222     if (mInAcceptNode) {
   223         aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
   224         return nullptr;
   225     }
   227     mWorkingPointer = mPointer;
   229     struct AutoClear {
   230         NodePointer* mPtr;
   231         AutoClear(NodePointer* ptr) : mPtr(ptr) {}
   232        ~AutoClear() { mPtr->Clear(); }
   233     } ac(&mWorkingPointer);
   235     while ((mWorkingPointer.*aMove)(mRoot)) {
   236         nsCOMPtr<nsINode> testNode = mWorkingPointer.mNode;
   237         int16_t filtered = TestNode(testNode, aResult);
   238         if (aResult.Failed()) {
   239             return nullptr;
   240         }
   242         if (filtered == nsIDOMNodeFilter::FILTER_ACCEPT) {
   243             mPointer = mWorkingPointer;
   244             return testNode.forget();
   245         }
   246     }
   248     return nullptr;
   249 }
   251 /* void detach (); */
   252 NS_IMETHODIMP NodeIterator::Detach(void)
   253 {
   254     if (mRoot) {
   255         mRoot->OwnerDoc()->WarnOnceAbout(nsIDocument::eNodeIteratorDetach);
   256     }
   257     return NS_OK;
   258 }
   260 /* readonly attribute nsIDOMNode referenceNode; */
   261 NS_IMETHODIMP NodeIterator::GetReferenceNode(nsIDOMNode * *aRefNode)
   262 {
   263     nsCOMPtr<nsIDOMNode> node(do_QueryInterface(GetReferenceNode()));
   264     node.forget(aRefNode);
   265     return NS_OK;
   266 }
   268 /* readonly attribute boolean pointerBeforeReferenceNode; */
   269 NS_IMETHODIMP NodeIterator::GetPointerBeforeReferenceNode(bool *aBeforeNode)
   270 {
   271     *aBeforeNode = PointerBeforeReferenceNode();
   272     return NS_OK;
   273 }
   275 /*
   276  * nsIMutationObserver interface
   277  */
   279 void NodeIterator::ContentRemoved(nsIDocument *aDocument,
   280                                   nsIContent *aContainer,
   281                                   nsIContent *aChild,
   282                                   int32_t aIndexInContainer,
   283                                   nsIContent *aPreviousSibling)
   284 {
   285     nsINode *container = NODE_FROM(aContainer, aDocument);
   287     mPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling);
   288     mWorkingPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling);
   289 }
   291 JSObject*
   292 NodeIterator::WrapObject(JSContext *cx)
   293 {
   294     return NodeIteratorBinding::Wrap(cx, this);
   295 }
   297 } // namespace dom
   298 } // namespace mozilla

mercurial