1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 : #include "nsCOMPtr.h"
38 : #include "nsGkAtoms.h"
39 :
40 : #include "nsFrameTraversal.h"
41 : #include "nsFrameList.h"
42 : #include "nsPlaceholderFrame.h"
43 :
44 :
45 : class nsFrameIterator : public nsIFrameEnumerator
46 : {
47 : public:
48 : typedef nsIFrame::ChildListID ChildListID;
49 :
50 : NS_DECL_ISUPPORTS
51 :
52 : virtual void First();
53 : virtual void Next();
54 : virtual nsIFrame* CurrentItem();
55 : virtual bool IsDone();
56 :
57 : virtual void Last();
58 : virtual void Prev();
59 :
60 : nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart,
61 : nsIteratorType aType, bool aLockScroll, bool aFollowOOFs);
62 :
63 : protected:
64 0 : void setCurrent(nsIFrame *aFrame){mCurrent = aFrame;}
65 0 : nsIFrame *getCurrent(){return mCurrent;}
66 0 : void setStart(nsIFrame *aFrame){mStart = aFrame;}
67 : nsIFrame *getStart(){return mStart;}
68 0 : nsIFrame *getLast(){return mLast;}
69 0 : void setLast(nsIFrame *aFrame){mLast = aFrame;}
70 : PRInt8 getOffEdge(){return mOffEdge;}
71 0 : void setOffEdge(PRInt8 aOffEdge){mOffEdge = aOffEdge;}
72 0 : void SetLockInScrollView(bool aLockScroll){mLockScroll = aLockScroll;}
73 :
74 : /*
75 : Our own versions of the standard frame tree navigation
76 : methods, which, if the iterator is following out-of-flows,
77 : apply the following rules for placeholder frames:
78 :
79 : - If a frame HAS a placeholder frame, getting its parent
80 : gets the placeholder's parent.
81 :
82 : - If a frame's first child or next/prev sibling IS a
83 : placeholder frame, then we instead return the real frame.
84 :
85 : - If a frame HAS a placeholder frame, getting its next/prev
86 : sibling gets the placeholder frame's next/prev sibling.
87 :
88 : These are all applied recursively to support multiple levels of
89 : placeholders.
90 : */
91 :
92 : nsIFrame* GetParentFrame(nsIFrame* aFrame);
93 : // like GetParentFrame but returns null once a popup frame is reached
94 : nsIFrame* GetParentFrameNotPopup(nsIFrame* aFrame);
95 :
96 : nsIFrame* GetFirstChild(nsIFrame* aFrame);
97 : nsIFrame* GetLastChild(nsIFrame* aFrame);
98 :
99 : nsIFrame* GetNextSibling(nsIFrame* aFrame);
100 : nsIFrame* GetPrevSibling(nsIFrame* aFrame);
101 :
102 : /*
103 : These methods are overridden by the bidi visual iterator to have the
104 : semantics of "get first child in visual order", "get last child in visual
105 : order", "get next sibling in visual order" and "get previous sibling in visual
106 : order".
107 : */
108 :
109 : virtual nsIFrame* GetFirstChildInner(nsIFrame* aFrame);
110 : virtual nsIFrame* GetLastChildInner(nsIFrame* aFrame);
111 :
112 : virtual nsIFrame* GetNextSiblingInner(nsIFrame* aFrame);
113 : virtual nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame);
114 :
115 : nsIFrame* GetPlaceholderFrame(nsIFrame* aFrame);
116 : bool IsPopupFrame(nsIFrame* aFrame);
117 :
118 : nsPresContext* mPresContext;
119 : bool mLockScroll;
120 : bool mFollowOOFs;
121 : nsIteratorType mType;
122 :
123 : private:
124 : nsIFrame *mStart;
125 : nsIFrame *mCurrent;
126 : nsIFrame *mLast; //the last one that was in current;
127 : PRInt8 mOffEdge; //0= no -1 to far prev, 1 to far next;
128 : };
129 :
130 :
131 :
132 : // Bidi visual iterator
133 : class nsVisualIterator: public nsFrameIterator
134 : {
135 : public:
136 0 : nsVisualIterator(nsPresContext* aPresContext, nsIFrame *aStart,
137 : nsIteratorType aType, bool aLockScroll, bool aFollowOOFs) :
138 0 : nsFrameIterator(aPresContext, aStart, aType, aLockScroll, aFollowOOFs) {}
139 :
140 : protected:
141 : nsIFrame* GetFirstChildInner(nsIFrame* aFrame);
142 : nsIFrame* GetLastChildInner(nsIFrame* aFrame);
143 :
144 : nsIFrame* GetNextSiblingInner(nsIFrame* aFrame);
145 : nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame);
146 : };
147 :
148 : /************IMPLEMENTATIONS**************/
149 :
150 0 : nsresult NS_CreateFrameTraversal(nsIFrameTraversal** aResult)
151 : {
152 0 : NS_ENSURE_ARG_POINTER(aResult);
153 0 : *aResult = nsnull;
154 :
155 0 : nsCOMPtr<nsIFrameTraversal> t(new nsFrameTraversal());
156 :
157 0 : *aResult = t;
158 0 : NS_ADDREF(*aResult);
159 :
160 0 : return NS_OK;
161 : }
162 :
163 : nsresult
164 0 : NS_NewFrameTraversal(nsIFrameEnumerator **aEnumerator,
165 : nsPresContext* aPresContext,
166 : nsIFrame *aStart,
167 : nsIteratorType aType,
168 : bool aVisual,
169 : bool aLockInScrollView,
170 : bool aFollowOOFs)
171 : {
172 0 : if (!aEnumerator || !aStart)
173 0 : return NS_ERROR_NULL_POINTER;
174 0 : nsCOMPtr<nsIFrameEnumerator> trav;
175 0 : if (aVisual) {
176 : trav = new nsVisualIterator(aPresContext, aStart, aType,
177 0 : aLockInScrollView, aFollowOOFs);
178 : } else {
179 : trav = new nsFrameIterator(aPresContext, aStart, aType,
180 0 : aLockInScrollView, aFollowOOFs);
181 : }
182 0 : trav.forget(aEnumerator);
183 0 : return NS_OK;
184 : }
185 :
186 :
187 0 : nsFrameTraversal::nsFrameTraversal()
188 : {
189 0 : }
190 :
191 0 : nsFrameTraversal::~nsFrameTraversal()
192 : {
193 0 : }
194 :
195 0 : NS_IMPL_ISUPPORTS1(nsFrameTraversal,nsIFrameTraversal)
196 :
197 : NS_IMETHODIMP
198 0 : nsFrameTraversal::NewFrameTraversal(nsIFrameEnumerator **aEnumerator,
199 : nsPresContext* aPresContext,
200 : nsIFrame *aStart,
201 : PRInt32 aType,
202 : bool aVisual,
203 : bool aLockInScrollView,
204 : bool aFollowOOFs)
205 : {
206 : return NS_NewFrameTraversal(aEnumerator, aPresContext, aStart,
207 : static_cast<nsIteratorType>(aType),
208 0 : aVisual, aLockInScrollView, aFollowOOFs);
209 : }
210 :
211 : // nsFrameIterator implementation
212 :
213 0 : NS_IMPL_ISUPPORTS1(nsFrameIterator, nsIFrameEnumerator)
214 :
215 0 : nsFrameIterator::nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart,
216 : nsIteratorType aType, bool aLockInScrollView,
217 0 : bool aFollowOOFs)
218 : {
219 0 : mOffEdge = 0;
220 0 : mPresContext = aPresContext;
221 0 : if (aFollowOOFs && aStart)
222 0 : aStart = nsPlaceholderFrame::GetRealFrameFor(aStart);
223 0 : setStart(aStart);
224 0 : setCurrent(aStart);
225 0 : setLast(aStart);
226 0 : mType = aType;
227 0 : SetLockInScrollView(aLockInScrollView);
228 0 : mFollowOOFs = aFollowOOFs;
229 0 : }
230 :
231 :
232 :
233 : nsIFrame*
234 0 : nsFrameIterator::CurrentItem()
235 : {
236 0 : if (mOffEdge)
237 0 : return nsnull;
238 :
239 0 : return mCurrent;
240 : }
241 :
242 :
243 :
244 : bool
245 0 : nsFrameIterator::IsDone()
246 : {
247 0 : return mOffEdge != 0;
248 : }
249 :
250 : void
251 0 : nsFrameIterator::First()
252 : {
253 0 : mCurrent = mStart;
254 0 : }
255 :
256 : static bool
257 0 : IsRootFrame(nsIFrame* aFrame)
258 : {
259 0 : nsIAtom* atom = aFrame->GetType();
260 : return (atom == nsGkAtoms::canvasFrame) ||
261 0 : (atom == nsGkAtoms::rootFrame);
262 : }
263 :
264 : void
265 0 : nsFrameIterator::Last()
266 : {
267 : nsIFrame* result;
268 0 : nsIFrame* parent = getCurrent();
269 : // If the current frame is a popup, don't move farther up the tree.
270 : // Otherwise, get the nearest root frame or popup.
271 0 : if (parent->GetType() != nsGkAtoms::menuPopupFrame) {
272 0 : while (!IsRootFrame(parent) && (result = GetParentFrameNotPopup(parent)))
273 0 : parent = result;
274 : }
275 :
276 0 : while ((result = GetLastChild(parent))) {
277 0 : parent = result;
278 : }
279 :
280 0 : setCurrent(parent);
281 0 : if (!parent)
282 0 : setOffEdge(1);
283 0 : }
284 :
285 : void
286 0 : nsFrameIterator::Next()
287 : {
288 : // recursive-oid method to get next frame
289 0 : nsIFrame *result = nsnull;
290 0 : nsIFrame *parent = getCurrent();
291 0 : if (!parent)
292 0 : parent = getLast();
293 :
294 0 : if (mType == eLeaf) {
295 : // Drill down to first leaf
296 0 : while ((result = GetFirstChild(parent))) {
297 0 : parent = result;
298 : }
299 0 : } else if (mType == ePreOrder) {
300 0 : result = GetFirstChild(parent);
301 0 : if (result)
302 0 : parent = result;
303 : }
304 :
305 0 : if (parent != getCurrent()) {
306 0 : result = parent;
307 : } else {
308 0 : while (parent) {
309 0 : result = GetNextSibling(parent);
310 0 : if (result) {
311 0 : if (mType != ePreOrder) {
312 0 : parent = result;
313 0 : while ((result = GetFirstChild(parent))) {
314 0 : parent = result;
315 : }
316 0 : result = parent;
317 : }
318 0 : break;
319 : }
320 : else {
321 0 : result = GetParentFrameNotPopup(parent);
322 0 : if (!result || IsRootFrame(result) ||
323 0 : (mLockScroll && result->GetType() == nsGkAtoms::scrollFrame)) {
324 0 : result = nsnull;
325 0 : break;
326 : }
327 0 : if (mType == ePostOrder)
328 0 : break;
329 0 : parent = result;
330 : }
331 : }
332 : }
333 :
334 0 : setCurrent(result);
335 0 : if (!result) {
336 0 : setOffEdge(1);
337 0 : setLast(parent);
338 : }
339 0 : }
340 :
341 : void
342 0 : nsFrameIterator::Prev()
343 : {
344 : // recursive-oid method to get prev frame
345 0 : nsIFrame *result = nsnull;
346 0 : nsIFrame *parent = getCurrent();
347 0 : if (!parent)
348 0 : parent = getLast();
349 :
350 0 : if (mType == eLeaf) {
351 : // Drill down to last leaf
352 0 : while ((result = GetLastChild(parent))) {
353 0 : parent = result;
354 : }
355 0 : } else if (mType == ePostOrder) {
356 0 : result = GetLastChild(parent);
357 0 : if (result)
358 0 : parent = result;
359 : }
360 :
361 0 : if (parent != getCurrent()) {
362 0 : result = parent;
363 : } else {
364 0 : while (parent) {
365 0 : result = GetPrevSibling(parent);
366 0 : if (result) {
367 0 : if (mType != ePostOrder) {
368 0 : parent = result;
369 0 : while ((result = GetLastChild(parent))) {
370 0 : parent = result;
371 : }
372 0 : result = parent;
373 : }
374 0 : break;
375 : } else {
376 0 : result = GetParentFrameNotPopup(parent);
377 0 : if (!result || IsRootFrame(result) ||
378 0 : (mLockScroll && result->GetType() == nsGkAtoms::scrollFrame)) {
379 0 : result = nsnull;
380 0 : break;
381 : }
382 0 : if (mType == ePreOrder)
383 0 : break;
384 0 : parent = result;
385 : }
386 : }
387 : }
388 :
389 0 : setCurrent(result);
390 0 : if (!result) {
391 0 : setOffEdge(-1);
392 0 : setLast(parent);
393 : }
394 0 : }
395 :
396 : nsIFrame*
397 0 : nsFrameIterator::GetParentFrame(nsIFrame* aFrame)
398 : {
399 0 : if (mFollowOOFs)
400 0 : aFrame = GetPlaceholderFrame(aFrame);
401 0 : if (aFrame)
402 0 : return aFrame->GetParent();
403 :
404 0 : return nsnull;
405 : }
406 :
407 : nsIFrame*
408 0 : nsFrameIterator::GetParentFrameNotPopup(nsIFrame* aFrame)
409 : {
410 0 : if (mFollowOOFs)
411 0 : aFrame = GetPlaceholderFrame(aFrame);
412 0 : if (aFrame) {
413 0 : nsIFrame* parent = aFrame->GetParent();
414 0 : if (!IsPopupFrame(parent))
415 0 : return parent;
416 : }
417 :
418 0 : return nsnull;
419 : }
420 :
421 : nsIFrame*
422 0 : nsFrameIterator::GetFirstChild(nsIFrame* aFrame)
423 : {
424 0 : nsIFrame* result = GetFirstChildInner(aFrame);
425 0 : if (mLockScroll && result && result->GetType() == nsGkAtoms::scrollFrame)
426 0 : return nsnull;
427 0 : if (result && mFollowOOFs) {
428 0 : result = nsPlaceholderFrame::GetRealFrameFor(result);
429 :
430 0 : if (IsPopupFrame(result))
431 0 : result = GetNextSibling(result);
432 : }
433 0 : return result;
434 : }
435 :
436 : nsIFrame*
437 0 : nsFrameIterator::GetLastChild(nsIFrame* aFrame)
438 : {
439 0 : nsIFrame* result = GetLastChildInner(aFrame);
440 0 : if (mLockScroll && result && result->GetType() == nsGkAtoms::scrollFrame)
441 0 : return nsnull;
442 0 : if (result && mFollowOOFs) {
443 0 : result = nsPlaceholderFrame::GetRealFrameFor(result);
444 :
445 0 : if (IsPopupFrame(result))
446 0 : result = GetPrevSibling(result);
447 : }
448 0 : return result;
449 : }
450 :
451 : nsIFrame*
452 0 : nsFrameIterator::GetNextSibling(nsIFrame* aFrame)
453 : {
454 0 : nsIFrame* result = nsnull;
455 0 : if (mFollowOOFs)
456 0 : aFrame = GetPlaceholderFrame(aFrame);
457 0 : if (aFrame) {
458 0 : result = GetNextSiblingInner(aFrame);
459 0 : if (result && mFollowOOFs)
460 0 : result = nsPlaceholderFrame::GetRealFrameFor(result);
461 : }
462 :
463 0 : if (mFollowOOFs && IsPopupFrame(result))
464 0 : result = GetNextSibling(result);
465 :
466 0 : return result;
467 : }
468 :
469 : nsIFrame*
470 0 : nsFrameIterator::GetPrevSibling(nsIFrame* aFrame)
471 : {
472 0 : nsIFrame* result = nsnull;
473 0 : if (mFollowOOFs)
474 0 : aFrame = GetPlaceholderFrame(aFrame);
475 0 : if (aFrame) {
476 0 : result = GetPrevSiblingInner(aFrame);
477 0 : if (result && mFollowOOFs)
478 0 : result = nsPlaceholderFrame::GetRealFrameFor(result);
479 : }
480 :
481 0 : if (mFollowOOFs && IsPopupFrame(result))
482 0 : result = GetPrevSibling(result);
483 :
484 0 : return result;
485 : }
486 :
487 : nsIFrame*
488 0 : nsFrameIterator::GetFirstChildInner(nsIFrame* aFrame) {
489 0 : return aFrame->GetFirstPrincipalChild();
490 : }
491 :
492 : nsIFrame*
493 0 : nsFrameIterator::GetLastChildInner(nsIFrame* aFrame) {
494 0 : return aFrame->PrincipalChildList().LastChild();
495 : }
496 :
497 : nsIFrame*
498 0 : nsFrameIterator::GetNextSiblingInner(nsIFrame* aFrame) {
499 0 : return aFrame->GetNextSibling();
500 : }
501 :
502 : nsIFrame*
503 0 : nsFrameIterator::GetPrevSiblingInner(nsIFrame* aFrame) {
504 0 : return aFrame->GetPrevSibling();
505 : }
506 :
507 :
508 : nsIFrame*
509 0 : nsFrameIterator::GetPlaceholderFrame(nsIFrame* aFrame)
510 : {
511 0 : nsIFrame* result = aFrame;
512 0 : nsIPresShell *presShell = mPresContext->GetPresShell();
513 0 : if (presShell) {
514 0 : nsIFrame* placeholder = presShell->GetPlaceholderFrameFor(aFrame);
515 0 : if (placeholder)
516 0 : result = placeholder;
517 : }
518 :
519 0 : if (result != aFrame)
520 0 : result = GetPlaceholderFrame(result);
521 :
522 0 : return result;
523 : }
524 :
525 : bool
526 0 : nsFrameIterator::IsPopupFrame(nsIFrame* aFrame)
527 : {
528 : return (aFrame &&
529 0 : aFrame->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_POPUP);
530 : }
531 :
532 : // nsVisualIterator implementation
533 :
534 : nsIFrame*
535 0 : nsVisualIterator::GetFirstChildInner(nsIFrame* aFrame) {
536 0 : return aFrame->PrincipalChildList().GetNextVisualFor(nsnull);
537 : }
538 :
539 : nsIFrame*
540 0 : nsVisualIterator::GetLastChildInner(nsIFrame* aFrame) {
541 0 : return aFrame->PrincipalChildList().GetPrevVisualFor(nsnull);
542 : }
543 :
544 : nsIFrame*
545 0 : nsVisualIterator::GetNextSiblingInner(nsIFrame* aFrame) {
546 0 : nsIFrame* parent = GetParentFrame(aFrame);
547 0 : if (!parent)
548 0 : return nsnull;
549 0 : return parent->PrincipalChildList().GetNextVisualFor(aFrame);
550 : }
551 :
552 : nsIFrame*
553 0 : nsVisualIterator::GetPrevSiblingInner(nsIFrame* aFrame) {
554 0 : nsIFrame* parent = GetParentFrame(aFrame);
555 0 : if (!parent)
556 0 : return nsnull;
557 0 : return parent->PrincipalChildList().GetPrevVisualFor(aFrame);
558 : }
|