tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

NodeIterator.cpp (5440B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      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/. */
      6 
      7 /*
      8 * Implementation of DOM Traversal's NodeIterator
      9 */
     10 
     11 #include "mozilla/dom/NodeIterator.h"
     12 
     13 #include "mozilla/dom/Document.h"
     14 #include "mozilla/dom/NodeFilterBinding.h"
     15 #include "mozilla/dom/NodeIteratorBinding.h"
     16 #include "nsCOMPtr.h"
     17 #include "nsContentUtils.h"
     18 #include "nsError.h"
     19 #include "nsIContent.h"
     20 
     21 namespace mozilla::dom {
     22 
     23 /*
     24 * NodePointer implementation
     25 */
     26 NodeIterator::NodePointer::NodePointer(nsINode* aNode, bool aBeforeNode)
     27    : mNode(aNode), mBeforeNode(aBeforeNode) {}
     28 
     29 bool NodeIterator::NodePointer::MoveToNext(nsINode* aRoot) {
     30  if (!mNode) return false;
     31 
     32  if (mBeforeNode) {
     33    mBeforeNode = false;
     34    return true;
     35  }
     36 
     37  nsINode* child = mNode->GetFirstChild();
     38  if (child) {
     39    mNode = child;
     40    return true;
     41  }
     42 
     43  return MoveForward(aRoot, mNode);
     44 }
     45 
     46 bool NodeIterator::NodePointer::MoveToPrevious(nsINode* aRoot) {
     47  if (!mNode) return false;
     48 
     49  if (!mBeforeNode) {
     50    mBeforeNode = true;
     51    return true;
     52  }
     53 
     54  if (mNode == aRoot) {
     55    return false;
     56  }
     57 
     58  MoveBackward(mNode->GetParentNode(), mNode->GetPreviousSibling());
     59 
     60  return true;
     61 }
     62 
     63 void NodeIterator::NodePointer::AdjustForRemoval(nsINode* aRoot,
     64                                                 nsINode* aContainer,
     65                                                 nsIContent* aChild) {
     66  // If mNode is null or the root there is nothing to do.
     67  if (!mNode || mNode == aRoot) {
     68    return;
     69  }
     70 
     71  // check if ancestor was removed
     72  if (!mNode->IsInclusiveDescendantOf(aChild)) {
     73    return;
     74  }
     75 
     76  if (mBeforeNode) {
     77    // Try the next sibling
     78    nsINode* nextSibling = aChild->GetNextSibling();
     79    if (nextSibling) {
     80      mNode = nextSibling;
     81      return;
     82    }
     83 
     84    // Next try siblings of ancestors
     85    if (MoveForward(aRoot, aContainer)) {
     86      return;
     87    }
     88 
     89    // No suitable node was found so try going backwards
     90    mBeforeNode = false;
     91  }
     92 
     93  MoveBackward(aContainer, aChild->GetPreviousSibling());
     94 }
     95 
     96 bool NodeIterator::NodePointer::MoveForward(nsINode* aRoot, nsINode* aNode) {
     97  while (1) {
     98    if (aNode == aRoot) break;
     99 
    100    nsINode* sibling = aNode->GetNextSibling();
    101    if (sibling) {
    102      mNode = sibling;
    103      return true;
    104    }
    105    aNode = aNode->GetParentNode();
    106  }
    107 
    108  return false;
    109 }
    110 
    111 void NodeIterator::NodePointer::MoveBackward(nsINode* aParent, nsINode* aNode) {
    112  if (aNode) {
    113    do {
    114      mNode = aNode;
    115      aNode = aNode->GetLastChild();
    116    } while (aNode);
    117  } else {
    118    mNode = aParent;
    119  }
    120 }
    121 
    122 /*
    123 * Factories, constructors and destructors
    124 */
    125 
    126 NodeIterator::NodeIterator(nsINode* aRoot, uint32_t aWhatToShow,
    127                           NodeFilter* aFilter)
    128    : nsTraversal(aRoot, aWhatToShow, aFilter), mPointer(mRoot, true) {
    129  aRoot->AddMutationObserver(this);
    130 }
    131 
    132 NodeIterator::~NodeIterator() {
    133  /* destructor code */
    134  if (mRoot) mRoot->RemoveMutationObserver(this);
    135 }
    136 
    137 /*
    138 * nsISupports and cycle collection stuff
    139 */
    140 
    141 NS_IMPL_CYCLE_COLLECTION_CLASS(NodeIterator)
    142 
    143 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(NodeIterator)
    144  if (tmp->mRoot) tmp->mRoot->RemoveMutationObserver(tmp);
    145  NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
    146  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilter)
    147 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    148 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NodeIterator)
    149  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
    150  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilter)
    151 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    152 
    153 // QueryInterface implementation for NodeIterator
    154 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NodeIterator)
    155  NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
    156  NS_INTERFACE_MAP_ENTRY(nsISupports)
    157 NS_INTERFACE_MAP_END
    158 
    159 NS_IMPL_CYCLE_COLLECTING_ADDREF(NodeIterator)
    160 NS_IMPL_CYCLE_COLLECTING_RELEASE(NodeIterator)
    161 
    162 already_AddRefed<nsINode> NodeIterator::NextOrPrevNode(
    163    NodePointer::MoveToMethodType aMove, ErrorResult& aResult) {
    164  if (mInAcceptNode) {
    165    aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    166    return nullptr;
    167  }
    168 
    169  mWorkingPointer = mPointer;
    170 
    171  struct AutoClear {
    172    NodePointer* mPtr;
    173    explicit AutoClear(NodePointer* ptr) : mPtr(ptr) {}
    174    ~AutoClear() { mPtr->Clear(); }
    175  } ac(&mWorkingPointer);
    176 
    177  while ((mWorkingPointer.*aMove)(mRoot)) {
    178    nsCOMPtr<nsINode> testNode;
    179    int16_t filtered = TestNode(mWorkingPointer.mNode, aResult, &testNode);
    180    if (aResult.Failed()) {
    181      return nullptr;
    182    }
    183 
    184    if (filtered == NodeFilter_Binding::FILTER_ACCEPT) {
    185      mPointer = mWorkingPointer;
    186      return testNode.forget();
    187    }
    188  }
    189 
    190  return nullptr;
    191 }
    192 
    193 void NodeIterator::Detach() {
    194  if (mRoot) {
    195    mRoot->OwnerDoc()->WarnOnceAbout(DeprecatedOperations::eNodeIteratorDetach);
    196  }
    197 }
    198 
    199 /*
    200 * nsIMutationObserver interface
    201 */
    202 
    203 void NodeIterator::ContentWillBeRemoved(nsIContent* aChild,
    204                                        const ContentRemoveInfo&) {
    205  nsINode* container = aChild->GetParentNode();
    206  mPointer.AdjustForRemoval(mRoot, container, aChild);
    207  mWorkingPointer.AdjustForRemoval(mRoot, container, aChild);
    208 }
    209 
    210 bool NodeIterator::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto,
    211                              JS::MutableHandle<JSObject*> aReflector) {
    212  return NodeIterator_Binding::Wrap(cx, this, aGivenProto, aReflector);
    213 }
    214 
    215 }  // namespace mozilla::dom