1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : // vim:cindent:ts=2:et:sw=2:
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /*
40 : * rendering object for CSS display:block, inline-block, and list-item
41 : * boxes, also used for various anonymous boxes
42 : */
43 :
44 : #ifndef nsBlockFrame_h___
45 : #define nsBlockFrame_h___
46 :
47 : #include "nsContainerFrame.h"
48 : #include "nsHTMLParts.h"
49 : #include "nsAbsoluteContainingBlock.h"
50 : #include "nsLineBox.h"
51 : #include "nsCSSPseudoElements.h"
52 : #include "nsStyleSet.h"
53 : #include "nsFloatManager.h"
54 :
55 : enum LineReflowStatus {
56 : // The line was completely reflowed and fit in available width, and we should
57 : // try to pull up content from the next line if possible.
58 : LINE_REFLOW_OK,
59 : // The line was completely reflowed and fit in available width, but we should
60 : // not try to pull up content from the next line.
61 : LINE_REFLOW_STOP,
62 : // We need to reflow the line again at its current vertical position. The
63 : // new reflow should not try to pull up any frames from the next line.
64 : LINE_REFLOW_REDO_NO_PULL,
65 : // We need to reflow the line again using the floats from its height
66 : // this reflow, since its height made it hit floats that were not
67 : // adjacent to its top.
68 : LINE_REFLOW_REDO_MORE_FLOATS,
69 : // We need to reflow the line again at a lower vertical postion where there
70 : // may be more horizontal space due to different float configuration.
71 : LINE_REFLOW_REDO_NEXT_BAND,
72 : // The line did not fit in the available vertical space. Try pushing it to
73 : // the next page or column if it's not the first line on the current page/column.
74 : LINE_REFLOW_TRUNCATED
75 : };
76 :
77 : class nsBlockReflowState;
78 : class nsBlockInFlowLineIterator;
79 : class nsBulletFrame;
80 : class nsLineBox;
81 : class nsFirstLineFrame;
82 : class nsIntervalSet;
83 :
84 : /**
85 : * Some invariants:
86 : * -- The overflow out-of-flows list contains the out-of-
87 : * flow frames whose placeholders are in the overflow list.
88 : * -- A given piece of content has at most one placeholder
89 : * frame in a block's normal child list.
90 : * -- While a block is being reflowed, and from then until
91 : * its next-in-flow is reflowed it may have a
92 : * PushedFloatProperty frame property that points to
93 : * an nsFrameList. This list contains continuations for
94 : * floats whose prev-in-flow is in the block's regular float
95 : * list and first-in-flows of floats that did not fit, but
96 : * whose placeholders are in the block or one of its
97 : * prev-in-flows.
98 : * -- In all these frame lists, if there are two frames for
99 : * the same content appearing in the list, then the frames
100 : * appear with the prev-in-flow before the next-in-flow.
101 : * -- While reflowing a block, its overflow line list
102 : * will usually be empty but in some cases will have lines
103 : * (while we reflow the block at its shrink-wrap width).
104 : * In this case any new overflowing content must be
105 : * prepended to the overflow lines.
106 : */
107 :
108 : // see nsHTMLParts.h for the public block state bits
109 :
110 : /**
111 : * Something in the block has changed that requires Bidi resolution to be
112 : * performed on the block. This flag must be either set on all blocks in a
113 : * continuation chain or none of them.
114 : */
115 : #define NS_BLOCK_NEEDS_BIDI_RESOLUTION NS_FRAME_STATE_BIT(20)
116 : #define NS_BLOCK_HAS_PUSHED_FLOATS NS_FRAME_STATE_BIT(21)
117 : #define NS_BLOCK_HAS_LINE_CURSOR NS_FRAME_STATE_BIT(24)
118 : #define NS_BLOCK_HAS_OVERFLOW_LINES NS_FRAME_STATE_BIT(25)
119 : #define NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS NS_FRAME_STATE_BIT(26)
120 :
121 : // Set on any block that has descendant frames in the normal
122 : // flow with 'clear' set to something other than 'none'
123 : // (including <BR CLEAR="..."> frames)
124 : #define NS_BLOCK_HAS_CLEAR_CHILDREN NS_FRAME_STATE_BIT(27)
125 :
126 : #define nsBlockFrameSuper nsContainerFrame
127 :
128 : /*
129 : * Base class for block and inline frames.
130 : * The block frame has an additional child list, kAbsoluteList, which
131 : * contains the absolutely positioned frames.
132 : */
133 : class nsBlockFrame : public nsBlockFrameSuper
134 : {
135 : public:
136 : NS_DECL_QUERYFRAME_TARGET(nsBlockFrame)
137 : NS_DECL_FRAMEARENA_HELPERS
138 :
139 : typedef nsLineList::iterator line_iterator;
140 : typedef nsLineList::const_iterator const_line_iterator;
141 : typedef nsLineList::reverse_iterator reverse_line_iterator;
142 : typedef nsLineList::const_reverse_iterator const_reverse_line_iterator;
143 :
144 0 : line_iterator begin_lines() { return mLines.begin(); }
145 0 : line_iterator end_lines() { return mLines.end(); }
146 0 : const_line_iterator begin_lines() const { return mLines.begin(); }
147 0 : const_line_iterator end_lines() const { return mLines.end(); }
148 : reverse_line_iterator rbegin_lines() { return mLines.rbegin(); }
149 0 : reverse_line_iterator rend_lines() { return mLines.rend(); }
150 0 : const_reverse_line_iterator rbegin_lines() const { return mLines.rbegin(); }
151 0 : const_reverse_line_iterator rend_lines() const { return mLines.rend(); }
152 0 : line_iterator line(nsLineBox* aList) { return mLines.begin(aList); }
153 0 : reverse_line_iterator rline(nsLineBox* aList) { return mLines.rbegin(aList); }
154 :
155 : friend nsIFrame* NS_NewBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags);
156 :
157 : // nsQueryFrame
158 : NS_DECL_QUERYFRAME
159 :
160 : // nsIFrame
161 : NS_IMETHOD Init(nsIContent* aContent,
162 : nsIFrame* aParent,
163 : nsIFrame* aPrevInFlow);
164 : NS_IMETHOD SetInitialChildList(ChildListID aListID,
165 : nsFrameList& aChildList);
166 : NS_IMETHOD AppendFrames(ChildListID aListID,
167 : nsFrameList& aFrameList);
168 : NS_IMETHOD InsertFrames(ChildListID aListID,
169 : nsIFrame* aPrevFrame,
170 : nsFrameList& aFrameList);
171 : NS_IMETHOD RemoveFrame(ChildListID aListID,
172 : nsIFrame* aOldFrame);
173 : virtual const nsFrameList& GetChildList(ChildListID aListID) const;
174 : virtual void GetChildLists(nsTArray<ChildList>* aLists) const;
175 : virtual nscoord GetBaseline() const;
176 : virtual nscoord GetCaretBaseline() const;
177 : virtual void DestroyFrom(nsIFrame* aDestructRoot);
178 : virtual nsSplittableType GetSplittableType() const;
179 : virtual bool IsFloatContainingBlock() const;
180 : NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
181 : const nsRect& aDirtyRect,
182 : const nsDisplayListSet& aLists);
183 : virtual void InvalidateInternal(const nsRect& aDamageRect,
184 : nscoord aX, nscoord aY, nsIFrame* aForChild,
185 : PRUint32 aFlags);
186 : virtual nsIAtom* GetType() const;
187 0 : virtual bool IsFrameOfType(PRUint32 aFlags) const
188 : {
189 : return nsContainerFrame::IsFrameOfType(aFlags &
190 : ~(nsIFrame::eCanContainOverflowContainers |
191 0 : nsIFrame::eBlockFrame));
192 : }
193 :
194 : #ifdef DEBUG
195 : NS_IMETHOD List(FILE* out, PRInt32 aIndent) const;
196 : NS_IMETHOD_(nsFrameState) GetDebugStateBits() const;
197 : NS_IMETHOD GetFrameName(nsAString& aResult) const;
198 : #endif
199 :
200 : #ifdef ACCESSIBILITY
201 : virtual already_AddRefed<nsAccessible> CreateAccessible();
202 : #endif
203 :
204 : // line cursor methods to speed up searching for the line(s)
205 : // containing a point. The basic idea is that we set the cursor
206 : // property if the lines' overflowArea.VisualOverflow().ys and
207 : // overflowArea.VisualOverflow().yMosts are non-decreasing
208 : // (considering only non-empty overflowArea.VisualOverflow()s; empty
209 : // overflowArea.VisualOverflow()s never participate in event handling
210 : // or painting), and the block has sufficient number of lines. The
211 : // cursor property points to a "recently used" line. If we get a
212 : // series of requests that work on lines
213 : // "near" the cursor, then we can find those nearby lines quickly by
214 : // starting our search at the cursor.
215 :
216 : // Clear out line cursor because we're disturbing the lines (i.e., Reflow)
217 : void ClearLineCursor();
218 : // Get the first line that might contain y-coord 'y', or nsnull if you must search
219 : // all lines. If nonnull is returned then we guarantee that the lines'
220 : // combinedArea.ys and combinedArea.yMosts are non-decreasing.
221 : // The actual line returned might not contain 'y', but if not, it is guaranteed
222 : // to be before any line which does contain 'y'.
223 : nsLineBox* GetFirstLineContaining(nscoord y);
224 : // Set the line cursor to our first line. Only call this if you
225 : // guarantee that the lines' combinedArea.ys and combinedArea.yMosts
226 : // are non-decreasing.
227 : void SetupLineCursor();
228 :
229 : virtual void ChildIsDirty(nsIFrame* aChild);
230 : virtual bool IsVisibleInSelection(nsISelection* aSelection);
231 :
232 : virtual bool IsEmpty();
233 : virtual bool CachedIsEmpty();
234 : virtual bool IsSelfEmpty();
235 :
236 : // Given that we have a bullet, does it actually draw something, i.e.,
237 : // do we have either a 'list-style-type' or 'list-style-image' that is
238 : // not 'none'?
239 : bool BulletIsEmpty() const;
240 :
241 : /**
242 : * Return the bullet text equivalent.
243 : */
244 : void GetBulletText(nsAString& aText) const;
245 :
246 : /**
247 : * Return true if there's a bullet.
248 : */
249 0 : bool HasBullet() const {
250 0 : return HasOutsideBullet() || HasInsideBullet();
251 : }
252 :
253 : virtual void MarkIntrinsicWidthsDirty();
254 : virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);
255 : virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext);
256 :
257 : virtual nsRect ComputeTightBounds(gfxContext* aContext) const;
258 :
259 : NS_IMETHOD Reflow(nsPresContext* aPresContext,
260 : nsHTMLReflowMetrics& aDesiredSize,
261 : const nsHTMLReflowState& aReflowState,
262 : nsReflowStatus& aStatus);
263 :
264 : NS_IMETHOD AttributeChanged(PRInt32 aNameSpaceID,
265 : nsIAtom* aAttribute,
266 : PRInt32 aModType);
267 :
268 : virtual nsresult StealFrame(nsPresContext* aPresContext,
269 : nsIFrame* aChild,
270 : bool aForceNormal = false);
271 :
272 : virtual void DeleteNextInFlowChild(nsPresContext* aPresContext,
273 : nsIFrame* aNextInFlow,
274 : bool aDeletingEmptyFrames);
275 :
276 : /**
277 : * Determines whether the collapsed margin carried out of the last
278 : * line includes the margin-top of a line with clearance (in which
279 : * case we must avoid collapsing that margin with our bottom margin)
280 : */
281 : bool CheckForCollapsedBottomMarginFromClearanceLine();
282 :
283 : static nsresult GetCurrentLine(nsBlockReflowState *aState, nsLineBox **aOutCurrentLine);
284 :
285 : static bool BlockIsMarginRoot(nsIFrame* aBlock);
286 : static bool BlockNeedsFloatManager(nsIFrame* aBlock);
287 :
288 : /**
289 : * Returns whether aFrame is a block frame that will wrap its contents
290 : * around floats intruding on it from the outside. (aFrame need not
291 : * be a block frame, but if it's not, the result will be false.)
292 : */
293 : static bool BlockCanIntersectFloats(nsIFrame* aFrame);
294 :
295 : /**
296 : * Returns the width that needs to be cleared past floats for blocks
297 : * that cannot intersect floats. aState must already have
298 : * GetAvailableSpace called on it for the vertical position that we
299 : * care about (which need not be its current mY)
300 : */
301 : struct ReplacedElementWidthToClear {
302 : nscoord marginLeft, borderBoxWidth, marginRight;
303 : nscoord MarginBoxWidth() const
304 : { return marginLeft + borderBoxWidth + marginRight; }
305 : };
306 : static ReplacedElementWidthToClear
307 : WidthToClearPastFloats(nsBlockReflowState& aState,
308 : const nsRect& aFloatAvailableSpace,
309 : nsIFrame* aFrame);
310 :
311 : /**
312 : * Creates a contination for aFloat and adds it to the list of overflow floats.
313 : * Also updates aState.mReflowStatus to include the float's incompleteness.
314 : * Must only be called while this block frame is in reflow.
315 : * aFloatStatus must be the float's true, unmodified reflow status.
316 : *
317 : */
318 : nsresult SplitFloat(nsBlockReflowState& aState,
319 : nsIFrame* aFloat,
320 : nsReflowStatus aFloatStatus);
321 :
322 : /**
323 : * Walks up the frame tree, starting with aCandidate, and returns the first
324 : * block frame that it encounters.
325 : */
326 : static nsBlockFrame* GetNearestAncestorBlock(nsIFrame* aCandidate);
327 :
328 0 : struct FrameLines {
329 : nsLineList mLines;
330 : nsFrameList mFrames;
331 : };
332 :
333 : protected:
334 0 : nsBlockFrame(nsStyleContext* aContext)
335 : : nsContainerFrame(aContext)
336 : , mMinWidth(NS_INTRINSIC_WIDTH_UNKNOWN)
337 0 : , mPrefWidth(NS_INTRINSIC_WIDTH_UNKNOWN)
338 : {
339 : #ifdef DEBUG
340 0 : InitDebugFlags();
341 : #endif
342 0 : }
343 : virtual ~nsBlockFrame();
344 :
345 : #ifdef DEBUG
346 : #ifdef _IMPL_NS_LAYOUT
347 0 : already_AddRefed<nsStyleContext> GetFirstLetterStyle(nsPresContext* aPresContext)
348 : {
349 : return aPresContext->StyleSet()->
350 : ProbePseudoElementStyle(mContent->AsElement(),
351 : nsCSSPseudoElements::ePseudo_firstLetter,
352 0 : mStyleContext);
353 : }
354 : #endif
355 : #endif
356 :
357 0 : nsLineBox* NewLineBox(nsIFrame* aFrame, bool aIsBlock) {
358 0 : return NS_NewLineBox(PresContext()->PresShell(), aFrame, aIsBlock);
359 : }
360 0 : nsLineBox* NewLineBox(nsLineBox* aFromLine, nsIFrame* aFrame, PRInt32 aCount) {
361 0 : return NS_NewLineBox(PresContext()->PresShell(), aFromLine, aFrame, aCount);
362 : }
363 0 : void FreeLineBox(nsLineBox* aLine) {
364 0 : aLine->Destroy(PresContext()->PresShell());
365 0 : }
366 :
367 : void TryAllLines(nsLineList::iterator* aIterator,
368 : nsLineList::iterator* aStartIterator,
369 : nsLineList::iterator* aEndIterator,
370 : bool* aInOverflowLines,
371 : FrameLines** aOverflowLines);
372 :
373 0 : void SetFlags(nsFrameState aFlags) {
374 0 : mState &= ~NS_BLOCK_FLAGS_MASK;
375 0 : mState |= aFlags;
376 0 : }
377 :
378 : /** move the frames contained by aLine by aDY
379 : * if aLine is a block, its child floats are added to the state manager
380 : */
381 : void SlideLine(nsBlockReflowState& aState,
382 : nsLineBox* aLine, nscoord aDY);
383 :
384 : virtual PRIntn GetSkipSides() const;
385 :
386 : virtual void ComputeFinalSize(const nsHTMLReflowState& aReflowState,
387 : nsBlockReflowState& aState,
388 : nsHTMLReflowMetrics& aMetrics,
389 : nscoord* aBottomEdgeOfChildren);
390 :
391 : void ComputeOverflowAreas(const nsRect& aBounds,
392 : const nsStyleDisplay* aDisplay,
393 : nscoord aBottomEdgeOfChildren,
394 : nsOverflowAreas& aOverflowAreas);
395 :
396 : /** add the frames in aFrameList to this block after aPrevSibling
397 : * this block thinks in terms of lines, but the frame construction code
398 : * knows nothing about lines at all. So we need to find the line that
399 : * contains aPrevSibling and add aFrameList after aPrevSibling on that line.
400 : * new lines are created as necessary to handle block data in aFrameList.
401 : * This function will clear aFrameList.
402 : */
403 : virtual nsresult AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling);
404 :
405 : #ifdef IBMBIDI
406 : /**
407 : * Perform Bidi resolution on this frame
408 : */
409 : nsresult ResolveBidi();
410 :
411 : /**
412 : * Test whether the frame is a form control in a visual Bidi page.
413 : * This is necessary for backwards-compatibility, because most visual
414 : * pages use logical order for form controls so that they will
415 : * display correctly on native widgets in OSs with Bidi support
416 : * @param aPresContext the pres context
417 : * @return whether the frame is a BIDI form control
418 : */
419 : bool IsVisualFormControl(nsPresContext* aPresContext);
420 : #endif
421 :
422 : public:
423 : /**
424 : * Does all the real work for removing aDeletedFrame
425 : * -- finds the line containing aDeletedFrame
426 : * -- removes all aDeletedFrame next-in-flows (or all continuations,
427 : * if REMOVE_FIXED_CONTINUATIONS is given)
428 : * -- marks lines dirty as needed
429 : * -- marks textruns dirty (unless FRAMES_ARE_EMPTY is given, in which
430 : * case textruns do not need to be dirtied)
431 : * -- destroys all removed frames
432 : */
433 : enum {
434 : REMOVE_FIXED_CONTINUATIONS = 0x02,
435 : FRAMES_ARE_EMPTY = 0x04
436 : };
437 : nsresult DoRemoveFrame(nsIFrame* aDeletedFrame, PRUint32 aFlags);
438 :
439 : void ReparentFloats(nsIFrame* aFirstFrame,
440 : nsBlockFrame* aOldParent, bool aFromOverflow,
441 : bool aReparentSiblings);
442 :
443 : virtual bool UpdateOverflow();
444 :
445 : /** Load all of aFrame's floats into the float manager iff aFrame is not a
446 : * block formatting context. Handles all necessary float manager translations;
447 : * assumes float manager is in aFrame's parent's coord system.
448 : * Safe to call on non-blocks (does nothing).
449 : */
450 : static void RecoverFloatsFor(nsIFrame* aFrame,
451 : nsFloatManager& aFloatManager);
452 :
453 : protected:
454 :
455 : /** grab overflow lines from this block's prevInFlow, and make them
456 : * part of this block's mLines list.
457 : * @return true if any lines were drained.
458 : */
459 : bool DrainOverflowLines();
460 :
461 : /** grab pushed floats from this block's prevInFlow, and splice
462 : * them into this block's mFloats list.
463 : */
464 : void DrainPushedFloats(nsBlockReflowState& aState);
465 :
466 : /** Load all our floats into the float manager (without reflowing them).
467 : * Assumes float manager is in our own coordinate system.
468 : */
469 : void RecoverFloats(nsFloatManager& aFloatManager);
470 :
471 : /** Reflow pushed floats
472 : */
473 : nsresult ReflowPushedFloats(nsBlockReflowState& aState,
474 : nsOverflowAreas& aOverflowAreas,
475 : nsReflowStatus& aStatus);
476 :
477 : /** Find any trailing BR clear from the last line of the block (or its PIFs)
478 : */
479 : PRUint8 FindTrailingClear();
480 :
481 : /**
482 : * Remove a float from our float list and also the float cache
483 : * for the line its placeholder is on.
484 : */
485 : line_iterator RemoveFloat(nsIFrame* aFloat);
486 :
487 : void CollectFloats(nsIFrame* aFrame, nsFrameList& aList,
488 : bool aFromOverflow, bool aCollectFromSiblings);
489 : // Remove a float, abs, rel positioned frame from the appropriate block's list
490 : static void DoRemoveOutOfFlowFrame(nsIFrame* aFrame);
491 :
492 : /** set up the conditions necessary for an resize reflow
493 : * the primary task is to mark the minimumly sufficient lines dirty.
494 : */
495 : nsresult PrepareResizeReflow(nsBlockReflowState& aState);
496 :
497 : /** reflow all lines that have been marked dirty */
498 : nsresult ReflowDirtyLines(nsBlockReflowState& aState);
499 :
500 : /** Mark a given line dirty due to reflow being interrupted on or before it */
501 : void MarkLineDirtyForInterrupt(nsLineBox* aLine);
502 :
503 : //----------------------------------------
504 : // Methods for line reflow
505 : /**
506 : * Reflow a line.
507 : * @param aState the current reflow state
508 : * @param aLine the line to reflow. can contain a single block frame
509 : * or contain 1 or more inline frames.
510 : * @param aKeepReflowGoing [OUT] indicates whether the caller should continue to reflow more lines
511 : */
512 : nsresult ReflowLine(nsBlockReflowState& aState,
513 : line_iterator aLine,
514 : bool* aKeepReflowGoing);
515 :
516 : // Return false if it needs another reflow because of reduced space
517 : // between floats that are next to it (but not next to its top), and
518 : // return true otherwise.
519 : bool PlaceLine(nsBlockReflowState& aState,
520 : nsLineLayout& aLineLayout,
521 : line_iterator aLine,
522 : nsFloatManager::SavedState* aFloatStateBeforeLine,
523 : nsRect& aFloatAvailableSpace, /* in-out */
524 : nscoord& aAvailableSpaceHeight, /* in-out */
525 : bool* aKeepReflowGoing);
526 :
527 : /**
528 : * Mark |aLine| dirty, and, if necessary because of possible
529 : * pull-up, mark the previous line dirty as well. Also invalidates textruns
530 : * on those lines because the text in the lines might have changed due to
531 : * addition/removal of frames.
532 : * @param aLine the line to mark dirty
533 : * @param aLineList the line list containing that line, null means the line
534 : * is in 'mLines' of this frame.
535 : */
536 : nsresult MarkLineDirty(line_iterator aLine,
537 : const nsLineList* aLineList = nsnull);
538 :
539 : // XXX where to go
540 : bool IsLastLine(nsBlockReflowState& aState,
541 : line_iterator aLine);
542 :
543 : void DeleteLine(nsBlockReflowState& aState,
544 : nsLineList::iterator aLine,
545 : nsLineList::iterator aLineEnd);
546 :
547 : //----------------------------------------
548 : // Methods for individual frame reflow
549 :
550 : bool ShouldApplyTopMargin(nsBlockReflowState& aState,
551 : nsLineBox* aLine);
552 :
553 : nsresult ReflowBlockFrame(nsBlockReflowState& aState,
554 : line_iterator aLine,
555 : bool* aKeepGoing);
556 :
557 : nsresult ReflowInlineFrames(nsBlockReflowState& aState,
558 : line_iterator aLine,
559 : bool* aKeepLineGoing);
560 :
561 : nsresult DoReflowInlineFrames(nsBlockReflowState& aState,
562 : nsLineLayout& aLineLayout,
563 : line_iterator aLine,
564 : nsFlowAreaRect& aFloatAvailableSpace,
565 : nscoord& aAvailableSpaceHeight,
566 : nsFloatManager::SavedState*
567 : aFloatStateBeforeLine,
568 : bool* aKeepReflowGoing,
569 : LineReflowStatus* aLineReflowStatus,
570 : bool aAllowPullUp);
571 :
572 : nsresult ReflowInlineFrame(nsBlockReflowState& aState,
573 : nsLineLayout& aLineLayout,
574 : line_iterator aLine,
575 : nsIFrame* aFrame,
576 : LineReflowStatus* aLineReflowStatus);
577 :
578 : // Compute the available width for a float.
579 : nsRect AdjustFloatAvailableSpace(nsBlockReflowState& aState,
580 : const nsRect& aFloatAvailableSpace,
581 : nsIFrame* aFloatFrame);
582 : // Computes the border-box width of the float
583 : nscoord ComputeFloatWidth(nsBlockReflowState& aState,
584 : const nsRect& aFloatAvailableSpace,
585 : nsIFrame* aFloat);
586 : // An incomplete aReflowStatus indicates the float should be split
587 : // but only if the available height is constrained.
588 : // aAdjustedAvailableSpace is the result of calling
589 : // nsBlockFrame::AdjustFloatAvailableSpace.
590 : nsresult ReflowFloat(nsBlockReflowState& aState,
591 : const nsRect& aAdjustedAvailableSpace,
592 : nsIFrame* aFloat,
593 : nsMargin& aFloatMargin,
594 : // Whether the float's position
595 : // (aAdjustedAvailableSpace) has been pushed down
596 : // due to the presence of other floats.
597 : bool aFloatPushedDown,
598 : nsReflowStatus& aReflowStatus);
599 :
600 : //----------------------------------------
601 : // Methods for pushing/pulling lines/frames
602 :
603 : /**
604 : * Create a next-in-flow, if necessary, for aFrame. If a new frame is
605 : * created, place it in aLine if aLine is not null.
606 : * @param aState the block reflow state
607 : * @param aLine where to put a new frame
608 : * @param aFrame the frame
609 : * @param aMadeNewFrame true if a new frame was created, false if not
610 : * @return NS_OK if a next-in-flow already exists or is successfully created
611 : */
612 : virtual nsresult CreateContinuationFor(nsBlockReflowState& aState,
613 : nsLineBox* aLine,
614 : nsIFrame* aFrame,
615 : bool& aMadeNewFrame);
616 :
617 : // Push aLine, which cannot be placed on this page/column but should
618 : // fit on a future one. Set aKeepReflowGoing to false.
619 : void PushTruncatedLine(nsBlockReflowState& aState,
620 : line_iterator aLine,
621 : bool& aKeepReflowGoing);
622 :
623 : nsresult SplitLine(nsBlockReflowState& aState,
624 : nsLineLayout& aLineLayout,
625 : line_iterator aLine,
626 : nsIFrame* aFrame,
627 : LineReflowStatus* aLineReflowStatus);
628 :
629 : /**
630 : * Pull a frame from the next available location (one of our lines or
631 : * one of our next-in-flows lines).
632 : * @return the pulled frame or nsnull
633 : */
634 : nsIFrame* PullFrame(nsBlockReflowState& aState,
635 : line_iterator aLine);
636 :
637 : /**
638 : * Try to pull a frame out of a line pointed at by aFromLine.
639 : *
640 : * Note: pulling a frame from a line that is a place-holder frame
641 : * doesn't automatically remove the corresponding float from the
642 : * line's float array. This happens indirectly: either the line gets
643 : * emptied (and destroyed) or the line gets reflowed (because we mark
644 : * it dirty) and the code at the top of ReflowLine empties the
645 : * array. So eventually, it will be removed, just not right away.
646 : *
647 : * @return the pulled frame or nsnull
648 : */
649 : nsIFrame* PullFrameFrom(nsBlockReflowState& aState,
650 : nsLineBox* aLine,
651 : nsBlockFrame* aFromContainer,
652 : bool aFromOverflowLine,
653 : nsFrameList& aFromFrameList,
654 : nsLineList::iterator aFromLine);
655 :
656 : /**
657 : * Push the line after aLineBefore to the overflow line list.
658 : * @param aLineBefore a line in 'mLines' (or begin_lines() when
659 : * pushing the first line)
660 : */
661 : void PushLines(nsBlockReflowState& aState,
662 : nsLineList::iterator aLineBefore);
663 :
664 : void PropagateFloatDamage(nsBlockReflowState& aState,
665 : nsLineBox* aLine,
666 : nscoord aDeltaY);
667 :
668 : void CheckFloats(nsBlockReflowState& aState);
669 :
670 : //----------------------------------------
671 : // List handling kludge
672 :
673 : // If this returns true, the block it's called on should get the
674 : // NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly
675 : // if it's already in reflow, or via calling FrameNeedsReflow() to schedule a
676 : // reflow.
677 : bool RenumberLists(nsPresContext* aPresContext);
678 :
679 : static bool RenumberListsInBlock(nsPresContext* aPresContext,
680 : nsBlockFrame* aBlockFrame,
681 : PRInt32* aOrdinal,
682 : PRInt32 aDepth);
683 :
684 : static bool RenumberListsFor(nsPresContext* aPresContext, nsIFrame* aKid, PRInt32* aOrdinal, PRInt32 aDepth);
685 :
686 : static bool FrameStartsCounterScope(nsIFrame* aFrame);
687 :
688 : void ReflowBullet(nsIFrame* aBulletFrame,
689 : nsBlockReflowState& aState,
690 : nsHTMLReflowMetrics& aMetrics,
691 : nscoord aLineTop);
692 :
693 : //----------------------------------------
694 :
695 : virtual nsILineIterator* GetLineIterator();
696 :
697 : public:
698 0 : bool HasOverflowLines() const {
699 0 : return 0 != (GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES);
700 : }
701 : FrameLines* GetOverflowLines() const;
702 : protected:
703 : FrameLines* RemoveOverflowLines();
704 : void SetOverflowLines(FrameLines* aOverflowLines);
705 : void DestroyOverflowLines();
706 :
707 : // Determine the computed height that's in effect for this block
708 : // frame (that is, our computed height minus the heights of our
709 : // previous in-flows).
710 : // XXXbz this clearly makes laying out a block with N in-flows
711 : // O(N^2)! Good thing the constant is tiny.
712 : nscoord GetEffectiveComputedHeight(const nsHTMLReflowState& aReflowState) const;
713 :
714 : /**
715 : * This class is useful for efficiently modifying the out of flow
716 : * overflow list. It gives the client direct writable access to
717 : * the frame list temporarily but ensures that property is only
718 : * written back if absolutely necessary.
719 : */
720 : struct nsAutoOOFFrameList {
721 : nsFrameList mList;
722 :
723 0 : nsAutoOOFFrameList(nsBlockFrame* aBlock)
724 0 : : mPropValue(aBlock->GetOverflowOutOfFlows())
725 0 : , mBlock(aBlock) {
726 0 : if (mPropValue) {
727 0 : mList = *mPropValue;
728 : }
729 0 : }
730 0 : ~nsAutoOOFFrameList() {
731 0 : mBlock->SetOverflowOutOfFlows(mList, mPropValue);
732 0 : }
733 : protected:
734 : nsFrameList* const mPropValue;
735 : nsBlockFrame* const mBlock;
736 : };
737 : friend struct nsAutoOOFFrameList;
738 :
739 : nsFrameList* GetOverflowOutOfFlows() const;
740 : void SetOverflowOutOfFlows(const nsFrameList& aList, nsFrameList* aPropValue);
741 :
742 : /**
743 : * @return true if this frame has an inside bullet frame.
744 : */
745 0 : bool HasInsideBullet() const {
746 0 : return 0 != (mState & NS_BLOCK_FRAME_HAS_INSIDE_BULLET);
747 : }
748 :
749 : /**
750 : * @return the inside bullet frame or nsnull if we don't have one.
751 : */
752 : nsBulletFrame* GetInsideBullet() const;
753 :
754 : /**
755 : * @return true if this frame has an outside bullet frame.
756 : */
757 0 : bool HasOutsideBullet() const {
758 0 : return 0 != (mState & NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET);
759 : }
760 :
761 : /**
762 : * @return the outside bullet frame or nsnull if we don't have one.
763 : */
764 : nsBulletFrame* GetOutsideBullet() const;
765 :
766 : /**
767 : * @return the outside bullet frame list frame property.
768 : */
769 : nsFrameList* GetOutsideBulletList() const;
770 :
771 : /**
772 : * @return the bullet frame or nsnull if we don't have one.
773 : */
774 0 : nsBulletFrame* GetBullet() const {
775 0 : nsBulletFrame* outside = GetOutsideBullet();
776 0 : return outside ? outside : GetInsideBullet();
777 : }
778 :
779 : /**
780 : * @return true if this frame has pushed floats.
781 : */
782 0 : bool HasPushedFloats() const {
783 0 : return 0 != (GetStateBits() & NS_BLOCK_HAS_PUSHED_FLOATS);
784 : }
785 :
786 : // Get the pushed floats list
787 : nsFrameList* GetPushedFloats() const;
788 : // Get the pushed floats list, or if there is not currently one,
789 : // make a new empty one.
790 : nsFrameList* EnsurePushedFloats();
791 : // Remove and return the pushed floats list.
792 : nsFrameList* RemovePushedFloats();
793 :
794 : #ifdef NS_DEBUG
795 : void VerifyLines(bool aFinalCheckOK);
796 : void VerifyOverflowSituation();
797 : PRInt32 GetDepth() const;
798 : #endif
799 :
800 : nscoord mMinWidth, mPrefWidth;
801 :
802 : nsLineList mLines;
803 :
804 : // List of all floats in this block
805 : // XXXmats blocks rarely have floats, make it a frame property
806 : nsFrameList mFloats;
807 :
808 : friend class nsBlockReflowState;
809 : friend class nsBlockInFlowLineIterator;
810 :
811 : #ifdef DEBUG
812 : public:
813 : static bool gLamePaintMetrics;
814 : static bool gLameReflowMetrics;
815 : static bool gNoisy;
816 : static bool gNoisyDamageRepair;
817 : static bool gNoisyIntrinsic;
818 : static bool gNoisyReflow;
819 : static bool gReallyNoisyReflow;
820 : static bool gNoisyFloatManager;
821 : static bool gVerifyLines;
822 : static bool gDisableResizeOpt;
823 :
824 : static PRInt32 gNoiseIndent;
825 :
826 : static const char* kReflowCommandType[];
827 :
828 : protected:
829 : static void InitDebugFlags();
830 : #endif
831 : };
832 :
833 : #ifdef DEBUG
834 : class AutoNoisyIndenter {
835 : public:
836 0 : AutoNoisyIndenter(bool aDoIndent) : mIndented(aDoIndent) {
837 0 : if (mIndented) {
838 0 : nsBlockFrame::gNoiseIndent++;
839 : }
840 0 : }
841 0 : ~AutoNoisyIndenter() {
842 0 : if (mIndented) {
843 0 : nsBlockFrame::gNoiseIndent--;
844 : }
845 0 : }
846 : private:
847 : bool mIndented;
848 : };
849 : #endif
850 :
851 : /**
852 : * Iterates over all lines in the prev-in-flows/next-in-flows of this block.
853 : */
854 0 : class nsBlockInFlowLineIterator {
855 : public:
856 : typedef nsBlockFrame::line_iterator line_iterator;
857 : /**
858 : * Set up the iterator to point to aLine which must be a normal line
859 : * in aFrame (not an overflow line).
860 : */
861 : nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator aLine);
862 : /**
863 : * Set up the iterator to point to the first line found starting from
864 : * aFrame. Sets aFoundValidLine to false if there is no such line.
865 : * After aFoundValidLine has returned false, don't call any methods on this
866 : * object again.
867 : */
868 : nsBlockInFlowLineIterator(nsBlockFrame* aFrame, bool* aFoundValidLine);
869 : /**
870 : * Set up the iterator to point to the line that contains aFindFrame (either
871 : * directly or indirectly). If aFrame is out of flow, or contained in an
872 : * out-of-flow, finds the line containing the out-of-flow's placeholder. If
873 : * the frame is not found, sets aFoundValidLine to false. After
874 : * aFoundValidLine has returned false, don't call any methods on this
875 : * object again.
876 : */
877 : nsBlockInFlowLineIterator(nsBlockFrame* aFrame, nsIFrame* aFindFrame,
878 : bool* aFoundValidLine);
879 :
880 0 : line_iterator GetLine() { return mLine; }
881 : bool IsLastLineInList();
882 0 : nsBlockFrame* GetContainer() { return mFrame; }
883 : bool GetInOverflow() { return mInOverflowLines != nsnull; }
884 :
885 : /**
886 : * Returns the current line list we're iterating, null means
887 : * we're iterating |mLines| of the container.
888 : */
889 0 : nsLineList* GetLineList() { return mInOverflowLines; }
890 :
891 : /**
892 : * Returns the end-iterator of whatever line list we're in.
893 : */
894 : line_iterator End();
895 :
896 : /**
897 : * Returns false if there are no more lines. After this has returned false,
898 : * don't call any methods on this object again.
899 : */
900 : bool Next();
901 : /**
902 : * Returns false if there are no more lines. After this has returned false,
903 : * don't call any methods on this object again.
904 : */
905 : bool Prev();
906 :
907 : private:
908 : friend class nsBlockFrame;
909 : // XXX nsBlockFrame uses this internally in one place. Try to remove it.
910 : nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator aLine, bool aInOverflow);
911 :
912 : nsBlockFrame* mFrame;
913 : line_iterator mLine;
914 : nsLineList* mInOverflowLines;
915 :
916 : /**
917 : * Moves iterator to next valid line reachable from the current block.
918 : * Returns false if there are no valid lines.
919 : */
920 : bool FindValidLine();
921 : };
922 :
923 : #endif /* nsBlockFrame_h___ */
|