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"
16 #include "nsIDOMRange.h"
18 #include "nsISupportsBase.h"
19 #include "nsISupportsUtils.h"
20 #include "nsITextServicesFilter.h"
23 //------------------------------------------------------------
24 nsFilteredContentIterator::nsFilteredContentIterator(nsITextServicesFilter
* aFilter
) :
28 mDirection(eDirNotSet
)
30 mIterator
= do_CreateInstance("@mozilla.org/content/post-content-iterator;1");
31 mPreIterator
= do_CreateInstance("@mozilla.org/content/pre-content-iterator;1");
34 //------------------------------------------------------------
35 nsFilteredContentIterator::~nsFilteredContentIterator()
39 //------------------------------------------------------------
40 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFilteredContentIterator
)
41 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFilteredContentIterator
)
43 NS_INTERFACE_MAP_BEGIN(nsFilteredContentIterator
)
44 NS_INTERFACE_MAP_ENTRY(nsIContentIterator
)
45 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIContentIterator
)
46 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsFilteredContentIterator
)
49 NS_IMPL_CYCLE_COLLECTION(nsFilteredContentIterator
,
56 //------------------------------------------------------------
58 nsFilteredContentIterator::Init(nsINode
* aRoot
)
60 NS_ENSURE_ARG_POINTER(aRoot
);
61 NS_ENSURE_TRUE(mPreIterator
, NS_ERROR_FAILURE
);
62 NS_ENSURE_TRUE(mIterator
, NS_ERROR_FAILURE
);
63 mIsOutOfRange
= false;
64 mDirection
= eForward
;
65 mCurrentIterator
= mPreIterator
;
67 mRange
= new nsRange(aRoot
);
68 nsCOMPtr
<nsIDOMNode
> domNode(do_QueryInterface(aRoot
));
70 mRange
->SelectNode(domNode
);
73 nsresult rv
= mPreIterator
->Init(mRange
);
74 NS_ENSURE_SUCCESS(rv
, rv
);
75 return mIterator
->Init(mRange
);
78 //------------------------------------------------------------
80 nsFilteredContentIterator::Init(nsIDOMRange
* aRange
)
82 NS_ENSURE_TRUE(mPreIterator
, NS_ERROR_FAILURE
);
83 NS_ENSURE_TRUE(mIterator
, NS_ERROR_FAILURE
);
84 NS_ENSURE_ARG_POINTER(aRange
);
85 mIsOutOfRange
= false;
86 mDirection
= eForward
;
87 mCurrentIterator
= mPreIterator
;
89 nsCOMPtr
<nsIDOMRange
> domRange
;
90 nsresult rv
= aRange
->CloneRange(getter_AddRefs(domRange
));
91 NS_ENSURE_SUCCESS(rv
, rv
);
92 mRange
= do_QueryInterface(domRange
);
94 rv
= mPreIterator
->Init(domRange
);
95 NS_ENSURE_SUCCESS(rv
, rv
);
96 return mIterator
->Init(domRange
);
99 //------------------------------------------------------------
101 nsFilteredContentIterator::SwitchDirections(bool aChangeToForward
)
103 nsINode
*node
= mCurrentIterator
->GetCurrentNode();
105 if (aChangeToForward
) {
106 mCurrentIterator
= mPreIterator
;
107 mDirection
= eForward
;
109 mCurrentIterator
= mIterator
;
110 mDirection
= eBackward
;
114 nsresult rv
= mCurrentIterator
->PositionAt(node
);
116 mIsOutOfRange
= true;
123 //------------------------------------------------------------
125 nsFilteredContentIterator::First()
127 if (!mCurrentIterator
) {
128 NS_ERROR("Missing iterator!");
133 // If we are switching directions then
134 // we need to switch how we process the nodes
135 if (mDirection
!= eForward
) {
136 mCurrentIterator
= mPreIterator
;
137 mDirection
= eForward
;
138 mIsOutOfRange
= false;
141 mCurrentIterator
->First();
143 if (mCurrentIterator
->IsDone()) {
147 nsINode
*currentNode
= mCurrentIterator
->GetCurrentNode();
148 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(currentNode
));
151 CheckAdvNode(node
, didCross
, eForward
);
154 //------------------------------------------------------------
156 nsFilteredContentIterator::Last()
158 if (!mCurrentIterator
) {
159 NS_ERROR("Missing iterator!");
164 // If we are switching directions then
165 // we need to switch how we process the nodes
166 if (mDirection
!= eBackward
) {
167 mCurrentIterator
= mIterator
;
168 mDirection
= eBackward
;
169 mIsOutOfRange
= false;
172 mCurrentIterator
->Last();
174 if (mCurrentIterator
->IsDone()) {
178 nsINode
*currentNode
= mCurrentIterator
->GetCurrentNode();
179 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(currentNode
));
182 CheckAdvNode(node
, didCross
, eBackward
);
185 ///////////////////////////////////////////////////////////////////////////
186 // ContentToParentOffset: returns the content node's parent and offset.
189 ContentToParentOffset(nsIContent
*aContent
, nsIDOMNode
**aParent
,
192 if (!aParent
|| !aOffset
)
201 nsIContent
* parent
= aContent
->GetParent();
206 *aOffset
= parent
->IndexOf(aContent
);
208 CallQueryInterface(parent
, aParent
);
211 ///////////////////////////////////////////////////////////////////////////
212 // ContentIsInTraversalRange: returns true if content is visited during
213 // the traversal of the range in the specified mode.
216 ContentIsInTraversalRange(nsIContent
*aContent
, bool aIsPreMode
,
217 nsIDOMNode
*aStartNode
, int32_t aStartOffset
,
218 nsIDOMNode
*aEndNode
, int32_t aEndOffset
)
220 NS_ENSURE_TRUE(aStartNode
&& aEndNode
&& aContent
, false);
222 nsCOMPtr
<nsIDOMNode
> parentNode
;
225 ContentToParentOffset(aContent
, getter_AddRefs(parentNode
), &indx
);
227 NS_ENSURE_TRUE(parentNode
, false);
232 int32_t startRes
= nsContentUtils::ComparePoints(aStartNode
, aStartOffset
,
234 int32_t endRes
= nsContentUtils::ComparePoints(aEndNode
, aEndOffset
,
236 return (startRes
<= 0) && (endRes
>= 0);
240 ContentIsInTraversalRange(nsIDOMRange
*aRange
, nsIDOMNode
* aNextNode
, bool aIsPreMode
)
242 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aNextNode
));
243 NS_ENSURE_TRUE(content
&& aRange
, false);
245 nsCOMPtr
<nsIDOMNode
> sNode
;
246 nsCOMPtr
<nsIDOMNode
> eNode
;
249 aRange
->GetStartContainer(getter_AddRefs(sNode
));
250 aRange
->GetStartOffset(&sOffset
);
251 aRange
->GetEndContainer(getter_AddRefs(eNode
));
252 aRange
->GetEndOffset(&eOffset
);
253 return ContentIsInTraversalRange(content
, aIsPreMode
, sNode
, sOffset
, eNode
, eOffset
);
256 //------------------------------------------------------------
257 // Helper function to advance to the next or previous node
259 nsFilteredContentIterator::AdvanceNode(nsIDOMNode
* aNode
, nsIDOMNode
*& aNewNode
, eDirectionType aDir
)
261 nsCOMPtr
<nsIDOMNode
> nextNode
;
262 if (aDir
== eForward
) {
263 aNode
->GetNextSibling(getter_AddRefs(nextNode
));
265 aNode
->GetPreviousSibling(getter_AddRefs(nextNode
));
269 // If we got here, that means we found the nxt/prv node
270 // make sure it is in our DOMRange
271 bool intersects
= ContentIsInTraversalRange(mRange
, nextNode
, aDir
== eForward
);
278 // The next node was null so we need to walk up the parent(s)
279 nsCOMPtr
<nsIDOMNode
> parent
;
280 aNode
->GetParentNode(getter_AddRefs(parent
));
281 NS_ASSERTION(parent
, "parent can't be nullptr");
283 // Make sure the parent is in the DOMRange before going further
284 bool intersects
= ContentIsInTraversalRange(mRange
, nextNode
, aDir
== eForward
);
286 // Now find the nxt/prv node after/before this node
287 nsresult rv
= AdvanceNode(parent
, aNewNode
, aDir
);
288 if (NS_SUCCEEDED(rv
) && aNewNode
) {
294 // if we get here it pretty much means
295 // we went out of the DOM Range
296 mIsOutOfRange
= true;
298 return NS_ERROR_FAILURE
;
301 //------------------------------------------------------------
302 // Helper function to see if the next/prev node should be skipped
304 nsFilteredContentIterator::CheckAdvNode(nsIDOMNode
* aNode
, bool& aDidSkip
, eDirectionType aDir
)
307 mIsOutOfRange
= false;
309 if (aNode
&& mFilter
) {
310 nsCOMPtr
<nsIDOMNode
> currentNode
= aNode
;
313 nsresult rv
= mFilter
->Skip(aNode
, &skipIt
);
314 if (NS_SUCCEEDED(rv
) && skipIt
) {
316 // Get the next/prev node and then
317 // see if we should skip that
318 nsCOMPtr
<nsIDOMNode
> advNode
;
319 rv
= AdvanceNode(aNode
, *getter_AddRefs(advNode
), aDir
);
320 if (NS_SUCCEEDED(rv
) && advNode
) {
323 return; // fell out of range
326 if (aNode
!= currentNode
) {
327 nsCOMPtr
<nsIContent
> content(do_QueryInterface(aNode
));
328 mCurrentIterator
->PositionAt(content
);
330 return; // found something
337 nsFilteredContentIterator::Next()
339 if (mIsOutOfRange
|| !mCurrentIterator
) {
340 NS_ASSERTION(mCurrentIterator
, "Missing iterator!");
345 // If we are switching directions then
346 // we need to switch how we process the nodes
347 if (mDirection
!= eForward
) {
348 nsresult rv
= SwitchDirections(true);
354 mCurrentIterator
->Next();
356 if (mCurrentIterator
->IsDone()) {
360 // If we can't get the current node then
361 // don't check to see if we can skip it
362 nsINode
*currentNode
= mCurrentIterator
->GetCurrentNode();
364 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(currentNode
));
365 CheckAdvNode(node
, mDidSkip
, eForward
);
369 nsFilteredContentIterator::Prev()
371 if (mIsOutOfRange
|| !mCurrentIterator
) {
372 NS_ASSERTION(mCurrentIterator
, "Missing iterator!");
377 // If we are switching directions then
378 // we need to switch how we process the nodes
379 if (mDirection
!= eBackward
) {
380 nsresult rv
= SwitchDirections(false);
386 mCurrentIterator
->Prev();
388 if (mCurrentIterator
->IsDone()) {
392 // If we can't get the current node then
393 // don't check to see if we can skip it
394 nsINode
*currentNode
= mCurrentIterator
->GetCurrentNode();
396 nsCOMPtr
<nsIDOMNode
> node(do_QueryInterface(currentNode
));
397 CheckAdvNode(node
, mDidSkip
, eBackward
);
401 nsFilteredContentIterator::GetCurrentNode()
403 if (mIsOutOfRange
|| !mCurrentIterator
) {
407 return mCurrentIterator
->GetCurrentNode();
411 nsFilteredContentIterator::IsDone()
413 if (mIsOutOfRange
|| !mCurrentIterator
) {
417 return mCurrentIterator
->IsDone();
421 nsFilteredContentIterator::PositionAt(nsINode
* aCurNode
)
423 NS_ENSURE_TRUE(mCurrentIterator
, NS_ERROR_FAILURE
);
424 mIsOutOfRange
= false;
425 return mCurrentIterator
->PositionAt(aCurNode
);