Bug 1665252 - remove allowpaymentrequest attribute from HTMLIFrameElement r=dom-worke...
[gecko.git] / dom / base / NodeIterator.cpp
blobe7f2a0c4cfb198f27ff18e91b54a37f03a216b60
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 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 NodeIterator
9 */
11 #include "mozilla/dom/NodeIterator.h"
13 #include "nsError.h"
15 #include "nsIContent.h"
16 #include "mozilla/dom/Document.h"
17 #include "nsContentUtils.h"
18 #include "nsCOMPtr.h"
19 #include "mozilla/dom/NodeFilterBinding.h"
20 #include "mozilla/dom/NodeIteratorBinding.h"
22 namespace mozilla {
23 namespace dom {
26 * NodePointer implementation
28 NodeIterator::NodePointer::NodePointer(nsINode* aNode, bool aBeforeNode)
29 : mNode(aNode), mBeforeNode(aBeforeNode) {}
31 bool NodeIterator::NodePointer::MoveToNext(nsINode* aRoot) {
32 if (!mNode) return false;
34 if (mBeforeNode) {
35 mBeforeNode = false;
36 return true;
39 nsINode* child = mNode->GetFirstChild();
40 if (child) {
41 mNode = child;
42 return true;
45 return MoveForward(aRoot, mNode);
48 bool NodeIterator::NodePointer::MoveToPrevious(nsINode* aRoot) {
49 if (!mNode) return false;
51 if (!mBeforeNode) {
52 mBeforeNode = true;
53 return true;
56 if (mNode == aRoot) return false;
58 MoveBackward(mNode->GetParentNode(), mNode->GetPreviousSibling());
60 return true;
63 void NodeIterator::NodePointer::AdjustAfterRemoval(
64 nsINode* aRoot, nsINode* aContainer, nsIContent* aChild,
65 nsIContent* aPreviousSibling) {
66 // If mNode is null or the root there is nothing to do.
67 if (!mNode || mNode == aRoot) return;
69 // check if ancestor was removed
70 if (!mNode->IsInclusiveDescendantOf(aChild)) return;
72 if (mBeforeNode) {
73 // Try the next sibling
74 nsINode* nextSibling = aPreviousSibling ? aPreviousSibling->GetNextSibling()
75 : aContainer->GetFirstChild();
77 if (nextSibling) {
78 mNode = nextSibling;
79 return;
82 // Next try siblings of ancestors
83 if (MoveForward(aRoot, aContainer)) return;
85 // No suitable node was found so try going backwards
86 mBeforeNode = false;
89 MoveBackward(aContainer, aPreviousSibling);
92 bool NodeIterator::NodePointer::MoveForward(nsINode* aRoot, nsINode* aNode) {
93 while (1) {
94 if (aNode == aRoot) break;
96 nsINode* sibling = aNode->GetNextSibling();
97 if (sibling) {
98 mNode = sibling;
99 return true;
101 aNode = aNode->GetParentNode();
104 return false;
107 void NodeIterator::NodePointer::MoveBackward(nsINode* aParent, nsINode* aNode) {
108 if (aNode) {
109 do {
110 mNode = aNode;
111 aNode = aNode->GetLastChild();
112 } while (aNode);
113 } else {
114 mNode = aParent;
119 * Factories, constructors and destructors
122 NodeIterator::NodeIterator(nsINode* aRoot, uint32_t aWhatToShow,
123 NodeFilter* aFilter)
124 : nsTraversal(aRoot, aWhatToShow, aFilter), mPointer(mRoot, true) {
125 aRoot->AddMutationObserver(this);
128 NodeIterator::~NodeIterator() {
129 /* destructor code */
130 if (mRoot) mRoot->RemoveMutationObserver(this);
134 * nsISupports and cycle collection stuff
137 NS_IMPL_CYCLE_COLLECTION_CLASS(NodeIterator)
139 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(NodeIterator)
140 if (tmp->mRoot) tmp->mRoot->RemoveMutationObserver(tmp);
141 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
142 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilter)
143 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
144 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(NodeIterator)
145 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
146 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilter)
147 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
149 // QueryInterface implementation for NodeIterator
150 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NodeIterator)
151 NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
152 NS_INTERFACE_MAP_ENTRY(nsISupports)
153 NS_INTERFACE_MAP_END
155 NS_IMPL_CYCLE_COLLECTING_ADDREF(NodeIterator)
156 NS_IMPL_CYCLE_COLLECTING_RELEASE(NodeIterator)
158 already_AddRefed<nsINode> NodeIterator::NextOrPrevNode(
159 NodePointer::MoveToMethodType aMove, ErrorResult& aResult) {
160 if (mInAcceptNode) {
161 aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
162 return nullptr;
165 mWorkingPointer = mPointer;
167 struct AutoClear {
168 NodePointer* mPtr;
169 explicit AutoClear(NodePointer* ptr) : mPtr(ptr) {}
170 ~AutoClear() { mPtr->Clear(); }
171 } ac(&mWorkingPointer);
173 while ((mWorkingPointer.*aMove)(mRoot)) {
174 nsCOMPtr<nsINode> testNode;
175 int16_t filtered = TestNode(mWorkingPointer.mNode, aResult, &testNode);
176 if (aResult.Failed()) {
177 return nullptr;
180 if (filtered == NodeFilter_Binding::FILTER_ACCEPT) {
181 mPointer = mWorkingPointer;
182 return testNode.forget();
186 return nullptr;
189 void NodeIterator::Detach() {
190 if (mRoot) {
191 mRoot->OwnerDoc()->WarnOnceAbout(Document::eNodeIteratorDetach);
196 * nsIMutationObserver interface
199 void NodeIterator::ContentRemoved(nsIContent* aChild,
200 nsIContent* aPreviousSibling) {
201 nsINode* container = aChild->GetParentNode();
203 mPointer.AdjustAfterRemoval(mRoot, container, aChild, aPreviousSibling);
204 mWorkingPointer.AdjustAfterRemoval(mRoot, container, aChild,
205 aPreviousSibling);
208 bool NodeIterator::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto,
209 JS::MutableHandle<JSObject*> aReflector) {
210 return NodeIterator_Binding::Wrap(cx, this, aGivenProto, aReflector);
213 } // namespace dom
214 } // namespace mozilla