1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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/. */
8 * Implementation of DOM Traversal's nsIDOMNodeIterator
11 #include "mozilla/dom/NodeIterator.h"
13 #include "nsIDOMNode.h"
16 #include "nsIContent.h"
17 #include "nsIDocument.h"
18 #include "nsContentUtils.h"
20 #include "mozilla/dom/NodeIteratorBinding.h"
26 * NodePointer implementation
28 NodeIterator::NodePointer::NodePointer(nsINode
*aNode
, bool aBeforeNode
) :
30 mBeforeNode(aBeforeNode
)
34 bool NodeIterator::NodePointer::MoveToNext(nsINode
*aRoot
)
44 nsINode
* child
= mNode
->GetFirstChild();
50 return MoveForward(aRoot
, mNode
);
53 bool NodeIterator::NodePointer::MoveToPrevious(nsINode
*aRoot
)
66 MoveBackward(mNode
->GetParentNode(), mNode
->GetPreviousSibling());
71 void NodeIterator::NodePointer::AdjustAfterRemoval(nsINode
*aRoot
,
74 nsIContent
*aPreviousSibling
)
76 // If mNode is null or the root there is nothing to do.
77 if (!mNode
|| mNode
== aRoot
)
80 // check if ancestor was removed
81 if (!nsContentUtils::ContentIsDescendantOf(mNode
, aChild
))
86 // Try the next sibling
87 nsINode
*nextSibling
= aPreviousSibling
? aPreviousSibling
->GetNextSibling()
88 : aContainer
->GetFirstChild();
95 // Next try siblings of ancestors
96 if (MoveForward(aRoot
, aContainer
))
99 // No suitable node was found so try going backwards
103 MoveBackward(aContainer
, aPreviousSibling
);
106 bool NodeIterator::NodePointer::MoveForward(nsINode
*aRoot
, nsINode
*aNode
)
112 nsINode
*sibling
= aNode
->GetNextSibling();
117 aNode
= aNode
->GetParentNode();
123 void NodeIterator::NodePointer::MoveBackward(nsINode
*aParent
, nsINode
*aNode
)
128 aNode
= aNode
->GetLastChild();
136 * Factories, constructors and destructors
139 NodeIterator::NodeIterator(nsINode
*aRoot
,
140 uint32_t aWhatToShow
,
141 const NodeFilterHolder
&aFilter
) :
142 nsTraversal(aRoot
, aWhatToShow
, aFilter
),
143 mPointer(mRoot
, true)
145 aRoot
->AddMutationObserver(this);
148 NodeIterator::~NodeIterator()
150 /* destructor code */
152 mRoot
->RemoveMutationObserver(this);
156 * nsISupports and cycle collection stuff
159 NS_IMPL_CYCLE_COLLECTION_CLASS(NodeIterator
)
161 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(NodeIterator
)
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
)
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
)
185 NS_ADDREF(*aRoot
= Root()->AsDOMNode());
189 /* readonly attribute unsigned long whatToShow; */
190 NS_IMETHODIMP
NodeIterator::GetWhatToShow(uint32_t *aWhatToShow
)
192 *aWhatToShow
= WhatToShow();
196 /* readonly attribute nsIDOMNodeFilter filter; */
197 NS_IMETHODIMP
NodeIterator::GetFilter(nsIDOMNodeFilter
**aFilter
)
199 NS_ENSURE_ARG_POINTER(aFilter
);
201 *aFilter
= mFilter
.ToXPCOMCallback().get();
206 /* nsIDOMNode nextNode () raises (DOMException); */
207 NS_IMETHODIMP
NodeIterator::NextNode(nsIDOMNode
**_retval
)
209 return ImplNodeGetter(&NodeIterator::NextNode
, _retval
);
212 /* nsIDOMNode previousNode () raises (DOMException); */
213 NS_IMETHODIMP
NodeIterator::PreviousNode(nsIDOMNode
**_retval
)
215 return ImplNodeGetter(&NodeIterator::PreviousNode
, _retval
);
218 already_AddRefed
<nsINode
>
219 NodeIterator::NextOrPrevNode(NodePointer::MoveToMethodType aMove
,
220 ErrorResult
& aResult
)
223 aResult
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
227 mWorkingPointer
= mPointer
;
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()) {
242 if (filtered
== nsIDOMNodeFilter::FILTER_ACCEPT
) {
243 mPointer
= mWorkingPointer
;
244 return testNode
.forget();
251 /* void detach (); */
252 NS_IMETHODIMP
NodeIterator::Detach(void)
255 mRoot
->OwnerDoc()->WarnOnceAbout(nsIDocument::eNodeIteratorDetach
);
260 /* readonly attribute nsIDOMNode referenceNode; */
261 NS_IMETHODIMP
NodeIterator::GetReferenceNode(nsIDOMNode
* *aRefNode
)
263 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(GetReferenceNode()));
264 node
.forget(aRefNode
);
268 /* readonly attribute boolean pointerBeforeReferenceNode; */
269 NS_IMETHODIMP
NodeIterator::GetPointerBeforeReferenceNode(bool *aBeforeNode
)
271 *aBeforeNode
= PointerBeforeReferenceNode();
276 * nsIMutationObserver interface
279 void NodeIterator::ContentRemoved(nsIDocument
*aDocument
,
280 nsIContent
*aContainer
,
282 int32_t aIndexInContainer
,
283 nsIContent
*aPreviousSibling
)
285 nsINode
*container
= NODE_FROM(aContainer
, aDocument
);
287 mPointer
.AdjustAfterRemoval(mRoot
, container
, aChild
, aPreviousSibling
);
288 mWorkingPointer
.AdjustAfterRemoval(mRoot
, container
, aChild
, aPreviousSibling
);
292 NodeIterator::WrapObject(JSContext
*cx
, JS::Handle
<JSObject
*> scope
)
294 return NodeIteratorBinding::Wrap(cx
, scope
, this);
298 } // namespace mozilla