1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Mats Palmgren <matspal@gmail.com>
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.
37 * ***** END LICENSE BLOCK ***** */
39 /* struct containing the input to nsIFrame::Reflow */
42 #include "nsStyleConsts.h"
43 #include "nsCSSAnonBoxes.h"
45 #include "nsIContent.h"
46 #include "nsGkAtoms.h"
47 #include "nsPresContext.h"
48 #include "nsIPresShell.h"
49 #include "nsIDeviceContext.h"
50 #include "nsIRenderingContext.h"
51 #include "nsIFontMetrics.h"
52 #include "nsBlockFrame.h"
53 #include "nsLineBox.h"
54 #include "nsImageFrame.h"
55 #include "nsTableFrame.h"
56 #include "nsTableCellFrame.h"
57 #include "nsIServiceManager.h"
58 #include "nsIPercentHeightObserver.h"
59 #include "nsContentUtils.h"
60 #include "nsLayoutUtils.h"
62 #include "nsBidiUtils.h"
66 #undef NOISY_VERTICAL_ALIGN
68 #undef NOISY_VERTICAL_ALIGN
71 using namespace mozilla
;
73 // Prefs-driven control for |text-decoration: blink|
74 static PRPackedBool sPrefIsLoaded
= PR_FALSE
;
75 static PRPackedBool sBlinkIsAllowed
= PR_TRUE
;
77 enum eNormalLineHeightControl
{
79 eNoExternalLeading
= 0, // does not include external leading
80 eIncludeExternalLeading
, // use whatever value font vendor provides
81 eCompensateLeading
// compensate leading if leading provided by font vendor is not enough
84 static eNormalLineHeightControl sNormalLineHeightControl
= eUninitialized
;
86 // Initialize a <b>root</b> reflow state with a rendering context to
87 // use for measuring things.
88 nsHTMLReflowState::nsHTMLReflowState(nsPresContext
* aPresContext
,
90 nsIRenderingContext
* aRenderingContext
,
91 const nsSize
& aAvailableSpace
)
92 : nsCSSOffsetState(aFrame
, aRenderingContext
)
96 NS_PRECONDITION(aPresContext
, "no pres context");
97 NS_PRECONDITION(aRenderingContext
, "no rendering context");
98 NS_PRECONDITION(aFrame
, "no frame");
99 parentReflowState
= nsnull
;
100 availableWidth
= aAvailableSpace
.width
;
101 availableHeight
= aAvailableSpace
.height
;
102 mFloatManager
= nsnull
;
103 mLineLayout
= nsnull
;
104 mFlags
.mSpecialHeightReflow
= PR_FALSE
;
105 mFlags
.mIsTopOfPage
= PR_FALSE
;
106 mFlags
.mTableIsSplittable
= PR_FALSE
;
107 mFlags
.mNextInFlowUntouched
= PR_FALSE
;
108 mFlags
.mAssumingHScrollbar
= mFlags
.mAssumingVScrollbar
= PR_FALSE
;
109 mFlags
.mHasClearance
= PR_FALSE
;
110 mFlags
.mHeightDependsOnAncestorCell
= PR_FALSE
;
111 mDiscoveredClearance
= nsnull
;
112 mPercentHeightObserver
= nsnull
;
116 static PRBool
CheckNextInFlowParenthood(nsIFrame
* aFrame
, nsIFrame
* aParent
)
118 nsIFrame
* frameNext
= aFrame
->GetNextInFlow();
119 nsIFrame
* parentNext
= aParent
->GetNextInFlow();
120 return frameNext
&& parentNext
&& frameNext
->GetParent() == parentNext
;
123 // Initialize a reflow state for a child frames reflow. Some state
124 // is copied from the parent reflow state; the remaining state is
126 nsHTMLReflowState::nsHTMLReflowState(nsPresContext
* aPresContext
,
127 const nsHTMLReflowState
& aParentReflowState
,
129 const nsSize
& aAvailableSpace
,
130 nscoord aContainingBlockWidth
,
131 nscoord aContainingBlockHeight
,
133 : nsCSSOffsetState(aFrame
, aParentReflowState
.rendContext
)
135 , mReflowDepth(aParentReflowState
.mReflowDepth
+ 1)
136 , mFlags(aParentReflowState
.mFlags
)
138 NS_PRECONDITION(aPresContext
, "no pres context");
139 NS_PRECONDITION(aFrame
, "no frame");
140 NS_PRECONDITION((aContainingBlockWidth
== -1) ==
141 (aContainingBlockHeight
== -1),
142 "cb width and height should only be non-default together");
143 NS_PRECONDITION(aInit
== PR_TRUE
|| aInit
== PR_FALSE
,
144 "aInit out of range for PRBool");
145 NS_PRECONDITION(!mFlags
.mSpecialHeightReflow
||
146 !NS_SUBTREE_DIRTY(aFrame
),
147 "frame should be clean when getting special height reflow");
149 parentReflowState
= &aParentReflowState
;
151 // If the parent is dirty, then the child is as well.
152 // XXX Are the other cases where the parent reflows a child a second
153 // time, as a resize?
154 if (!mFlags
.mSpecialHeightReflow
)
155 frame
->AddStateBits(parentReflowState
->frame
->GetStateBits() &
158 availableWidth
= aAvailableSpace
.width
;
159 availableHeight
= aAvailableSpace
.height
;
161 mFloatManager
= aParentReflowState
.mFloatManager
;
162 if (frame
->IsFrameOfType(nsIFrame::eLineParticipant
))
163 mLineLayout
= aParentReflowState
.mLineLayout
;
165 mLineLayout
= nsnull
;
166 mFlags
.mIsTopOfPage
= aParentReflowState
.mFlags
.mIsTopOfPage
;
167 mFlags
.mNextInFlowUntouched
= aParentReflowState
.mFlags
.mNextInFlowUntouched
&&
168 CheckNextInFlowParenthood(aFrame
, aParentReflowState
.frame
);
169 mFlags
.mAssumingHScrollbar
= mFlags
.mAssumingVScrollbar
= PR_FALSE
;
170 mFlags
.mHasClearance
= PR_FALSE
;
171 mDiscoveredClearance
= nsnull
;
172 mPercentHeightObserver
= (aParentReflowState
.mPercentHeightObserver
&&
173 aParentReflowState
.mPercentHeightObserver
->NeedsToObserve(*this))
174 ? aParentReflowState
.mPercentHeightObserver
: nsnull
;
177 Init(aPresContext
, aContainingBlockWidth
, aContainingBlockHeight
);
182 nsCSSOffsetState::ComputeWidthValue(nscoord aContainingBlockWidth
,
183 nscoord aContentEdgeToBoxSizing
,
184 nscoord aBoxSizingToMarginEdge
,
185 const nsStyleCoord
& aCoord
)
187 return nsLayoutUtils::ComputeWidthValue(rendContext
, frame
,
188 aContainingBlockWidth
,
189 aContentEdgeToBoxSizing
,
190 aBoxSizingToMarginEdge
,
195 nsCSSOffsetState::ComputeWidthValue(nscoord aContainingBlockWidth
,
197 const nsStyleCoord
& aCoord
)
199 nscoord inside
= 0, outside
= mComputedBorderPadding
.LeftRight() +
200 mComputedMargin
.LeftRight();
201 switch (aBoxSizing
) {
202 case NS_STYLE_BOX_SIZING_BORDER
:
203 inside
= mComputedBorderPadding
.LeftRight();
205 case NS_STYLE_BOX_SIZING_PADDING
:
206 inside
= mComputedPadding
.LeftRight();
211 return ComputeWidthValue(aContainingBlockWidth
, inside
,
216 nsHTMLReflowState::SetComputedWidth(nscoord aComputedWidth
)
218 NS_ASSERTION(frame
, "Must have a frame!");
219 // It'd be nice to assert that |frame| is not in reflow, but this fails for
222 // 1) Viewport frames reset the computed width on a copy of their reflow
223 // state when reflowing fixed-pos kids. In that case we actually don't
224 // want to mess with the resize flags, because comparing the frame's rect
225 // to the munged computed width is pointless.
226 // 2) nsFrame::BoxReflow creates a reflow state for its parent. This reflow
227 // state is not used to reflow the parent, but just as a parent for the
228 // frame's own reflow state. So given a nsBoxFrame inside some non-XUL
229 // (like a text control, for example), we'll end up creating a reflow
230 // state for the parent while the parent is reflowing.
232 NS_PRECONDITION(aComputedWidth
>= 0, "Invalid computed width");
233 if (mComputedWidth
!= aComputedWidth
) {
234 mComputedWidth
= aComputedWidth
;
235 if (frame
->GetType() != nsGkAtoms::viewportFrame
) { // Or check GetParent()?
236 InitResizeFlags(frame
->PresContext());
242 nsHTMLReflowState::SetComputedHeight(nscoord aComputedHeight
)
244 NS_ASSERTION(frame
, "Must have a frame!");
245 // It'd be nice to assert that |frame| is not in reflow, but this fails
248 // nsFrame::BoxReflow creates a reflow state for its parent. This reflow
249 // state is not used to reflow the parent, but just as a parent for the
250 // frame's own reflow state. So given a nsBoxFrame inside some non-XUL
251 // (like a text control, for example), we'll end up creating a reflow
252 // state for the parent while the parent is reflowing.
254 NS_PRECONDITION(aComputedHeight
>= 0, "Invalid computed height");
255 if (mComputedHeight
!= aComputedHeight
) {
256 mComputedHeight
= aComputedHeight
;
257 InitResizeFlags(frame
->PresContext());
262 nsHTMLReflowState::Init(nsPresContext
* aPresContext
,
263 nscoord aContainingBlockWidth
,
264 nscoord aContainingBlockHeight
,
265 const nsMargin
* aBorder
,
266 const nsMargin
* aPadding
)
268 NS_WARN_IF_FALSE(availableWidth
!= NS_UNCONSTRAINEDSIZE
,
269 "have unconstrained width; this should only result from "
270 "very large sizes, not attempts at intrinsic width "
273 mStylePosition
= frame
->GetStylePosition();
274 mStyleDisplay
= frame
->GetStyleDisplay();
275 mStyleVisibility
= frame
->GetStyleVisibility();
276 mStyleBorder
= frame
->GetStyleBorder();
277 mStyleMargin
= frame
->GetStyleMargin();
278 mStylePadding
= frame
->GetStylePadding();
279 mStyleText
= frame
->GetStyleText();
284 InitConstraints(aPresContext
, aContainingBlockWidth
, aContainingBlockHeight
, aBorder
, aPadding
);
286 InitResizeFlags(aPresContext
);
288 NS_WARN_IF_FALSE((mFrameType
== NS_CSS_FRAME_TYPE_INLINE
&&
289 !frame
->IsFrameOfType(nsIFrame::eReplaced
)) ||
290 frame
->GetType() == nsGkAtoms::textFrame
||
291 mComputedWidth
!= NS_UNCONSTRAINEDSIZE
,
292 "have unconstrained width; this should only result from "
293 "very large sizes, not attempts at intrinsic width "
297 void nsHTMLReflowState::InitCBReflowState()
299 if (!parentReflowState
) {
300 mCBReflowState
= nsnull
;
304 // If outer tables ever become containing blocks, we need to make sure to use
305 // their mCBReflowState in the non-absolutely-positioned case for inner
307 NS_ASSERTION(frame
->GetType() != nsGkAtoms::tableFrame
||
308 !frame
->GetParent()->IsContainingBlock(),
309 "Outer table should not be containing block");
311 if (parentReflowState
->frame
->IsContainingBlock() ||
312 // Absolutely positioned frames should always be kids of the frames that
313 // determine their containing block....
314 (NS_FRAME_GET_TYPE(mFrameType
) == NS_CSS_FRAME_TYPE_ABSOLUTE
)) {
315 // an absolutely positioned inner table needs to use the parent of
316 // the outer table. So the above comment about absolutely
317 // positioned frames is sort of a lie.
318 if (parentReflowState
->parentReflowState
&&
319 frame
->GetType() == nsGkAtoms::tableFrame
) {
320 mCBReflowState
= parentReflowState
->parentReflowState
;
322 mCBReflowState
= parentReflowState
;
328 mCBReflowState
= parentReflowState
->mCBReflowState
;
331 /* Check whether CalcQuirkContainingBlockHeight would stop on the
332 * given reflow state, using its block as a height. (essentially
333 * returns false for any case in which CalcQuirkContainingBlockHeight
334 * has a "continue" in its main loop.)
336 * XXX Maybe refactor CalcQuirkContainingBlockHeight so it uses
337 * this function as well
340 IsQuirkContainingBlockHeight(const nsHTMLReflowState
* rs
)
342 nsIAtom
* frameType
= rs
->frame
->GetType();
343 if (nsGkAtoms::blockFrame
== frameType
||
345 nsGkAtoms::XULLabelFrame
== frameType
||
347 nsGkAtoms::scrollFrame
== frameType
) {
348 // Note: This next condition could change due to a style change,
349 // but that would cause a style reflow anyway, which means we're ok.
350 if (NS_AUTOHEIGHT
== rs
->ComputedHeight()) {
351 if (!rs
->frame
->GetStyleDisplay()->IsAbsolutelyPositioned()) {
361 nsHTMLReflowState::InitResizeFlags(nsPresContext
* aPresContext
)
363 mFlags
.mHResize
= !(frame
->GetStateBits() & NS_FRAME_IS_DIRTY
) &&
364 frame
->GetSize().width
!=
365 mComputedWidth
+ mComputedBorderPadding
.LeftRight();
367 // XXX Should we really need to null check mCBReflowState? (We do for
368 // at least nsBoxFrame).
369 if (IS_TABLE_CELL(frame
->GetType()) &&
370 (mFlags
.mSpecialHeightReflow
||
371 (frame
->GetFirstInFlow()->GetStateBits() &
372 NS_TABLE_CELL_HAD_SPECIAL_REFLOW
)) &&
373 (frame
->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT
)) {
374 // Need to set the bit on the cell so that
375 // mCBReflowState->mFlags.mVResize is set correctly below when
376 // reflowing descendant.
377 mFlags
.mVResize
= PR_TRUE
;
378 } else if (mCBReflowState
&& !frame
->IsContainingBlock()) {
379 // XXX Is this problematic for relatively positioned inlines acting
380 // as containing block for absolutely positioned elements?
381 // Possibly; in that case we should at least be checking
382 // NS_SUBTREE_DIRTY, I'd think.
383 mFlags
.mVResize
= mCBReflowState
->mFlags
.mVResize
;
384 } else if (mComputedHeight
== NS_AUTOHEIGHT
) {
385 if (eCompatibility_NavQuirks
== aPresContext
->CompatibilityMode() &&
387 mFlags
.mVResize
= mCBReflowState
->mFlags
.mVResize
;
389 mFlags
.mVResize
= mFlags
.mHResize
;
391 mFlags
.mVResize
= mFlags
.mVResize
|| NS_SUBTREE_DIRTY(frame
);
394 mFlags
.mVResize
= frame
->GetSize().height
!=
395 mComputedHeight
+ mComputedBorderPadding
.TopBottom();
398 PRBool dependsOnCBHeight
=
399 (mStylePosition
->HeightDependsOnContainer() &&
400 // FIXME: condition this on not-abspos?
401 mStylePosition
->mHeight
.GetUnit() != eStyleUnit_Auto
) ||
402 (mStylePosition
->MinHeightDependsOnContainer() &&
403 // FIXME: condition this on not-abspos?
404 mStylePosition
->mMinHeight
.GetUnit() != eStyleUnit_Auto
) ||
405 (mStylePosition
->MaxHeightDependsOnContainer() &&
406 // FIXME: condition this on not-abspos?
407 mStylePosition
->mMaxHeight
.GetUnit() != eStyleUnit_Auto
) ||
408 mStylePosition
->OffsetHasPercent(NS_SIDE_TOP
) ||
409 mStylePosition
->mOffset
.GetBottomUnit() != eStyleUnit_Auto
||
410 frame
->IsBoxFrame() ||
411 (mStylePosition
->mHeight
.GetUnit() == eStyleUnit_Auto
&&
412 frame
->GetIntrinsicSize().height
.GetUnit() == eStyleUnit_Percent
);
414 if (mStyleText
->mLineHeight
.GetUnit() == eStyleUnit_Enumerated
) {
415 NS_ASSERTION(mStyleText
->mLineHeight
.GetIntValue() ==
416 NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT
,
417 "bad line-height value");
419 // line-height depends on block height
420 frame
->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT
);
421 // but only on containing blocks if this frame is not a suitable block
422 dependsOnCBHeight
|= !frame
->IsContainingBlock();
425 // If we're the descendant of a table cell that performs special height
426 // reflows and we could be the child that requires them, always set
427 // the vertical resize in case this is the first pass before the
428 // special height reflow. However, don't do this if it actually is
429 // the special height reflow, since in that case it will already be
430 // set correctly above if we need it set.
431 if (!mFlags
.mVResize
&& mCBReflowState
&&
432 (IS_TABLE_CELL(mCBReflowState
->frame
->GetType()) ||
433 mCBReflowState
->mFlags
.mHeightDependsOnAncestorCell
) &&
434 !mCBReflowState
->mFlags
.mSpecialHeightReflow
&&
436 mFlags
.mVResize
= PR_TRUE
;
437 mFlags
.mHeightDependsOnAncestorCell
= PR_TRUE
;
440 // Set NS_FRAME_CONTAINS_RELATIVE_HEIGHT if it's needed.
442 // It would be nice to check that |mComputedHeight != NS_AUTOHEIGHT|
443 // &&ed with the percentage height check. However, this doesn't get
444 // along with table special height reflows, since a special height
445 // reflow (a quirk that makes such percentage heights work on children
446 // of table cells) can cause not just a single percentage height to
447 // become fixed, but an entire descendant chain of percentage heights
449 if (dependsOnCBHeight
&& mCBReflowState
) {
450 const nsHTMLReflowState
*rs
= this;
451 PRBool hitCBReflowState
= PR_FALSE
;
453 rs
= rs
->parentReflowState
;
458 if (rs
->frame
->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT
)
459 break; // no need to go further
460 rs
->frame
->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT
);
462 // Keep track of whether we've hit the containing block, because
463 // we need to go at least that far.
464 if (rs
== mCBReflowState
) {
465 hitCBReflowState
= PR_TRUE
;
468 } while (!hitCBReflowState
||
469 (eCompatibility_NavQuirks
== aPresContext
->CompatibilityMode() &&
470 !IsQuirkContainingBlockHeight(rs
)));
471 // Note: We actually don't need to set the
472 // NS_FRAME_CONTAINS_RELATIVE_HEIGHT bit for the cases
473 // where we hit the early break statements in
474 // CalcQuirkContainingBlockHeight. But it doesn't hurt
475 // us to set the bit in these cases.
478 if (frame
->GetStateBits() & NS_FRAME_IS_DIRTY
) {
479 // If we're reflowing everything, then we'll find out if we need
481 frame
->RemoveStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT
);
487 nsHTMLReflowState::GetContainingBlockContentWidth(const nsHTMLReflowState
* aReflowState
)
489 const nsHTMLReflowState
* rs
= aReflowState
->mCBReflowState
;
492 return rs
->mComputedWidth
;
497 nsHTMLReflowState::GetContainingBlockFor(const nsIFrame
* aFrame
)
499 NS_PRECONDITION(aFrame
, "Must have frame to work with");
500 nsIFrame
* container
= aFrame
->GetParent();
501 if (aFrame
->GetStyleDisplay()->IsAbsolutelyPositioned()) {
502 // Absolutely positioned frames are just kids of their containing
503 // blocks (which may happen to be inlines).
506 while (container
&& !container
->IsContainingBlock()) {
507 container
= container
->GetParent();
513 nsHTMLReflowState::InitFrameType()
515 const nsStyleDisplay
*disp
= mStyleDisplay
;
516 nsCSSFrameType frameType
;
518 // Section 9.7 of the CSS2 spec indicates that absolute position
519 // takes precedence over float which takes precedence over display.
520 // XXXldb nsRuleNode::ComputeDisplayData should take care of this, right?
521 // Make sure the frame was actually moved out of the flow, and don't
523 // just assume what the style says, because we might not have had a
524 // useful float/absolute containing block
525 nsIFrame
* frameToTest
=
526 frame
->GetType() == nsGkAtoms::tableFrame
? frame
->GetParent() : frame
;
528 DISPLAY_INIT_TYPE(frameToTest
, this);
530 NS_ASSERTION(frameToTest
->GetStyleDisplay()->IsAbsolutelyPositioned() ==
531 disp
->IsAbsolutelyPositioned(),
532 "Unexpected position style");
533 NS_ASSERTION(frameToTest
->GetStyleDisplay()->IsFloating() ==
534 disp
->IsFloating(), "Unexpected float style");
535 if (frameToTest
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
536 if (disp
->IsAbsolutelyPositioned()) {
537 frameType
= NS_CSS_FRAME_TYPE_ABSOLUTE
;
538 //XXXfr hack for making frames behave properly when in overflow container lists
539 // see bug 154892; need to revisit later
540 if (frameToTest
->GetPrevInFlow())
541 frameType
= NS_CSS_FRAME_TYPE_BLOCK
;
543 else if (disp
->IsFloating()) {
544 frameType
= NS_CSS_FRAME_TYPE_FLOATING
;
546 NS_ASSERTION(disp
->mDisplay
== NS_STYLE_DISPLAY_POPUP
,
547 "unknown out of flow frame type");
548 frameType
= NS_CSS_FRAME_TYPE_UNKNOWN
;
552 switch (disp
->mDisplay
) {
553 case NS_STYLE_DISPLAY_BLOCK
:
554 case NS_STYLE_DISPLAY_LIST_ITEM
:
555 case NS_STYLE_DISPLAY_TABLE
:
556 case NS_STYLE_DISPLAY_TABLE_CAPTION
:
557 frameType
= NS_CSS_FRAME_TYPE_BLOCK
;
560 case NS_STYLE_DISPLAY_INLINE
:
561 case NS_STYLE_DISPLAY_INLINE_BLOCK
:
562 case NS_STYLE_DISPLAY_MARKER
:
563 case NS_STYLE_DISPLAY_INLINE_TABLE
:
564 case NS_STYLE_DISPLAY_INLINE_BOX
:
565 case NS_STYLE_DISPLAY_INLINE_GRID
:
566 case NS_STYLE_DISPLAY_INLINE_STACK
:
567 frameType
= NS_CSS_FRAME_TYPE_INLINE
;
570 case NS_STYLE_DISPLAY_RUN_IN
:
571 case NS_STYLE_DISPLAY_COMPACT
:
572 // XXX need to look ahead at the frame's sibling
573 frameType
= NS_CSS_FRAME_TYPE_BLOCK
;
576 case NS_STYLE_DISPLAY_TABLE_CELL
:
577 case NS_STYLE_DISPLAY_TABLE_ROW_GROUP
:
578 case NS_STYLE_DISPLAY_TABLE_COLUMN
:
579 case NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
:
580 case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
:
581 case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP
:
582 case NS_STYLE_DISPLAY_TABLE_ROW
:
583 frameType
= NS_CSS_FRAME_TYPE_INTERNAL_TABLE
;
586 case NS_STYLE_DISPLAY_NONE
:
588 frameType
= NS_CSS_FRAME_TYPE_UNKNOWN
;
593 // See if the frame is replaced
594 if (frame
->IsFrameOfType(nsIFrame::eReplacedContainsBlock
)) {
595 frameType
= NS_FRAME_REPLACED_CONTAINS_BLOCK(frameType
);
596 } else if (frame
->IsFrameOfType(nsIFrame::eReplaced
)) {
597 frameType
= NS_FRAME_REPLACED(frameType
);
600 mFrameType
= frameType
;
604 nsHTMLReflowState::ComputeRelativeOffsets(const nsHTMLReflowState
* cbrs
,
605 nscoord aContainingBlockWidth
,
606 nscoord aContainingBlockHeight
,
607 nsPresContext
* aPresContext
)
609 // Compute the 'left' and 'right' values. 'Left' moves the boxes to the right,
610 // and 'right' moves the boxes to the left. The computed values are always:
612 PRBool leftIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetLeftUnit();
613 PRBool rightIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetRightUnit();
615 // If neither 'left' not 'right' are auto, then we're over-constrained and
616 // we ignore one of them
617 if (!leftIsAuto
&& !rightIsAuto
) {
618 if (mCBReflowState
&&
619 NS_STYLE_DIRECTION_RTL
== mCBReflowState
->mStyleVisibility
->mDirection
) {
620 leftIsAuto
= PR_TRUE
;
622 rightIsAuto
= PR_TRUE
;
628 // If both are 'auto' (their initial values), the computed values are 0
629 mComputedOffsets
.left
= mComputedOffsets
.right
= 0;
631 // 'Right' isn't 'auto' so compute its value
632 mComputedOffsets
.right
= nsLayoutUtils::
633 ComputeWidthDependentValue(aContainingBlockWidth
,
634 mStylePosition
->mOffset
.GetRight());
636 // Computed value for 'left' is minus the value of 'right'
637 mComputedOffsets
.left
= -mComputedOffsets
.right
;
641 NS_ASSERTION(rightIsAuto
, "unexpected specified constraint");
643 // 'Left' isn't 'auto' so compute its value
644 mComputedOffsets
.left
= nsLayoutUtils::
645 ComputeWidthDependentValue(aContainingBlockWidth
,
646 mStylePosition
->mOffset
.GetLeft());
648 // Computed value for 'right' is minus the value of 'left'
649 mComputedOffsets
.right
= -mComputedOffsets
.left
;
652 // Compute the 'top' and 'bottom' values. The 'top' and 'bottom' properties
653 // move relatively positioned elements up and down. They also must be each
655 PRBool topIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetTopUnit();
656 PRBool bottomIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetBottomUnit();
658 // Check for percentage based values and a containing block height that
659 // depends on the content height. Treat them like 'auto'
660 if (NS_AUTOHEIGHT
== aContainingBlockHeight
) {
661 if (mStylePosition
->OffsetHasPercent(NS_SIDE_TOP
)) {
664 if (mStylePosition
->OffsetHasPercent(NS_SIDE_BOTTOM
)) {
665 bottomIsAuto
= PR_TRUE
;
669 // If neither is 'auto', 'bottom' is ignored
670 if (!topIsAuto
&& !bottomIsAuto
) {
671 bottomIsAuto
= PR_TRUE
;
676 // If both are 'auto' (their initial values), the computed values are 0
677 mComputedOffsets
.top
= mComputedOffsets
.bottom
= 0;
679 // 'Bottom' isn't 'auto' so compute its value
680 mComputedOffsets
.bottom
= nsLayoutUtils::
681 ComputeHeightDependentValue(aContainingBlockHeight
,
682 mStylePosition
->mOffset
.GetBottom());
684 // Computed value for 'top' is minus the value of 'bottom'
685 mComputedOffsets
.top
= -mComputedOffsets
.bottom
;
689 NS_ASSERTION(bottomIsAuto
, "unexpected specified constraint");
691 // 'Top' isn't 'auto' so compute its value
692 mComputedOffsets
.top
= nsLayoutUtils::
693 ComputeHeightDependentValue(aContainingBlockHeight
,
694 mStylePosition
->mOffset
.GetTop());
696 // Computed value for 'bottom' is minus the value of 'top'
697 mComputedOffsets
.bottom
= -mComputedOffsets
.top
;
701 FrameProperties
props(aPresContext
->PropertyTable(), frame
);
702 nsPoint
* offsets
= static_cast<nsPoint
*>
703 (props
.Get(nsIFrame::ComputedOffsetProperty()));
705 offsets
->MoveTo(mComputedOffsets
.left
, mComputedOffsets
.top
);
707 props
.Set(nsIFrame::ComputedOffsetProperty(),
708 new nsPoint(mComputedOffsets
.left
, mComputedOffsets
.top
));
713 GetNearestContainingBlock(nsIFrame
*aFrame
)
715 nsIFrame
*cb
= aFrame
;
717 cb
= cb
->GetParent();
718 } while (!cb
->IsContainingBlock());
723 nsHTMLReflowState::GetHypotheticalBoxContainer(nsIFrame
* aFrame
,
724 nscoord
& aCBLeftEdge
,
727 aFrame
= GetNearestContainingBlock(aFrame
);
728 NS_ASSERTION(aFrame
!= frame
, "How did that happen?");
730 /* Now aFrame is the containing block we want */
732 /* Check whether the containing block is currently being reflowed.
733 If so, use the info from the reflow state. */
734 const nsHTMLReflowState
* state
;
735 if (aFrame
->GetStateBits() & NS_FRAME_IN_REFLOW
) {
736 for (state
= parentReflowState
; state
&& state
->frame
!= aFrame
;
737 state
= state
->parentReflowState
) {
745 aCBLeftEdge
= state
->mComputedBorderPadding
.left
;
746 aCBWidth
= state
->mComputedWidth
;
748 /* Didn't find a reflow state for aFrame. Just compute the information we
749 want, on the assumption that aFrame already knows its size. This really
750 ought to be true by now. */
751 NS_ASSERTION(!(aFrame
->GetStateBits() & NS_FRAME_IN_REFLOW
),
752 "aFrame shouldn't be in reflow; we'll lie if it is");
753 nsMargin borderPadding
= aFrame
->GetUsedBorderAndPadding();
754 aCBLeftEdge
= borderPadding
.left
;
755 aCBWidth
= aFrame
->GetSize().width
- borderPadding
.LeftRight();
761 // When determining the hypothetical box that would have been if the element
762 // had been in the flow we may not be able to exactly determine both the left
763 // and right edges. For example, if the element is a non-replaced inline-level
764 // element we would have to reflow it in order to determine it desired width.
765 // In that case depending on the progression direction either the left or
766 // right edge would be marked as not being exact
767 struct nsHypotheticalBox
{
768 // offsets from left edge of containing block (which is a padding edge)
769 nscoord mLeft
, mRight
;
770 // offset from top edge of containing block (which is a padding edge)
773 PRPackedBool mLeftIsExact
, mRightIsExact
;
776 nsHypotheticalBox() {
778 mLeftIsExact
= mRightIsExact
= PR_FALSE
;
784 GetIntrinsicSizeFor(nsIFrame
* aFrame
, nsSize
& aIntrinsicSize
)
786 // See if it is an image frame
787 PRBool success
= PR_FALSE
;
789 // Currently the only type of replaced frame that we can get the intrinsic
790 // size for is an image frame
791 // XXX We should add back the GetReflowMetrics() function and one of the
792 // things should be the intrinsic size...
793 if (aFrame
->GetType() == nsGkAtoms::imageFrame
) {
794 nsImageFrame
* imageFrame
= (nsImageFrame
*)aFrame
;
796 if (NS_SUCCEEDED(imageFrame
->GetIntrinsicImageSize(aIntrinsicSize
))) {
797 success
= (aIntrinsicSize
!= nsSize(0, 0));
804 * aInsideBoxSizing returns the part of the horizontal padding, border,
805 * and margin that goes inside the edge given by -moz-box-sizing;
806 * aOutsideBoxSizing returns the rest.
809 nsHTMLReflowState::CalculateHorizBorderPaddingMargin(
810 nscoord aContainingBlockWidth
,
811 nscoord
* aInsideBoxSizing
,
812 nscoord
* aOutsideBoxSizing
)
814 const nsMargin
& border
= mStyleBorder
->GetActualBorder();
815 nsMargin padding
, margin
;
817 // See if the style system can provide us the padding directly
818 if (!mStylePadding
->GetPadding(padding
)) {
819 // We have to compute the left and right values
820 padding
.left
= nsLayoutUtils::
821 ComputeWidthDependentValue(aContainingBlockWidth
,
822 mStylePadding
->mPadding
.GetLeft());
823 padding
.right
= nsLayoutUtils::
824 ComputeWidthDependentValue(aContainingBlockWidth
,
825 mStylePadding
->mPadding
.GetRight());
828 // See if the style system can provide us the margin directly
829 if (!mStyleMargin
->GetMargin(margin
)) {
830 // We have to compute the left and right values
831 if (eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetLeftUnit()) {
832 // XXX FIXME (or does CalculateBlockSideMargins do this?)
833 margin
.left
= 0; // just ignore
835 margin
.left
= nsLayoutUtils::
836 ComputeWidthDependentValue(aContainingBlockWidth
,
837 mStyleMargin
->mMargin
.GetLeft());
839 if (eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetRightUnit()) {
840 // XXX FIXME (or does CalculateBlockSideMargins do this?)
841 margin
.right
= 0; // just ignore
843 margin
.right
= nsLayoutUtils::
844 ComputeWidthDependentValue(aContainingBlockWidth
,
845 mStyleMargin
->mMargin
.GetRight());
850 padding
.LeftRight() + border
.LeftRight() + margin
.LeftRight();
852 switch (mStylePosition
->mBoxSizing
) {
853 case NS_STYLE_BOX_SIZING_BORDER
:
854 inside
+= border
.LeftRight();
856 case NS_STYLE_BOX_SIZING_PADDING
:
857 inside
+= padding
.LeftRight();
860 *aInsideBoxSizing
= inside
;
861 *aOutsideBoxSizing
= outside
;
866 * Returns PR_TRUE iff a pre-order traversal of the normal child
867 * frames rooted at aFrame finds no non-empty frame before aDescendant.
869 static PRBool
AreAllEarlierInFlowFramesEmpty(nsIFrame
* aFrame
,
870 nsIFrame
* aDescendant
, PRBool
* aFound
) {
871 if (aFrame
== aDescendant
) {
875 if (!aFrame
->IsSelfEmpty()) {
879 for (nsIFrame
* f
= aFrame
->GetFirstChild(nsnull
); f
; f
= f
->GetNextSibling()) {
880 PRBool allEmpty
= AreAllEarlierInFlowFramesEmpty(f
, aDescendant
, aFound
);
881 if (*aFound
|| !allEmpty
) {
889 // Calculate the hypothetical box that the element would have if it were in
890 // the flow. The values returned are relative to the padding edge of the
891 // absolute containing block
892 // aContainingBlock is the placeholder's containing block (XXX rename it?)
893 // cbrs->frame is the actual containing block
895 nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext
* aPresContext
,
896 nsIFrame
* aPlaceholderFrame
,
897 nsIFrame
* aContainingBlock
,
898 nscoord aBlockLeftContentEdge
,
899 nscoord aBlockContentWidth
,
900 const nsHTMLReflowState
* cbrs
,
901 nsHypotheticalBox
& aHypotheticalBox
)
903 NS_ASSERTION(mStyleDisplay
->mOriginalDisplay
!= NS_STYLE_DISPLAY_NONE
,
904 "mOriginalDisplay has not been properly initialized");
906 // If it's a replaced element and it has a 'auto' value for 'width', see if we
907 // can get the intrinsic size. This will allow us to exactly determine both the
908 // left and right edges
909 PRBool isAutoWidth
= mStylePosition
->mWidth
.GetUnit() == eStyleUnit_Auto
;
910 nsSize intrinsicSize
;
911 PRBool knowIntrinsicSize
= PR_FALSE
;
912 if (NS_FRAME_IS_REPLACED(mFrameType
) && isAutoWidth
) {
913 // See if we can get the intrinsic size of the element
914 knowIntrinsicSize
= GetIntrinsicSizeFor(frame
, intrinsicSize
);
917 // See if we can calculate what the box width would have been if the
918 // element had been in the flow
920 PRBool knowBoxWidth
= PR_FALSE
;
921 if ((NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) &&
922 !NS_FRAME_IS_REPLACED(mFrameType
)) {
923 // For non-replaced inline-level elements the 'width' property doesn't apply,
924 // so we don't know what the width would have been without reflowing it
927 // It's either a replaced inline-level element or a block-level element
929 // Determine the total amount of horizontal border/padding/margin that
930 // the element would have had if it had been in the flow. Note that we
931 // ignore any 'auto' and 'inherit' values
932 nscoord insideBoxSizing
, outsideBoxSizing
;
933 CalculateHorizBorderPaddingMargin(aBlockContentWidth
,
934 &insideBoxSizing
, &outsideBoxSizing
);
936 if (NS_FRAME_IS_REPLACED(mFrameType
) && isAutoWidth
) {
937 // It's a replaced element with an 'auto' width so the box width is
938 // its intrinsic size plus any border/padding/margin
939 if (knowIntrinsicSize
) {
940 boxWidth
= intrinsicSize
.width
+ outsideBoxSizing
+ insideBoxSizing
;
941 knowBoxWidth
= PR_TRUE
;
944 } else if (isAutoWidth
) {
945 // The box width is the containing block width
946 boxWidth
= aBlockContentWidth
;
947 knowBoxWidth
= PR_TRUE
;
950 // We need to compute it. It's important we do this, because if it's
951 // percentage based this computed value may be different from the computed
952 // value calculated using the absolute containing block width
953 boxWidth
= ComputeWidthValue(aBlockContentWidth
,
954 insideBoxSizing
, outsideBoxSizing
,
955 mStylePosition
->mWidth
) +
956 insideBoxSizing
+ outsideBoxSizing
;
957 knowBoxWidth
= PR_TRUE
;
961 // Get the 'direction' of the block
962 const nsStyleVisibility
* blockVis
= aContainingBlock
->GetStyleVisibility();
964 // Get the placeholder x-offset and y-offset in the coordinate
965 // space of its containing block
966 // XXXbz the placeholder is not fully reflowed yet if our containing block is
967 // relatively positioned...
968 nsPoint placeholderOffset
= aPlaceholderFrame
->GetOffsetTo(aContainingBlock
);
970 // First, determine the hypothetical box's mTop. We want to check the
971 // content insertion frame of aContainingBlock for block-ness, but make
972 // sure to compute all coordinates in the coordinate system of
974 nsBlockFrame
* blockFrame
=
975 nsLayoutUtils::GetAsBlock(aContainingBlock
->GetContentInsertionFrame());
977 nscoord blockYOffset
= blockFrame
->GetOffsetTo(aContainingBlock
).y
;
979 nsBlockInFlowLineIterator
iter(blockFrame
, aPlaceholderFrame
, &isValid
);
981 // Give up. We're probably dealing with somebody using
982 // position:absolute inside native-anonymous content anyway.
983 aHypotheticalBox
.mTop
= placeholderOffset
.y
;
985 NS_ASSERTION(iter
.GetContainer() == blockFrame
,
986 "Found placeholder in wrong block!");
987 nsBlockFrame::line_iterator lineBox
= iter
.GetLine();
989 // How we determine the hypothetical box depends on whether the element
990 // would have been inline-level or block-level
991 if (NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) {
992 // Use the top of the inline box which the placeholder lives in
993 // as the hypothetical box's top.
994 aHypotheticalBox
.mTop
= lineBox
->mBounds
.y
+ blockYOffset
;
996 // The element would have been block-level which means it would
997 // be below the line containing the placeholder frame, unless
998 // all the frames before it are empty. In that case, it would
999 // have been just before this line.
1000 // XXXbz the line box is not fully reflowed yet if our
1001 // containing block is relatively positioned...
1002 if (lineBox
!= iter
.End()) {
1003 nsIFrame
* firstFrame
= lineBox
->mFirstChild
;
1004 PRBool found
= PR_FALSE
;
1005 PRBool allEmpty
= PR_TRUE
;
1006 while (firstFrame
) { // See bug 223064
1007 allEmpty
= AreAllEarlierInFlowFramesEmpty(firstFrame
,
1008 aPlaceholderFrame
, &found
);
1009 if (found
|| !allEmpty
)
1011 firstFrame
= firstFrame
->GetNextSibling();
1013 NS_ASSERTION(firstFrame
, "Couldn't find placeholder!");
1016 // The top of the hypothetical box is the top of the line
1017 // containing the placeholder, since there is nothing in the
1018 // line before our placeholder except empty frames.
1019 aHypotheticalBox
.mTop
= lineBox
->mBounds
.y
+ blockYOffset
;
1021 // The top of the hypothetical box is just below the line
1022 // containing the placeholder.
1023 aHypotheticalBox
.mTop
= lineBox
->mBounds
.YMost() + blockYOffset
;
1026 // Just use the placeholder's y-offset wrt the containing block
1027 aHypotheticalBox
.mTop
= placeholderOffset
.y
;
1032 // The containing block is not a block, so it's probably something
1033 // like a XUL box, etc.
1034 // Just use the placeholder's y-offset
1035 aHypotheticalBox
.mTop
= placeholderOffset
.y
;
1038 // Second, determine the hypothetical box's mLeft & mRight
1039 // To determine the left and right offsets we need to look at the block's 'direction'
1040 if (NS_STYLE_DIRECTION_LTR
== blockVis
->mDirection
) {
1041 // How we determine the hypothetical box depends on whether the element
1042 // would have been inline-level or block-level
1043 if (NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) {
1044 // The placeholder represents the left edge of the hypothetical box
1045 aHypotheticalBox
.mLeft
= placeholderOffset
.x
;
1047 aHypotheticalBox
.mLeft
= aBlockLeftContentEdge
;
1050 aHypotheticalBox
.mLeftIsExact
= PR_TRUE
;
1054 aHypotheticalBox
.mRight
= aHypotheticalBox
.mLeft
+ boxWidth
;
1056 aHypotheticalBox
.mRightIsExact
= PR_TRUE
;
1059 // We can't compute the right edge because we don't know the desired
1060 // width. So instead use the right content edge of the block parent,
1061 // but remember it's not exact
1062 aHypotheticalBox
.mRight
= aBlockLeftContentEdge
+ aBlockContentWidth
;
1064 aHypotheticalBox
.mRightIsExact
= PR_FALSE
;
1069 // The placeholder represents the right edge of the hypothetical box
1070 if (NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) {
1071 aHypotheticalBox
.mRight
= placeholderOffset
.x
;
1073 aHypotheticalBox
.mRight
= aBlockLeftContentEdge
+ aBlockContentWidth
;
1076 aHypotheticalBox
.mRightIsExact
= PR_TRUE
;
1080 aHypotheticalBox
.mLeft
= aHypotheticalBox
.mRight
- boxWidth
;
1082 aHypotheticalBox
.mLeftIsExact
= PR_TRUE
;
1085 // We can't compute the left edge because we don't know the desired
1086 // width. So instead use the left content edge of the block parent,
1087 // but remember it's not exact
1088 aHypotheticalBox
.mLeft
= aBlockLeftContentEdge
;
1090 aHypotheticalBox
.mLeftIsExact
= PR_FALSE
;
1096 // The current coordinate space is that of the nearest block to the placeholder.
1097 // Convert to the coordinate space of the absolute containing block
1098 // One weird thing here is that for fixed-positioned elements we want to do
1099 // the conversion incorrectly; specifically we want to ignore any scrolling
1100 // that may have happened;
1102 if (mStyleDisplay
->mPosition
== NS_STYLE_POSITION_FIXED
&&
1103 // Exclude cases inside -moz-transform where fixed is like absolute.
1104 nsLayoutUtils::IsReallyFixedPos(frame
)) {
1105 // In this case, cbrs->frame will always be an ancestor of
1106 // aContainingBlock, so can just walk our way up the frame tree.
1107 // Make sure to not add positions of frames whose parent is a
1108 // scrollFrame, since we're doing fixed positioning, which assumes
1109 // everything is scrolled to (0,0).
1110 cbOffset
.MoveTo(0, 0);
1112 NS_ASSERTION(aContainingBlock
,
1113 "Should hit cbrs->frame before we run off the frame tree!");
1114 cbOffset
+= aContainingBlock
->GetPositionIgnoringScrolling();
1115 aContainingBlock
= aContainingBlock
->GetParent();
1116 } while (aContainingBlock
!= cbrs
->frame
);
1118 // XXXldb We need to either ignore scrolling for the absolute
1119 // positioning case too (and take the incompatibility) or figure out
1120 // how to make these positioned elements actually *move* when we
1121 // scroll, and thus avoid the resulting incremental reflow bugs.
1122 cbOffset
= aContainingBlock
->GetOffsetTo(cbrs
->frame
);
1124 aHypotheticalBox
.mLeft
+= cbOffset
.x
;
1125 aHypotheticalBox
.mTop
+= cbOffset
.y
;
1126 aHypotheticalBox
.mRight
+= cbOffset
.x
;
1128 // The specified offsets are relative to the absolute containing block's
1129 // padding edge and our current values are relative to the border edge, so
1131 nsMargin border
= cbrs
->mComputedBorderPadding
- cbrs
->mComputedPadding
;
1132 aHypotheticalBox
.mLeft
-= border
.left
;
1133 aHypotheticalBox
.mRight
-= border
.left
;
1134 aHypotheticalBox
.mTop
-= border
.top
;
1138 nsHTMLReflowState::InitAbsoluteConstraints(nsPresContext
* aPresContext
,
1139 const nsHTMLReflowState
* cbrs
,
1140 nscoord containingBlockWidth
,
1141 nscoord containingBlockHeight
)
1143 NS_PRECONDITION(containingBlockHeight
!= NS_AUTOHEIGHT
,
1144 "containing block height must be constrained");
1146 nsIFrame
* outOfFlow
=
1147 frame
->GetType() == nsGkAtoms::tableFrame
? frame
->GetParent() : frame
;
1148 NS_ASSERTION(outOfFlow
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
,
1149 "Why are we here?");
1151 // Get the placeholder frame
1152 nsIFrame
* placeholderFrame
;
1154 placeholderFrame
= aPresContext
->PresShell()->GetPlaceholderFrameFor(outOfFlow
);
1155 NS_ASSERTION(nsnull
!= placeholderFrame
, "no placeholder frame");
1157 // If both 'left' and 'right' are 'auto' or both 'top' and 'bottom' are
1158 // 'auto', then compute the hypothetical box of where the element would
1159 // have been if it had been in the flow
1160 nsHypotheticalBox hypotheticalBox
;
1161 if (((eStyleUnit_Auto
== mStylePosition
->mOffset
.GetLeftUnit()) &&
1162 (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetRightUnit())) ||
1163 ((eStyleUnit_Auto
== mStylePosition
->mOffset
.GetTopUnit()) &&
1164 (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetBottomUnit()))) {
1165 // Find the nearest containing block frame to the placeholder frame,
1166 // and return its left edge and width.
1167 nscoord cbLeftEdge
, cbWidth
;
1168 nsIFrame
* cbFrame
= GetHypotheticalBoxContainer(placeholderFrame
,
1172 CalculateHypotheticalBox(aPresContext
, placeholderFrame
, cbFrame
,
1173 cbLeftEdge
, cbWidth
, cbrs
, hypotheticalBox
);
1176 // Initialize the 'left' and 'right' computed offsets
1177 // XXX Handle new 'static-position' value...
1178 PRBool leftIsAuto
= PR_FALSE
, rightIsAuto
= PR_FALSE
;
1179 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetLeftUnit()) {
1180 mComputedOffsets
.left
= 0;
1181 leftIsAuto
= PR_TRUE
;
1183 mComputedOffsets
.left
= nsLayoutUtils::
1184 ComputeWidthDependentValue(containingBlockWidth
,
1185 mStylePosition
->mOffset
.GetLeft());
1187 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetRightUnit()) {
1188 mComputedOffsets
.right
= 0;
1189 rightIsAuto
= PR_TRUE
;
1191 mComputedOffsets
.right
= nsLayoutUtils::
1192 ComputeWidthDependentValue(containingBlockWidth
,
1193 mStylePosition
->mOffset
.GetRight());
1196 // Use the horizontal component of the hypothetical box in the cases
1197 // where it's needed.
1198 if (leftIsAuto
&& rightIsAuto
) {
1199 // Use the direction of the original ("static-position") containing block
1200 // to dictate whether 'left' or 'right' is treated like 'static-position'.
1201 if (NS_STYLE_DIRECTION_LTR
== GetNearestContainingBlock(placeholderFrame
)
1202 ->GetStyleVisibility()->mDirection
) {
1203 NS_ASSERTION(hypotheticalBox
.mLeftIsExact
, "should always have "
1204 "exact value on containing block's start side");
1205 mComputedOffsets
.left
= hypotheticalBox
.mLeft
;
1206 leftIsAuto
= PR_FALSE
;
1208 NS_ASSERTION(hypotheticalBox
.mRightIsExact
, "should always have "
1209 "exact value on containing block's start side");
1210 mComputedOffsets
.right
= containingBlockWidth
- hypotheticalBox
.mRight
;
1211 rightIsAuto
= PR_FALSE
;
1215 // Initialize the 'top' and 'bottom' computed offsets
1216 PRBool topIsAuto
= PR_FALSE
, bottomIsAuto
= PR_FALSE
;
1217 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetTopUnit()) {
1218 mComputedOffsets
.top
= 0;
1219 topIsAuto
= PR_TRUE
;
1221 mComputedOffsets
.top
= nsLayoutUtils::
1222 ComputeHeightDependentValue(containingBlockHeight
,
1223 mStylePosition
->mOffset
.GetTop());
1225 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetBottomUnit()) {
1226 mComputedOffsets
.bottom
= 0;
1227 bottomIsAuto
= PR_TRUE
;
1229 mComputedOffsets
.bottom
= nsLayoutUtils::
1230 ComputeHeightDependentValue(containingBlockHeight
,
1231 mStylePosition
->mOffset
.GetBottom());
1234 if (topIsAuto
&& bottomIsAuto
) {
1235 // Treat 'top' like 'static-position'
1236 mComputedOffsets
.top
= hypotheticalBox
.mTop
;
1237 topIsAuto
= PR_FALSE
;
1240 PRBool widthIsAuto
= eStyleUnit_Auto
== mStylePosition
->mWidth
.GetUnit();
1241 PRBool heightIsAuto
= eStyleUnit_Auto
== mStylePosition
->mHeight
.GetUnit();
1243 PRBool shrinkWrap
= leftIsAuto
|| rightIsAuto
;
1245 frame
->ComputeSize(rendContext
,
1246 nsSize(containingBlockWidth
,
1247 containingBlockHeight
),
1248 containingBlockWidth
, // XXX or availableWidth?
1249 nsSize(mComputedMargin
.LeftRight() +
1250 mComputedOffsets
.LeftRight(),
1251 mComputedMargin
.TopBottom() +
1252 mComputedOffsets
.TopBottom()),
1253 nsSize(mComputedBorderPadding
.LeftRight() -
1254 mComputedPadding
.LeftRight(),
1255 mComputedBorderPadding
.TopBottom() -
1256 mComputedPadding
.TopBottom()),
1257 nsSize(mComputedPadding
.LeftRight(),
1258 mComputedPadding
.TopBottom()),
1260 mComputedWidth
= size
.width
;
1261 mComputedHeight
= size
.height
;
1262 NS_ASSERTION(mComputedWidth
>= 0, "Bogus width");
1263 NS_ASSERTION(mComputedHeight
== NS_UNCONSTRAINEDSIZE
||
1264 mComputedHeight
>= 0, "Bogus height");
1266 // XXX Now that we have ComputeSize, can we condense many of the
1267 // branches off of widthIsAuto?
1270 // We know 'right' is not 'auto' anymore thanks to the hypothetical
1272 // Solve for 'left'.
1274 // XXXldb This, and the corresponding code in
1275 // nsAbsoluteContainingBlock.cpp, could probably go away now that
1276 // we always compute widths.
1277 mComputedOffsets
.left
= NS_AUTOOFFSET
;
1279 mComputedOffsets
.left
= containingBlockWidth
- mComputedMargin
.left
-
1280 mComputedBorderPadding
.left
- mComputedWidth
- mComputedBorderPadding
.right
-
1281 mComputedMargin
.right
- mComputedOffsets
.right
;
1284 } else if (rightIsAuto
) {
1285 // We know 'left' is not 'auto' anymore thanks to the hypothetical
1287 // Solve for 'right'.
1289 // XXXldb This, and the corresponding code in
1290 // nsAbsoluteContainingBlock.cpp, could probably go away now that
1291 // we always compute widths.
1292 mComputedOffsets
.right
= NS_AUTOOFFSET
;
1294 mComputedOffsets
.right
= containingBlockWidth
- mComputedOffsets
.left
-
1295 mComputedMargin
.left
- mComputedBorderPadding
.left
- mComputedWidth
-
1296 mComputedBorderPadding
.right
- mComputedMargin
.right
;
1299 // Neither 'left' nor 'right' is 'auto'. However, the width might
1300 // still not fill all the available space (even though we didn't
1301 // shrink-wrap) in case:
1302 // * width was specified
1303 // * we're dealing with a replaced element
1304 // * width was constrained by min-width or max-width.
1306 nscoord availMarginSpace
= containingBlockWidth
-
1307 mComputedOffsets
.LeftRight() -
1308 mComputedMargin
.LeftRight() -
1309 mComputedBorderPadding
.LeftRight() -
1311 PRBool marginLeftIsAuto
=
1312 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetLeftUnit();
1313 PRBool marginRightIsAuto
=
1314 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetRightUnit();
1316 if (availMarginSpace
< 0 ||
1317 (!marginLeftIsAuto
&& !marginRightIsAuto
)) {
1318 // We're over-constrained so use the direction of the containing block
1319 // to dictate which value to ignore. (And note that the spec says to ignore
1320 // 'left' or 'right' rather than 'margin-left' or 'margin-right'.)
1322 NS_STYLE_DIRECTION_RTL
== cbrs
->mStyleVisibility
->mDirection
) {
1323 // Ignore the specified value for 'left'.
1324 mComputedOffsets
.left
+= availMarginSpace
;
1326 // Ignore the specified value for 'right'.
1327 mComputedOffsets
.right
+= availMarginSpace
;
1329 } else if (marginLeftIsAuto
) {
1330 if (marginRightIsAuto
) {
1331 // Both 'margin-left' and 'margin-right' are 'auto', so they get
1333 mComputedMargin
.left
= availMarginSpace
/ 2;
1334 mComputedMargin
.right
= availMarginSpace
- mComputedMargin
.left
;
1336 // Just 'margin-left' is 'auto'
1337 mComputedMargin
.left
= availMarginSpace
;
1340 // Just 'margin-right' is 'auto'
1341 mComputedMargin
.right
= availMarginSpace
;
1348 mComputedOffsets
.top
= NS_AUTOOFFSET
;
1350 mComputedOffsets
.top
= containingBlockHeight
- mComputedMargin
.top
-
1351 mComputedBorderPadding
.top
- mComputedHeight
- mComputedBorderPadding
.bottom
-
1352 mComputedMargin
.bottom
- mComputedOffsets
.bottom
;
1354 } else if (bottomIsAuto
) {
1355 // solve for 'bottom'
1357 mComputedOffsets
.bottom
= NS_AUTOOFFSET
;
1359 mComputedOffsets
.bottom
= containingBlockHeight
- mComputedOffsets
.top
-
1360 mComputedMargin
.top
- mComputedBorderPadding
.top
- mComputedHeight
-
1361 mComputedBorderPadding
.bottom
- mComputedMargin
.bottom
;
1364 // Neither 'top' nor 'bottom' is 'auto'.
1365 nscoord autoHeight
= containingBlockHeight
-
1366 mComputedOffsets
.TopBottom() -
1367 mComputedMargin
.TopBottom() -
1368 mComputedBorderPadding
.TopBottom();
1369 if (autoHeight
< 0) {
1373 if (mComputedHeight
== NS_UNCONSTRAINEDSIZE
) {
1374 // For non-replaced elements with 'height' auto, the 'height'
1375 // fills the remaining space.
1376 mComputedHeight
= autoHeight
;
1378 // XXX Do these need box-sizing adjustments?
1379 if (mComputedHeight
> mComputedMaxHeight
)
1380 mComputedHeight
= mComputedMaxHeight
;
1381 if (mComputedHeight
< mComputedMinHeight
)
1382 mComputedHeight
= mComputedMinHeight
;
1385 // The height might still not fill all the available space in case:
1386 // * height was specified
1387 // * we're dealing with a replaced element
1388 // * height was constrained by min-height or max-height.
1389 nscoord availMarginSpace
= autoHeight
- mComputedHeight
;
1390 PRBool marginTopIsAuto
=
1391 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetTopUnit();
1392 PRBool marginBottomIsAuto
=
1393 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetBottomUnit();
1395 if (availMarginSpace
< 0 || (!marginTopIsAuto
&& !marginBottomIsAuto
)) {
1396 // We're over-constrained so ignore the specified value for
1397 // 'bottom'. (And note that the spec says to ignore 'bottom'
1398 // rather than 'margin-bottom'.)
1399 mComputedOffsets
.bottom
+= availMarginSpace
;
1400 } else if (marginTopIsAuto
) {
1401 if (marginBottomIsAuto
) {
1402 // Both 'margin-top' and 'margin-bottom' are 'auto', so they get
1404 mComputedMargin
.top
= availMarginSpace
/ 2;
1405 mComputedMargin
.bottom
= availMarginSpace
- mComputedMargin
.top
;
1407 // Just 'margin-top' is 'auto'
1408 mComputedMargin
.top
= availMarginSpace
;
1411 // Just 'margin-bottom' is 'auto'
1412 mComputedMargin
.bottom
= availMarginSpace
;
1418 GetVerticalMarginBorderPadding(const nsHTMLReflowState
* aReflowState
)
1421 if (!aReflowState
) return result
;
1423 // zero auto margins
1424 nsMargin margin
= aReflowState
->mComputedMargin
;
1425 if (NS_AUTOMARGIN
== margin
.top
)
1427 if (NS_AUTOMARGIN
== margin
.bottom
)
1430 result
+= margin
.top
+ margin
.bottom
;
1431 result
+= aReflowState
->mComputedBorderPadding
.top
+
1432 aReflowState
->mComputedBorderPadding
.bottom
;
1437 /* Get the height based on the viewport of the containing block specified
1438 * in aReflowState when the containing block has mComputedHeight == NS_AUTOHEIGHT
1439 * This will walk up the chain of containing blocks looking for a computed height
1440 * until it finds the canvas frame, or it encounters a frame that is not a block,
1441 * area, or scroll frame. This handles compatibility with IE (see bug 85016 and bug 219693)
1443 * When we encounter scrolledContent block frames, we skip over them, since they are guaranteed to not be useful for computing the containing block.
1445 * See also IsQuirkContainingBlockHeight.
1448 CalcQuirkContainingBlockHeight(const nsHTMLReflowState
* aCBReflowState
)
1450 nsHTMLReflowState
* firstAncestorRS
= nsnull
; // a candidate for html frame
1451 nsHTMLReflowState
* secondAncestorRS
= nsnull
; // a candidate for body frame
1453 // initialize the default to NS_AUTOHEIGHT as this is the containings block
1454 // computed height when this function is called. It is possible that we
1455 // don't alter this height especially if we are restricted to one level
1456 nscoord result
= NS_AUTOHEIGHT
;
1458 const nsHTMLReflowState
* rs
= aCBReflowState
;
1459 for (; rs
; rs
= (nsHTMLReflowState
*)(rs
->parentReflowState
)) {
1460 nsIAtom
* frameType
= rs
->frame
->GetType();
1461 // if the ancestor is auto height then skip it and continue up if it
1462 // is the first block frame and possibly the body/html
1463 if (nsGkAtoms::blockFrame
== frameType
||
1465 nsGkAtoms::XULLabelFrame
== frameType
||
1467 nsGkAtoms::scrollFrame
== frameType
) {
1469 secondAncestorRS
= firstAncestorRS
;
1470 firstAncestorRS
= (nsHTMLReflowState
*)rs
;
1472 // If the current frame we're looking at is positioned, we don't want to
1473 // go any further (see bug 221784). The behavior we want here is: 1) If
1474 // not auto-height, use this as the percentage base. 2) If auto-height,
1475 // keep looking, unless the frame is positioned.
1476 if (NS_AUTOHEIGHT
== rs
->ComputedHeight()) {
1477 if (rs
->frame
->GetStyleDisplay()->IsAbsolutelyPositioned()) {
1484 else if (nsGkAtoms::canvasFrame
== frameType
) {
1485 // Always continue on to the height calculation
1487 else if (nsGkAtoms::pageContentFrame
== frameType
) {
1488 nsIFrame
* prevInFlow
= rs
->frame
->GetPrevInFlow();
1489 // only use the page content frame for a height basis if it is the first in flow
1497 // if the ancestor is the page content frame then the percent base is
1498 // the avail height, otherwise it is the computed height
1499 result
= (nsGkAtoms::pageContentFrame
== frameType
)
1500 ? rs
->availableHeight
: rs
->ComputedHeight();
1501 // if unconstrained - don't sutract borders - would result in huge height
1502 if (NS_AUTOHEIGHT
== result
) return result
;
1504 // if we got to the canvas or page content frame, then subtract out
1505 // margin/border/padding for the BODY and HTML elements
1506 if ((nsGkAtoms::canvasFrame
== frameType
) ||
1507 (nsGkAtoms::pageContentFrame
== frameType
)) {
1509 result
-= GetVerticalMarginBorderPadding(firstAncestorRS
);
1510 result
-= GetVerticalMarginBorderPadding(secondAncestorRS
);
1513 // make sure the first ancestor is the HTML and the second is the BODY
1514 if (firstAncestorRS
) {
1515 nsIContent
* frameContent
= firstAncestorRS
->frame
->GetContent();
1517 nsIAtom
*contentTag
= frameContent
->Tag();
1518 NS_ASSERTION(contentTag
== nsGkAtoms::html
, "First ancestor is not HTML");
1521 if (secondAncestorRS
) {
1522 nsIContent
* frameContent
= secondAncestorRS
->frame
->GetContent();
1524 nsIAtom
*contentTag
= frameContent
->Tag();
1525 NS_ASSERTION(contentTag
== nsGkAtoms::body
, "Second ancestor is not BODY");
1531 // if we got to the html frame (a block child of the canvas) ...
1532 else if (nsGkAtoms::blockFrame
== frameType
&&
1533 nsGkAtoms::canvasFrame
==
1534 rs
->parentReflowState
->frame
->GetType()) {
1535 // ... then subtract out margin/border/padding for the BODY element
1536 result
-= GetVerticalMarginBorderPadding(secondAncestorRS
);
1541 // Make sure not to return a negative height here!
1542 return NS_MAX(result
, 0);
1544 // Called by InitConstraints() to compute the containing block rectangle for
1545 // the element. Handles the special logic for absolutely positioned elements
1547 nsHTMLReflowState::ComputeContainingBlockRectangle(nsPresContext
* aPresContext
,
1548 const nsHTMLReflowState
* aContainingBlockRS
,
1549 nscoord
& aContainingBlockWidth
,
1550 nscoord
& aContainingBlockHeight
)
1552 // Unless the element is absolutely positioned, the containing block is
1553 // formed by the content edge of the nearest block-level ancestor
1554 aContainingBlockWidth
= aContainingBlockRS
->mComputedWidth
;
1555 aContainingBlockHeight
= aContainingBlockRS
->mComputedHeight
;
1557 if (NS_FRAME_GET_TYPE(mFrameType
) == NS_CSS_FRAME_TYPE_ABSOLUTE
) {
1558 // See if the ancestor is block-level or inline-level
1559 if (NS_FRAME_GET_TYPE(aContainingBlockRS
->mFrameType
) == NS_CSS_FRAME_TYPE_INLINE
) {
1560 // Base our size on the actual size of the frame. In cases when this is
1561 // completely bogus (eg initial reflow), this code shouldn't even be
1562 // called, since the code in nsPositionedInlineFrame::Reflow will pass in
1563 // the containing block dimensions to our constructor.
1564 // XXXbz we should be taking the in-flows into account too, but
1565 // that's very hard.
1566 nsMargin computedBorder
= aContainingBlockRS
->mComputedBorderPadding
-
1567 aContainingBlockRS
->mComputedPadding
;
1568 aContainingBlockWidth
= aContainingBlockRS
->frame
->GetRect().width
-
1569 computedBorder
.LeftRight();;
1570 NS_ASSERTION(aContainingBlockWidth
>= 0,
1571 "Negative containing block width!");
1572 aContainingBlockHeight
= aContainingBlockRS
->frame
->GetRect().height
-
1573 computedBorder
.TopBottom();
1574 NS_ASSERTION(aContainingBlockHeight
>= 0,
1575 "Negative containing block height!");
1577 // If the ancestor is block-level, the containing block is formed by the
1578 // padding edge of the ancestor
1579 aContainingBlockWidth
+= aContainingBlockRS
->mComputedPadding
.LeftRight();
1580 aContainingBlockHeight
+= aContainingBlockRS
->mComputedPadding
.TopBottom();
1583 // an element in quirks mode gets a containing block based on looking for a
1584 // parent with a non-auto height if the element has a percent height
1585 // Note: We don't emulate this quirk for percents in calc().
1586 if (NS_AUTOHEIGHT
== aContainingBlockHeight
) {
1587 if (eCompatibility_NavQuirks
== aPresContext
->CompatibilityMode() &&
1588 mStylePosition
->mHeight
.GetUnit() == eStyleUnit_Percent
) {
1589 aContainingBlockHeight
= CalcQuirkContainingBlockHeight(aContainingBlockRS
);
1595 // Prefs callback to pick up changes
1597 PrefsChanged(const char *aPrefName
, void *instance
)
1600 nsContentUtils::GetBoolPref("browser.blink_allowed", sBlinkIsAllowed
);
1602 return 0; /* PREF_OK */
1605 // Check to see if |text-decoration: blink| is allowed. The first time
1606 // called, register the callback and then force-load the pref. After that,
1607 // just use the cached value.
1608 static PRBool
BlinkIsAllowed(void)
1610 if (!sPrefIsLoaded
) {
1611 // Set up a listener and check the initial value
1612 nsContentUtils::RegisterPrefCallback("browser.blink_allowed", PrefsChanged
,
1614 PrefsChanged(nsnull
, nsnull
);
1615 sPrefIsLoaded
= PR_TRUE
;
1617 return sBlinkIsAllowed
;
1620 static eNormalLineHeightControl
GetNormalLineHeightCalcControl(void)
1622 if (sNormalLineHeightControl
== eUninitialized
) {
1623 // browser.display.normal_lineheight_calc_control is not user
1624 // changeable, so no need to register callback for it.
1625 sNormalLineHeightControl
=
1626 static_cast<eNormalLineHeightControl
>
1627 (nsContentUtils::GetIntPref("browser.display.normal_lineheight_calc_control", eNoExternalLeading
));
1629 return sNormalLineHeightControl
;
1632 static inline PRBool
1633 IsSideCaption(nsIFrame
* aFrame
, const nsStyleDisplay
* aStyleDisplay
)
1635 if (aStyleDisplay
->mDisplay
!= NS_STYLE_DISPLAY_TABLE_CAPTION
)
1637 PRUint8 captionSide
= aFrame
->GetStyleTableBorder()->mCaptionSide
;
1638 return captionSide
== NS_STYLE_CAPTION_SIDE_LEFT
||
1639 captionSide
== NS_STYLE_CAPTION_SIDE_RIGHT
;
1642 // XXX refactor this code to have methods for each set of properties
1643 // we are computing: width,height,line-height; margin; offsets
1646 nsHTMLReflowState::InitConstraints(nsPresContext
* aPresContext
,
1647 nscoord aContainingBlockWidth
,
1648 nscoord aContainingBlockHeight
,
1649 const nsMargin
* aBorder
,
1650 const nsMargin
* aPadding
)
1652 DISPLAY_INIT_CONSTRAINTS(frame
, this,
1653 aContainingBlockWidth
, aContainingBlockHeight
,
1656 // If this is the root frame, then set the computed width and
1657 // height equal to the available space
1658 if (nsnull
== parentReflowState
) {
1659 // XXXldb This doesn't mean what it used to!
1660 InitOffsets(aContainingBlockWidth
, aBorder
, aPadding
);
1661 // Override mComputedMargin since reflow roots start from the
1662 // frame's boundary, which is inside the margin.
1663 mComputedMargin
.SizeTo(0, 0, 0, 0);
1664 mComputedOffsets
.SizeTo(0, 0, 0, 0);
1666 mComputedWidth
= availableWidth
- mComputedBorderPadding
.LeftRight();
1667 if (mComputedWidth
< 0)
1669 if (availableHeight
!= NS_UNCONSTRAINEDSIZE
) {
1670 mComputedHeight
= availableHeight
- mComputedBorderPadding
.TopBottom();
1671 if (mComputedHeight
< 0)
1672 mComputedHeight
= 0;
1674 mComputedHeight
= NS_UNCONSTRAINEDSIZE
;
1677 mComputedMinWidth
= mComputedMinHeight
= 0;
1678 mComputedMaxWidth
= mComputedMaxHeight
= NS_UNCONSTRAINEDSIZE
;
1680 // Get the containing block reflow state
1681 const nsHTMLReflowState
* cbrs
= mCBReflowState
;
1682 NS_ASSERTION(nsnull
!= cbrs
, "no containing block");
1684 // If we weren't given a containing block width and height, then
1686 if (aContainingBlockWidth
== -1) {
1687 ComputeContainingBlockRectangle(aPresContext
, cbrs
, aContainingBlockWidth
,
1688 aContainingBlockHeight
);
1691 // See if the containing block height is based on the size of its
1694 if (NS_AUTOHEIGHT
== aContainingBlockHeight
) {
1695 // See if the containing block is a cell frame which needs
1696 // to use the mComputedHeight of the cell instead of what the cell block passed in.
1697 // XXX It seems like this could lead to bugs with min-height and friends
1698 if (cbrs
->parentReflowState
) {
1699 fType
= cbrs
->frame
->GetType();
1700 if (IS_TABLE_CELL(fType
)) {
1701 // use the cell's computed height
1702 aContainingBlockHeight
= cbrs
->mComputedHeight
;
1707 InitOffsets(aContainingBlockWidth
, aBorder
, aPadding
);
1709 const nsStyleCoord
&height
= mStylePosition
->mHeight
;
1710 nsStyleUnit heightUnit
= height
.GetUnit();
1712 // Check for a percentage based height and a containing block height
1713 // that depends on the content height
1714 // XXX twiddling heightUnit doesn't help anymore
1715 // FIXME Shouldn't we fix that?
1716 if (height
.HasPercent()) {
1717 if (NS_AUTOHEIGHT
== aContainingBlockHeight
) {
1718 // this if clause enables %-height on replaced inline frames,
1719 // such as images. See bug 54119. The else clause "heightUnit = eStyleUnit_Auto;"
1720 // used to be called exclusively.
1721 if (NS_FRAME_REPLACED(NS_CSS_FRAME_TYPE_INLINE
) == mFrameType
||
1722 NS_FRAME_REPLACED_CONTAINS_BLOCK(
1723 NS_CSS_FRAME_TYPE_INLINE
) == mFrameType
) {
1724 // Get the containing block reflow state
1725 NS_ASSERTION(nsnull
!= cbrs
, "no containing block");
1726 // in quirks mode, get the cb height using the special quirk method
1727 if (eCompatibility_NavQuirks
== aPresContext
->CompatibilityMode()) {
1728 if (!IS_TABLE_CELL(fType
)) {
1729 aContainingBlockHeight
= CalcQuirkContainingBlockHeight(cbrs
);
1730 if (aContainingBlockHeight
== NS_AUTOHEIGHT
) {
1731 heightUnit
= eStyleUnit_Auto
;
1735 heightUnit
= eStyleUnit_Auto
;
1738 // in standard mode, use the cb height. if it's "auto", as will be the case
1739 // by default in BODY, use auto height as per CSS2 spec.
1742 if (NS_AUTOHEIGHT
!= cbrs
->mComputedHeight
)
1743 aContainingBlockHeight
= cbrs
->mComputedHeight
;
1745 heightUnit
= eStyleUnit_Auto
;
1749 // default to interpreting the height like 'auto'
1750 heightUnit
= eStyleUnit_Auto
;
1755 // Compute our offsets if the element is relatively positioned. We need
1756 // the correct containing block width and height here, which is why we need
1757 // to do it after all the quirks-n-such above.
1758 if (NS_STYLE_POSITION_RELATIVE
== mStyleDisplay
->mPosition
) {
1759 ComputeRelativeOffsets(cbrs
, aContainingBlockWidth
, aContainingBlockHeight
, aPresContext
);
1761 // Initialize offsets to 0
1762 mComputedOffsets
.SizeTo(0, 0, 0, 0);
1765 // Calculate the computed values for min and max properties. Note that
1766 // this MUST come after we've computed our border and padding.
1767 ComputeMinMaxValues(aContainingBlockWidth
, aContainingBlockHeight
, cbrs
);
1769 // Calculate the computed width and height. This varies by frame type
1771 if (NS_CSS_FRAME_TYPE_INTERNAL_TABLE
== mFrameType
) {
1772 // Internal table elements. The rules vary depending on the type.
1773 // Calculate the computed width
1774 PRBool rowOrRowGroup
= PR_FALSE
;
1775 const nsStyleCoord
&width
= mStylePosition
->mWidth
;
1776 nsStyleUnit widthUnit
= width
.GetUnit();
1777 if ((NS_STYLE_DISPLAY_TABLE_ROW
== mStyleDisplay
->mDisplay
) ||
1778 (NS_STYLE_DISPLAY_TABLE_ROW_GROUP
== mStyleDisplay
->mDisplay
)) {
1779 // 'width' property doesn't apply to table rows and row groups
1780 widthUnit
= eStyleUnit_Auto
;
1781 rowOrRowGroup
= PR_TRUE
;
1784 // calc() acts like auto on internal table elements
1785 if (eStyleUnit_Auto
== widthUnit
|| width
.IsCalcUnit()) {
1786 mComputedWidth
= availableWidth
;
1788 if ((mComputedWidth
!= NS_UNCONSTRAINEDSIZE
) && !rowOrRowGroup
){
1789 // Internal table elements don't have margins. Only tables and
1790 // cells have border and padding
1791 mComputedWidth
-= mComputedBorderPadding
.left
+
1792 mComputedBorderPadding
.right
;
1793 if (mComputedWidth
< 0)
1796 NS_ASSERTION(mComputedWidth
>= 0, "Bogus computed width");
1799 NS_ASSERTION(widthUnit
== mStylePosition
->mWidth
.GetUnit(),
1800 "unexpected width unit change");
1801 mComputedWidth
= ComputeWidthValue(aContainingBlockWidth
,
1802 mStylePosition
->mBoxSizing
,
1803 mStylePosition
->mWidth
);
1806 // Calculate the computed height
1807 if ((NS_STYLE_DISPLAY_TABLE_COLUMN
== mStyleDisplay
->mDisplay
) ||
1808 (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
== mStyleDisplay
->mDisplay
)) {
1809 // 'height' property doesn't apply to table columns and column groups
1810 heightUnit
= eStyleUnit_Auto
;
1812 // calc() acts like 'auto' on internal table elements
1813 if (eStyleUnit_Auto
== heightUnit
|| height
.IsCalcUnit()) {
1814 mComputedHeight
= NS_AUTOHEIGHT
;
1816 NS_ASSERTION(heightUnit
== mStylePosition
->mHeight
.GetUnit(),
1817 "unexpected height unit change");
1818 mComputedHeight
= nsLayoutUtils::
1819 ComputeHeightValue(aContainingBlockHeight
, mStylePosition
->mHeight
);
1822 // Doesn't apply to table elements
1823 mComputedMinWidth
= mComputedMinHeight
= 0;
1824 mComputedMaxWidth
= mComputedMaxHeight
= NS_UNCONSTRAINEDSIZE
;
1826 } else if (NS_FRAME_GET_TYPE(mFrameType
) == NS_CSS_FRAME_TYPE_ABSOLUTE
) {
1827 // XXX not sure if this belongs here or somewhere else - cwk
1828 InitAbsoluteConstraints(aPresContext
, cbrs
, aContainingBlockWidth
,
1829 aContainingBlockHeight
);
1832 NS_CSS_FRAME_TYPE_BLOCK
== NS_FRAME_GET_TYPE(mFrameType
);
1833 // make sure legend frames with display:block and width:auto still
1835 PRBool shrinkWrap
= !isBlock
|| frame
->GetType() == nsGkAtoms::legendFrame
;
1837 frame
->ComputeSize(rendContext
,
1838 nsSize(aContainingBlockWidth
,
1839 aContainingBlockHeight
),
1841 nsSize(mComputedMargin
.LeftRight(),
1842 mComputedMargin
.TopBottom()),
1843 nsSize(mComputedBorderPadding
.LeftRight() -
1844 mComputedPadding
.LeftRight(),
1845 mComputedBorderPadding
.TopBottom() -
1846 mComputedPadding
.TopBottom()),
1847 nsSize(mComputedPadding
.LeftRight(),
1848 mComputedPadding
.TopBottom()),
1851 mComputedWidth
= size
.width
;
1852 mComputedHeight
= size
.height
;
1853 NS_ASSERTION(mComputedWidth
>= 0, "Bogus width");
1854 NS_ASSERTION(mComputedHeight
== NS_UNCONSTRAINEDSIZE
||
1855 mComputedHeight
>= 0, "Bogus height");
1857 if (isBlock
&& !IsSideCaption(frame
, mStyleDisplay
))
1858 CalculateBlockSideMargins(availableWidth
, mComputedWidth
);
1861 // Check for blinking text and permission to display it
1862 mFlags
.mBlinks
= (parentReflowState
&& parentReflowState
->mFlags
.mBlinks
);
1863 if (!mFlags
.mBlinks
&& BlinkIsAllowed()) {
1864 const nsStyleTextReset
* st
= frame
->GetStyleTextReset();
1866 ((st
->mTextDecoration
& NS_STYLE_TEXT_DECORATION_BLINK
) != 0);
1871 UpdateProp(FrameProperties
& aProps
,
1872 const FramePropertyDescriptor
* aProperty
,
1874 nsMargin
& aNewValue
)
1877 nsMargin
* propValue
= static_cast<nsMargin
*>(aProps
.Get(aProperty
));
1879 *propValue
= aNewValue
;
1881 aProps
.Set(aProperty
, new nsMargin(aNewValue
));
1884 aProps
.Delete(aProperty
);
1889 nsCSSOffsetState::InitOffsets(nscoord aContainingBlockWidth
,
1890 const nsMargin
*aBorder
,
1891 const nsMargin
*aPadding
)
1893 DISPLAY_INIT_OFFSETS(frame
, this, aContainingBlockWidth
, aBorder
, aPadding
);
1895 // Since we are in reflow, we don't need to store these properties anymore
1896 // unless they are dependent on width, in which case we store the new value.
1897 nsPresContext
*presContext
= frame
->PresContext();
1898 FrameProperties
props(presContext
->PropertyTable(), frame
);
1899 props
.Delete(nsIFrame::UsedBorderProperty());
1901 // Compute margins from the specified margin style information. These
1902 // become the default computed values, and may be adjusted below
1903 // XXX fix to provide 0,0 for the top&bottom margins for
1904 // inline-non-replaced elements
1905 PRBool needMarginProp
= ComputeMargin(aContainingBlockWidth
);
1906 // XXX We need to include 'auto' horizontal margins in this too!
1907 // ... but if we did that, we'd need to fix nsFrame::GetUsedMargin
1908 // to use it even when the margins are all zero (since sometimes
1909 // they get treated as auto)
1910 ::UpdateProp(props
, nsIFrame::UsedMarginProperty(), needMarginProp
,
1914 const nsStyleDisplay
*disp
= frame
->GetStyleDisplay();
1915 PRBool isThemed
= frame
->IsThemed(disp
);
1916 PRBool needPaddingProp
;
1919 presContext
->GetTheme()->GetWidgetPadding(presContext
->DeviceContext(),
1920 frame
, disp
->mAppearance
,
1922 mComputedPadding
.top
= presContext
->DevPixelsToAppUnits(widget
.top
);
1923 mComputedPadding
.right
= presContext
->DevPixelsToAppUnits(widget
.right
);
1924 mComputedPadding
.bottom
= presContext
->DevPixelsToAppUnits(widget
.bottom
);
1925 mComputedPadding
.left
= presContext
->DevPixelsToAppUnits(widget
.left
);
1926 needPaddingProp
= PR_FALSE
;
1928 else if (aPadding
) { // padding is an input arg
1929 mComputedPadding
= *aPadding
;
1930 needPaddingProp
= frame
->GetStylePadding()->IsWidthDependent();
1933 needPaddingProp
= ComputePadding(aContainingBlockWidth
);
1938 presContext
->GetTheme()->GetWidgetBorder(presContext
->DeviceContext(),
1939 frame
, disp
->mAppearance
,
1941 mComputedBorderPadding
.top
=
1942 presContext
->DevPixelsToAppUnits(widget
.top
);
1943 mComputedBorderPadding
.right
=
1944 presContext
->DevPixelsToAppUnits(widget
.right
);
1945 mComputedBorderPadding
.bottom
=
1946 presContext
->DevPixelsToAppUnits(widget
.bottom
);
1947 mComputedBorderPadding
.left
=
1948 presContext
->DevPixelsToAppUnits(widget
.left
);
1950 else if (aBorder
) { // border is an input arg
1951 mComputedBorderPadding
= *aBorder
;
1954 mComputedBorderPadding
= frame
->GetStyleBorder()->GetActualBorder();
1956 mComputedBorderPadding
+= mComputedPadding
;
1958 nsIAtom
* frameType
= frame
->GetType();
1959 if (frameType
== nsGkAtoms::tableFrame
) {
1960 nsTableFrame
*tableFrame
= static_cast<nsTableFrame
*>(frame
);
1962 if (tableFrame
->IsBorderCollapse()) {
1963 // border-collapsed tables don't use any of their padding, and
1964 // only part of their border. We need to do this here before we
1965 // try to do anything like handling 'auto' widths,
1966 // '-moz-box-sizing', or 'auto' margins.
1967 mComputedPadding
.SizeTo(0,0,0,0);
1968 mComputedBorderPadding
= tableFrame
->GetIncludedOuterBCBorder();
1970 } else if (frameType
== nsGkAtoms::scrollbarFrame
) {
1971 // scrollbars may have had their width or height smashed to zero
1972 // by the associated scrollframe, in which case we must not report
1973 // any padding or border.
1974 nsSize
size(frame
->GetSize());
1975 if (size
.width
== 0 || size
.height
== 0) {
1976 mComputedPadding
.SizeTo(0,0,0,0);
1977 mComputedBorderPadding
.SizeTo(0,0,0,0);
1980 ::UpdateProp(props
, nsIFrame::UsedPaddingProperty(), needPaddingProp
,
1984 // This code enforces section 10.3.3 of the CSS2 spec for this formula:
1986 // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' +
1987 // 'padding-right' + 'border-right-width' + 'margin-right'
1988 // = width of containing block
1990 // Note: the width unit is not auto when this is called
1992 nsHTMLReflowState::CalculateBlockSideMargins(nscoord aAvailWidth
,
1993 nscoord aComputedWidth
)
1995 NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE
!= aComputedWidth
&&
1996 NS_UNCONSTRAINEDSIZE
!= aAvailWidth
,
1997 "have unconstrained width; this should only result from "
1998 "very large sizes, not attempts at intrinsic width "
2001 nscoord sum
= mComputedMargin
.left
+ mComputedBorderPadding
.left
+
2002 aComputedWidth
+ mComputedBorderPadding
.right
+ mComputedMargin
.right
;
2003 if (sum
== aAvailWidth
)
2004 // The sum is already correct
2007 // Determine the left and right margin values. The width value
2008 // remains constant while we do this.
2010 // Calculate how much space is available for margins
2011 nscoord availMarginSpace
= aAvailWidth
- sum
;
2013 // If the available margin space is negative, then don't follow the
2014 // usual overconstraint rules.
2015 if (availMarginSpace
< 0) {
2016 if (mCBReflowState
&&
2017 mCBReflowState
->mStyleVisibility
->mDirection
== NS_STYLE_DIRECTION_RTL
) {
2018 mComputedMargin
.left
+= availMarginSpace
;
2020 mComputedMargin
.right
+= availMarginSpace
;
2025 // The css2 spec clearly defines how block elements should behave
2026 // in section 10.3.3.
2027 PRBool isAutoLeftMargin
=
2028 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetLeftUnit();
2029 PRBool isAutoRightMargin
=
2030 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetRightUnit();
2031 if (!isAutoLeftMargin
&& !isAutoRightMargin
) {
2032 // Neither margin is 'auto' so we're over constrained. Use the
2033 // 'direction' property of the parent to tell which margin to
2035 // First check if there is an HTML alignment that we should honor
2036 const nsHTMLReflowState
* prs
= parentReflowState
;
2037 if (frame
->GetType() == nsGkAtoms::tableFrame
) {
2038 NS_ASSERTION(prs
->frame
->GetType() == nsGkAtoms::tableOuterFrame
,
2039 "table not inside outer table");
2040 // Center the table within the outer table based on the alignment
2041 // of the outer table's parent.
2042 prs
= prs
->parentReflowState
;
2045 (prs
->mStyleText
->mTextAlign
== NS_STYLE_TEXT_ALIGN_MOZ_LEFT
||
2046 prs
->mStyleText
->mTextAlign
== NS_STYLE_TEXT_ALIGN_MOZ_CENTER
||
2047 prs
->mStyleText
->mTextAlign
== NS_STYLE_TEXT_ALIGN_MOZ_RIGHT
)) {
2049 prs
->mStyleText
->mTextAlign
!= NS_STYLE_TEXT_ALIGN_MOZ_LEFT
;
2051 prs
->mStyleText
->mTextAlign
!= NS_STYLE_TEXT_ALIGN_MOZ_RIGHT
;
2053 // Otherwise apply the CSS rules, and ignore one margin by forcing
2054 // it to 'auto', depending on 'direction'.
2055 else if (mCBReflowState
&&
2056 NS_STYLE_DIRECTION_RTL
== mCBReflowState
->mStyleVisibility
->mDirection
) {
2057 isAutoLeftMargin
= PR_TRUE
;
2060 isAutoRightMargin
= PR_TRUE
;
2064 // Logic which is common to blocks and tables
2065 // The computed margins need not be zero because the 'auto' could come from
2066 // overconstraint or from HTML alignment so values need to be accumulated
2068 if (isAutoLeftMargin
) {
2069 if (isAutoRightMargin
) {
2070 // Both margins are 'auto' so the computed addition should be equal
2071 nscoord forLeft
= availMarginSpace
/ 2;
2072 mComputedMargin
.left
+= forLeft
;
2073 mComputedMargin
.right
+= availMarginSpace
- forLeft
;
2075 mComputedMargin
.left
+= availMarginSpace
;
2077 } else if (isAutoRightMargin
) {
2078 mComputedMargin
.right
+= availMarginSpace
;
2082 #define NORMAL_LINE_HEIGHT_FACTOR 1.2f // in term of emHeight
2083 // For "normal" we use the font's normal line height (em height + leading).
2084 // If both internal leading and external leading specified by font itself
2085 // are zeros, we should compensate this by creating extra (external) leading
2086 // in eCompensateLeading mode. This is necessary because without this
2087 // compensation, normal line height might looks too tight.
2089 // For risk management, we use preference to control the behavior, and
2090 // eNoExternalLeading is the old behavior.
2092 GetNormalLineHeight(nsIFontMetrics
* aFontMetrics
)
2094 NS_PRECONDITION(nsnull
!= aFontMetrics
, "no font metrics");
2096 nscoord normalLineHeight
;
2098 nscoord externalLeading
, internalLeading
, emHeight
;
2099 aFontMetrics
->GetExternalLeading(externalLeading
);
2100 aFontMetrics
->GetInternalLeading(internalLeading
);
2101 aFontMetrics
->GetEmHeight(emHeight
);
2102 switch (GetNormalLineHeightCalcControl()) {
2103 case eIncludeExternalLeading
:
2104 normalLineHeight
= emHeight
+ internalLeading
+ externalLeading
;
2106 case eCompensateLeading
:
2107 if (!internalLeading
&& !externalLeading
)
2108 normalLineHeight
= NSToCoordRound(emHeight
* NORMAL_LINE_HEIGHT_FACTOR
);
2110 normalLineHeight
= emHeight
+ internalLeading
+ externalLeading
;
2113 //case eNoExternalLeading:
2114 normalLineHeight
= emHeight
+ internalLeading
;
2116 return normalLineHeight
;
2120 ComputeLineHeight(nsStyleContext
* aStyleContext
,
2121 nscoord aBlockHeight
)
2123 const nsStyleCoord
& lhCoord
= aStyleContext
->GetStyleText()->mLineHeight
;
2125 if (lhCoord
.GetUnit() == eStyleUnit_Coord
)
2126 return lhCoord
.GetCoordValue();
2128 if (lhCoord
.GetUnit() == eStyleUnit_Factor
)
2129 // For factor units the computed value of the line-height property
2130 // is found by multiplying the factor by the font's computed size
2131 // (adjusted for min-size prefs and text zoom).
2132 return NSToCoordRound(lhCoord
.GetFactorValue() *
2133 aStyleContext
->GetStyleFont()->mFont
.size
);
2135 NS_ASSERTION(lhCoord
.GetUnit() == eStyleUnit_Normal
||
2136 lhCoord
.GetUnit() == eStyleUnit_Enumerated
,
2137 "bad line-height unit");
2139 if (lhCoord
.GetUnit() == eStyleUnit_Enumerated
) {
2140 NS_ASSERTION(lhCoord
.GetIntValue() == NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT
,
2141 "bad line-height value");
2142 if (aBlockHeight
!= NS_AUTOHEIGHT
)
2143 return aBlockHeight
;
2146 nsCOMPtr
<nsIFontMetrics
> fm
;
2147 nsLayoutUtils::GetFontMetricsForStyleContext(aStyleContext
,
2148 getter_AddRefs(fm
));
2149 return GetNormalLineHeight(fm
);
2153 nsHTMLReflowState::CalcLineHeight() const
2155 nscoord blockHeight
=
2156 frame
->IsContainingBlock() ? mComputedHeight
:
2157 (mCBReflowState
? mCBReflowState
->mComputedHeight
: NS_AUTOHEIGHT
);
2159 return CalcLineHeight(frame
->GetStyleContext(), blockHeight
);
2162 /* static */ nscoord
2163 nsHTMLReflowState::CalcLineHeight(nsStyleContext
* aStyleContext
,
2164 nscoord aBlockHeight
)
2166 NS_PRECONDITION(aStyleContext
, "Must have a style context");
2168 nscoord lineHeight
= ComputeLineHeight(aStyleContext
, aBlockHeight
);
2170 NS_ASSERTION(lineHeight
>= 0, "ComputeLineHeight screwed up");
2176 nsCSSOffsetState::ComputeMargin(nscoord aContainingBlockWidth
)
2178 // If style style can provide us the margin directly, then use it.
2179 const nsStyleMargin
*styleMargin
= frame
->GetStyleMargin();
2180 PRBool isWidthDependent
= !styleMargin
->GetMargin(mComputedMargin
);
2181 if (isWidthDependent
) {
2182 // We have to compute the value
2183 mComputedMargin
.left
= nsLayoutUtils::
2184 ComputeWidthDependentValue(aContainingBlockWidth
,
2185 styleMargin
->mMargin
.GetLeft());
2186 mComputedMargin
.right
= nsLayoutUtils::
2187 ComputeWidthDependentValue(aContainingBlockWidth
,
2188 styleMargin
->mMargin
.GetRight());
2190 // According to the CSS2 spec, margin percentages are
2191 // calculated with respect to the *width* of the containing
2192 // block, even for margin-top and margin-bottom.
2193 // XXX This isn't true for page boxes, if we implement them.
2194 mComputedMargin
.top
= nsLayoutUtils::
2195 ComputeWidthDependentValue(aContainingBlockWidth
,
2196 styleMargin
->mMargin
.GetTop());
2197 mComputedMargin
.bottom
= nsLayoutUtils::
2198 ComputeWidthDependentValue(aContainingBlockWidth
,
2199 styleMargin
->mMargin
.GetBottom());
2201 return isWidthDependent
;
2205 nsCSSOffsetState::ComputePadding(nscoord aContainingBlockWidth
)
2207 // If style can provide us the padding directly, then use it.
2208 const nsStylePadding
*stylePadding
= frame
->GetStylePadding();
2209 PRBool isWidthDependent
= !stylePadding
->GetPadding(mComputedPadding
);
2210 // a table row/col group, row/col doesn't have padding
2211 // XXXldb Neither do border-collapse tables.
2212 nsIAtom
* frameType
= frame
->GetType();
2213 if (nsGkAtoms::tableRowGroupFrame
== frameType
||
2214 nsGkAtoms::tableColGroupFrame
== frameType
||
2215 nsGkAtoms::tableRowFrame
== frameType
||
2216 nsGkAtoms::tableColFrame
== frameType
) {
2217 mComputedPadding
.SizeTo(0,0,0,0);
2219 else if (isWidthDependent
) {
2220 // We have to compute the value
2221 // clamp negative calc() results to 0
2222 mComputedPadding
.left
= NS_MAX(0, nsLayoutUtils::
2223 ComputeWidthDependentValue(aContainingBlockWidth
,
2224 stylePadding
->mPadding
.GetLeft()));
2225 mComputedPadding
.right
= NS_MAX(0, nsLayoutUtils::
2226 ComputeWidthDependentValue(aContainingBlockWidth
,
2227 stylePadding
->mPadding
.GetRight()));
2229 // According to the CSS2 spec, percentages are calculated with respect to
2230 // containing block width for padding-top and padding-bottom
2231 mComputedPadding
.top
= NS_MAX(0, nsLayoutUtils::
2232 ComputeWidthDependentValue(aContainingBlockWidth
,
2233 stylePadding
->mPadding
.GetTop()));
2234 mComputedPadding
.bottom
= NS_MAX(0, nsLayoutUtils::
2235 ComputeWidthDependentValue(aContainingBlockWidth
,
2236 stylePadding
->mPadding
.GetBottom()));
2238 return isWidthDependent
;
2242 nsHTMLReflowState::ApplyMinMaxConstraints(nscoord
* aFrameWidth
,
2243 nscoord
* aFrameHeight
) const
2246 if (NS_UNCONSTRAINEDSIZE
!= mComputedMaxWidth
) {
2247 *aFrameWidth
= NS_MIN(*aFrameWidth
, mComputedMaxWidth
);
2249 *aFrameWidth
= NS_MAX(*aFrameWidth
, mComputedMinWidth
);
2253 if (NS_UNCONSTRAINEDSIZE
!= mComputedMaxHeight
) {
2254 *aFrameHeight
= NS_MIN(*aFrameHeight
, mComputedMaxHeight
);
2256 *aFrameHeight
= NS_MAX(*aFrameHeight
, mComputedMinHeight
);
2261 nsHTMLReflowState::ComputeMinMaxValues(nscoord aContainingBlockWidth
,
2262 nscoord aContainingBlockHeight
,
2263 const nsHTMLReflowState
* aContainingBlockRS
)
2265 mComputedMinWidth
= ComputeWidthValue(aContainingBlockWidth
,
2266 mStylePosition
->mBoxSizing
,
2267 mStylePosition
->mMinWidth
);
2269 if (eStyleUnit_None
== mStylePosition
->mMaxWidth
.GetUnit()) {
2270 // Specified value of 'none'
2271 mComputedMaxWidth
= NS_UNCONSTRAINEDSIZE
; // no limit
2273 mComputedMaxWidth
= ComputeWidthValue(aContainingBlockWidth
,
2274 mStylePosition
->mBoxSizing
,
2275 mStylePosition
->mMaxWidth
);
2278 // If the computed value of 'min-width' is greater than the value of
2279 // 'max-width', 'max-width' is set to the value of 'min-width'
2280 if (mComputedMinWidth
> mComputedMaxWidth
) {
2281 mComputedMaxWidth
= mComputedMinWidth
;
2284 // Check for percentage based values and a containing block height that
2285 // depends on the content height. Treat them like 'auto'
2286 // Likewise, check for calc() on internal table elements; calc() on
2287 // such elements is unsupported.
2288 const nsStyleCoord
&minHeight
= mStylePosition
->mMinHeight
;
2289 if ((NS_AUTOHEIGHT
== aContainingBlockHeight
&&
2290 minHeight
.HasPercent()) ||
2291 (mFrameType
== NS_CSS_FRAME_TYPE_INTERNAL_TABLE
&&
2292 minHeight
.IsCalcUnit())) {
2293 mComputedMinHeight
= 0;
2295 mComputedMinHeight
= nsLayoutUtils::
2296 ComputeHeightValue(aContainingBlockHeight
, minHeight
);
2298 const nsStyleCoord
&maxHeight
= mStylePosition
->mMaxHeight
;
2299 nsStyleUnit maxHeightUnit
= maxHeight
.GetUnit();
2300 if (eStyleUnit_None
== maxHeightUnit
) {
2301 // Specified value of 'none'
2302 mComputedMaxHeight
= NS_UNCONSTRAINEDSIZE
; // no limit
2304 // Check for percentage based values and a containing block height that
2305 // depends on the content height. Treat them like 'auto'
2306 // Likewise, check for calc() on internal table elements; calc() on
2307 // such elements is unsupported.
2308 if ((NS_AUTOHEIGHT
== aContainingBlockHeight
&&
2309 maxHeight
.HasPercent()) ||
2310 (mFrameType
== NS_CSS_FRAME_TYPE_INTERNAL_TABLE
&&
2311 maxHeight
.IsCalcUnit())) {
2312 mComputedMaxHeight
= NS_UNCONSTRAINEDSIZE
;
2314 mComputedMaxHeight
= nsLayoutUtils::
2315 ComputeHeightValue(aContainingBlockHeight
, maxHeight
);
2319 // If the computed value of 'min-height' is greater than the value of
2320 // 'max-height', 'max-height' is set to the value of 'min-height'
2321 if (mComputedMinHeight
> mComputedMaxHeight
) {
2322 mComputedMaxHeight
= mComputedMinHeight
;
2327 nsHTMLReflowState::SetTruncated(const nsHTMLReflowMetrics
& aMetrics
,
2328 nsReflowStatus
* aStatus
) const
2330 if (availableHeight
!= NS_UNCONSTRAINEDSIZE
&&
2331 availableHeight
< aMetrics
.height
&&
2332 !mFlags
.mIsTopOfPage
) {
2333 *aStatus
|= NS_FRAME_TRUNCATED
;
2335 *aStatus
&= ~NS_FRAME_TRUNCATED
;