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
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/
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
15 * The Original Code is mozilla.org code.
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.
23 * Elika J. Etemad ("fantasai") <fantasai@inkedblade.net>
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.
37 * ***** END LICENSE BLOCK ***** */
39 /* base class #1 for rendering objects that have child lists */
41 #ifndef nsContainerFrame_h___
42 #define nsContainerFrame_h___
44 #include "nsSplittableFrame.h"
45 #include "nsFrameList.h"
46 #include "nsLayoutUtils.h"
49 * Child list name indices
50 * @see #GetAdditionalChildListName()
52 #define NS_CONTAINER_LIST_COUNT_SANS_OC 1
53 // for frames that don't use overflow containers
54 #define NS_CONTAINER_LIST_COUNT_INCL_OC 3
55 // for frames that support overflow containers
57 // Option flags for ReflowChild() and FinishReflowChild()
59 #define NS_FRAME_NO_MOVE_VIEW 0x0001
60 #define NS_FRAME_NO_MOVE_FRAME (0x0002 | NS_FRAME_NO_MOVE_VIEW)
61 #define NS_FRAME_NO_SIZE_VIEW 0x0004
62 #define NS_FRAME_NO_VISIBILITY 0x0008
63 // Only applies to ReflowChild: if true, invalidate the child if it's
65 #define NS_FRAME_INVALIDATE_ON_MOVE 0x0010
67 class nsOverflowContinuationTracker
;
70 * Implementation of a container frame.
72 class nsContainerFrame
: public nsSplittableFrame
76 NS_IMETHOD
Init(nsIContent
* aContent
,
78 nsIFrame
* aPrevInFlow
);
79 NS_IMETHOD
SetInitialChildList(nsIAtom
* aListName
,
80 nsIFrame
* aChildList
);
81 NS_IMETHOD
AppendFrames(nsIAtom
* aListName
,
82 nsIFrame
* aFrameList
);
83 NS_IMETHOD
InsertFrames(nsIAtom
* aListName
,
85 nsIFrame
* aFrameList
);
86 NS_IMETHOD
RemoveFrame(nsIAtom
* aListName
,
89 virtual nsIFrame
* GetFirstChild(nsIAtom
* aListName
) const;
90 virtual nsIAtom
* GetAdditionalChildListName(PRInt32 aIndex
) const;
91 virtual void Destroy();
92 virtual void ChildIsDirty(nsIFrame
* aChild
);
94 virtual PRBool
IsLeaf() const;
95 virtual PRBool
PeekOffsetNoAmount(PRBool aForward
, PRInt32
* aOffset
);
96 virtual PRBool
PeekOffsetCharacter(PRBool aForward
, PRInt32
* aOffset
);
99 NS_IMETHOD
List(FILE* out
, PRInt32 aIndent
) const;
102 // nsContainerFrame methods
103 virtual void DeleteNextInFlowChild(nsPresContext
* aPresContext
,
104 nsIFrame
* aNextInFlow
);
106 static PRInt32
LengthOf(nsIFrame
* aFrameList
) {
107 nsFrameList
tmp(aFrameList
);
108 return tmp
.GetLength();
111 // Positions the frame's view based on the frame's origin
112 static void PositionFrameView(nsIFrame
* aKidFrame
);
114 // Set the view's size and position after its frame has been reflowed.
117 // NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
118 // don't want to automatically sync the frame and view
119 // NS_FRAME_NO_SIZE_VIEW - don't size the view
120 static void SyncFrameViewAfterReflow(nsPresContext
* aPresContext
,
123 const nsRect
* aCombinedArea
,
124 PRUint32 aFlags
= 0);
126 // Sets the view's attributes from the frame style.
129 // - content transparency
131 // Call this when one of these styles changes or when the view has just
133 // @param aStyleContext can be null, in which case the frame's style context is used
134 static void SyncFrameViewProperties(nsPresContext
* aPresContext
,
136 nsStyleContext
* aStyleContext
,
138 PRUint32 aFlags
= 0);
140 // Returns PR_TRUE if the frame requires a view
141 static PRBool
FrameNeedsView(nsIFrame
* aFrame
);
143 // Used by both nsInlineFrame and nsFirstLetterFrame.
144 void DoInlineIntrinsicWidth(nsIRenderingContext
*aRenderingContext
,
145 InlineIntrinsicWidthData
*aData
,
146 nsLayoutUtils::IntrinsicWidthType aType
);
149 * This is the CSS block concept of computing 'auto' widths, which most
150 * classes derived from nsContainerFrame want.
152 virtual nsSize
ComputeAutoSize(nsIRenderingContext
*aRenderingContext
,
153 nsSize aCBSize
, nscoord aAvailableWidth
,
154 nsSize aMargin
, nsSize aBorder
,
155 nsSize aPadding
, PRBool aShrinkWrap
);
158 * Invokes the WillReflow() function, positions the frame and its view (if
159 * requested), and then calls Reflow(). If the reflow succeeds and the child
160 * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
163 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
164 * don't want to automatically sync the frame and view
165 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
166 * case. Also implies NS_FRAME_NO_MOVE_VIEW
168 nsresult
ReflowChild(nsIFrame
* aKidFrame
,
169 nsPresContext
* aPresContext
,
170 nsHTMLReflowMetrics
& aDesiredSize
,
171 const nsHTMLReflowState
& aReflowState
,
175 nsReflowStatus
& aStatus
,
176 nsOverflowContinuationTracker
* aTracker
= nsnull
);
179 * The second half of frame reflow. Does the following:
180 * - sets the frame's bounds
181 * - sizes and positions (if requested) the frame's view. If the frame's final
182 * position differs from the current position and the frame itself does not
183 * have a view, then any child frames with views are positioned so they stay
185 * - sets the view's visibility, opacity, content transparency, and clip
186 * - invoked the DidReflow() function
189 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
190 * case. Also implies NS_FRAME_NO_MOVE_VIEW
191 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
192 * don't want to automatically sync the frame and view
193 * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
195 static nsresult
FinishReflowChild(nsIFrame
* aKidFrame
,
196 nsPresContext
* aPresContext
,
197 const nsHTMLReflowState
* aReflowState
,
198 const nsHTMLReflowMetrics
& aDesiredSize
,
204 static void PositionChildViews(nsIFrame
* aFrame
);
206 // ==========================================================================
207 /* Overflow containers are continuation frames that hold overflow. They
208 * are created when the frame runs out of computed height, but still has
209 * too much content to fit in the availableHeight. The parent creates a
210 * continuation as usual, but marks it as NS_FRAME_IS_OVERFLOW_CONTAINER
211 * and adds it to its next-in-flow's overflow container list, either by
212 * adding it directly or by putting it in its own excess overflow containers
213 * list (to be drained by the next-in-flow when it calls
214 * ReflowOverflowContainerChildren). The parent continues reflow as if
215 * the frame was complete once it ran out of computed height, but returns
216 * either an NS_FRAME_NOT_COMPLETE or NS_FRAME_OVERFLOW_INCOMPLETE reflow
217 * status to request a next-in-flow. The parent's next-in-flow is then
218 * responsible for calling ReflowOverflowContainerChildren to (drain and)
219 * reflow these overflow continuations. Overflow containers do not affect
220 * other frames' size or position during reflow (but do affect their
221 * parent's overflow area).
223 * Overflow container continuations are different from normal continuations
225 * - more than one child of the frame can have its next-in-flow broken
226 * off and pushed into the frame's next-in-flow
227 * - new continuations may need to be spliced into the middle of the list
228 * or deleted continuations slipped out
229 * e.g. A, B, C are all fixed-size containers on one page, all have
230 * overflow beyond availableHeight, and content is dynamically added
232 * As a result, it is not possible to simply prepend the new continuations
233 * to the old list as with the overflowProperty mechanism. To avoid
234 * complicated list splicing, the code assumes only one overflow containers
235 * list exists for a given frame: either its own overflowContainersProperty
236 * or its prev-in-flow's excessOverflowContainersProperty, not both.
238 * The nsOverflowContinuationTracker helper class should be used for tracking
239 * overflow containers and adding them to the appropriate list.
240 * See nsBlockFrame::Reflow for a sample implementation.
243 friend class nsOverflowContinuationTracker
;
246 * Reflow overflow container children. They are invisible to normal reflow
247 * (i.e. don't affect sizing or placement of other children) and inherit
248 * width and horizontal position from their prev-in-flow.
251 * 1. Pulls excess overflow containers from the prev-in-flow and adds
252 * them to our overflow container list
253 * 2. Reflows all our overflow container kids
254 * 3. Expands aOverflowRect as necessary to accomodate these children.
255 * 4. Sets aStatus's NS_FRAME_OVERFLOW_IS_INCOMPLETE flag (along with
256 * NS_FRAME_REFLOW_NEXTINFLOW as necessary) if any overflow children
258 * 5. Prepends a list of their continuations to our excess overflow
259 * container list, to be drained into our next-in-flow when it is
262 * The caller is responsible for tracking any new overflow container
263 * continuations it makes, removing them from its child list, and
264 * making sure they are stored properly in the overflow container lists.
265 * The nsOverflowContinuationTracker helper class should be used for this.
267 * (aFlags just gets passed through to ReflowChild)
269 nsresult
ReflowOverflowContainerChildren(nsPresContext
* aPresContext
,
270 const nsHTMLReflowState
& aReflowState
,
271 nsRect
& aOverflowRect
,
273 nsReflowStatus
& aStatus
);
276 * Inserts aFrameList's frames into our main child list--without reparenting
277 * or requesting reflow.
279 virtual nsresult
AddFrames(nsIFrame
* aFrameList
,
280 nsIFrame
* aPrevSibling
);
283 * Removes aChild without destroying it and without requesting reflow.
284 * Continuations are not affected. Checks the primary and overflow
285 * or overflow containers and excess overflow containers lists, depending
286 * on whether the NS_FRAME_IS_OVERFLOW_CONTAINER flag is set. Does not
287 * check any other auxiliary lists.
288 * Returns NS_ERROR_UNEXPECTED if we failed to remove aChild.
289 * Returns other error codes if we failed to put back a proptable list.
290 * If aForceNormal is true, only checks the primary and overflow lists
291 * even when the NS_FRAME_IS_OVERFLOW_CONTAINER flag is set.
293 virtual nsresult
StealFrame(nsPresContext
* aPresContext
,
295 PRBool aForceNormal
= PR_FALSE
);
298 * Add overflow containers to the display list
300 void DisplayOverflowContainers(nsDisplayListBuilder
* aBuilder
,
301 const nsRect
& aDirtyRect
,
302 const nsDisplayListSet
& aLists
);
305 * Builds display lists for the children. The background
306 * of each child is placed in the Content() list (suitable for inline
307 * children and other elements that behave like inlines,
308 * but not for in-flow block children of blocks). DOES NOT
309 * paint the background/borders/outline of this frame. This should
310 * probably be avoided and eventually removed. It's currently here
311 * to emulate what nsContainerFrame::Paint did.
313 NS_IMETHOD
BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
314 const nsRect
& aDirtyRect
,
315 const nsDisplayListSet
& aLists
);
318 nsContainerFrame(nsStyleContext
* aContext
) : nsSplittableFrame(aContext
) {}
322 * Builds a display list for non-block children that behave like
323 * inlines. This puts the background of each child into the
324 * Content() list (suitable for inline children but not for
325 * in-flow block children of blocks).
326 * @param aForcePseudoStack forces each child into a pseudo-stacking-context
327 * so its background and all other display items (except for positioned
328 * display items) go into the Content() list.
330 nsresult
BuildDisplayListForNonBlockChildren(nsDisplayListBuilder
* aBuilder
,
331 const nsRect
& aDirtyRect
,
332 const nsDisplayListSet
& aLists
,
333 PRUint32 aFlags
= 0);
336 // ==========================================================================
337 /* Overflow Frames are frames that did not fit and must be pulled by
338 * our next-in-flow during its reflow. (The same concept for overflow
339 * containers is called "excess frames". We should probably make the
344 * Get the frames on the overflow list
346 nsIFrame
* GetOverflowFrames(nsPresContext
* aPresContext
,
347 PRBool aRemoveProperty
) const;
349 * Set the overflow list
351 nsresult
SetOverflowFrames(nsPresContext
* aPresContext
,
352 nsIFrame
* aOverflowFrames
);
355 * Moves any frames on both the prev-in-flow's overflow list and the
356 * receiver's overflow to the receiver's child list.
358 * Resets the overlist pointers to nsnull, and updates the receiver's child
359 * count and content mapping.
361 * @return PR_TRUE if any frames were moved and PR_FALSE otherwise
363 PRBool
MoveOverflowToChildList(nsPresContext
* aPresContext
);
366 * Push aFromChild and its next siblings to the next-in-flow. Change
367 * the geometric parent of each frame that's pushed. If there is no
368 * next-in-flow the frames are placed on the overflow list (and the
369 * geometric parent is left unchanged).
371 * Updates the next-in-flow's child count. Does <b>not</b> update the
372 * pusher's child count.
374 * @param aFromChild the first child frame to push. It is disconnected from
376 * @param aPrevSibling aFromChild's previous sibling. Must not be null.
377 * It's an error to push a parent's first child frame
379 void PushChildren(nsPresContext
* aPresContext
,
380 nsIFrame
* aFromChild
,
381 nsIFrame
* aPrevSibling
);
383 // ==========================================================================
385 * Convenience methods for nsFrameLists stored in the
386 * PresContext's proptable
390 * Get the PresContext-stored nsFrameList named aPropID for this frame.
393 nsFrameList
* GetPropTableFrames(nsPresContext
* aPresContext
,
394 nsIAtom
* aPropID
) const;
397 * Remove and return the PresContext-stored nsFrameList named aPropID for
398 * this frame. May return null.
400 nsFrameList
* RemovePropTableFrames(nsPresContext
* aPresContext
,
401 nsIAtom
* aPropID
) const;
404 * Remove aFrame from the PresContext-stored nsFrameList named aPropID
405 * for this frame, deleting the list if it is now empty.
406 * Return true if the aFrame was successfully removed,
407 * Return false otherwise.
410 PRBool
RemovePropTableFrame(nsPresContext
* aPresContext
,
412 nsIAtom
* aPropID
) const;
415 * Set the PresContext-stored nsFrameList named aPropID for this frame
416 * to the given aFrameList, which must not be null.
418 nsresult
SetPropTableFrames(nsPresContext
* aPresContext
,
419 nsFrameList
* aFrameList
,
420 nsIAtom
* aPropID
) const;
421 // ==========================================================================
426 // ==========================================================================
427 /* The out-of-flow-related code below is for a hacky way of splitting
428 * absolutely-positioned frames. Basically what we do is split the frame
429 * in nsAbsoluteContainingBlock and pretend the continuation is an overflow
430 * container. This isn't an ideal solution, but it lets us print the content
431 * at least. See bug 154892.
434 #define IS_TRUE_OVERFLOW_CONTAINER(frame) \
435 ( (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) \
436 && !(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) )
437 //XXXfr This check isn't quite correct, because it doesn't handle cases
438 // where the out-of-flow has overflow.. but that's rare.
439 // We'll need to revisit the way abspos continuations are handled later
440 // for various reasons, this detail is one of them. See bug 154892
443 * Helper class for tracking overflow container continuations during reflow.
445 * A frame is related to two sets of overflow containers: those that /are/
446 * its own children, and those that are /continuations/ of its children.
447 * This tracker walks through those continuations (the frame's NIF's children)
448 * and their prev-in-flows (a subset of the frame's normal and overflow
449 * container children) in parallel. It allows the reflower to synchronously
450 * walk its overflow continuations while it loops through and reflows its
451 * children. This makes it possible to insert new continuations at the correct
452 * place in the overflow containers list.
454 * The reflower is expected to loop through its children in the same order it
455 * looped through them the last time (if there was a last time).
456 * For each child, the reflower should either
457 * - call Skip for the child if was not reflowed in this pass
458 * - call Insert for the overflow continuation if the child was reflowed
459 * but has incomplete overflow
460 * - call Finished for the child if it was reflowed in this pass but
461 * is either complete or has a normal next-in-flow. This call can
462 * be skipped if the child did not previously have an overflow
465 class nsOverflowContinuationTracker
{
468 * Initializes an nsOverflowContinuationTracker to help track overflow
469 * continuations of aFrame's children. Typically invoked on 'this'.
471 * aWalkOOFFrames determines whether the walker skips out-of-flow frames
472 * or skips non-out-of-flow frames.
474 * Don't set aSkipOverflowContainerChildren to PR_FALSE unless you plan
475 * to walk your own overflow container children. (Usually they are handled
476 * by calling ReflowOverflowContainerChildren.) aWalkOOFFrames is ignored
477 * if aSkipOverflowContainerChildren is false.
479 nsOverflowContinuationTracker(nsPresContext
* aPresContext
,
480 nsContainerFrame
* aFrame
,
481 PRBool aWalkOOFFrames
,
482 PRBool aSkipOverflowContainerChildren
= PR_TRUE
);
484 * This function adds an overflow continuation to our running list and
485 * sets its NS_FRAME_IS_OVERFLOW_CONTAINER flag.
487 * aReflowStatus should preferably be specific to the recently-reflowed
488 * child and not influenced by any of its siblings' statuses. This
489 * function sets the NS_FRAME_IS_DIRTY bit on aOverflowCont if it needs
490 * to be reflowed. (Its need for reflow depends on changes to its
491 * prev-in-flow, not to its parent--for whom it is invisible, reflow-wise.)
493 * The caller MUST disconnect the frame from its parent's child list
494 * if it was not previously an NS_FRAME_IS_OVERFLOW_CONTAINER (because
495 * StealFrame is much more inefficient than disconnecting in place
496 * during Reflow, which the caller is able to do but we are not).
498 * The caller MUST NOT disconnect the frame from its parent's
499 * child list if it is already an NS_FRAME_IS_OVERFLOW_CONTAINER.
500 * (In this case we will disconnect and reconnect it ourselves.)
502 nsresult
Insert(nsIFrame
* aOverflowCont
,
503 nsReflowStatus
& aReflowStatus
);
505 * This function must be called for each child that is reflowed
506 * but no longer has an overflow continuation. (It may be called for
507 * other children, but in that case has no effect.) It increments our
508 * walker and makes sure we drop any dangling pointers to its
509 * next-in-flow. This function MUST be called before stealing or
510 * deleting aChild's next-in-flow.
512 void Finish(nsIFrame
* aChild
);
515 * This function should be called for each child that isn't reflowed.
516 * It increments our walker and sets the NS_FRAME_OVERFLOW_INCOMPLETE
517 * reflow flag if it encounters an overflow continuation so that our
518 * next-in-flow doesn't get prematurely deleted. It MUST be called on
519 * each unreflowed child that has an overflow container continuation;
520 * it MAY be called on other children, but it isn't necessary (doesn't
523 void Skip(nsIFrame
* aChild
, nsReflowStatus
& aReflowStatus
)
525 NS_PRECONDITION(aChild
, "null ptr");
526 if (aChild
== mSentry
) {
528 aReflowStatus
= NS_FRAME_MERGE_INCOMPLETE(aReflowStatus
,
529 NS_FRAME_OVERFLOW_INCOMPLETE
);
535 void SetUpListWalker();
538 /* We hold a pointer to either the next-in-flow's overflow containers list
539 or, if that doesn't exist, our frame's excess overflow containers list.
540 We need to make sure that we drop that pointer if the list becomes
541 empty and is deleted elsewhere. */
542 nsFrameList
* mOverflowContList
;
543 /* We hold a pointer to the most recently-reflowed child that has an
544 overflow container next-in-flow. We do this because it's a known
545 good point; this pointer won't be deleted on us. We can use it to
546 recover our place in the list. */
547 nsIFrame
* mPrevOverflowCont
;
548 /* This is a pointer to the next overflow container's prev-in-flow, which
549 is (or should be) a child of our frame. When we hit this, we will need
550 to increment this walker to the next overflow container. */
552 /* Parent of all frames in mOverflowContList. If our mOverflowContList
553 is an excessOverflowContainersProperty, then this our frame (the frame
554 that was passed in to our constructor). Otherwise this is that frame's
555 next-in-flow, and our mOverflowContList is mParent's
556 overflowContainersProperty */
557 nsContainerFrame
* mParent
;
558 /* Tells SetUpListWalker whether or not to walk us past any continuations
559 of overflow containers. aWalkOOFFrames is ignored when this is false. */
560 PRBool mSkipOverflowContainerChildren
;
561 /* Tells us whether to pay attention to OOF frames or non-OOF frames */
562 PRBool mWalkOOFFrames
;
565 #endif /* nsContainerFrame_h___ */