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 : * Elika J. Etemad ("fantasai") <fantasai@inkedblade.net>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /* base class #1 for rendering objects that have child lists */
40 :
41 : #ifndef nsContainerFrame_h___
42 : #define nsContainerFrame_h___
43 :
44 : #include "nsSplittableFrame.h"
45 : #include "nsFrameList.h"
46 : #include "nsLayoutUtils.h"
47 : #include "nsAutoPtr.h"
48 :
49 : // Option flags for ReflowChild() and FinishReflowChild()
50 : // member functions
51 : #define NS_FRAME_NO_MOVE_VIEW 0x0001
52 : #define NS_FRAME_NO_MOVE_FRAME (0x0002 | NS_FRAME_NO_MOVE_VIEW)
53 : #define NS_FRAME_NO_SIZE_VIEW 0x0004
54 : #define NS_FRAME_NO_VISIBILITY 0x0008
55 : // Only applies to ReflowChild: if true, invalidate the child if it's
56 : // being moved
57 : #define NS_FRAME_INVALIDATE_ON_MOVE 0x0010
58 :
59 : class nsOverflowContinuationTracker;
60 :
61 : // Some macros for container classes to do sanity checking on
62 : // width/height/x/y values computed during reflow.
63 : // NOTE: AppUnitsPerCSSPixel value hardwired here to remove the
64 : // dependency on nsDeviceContext.h. It doesn't matter if it's a
65 : // little off.
66 : #ifdef DEBUG
67 : #define CRAZY_W (1000000*60)
68 : #define CRAZY_H CRAZY_W
69 :
70 : #define CRAZY_WIDTH(_x) (((_x) < -CRAZY_W) || ((_x) > CRAZY_W))
71 : #define CRAZY_HEIGHT(_y) (((_y) < -CRAZY_H) || ((_y) > CRAZY_H))
72 : #endif
73 :
74 : /**
75 : * Implementation of a container frame.
76 : */
77 : class nsContainerFrame : public nsSplittableFrame
78 : {
79 : public:
80 : NS_DECL_FRAMEARENA_HELPERS
81 : NS_DECL_QUERYFRAME_TARGET(nsContainerFrame)
82 : NS_DECL_QUERYFRAME
83 :
84 : // nsIFrame overrides
85 : NS_IMETHOD Init(nsIContent* aContent,
86 : nsIFrame* aParent,
87 : nsIFrame* aPrevInFlow);
88 : NS_IMETHOD SetInitialChildList(ChildListID aListID,
89 : nsFrameList& aChildList);
90 : NS_IMETHOD AppendFrames(ChildListID aListID,
91 : nsFrameList& aFrameList);
92 : NS_IMETHOD InsertFrames(ChildListID aListID,
93 : nsIFrame* aPrevFrame,
94 : nsFrameList& aFrameList);
95 : NS_IMETHOD RemoveFrame(ChildListID aListID,
96 : nsIFrame* aOldFrame);
97 :
98 : virtual const nsFrameList& GetChildList(ChildListID aList) const;
99 : virtual void GetChildLists(nsTArray<ChildList>* aLists) const;
100 : virtual void DestroyFrom(nsIFrame* aDestructRoot);
101 : virtual void ChildIsDirty(nsIFrame* aChild);
102 :
103 : virtual bool IsLeaf() const;
104 : virtual bool PeekOffsetNoAmount(bool aForward, PRInt32* aOffset);
105 : virtual bool PeekOffsetCharacter(bool aForward, PRInt32* aOffset,
106 : bool aRespectClusters = true);
107 :
108 : #ifdef DEBUG
109 : NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
110 : #endif
111 :
112 : // nsContainerFrame methods
113 :
114 : /**
115 : * Helper method to create next-in-flows if necessary. If aFrame
116 : * already has a next-in-flow then this method does
117 : * nothing. Otherwise, a new continuation frame is created and
118 : * linked into the flow. In addition, the new frame is inserted
119 : * into the principal child list after aFrame.
120 : * @note calling this method on a block frame is illegal. Use
121 : * nsBlockFrame::CreateContinuationFor() instead.
122 : * @param aNextInFlowResult will contain the next-in-flow
123 : * <b>if and only if</b> one is created. If a next-in-flow already
124 : * exists aNextInFlowResult is set to nsnull.
125 : * @return NS_OK if a next-in-flow already exists or is successfully created.
126 : */
127 : nsresult CreateNextInFlow(nsPresContext* aPresContext,
128 : nsIFrame* aFrame,
129 : nsIFrame*& aNextInFlowResult);
130 :
131 : /**
132 : * Delete aNextInFlow and its next-in-flows.
133 : * @param aDeletingEmptyFrames if set, then the reflow for aNextInFlow's
134 : * content was complete before aNextInFlow, so aNextInFlow and its
135 : * next-in-flows no longer map any real content.
136 : */
137 : virtual void DeleteNextInFlowChild(nsPresContext* aPresContext,
138 : nsIFrame* aNextInFlow,
139 : bool aDeletingEmptyFrames);
140 :
141 : /**
142 : * Helper method to wrap views around frames. Used by containers
143 : * under special circumstances (can be used by leaf frames as well)
144 : */
145 : static nsresult CreateViewForFrame(nsIFrame* aFrame,
146 : bool aForce);
147 :
148 : // Positions the frame's view based on the frame's origin
149 : static void PositionFrameView(nsIFrame* aKidFrame);
150 :
151 : static nsresult ReparentFrameView(nsPresContext* aPresContext,
152 : nsIFrame* aChildFrame,
153 : nsIFrame* aOldParentFrame,
154 : nsIFrame* aNewParentFrame);
155 :
156 : static nsresult ReparentFrameViewList(nsPresContext* aPresContext,
157 : const nsFrameList& aChildFrameList,
158 : nsIFrame* aOldParentFrame,
159 : nsIFrame* aNewParentFrame);
160 :
161 : // Set the view's size and position after its frame has been reflowed.
162 : //
163 : // Flags:
164 : // NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
165 : // don't want to automatically sync the frame and view
166 : // NS_FRAME_NO_SIZE_VIEW - don't size the view
167 : static void SyncFrameViewAfterReflow(nsPresContext* aPresContext,
168 : nsIFrame* aFrame,
169 : nsIView* aView,
170 : const nsRect& aVisualOverflowArea,
171 : PRUint32 aFlags = 0);
172 :
173 : // Syncs properties to the top level view and window, like transparency and
174 : // shadow.
175 : static void SyncWindowProperties(nsPresContext* aPresContext,
176 : nsIFrame* aFrame,
177 : nsIView* aView);
178 :
179 : // Sets the view's attributes from the frame style.
180 : // - visibility
181 : // - clip
182 : // Call this when one of these styles changes or when the view has just
183 : // been created.
184 : // @param aStyleContext can be null, in which case the frame's style context is used
185 : static void SyncFrameViewProperties(nsPresContext* aPresContext,
186 : nsIFrame* aFrame,
187 : nsStyleContext* aStyleContext,
188 : nsIView* aView,
189 : PRUint32 aFlags = 0);
190 :
191 : // Used by both nsInlineFrame and nsFirstLetterFrame.
192 : void DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext,
193 : InlineIntrinsicWidthData *aData,
194 : nsLayoutUtils::IntrinsicWidthType aType);
195 :
196 : /**
197 : * This is the CSS block concept of computing 'auto' widths, which most
198 : * classes derived from nsContainerFrame want.
199 : */
200 : virtual nsSize ComputeAutoSize(nsRenderingContext *aRenderingContext,
201 : nsSize aCBSize, nscoord aAvailableWidth,
202 : nsSize aMargin, nsSize aBorder,
203 : nsSize aPadding, bool aShrinkWrap);
204 :
205 : /**
206 : * Invokes the WillReflow() function, positions the frame and its view (if
207 : * requested), and then calls Reflow(). If the reflow succeeds and the child
208 : * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
209 : *
210 : * Flags:
211 : * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
212 : * don't want to automatically sync the frame and view
213 : * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
214 : * case. Also implies NS_FRAME_NO_MOVE_VIEW
215 : */
216 : nsresult ReflowChild(nsIFrame* aKidFrame,
217 : nsPresContext* aPresContext,
218 : nsHTMLReflowMetrics& aDesiredSize,
219 : const nsHTMLReflowState& aReflowState,
220 : nscoord aX,
221 : nscoord aY,
222 : PRUint32 aFlags,
223 : nsReflowStatus& aStatus,
224 : nsOverflowContinuationTracker* aTracker = nsnull);
225 :
226 : /**
227 : * The second half of frame reflow. Does the following:
228 : * - sets the frame's bounds
229 : * - sizes and positions (if requested) the frame's view. If the frame's final
230 : * position differs from the current position and the frame itself does not
231 : * have a view, then any child frames with views are positioned so they stay
232 : * in sync
233 : * - sets the view's visibility, opacity, content transparency, and clip
234 : * - invoked the DidReflow() function
235 : *
236 : * Flags:
237 : * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
238 : * case. Also implies NS_FRAME_NO_MOVE_VIEW
239 : * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
240 : * don't want to automatically sync the frame and view
241 : * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
242 : */
243 : static nsresult FinishReflowChild(nsIFrame* aKidFrame,
244 : nsPresContext* aPresContext,
245 : const nsHTMLReflowState* aReflowState,
246 : const nsHTMLReflowMetrics& aDesiredSize,
247 : nscoord aX,
248 : nscoord aY,
249 : PRUint32 aFlags);
250 :
251 :
252 : static void PositionChildViews(nsIFrame* aFrame);
253 :
254 : // ==========================================================================
255 : /* Overflow containers are continuation frames that hold overflow. They
256 : * are created when the frame runs out of computed height, but still has
257 : * too much content to fit in the availableHeight. The parent creates a
258 : * continuation as usual, but marks it as NS_FRAME_IS_OVERFLOW_CONTAINER
259 : * and adds it to its next-in-flow's overflow container list, either by
260 : * adding it directly or by putting it in its own excess overflow containers
261 : * list (to be drained by the next-in-flow when it calls
262 : * ReflowOverflowContainerChildren). The parent continues reflow as if
263 : * the frame was complete once it ran out of computed height, but returns
264 : * either an NS_FRAME_NOT_COMPLETE or NS_FRAME_OVERFLOW_INCOMPLETE reflow
265 : * status to request a next-in-flow. The parent's next-in-flow is then
266 : * responsible for calling ReflowOverflowContainerChildren to (drain and)
267 : * reflow these overflow continuations. Overflow containers do not affect
268 : * other frames' size or position during reflow (but do affect their
269 : * parent's overflow area).
270 : *
271 : * Overflow container continuations are different from normal continuations
272 : * in that
273 : * - more than one child of the frame can have its next-in-flow broken
274 : * off and pushed into the frame's next-in-flow
275 : * - new continuations may need to be spliced into the middle of the list
276 : * or deleted continuations slipped out
277 : * e.g. A, B, C are all fixed-size containers on one page, all have
278 : * overflow beyond availableHeight, and content is dynamically added
279 : * and removed from B
280 : * As a result, it is not possible to simply prepend the new continuations
281 : * to the old list as with the overflowProperty mechanism. To avoid
282 : * complicated list splicing, the code assumes only one overflow containers
283 : * list exists for a given frame: either its own overflowContainersProperty
284 : * or its prev-in-flow's excessOverflowContainersProperty, not both.
285 : *
286 : * The nsOverflowContinuationTracker helper class should be used for tracking
287 : * overflow containers and adding them to the appropriate list.
288 : * See nsBlockFrame::Reflow for a sample implementation.
289 : */
290 :
291 : friend class nsOverflowContinuationTracker;
292 :
293 : /**
294 : * Reflow overflow container children. They are invisible to normal reflow
295 : * (i.e. don't affect sizing or placement of other children) and inherit
296 : * width and horizontal position from their prev-in-flow.
297 : *
298 : * This method
299 : * 1. Pulls excess overflow containers from the prev-in-flow and adds
300 : * them to our overflow container list
301 : * 2. Reflows all our overflow container kids
302 : * 3. Expands aOverflowRect as necessary to accomodate these children.
303 : * 4. Sets aStatus's NS_FRAME_OVERFLOW_IS_INCOMPLETE flag (along with
304 : * NS_FRAME_REFLOW_NEXTINFLOW as necessary) if any overflow children
305 : * are incomplete and
306 : * 5. Prepends a list of their continuations to our excess overflow
307 : * container list, to be drained into our next-in-flow when it is
308 : * reflowed.
309 : *
310 : * The caller is responsible for tracking any new overflow container
311 : * continuations it makes, removing them from its child list, and
312 : * making sure they are stored properly in the overflow container lists.
313 : * The nsOverflowContinuationTracker helper class should be used for this.
314 : *
315 : * (aFlags just gets passed through to ReflowChild)
316 : */
317 : nsresult ReflowOverflowContainerChildren(nsPresContext* aPresContext,
318 : const nsHTMLReflowState& aReflowState,
319 : nsOverflowAreas& aOverflowRects,
320 : PRUint32 aFlags,
321 : nsReflowStatus& aStatus);
322 :
323 : /**
324 : * Removes aChild without destroying it and without requesting reflow.
325 : * Continuations are not affected. Checks the primary and overflow
326 : * or overflow containers and excess overflow containers lists, depending
327 : * on whether the NS_FRAME_IS_OVERFLOW_CONTAINER flag is set. Does not
328 : * check any other auxiliary lists.
329 : * Returns NS_ERROR_UNEXPECTED if we failed to remove aChild.
330 : * Returns other error codes if we failed to put back a proptable list.
331 : * If aForceNormal is true, only checks the primary and overflow lists
332 : * even when the NS_FRAME_IS_OVERFLOW_CONTAINER flag is set.
333 : */
334 : virtual nsresult StealFrame(nsPresContext* aPresContext,
335 : nsIFrame* aChild,
336 : bool aForceNormal = false);
337 :
338 : /**
339 : * Removes the next-siblings of aChild without destroying them and without
340 : * requesting reflow. Checks the principal and overflow lists (not
341 : * overflow containers / excess overflow containers). Does not check any
342 : * other auxiliary lists.
343 : * @param aChild a child frame or nsnull
344 : * @return If aChild is non-null, the next-siblings of aChild, if any.
345 : * If aChild is null, all child frames on the principal list, if any.
346 : */
347 : nsFrameList StealFramesAfter(nsIFrame* aChild);
348 :
349 : /**
350 : * Add overflow containers to the display list
351 : */
352 : void DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
353 : const nsRect& aDirtyRect,
354 : const nsDisplayListSet& aLists);
355 :
356 : /**
357 : * Builds display lists for the children. The background
358 : * of each child is placed in the Content() list (suitable for inline
359 : * children and other elements that behave like inlines,
360 : * but not for in-flow block children of blocks). DOES NOT
361 : * paint the background/borders/outline of this frame. This should
362 : * probably be avoided and eventually removed. It's currently here
363 : * to emulate what nsContainerFrame::Paint did.
364 : */
365 : NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
366 : const nsRect& aDirtyRect,
367 : const nsDisplayListSet& aLists);
368 :
369 : // Destructor function for the proptable-stored framelists
370 0 : static void DestroyFrameList(void* aPropertyValue)
371 : {
372 0 : if (aPropertyValue) {
373 0 : static_cast<nsFrameList*>(aPropertyValue)->Destroy();
374 : }
375 0 : }
376 :
377 0 : NS_DECLARE_FRAME_PROPERTY(OverflowProperty, DestroyFrameList)
378 0 : NS_DECLARE_FRAME_PROPERTY(OverflowContainersProperty, DestroyFrameList)
379 0 : NS_DECLARE_FRAME_PROPERTY(ExcessOverflowContainersProperty, DestroyFrameList)
380 :
381 : protected:
382 0 : nsContainerFrame(nsStyleContext* aContext) : nsSplittableFrame(aContext) {}
383 : ~nsContainerFrame();
384 :
385 : /**
386 : * Builds a display list for non-block children that behave like
387 : * inlines. This puts the background of each child into the
388 : * Content() list (suitable for inline children but not for
389 : * in-flow block children of blocks).
390 : * @param aForcePseudoStack forces each child into a pseudo-stacking-context
391 : * so its background and all other display items (except for positioned
392 : * display items) go into the Content() list.
393 : */
394 : nsresult BuildDisplayListForNonBlockChildren(nsDisplayListBuilder* aBuilder,
395 : const nsRect& aDirtyRect,
396 : const nsDisplayListSet& aLists,
397 : PRUint32 aFlags = 0);
398 :
399 : /**
400 : * A version of BuildDisplayList that use DISPLAY_CHILD_INLINE.
401 : * Intended as a convenience for derived classes.
402 : */
403 0 : nsresult BuildDisplayListForInline(nsDisplayListBuilder* aBuilder,
404 : const nsRect& aDirtyRect,
405 : const nsDisplayListSet& aLists) {
406 0 : nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
407 0 : NS_ENSURE_SUCCESS(rv, rv);
408 : rv = BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists,
409 0 : DISPLAY_CHILD_INLINE);
410 0 : NS_ENSURE_SUCCESS(rv, rv);
411 0 : return rv;
412 : }
413 :
414 :
415 : // ==========================================================================
416 : /* Overflow Frames are frames that did not fit and must be pulled by
417 : * our next-in-flow during its reflow. (The same concept for overflow
418 : * containers is called "excess frames". We should probably make the
419 : * names match.)
420 : */
421 :
422 : /**
423 : * Get the frames on the overflow list. Can return null if there are no
424 : * overflow frames. The caller does NOT take ownership of the list; it's
425 : * still owned by this frame. A non-null return value indicates that the
426 : * list is nonempty.
427 : */
428 : inline nsFrameList* GetOverflowFrames() const;
429 :
430 : /**
431 : * As GetOverflowFrames, but removes the overflow frames property. The
432 : * caller is responsible for deleting nsFrameList and either passing
433 : * ownership of the frames to someone else or destroying the frames. A
434 : * non-null return value indicates that the list is nonempty. The
435 : * recommended way to use this function it to assign its return value
436 : * into an nsAutoPtr.
437 : */
438 : inline nsFrameList* StealOverflowFrames();
439 :
440 : /**
441 : * Set the overflow list. aOverflowFrames must not be an empty list.
442 : */
443 : void SetOverflowFrames(nsPresContext* aPresContext,
444 : const nsFrameList& aOverflowFrames);
445 :
446 : /**
447 : * Destroy the overflow list and any frames that are on it.
448 : * Calls DestructFrom() insead of Destruct() on the frames if
449 : * aDestructRoot is non-null.
450 : */
451 : void DestroyOverflowList(nsPresContext* aPresContext,
452 : nsIFrame* aDestructRoot);
453 :
454 : /**
455 : * Moves any frames on both the prev-in-flow's overflow list and the
456 : * receiver's overflow to the receiver's child list.
457 : *
458 : * Resets the overlist pointers to nsnull, and updates the receiver's child
459 : * count and content mapping.
460 : *
461 : * @return true if any frames were moved and false otherwise
462 : */
463 : bool MoveOverflowToChildList(nsPresContext* aPresContext);
464 :
465 : /**
466 : * Push aFromChild and its next siblings to the next-in-flow. Change
467 : * the geometric parent of each frame that's pushed. If there is no
468 : * next-in-flow the frames are placed on the overflow list (and the
469 : * geometric parent is left unchanged).
470 : *
471 : * Updates the next-in-flow's child count. Does <b>not</b> update the
472 : * pusher's child count.
473 : *
474 : * @param aFromChild the first child frame to push. It is disconnected from
475 : * aPrevSibling
476 : * @param aPrevSibling aFromChild's previous sibling. Must not be null.
477 : * It's an error to push a parent's first child frame
478 : */
479 : void PushChildren(nsPresContext* aPresContext,
480 : nsIFrame* aFromChild,
481 : nsIFrame* aPrevSibling);
482 :
483 : // ==========================================================================
484 : /*
485 : * Convenience methods for nsFrameLists stored in the
486 : * PresContext's proptable
487 : */
488 :
489 : /**
490 : * Get the PresContext-stored nsFrameList named aPropID for this frame.
491 : * May return null.
492 : */
493 : nsFrameList* GetPropTableFrames(nsPresContext* aPresContext,
494 : const FramePropertyDescriptor* aProperty) const;
495 :
496 : /**
497 : * Remove and return the PresContext-stored nsFrameList named aPropID for
498 : * this frame. May return null.
499 : */
500 : nsFrameList* RemovePropTableFrames(nsPresContext* aPresContext,
501 : const FramePropertyDescriptor* aProperty);
502 :
503 : /**
504 : * Remove aFrame from the PresContext-stored nsFrameList named aPropID
505 : * for this frame, deleting the list if it is now empty.
506 : * Return true if the aFrame was successfully removed,
507 : * Return false otherwise.
508 : */
509 : bool RemovePropTableFrame(nsPresContext* aPresContext,
510 : nsIFrame* aFrame,
511 : const FramePropertyDescriptor* aProperty);
512 :
513 : /**
514 : * Set the PresContext-stored nsFrameList named aPropID for this frame
515 : * to the given aFrameList, which must not be null.
516 : */
517 : nsresult SetPropTableFrames(nsPresContext* aPresContext,
518 : nsFrameList* aFrameList,
519 : const FramePropertyDescriptor* aProperty);
520 : // ==========================================================================
521 :
522 : nsFrameList mFrames;
523 : };
524 :
525 : // ==========================================================================
526 : /* The out-of-flow-related code below is for a hacky way of splitting
527 : * absolutely-positioned frames. Basically what we do is split the frame
528 : * in nsAbsoluteContainingBlock and pretend the continuation is an overflow
529 : * container. This isn't an ideal solution, but it lets us print the content
530 : * at least. See bug 154892.
531 : */
532 :
533 : #define IS_TRUE_OVERFLOW_CONTAINER(frame) \
534 : ( (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) \
535 : && !( (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && \
536 : frame->GetStyleDisplay()->IsAbsolutelyPositioned() ) )
537 : //XXXfr This check isn't quite correct, because it doesn't handle cases
538 : // where the out-of-flow has overflow.. but that's rare.
539 : // We'll need to revisit the way abspos continuations are handled later
540 : // for various reasons, this detail is one of them. See bug 154892
541 :
542 : /**
543 : * Helper class for tracking overflow container continuations during reflow.
544 : *
545 : * A frame is related to two sets of overflow containers: those that /are/
546 : * its own children, and those that are /continuations/ of its children.
547 : * This tracker walks through those continuations (the frame's NIF's children)
548 : * and their prev-in-flows (a subset of the frame's normal and overflow
549 : * container children) in parallel. It allows the reflower to synchronously
550 : * walk its overflow continuations while it loops through and reflows its
551 : * children. This makes it possible to insert new continuations at the correct
552 : * place in the overflow containers list.
553 : *
554 : * The reflower is expected to loop through its children in the same order it
555 : * looped through them the last time (if there was a last time).
556 : * For each child, the reflower should either
557 : * - call Skip for the child if was not reflowed in this pass
558 : * - call Insert for the overflow continuation if the child was reflowed
559 : * but has incomplete overflow
560 : * - call Finished for the child if it was reflowed in this pass but
561 : * is either complete or has a normal next-in-flow. This call can
562 : * be skipped if the child did not previously have an overflow
563 : * continuation.
564 : */
565 : class nsOverflowContinuationTracker {
566 : public:
567 : /**
568 : * Initializes an nsOverflowContinuationTracker to help track overflow
569 : * continuations of aFrame's children. Typically invoked on 'this'.
570 : *
571 : * aWalkOOFFrames determines whether the walker skips out-of-flow frames
572 : * or skips non-out-of-flow frames.
573 : *
574 : * Don't set aSkipOverflowContainerChildren to false unless you plan
575 : * to walk your own overflow container children. (Usually they are handled
576 : * by calling ReflowOverflowContainerChildren.) aWalkOOFFrames is ignored
577 : * if aSkipOverflowContainerChildren is false.
578 : */
579 : nsOverflowContinuationTracker(nsPresContext* aPresContext,
580 : nsContainerFrame* aFrame,
581 : bool aWalkOOFFrames,
582 : bool aSkipOverflowContainerChildren = true);
583 : /**
584 : * This function adds an overflow continuation to our running list and
585 : * sets its NS_FRAME_IS_OVERFLOW_CONTAINER flag.
586 : *
587 : * aReflowStatus should preferably be specific to the recently-reflowed
588 : * child and not influenced by any of its siblings' statuses. This
589 : * function sets the NS_FRAME_IS_DIRTY bit on aOverflowCont if it needs
590 : * to be reflowed. (Its need for reflow depends on changes to its
591 : * prev-in-flow, not to its parent--for whom it is invisible, reflow-wise.)
592 : *
593 : * The caller MUST disconnect the frame from its parent's child list
594 : * if it was not previously an NS_FRAME_IS_OVERFLOW_CONTAINER (because
595 : * StealFrame is much more inefficient than disconnecting in place
596 : * during Reflow, which the caller is able to do but we are not).
597 : *
598 : * The caller MUST NOT disconnect the frame from its parent's
599 : * child list if it is already an NS_FRAME_IS_OVERFLOW_CONTAINER.
600 : * (In this case we will disconnect and reconnect it ourselves.)
601 : */
602 : nsresult Insert(nsIFrame* aOverflowCont,
603 : nsReflowStatus& aReflowStatus);
604 : /**
605 : * This function must be called for each child that is reflowed
606 : * but no longer has an overflow continuation. (It may be called for
607 : * other children, but in that case has no effect.) It increments our
608 : * walker and makes sure we drop any dangling pointers to its
609 : * next-in-flow. This function MUST be called before stealing or
610 : * deleting aChild's next-in-flow.
611 : */
612 : void Finish(nsIFrame* aChild);
613 :
614 : /**
615 : * This function should be called for each child that isn't reflowed.
616 : * It increments our walker and sets the NS_FRAME_OVERFLOW_INCOMPLETE
617 : * reflow flag if it encounters an overflow continuation so that our
618 : * next-in-flow doesn't get prematurely deleted. It MUST be called on
619 : * each unreflowed child that has an overflow container continuation;
620 : * it MAY be called on other children, but it isn't necessary (doesn't
621 : * do anything).
622 : */
623 0 : void Skip(nsIFrame* aChild, nsReflowStatus& aReflowStatus)
624 : {
625 0 : NS_PRECONDITION(aChild, "null ptr");
626 0 : if (aChild == mSentry) {
627 0 : StepForward();
628 0 : NS_MergeReflowStatusInto(&aReflowStatus, NS_FRAME_OVERFLOW_INCOMPLETE);
629 : }
630 0 : }
631 :
632 : private:
633 :
634 : void SetUpListWalker();
635 : void StepForward();
636 :
637 : /* We hold a pointer to either the next-in-flow's overflow containers list
638 : or, if that doesn't exist, our frame's excess overflow containers list.
639 : We need to make sure that we drop that pointer if the list becomes
640 : empty and is deleted elsewhere. */
641 : nsFrameList* mOverflowContList;
642 : /* We hold a pointer to the most recently-reflowed child that has an
643 : overflow container next-in-flow. We do this because it's a known
644 : good point; this pointer won't be deleted on us. We can use it to
645 : recover our place in the list. */
646 : nsIFrame* mPrevOverflowCont;
647 : /* This is a pointer to the next overflow container's prev-in-flow, which
648 : is (or should be) a child of our frame. When we hit this, we will need
649 : to increment this walker to the next overflow container. */
650 : nsIFrame* mSentry;
651 : /* Parent of all frames in mOverflowContList. If our mOverflowContList
652 : is an excessOverflowContainersProperty, or null, then this is our frame
653 : (the frame that was passed in to our constructor). Otherwise this is
654 : that frame's next-in-flow, and our mOverflowContList is mParent's
655 : overflowContainersProperty */
656 : nsContainerFrame* mParent;
657 : /* Tells SetUpListWalker whether or not to walk us past any continuations
658 : of overflow containers. aWalkOOFFrames is ignored when this is false. */
659 : bool mSkipOverflowContainerChildren;
660 : /* Tells us whether to pay attention to OOF frames or non-OOF frames */
661 : bool mWalkOOFFrames;
662 : };
663 :
664 : inline
665 : nsFrameList*
666 0 : nsContainerFrame::GetOverflowFrames() const
667 : {
668 : nsFrameList* list =
669 0 : static_cast<nsFrameList*>(Properties().Get(OverflowProperty()));
670 0 : NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
671 0 : return list;
672 : }
673 :
674 : inline
675 : nsFrameList*
676 0 : nsContainerFrame::StealOverflowFrames()
677 : {
678 : nsFrameList* list =
679 0 : static_cast<nsFrameList*>(Properties().Remove(OverflowProperty()));
680 0 : NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
681 0 : return list;
682 : }
683 :
684 : #endif /* nsContainerFrame_h___ */
|