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 : NS_DECLARE_FRAME_PROPERTY(LineCursorProperty, nsnull)
358 0 : nsLineBox* GetLineCursor() {
359 0 : return (GetStateBits() & NS_BLOCK_HAS_LINE_CURSOR) ?
360 0 : static_cast<nsLineBox*>(Properties().Get(LineCursorProperty())) : nsnull;
361 : }
362 :
363 0 : nsLineBox* NewLineBox(nsIFrame* aFrame, bool aIsBlock) {
364 0 : return NS_NewLineBox(PresContext()->PresShell(), aFrame, aIsBlock);
365 : }
366 0 : nsLineBox* NewLineBox(nsLineBox* aFromLine, nsIFrame* aFrame, PRInt32 aCount) {
367 0 : return NS_NewLineBox(PresContext()->PresShell(), aFromLine, aFrame, aCount);
368 : }
369 0 : void FreeLineBox(nsLineBox* aLine) {
370 0 : if (aLine == GetLineCursor()) {
371 0 : ClearLineCursor();
372 : }
373 0 : aLine->Destroy(PresContext()->PresShell());
374 0 : }
375 :
376 : void TryAllLines(nsLineList::iterator* aIterator,
377 : nsLineList::iterator* aStartIterator,
378 : nsLineList::iterator* aEndIterator,
379 : bool* aInOverflowLines,
380 : FrameLines** aOverflowLines);
381 :
382 0 : void SetFlags(nsFrameState aFlags) {
383 0 : mState &= ~NS_BLOCK_FLAGS_MASK;
384 0 : mState |= aFlags;
385 0 : }
386 :
387 : /** move the frames contained by aLine by aDY
388 : * if aLine is a block, its child floats are added to the state manager
389 : */
390 : void SlideLine(nsBlockReflowState& aState,
391 : nsLineBox* aLine, nscoord aDY);
392 :
393 : virtual PRIntn GetSkipSides() const;
394 :
395 : virtual void ComputeFinalSize(const nsHTMLReflowState& aReflowState,
396 : nsBlockReflowState& aState,
397 : nsHTMLReflowMetrics& aMetrics,
398 : nscoord* aBottomEdgeOfChildren);
399 :
400 : void ComputeOverflowAreas(const nsRect& aBounds,
401 : const nsStyleDisplay* aDisplay,
402 : nscoord aBottomEdgeOfChildren,
403 : nsOverflowAreas& aOverflowAreas);
404 :
405 : /** add the frames in aFrameList to this block after aPrevSibling
406 : * this block thinks in terms of lines, but the frame construction code
407 : * knows nothing about lines at all. So we need to find the line that
408 : * contains aPrevSibling and add aFrameList after aPrevSibling on that line.
409 : * new lines are created as necessary to handle block data in aFrameList.
410 : * This function will clear aFrameList.
411 : */
412 : virtual nsresult AddFrames(nsFrameList& aFrameList, nsIFrame* aPrevSibling);
413 :
414 : #ifdef IBMBIDI
415 : /**
416 : * Perform Bidi resolution on this frame
417 : */
418 : nsresult ResolveBidi();
419 :
420 : /**
421 : * Test whether the frame is a form control in a visual Bidi page.
422 : * This is necessary for backwards-compatibility, because most visual
423 : * pages use logical order for form controls so that they will
424 : * display correctly on native widgets in OSs with Bidi support
425 : * @param aPresContext the pres context
426 : * @return whether the frame is a BIDI form control
427 : */
428 : bool IsVisualFormControl(nsPresContext* aPresContext);
429 : #endif
430 :
431 : public:
432 : /**
433 : * Does all the real work for removing aDeletedFrame
434 : * -- finds the line containing aDeletedFrame
435 : * -- removes all aDeletedFrame next-in-flows (or all continuations,
436 : * if REMOVE_FIXED_CONTINUATIONS is given)
437 : * -- marks lines dirty as needed
438 : * -- marks textruns dirty (unless FRAMES_ARE_EMPTY is given, in which
439 : * case textruns do not need to be dirtied)
440 : * -- destroys all removed frames
441 : */
442 : enum {
443 : REMOVE_FIXED_CONTINUATIONS = 0x02,
444 : FRAMES_ARE_EMPTY = 0x04
445 : };
446 : nsresult DoRemoveFrame(nsIFrame* aDeletedFrame, PRUint32 aFlags);
447 :
448 : void ReparentFloats(nsIFrame* aFirstFrame,
449 : nsBlockFrame* aOldParent, bool aFromOverflow,
450 : bool aReparentSiblings);
451 :
452 : virtual bool UpdateOverflow();
453 :
454 : /** Load all of aFrame's floats into the float manager iff aFrame is not a
455 : * block formatting context. Handles all necessary float manager translations;
456 : * assumes float manager is in aFrame's parent's coord system.
457 : * Safe to call on non-blocks (does nothing).
458 : */
459 : static void RecoverFloatsFor(nsIFrame* aFrame,
460 : nsFloatManager& aFloatManager);
461 :
462 : protected:
463 :
464 : /** grab overflow lines from this block's prevInFlow, and make them
465 : * part of this block's mLines list.
466 : * @return true if any lines were drained.
467 : */
468 : bool DrainOverflowLines();
469 :
470 : /** grab pushed floats from this block's prevInFlow, and splice
471 : * them into this block's mFloats list.
472 : */
473 : void DrainPushedFloats(nsBlockReflowState& aState);
474 :
475 : /** Load all our floats into the float manager (without reflowing them).
476 : * Assumes float manager is in our own coordinate system.
477 : */
478 : void RecoverFloats(nsFloatManager& aFloatManager);
479 :
480 : /** Reflow pushed floats
481 : */
482 : nsresult ReflowPushedFloats(nsBlockReflowState& aState,
483 : nsOverflowAreas& aOverflowAreas,
484 : nsReflowStatus& aStatus);
485 :
486 : /** Find any trailing BR clear from the last line of the block (or its PIFs)
487 : */
488 : PRUint8 FindTrailingClear();
489 :
490 : /**
491 : * Remove a float from our float list and also the float cache
492 : * for the line its placeholder is on.
493 : */
494 : line_iterator RemoveFloat(nsIFrame* aFloat);
495 :
496 : void CollectFloats(nsIFrame* aFrame, nsFrameList& aList,
497 : bool aFromOverflow, bool aCollectFromSiblings);
498 : // Remove a float, abs, rel positioned frame from the appropriate block's list
499 : static void DoRemoveOutOfFlowFrame(nsIFrame* aFrame);
500 :
501 : /** set up the conditions necessary for an resize reflow
502 : * the primary task is to mark the minimumly sufficient lines dirty.
503 : */
504 : nsresult PrepareResizeReflow(nsBlockReflowState& aState);
505 :
506 : /** reflow all lines that have been marked dirty */
507 : nsresult ReflowDirtyLines(nsBlockReflowState& aState);
508 :
509 : /** Mark a given line dirty due to reflow being interrupted on or before it */
510 : void MarkLineDirtyForInterrupt(nsLineBox* aLine);
511 :
512 : //----------------------------------------
513 : // Methods for line reflow
514 : /**
515 : * Reflow a line.
516 : * @param aState the current reflow state
517 : * @param aLine the line to reflow. can contain a single block frame
518 : * or contain 1 or more inline frames.
519 : * @param aKeepReflowGoing [OUT] indicates whether the caller should continue to reflow more lines
520 : */
521 : nsresult ReflowLine(nsBlockReflowState& aState,
522 : line_iterator aLine,
523 : bool* aKeepReflowGoing);
524 :
525 : // Return false if it needs another reflow because of reduced space
526 : // between floats that are next to it (but not next to its top), and
527 : // return true otherwise.
528 : bool PlaceLine(nsBlockReflowState& aState,
529 : nsLineLayout& aLineLayout,
530 : line_iterator aLine,
531 : nsFloatManager::SavedState* aFloatStateBeforeLine,
532 : nsRect& aFloatAvailableSpace, /* in-out */
533 : nscoord& aAvailableSpaceHeight, /* in-out */
534 : bool* aKeepReflowGoing);
535 :
536 : /**
537 : * Mark |aLine| dirty, and, if necessary because of possible
538 : * pull-up, mark the previous line dirty as well. Also invalidates textruns
539 : * on those lines because the text in the lines might have changed due to
540 : * addition/removal of frames.
541 : * @param aLine the line to mark dirty
542 : * @param aLineList the line list containing that line, null means the line
543 : * is in 'mLines' of this frame.
544 : */
545 : nsresult MarkLineDirty(line_iterator aLine,
546 : const nsLineList* aLineList = nsnull);
547 :
548 : // XXX where to go
549 : bool IsLastLine(nsBlockReflowState& aState,
550 : line_iterator aLine);
551 :
552 : void DeleteLine(nsBlockReflowState& aState,
553 : nsLineList::iterator aLine,
554 : nsLineList::iterator aLineEnd);
555 :
556 : //----------------------------------------
557 : // Methods for individual frame reflow
558 :
559 : bool ShouldApplyTopMargin(nsBlockReflowState& aState,
560 : nsLineBox* aLine);
561 :
562 : nsresult ReflowBlockFrame(nsBlockReflowState& aState,
563 : line_iterator aLine,
564 : bool* aKeepGoing);
565 :
566 : nsresult ReflowInlineFrames(nsBlockReflowState& aState,
567 : line_iterator aLine,
568 : bool* aKeepLineGoing);
569 :
570 : nsresult DoReflowInlineFrames(nsBlockReflowState& aState,
571 : nsLineLayout& aLineLayout,
572 : line_iterator aLine,
573 : nsFlowAreaRect& aFloatAvailableSpace,
574 : nscoord& aAvailableSpaceHeight,
575 : nsFloatManager::SavedState*
576 : aFloatStateBeforeLine,
577 : bool* aKeepReflowGoing,
578 : LineReflowStatus* aLineReflowStatus,
579 : bool aAllowPullUp);
580 :
581 : nsresult ReflowInlineFrame(nsBlockReflowState& aState,
582 : nsLineLayout& aLineLayout,
583 : line_iterator aLine,
584 : nsIFrame* aFrame,
585 : LineReflowStatus* aLineReflowStatus);
586 :
587 : // Compute the available width for a float.
588 : nsRect AdjustFloatAvailableSpace(nsBlockReflowState& aState,
589 : const nsRect& aFloatAvailableSpace,
590 : nsIFrame* aFloatFrame);
591 : // Computes the border-box width of the float
592 : nscoord ComputeFloatWidth(nsBlockReflowState& aState,
593 : const nsRect& aFloatAvailableSpace,
594 : nsIFrame* aFloat);
595 : // An incomplete aReflowStatus indicates the float should be split
596 : // but only if the available height is constrained.
597 : // aAdjustedAvailableSpace is the result of calling
598 : // nsBlockFrame::AdjustFloatAvailableSpace.
599 : nsresult ReflowFloat(nsBlockReflowState& aState,
600 : const nsRect& aAdjustedAvailableSpace,
601 : nsIFrame* aFloat,
602 : nsMargin& aFloatMargin,
603 : // Whether the float's position
604 : // (aAdjustedAvailableSpace) has been pushed down
605 : // due to the presence of other floats.
606 : bool aFloatPushedDown,
607 : nsReflowStatus& aReflowStatus);
608 :
609 : //----------------------------------------
610 : // Methods for pushing/pulling lines/frames
611 :
612 : /**
613 : * Create a next-in-flow, if necessary, for aFrame. If a new frame is
614 : * created, place it in aLine if aLine is not null.
615 : * @param aState the block reflow state
616 : * @param aLine where to put a new frame
617 : * @param aFrame the frame
618 : * @param aMadeNewFrame true if a new frame was created, false if not
619 : * @return NS_OK if a next-in-flow already exists or is successfully created
620 : */
621 : virtual nsresult CreateContinuationFor(nsBlockReflowState& aState,
622 : nsLineBox* aLine,
623 : nsIFrame* aFrame,
624 : bool& aMadeNewFrame);
625 :
626 : // Push aLine, which cannot be placed on this page/column but should
627 : // fit on a future one. Set aKeepReflowGoing to false.
628 : void PushTruncatedLine(nsBlockReflowState& aState,
629 : line_iterator aLine,
630 : bool& aKeepReflowGoing);
631 :
632 : nsresult SplitLine(nsBlockReflowState& aState,
633 : nsLineLayout& aLineLayout,
634 : line_iterator aLine,
635 : nsIFrame* aFrame,
636 : LineReflowStatus* aLineReflowStatus);
637 :
638 : /**
639 : * Pull a frame from the next available location (one of our lines or
640 : * one of our next-in-flows lines).
641 : * @return the pulled frame or nsnull
642 : */
643 : nsIFrame* PullFrame(nsBlockReflowState& aState,
644 : line_iterator aLine);
645 :
646 : /**
647 : * Try to pull a frame out of a line pointed at by aFromLine.
648 : *
649 : * Note: pulling a frame from a line that is a place-holder frame
650 : * doesn't automatically remove the corresponding float from the
651 : * line's float array. This happens indirectly: either the line gets
652 : * emptied (and destroyed) or the line gets reflowed (because we mark
653 : * it dirty) and the code at the top of ReflowLine empties the
654 : * array. So eventually, it will be removed, just not right away.
655 : *
656 : * @return the pulled frame or nsnull
657 : */
658 : nsIFrame* PullFrameFrom(nsBlockReflowState& aState,
659 : nsLineBox* aLine,
660 : nsBlockFrame* aFromContainer,
661 : bool aFromOverflowLine,
662 : nsFrameList& aFromFrameList,
663 : nsLineList::iterator aFromLine);
664 :
665 : /**
666 : * Push the line after aLineBefore to the overflow line list.
667 : * @param aLineBefore a line in 'mLines' (or begin_lines() when
668 : * pushing the first line)
669 : */
670 : void PushLines(nsBlockReflowState& aState,
671 : nsLineList::iterator aLineBefore);
672 :
673 : void PropagateFloatDamage(nsBlockReflowState& aState,
674 : nsLineBox* aLine,
675 : nscoord aDeltaY);
676 :
677 : void CheckFloats(nsBlockReflowState& aState);
678 :
679 : //----------------------------------------
680 : // List handling kludge
681 :
682 : // If this returns true, the block it's called on should get the
683 : // NS_FRAME_HAS_DIRTY_CHILDREN bit set on it by the caller; either directly
684 : // if it's already in reflow, or via calling FrameNeedsReflow() to schedule a
685 : // reflow.
686 : bool RenumberLists(nsPresContext* aPresContext);
687 :
688 : static bool RenumberListsInBlock(nsPresContext* aPresContext,
689 : nsBlockFrame* aBlockFrame,
690 : PRInt32* aOrdinal,
691 : PRInt32 aDepth);
692 :
693 : static bool RenumberListsFor(nsPresContext* aPresContext, nsIFrame* aKid, PRInt32* aOrdinal, PRInt32 aDepth);
694 :
695 : static bool FrameStartsCounterScope(nsIFrame* aFrame);
696 :
697 : void ReflowBullet(nsIFrame* aBulletFrame,
698 : nsBlockReflowState& aState,
699 : nsHTMLReflowMetrics& aMetrics,
700 : nscoord aLineTop);
701 :
702 : //----------------------------------------
703 :
704 : virtual nsILineIterator* GetLineIterator();
705 :
706 : public:
707 0 : bool HasOverflowLines() const {
708 0 : return 0 != (GetStateBits() & NS_BLOCK_HAS_OVERFLOW_LINES);
709 : }
710 : FrameLines* GetOverflowLines() const;
711 : protected:
712 : FrameLines* RemoveOverflowLines();
713 : void SetOverflowLines(FrameLines* aOverflowLines);
714 : void DestroyOverflowLines();
715 :
716 : // Determine the computed height that's in effect for this block
717 : // frame (that is, our computed height minus the heights of our
718 : // previous in-flows).
719 : // XXXbz this clearly makes laying out a block with N in-flows
720 : // O(N^2)! Good thing the constant is tiny.
721 : nscoord GetEffectiveComputedHeight(const nsHTMLReflowState& aReflowState) const;
722 :
723 : /**
724 : * This class is useful for efficiently modifying the out of flow
725 : * overflow list. It gives the client direct writable access to
726 : * the frame list temporarily but ensures that property is only
727 : * written back if absolutely necessary.
728 : */
729 : struct nsAutoOOFFrameList {
730 : nsFrameList mList;
731 :
732 0 : nsAutoOOFFrameList(nsBlockFrame* aBlock)
733 0 : : mPropValue(aBlock->GetOverflowOutOfFlows())
734 0 : , mBlock(aBlock) {
735 0 : if (mPropValue) {
736 0 : mList = *mPropValue;
737 : }
738 0 : }
739 0 : ~nsAutoOOFFrameList() {
740 0 : mBlock->SetOverflowOutOfFlows(mList, mPropValue);
741 0 : }
742 : protected:
743 : nsFrameList* const mPropValue;
744 : nsBlockFrame* const mBlock;
745 : };
746 : friend struct nsAutoOOFFrameList;
747 :
748 : nsFrameList* GetOverflowOutOfFlows() const;
749 : void SetOverflowOutOfFlows(const nsFrameList& aList, nsFrameList* aPropValue);
750 :
751 : /**
752 : * @return true if this frame has an inside bullet frame.
753 : */
754 0 : bool HasInsideBullet() const {
755 0 : return 0 != (mState & NS_BLOCK_FRAME_HAS_INSIDE_BULLET);
756 : }
757 :
758 : /**
759 : * @return the inside bullet frame or nsnull if we don't have one.
760 : */
761 : nsBulletFrame* GetInsideBullet() const;
762 :
763 : /**
764 : * @return true if this frame has an outside bullet frame.
765 : */
766 0 : bool HasOutsideBullet() const {
767 0 : return 0 != (mState & NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET);
768 : }
769 :
770 : /**
771 : * @return the outside bullet frame or nsnull if we don't have one.
772 : */
773 : nsBulletFrame* GetOutsideBullet() const;
774 :
775 : /**
776 : * @return the outside bullet frame list frame property.
777 : */
778 : nsFrameList* GetOutsideBulletList() const;
779 :
780 : /**
781 : * @return the bullet frame or nsnull if we don't have one.
782 : */
783 0 : nsBulletFrame* GetBullet() const {
784 0 : nsBulletFrame* outside = GetOutsideBullet();
785 0 : return outside ? outside : GetInsideBullet();
786 : }
787 :
788 : /**
789 : * @return true if this frame has pushed floats.
790 : */
791 0 : bool HasPushedFloats() const {
792 0 : return 0 != (GetStateBits() & NS_BLOCK_HAS_PUSHED_FLOATS);
793 : }
794 :
795 : // Get the pushed floats list
796 : nsFrameList* GetPushedFloats() const;
797 : // Get the pushed floats list, or if there is not currently one,
798 : // make a new empty one.
799 : nsFrameList* EnsurePushedFloats();
800 : // Remove and return the pushed floats list.
801 : nsFrameList* RemovePushedFloats();
802 :
803 : #ifdef NS_DEBUG
804 : void VerifyLines(bool aFinalCheckOK);
805 : void VerifyOverflowSituation();
806 : PRInt32 GetDepth() const;
807 : #endif
808 :
809 : nscoord mMinWidth, mPrefWidth;
810 :
811 : nsLineList mLines;
812 :
813 : // List of all floats in this block
814 : // XXXmats blocks rarely have floats, make it a frame property
815 : nsFrameList mFloats;
816 :
817 : friend class nsBlockReflowState;
818 : friend class nsBlockInFlowLineIterator;
819 :
820 : #ifdef DEBUG
821 : public:
822 : static bool gLamePaintMetrics;
823 : static bool gLameReflowMetrics;
824 : static bool gNoisy;
825 : static bool gNoisyDamageRepair;
826 : static bool gNoisyIntrinsic;
827 : static bool gNoisyReflow;
828 : static bool gReallyNoisyReflow;
829 : static bool gNoisyFloatManager;
830 : static bool gVerifyLines;
831 : static bool gDisableResizeOpt;
832 :
833 : static PRInt32 gNoiseIndent;
834 :
835 : static const char* kReflowCommandType[];
836 :
837 : protected:
838 : static void InitDebugFlags();
839 : #endif
840 : };
841 :
842 : #ifdef DEBUG
843 : class AutoNoisyIndenter {
844 : public:
845 0 : AutoNoisyIndenter(bool aDoIndent) : mIndented(aDoIndent) {
846 0 : if (mIndented) {
847 0 : nsBlockFrame::gNoiseIndent++;
848 : }
849 0 : }
850 0 : ~AutoNoisyIndenter() {
851 0 : if (mIndented) {
852 0 : nsBlockFrame::gNoiseIndent--;
853 : }
854 0 : }
855 : private:
856 : bool mIndented;
857 : };
858 : #endif
859 :
860 : /**
861 : * Iterates over all lines in the prev-in-flows/next-in-flows of this block.
862 : */
863 0 : class nsBlockInFlowLineIterator {
864 : public:
865 : typedef nsBlockFrame::line_iterator line_iterator;
866 : /**
867 : * Set up the iterator to point to aLine which must be a normal line
868 : * in aFrame (not an overflow line).
869 : */
870 : nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator aLine);
871 : /**
872 : * Set up the iterator to point to the first line found starting from
873 : * aFrame. Sets aFoundValidLine to false if there is no such line.
874 : * After aFoundValidLine has returned false, don't call any methods on this
875 : * object again.
876 : */
877 : nsBlockInFlowLineIterator(nsBlockFrame* aFrame, bool* aFoundValidLine);
878 : /**
879 : * Set up the iterator to point to the line that contains aFindFrame (either
880 : * directly or indirectly). If aFrame is out of flow, or contained in an
881 : * out-of-flow, finds the line containing the out-of-flow's placeholder. If
882 : * the frame is not found, sets aFoundValidLine to false. After
883 : * aFoundValidLine has returned false, don't call any methods on this
884 : * object again.
885 : */
886 : nsBlockInFlowLineIterator(nsBlockFrame* aFrame, nsIFrame* aFindFrame,
887 : bool* aFoundValidLine);
888 :
889 0 : line_iterator GetLine() { return mLine; }
890 : bool IsLastLineInList();
891 0 : nsBlockFrame* GetContainer() { return mFrame; }
892 : bool GetInOverflow() { return mInOverflowLines != nsnull; }
893 :
894 : /**
895 : * Returns the current line list we're iterating, null means
896 : * we're iterating |mLines| of the container.
897 : */
898 0 : nsLineList* GetLineList() { return mInOverflowLines; }
899 :
900 : /**
901 : * Returns the end-iterator of whatever line list we're in.
902 : */
903 : line_iterator End();
904 :
905 : /**
906 : * Returns false if there are no more lines. After this has returned false,
907 : * don't call any methods on this object again.
908 : */
909 : bool Next();
910 : /**
911 : * Returns false if there are no more lines. After this has returned false,
912 : * don't call any methods on this object again.
913 : */
914 : bool Prev();
915 :
916 : private:
917 : friend class nsBlockFrame;
918 : // XXX nsBlockFrame uses this internally in one place. Try to remove it.
919 : nsBlockInFlowLineIterator(nsBlockFrame* aFrame, line_iterator aLine, bool aInOverflow);
920 :
921 : nsBlockFrame* mFrame;
922 : line_iterator mLine;
923 : nsLineList* mInOverflowLines;
924 :
925 : /**
926 : * Moves iterator to next valid line reachable from the current block.
927 : * Returns false if there are no valid lines.
928 : */
929 : bool FindValidLine();
930 : };
931 :
932 : #endif /* nsBlockFrame_h___ */
|