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