1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/mozalloc.h"
7 #include "nsComponentManagerUtils.h"
8 #include "nsContentUtils.h"
11 #include "nsFilteredContentIterator.h"
13 #include "nsIContent.h"
14 #include "nsIContentIterator.h"
15 #include "nsIDOMNode.h"
17 #include "nsISupportsBase.h"
18 #include "nsISupportsUtils.h"
19 #include "nsITextServicesFilter.h"
22 //------------------------------------------------------------
23 nsFilteredContentIterator::nsFilteredContentIterator(nsITextServicesFilter
* aFilter
) :
27 mDirection(eDirNotSet
)
29 mIterator
= do_CreateInstance("@mozilla.org/content/post-content-iterator;1");
30 mPreIterator
= do_CreateInstance("@mozilla.org/content/pre-content-iterator;1");
33 //------------------------------------------------------------
34 nsFilteredContentIterator::~nsFilteredContentIterator()
38 //------------------------------------------------------------
39 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFilteredContentIterator
)
40 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFilteredContentIterator
)
42 NS_INTERFACE_MAP_BEGIN(nsFilteredContentIterator
)
43 NS_INTERFACE_MAP_ENTRY(nsIContentIterator
)
44 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIContentIterator
)
45 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsFilteredContentIterator
)
48 NS_IMPL_CYCLE_COLLECTION(nsFilteredContentIterator
,
55 //------------------------------------------------------------
57 nsFilteredContentIterator::Init(nsINode
* aRoot
)
59 NS_ENSURE_ARG_POINTER(aRoot
);
60 NS_ENSURE_TRUE(mPreIterator
, NS_ERROR_FAILURE
);
61 NS_ENSURE_TRUE(mIterator
, NS_ERROR_FAILURE
);
62 mIsOutOfRange
= false;
63 mDirection
= eForward
;
64 mCurrentIterator
= mPreIterator
;
66 mRange
= new nsRange(aRoot
);
67 nsCOMPtr
<nsIDOMNode
> domNode(do_QueryInterface(aRoot
));
69 mRange
->SelectNode(domNode
);
72 nsresult rv
= mPreIterator
->Init(mRange
);
73 NS_ENSURE_SUCCESS(rv
, rv
);
74 return mIterator
->Init(mRange
);
77 //------------------------------------------------------------
79 nsFilteredContentIterator::Init(nsIDOMRange
* aRange
)
81 NS_ENSURE_TRUE(mPreIterator
, NS_ERROR_FAILURE
);
82 NS_ENSURE_TRUE(mIterator
, NS_ERROR_FAILURE
);
83 NS_ENSURE_ARG_POINTER(aRange
);
84 mIsOutOfRange
= false;
85 mDirection
= eForward
;
86 mCurrentIterator
= mPreIterator
;
88 mRange
= static_cast<nsRange
*>(aRange
)->CloneRange();
90 nsresult rv
= mPreIterator
->Init(mRange
);
91 NS_ENSURE_SUCCESS(rv
, rv
);
92 return mIterator
->Init(mRange
);
95 //------------------------------------------------------------
97 nsFilteredContentIterator::SwitchDirections(bool aChangeToForward
)
99 nsINode
*node
= mCurrentIterator
->GetCurrentNode();
101 if (aChangeToForward
) {
102 mCurrentIterator
= mPreIterator
;
103 mDirection
= eForward
;
105 mCurrentIterator
= mIterator
;
106 mDirection
= eBackward
;
110 nsresult rv
= mCurrentIterator
->PositionAt(node
);
112 mIsOutOfRange
= true;
119 //------------------------------------------------------------
121 nsFilteredContentIterator::First()
123 if (!mCurrentIterator
) {
124 NS_ERROR("Missing iterator!");
129 // If we are switching directions then
130 // we need to switch how we process the nodes
131 if (mDirection
!= eForward
) {
132 mCurrentIterator
= mPreIterator
;
133 mDirection
= eForward
;
134 mIsOutOfRange
= false;
137 mCurrentIterator
->First();
139 if (mCurrentIterator
->IsDone()) {
143 nsINode
*currentNode
= mCurrentIterator
->GetCurrentNode();
144 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(currentNode
));
147 CheckAdvNode(node
, didCross
, eForward
);
150 //------------------------------------------------------------
152 nsFilteredContentIterator::Last()
154 if (!mCurrentIterator
) {
155 NS_ERROR("Missing iterator!");
160 // If we are switching directions then
161 // we need to switch how we process the nodes
162 if (mDirection
!= eBackward
) {
163 mCurrentIterator
= mIterator
;
164 mDirection
= eBackward
;
165 mIsOutOfRange
= false;
168 mCurrentIterator
->Last();
170 if (mCurrentIterator
->IsDone()) {
174 nsINode
*currentNode
= mCurrentIterator
->GetCurrentNode();
175 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(currentNode
));
178 CheckAdvNode(node
, didCross
, eBackward
);
181 ///////////////////////////////////////////////////////////////////////////
182 // ContentToParentOffset: returns the content node's parent and offset.
185 ContentToParentOffset(nsIContent
*aContent
, nsIDOMNode
**aParent
,
188 if (!aParent
|| !aOffset
)
197 nsIContent
* parent
= aContent
->GetParent();
202 *aOffset
= parent
->IndexOf(aContent
);
204 CallQueryInterface(parent
, aParent
);
207 ///////////////////////////////////////////////////////////////////////////
208 // ContentIsInTraversalRange: returns true if content is visited during
209 // the traversal of the range in the specified mode.
212 ContentIsInTraversalRange(nsIContent
*aContent
, bool aIsPreMode
,
213 nsIDOMNode
*aStartNode
, int32_t aStartOffset
,
214 nsIDOMNode
*aEndNode
, int32_t aEndOffset
)
216 NS_ENSURE_TRUE(aStartNode
&& aEndNode
&& aContent
, false);
218 nsCOMPtr
<nsIDOMNode
> parentNode
;
221 ContentToParentOffset(aContent
, getter_AddRefs(parentNode
), &indx
);
223 NS_ENSURE_TRUE(parentNode
, false);
228 int32_t startRes
= nsContentUtils::ComparePoints(aStartNode
, aStartOffset
,
230 int32_t endRes
= nsContentUtils::ComparePoints(aEndNode
, aEndOffset
,
232 return (startRes
<= 0) && (endRes
>= 0);
236 ContentIsInTraversalRange(nsRange
* aRange
, nsIDOMNode
* aNextNode
, bool aIsPreMode
)
238 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aNextNode
));
239 NS_ENSURE_TRUE(content
&& aRange
, false);
241 nsCOMPtr
<nsIDOMNode
> sNode
;
242 nsCOMPtr
<nsIDOMNode
> eNode
;
245 aRange
->GetStartContainer(getter_AddRefs(sNode
));
246 aRange
->GetStartOffset(&sOffset
);
247 aRange
->GetEndContainer(getter_AddRefs(eNode
));
248 aRange
->GetEndOffset(&eOffset
);
249 return ContentIsInTraversalRange(content
, aIsPreMode
, sNode
, sOffset
, eNode
, eOffset
);
252 //------------------------------------------------------------
253 // Helper function to advance to the next or previous node
255 nsFilteredContentIterator::AdvanceNode(nsIDOMNode
* aNode
, nsIDOMNode
*& aNewNode
, eDirectionType aDir
)
257 nsCOMPtr
<nsIDOMNode
> nextNode
;
258 if (aDir
== eForward
) {
259 aNode
->GetNextSibling(getter_AddRefs(nextNode
));
261 aNode
->GetPreviousSibling(getter_AddRefs(nextNode
));
265 // If we got here, that means we found the nxt/prv node
266 // make sure it is in our DOMRange
267 bool intersects
= ContentIsInTraversalRange(mRange
, nextNode
, aDir
== eForward
);
274 // The next node was null so we need to walk up the parent(s)
275 nsCOMPtr
<nsIDOMNode
> parent
;
276 aNode
->GetParentNode(getter_AddRefs(parent
));
277 NS_ASSERTION(parent
, "parent can't be nullptr");
279 // Make sure the parent is in the DOMRange before going further
280 bool intersects
= ContentIsInTraversalRange(mRange
, nextNode
, aDir
== eForward
);
282 // Now find the nxt/prv node after/before this node
283 nsresult rv
= AdvanceNode(parent
, aNewNode
, aDir
);
284 if (NS_SUCCEEDED(rv
) && aNewNode
) {
290 // if we get here it pretty much means
291 // we went out of the DOM Range
292 mIsOutOfRange
= true;
294 return NS_ERROR_FAILURE
;
297 //------------------------------------------------------------
298 // Helper function to see if the next/prev node should be skipped
300 nsFilteredContentIterator::CheckAdvNode(nsIDOMNode
* aNode
, bool& aDidSkip
, eDirectionType aDir
)
303 mIsOutOfRange
= false;
305 if (aNode
&& mFilter
) {
306 nsCOMPtr
<nsIDOMNode
> currentNode
= aNode
;
309 nsresult rv
= mFilter
->Skip(aNode
, &skipIt
);
310 if (NS_SUCCEEDED(rv
) && skipIt
) {
312 // Get the next/prev node and then
313 // see if we should skip that
314 nsCOMPtr
<nsIDOMNode
> advNode
;
315 rv
= AdvanceNode(aNode
, *getter_AddRefs(advNode
), aDir
);
316 if (NS_SUCCEEDED(rv
) && advNode
) {
319 return; // fell out of range
322 if (aNode
!= currentNode
) {
323 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aNode
));
324 mCurrentIterator
->PositionAt(content
);
326 return; // found something
333 nsFilteredContentIterator::Next()
335 if (mIsOutOfRange
|| !mCurrentIterator
) {
336 NS_ASSERTION(mCurrentIterator
, "Missing iterator!");
341 // If we are switching directions then
342 // we need to switch how we process the nodes
343 if (mDirection
!= eForward
) {
344 nsresult rv
= SwitchDirections(true);
350 mCurrentIterator
->Next();
352 if (mCurrentIterator
->IsDone()) {
356 // If we can't get the current node then
357 // don't check to see if we can skip it
358 nsINode
*currentNode
= mCurrentIterator
->GetCurrentNode();
360 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(currentNode
));
361 CheckAdvNode(node
, mDidSkip
, eForward
);
365 nsFilteredContentIterator::Prev()
367 if (mIsOutOfRange
|| !mCurrentIterator
) {
368 NS_ASSERTION(mCurrentIterator
, "Missing iterator!");
373 // If we are switching directions then
374 // we need to switch how we process the nodes
375 if (mDirection
!= eBackward
) {
376 nsresult rv
= SwitchDirections(false);
382 mCurrentIterator
->Prev();
384 if (mCurrentIterator
->IsDone()) {
388 // If we can't get the current node then
389 // don't check to see if we can skip it
390 nsINode
*currentNode
= mCurrentIterator
->GetCurrentNode();
392 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(currentNode
));
393 CheckAdvNode(node
, mDidSkip
, eBackward
);
397 nsFilteredContentIterator::GetCurrentNode()
399 if (mIsOutOfRange
|| !mCurrentIterator
) {
403 return mCurrentIterator
->GetCurrentNode();
407 nsFilteredContentIterator::IsDone()
409 if (mIsOutOfRange
|| !mCurrentIterator
) {
413 return mCurrentIterator
->IsDone();
417 nsFilteredContentIterator::PositionAt(nsINode
* aCurNode
)
419 NS_ENSURE_TRUE(mCurrentIterator
, NS_ERROR_FAILURE
);
420 mIsOutOfRange
= false;
421 return mCurrentIterator
->PositionAt(aCurNode
);