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