Line data Source code
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/. */
5 :
6 : /* base class #1 for rendering objects that have child lists */
7 :
8 : #ifndef nsContainerFrame_h___
9 : #define nsContainerFrame_h___
10 :
11 : #include "mozilla/Attributes.h"
12 : #include "nsSplittableFrame.h"
13 : #include "nsFrameList.h"
14 : #include "nsLayoutUtils.h"
15 :
16 : // Option flags for ReflowChild() and FinishReflowChild()
17 : // member functions
18 : #define NS_FRAME_NO_MOVE_VIEW 0x0001
19 : #define NS_FRAME_NO_MOVE_FRAME (0x0002 | NS_FRAME_NO_MOVE_VIEW)
20 : #define NS_FRAME_NO_SIZE_VIEW 0x0004
21 : #define NS_FRAME_NO_VISIBILITY 0x0008
22 : // Only applies to ReflowChild; if true, don't delete the next-in-flow, even
23 : // if the reflow is fully complete.
24 : #define NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD 0x0010
25 :
26 : class nsOverflowContinuationTracker;
27 :
28 : // Some macros for container classes to do sanity checking on
29 : // width/height/x/y values computed during reflow.
30 : // NOTE: AppUnitsPerCSSPixel value hardwired here to remove the
31 : // dependency on nsDeviceContext.h. It doesn't matter if it's a
32 : // little off.
33 : #ifdef DEBUG
34 : // 10 million pixels, converted to app units. Note that this a bit larger
35 : // than 1/4 of nscoord_MAX. So, if any content gets to be this large, we're
36 : // definitely in danger of grazing up against nscoord_MAX; hence, it's CRAZY.
37 : #define CRAZY_COORD (10000000*60)
38 : #define CRAZY_SIZE(_x) (((_x) < -CRAZY_COORD) || ((_x) > CRAZY_COORD))
39 : #endif
40 :
41 : /**
42 : * Implementation of a container frame.
43 : */
44 : class nsContainerFrame : public nsSplittableFrame
45 : {
46 : public:
47 : NS_DECL_ABSTRACT_FRAME(nsContainerFrame)
48 : NS_DECL_QUERYFRAME_TARGET(nsContainerFrame)
49 : NS_DECL_QUERYFRAME
50 :
51 : // nsIFrame overrides
52 : virtual void Init(nsIContent* aContent,
53 : nsContainerFrame* aParent,
54 : nsIFrame* aPrevInFlow) override;
55 1093 : virtual nsContainerFrame* GetContentInsertionFrame() override
56 : {
57 1093 : return this;
58 : }
59 :
60 : virtual const nsFrameList& GetChildList(ChildListID aList) const override;
61 : virtual void GetChildLists(nsTArray<ChildList>* aLists) const override;
62 : virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
63 : virtual void ChildIsDirty(nsIFrame* aChild) override;
64 :
65 : virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) override;
66 : virtual FrameSearchResult
67 : PeekOffsetCharacter(bool aForward, int32_t* aOffset,
68 : PeekOffsetCharacterOptions aOptions =
69 : PeekOffsetCharacterOptions()) override;
70 :
71 : virtual nsresult AttributeChanged(int32_t aNameSpaceID,
72 : nsIAtom* aAttribute,
73 : int32_t aModType) override;
74 :
75 : #ifdef DEBUG_FRAME_DUMP
76 : void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const override;
77 : #endif
78 :
79 : // nsContainerFrame methods
80 :
81 : /**
82 : * Called to set the initial list of frames. This happens after the frame
83 : * has been initialized.
84 : *
85 : * This is only called once for a given child list, and won't be called
86 : * at all for child lists with no initial list of frames.
87 : *
88 : * @param aListID the child list identifier.
89 : * @param aChildList list of child frames. Each of the frames has its
90 : * NS_FRAME_IS_DIRTY bit set. Must not be empty.
91 : * This method cannot handle the child list returned by
92 : * GetAbsoluteListID().
93 : * @see #Init()
94 : */
95 : virtual void SetInitialChildList(ChildListID aListID,
96 : nsFrameList& aChildList);
97 :
98 : /**
99 : * This method is responsible for appending frames to the frame
100 : * list. The implementation should append the frames to the specified
101 : * child list and then generate a reflow command.
102 : *
103 : * @param aListID the child list identifier.
104 : * @param aFrameList list of child frames to append. Each of the frames has
105 : * its NS_FRAME_IS_DIRTY bit set. Must not be empty.
106 : */
107 : virtual void AppendFrames(ChildListID aListID, nsFrameList& aFrameList);
108 :
109 : /**
110 : * This method is responsible for inserting frames into the frame
111 : * list. The implementation should insert the new frames into the specified
112 : * child list and then generate a reflow command.
113 : *
114 : * @param aListID the child list identifier.
115 : * @param aPrevFrame the frame to insert frames <b>after</b>
116 : * @param aFrameList list of child frames to insert <b>after</b> aPrevFrame.
117 : * Each of the frames has its NS_FRAME_IS_DIRTY bit set
118 : */
119 : virtual void InsertFrames(ChildListID aListID,
120 : nsIFrame* aPrevFrame,
121 : nsFrameList& aFrameList);
122 :
123 : /**
124 : * This method is responsible for removing a frame in the frame
125 : * list. The implementation should do something with the removed frame
126 : * and then generate a reflow command. The implementation is responsible
127 : * for destroying aOldFrame (the caller mustn't destroy aOldFrame).
128 : *
129 : * @param aListID the child list identifier.
130 : * @param aOldFrame the frame to remove
131 : */
132 : virtual void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame);
133 :
134 : /**
135 : * Helper method to create next-in-flows if necessary. If aFrame
136 : * already has a next-in-flow then this method does
137 : * nothing. Otherwise, a new continuation frame is created and
138 : * linked into the flow. In addition, the new frame is inserted
139 : * into the principal child list after aFrame.
140 : * @note calling this method on a block frame is illegal. Use
141 : * nsBlockFrame::CreateContinuationFor() instead.
142 : * @return the next-in-flow <b>if and only if</b> one is created. If
143 : * a next-in-flow already exists, nullptr will be returned.
144 : */
145 : nsIFrame* CreateNextInFlow(nsIFrame* aFrame);
146 :
147 : /**
148 : * Delete aNextInFlow and its next-in-flows.
149 : * @param aDeletingEmptyFrames if set, then the reflow for aNextInFlow's
150 : * content was complete before aNextInFlow, so aNextInFlow and its
151 : * next-in-flows no longer map any real content.
152 : */
153 : virtual void DeleteNextInFlowChild(nsIFrame* aNextInFlow,
154 : bool aDeletingEmptyFrames);
155 :
156 : // Positions the frame's view based on the frame's origin
157 : static void PositionFrameView(nsIFrame* aKidFrame);
158 :
159 : static nsresult ReparentFrameView(nsIFrame* aChildFrame,
160 : nsIFrame* aOldParentFrame,
161 : nsIFrame* aNewParentFrame);
162 :
163 : static nsresult ReparentFrameViewList(const nsFrameList& aChildFrameList,
164 : nsIFrame* aOldParentFrame,
165 : nsIFrame* aNewParentFrame);
166 :
167 : // Set the view's size and position after its frame has been reflowed.
168 : //
169 : // Flags:
170 : // NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
171 : // don't want to automatically sync the frame and view
172 : // NS_FRAME_NO_SIZE_VIEW - don't size the view
173 : static void SyncFrameViewAfterReflow(nsPresContext* aPresContext,
174 : nsIFrame* aFrame,
175 : nsView* aView,
176 : const nsRect& aVisualOverflowArea,
177 : uint32_t aFlags = 0);
178 :
179 : // Syncs properties to the top level view and window, like transparency and
180 : // shadow.
181 : // The SET_ASYNC indicates that the actual nsIWidget calls to sync the window
182 : // properties should be done async.
183 : enum {
184 : SET_ASYNC = 0x01,
185 : };
186 : static void SyncWindowProperties(nsPresContext* aPresContext,
187 : nsIFrame* aFrame,
188 : nsView* aView,
189 : gfxContext* aRC,
190 : uint32_t aFlags);
191 :
192 : /**
193 : * Converts the minimum and maximum sizes given in inner window app units to
194 : * outer window device pixel sizes and assigns these constraints to the widget.
195 : *
196 : * @param aPresContext pres context
197 : * @param aWidget widget for this frame
198 : * @param minimum size of the window in app units
199 : * @param maxmimum size of the window in app units
200 : */
201 : static void SetSizeConstraints(nsPresContext* aPresContext,
202 : nsIWidget* aWidget,
203 : const nsSize& aMinSize,
204 : const nsSize& aMaxSize);
205 :
206 : // Used by both nsInlineFrame and nsFirstLetterFrame.
207 : void DoInlineIntrinsicISize(gfxContext *aRenderingContext,
208 : InlineIntrinsicISizeData *aData,
209 : nsLayoutUtils::IntrinsicISizeType aType);
210 :
211 : /**
212 : * This is the CSS block concept of computing 'auto' widths, which most
213 : * classes derived from nsContainerFrame want.
214 : */
215 : virtual mozilla::LogicalSize
216 : ComputeAutoSize(gfxContext* aRenderingContext,
217 : mozilla::WritingMode aWM,
218 : const mozilla::LogicalSize& aCBSize,
219 : nscoord aAvailableISize,
220 : const mozilla::LogicalSize& aMargin,
221 : const mozilla::LogicalSize& aBorder,
222 : const mozilla::LogicalSize& aPadding,
223 : ComputeSizeFlags aFlags) override;
224 :
225 : /**
226 : * Positions aChildFrame and its view (if requested), and then calls Reflow().
227 : * If the reflow status after reflowing the child is FULLY_COMPLETE then any
228 : * next-in-flows are deleted using DeleteNextInFlowChild().
229 : *
230 : * @param aContainerSize size of the border-box of the containing frame
231 : *
232 : * Flags:
233 : * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
234 : * don't want to automatically sync the frame and view
235 : * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aPos is ignored in this
236 : * case. Also implies NS_FRAME_NO_MOVE_VIEW
237 : */
238 : void ReflowChild(nsIFrame* aChildFrame,
239 : nsPresContext* aPresContext,
240 : ReflowOutput& aDesiredSize,
241 : const ReflowInput& aReflowInput,
242 : const mozilla::WritingMode& aWM,
243 : const mozilla::LogicalPoint& aPos,
244 : const nsSize& aContainerSize,
245 : uint32_t aFlags,
246 : nsReflowStatus& aStatus,
247 : nsOverflowContinuationTracker* aTracker = nullptr);
248 :
249 : /**
250 : * The second half of frame reflow. Does the following:
251 : * - sets the frame's bounds
252 : * - sizes and positions (if requested) the frame's view. If the frame's final
253 : * position differs from the current position and the frame itself does not
254 : * have a view, then any child frames with views are positioned so they stay
255 : * in sync
256 : * - sets the view's visibility, opacity, content transparency, and clip
257 : * - invoked the DidReflow() function
258 : *
259 : * @param aContainerSize size of the border-box of the containing frame
260 : *
261 : * Flags:
262 : * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aPos is ignored in this
263 : * case. Also implies NS_FRAME_NO_MOVE_VIEW
264 : * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
265 : * don't want to automatically sync the frame and view
266 : * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
267 : */
268 : static void FinishReflowChild(nsIFrame* aKidFrame,
269 : nsPresContext* aPresContext,
270 : const ReflowOutput& aDesiredSize,
271 : const ReflowInput* aReflowInput,
272 : const mozilla::WritingMode& aWM,
273 : const mozilla::LogicalPoint& aPos,
274 : const nsSize& aContainerSize,
275 : uint32_t aFlags);
276 :
277 : //XXX temporary: hold on to a copy of the old physical versions of
278 : // ReflowChild and FinishReflowChild so that we can convert callers
279 : // incrementally.
280 : void ReflowChild(nsIFrame* aKidFrame,
281 : nsPresContext* aPresContext,
282 : ReflowOutput& aDesiredSize,
283 : const ReflowInput& aReflowInput,
284 : nscoord aX,
285 : nscoord aY,
286 : uint32_t aFlags,
287 : nsReflowStatus& aStatus,
288 : nsOverflowContinuationTracker* aTracker = nullptr);
289 :
290 : static void FinishReflowChild(nsIFrame* aKidFrame,
291 : nsPresContext* aPresContext,
292 : const ReflowOutput& aDesiredSize,
293 : const ReflowInput* aReflowInput,
294 : nscoord aX,
295 : nscoord aY,
296 : uint32_t aFlags);
297 :
298 : static void PositionChildViews(nsIFrame* aFrame);
299 :
300 : // ==========================================================================
301 : /* Overflow containers are continuation frames that hold overflow. They
302 : * are created when the frame runs out of computed height, but still has
303 : * too much content to fit in the availableHeight. The parent creates a
304 : * continuation as usual, but marks it as NS_FRAME_IS_OVERFLOW_CONTAINER
305 : * and adds it to its next-in-flow's overflow container list, either by
306 : * adding it directly or by putting it in its own excess overflow containers
307 : * list (to be drained by the next-in-flow when it calls
308 : * ReflowOverflowContainerChildren). The parent continues reflow as if
309 : * the frame was complete once it ran out of computed height, but returns a
310 : * reflow status with either IsIncomplete() or IsOverflowIncomplete() equal
311 : * to true to request a next-in-flow. The parent's next-in-flow is then
312 : * responsible for calling ReflowOverflowContainerChildren to (drain and)
313 : * reflow these overflow continuations. Overflow containers do not affect
314 : * other frames' size or position during reflow (but do affect their
315 : * parent's overflow area).
316 : *
317 : * Overflow container continuations are different from normal continuations
318 : * in that
319 : * - more than one child of the frame can have its next-in-flow broken
320 : * off and pushed into the frame's next-in-flow
321 : * - new continuations may need to be spliced into the middle of the list
322 : * or deleted continuations slipped out
323 : * e.g. A, B, C are all fixed-size containers on one page, all have
324 : * overflow beyond availableHeight, and content is dynamically added
325 : * and removed from B
326 : * As a result, it is not possible to simply prepend the new continuations
327 : * to the old list as with the overflowProperty mechanism. To avoid
328 : * complicated list splicing, the code assumes only one overflow containers
329 : * list exists for a given frame: either its own overflowContainersProperty
330 : * or its prev-in-flow's excessOverflowContainersProperty, not both.
331 : *
332 : * The nsOverflowContinuationTracker helper class should be used for tracking
333 : * overflow containers and adding them to the appropriate list.
334 : * See nsBlockFrame::Reflow for a sample implementation.
335 : */
336 :
337 : friend class nsOverflowContinuationTracker;
338 :
339 : typedef void (*ChildFrameMerger)(nsFrameList& aDest, nsFrameList& aSrc,
340 : nsContainerFrame* aParent);
341 0 : static inline void DefaultChildFrameMerge(nsFrameList& aDest,
342 : nsFrameList& aSrc,
343 : nsContainerFrame* aParent)
344 : {
345 0 : aDest.AppendFrames(nullptr, aSrc);
346 0 : }
347 :
348 : /**
349 : * Reflow overflow container children. They are invisible to normal reflow
350 : * (i.e. don't affect sizing or placement of other children) and inherit
351 : * width and horizontal position from their prev-in-flow.
352 : *
353 : * This method
354 : * 1. Pulls excess overflow containers from the prev-in-flow and adds
355 : * them to our overflow container list
356 : * 2. Reflows all our overflow container kids
357 : * 3. Expands aOverflowRect as necessary to accomodate these children.
358 : * 4. Sets aStatus's mOverflowIncomplete flag (along with
359 : * mNextInFlowNeedsReflow as necessary) if any overflow children
360 : * are incomplete and
361 : * 5. Prepends a list of their continuations to our excess overflow
362 : * container list, to be drained into our next-in-flow when it is
363 : * reflowed.
364 : *
365 : * The caller is responsible for tracking any new overflow container
366 : * continuations it makes, removing them from its child list, and
367 : * making sure they are stored properly in the overflow container lists.
368 : * The nsOverflowContinuationTracker helper class should be used for this.
369 : *
370 : * @param aFlags is passed through to ReflowChild
371 : * @param aMergeFunc is passed to DrainExcessOverflowContainersList
372 : */
373 : void ReflowOverflowContainerChildren(nsPresContext* aPresContext,
374 : const ReflowInput& aReflowInput,
375 : nsOverflowAreas& aOverflowRects,
376 : uint32_t aFlags,
377 : nsReflowStatus& aStatus,
378 : ChildFrameMerger aMergeFunc =
379 : DefaultChildFrameMerge);
380 :
381 : /**
382 : * Move any frames on our overflow list to the end of our principal list.
383 : * @return true if there were any overflow frames
384 : */
385 : virtual bool DrainSelfOverflowList() override;
386 :
387 :
388 : /**
389 : * Move all frames on our prev-in-flow's and our own ExcessOverflowContainers
390 : * lists to our OverflowContainers list. If there are frames on multiple
391 : * lists they are merged using aMergeFunc.
392 : * @return a pointer to our OverflowContainers list, if any
393 : */
394 : nsFrameList* DrainExcessOverflowContainersList(ChildFrameMerger aMergeFunc =
395 : DefaultChildFrameMerge);
396 :
397 : /**
398 : * Removes aChild without destroying it and without requesting reflow.
399 : * Continuations are not affected. Checks the principal and overflow lists,
400 : * and also the [excess] overflow containers lists if the frame bit
401 : * NS_FRAME_IS_OVERFLOW_CONTAINER is set. It does not check any other lists.
402 : * Returns NS_ERROR_UNEXPECTED if aChild wasn't found on any of the lists
403 : * mentioned above.
404 : */
405 : virtual nsresult StealFrame(nsIFrame* aChild);
406 :
407 : /**
408 : * Removes the next-siblings of aChild without destroying them and without
409 : * requesting reflow. Checks the principal and overflow lists (not
410 : * overflow containers / excess overflow containers). Does not check any
411 : * other auxiliary lists.
412 : * @param aChild a child frame or nullptr
413 : * @return If aChild is non-null, the next-siblings of aChild, if any.
414 : * If aChild is null, all child frames on the principal list, if any.
415 : */
416 : nsFrameList StealFramesAfter(nsIFrame* aChild);
417 :
418 : /**
419 : * Add overflow containers to the display list
420 : */
421 : void DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
422 : const nsRect& aDirtyRect,
423 : const nsDisplayListSet& aLists);
424 :
425 : /**
426 : * Builds display lists for the children. The background
427 : * of each child is placed in the Content() list (suitable for inline
428 : * children and other elements that behave like inlines,
429 : * but not for in-flow block children of blocks). DOES NOT
430 : * paint the background/borders/outline of this frame. This should
431 : * probably be avoided and eventually removed. It's currently here
432 : * to emulate what nsContainerFrame::Paint did.
433 : */
434 : virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
435 : const nsRect& aDirtyRect,
436 : const nsDisplayListSet& aLists) override;
437 :
438 66 : static void PlaceFrameView(nsIFrame* aFrame)
439 : {
440 66 : if (aFrame->HasView())
441 0 : nsContainerFrame::PositionFrameView(aFrame);
442 : else
443 66 : nsContainerFrame::PositionChildViews(aFrame);
444 66 : }
445 :
446 : static bool FrameStartsCounterScope(nsIFrame* aFrame);
447 :
448 : /**
449 : * Renumber the list of the counter scope started by this frame, if any.
450 : * If this returns true, the frame it's called on should get the
451 : * NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly
452 : * if it's already in reflow, or via calling FrameNeedsReflow() to schedule
453 : * a reflow.
454 : */
455 : bool RenumberList();
456 :
457 : /**
458 : * Renumber this frame if it's a list-item, then call RenumberChildFrames.
459 : * @param aOrdinal Ordinal number to start counting at.
460 : * Modifies this number for each associated list
461 : * item. Changes in the numbering due to setting
462 : * the |value| attribute are included if |aForCounting|
463 : * is false. This value is both an input and output
464 : * of this function, with the output value being the
465 : * next ordinal number to be used.
466 : * @param aDepth Current depth in frame tree from root list element.
467 : * @param aIncrement Amount to increase by after visiting each associated
468 : * list item, unless overridden by |value|.
469 : * @param aForCounting Whether we are counting the elements or actually
470 : * restyling them. When true, this simply visits all children,
471 : * ignoring |<li value="..">| changes, effectively counting them
472 : * and storing the result in |aOrdinal|. This is useful for
473 : * |<ol reversed>|, where we need to count the number of
474 : * applicable child list elements before numbering. When false,
475 : * this will restyle all applicable descendants, and the next
476 : * ordinal value will be stored in |aOrdinal|, taking into account
477 : * any changes from |<li value="..">|.
478 : */
479 : bool RenumberFrameAndDescendants(int32_t* aOrdinal,
480 : int32_t aDepth,
481 : int32_t aIncrement,
482 : bool aForCounting) override;
483 : /**
484 : * Renumber the child frames using RenumberFrameAndDescendants.
485 : * See RenumberFrameAndDescendants for description of parameters.
486 : */
487 : virtual bool RenumberChildFrames(int32_t* aOrdinal,
488 : int32_t aDepth,
489 : int32_t aIncrement,
490 : bool aForCounting);
491 :
492 : /**
493 : * Returns a CSS Box Alignment constant which the caller can use to align
494 : * the absolutely-positioned child (whose ReflowInput is aChildRI) within
495 : * a CSS Box Alignment area associated with this container.
496 : *
497 : * The lower 8 bits of the returned value are guaranteed to form a valid
498 : * argument for CSSAlignUtils::AlignJustifySelf(). (The upper 8 bits may
499 : * encode an <overflow-position>.)
500 : *
501 : * NOTE: This default nsContainerFrame implementation is a stub, and isn't
502 : * meant to be called. Subclasses must provide their own implementations, if
503 : * they use CSS Box Alignment to determine the static position of their
504 : * absolutely-positioned children. (Though: if subclasses share enough code,
505 : * maybe this nsContainerFrame impl should include some shared code.)
506 : *
507 : * @param aChildRI A ReflowInput for the positioned child frame that's being
508 : * aligned.
509 : * @param aLogicalAxis The axis (of this container frame) in which the caller
510 : * would like to align the child frame.
511 : */
512 : virtual uint16_t CSSAlignmentForAbsPosChild(
513 : const ReflowInput& aChildRI,
514 : mozilla::LogicalAxis aLogicalAxis) const;
515 :
516 : #define NS_DECLARE_FRAME_PROPERTY_FRAMELIST(prop) \
517 : NS_DECLARE_FRAME_PROPERTY_WITH_DTOR_NEVER_CALLED(prop, nsFrameList)
518 :
519 : typedef PropertyDescriptor<nsFrameList> FrameListPropertyDescriptor;
520 :
521 2386 : NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowProperty)
522 2354 : NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowContainersProperty)
523 2539 : NS_DECLARE_FRAME_PROPERTY_FRAMELIST(ExcessOverflowContainersProperty)
524 2376 : NS_DECLARE_FRAME_PROPERTY_FRAMELIST(BackdropProperty)
525 :
526 : // Only really used on nsBlockFrame instances, but the caller thinks it could
527 : // have arbitrary nsContainerFrames.
528 0 : NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(FirstLetterProperty, nsIFrame)
529 :
530 0 : void SetHasFirstLetterChild()
531 : {
532 0 : mHasFirstLetterChild = true;
533 0 : }
534 :
535 0 : void ClearHasFirstLetterChild()
536 : {
537 0 : mHasFirstLetterChild = false;
538 0 : }
539 :
540 : #ifdef DEBUG
541 : // Use this to suppress the CRAZY_SIZE assertions.
542 75 : NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(DebugReflowingWithInfiniteISize, bool)
543 75 : bool IsCrazySizeAssertSuppressed() const {
544 75 : return GetProperty(DebugReflowingWithInfiniteISize());
545 : }
546 : #endif
547 :
548 : protected:
549 448 : nsContainerFrame(nsStyleContext* aContext, ClassID aID)
550 448 : : nsSplittableFrame(aContext, aID)
551 448 : {}
552 :
553 : ~nsContainerFrame();
554 :
555 : /**
556 : * Helper for DestroyFrom. DestroyAbsoluteFrames is called before
557 : * destroying frames on lists that can contain placeholders.
558 : * Derived classes must do that too, if they destroy such frame lists.
559 : * See nsBlockFrame::DestroyFrom for an example.
560 : */
561 : void DestroyAbsoluteFrames(nsIFrame* aDestructRoot);
562 :
563 : /**
564 : * Helper for StealFrame. Returns true if aChild was removed from its list.
565 : */
566 : bool MaybeStealOverflowContainerFrame(nsIFrame* aChild);
567 :
568 : /**
569 : * Builds a display list for non-block children that behave like
570 : * inlines. This puts the background of each child into the
571 : * Content() list (suitable for inline children but not for
572 : * in-flow block children of blocks).
573 : * @param aForcePseudoStack forces each child into a pseudo-stacking-context
574 : * so its background and all other display items (except for positioned
575 : * display items) go into the Content() list.
576 : */
577 : void BuildDisplayListForNonBlockChildren(nsDisplayListBuilder* aBuilder,
578 : const nsRect& aDirtyRect,
579 : const nsDisplayListSet& aLists,
580 : uint32_t aFlags = 0);
581 :
582 : /**
583 : * A version of BuildDisplayList that use DISPLAY_CHILD_INLINE.
584 : * Intended as a convenience for derived classes.
585 : */
586 0 : void BuildDisplayListForInline(nsDisplayListBuilder* aBuilder,
587 : const nsRect& aDirtyRect,
588 : const nsDisplayListSet& aLists) {
589 0 : DisplayBorderBackgroundOutline(aBuilder, aLists);
590 : BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists,
591 0 : DISPLAY_CHILD_INLINE);
592 0 : }
593 :
594 :
595 : // ==========================================================================
596 : /* Overflow Frames are frames that did not fit and must be pulled by
597 : * our next-in-flow during its reflow. (The same concept for overflow
598 : * containers is called "excess frames". We should probably make the
599 : * names match.)
600 : */
601 :
602 : /**
603 : * Get the frames on the overflow list. Can return null if there are no
604 : * overflow frames. The caller does NOT take ownership of the list; it's
605 : * still owned by this frame. A non-null return value indicates that the
606 : * list is nonempty.
607 : */
608 : inline nsFrameList* GetOverflowFrames() const;
609 :
610 : /**
611 : * As GetOverflowFrames, but removes the overflow frames property. The
612 : * caller is responsible for deleting nsFrameList and either passing
613 : * ownership of the frames to someone else or destroying the frames.
614 : * A non-null return value indicates that the list is nonempty. The
615 : * recommended way to use this function it to assign its return value
616 : * into an AutoFrameListPtr.
617 : */
618 : inline nsFrameList* StealOverflowFrames();
619 :
620 : /**
621 : * Set the overflow list. aOverflowFrames must not be an empty list.
622 : */
623 : void SetOverflowFrames(const nsFrameList& aOverflowFrames);
624 :
625 : /**
626 : * Destroy the overflow list, which must be empty.
627 : */
628 : inline void DestroyOverflowList();
629 :
630 : /**
631 : * Moves any frames on both the prev-in-flow's overflow list and the
632 : * receiver's overflow to the receiver's child list.
633 : *
634 : * Resets the overlist pointers to nullptr, and updates the receiver's child
635 : * count and content mapping.
636 : *
637 : * @return true if any frames were moved and false otherwise
638 : */
639 : bool MoveOverflowToChildList();
640 :
641 : /**
642 : * Push aFromChild and its next siblings to the next-in-flow. Change
643 : * the geometric parent of each frame that's pushed. If there is no
644 : * next-in-flow the frames are placed on the overflow list (and the
645 : * geometric parent is left unchanged).
646 : *
647 : * Updates the next-in-flow's child count. Does <b>not</b> update the
648 : * pusher's child count.
649 : *
650 : * @param aFromChild the first child frame to push. It is disconnected from
651 : * aPrevSibling
652 : * @param aPrevSibling aFromChild's previous sibling. Must not be null.
653 : * It's an error to push a parent's first child frame
654 : */
655 : void PushChildren(nsIFrame* aFromChild, nsIFrame* aPrevSibling);
656 :
657 : // ==========================================================================
658 : /*
659 : * Convenience methods for traversing continuations
660 : */
661 :
662 : struct ContinuationTraversingState
663 : {
664 : nsContainerFrame* mNextInFlow;
665 0 : explicit ContinuationTraversingState(nsContainerFrame* aFrame)
666 0 : : mNextInFlow(static_cast<nsContainerFrame*>(aFrame->GetNextInFlow()))
667 0 : { }
668 : };
669 :
670 : /**
671 : * Find the first frame that is a child of this frame's next-in-flows,
672 : * considering both their principal child lists and overflow lists.
673 : */
674 : nsIFrame* GetNextInFlowChild(ContinuationTraversingState& aState,
675 : bool* aIsInOverflow = nullptr);
676 :
677 : /**
678 : * Remove the result of GetNextInFlowChild from its current parent and
679 : * append it to this frame's principal child list.
680 : */
681 : nsIFrame* PullNextInFlowChild(ContinuationTraversingState& aState);
682 :
683 : // ==========================================================================
684 : /*
685 : * Convenience methods for nsFrameLists stored in the
686 : * PresContext's proptable
687 : */
688 :
689 : /**
690 : * Get the PresContext-stored nsFrameList named aPropID for this frame.
691 : * May return null.
692 : */
693 : nsFrameList* GetPropTableFrames(FrameListPropertyDescriptor aProperty) const;
694 :
695 : /**
696 : * Remove and return the PresContext-stored nsFrameList named aPropID for
697 : * this frame. May return null.
698 : */
699 : nsFrameList* RemovePropTableFrames(FrameListPropertyDescriptor aProperty);
700 :
701 : /**
702 : * Set the PresContext-stored nsFrameList named aPropID for this frame
703 : * to the given aFrameList, which must not be null.
704 : */
705 : void SetPropTableFrames(nsFrameList* aFrameList,
706 : FrameListPropertyDescriptor aProperty);
707 :
708 : /**
709 : * Safely destroy the frames on the nsFrameList stored on aProp for this
710 : * frame then remove the property and delete the frame list.
711 : * Nothing happens if the property doesn't exist.
712 : */
713 : void SafelyDestroyFrameListProp(nsIFrame* aDestructRoot,
714 : nsIPresShell* aPresShell,
715 : FrameListPropertyDescriptor aProp);
716 :
717 : // ==========================================================================
718 :
719 : // Helper used by Progress and Meter frames. Returns true if the bar should
720 : // be rendered vertically, based on writing-mode and -moz-orient properties.
721 : bool ResolvedOrientationIsVertical();
722 :
723 : // ==========================================================================
724 :
725 : nsFrameList mFrames;
726 : };
727 :
728 : // ==========================================================================
729 : /* The out-of-flow-related code below is for a hacky way of splitting
730 : * absolutely-positioned frames. Basically what we do is split the frame
731 : * in nsAbsoluteContainingBlock and pretend the continuation is an overflow
732 : * container. This isn't an ideal solution, but it lets us print the content
733 : * at least. See bug 154892.
734 : */
735 :
736 : #define IS_TRUE_OVERFLOW_CONTAINER(frame) \
737 : ( (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) \
738 : && !( (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && \
739 : frame->IsAbsolutelyPositioned() ) )
740 : //XXXfr This check isn't quite correct, because it doesn't handle cases
741 : // where the out-of-flow has overflow.. but that's rare.
742 : // We'll need to revisit the way abspos continuations are handled later
743 : // for various reasons, this detail is one of them. See bug 154892
744 :
745 : /**
746 : * Helper class for tracking overflow container continuations during reflow.
747 : *
748 : * A frame is related to two sets of overflow containers: those that /are/
749 : * its own children, and those that are /continuations/ of its children.
750 : * This tracker walks through those continuations (the frame's NIF's children)
751 : * and their prev-in-flows (a subset of the frame's normal and overflow
752 : * container children) in parallel. It allows the reflower to synchronously
753 : * walk its overflow continuations while it loops through and reflows its
754 : * children. This makes it possible to insert new continuations at the correct
755 : * place in the overflow containers list.
756 : *
757 : * The reflower is expected to loop through its children in the same order it
758 : * looped through them the last time (if there was a last time).
759 : * For each child, the reflower should either
760 : * - call Skip for the child if was not reflowed in this pass
761 : * - call Insert for the overflow continuation if the child was reflowed
762 : * but has incomplete overflow
763 : * - call Finished for the child if it was reflowed in this pass but
764 : * is either complete or has a normal next-in-flow. This call can
765 : * be skipped if the child did not previously have an overflow
766 : * continuation.
767 : */
768 : class nsOverflowContinuationTracker {
769 : public:
770 : /**
771 : * Initializes an nsOverflowContinuationTracker to help track overflow
772 : * continuations of aFrame's children. Typically invoked on 'this'.
773 : *
774 : * aWalkOOFFrames determines whether the walker skips out-of-flow frames
775 : * or skips non-out-of-flow frames.
776 : *
777 : * Don't set aSkipOverflowContainerChildren to false unless you plan
778 : * to walk your own overflow container children. (Usually they are handled
779 : * by calling ReflowOverflowContainerChildren.) aWalkOOFFrames is ignored
780 : * if aSkipOverflowContainerChildren is false.
781 : */
782 : nsOverflowContinuationTracker(nsContainerFrame* aFrame,
783 : bool aWalkOOFFrames,
784 : bool aSkipOverflowContainerChildren = true);
785 : /**
786 : * This function adds an overflow continuation to our running list and
787 : * sets its NS_FRAME_IS_OVERFLOW_CONTAINER flag.
788 : *
789 : * aReflowStatus should preferably be specific to the recently-reflowed
790 : * child and not influenced by any of its siblings' statuses. This
791 : * function sets the NS_FRAME_IS_DIRTY bit on aOverflowCont if it needs
792 : * to be reflowed. (Its need for reflow depends on changes to its
793 : * prev-in-flow, not to its parent--for whom it is invisible, reflow-wise.)
794 : *
795 : * The caller MUST disconnect the frame from its parent's child list
796 : * if it was not previously an NS_FRAME_IS_OVERFLOW_CONTAINER (because
797 : * StealFrame is much more inefficient than disconnecting in place
798 : * during Reflow, which the caller is able to do but we are not).
799 : *
800 : * The caller MUST NOT disconnect the frame from its parent's
801 : * child list if it is already an NS_FRAME_IS_OVERFLOW_CONTAINER.
802 : * (In this case we will disconnect and reconnect it ourselves.)
803 : */
804 : nsresult Insert(nsIFrame* aOverflowCont,
805 : nsReflowStatus& aReflowStatus);
806 : /**
807 : * Begin/EndFinish() must be called for each child that is reflowed
808 : * but no longer has an overflow continuation. (It may be called for
809 : * other children, but in that case has no effect.) It increments our
810 : * walker and makes sure we drop any dangling pointers to its
811 : * next-in-flow. This function MUST be called before stealing or
812 : * deleting aChild's next-in-flow.
813 : * The AutoFinish helper object does that for you. Use it like so:
814 : * if (kidNextInFlow) {
815 : * nsOverflowContinuationTracker::AutoFinish fini(tracker, kid);
816 : * ... DeleteNextInFlowChild/StealFrame(kidNextInFlow) here ...
817 : * }
818 : */
819 : class MOZ_RAII AutoFinish {
820 : public:
821 0 : AutoFinish(nsOverflowContinuationTracker* aTracker, nsIFrame* aChild)
822 0 : : mTracker(aTracker), mChild(aChild)
823 : {
824 0 : if (mTracker) mTracker->BeginFinish(mChild);
825 0 : }
826 0 : ~AutoFinish()
827 0 : {
828 0 : if (mTracker) mTracker->EndFinish(mChild);
829 0 : }
830 : private:
831 : nsOverflowContinuationTracker* mTracker;
832 : nsIFrame* mChild;
833 : };
834 :
835 : /**
836 : * This function should be called for each child that isn't reflowed.
837 : * It increments our walker and sets the mOverflowIncomplete
838 : * reflow flag if it encounters an overflow continuation so that our
839 : * next-in-flow doesn't get prematurely deleted. It MUST be called on
840 : * each unreflowed child that has an overflow container continuation;
841 : * it MAY be called on other children, but it isn't necessary (doesn't
842 : * do anything).
843 : */
844 66 : void Skip(nsIFrame* aChild, nsReflowStatus& aReflowStatus)
845 : {
846 66 : NS_PRECONDITION(aChild, "null ptr");
847 66 : if (aChild == mSentry) {
848 0 : StepForward();
849 0 : if (aReflowStatus.IsComplete()) {
850 0 : aReflowStatus.SetOverflowIncomplete();
851 : }
852 : }
853 66 : }
854 :
855 : private:
856 :
857 : /**
858 : * @see class AutoFinish
859 : */
860 : void BeginFinish(nsIFrame* aChild);
861 : void EndFinish(nsIFrame* aChild);
862 :
863 : void SetupOverflowContList();
864 : void SetUpListWalker();
865 : void StepForward();
866 :
867 : /* We hold a pointer to either the next-in-flow's overflow containers list
868 : or, if that doesn't exist, our frame's excess overflow containers list.
869 : We need to make sure that we drop that pointer if the list becomes
870 : empty and is deleted elsewhere. */
871 : nsFrameList* mOverflowContList;
872 : /* We hold a pointer to the most recently-reflowed child that has an
873 : overflow container next-in-flow. We do this because it's a known
874 : good point; this pointer won't be deleted on us. We can use it to
875 : recover our place in the list. */
876 : nsIFrame* mPrevOverflowCont;
877 : /* This is a pointer to the next overflow container's prev-in-flow, which
878 : is (or should be) a child of our frame. When we hit this, we will need
879 : to increment this walker to the next overflow container. */
880 : nsIFrame* mSentry;
881 : /* Parent of all frames in mOverflowContList. If our mOverflowContList
882 : is an excessOverflowContainersProperty, or null, then this is our frame
883 : (the frame that was passed in to our constructor). Otherwise this is
884 : that frame's next-in-flow, and our mOverflowContList is mParent's
885 : overflowContainersProperty */
886 : nsContainerFrame* mParent;
887 : /* Tells SetUpListWalker whether or not to walk us past any continuations
888 : of overflow containers. aWalkOOFFrames is ignored when this is false. */
889 : bool mSkipOverflowContainerChildren;
890 : /* Tells us whether to pay attention to OOF frames or non-OOF frames */
891 : bool mWalkOOFFrames;
892 : };
893 :
894 : inline
895 : nsFrameList*
896 0 : nsContainerFrame::GetOverflowFrames() const
897 : {
898 0 : nsFrameList* list = GetProperty(OverflowProperty());
899 0 : NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
900 0 : return list;
901 : }
902 :
903 : inline
904 : nsFrameList*
905 32 : nsContainerFrame::StealOverflowFrames()
906 : {
907 32 : nsFrameList* list = RemoveProperty(OverflowProperty());
908 32 : NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
909 32 : return list;
910 : }
911 :
912 : inline void
913 0 : nsContainerFrame::DestroyOverflowList()
914 : {
915 0 : nsFrameList* list = RemovePropTableFrames(OverflowProperty());
916 0 : MOZ_ASSERT(list && list->IsEmpty());
917 0 : list->Delete(PresContext()->PresShell());
918 0 : }
919 :
920 : #endif /* nsContainerFrame_h___ */
|