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.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 /* struct containing the input to nsIFrame::Reflow */
41 #include "nsStyleConsts.h"
42 #include "nsCSSAnonBoxes.h"
44 #include "nsIContent.h"
45 #include "nsGkAtoms.h"
46 #include "nsPresContext.h"
47 #include "nsIPresShell.h"
48 #include "nsIDeviceContext.h"
49 #include "nsIRenderingContext.h"
50 #include "nsIFontMetrics.h"
51 #include "nsBlockFrame.h"
52 #include "nsLineBox.h"
53 #include "nsImageFrame.h"
54 #include "nsTableFrame.h"
55 #include "nsTableCellFrame.h"
56 #include "nsIServiceManager.h"
57 #include "nsIPercentHeightObserver.h"
58 #include "nsContentUtils.h"
59 #include "nsLayoutUtils.h"
61 #include "nsBidiUtils.h"
65 #undef NOISY_VERTICAL_ALIGN
67 #undef NOISY_VERTICAL_ALIGN
70 using namespace mozilla
;
72 // Prefs-driven control for |text-decoration: blink|
73 static PRPackedBool sPrefIsLoaded
= PR_FALSE
;
74 static PRPackedBool sBlinkIsAllowed
= PR_TRUE
;
76 enum eNormalLineHeightControl
{
78 eNoExternalLeading
= 0, // does not include external leading
79 eIncludeExternalLeading
, // use whatever value font vendor provides
80 eCompensateLeading
// compensate leading if leading provided by font vendor is not enough
83 static eNormalLineHeightControl sNormalLineHeightControl
= eUninitialized
;
85 // Initialize a <b>root</b> reflow state with a rendering context to
86 // use for measuring things.
87 nsHTMLReflowState::nsHTMLReflowState(nsPresContext
* aPresContext
,
89 nsIRenderingContext
* aRenderingContext
,
90 const nsSize
& aAvailableSpace
)
91 : nsCSSOffsetState(aFrame
, aRenderingContext
)
95 NS_PRECONDITION(aPresContext
, "no pres context");
96 NS_PRECONDITION(aRenderingContext
, "no rendering context");
97 NS_PRECONDITION(aFrame
, "no frame");
98 parentReflowState
= nsnull
;
99 availableWidth
= aAvailableSpace
.width
;
100 availableHeight
= aAvailableSpace
.height
;
101 mFloatManager
= nsnull
;
102 mLineLayout
= nsnull
;
103 mFlags
.mSpecialHeightReflow
= PR_FALSE
;
104 mFlags
.mIsTopOfPage
= PR_FALSE
;
105 mFlags
.mTableIsSplittable
= PR_FALSE
;
106 mFlags
.mNextInFlowUntouched
= PR_FALSE
;
107 mFlags
.mAssumingHScrollbar
= mFlags
.mAssumingVScrollbar
= PR_FALSE
;
108 mFlags
.mHasClearance
= PR_FALSE
;
109 mFlags
.mHeightDependsOnAncestorCell
= PR_FALSE
;
110 mDiscoveredClearance
= nsnull
;
111 mPercentHeightObserver
= nsnull
;
115 static PRBool
CheckNextInFlowParenthood(nsIFrame
* aFrame
, nsIFrame
* aParent
)
117 nsIFrame
* frameNext
= aFrame
->GetNextInFlow();
118 nsIFrame
* parentNext
= aParent
->GetNextInFlow();
119 return frameNext
&& parentNext
&& frameNext
->GetParent() == parentNext
;
122 // Initialize a reflow state for a child frames reflow. Some state
123 // is copied from the parent reflow state; the remaining state is
125 nsHTMLReflowState::nsHTMLReflowState(nsPresContext
* aPresContext
,
126 const nsHTMLReflowState
& aParentReflowState
,
128 const nsSize
& aAvailableSpace
,
129 nscoord aContainingBlockWidth
,
130 nscoord aContainingBlockHeight
,
132 : nsCSSOffsetState(aFrame
, aParentReflowState
.rendContext
)
134 , mReflowDepth(aParentReflowState
.mReflowDepth
+ 1)
135 , mFlags(aParentReflowState
.mFlags
)
137 NS_PRECONDITION(aPresContext
, "no pres context");
138 NS_PRECONDITION(aFrame
, "no frame");
139 NS_PRECONDITION((aContainingBlockWidth
== -1) ==
140 (aContainingBlockHeight
== -1),
141 "cb width and height should only be non-default together");
142 NS_PRECONDITION(aInit
== PR_TRUE
|| aInit
== PR_FALSE
,
143 "aInit out of range for PRBool");
144 NS_PRECONDITION(!mFlags
.mSpecialHeightReflow
||
145 !NS_SUBTREE_DIRTY(aFrame
),
146 "frame should be clean when getting special height reflow");
148 parentReflowState
= &aParentReflowState
;
150 // If the parent is dirty, then the child is as well.
151 // XXX Are the other cases where the parent reflows a child a second
152 // time, as a resize?
153 if (!mFlags
.mSpecialHeightReflow
)
154 frame
->AddStateBits(parentReflowState
->frame
->GetStateBits() &
157 availableWidth
= aAvailableSpace
.width
;
158 availableHeight
= aAvailableSpace
.height
;
160 mFloatManager
= aParentReflowState
.mFloatManager
;
161 if (frame
->IsFrameOfType(nsIFrame::eLineParticipant
))
162 mLineLayout
= aParentReflowState
.mLineLayout
;
164 mLineLayout
= nsnull
;
165 mFlags
.mIsTopOfPage
= aParentReflowState
.mFlags
.mIsTopOfPage
;
166 mFlags
.mNextInFlowUntouched
= aParentReflowState
.mFlags
.mNextInFlowUntouched
&&
167 CheckNextInFlowParenthood(aFrame
, aParentReflowState
.frame
);
168 mFlags
.mAssumingHScrollbar
= mFlags
.mAssumingVScrollbar
= PR_FALSE
;
169 mFlags
.mHasClearance
= PR_FALSE
;
170 mDiscoveredClearance
= nsnull
;
171 mPercentHeightObserver
= (aParentReflowState
.mPercentHeightObserver
&&
172 aParentReflowState
.mPercentHeightObserver
->NeedsToObserve(*this))
173 ? aParentReflowState
.mPercentHeightObserver
: nsnull
;
176 Init(aPresContext
, aContainingBlockWidth
, aContainingBlockHeight
);
181 nsCSSOffsetState::ComputeWidthValue(nscoord aContainingBlockWidth
,
182 nscoord aContentEdgeToBoxSizing
,
183 nscoord aBoxSizingToMarginEdge
,
184 const nsStyleCoord
& aCoord
)
186 return nsLayoutUtils::ComputeWidthValue(rendContext
, frame
,
187 aContainingBlockWidth
,
188 aContentEdgeToBoxSizing
,
189 aBoxSizingToMarginEdge
,
194 nsCSSOffsetState::ComputeWidthValue(nscoord aContainingBlockWidth
,
196 const nsStyleCoord
& aCoord
)
198 nscoord inside
= 0, outside
= mComputedBorderPadding
.LeftRight() +
199 mComputedMargin
.LeftRight();
200 switch (aBoxSizing
) {
201 case NS_STYLE_BOX_SIZING_BORDER
:
202 inside
= mComputedBorderPadding
.LeftRight();
204 case NS_STYLE_BOX_SIZING_PADDING
:
205 inside
= mComputedPadding
.LeftRight();
210 return ComputeWidthValue(aContainingBlockWidth
, inside
,
215 nsHTMLReflowState::SetComputedWidth(nscoord aComputedWidth
)
217 NS_ASSERTION(frame
, "Must have a frame!");
218 // It'd be nice to assert that |frame| is not in reflow, but this fails for
221 // 1) Viewport frames reset the computed width on a copy of their reflow
222 // state when reflowing fixed-pos kids. In that case we actually don't
223 // want to mess with the resize flags, because comparing the frame's rect
224 // to the munged computed width is pointless.
225 // 2) nsFrame::BoxReflow creates a reflow state for its parent. This reflow
226 // state is not used to reflow the parent, but just as a parent for the
227 // frame's own reflow state. So given a nsBoxFrame inside some non-XUL
228 // (like a text control, for example), we'll end up creating a reflow
229 // state for the parent while the parent is reflowing.
231 NS_PRECONDITION(aComputedWidth
>= 0, "Invalid computed width");
232 if (mComputedWidth
!= aComputedWidth
) {
233 mComputedWidth
= aComputedWidth
;
234 if (frame
->GetType() != nsGkAtoms::viewportFrame
) { // Or check GetParent()?
235 InitResizeFlags(frame
->PresContext());
241 nsHTMLReflowState::SetComputedHeight(nscoord aComputedHeight
)
243 NS_ASSERTION(frame
, "Must have a frame!");
244 // It'd be nice to assert that |frame| is not in reflow, but this fails
247 // nsFrame::BoxReflow creates a reflow state for its parent. This reflow
248 // state is not used to reflow the parent, but just as a parent for the
249 // frame's own reflow state. So given a nsBoxFrame inside some non-XUL
250 // (like a text control, for example), we'll end up creating a reflow
251 // state for the parent while the parent is reflowing.
253 NS_PRECONDITION(aComputedHeight
>= 0, "Invalid computed height");
254 if (mComputedHeight
!= aComputedHeight
) {
255 mComputedHeight
= aComputedHeight
;
256 InitResizeFlags(frame
->PresContext());
261 nsHTMLReflowState::Init(nsPresContext
* aPresContext
,
262 nscoord aContainingBlockWidth
,
263 nscoord aContainingBlockHeight
,
264 const nsMargin
* aBorder
,
265 const nsMargin
* aPadding
)
267 NS_WARN_IF_FALSE(availableWidth
!= NS_UNCONSTRAINEDSIZE
,
268 "have unconstrained width; this should only result from "
269 "very large sizes, not attempts at intrinsic width "
272 mStylePosition
= frame
->GetStylePosition();
273 mStyleDisplay
= frame
->GetStyleDisplay();
274 mStyleVisibility
= frame
->GetStyleVisibility();
275 mStyleBorder
= frame
->GetStyleBorder();
276 mStyleMargin
= frame
->GetStyleMargin();
277 mStylePadding
= frame
->GetStylePadding();
278 mStyleText
= frame
->GetStyleText();
283 InitConstraints(aPresContext
, aContainingBlockWidth
, aContainingBlockHeight
, aBorder
, aPadding
);
285 InitResizeFlags(aPresContext
);
287 NS_WARN_IF_FALSE((mFrameType
== NS_CSS_FRAME_TYPE_INLINE
&&
288 !frame
->IsFrameOfType(nsIFrame::eReplaced
)) ||
289 frame
->GetType() == nsGkAtoms::textFrame
||
290 mComputedWidth
!= NS_UNCONSTRAINEDSIZE
,
291 "have unconstrained width; this should only result from "
292 "very large sizes, not attempts at intrinsic width "
296 void nsHTMLReflowState::InitCBReflowState()
298 if (!parentReflowState
) {
299 mCBReflowState
= nsnull
;
303 // If outer tables ever become containing blocks, we need to make sure to use
304 // their mCBReflowState in the non-absolutely-positioned case for inner
306 NS_ASSERTION(frame
->GetType() != nsGkAtoms::tableFrame
||
307 !frame
->GetParent()->IsContainingBlock(),
308 "Outer table should not be containing block");
310 if (parentReflowState
->frame
->IsContainingBlock() ||
311 // Absolutely positioned frames should always be kids of the frames that
312 // determine their containing block....
313 (NS_FRAME_GET_TYPE(mFrameType
) == NS_CSS_FRAME_TYPE_ABSOLUTE
)) {
314 // an absolutely positioned inner table needs to use the parent of
315 // the outer table. So the above comment about absolutely
316 // positioned frames is sort of a lie.
317 if (parentReflowState
->parentReflowState
&&
318 frame
->GetType() == nsGkAtoms::tableFrame
) {
319 mCBReflowState
= parentReflowState
->parentReflowState
;
321 mCBReflowState
= parentReflowState
;
327 mCBReflowState
= parentReflowState
->mCBReflowState
;
330 /* Check whether CalcQuirkContainingBlockHeight would stop on the
331 * given reflow state, using its block as a height. (essentially
332 * returns false for any case in which CalcQuirkContainingBlockHeight
333 * has a "continue" in its main loop.)
335 * XXX Maybe refactor CalcQuirkContainingBlockHeight so it uses
336 * this function as well
339 IsQuirkContainingBlockHeight(const nsHTMLReflowState
* rs
)
341 nsIAtom
* frameType
= rs
->frame
->GetType();
342 if (nsGkAtoms::blockFrame
== frameType
||
344 nsGkAtoms::XULLabelFrame
== frameType
||
346 nsGkAtoms::scrollFrame
== frameType
) {
347 // Note: This next condition could change due to a style change,
348 // but that would cause a style reflow anyway, which means we're ok.
349 if (NS_AUTOHEIGHT
== rs
->ComputedHeight()) {
350 if (!rs
->frame
->GetStyleDisplay()->IsAbsolutelyPositioned()) {
360 nsHTMLReflowState::InitResizeFlags(nsPresContext
* aPresContext
)
362 mFlags
.mHResize
= !(frame
->GetStateBits() & NS_FRAME_IS_DIRTY
) &&
363 frame
->GetSize().width
!=
364 mComputedWidth
+ mComputedBorderPadding
.LeftRight();
366 // XXX Should we really need to null check mCBReflowState? (We do for
367 // at least nsBoxFrame).
368 if (IS_TABLE_CELL(frame
->GetType()) &&
369 (mFlags
.mSpecialHeightReflow
||
370 (frame
->GetFirstInFlow()->GetStateBits() &
371 NS_TABLE_CELL_HAD_SPECIAL_REFLOW
)) &&
372 (frame
->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT
)) {
373 // Need to set the bit on the cell so that
374 // mCBReflowState->mFlags.mVResize is set correctly below when
375 // reflowing descendant.
376 mFlags
.mVResize
= PR_TRUE
;
377 } else if (mCBReflowState
&& !frame
->IsContainingBlock()) {
378 // XXX Is this problematic for relatively positioned inlines acting
379 // as containing block for absolutely positioned elements?
380 // Possibly; in that case we should at least be checking
381 // NS_SUBTREE_DIRTY, I'd think.
382 mFlags
.mVResize
= mCBReflowState
->mFlags
.mVResize
;
383 } else if (mComputedHeight
== NS_AUTOHEIGHT
) {
384 if (eCompatibility_NavQuirks
== aPresContext
->CompatibilityMode() &&
386 mFlags
.mVResize
= mCBReflowState
->mFlags
.mVResize
;
388 mFlags
.mVResize
= mFlags
.mHResize
;
390 mFlags
.mVResize
= mFlags
.mVResize
|| NS_SUBTREE_DIRTY(frame
);
393 mFlags
.mVResize
= frame
->GetSize().height
!=
394 mComputedHeight
+ mComputedBorderPadding
.TopBottom();
397 PRBool dependsOnCBHeight
=
398 mStylePosition
->mHeight
.GetUnit() == eStyleUnit_Percent
||
399 mStylePosition
->mMinHeight
.GetUnit() == eStyleUnit_Percent
||
400 mStylePosition
->mMaxHeight
.GetUnit() == eStyleUnit_Percent
||
401 mStylePosition
->mOffset
.GetTopUnit() == eStyleUnit_Percent
||
402 mStylePosition
->mOffset
.GetBottomUnit() != eStyleUnit_Auto
||
403 frame
->IsBoxFrame() ||
404 (mStylePosition
->mHeight
.GetUnit() == eStyleUnit_Auto
&&
405 frame
->GetIntrinsicSize().height
.GetUnit() == eStyleUnit_Percent
);
407 if (mStyleText
->mLineHeight
.GetUnit() == eStyleUnit_Enumerated
) {
408 NS_ASSERTION(mStyleText
->mLineHeight
.GetIntValue() ==
409 NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT
,
410 "bad line-height value");
412 // line-height depends on block height
413 frame
->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT
);
414 // but only on containing blocks if this frame is not a suitable block
415 dependsOnCBHeight
|= !frame
->IsContainingBlock();
418 // If we're the descendant of a table cell that performs special height
419 // reflows and we could be the child that requires them, always set
420 // the vertical resize in case this is the first pass before the
421 // special height reflow. However, don't do this if it actually is
422 // the special height reflow, since in that case it will already be
423 // set correctly above if we need it set.
424 if (!mFlags
.mVResize
&& mCBReflowState
&&
425 (IS_TABLE_CELL(mCBReflowState
->frame
->GetType()) ||
426 mCBReflowState
->mFlags
.mHeightDependsOnAncestorCell
) &&
427 !mCBReflowState
->mFlags
.mSpecialHeightReflow
&&
429 mFlags
.mVResize
= PR_TRUE
;
430 mFlags
.mHeightDependsOnAncestorCell
= PR_TRUE
;
433 // Set NS_FRAME_CONTAINS_RELATIVE_HEIGHT if it's needed.
435 // It would be nice to check that |mComputedHeight != NS_AUTOHEIGHT|
436 // &&ed with the percentage height check. However, this doesn't get
437 // along with table special height reflows, since a special height
438 // reflow (a quirk that makes such percentage heights work on children
439 // of table cells) can cause not just a single percentage height to
440 // become fixed, but an entire descendant chain of percentage heights
442 if (dependsOnCBHeight
&& mCBReflowState
) {
443 const nsHTMLReflowState
*rs
= this;
444 PRBool hitCBReflowState
= PR_FALSE
;
446 rs
= rs
->parentReflowState
;
451 if (rs
->frame
->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT
)
452 break; // no need to go further
453 rs
->frame
->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT
);
455 // Keep track of whether we've hit the containing block, because
456 // we need to go at least that far.
457 if (rs
== mCBReflowState
) {
458 hitCBReflowState
= PR_TRUE
;
461 } while (!hitCBReflowState
||
462 (eCompatibility_NavQuirks
== aPresContext
->CompatibilityMode() &&
463 !IsQuirkContainingBlockHeight(rs
)));
464 // Note: We actually don't need to set the
465 // NS_FRAME_CONTAINS_RELATIVE_HEIGHT bit for the cases
466 // where we hit the early break statements in
467 // CalcQuirkContainingBlockHeight. But it doesn't hurt
468 // us to set the bit in these cases.
471 if (frame
->GetStateBits() & NS_FRAME_IS_DIRTY
) {
472 // If we're reflowing everything, then we'll find out if we need
474 frame
->RemoveStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT
);
480 nsHTMLReflowState::GetContainingBlockContentWidth(const nsHTMLReflowState
* aReflowState
)
482 const nsHTMLReflowState
* rs
= aReflowState
->mCBReflowState
;
485 return rs
->mComputedWidth
;
490 nsHTMLReflowState::GetContainingBlockFor(const nsIFrame
* aFrame
)
492 NS_PRECONDITION(aFrame
, "Must have frame to work with");
493 nsIFrame
* container
= aFrame
->GetParent();
494 if (aFrame
->GetStyleDisplay()->IsAbsolutelyPositioned()) {
495 // Absolutely positioned frames are just kids of their containing
496 // blocks (which may happen to be inlines).
499 while (container
&& !container
->IsContainingBlock()) {
500 container
= container
->GetParent();
506 nsHTMLReflowState::InitFrameType()
508 const nsStyleDisplay
*disp
= mStyleDisplay
;
509 nsCSSFrameType frameType
;
511 // Section 9.7 of the CSS2 spec indicates that absolute position
512 // takes precedence over float which takes precedence over display.
513 // XXXldb nsRuleNode::ComputeDisplayData should take care of this, right?
514 // Make sure the frame was actually moved out of the flow, and don't
516 // just assume what the style says, because we might not have had a
517 // useful float/absolute containing block
518 nsIFrame
* frameToTest
=
519 frame
->GetType() == nsGkAtoms::tableFrame
? frame
->GetParent() : frame
;
521 DISPLAY_INIT_TYPE(frameToTest
, this);
523 NS_ASSERTION(frameToTest
->GetStyleDisplay()->IsAbsolutelyPositioned() ==
524 disp
->IsAbsolutelyPositioned(),
525 "Unexpected position style");
526 NS_ASSERTION(frameToTest
->GetStyleDisplay()->IsFloating() ==
527 disp
->IsFloating(), "Unexpected float style");
528 if (frameToTest
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
529 if (disp
->IsAbsolutelyPositioned()) {
530 frameType
= NS_CSS_FRAME_TYPE_ABSOLUTE
;
531 //XXXfr hack for making frames behave properly when in overflow container lists
532 // see bug 154892; need to revisit later
533 if (frameToTest
->GetPrevInFlow())
534 frameType
= NS_CSS_FRAME_TYPE_BLOCK
;
536 else if (disp
->IsFloating()) {
537 frameType
= NS_CSS_FRAME_TYPE_FLOATING
;
539 NS_ASSERTION(disp
->mDisplay
== NS_STYLE_DISPLAY_POPUP
,
540 "unknown out of flow frame type");
541 frameType
= NS_CSS_FRAME_TYPE_UNKNOWN
;
545 switch (disp
->mDisplay
) {
546 case NS_STYLE_DISPLAY_BLOCK
:
547 case NS_STYLE_DISPLAY_LIST_ITEM
:
548 case NS_STYLE_DISPLAY_TABLE
:
549 case NS_STYLE_DISPLAY_TABLE_CAPTION
:
550 frameType
= NS_CSS_FRAME_TYPE_BLOCK
;
553 case NS_STYLE_DISPLAY_INLINE
:
554 case NS_STYLE_DISPLAY_INLINE_BLOCK
:
555 case NS_STYLE_DISPLAY_MARKER
:
556 case NS_STYLE_DISPLAY_INLINE_TABLE
:
557 case NS_STYLE_DISPLAY_INLINE_BOX
:
558 case NS_STYLE_DISPLAY_INLINE_GRID
:
559 case NS_STYLE_DISPLAY_INLINE_STACK
:
560 frameType
= NS_CSS_FRAME_TYPE_INLINE
;
563 case NS_STYLE_DISPLAY_RUN_IN
:
564 case NS_STYLE_DISPLAY_COMPACT
:
565 // XXX need to look ahead at the frame's sibling
566 frameType
= NS_CSS_FRAME_TYPE_BLOCK
;
569 case NS_STYLE_DISPLAY_TABLE_CELL
:
570 case NS_STYLE_DISPLAY_TABLE_ROW_GROUP
:
571 case NS_STYLE_DISPLAY_TABLE_COLUMN
:
572 case NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
:
573 case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
:
574 case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP
:
575 case NS_STYLE_DISPLAY_TABLE_ROW
:
576 frameType
= NS_CSS_FRAME_TYPE_INTERNAL_TABLE
;
579 case NS_STYLE_DISPLAY_NONE
:
581 frameType
= NS_CSS_FRAME_TYPE_UNKNOWN
;
586 // See if the frame is replaced
587 if (frame
->IsFrameOfType(nsIFrame::eReplacedContainsBlock
)) {
588 frameType
= NS_FRAME_REPLACED_CONTAINS_BLOCK(frameType
);
589 } else if (frame
->IsFrameOfType(nsIFrame::eReplaced
)) {
590 frameType
= NS_FRAME_REPLACED(frameType
);
593 mFrameType
= frameType
;
597 nsHTMLReflowState::ComputeRelativeOffsets(const nsHTMLReflowState
* cbrs
,
598 nscoord aContainingBlockWidth
,
599 nscoord aContainingBlockHeight
,
600 nsPresContext
* aPresContext
)
602 // Compute the 'left' and 'right' values. 'Left' moves the boxes to the right,
603 // and 'right' moves the boxes to the left. The computed values are always:
605 PRBool leftIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetLeftUnit();
606 PRBool rightIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetRightUnit();
608 // Check for percentage based values and an unconstrained containing
609 // block width. Treat them like 'auto'
610 if (NS_UNCONSTRAINEDSIZE
== aContainingBlockWidth
) {
611 if (eStyleUnit_Percent
== mStylePosition
->mOffset
.GetLeftUnit()) {
612 leftIsAuto
= PR_TRUE
;
614 if (eStyleUnit_Percent
== mStylePosition
->mOffset
.GetRightUnit()) {
615 rightIsAuto
= PR_TRUE
;
619 // If neither 'left' not 'right' are auto, then we're over-constrained and
620 // we ignore one of them
621 if (!leftIsAuto
&& !rightIsAuto
) {
622 if (mCBReflowState
&&
623 NS_STYLE_DIRECTION_RTL
== mCBReflowState
->mStyleVisibility
->mDirection
) {
624 leftIsAuto
= PR_TRUE
;
626 rightIsAuto
= PR_TRUE
;
632 // If both are 'auto' (their initial values), the computed values are 0
633 mComputedOffsets
.left
= mComputedOffsets
.right
= 0;
635 // 'Right' isn't 'auto' so compute its value
636 mComputedOffsets
.right
= nsLayoutUtils::
637 ComputeWidthDependentValue(aContainingBlockWidth
,
638 mStylePosition
->mOffset
.GetRight());
640 // Computed value for 'left' is minus the value of 'right'
641 mComputedOffsets
.left
= -mComputedOffsets
.right
;
645 NS_ASSERTION(rightIsAuto
, "unexpected specified constraint");
647 // 'Left' isn't 'auto' so compute its value
648 mComputedOffsets
.left
= nsLayoutUtils::
649 ComputeWidthDependentValue(aContainingBlockWidth
,
650 mStylePosition
->mOffset
.GetLeft());
652 // Computed value for 'right' is minus the value of 'left'
653 mComputedOffsets
.right
= -mComputedOffsets
.left
;
656 // Compute the 'top' and 'bottom' values. The 'top' and 'bottom' properties
657 // move relatively positioned elements up and down. They also must be each
659 PRBool topIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetTopUnit();
660 PRBool bottomIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetBottomUnit();
662 // Check for percentage based values and a containing block height that
663 // depends on the content height. Treat them like 'auto'
664 if (NS_AUTOHEIGHT
== aContainingBlockHeight
) {
665 if (eStyleUnit_Percent
== mStylePosition
->mOffset
.GetTopUnit()) {
668 if (eStyleUnit_Percent
== mStylePosition
->mOffset
.GetBottomUnit()) {
669 bottomIsAuto
= PR_TRUE
;
673 // If neither is 'auto', 'bottom' is ignored
674 if (!topIsAuto
&& !bottomIsAuto
) {
675 bottomIsAuto
= PR_TRUE
;
680 // If both are 'auto' (their initial values), the computed values are 0
681 mComputedOffsets
.top
= mComputedOffsets
.bottom
= 0;
683 // 'Bottom' isn't 'auto' so compute its value
684 mComputedOffsets
.bottom
= nsLayoutUtils::
685 ComputeHeightDependentValue(aContainingBlockHeight
,
686 mStylePosition
->mOffset
.GetBottom());
688 // Computed value for 'top' is minus the value of 'bottom'
689 mComputedOffsets
.top
= -mComputedOffsets
.bottom
;
693 NS_ASSERTION(bottomIsAuto
, "unexpected specified constraint");
695 // 'Top' isn't 'auto' so compute its value
696 mComputedOffsets
.top
= nsLayoutUtils::
697 ComputeHeightDependentValue(aContainingBlockHeight
,
698 mStylePosition
->mOffset
.GetTop());
700 // Computed value for 'bottom' is minus the value of 'top'
701 mComputedOffsets
.bottom
= -mComputedOffsets
.top
;
705 FrameProperties
props(aPresContext
->PropertyTable(), frame
);
706 nsPoint
* offsets
= static_cast<nsPoint
*>
707 (props
.Get(nsIFrame::ComputedOffsetProperty()));
709 offsets
->MoveTo(mComputedOffsets
.left
, mComputedOffsets
.top
);
711 props
.Set(nsIFrame::ComputedOffsetProperty(),
712 new nsPoint(mComputedOffsets
.left
, mComputedOffsets
.top
));
717 GetNearestContainingBlock(nsIFrame
*aFrame
)
719 nsIFrame
*cb
= aFrame
;
721 cb
= cb
->GetParent();
722 } while (!cb
->IsContainingBlock());
727 nsHTMLReflowState::GetHypotheticalBoxContainer(nsIFrame
* aFrame
,
728 nscoord
& aCBLeftEdge
,
731 aFrame
= GetNearestContainingBlock(aFrame
);
732 NS_ASSERTION(aFrame
!= frame
, "How did that happen?");
734 /* Now aFrame is the containing block we want */
736 /* Check whether the containing block is currently being reflowed.
737 If so, use the info from the reflow state. */
738 const nsHTMLReflowState
* state
;
739 if (aFrame
->GetStateBits() & NS_FRAME_IN_REFLOW
) {
740 for (state
= parentReflowState
; state
&& state
->frame
!= aFrame
;
741 state
= state
->parentReflowState
) {
749 aCBLeftEdge
= state
->mComputedBorderPadding
.left
;
750 aCBWidth
= state
->mComputedWidth
;
752 /* Didn't find a reflow state for aFrame. Just compute the information we
753 want, on the assumption that aFrame already knows its size. This really
754 ought to be true by now. */
755 NS_ASSERTION(!(aFrame
->GetStateBits() & NS_FRAME_IN_REFLOW
),
756 "aFrame shouldn't be in reflow; we'll lie if it is");
757 nsMargin borderPadding
= aFrame
->GetUsedBorderAndPadding();
758 aCBLeftEdge
= borderPadding
.left
;
759 aCBWidth
= aFrame
->GetSize().width
- borderPadding
.LeftRight();
765 // When determining the hypothetical box that would have been if the element
766 // had been in the flow we may not be able to exactly determine both the left
767 // and right edges. For example, if the element is a non-replaced inline-level
768 // element we would have to reflow it in order to determine it desired width.
769 // In that case depending on the progression direction either the left or
770 // right edge would be marked as not being exact
771 struct nsHypotheticalBox
{
772 // offsets from left edge of containing block (which is a padding edge)
773 nscoord mLeft
, mRight
;
774 // offset from top edge of containing block (which is a padding edge)
777 PRPackedBool mLeftIsExact
, mRightIsExact
;
780 nsHypotheticalBox() {
782 mLeftIsExact
= mRightIsExact
= PR_FALSE
;
788 GetIntrinsicSizeFor(nsIFrame
* aFrame
, nsSize
& aIntrinsicSize
)
790 // See if it is an image frame
791 PRBool result
= PR_FALSE
;
793 // Currently the only type of replaced frame that we can get the intrinsic
794 // size for is an image frame
795 // XXX We should add back the GetReflowMetrics() function and one of the
796 // things should be the intrinsic size...
797 if (aFrame
->GetType() == nsGkAtoms::imageFrame
) {
798 nsImageFrame
* imageFrame
= (nsImageFrame
*)aFrame
;
800 imageFrame
->GetIntrinsicImageSize(aIntrinsicSize
);
801 result
= (aIntrinsicSize
!= nsSize(0, 0));
807 * aInsideBoxSizing returns the part of the horizontal padding, border,
808 * and margin that goes inside the edge given by -moz-box-sizing;
809 * aOutsideBoxSizing returns the rest.
812 nsHTMLReflowState::CalculateHorizBorderPaddingMargin(
813 nscoord aContainingBlockWidth
,
814 nscoord
* aInsideBoxSizing
,
815 nscoord
* aOutsideBoxSizing
)
817 const nsMargin
& border
= mStyleBorder
->GetActualBorder();
818 nsMargin padding
, margin
;
820 // See if the style system can provide us the padding directly
821 if (!mStylePadding
->GetPadding(padding
)) {
822 // We have to compute the left and right values
823 padding
.left
= nsLayoutUtils::
824 ComputeWidthDependentValue(aContainingBlockWidth
,
825 mStylePadding
->mPadding
.GetLeft());
826 padding
.right
= nsLayoutUtils::
827 ComputeWidthDependentValue(aContainingBlockWidth
,
828 mStylePadding
->mPadding
.GetRight());
831 // See if the style system can provide us the margin directly
832 if (!mStyleMargin
->GetMargin(margin
)) {
833 // We have to compute the left and right values
834 if (eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetLeftUnit()) {
835 // XXX FIXME (or does CalculateBlockSideMargins do this?)
836 margin
.left
= 0; // just ignore
838 margin
.left
= nsLayoutUtils::
839 ComputeWidthDependentValue(aContainingBlockWidth
,
840 mStyleMargin
->mMargin
.GetLeft());
842 if (eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetRightUnit()) {
843 // XXX FIXME (or does CalculateBlockSideMargins do this?)
844 margin
.right
= 0; // just ignore
846 margin
.right
= nsLayoutUtils::
847 ComputeWidthDependentValue(aContainingBlockWidth
,
848 mStyleMargin
->mMargin
.GetRight());
853 padding
.LeftRight() + border
.LeftRight() + margin
.LeftRight();
855 switch (mStylePosition
->mBoxSizing
) {
856 case NS_STYLE_BOX_SIZING_BORDER
:
857 inside
+= border
.LeftRight();
859 case NS_STYLE_BOX_SIZING_PADDING
:
860 inside
+= padding
.LeftRight();
863 *aInsideBoxSizing
= inside
;
864 *aOutsideBoxSizing
= outside
;
869 * Returns PR_TRUE iff a pre-order traversal of the normal child
870 * frames rooted at aFrame finds no non-empty frame before aDescendant.
872 static PRBool
AreAllEarlierInFlowFramesEmpty(nsIFrame
* aFrame
,
873 nsIFrame
* aDescendant
, PRBool
* aFound
) {
874 if (aFrame
== aDescendant
) {
878 if (!aFrame
->IsSelfEmpty()) {
882 for (nsIFrame
* f
= aFrame
->GetFirstChild(nsnull
); f
; f
= f
->GetNextSibling()) {
883 PRBool allEmpty
= AreAllEarlierInFlowFramesEmpty(f
, aDescendant
, aFound
);
884 if (*aFound
|| !allEmpty
) {
892 // Calculate the hypothetical box that the element would have if it were in
893 // the flow. The values returned are relative to the padding edge of the
894 // absolute containing block
895 // aContainingBlock is the placeholder's containing block (XXX rename it?)
896 // cbrs->frame is the actual containing block
898 nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext
* aPresContext
,
899 nsIFrame
* aPlaceholderFrame
,
900 nsIFrame
* aContainingBlock
,
901 nscoord aBlockLeftContentEdge
,
902 nscoord aBlockContentWidth
,
903 const nsHTMLReflowState
* cbrs
,
904 nsHypotheticalBox
& aHypotheticalBox
)
906 NS_ASSERTION(mStyleDisplay
->mOriginalDisplay
!= NS_STYLE_DISPLAY_NONE
,
907 "mOriginalDisplay has not been properly initialized");
909 // If it's a replaced element and it has a 'auto' value for 'width', see if we
910 // can get the intrinsic size. This will allow us to exactly determine both the
911 // left and right edges
912 PRBool isAutoWidth
= mStylePosition
->mWidth
.GetUnit() == eStyleUnit_Auto
;
913 nsSize intrinsicSize
;
914 PRBool knowIntrinsicSize
= PR_FALSE
;
915 if (NS_FRAME_IS_REPLACED(mFrameType
) && isAutoWidth
) {
916 // See if we can get the intrinsic size of the element
917 knowIntrinsicSize
= GetIntrinsicSizeFor(frame
, intrinsicSize
);
920 // See if we can calculate what the box width would have been if the
921 // element had been in the flow
923 PRBool knowBoxWidth
= PR_FALSE
;
924 if ((NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) &&
925 !NS_FRAME_IS_REPLACED(mFrameType
)) {
926 // For non-replaced inline-level elements the 'width' property doesn't apply,
927 // so we don't know what the width would have been without reflowing it
930 // It's either a replaced inline-level element or a block-level element
932 // Determine the total amount of horizontal border/padding/margin that
933 // the element would have had if it had been in the flow. Note that we
934 // ignore any 'auto' and 'inherit' values
935 nscoord insideBoxSizing
, outsideBoxSizing
;
936 CalculateHorizBorderPaddingMargin(aBlockContentWidth
,
937 &insideBoxSizing
, &outsideBoxSizing
);
939 if (NS_FRAME_IS_REPLACED(mFrameType
) && isAutoWidth
) {
940 // It's a replaced element with an 'auto' width so the box width is
941 // its intrinsic size plus any border/padding/margin
942 if (knowIntrinsicSize
) {
943 boxWidth
= intrinsicSize
.width
+ outsideBoxSizing
+ insideBoxSizing
;
944 knowBoxWidth
= PR_TRUE
;
947 } else if (isAutoWidth
) {
948 // The box width is the containing block width
949 boxWidth
= aBlockContentWidth
;
950 knowBoxWidth
= PR_TRUE
;
953 // We need to compute it. It's important we do this, because if it's
954 // percentage based this computed value may be different from the computed
955 // value calculated using the absolute containing block width
956 boxWidth
= ComputeWidthValue(aBlockContentWidth
,
957 insideBoxSizing
, outsideBoxSizing
,
958 mStylePosition
->mWidth
) +
959 insideBoxSizing
+ outsideBoxSizing
;
960 knowBoxWidth
= PR_TRUE
;
964 // Get the 'direction' of the block
965 const nsStyleVisibility
* blockVis
= aContainingBlock
->GetStyleVisibility();
967 // Get the placeholder x-offset and y-offset in the coordinate
968 // space of its containing block
969 // XXXbz the placeholder is not fully reflowed yet if our containing block is
970 // relatively positioned...
971 nsPoint placeholderOffset
= aPlaceholderFrame
->GetOffsetTo(aContainingBlock
);
973 // First, determine the hypothetical box's mTop. We want to check the
974 // content insertion frame of aContainingBlock for block-ness, but make
975 // sure to compute all coordinates in the coordinate system of
977 nsBlockFrame
* blockFrame
=
978 nsLayoutUtils::GetAsBlock(aContainingBlock
->GetContentInsertionFrame());
980 nscoord blockYOffset
= blockFrame
->GetOffsetTo(aContainingBlock
).y
;
982 nsBlockInFlowLineIterator
iter(blockFrame
, aPlaceholderFrame
, &isValid
);
983 NS_ASSERTION(isValid
, "Can't find placeholder!");
984 NS_ASSERTION(iter
.GetContainer() == blockFrame
, "Found placeholder in wrong block!");
985 nsBlockFrame::line_iterator lineBox
= iter
.GetLine();
987 // How we determine the hypothetical box depends on whether the element
988 // would have been inline-level or block-level
989 if (NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) {
990 // Use the top of the inline box which the placeholder lives in as the
991 // hypothetical box's top.
992 aHypotheticalBox
.mTop
= lineBox
->mBounds
.y
+ blockYOffset
;
994 // The element would have been block-level which means it would be below
995 // the line containing the placeholder frame, unless all the frames
996 // before it are empty. In that case, it would have been just before
998 // XXXbz the line box is not fully reflowed yet if our containing block is
999 // relatively positioned...
1000 if (lineBox
!= iter
.End()) {
1001 nsIFrame
* firstFrame
= lineBox
->mFirstChild
;
1002 PRBool found
= PR_FALSE
;
1003 PRBool allEmpty
= PR_TRUE
;
1004 while (firstFrame
) { // See bug 223064
1005 allEmpty
= AreAllEarlierInFlowFramesEmpty(firstFrame
,
1006 aPlaceholderFrame
, &found
);
1007 if (found
|| !allEmpty
)
1009 firstFrame
= firstFrame
->GetNextSibling();
1011 NS_ASSERTION(firstFrame
, "Couldn't find placeholder!");
1014 // The top of the hypothetical box is the top of the line containing
1015 // the placeholder, since there is nothing in the line before our
1016 // placeholder except empty frames.
1017 aHypotheticalBox
.mTop
= lineBox
->mBounds
.y
+ blockYOffset
;
1019 // The top of the hypothetical box is just below the line containing
1021 aHypotheticalBox
.mTop
= lineBox
->mBounds
.YMost() + blockYOffset
;
1024 // Just use the placeholder's y-offset wrt the containing block
1025 aHypotheticalBox
.mTop
= placeholderOffset
.y
;
1029 // The containing block is not a block, so it's probably something
1030 // like a XUL box, etc.
1031 // Just use the placeholder's y-offset
1032 aHypotheticalBox
.mTop
= placeholderOffset
.y
;
1035 // Second, determine the hypothetical box's mLeft & mRight
1036 // To determine the left and right offsets we need to look at the block's 'direction'
1037 if (NS_STYLE_DIRECTION_LTR
== blockVis
->mDirection
) {
1038 // How we determine the hypothetical box depends on whether the element
1039 // would have been inline-level or block-level
1040 if (NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) {
1041 // The placeholder represents the left edge of the hypothetical box
1042 aHypotheticalBox
.mLeft
= placeholderOffset
.x
;
1044 aHypotheticalBox
.mLeft
= aBlockLeftContentEdge
;
1047 aHypotheticalBox
.mLeftIsExact
= PR_TRUE
;
1051 aHypotheticalBox
.mRight
= aHypotheticalBox
.mLeft
+ boxWidth
;
1053 aHypotheticalBox
.mRightIsExact
= PR_TRUE
;
1056 // We can't compute the right edge because we don't know the desired
1057 // width. So instead use the right content edge of the block parent,
1058 // but remember it's not exact
1059 aHypotheticalBox
.mRight
= aBlockLeftContentEdge
+ aBlockContentWidth
;
1061 aHypotheticalBox
.mRightIsExact
= PR_FALSE
;
1066 // The placeholder represents the right edge of the hypothetical box
1067 if (NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) {
1068 aHypotheticalBox
.mRight
= placeholderOffset
.x
;
1070 aHypotheticalBox
.mRight
= aBlockLeftContentEdge
+ aBlockContentWidth
;
1073 aHypotheticalBox
.mRightIsExact
= PR_TRUE
;
1077 aHypotheticalBox
.mLeft
= aHypotheticalBox
.mRight
- boxWidth
;
1079 aHypotheticalBox
.mLeftIsExact
= PR_TRUE
;
1082 // We can't compute the left edge because we don't know the desired
1083 // width. So instead use the left content edge of the block parent,
1084 // but remember it's not exact
1085 aHypotheticalBox
.mLeft
= aBlockLeftContentEdge
;
1087 aHypotheticalBox
.mLeftIsExact
= PR_FALSE
;
1093 // The current coordinate space is that of the nearest block to the placeholder.
1094 // Convert to the coordinate space of the absolute containing block
1095 // One weird thing here is that for fixed-positioned elements we want to do
1096 // the conversion incorrectly; specifically we want to ignore any scrolling
1097 // that may have happened;
1099 if (mStyleDisplay
->mPosition
== NS_STYLE_POSITION_FIXED
&&
1100 // Exclude cases inside -moz-transform where fixed is like absolute.
1101 nsLayoutUtils::IsReallyFixedPos(frame
)) {
1102 // In this case, cbrs->frame will always be an ancestor of
1103 // aContainingBlock, so can just walk our way up the frame tree.
1104 // Make sure to not add positions of frames whose parent is a
1105 // scrollFrame, since we're doing fixed positioning, which assumes
1106 // everything is scrolled to (0,0).
1107 cbOffset
.MoveTo(0, 0);
1109 NS_ASSERTION(aContainingBlock
,
1110 "Should hit cbrs->frame before we run off the frame tree!");
1111 cbOffset
+= aContainingBlock
->GetPositionIgnoringScrolling();
1112 aContainingBlock
= aContainingBlock
->GetParent();
1113 } while (aContainingBlock
!= cbrs
->frame
);
1115 // XXXldb We need to either ignore scrolling for the absolute
1116 // positioning case too (and take the incompatibility) or figure out
1117 // how to make these positioned elements actually *move* when we
1118 // scroll, and thus avoid the resulting incremental reflow bugs.
1119 cbOffset
= aContainingBlock
->GetOffsetTo(cbrs
->frame
);
1121 aHypotheticalBox
.mLeft
+= cbOffset
.x
;
1122 aHypotheticalBox
.mTop
+= cbOffset
.y
;
1123 aHypotheticalBox
.mRight
+= cbOffset
.x
;
1125 // The specified offsets are relative to the absolute containing block's
1126 // padding edge and our current values are relative to the border edge, so
1128 nsMargin border
= cbrs
->mComputedBorderPadding
- cbrs
->mComputedPadding
;
1129 aHypotheticalBox
.mLeft
-= border
.left
;
1130 aHypotheticalBox
.mRight
-= border
.left
;
1131 aHypotheticalBox
.mTop
-= border
.top
;
1135 nsHTMLReflowState::InitAbsoluteConstraints(nsPresContext
* aPresContext
,
1136 const nsHTMLReflowState
* cbrs
,
1137 nscoord containingBlockWidth
,
1138 nscoord containingBlockHeight
)
1140 NS_PRECONDITION(containingBlockHeight
!= NS_AUTOHEIGHT
,
1141 "containing block height must be constrained");
1143 nsIFrame
* outOfFlow
=
1144 frame
->GetType() == nsGkAtoms::tableFrame
? frame
->GetParent() : frame
;
1145 NS_ASSERTION(outOfFlow
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
,
1146 "Why are we here?");
1148 // Get the placeholder frame
1149 nsIFrame
* placeholderFrame
;
1151 placeholderFrame
= aPresContext
->PresShell()->GetPlaceholderFrameFor(outOfFlow
);
1152 NS_ASSERTION(nsnull
!= placeholderFrame
, "no placeholder frame");
1154 // If both 'left' and 'right' are 'auto' or both 'top' and 'bottom' are
1155 // 'auto', then compute the hypothetical box of where the element would
1156 // have been if it had been in the flow
1157 nsHypotheticalBox hypotheticalBox
;
1158 if (((eStyleUnit_Auto
== mStylePosition
->mOffset
.GetLeftUnit()) &&
1159 (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetRightUnit())) ||
1160 ((eStyleUnit_Auto
== mStylePosition
->mOffset
.GetTopUnit()) &&
1161 (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetBottomUnit()))) {
1162 // Find the nearest containing block frame to the placeholder frame,
1163 // and return its left edge and width.
1164 nscoord cbLeftEdge
, cbWidth
;
1165 nsIFrame
* cbFrame
= GetHypotheticalBoxContainer(placeholderFrame
,
1169 CalculateHypotheticalBox(aPresContext
, placeholderFrame
, cbFrame
,
1170 cbLeftEdge
, cbWidth
, cbrs
, hypotheticalBox
);
1173 // Initialize the 'left' and 'right' computed offsets
1174 // XXX Handle new 'static-position' value...
1175 PRBool leftIsAuto
= PR_FALSE
, rightIsAuto
= PR_FALSE
;
1176 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetLeftUnit()) {
1177 mComputedOffsets
.left
= 0;
1178 leftIsAuto
= PR_TRUE
;
1180 mComputedOffsets
.left
= nsLayoutUtils::
1181 ComputeWidthDependentValue(containingBlockWidth
,
1182 mStylePosition
->mOffset
.GetLeft());
1184 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetRightUnit()) {
1185 mComputedOffsets
.right
= 0;
1186 rightIsAuto
= PR_TRUE
;
1188 mComputedOffsets
.right
= nsLayoutUtils::
1189 ComputeWidthDependentValue(containingBlockWidth
,
1190 mStylePosition
->mOffset
.GetRight());
1193 // Use the horizontal component of the hypothetical box in the cases
1194 // where it's needed.
1195 if (leftIsAuto
&& rightIsAuto
) {
1196 // Use the direction of the original ("static-position") containing block
1197 // to dictate whether 'left' or 'right' is treated like 'static-position'.
1198 if (NS_STYLE_DIRECTION_LTR
== GetNearestContainingBlock(placeholderFrame
)
1199 ->GetStyleVisibility()->mDirection
) {
1200 NS_ASSERTION(hypotheticalBox
.mLeftIsExact
, "should always have "
1201 "exact value on containing block's start side");
1202 mComputedOffsets
.left
= hypotheticalBox
.mLeft
;
1203 leftIsAuto
= PR_FALSE
;
1205 NS_ASSERTION(hypotheticalBox
.mRightIsExact
, "should always have "
1206 "exact value on containing block's start side");
1207 mComputedOffsets
.right
= containingBlockWidth
- hypotheticalBox
.mRight
;
1208 rightIsAuto
= PR_FALSE
;
1212 // Initialize the 'top' and 'bottom' computed offsets
1213 PRBool topIsAuto
= PR_FALSE
, bottomIsAuto
= PR_FALSE
;
1214 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetTopUnit()) {
1215 mComputedOffsets
.top
= 0;
1216 topIsAuto
= PR_TRUE
;
1218 mComputedOffsets
.top
= nsLayoutUtils::
1219 ComputeHeightDependentValue(containingBlockHeight
,
1220 mStylePosition
->mOffset
.GetTop());
1222 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetBottomUnit()) {
1223 mComputedOffsets
.bottom
= 0;
1224 bottomIsAuto
= PR_TRUE
;
1226 mComputedOffsets
.bottom
= nsLayoutUtils::
1227 ComputeHeightDependentValue(containingBlockHeight
,
1228 mStylePosition
->mOffset
.GetBottom());
1231 if (topIsAuto
&& bottomIsAuto
) {
1232 // Treat 'top' like 'static-position'
1233 mComputedOffsets
.top
= hypotheticalBox
.mTop
;
1234 topIsAuto
= PR_FALSE
;
1237 PRBool widthIsAuto
= eStyleUnit_Auto
== mStylePosition
->mWidth
.GetUnit();
1238 PRBool heightIsAuto
= eStyleUnit_Auto
== mStylePosition
->mHeight
.GetUnit();
1240 PRBool shrinkWrap
= leftIsAuto
|| rightIsAuto
;
1242 frame
->ComputeSize(rendContext
,
1243 nsSize(containingBlockWidth
,
1244 containingBlockHeight
),
1245 containingBlockWidth
, // XXX or availableWidth?
1246 nsSize(mComputedMargin
.LeftRight() +
1247 mComputedOffsets
.LeftRight(),
1248 mComputedMargin
.TopBottom() +
1249 mComputedOffsets
.TopBottom()),
1250 nsSize(mComputedBorderPadding
.LeftRight() -
1251 mComputedPadding
.LeftRight(),
1252 mComputedBorderPadding
.TopBottom() -
1253 mComputedPadding
.TopBottom()),
1254 nsSize(mComputedPadding
.LeftRight(),
1255 mComputedPadding
.TopBottom()),
1257 mComputedWidth
= size
.width
;
1258 mComputedHeight
= size
.height
;
1259 NS_ASSERTION(mComputedWidth
>= 0, "Bogus width");
1260 NS_ASSERTION(mComputedHeight
== NS_UNCONSTRAINEDSIZE
||
1261 mComputedHeight
>= 0, "Bogus height");
1263 // XXX Now that we have ComputeSize, can we condense many of the
1264 // branches off of widthIsAuto?
1267 // We know 'right' is not 'auto' anymore thanks to the hypothetical
1269 // Solve for 'left'.
1271 // XXXldb This, and the corresponding code in
1272 // nsAbsoluteContainingBlock.cpp, could probably go away now that
1273 // we always compute widths.
1274 mComputedOffsets
.left
= NS_AUTOOFFSET
;
1276 mComputedOffsets
.left
= containingBlockWidth
- mComputedMargin
.left
-
1277 mComputedBorderPadding
.left
- mComputedWidth
- mComputedBorderPadding
.right
-
1278 mComputedMargin
.right
- mComputedOffsets
.right
;
1281 } else if (rightIsAuto
) {
1282 // We know 'left' is not 'auto' anymore thanks to the hypothetical
1284 // Solve for 'right'.
1286 // XXXldb This, and the corresponding code in
1287 // nsAbsoluteContainingBlock.cpp, could probably go away now that
1288 // we always compute widths.
1289 mComputedOffsets
.right
= NS_AUTOOFFSET
;
1291 mComputedOffsets
.right
= containingBlockWidth
- mComputedOffsets
.left
-
1292 mComputedMargin
.left
- mComputedBorderPadding
.left
- mComputedWidth
-
1293 mComputedBorderPadding
.right
- mComputedMargin
.right
;
1296 // Neither 'left' nor 'right' is 'auto'. However, the width might
1297 // still not fill all the available space (even though we didn't
1298 // shrink-wrap) in case:
1299 // * width was specified
1300 // * we're dealing with a replaced element
1301 // * width was constrained by min-width or max-width.
1303 nscoord availMarginSpace
= containingBlockWidth
-
1304 mComputedOffsets
.LeftRight() -
1305 mComputedMargin
.LeftRight() -
1306 mComputedBorderPadding
.LeftRight() -
1308 PRBool marginLeftIsAuto
=
1309 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetLeftUnit();
1310 PRBool marginRightIsAuto
=
1311 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetRightUnit();
1313 if (availMarginSpace
< 0 ||
1314 (!marginLeftIsAuto
&& !marginRightIsAuto
)) {
1315 // We're over-constrained so use the direction of the containing block
1316 // to dictate which value to ignore. (And note that the spec says to ignore
1317 // 'left' or 'right' rather than 'margin-left' or 'margin-right'.)
1319 NS_STYLE_DIRECTION_RTL
== cbrs
->mStyleVisibility
->mDirection
) {
1320 // Ignore the specified value for 'left'.
1321 mComputedOffsets
.left
+= availMarginSpace
;
1323 // Ignore the specified value for 'right'.
1324 mComputedOffsets
.right
+= availMarginSpace
;
1326 } else if (marginLeftIsAuto
) {
1327 if (marginRightIsAuto
) {
1328 // Both 'margin-left' and 'margin-right' are 'auto', so they get
1330 mComputedMargin
.left
= availMarginSpace
/ 2;
1331 mComputedMargin
.right
= availMarginSpace
- mComputedMargin
.left
;
1333 // Just 'margin-left' is 'auto'
1334 mComputedMargin
.left
= availMarginSpace
;
1337 // Just 'margin-right' is 'auto'
1338 mComputedMargin
.right
= availMarginSpace
;
1345 mComputedOffsets
.top
= NS_AUTOOFFSET
;
1347 mComputedOffsets
.top
= containingBlockHeight
- mComputedMargin
.top
-
1348 mComputedBorderPadding
.top
- mComputedHeight
- mComputedBorderPadding
.bottom
-
1349 mComputedMargin
.bottom
- mComputedOffsets
.bottom
;
1351 } else if (bottomIsAuto
) {
1352 // solve for 'bottom'
1354 mComputedOffsets
.bottom
= NS_AUTOOFFSET
;
1356 mComputedOffsets
.bottom
= containingBlockHeight
- mComputedOffsets
.top
-
1357 mComputedMargin
.top
- mComputedBorderPadding
.top
- mComputedHeight
-
1358 mComputedBorderPadding
.bottom
- mComputedMargin
.bottom
;
1361 // Neither 'top' nor 'bottom' is 'auto'.
1362 nscoord autoHeight
= containingBlockHeight
-
1363 mComputedOffsets
.TopBottom() -
1364 mComputedMargin
.TopBottom() -
1365 mComputedBorderPadding
.TopBottom();
1366 if (autoHeight
< 0) {
1370 if (mComputedHeight
== NS_UNCONSTRAINEDSIZE
) {
1371 // For non-replaced elements with 'height' auto, the 'height'
1372 // fills the remaining space.
1373 mComputedHeight
= autoHeight
;
1375 // XXX Do these need box-sizing adjustments?
1376 if (mComputedHeight
> mComputedMaxHeight
)
1377 mComputedHeight
= mComputedMaxHeight
;
1378 if (mComputedHeight
< mComputedMinHeight
)
1379 mComputedHeight
= mComputedMinHeight
;
1382 // The height might still not fill all the available space in case:
1383 // * height was specified
1384 // * we're dealing with a replaced element
1385 // * height was constrained by min-height or max-height.
1386 nscoord availMarginSpace
= autoHeight
- mComputedHeight
;
1387 PRBool marginTopIsAuto
=
1388 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetTopUnit();
1389 PRBool marginBottomIsAuto
=
1390 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetBottomUnit();
1392 if (availMarginSpace
< 0 || (!marginTopIsAuto
&& !marginBottomIsAuto
)) {
1393 // We're over-constrained so ignore the specified value for
1394 // 'bottom'. (And note that the spec says to ignore 'bottom'
1395 // rather than 'margin-bottom'.)
1396 mComputedOffsets
.bottom
+= availMarginSpace
;
1397 } else if (marginTopIsAuto
) {
1398 if (marginBottomIsAuto
) {
1399 // Both 'margin-top' and 'margin-bottom' are 'auto', so they get
1401 mComputedMargin
.top
= availMarginSpace
/ 2;
1402 mComputedMargin
.bottom
= availMarginSpace
- mComputedMargin
.top
;
1404 // Just 'margin-top' is 'auto'
1405 mComputedMargin
.top
= availMarginSpace
- mComputedMargin
.bottom
;
1408 // Just 'margin-bottom' is 'auto'
1409 mComputedMargin
.bottom
= availMarginSpace
- mComputedMargin
.top
;
1415 GetVerticalMarginBorderPadding(const nsHTMLReflowState
* aReflowState
)
1418 if (!aReflowState
) return result
;
1420 // zero auto margins
1421 nsMargin margin
= aReflowState
->mComputedMargin
;
1422 if (NS_AUTOMARGIN
== margin
.top
)
1424 if (NS_AUTOMARGIN
== margin
.bottom
)
1427 result
+= margin
.top
+ margin
.bottom
;
1428 result
+= aReflowState
->mComputedBorderPadding
.top
+
1429 aReflowState
->mComputedBorderPadding
.bottom
;
1434 /* Get the height based on the viewport of the containing block specified
1435 * in aReflowState when the containing block has mComputedHeight == NS_AUTOHEIGHT
1436 * This will walk up the chain of containing blocks looking for a computed height
1437 * until it finds the canvas frame, or it encounters a frame that is not a block,
1438 * area, or scroll frame. This handles compatibility with IE (see bug 85016 and bug 219693)
1440 * When we encounter scrolledContent block frames, we skip over them, since they are guaranteed to not be useful for computing the containing block.
1442 * See also IsQuirkContainingBlockHeight.
1445 CalcQuirkContainingBlockHeight(const nsHTMLReflowState
* aCBReflowState
)
1447 nsHTMLReflowState
* firstAncestorRS
= nsnull
; // a candidate for html frame
1448 nsHTMLReflowState
* secondAncestorRS
= nsnull
; // a candidate for body frame
1450 // initialize the default to NS_AUTOHEIGHT as this is the containings block
1451 // computed height when this function is called. It is possible that we
1452 // don't alter this height especially if we are restricted to one level
1453 nscoord result
= NS_AUTOHEIGHT
;
1455 const nsHTMLReflowState
* rs
= aCBReflowState
;
1456 for (; rs
; rs
= (nsHTMLReflowState
*)(rs
->parentReflowState
)) {
1457 nsIAtom
* frameType
= rs
->frame
->GetType();
1458 // if the ancestor is auto height then skip it and continue up if it
1459 // is the first block frame and possibly the body/html
1460 if (nsGkAtoms::blockFrame
== frameType
||
1462 nsGkAtoms::XULLabelFrame
== frameType
||
1464 nsGkAtoms::scrollFrame
== frameType
) {
1466 secondAncestorRS
= firstAncestorRS
;
1467 firstAncestorRS
= (nsHTMLReflowState
*)rs
;
1469 // If the current frame we're looking at is positioned, we don't want to
1470 // go any further (see bug 221784). The behavior we want here is: 1) If
1471 // not auto-height, use this as the percentage base. 2) If auto-height,
1472 // keep looking, unless the frame is positioned.
1473 if (NS_AUTOHEIGHT
== rs
->ComputedHeight()) {
1474 if (rs
->frame
->GetStyleDisplay()->IsAbsolutelyPositioned()) {
1481 else if (nsGkAtoms::canvasFrame
== frameType
) {
1482 // Always continue on to the height calculation
1484 else if (nsGkAtoms::pageContentFrame
== frameType
) {
1485 nsIFrame
* prevInFlow
= rs
->frame
->GetPrevInFlow();
1486 // only use the page content frame for a height basis if it is the first in flow
1494 // if the ancestor is the page content frame then the percent base is
1495 // the avail height, otherwise it is the computed height
1496 result
= (nsGkAtoms::pageContentFrame
== frameType
)
1497 ? rs
->availableHeight
: rs
->ComputedHeight();
1498 // if unconstrained - don't sutract borders - would result in huge height
1499 if (NS_AUTOHEIGHT
== result
) return result
;
1501 // if we got to the canvas or page content frame, then subtract out
1502 // margin/border/padding for the BODY and HTML elements
1503 if ((nsGkAtoms::canvasFrame
== frameType
) ||
1504 (nsGkAtoms::pageContentFrame
== frameType
)) {
1506 result
-= GetVerticalMarginBorderPadding(firstAncestorRS
);
1507 result
-= GetVerticalMarginBorderPadding(secondAncestorRS
);
1510 // make sure the first ancestor is the HTML and the second is the BODY
1511 if (firstAncestorRS
) {
1512 nsIContent
* frameContent
= firstAncestorRS
->frame
->GetContent();
1514 nsIAtom
*contentTag
= frameContent
->Tag();
1515 NS_ASSERTION(contentTag
== nsGkAtoms::html
, "First ancestor is not HTML");
1518 if (secondAncestorRS
) {
1519 nsIContent
* frameContent
= secondAncestorRS
->frame
->GetContent();
1521 nsIAtom
*contentTag
= frameContent
->Tag();
1522 NS_ASSERTION(contentTag
== nsGkAtoms::body
, "Second ancestor is not BODY");
1528 // if we got to the html frame (a block child of the canvas) ...
1529 else if (nsGkAtoms::blockFrame
== frameType
&&
1530 nsGkAtoms::canvasFrame
==
1531 rs
->parentReflowState
->frame
->GetType()) {
1532 // ... then subtract out margin/border/padding for the BODY element
1533 result
-= GetVerticalMarginBorderPadding(secondAncestorRS
);
1538 // Make sure not to return a negative height here!
1539 return NS_MAX(result
, 0);
1541 // Called by InitConstraints() to compute the containing block rectangle for
1542 // the element. Handles the special logic for absolutely positioned elements
1544 nsHTMLReflowState::ComputeContainingBlockRectangle(nsPresContext
* aPresContext
,
1545 const nsHTMLReflowState
* aContainingBlockRS
,
1546 nscoord
& aContainingBlockWidth
,
1547 nscoord
& aContainingBlockHeight
)
1549 // Unless the element is absolutely positioned, the containing block is
1550 // formed by the content edge of the nearest block-level ancestor
1551 aContainingBlockWidth
= aContainingBlockRS
->mComputedWidth
;
1552 aContainingBlockHeight
= aContainingBlockRS
->mComputedHeight
;
1554 if (NS_FRAME_GET_TYPE(mFrameType
) == NS_CSS_FRAME_TYPE_ABSOLUTE
) {
1555 // See if the ancestor is block-level or inline-level
1556 if (NS_FRAME_GET_TYPE(aContainingBlockRS
->mFrameType
) == NS_CSS_FRAME_TYPE_INLINE
) {
1557 // Base our size on the actual size of the frame. In cases when this is
1558 // completely bogus (eg initial reflow), this code shouldn't even be
1559 // called, since the code in nsPositionedInlineFrame::Reflow will pass in
1560 // the containing block dimensions to our constructor.
1561 // XXXbz we should be taking the in-flows into account too, but
1562 // that's very hard.
1563 nsMargin computedBorder
= aContainingBlockRS
->mComputedBorderPadding
-
1564 aContainingBlockRS
->mComputedPadding
;
1565 aContainingBlockWidth
= aContainingBlockRS
->frame
->GetRect().width
-
1566 computedBorder
.LeftRight();;
1567 NS_ASSERTION(aContainingBlockWidth
>= 0,
1568 "Negative containing block width!");
1569 aContainingBlockHeight
= aContainingBlockRS
->frame
->GetRect().height
-
1570 computedBorder
.TopBottom();
1571 NS_ASSERTION(aContainingBlockHeight
>= 0,
1572 "Negative containing block height!");
1574 // If the ancestor is block-level, the containing block is formed by the
1575 // padding edge of the ancestor
1576 aContainingBlockWidth
+= aContainingBlockRS
->mComputedPadding
.LeftRight();
1577 aContainingBlockHeight
+= aContainingBlockRS
->mComputedPadding
.TopBottom();
1580 // an element in quirks mode gets a containing block based on looking for a
1581 // parent with a non-auto height if the element has a percent height
1582 if (NS_AUTOHEIGHT
== aContainingBlockHeight
) {
1583 if (eCompatibility_NavQuirks
== aPresContext
->CompatibilityMode() &&
1584 mStylePosition
->mHeight
.GetUnit() == eStyleUnit_Percent
) {
1585 aContainingBlockHeight
= CalcQuirkContainingBlockHeight(aContainingBlockRS
);
1591 // Prefs callback to pick up changes
1593 PrefsChanged(const char *aPrefName
, void *instance
)
1596 nsContentUtils::GetBoolPref("browser.blink_allowed", sBlinkIsAllowed
);
1598 return 0; /* PREF_OK */
1601 // Check to see if |text-decoration: blink| is allowed. The first time
1602 // called, register the callback and then force-load the pref. After that,
1603 // just use the cached value.
1604 static PRBool
BlinkIsAllowed(void)
1606 if (!sPrefIsLoaded
) {
1607 // Set up a listener and check the initial value
1608 nsContentUtils::RegisterPrefCallback("browser.blink_allowed", PrefsChanged
,
1610 PrefsChanged(nsnull
, nsnull
);
1611 sPrefIsLoaded
= PR_TRUE
;
1613 return sBlinkIsAllowed
;
1616 static eNormalLineHeightControl
GetNormalLineHeightCalcControl(void)
1618 if (sNormalLineHeightControl
== eUninitialized
) {
1619 // browser.display.normal_lineheight_calc_control is not user
1620 // changeable, so no need to register callback for it.
1621 sNormalLineHeightControl
=
1622 static_cast<eNormalLineHeightControl
>
1623 (nsContentUtils::GetIntPref("browser.display.normal_lineheight_calc_control", eNoExternalLeading
));
1625 return sNormalLineHeightControl
;
1628 static inline PRBool
1629 IsSideCaption(nsIFrame
* aFrame
, const nsStyleDisplay
* aStyleDisplay
)
1631 if (aStyleDisplay
->mDisplay
!= NS_STYLE_DISPLAY_TABLE_CAPTION
)
1633 PRUint8 captionSide
= aFrame
->GetStyleTableBorder()->mCaptionSide
;
1634 return captionSide
== NS_STYLE_CAPTION_SIDE_LEFT
||
1635 captionSide
== NS_STYLE_CAPTION_SIDE_RIGHT
;
1638 // XXX refactor this code to have methods for each set of properties
1639 // we are computing: width,height,line-height; margin; offsets
1642 nsHTMLReflowState::InitConstraints(nsPresContext
* aPresContext
,
1643 nscoord aContainingBlockWidth
,
1644 nscoord aContainingBlockHeight
,
1645 const nsMargin
* aBorder
,
1646 const nsMargin
* aPadding
)
1648 DISPLAY_INIT_CONSTRAINTS(frame
, this,
1649 aContainingBlockWidth
, aContainingBlockHeight
,
1652 // Since we are in reflow, we don't need to store these properties anymore
1653 FrameProperties
props(aPresContext
->PropertyTable(), frame
);
1654 props
.Delete(nsIFrame::UsedBorderProperty());
1655 props
.Delete(nsIFrame::UsedPaddingProperty());
1656 props
.Delete(nsIFrame::UsedMarginProperty());
1658 // If this is the root frame, then set the computed width and
1659 // height equal to the available space
1660 if (nsnull
== parentReflowState
) {
1661 // XXXldb This doesn't mean what it used to!
1662 InitOffsets(aContainingBlockWidth
, aBorder
, aPadding
);
1663 // Override mComputedMargin since reflow roots start from the
1664 // frame's boundary, which is inside the margin.
1665 mComputedMargin
.SizeTo(0, 0, 0, 0);
1666 mComputedOffsets
.SizeTo(0, 0, 0, 0);
1668 mComputedWidth
= availableWidth
- mComputedBorderPadding
.LeftRight();
1669 if (mComputedWidth
< 0)
1671 if (availableHeight
!= NS_UNCONSTRAINEDSIZE
) {
1672 mComputedHeight
= availableHeight
- mComputedBorderPadding
.TopBottom();
1673 if (mComputedHeight
< 0)
1674 mComputedHeight
= 0;
1676 mComputedHeight
= NS_UNCONSTRAINEDSIZE
;
1679 mComputedMinWidth
= mComputedMinHeight
= 0;
1680 mComputedMaxWidth
= mComputedMaxHeight
= NS_UNCONSTRAINEDSIZE
;
1682 // Get the containing block reflow state
1683 const nsHTMLReflowState
* cbrs
= mCBReflowState
;
1684 NS_ASSERTION(nsnull
!= cbrs
, "no containing block");
1686 // If we weren't given a containing block width and height, then
1688 if (aContainingBlockWidth
== -1) {
1689 ComputeContainingBlockRectangle(aPresContext
, cbrs
, aContainingBlockWidth
,
1690 aContainingBlockHeight
);
1693 // See if the containing block height is based on the size of its
1696 if (NS_AUTOHEIGHT
== aContainingBlockHeight
) {
1697 // See if the containing block is a cell frame which needs
1698 // to use the mComputedHeight of the cell instead of what the cell block passed in.
1699 // XXX It seems like this could lead to bugs with min-height and friends
1700 if (cbrs
->parentReflowState
) {
1701 fType
= cbrs
->frame
->GetType();
1702 if (IS_TABLE_CELL(fType
)) {
1703 // use the cell's computed height
1704 aContainingBlockHeight
= cbrs
->mComputedHeight
;
1709 InitOffsets(aContainingBlockWidth
, aBorder
, aPadding
);
1711 nsStyleUnit heightUnit
= mStylePosition
->mHeight
.GetUnit();
1713 // Check for a percentage based height and a containing block height
1714 // that depends on the content height
1715 // XXX twiddling heightUnit doesn't help anymore
1716 if (eStyleUnit_Percent
== heightUnit
) {
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 nsStyleUnit widthUnit
= mStylePosition
->mWidth
.GetUnit();
1776 if ((NS_STYLE_DISPLAY_TABLE_ROW
== mStyleDisplay
->mDisplay
) ||
1777 (NS_STYLE_DISPLAY_TABLE_ROW_GROUP
== mStyleDisplay
->mDisplay
)) {
1778 // 'width' property doesn't apply to table rows and row groups
1779 widthUnit
= eStyleUnit_Auto
;
1780 rowOrRowGroup
= PR_TRUE
;
1783 if (eStyleUnit_Auto
== widthUnit
) {
1784 mComputedWidth
= availableWidth
;
1786 if ((mComputedWidth
!= NS_UNCONSTRAINEDSIZE
) && !rowOrRowGroup
){
1787 // Internal table elements don't have margins. Only tables and
1788 // cells have border and padding
1789 mComputedWidth
-= mComputedBorderPadding
.left
+
1790 mComputedBorderPadding
.right
;
1791 if (mComputedWidth
< 0)
1794 NS_ASSERTION(mComputedWidth
>= 0, "Bogus computed width");
1797 NS_ASSERTION(widthUnit
== mStylePosition
->mWidth
.GetUnit(),
1798 "unexpected width unit change");
1799 mComputedWidth
= ComputeWidthValue(aContainingBlockWidth
,
1800 mStylePosition
->mBoxSizing
,
1801 mStylePosition
->mWidth
);
1804 // Calculate the computed height
1805 if ((NS_STYLE_DISPLAY_TABLE_COLUMN
== mStyleDisplay
->mDisplay
) ||
1806 (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
== mStyleDisplay
->mDisplay
)) {
1807 // 'height' property doesn't apply to table columns and column groups
1808 heightUnit
= eStyleUnit_Auto
;
1810 if (eStyleUnit_Auto
== heightUnit
) {
1811 mComputedHeight
= NS_AUTOHEIGHT
;
1813 NS_ASSERTION(heightUnit
== mStylePosition
->mHeight
.GetUnit(),
1814 "unexpected height unit change");
1815 mComputedHeight
= nsLayoutUtils::
1816 ComputeHeightDependentValue(aContainingBlockHeight
,
1817 mStylePosition
->mHeight
);
1820 // Doesn't apply to table elements
1821 mComputedMinWidth
= mComputedMinHeight
= 0;
1822 mComputedMaxWidth
= mComputedMaxHeight
= NS_UNCONSTRAINEDSIZE
;
1824 } else if (NS_FRAME_GET_TYPE(mFrameType
) == NS_CSS_FRAME_TYPE_ABSOLUTE
) {
1825 // XXX not sure if this belongs here or somewhere else - cwk
1826 InitAbsoluteConstraints(aPresContext
, cbrs
, aContainingBlockWidth
,
1827 aContainingBlockHeight
);
1830 NS_CSS_FRAME_TYPE_BLOCK
== NS_FRAME_GET_TYPE(mFrameType
);
1831 // make sure legend frames with display:block and width:auto still
1833 PRBool shrinkWrap
= !isBlock
|| frame
->GetType() == nsGkAtoms::legendFrame
;
1835 frame
->ComputeSize(rendContext
,
1836 nsSize(aContainingBlockWidth
,
1837 aContainingBlockHeight
),
1839 nsSize(mComputedMargin
.LeftRight(),
1840 mComputedMargin
.TopBottom()),
1841 nsSize(mComputedBorderPadding
.LeftRight() -
1842 mComputedPadding
.LeftRight(),
1843 mComputedBorderPadding
.TopBottom() -
1844 mComputedPadding
.TopBottom()),
1845 nsSize(mComputedPadding
.LeftRight(),
1846 mComputedPadding
.TopBottom()),
1849 mComputedWidth
= size
.width
;
1850 mComputedHeight
= size
.height
;
1851 NS_ASSERTION(mComputedWidth
>= 0, "Bogus width");
1852 NS_ASSERTION(mComputedHeight
== NS_UNCONSTRAINEDSIZE
||
1853 mComputedHeight
>= 0, "Bogus height");
1855 if (isBlock
&& !IsSideCaption(frame
, mStyleDisplay
))
1856 CalculateBlockSideMargins(availableWidth
, mComputedWidth
);
1859 // Check for blinking text and permission to display it
1860 mFlags
.mBlinks
= (parentReflowState
&& parentReflowState
->mFlags
.mBlinks
);
1861 if (!mFlags
.mBlinks
&& BlinkIsAllowed()) {
1862 const nsStyleTextReset
* st
= frame
->GetStyleTextReset();
1864 ((st
->mTextDecoration
& NS_STYLE_TEXT_DECORATION_BLINK
) != 0);
1869 nsCSSOffsetState::InitOffsets(nscoord aContainingBlockWidth
,
1870 const nsMargin
*aBorder
,
1871 const nsMargin
*aPadding
)
1873 DISPLAY_INIT_OFFSETS(frame
, this, aContainingBlockWidth
, aBorder
, aPadding
);
1875 // Compute margins from the specified margin style information. These
1876 // become the default computed values, and may be adjusted below
1877 // XXX fix to provide 0,0 for the top&bottom margins for
1878 // inline-non-replaced elements
1879 ComputeMargin(aContainingBlockWidth
);
1881 const nsStyleDisplay
*disp
= frame
->GetStyleDisplay();
1882 PRBool isThemed
= frame
->IsThemed(disp
);
1883 nsPresContext
*presContext
= frame
->PresContext();
1887 presContext
->GetTheme()->GetWidgetPadding(presContext
->DeviceContext(),
1888 frame
, disp
->mAppearance
,
1890 mComputedPadding
.top
= presContext
->DevPixelsToAppUnits(widget
.top
);
1891 mComputedPadding
.right
= presContext
->DevPixelsToAppUnits(widget
.right
);
1892 mComputedPadding
.bottom
= presContext
->DevPixelsToAppUnits(widget
.bottom
);
1893 mComputedPadding
.left
= presContext
->DevPixelsToAppUnits(widget
.left
);
1895 else if (aPadding
) { // padding is an input arg
1896 mComputedPadding
.top
= aPadding
->top
;
1897 mComputedPadding
.right
= aPadding
->right
;
1898 mComputedPadding
.bottom
= aPadding
->bottom
;
1899 mComputedPadding
.left
= aPadding
->left
;
1902 ComputePadding(aContainingBlockWidth
);
1907 presContext
->GetTheme()->GetWidgetBorder(presContext
->DeviceContext(),
1908 frame
, disp
->mAppearance
,
1910 mComputedBorderPadding
.top
=
1911 presContext
->DevPixelsToAppUnits(widget
.top
);
1912 mComputedBorderPadding
.right
=
1913 presContext
->DevPixelsToAppUnits(widget
.right
);
1914 mComputedBorderPadding
.bottom
=
1915 presContext
->DevPixelsToAppUnits(widget
.bottom
);
1916 mComputedBorderPadding
.left
=
1917 presContext
->DevPixelsToAppUnits(widget
.left
);
1919 else if (aBorder
) { // border is an input arg
1920 mComputedBorderPadding
= *aBorder
;
1923 mComputedBorderPadding
= frame
->GetStyleBorder()->GetActualBorder();
1925 mComputedBorderPadding
+= mComputedPadding
;
1927 nsIAtom
* frameType
= frame
->GetType();
1928 if (frameType
== nsGkAtoms::tableFrame
) {
1929 nsTableFrame
*tableFrame
= static_cast<nsTableFrame
*>(frame
);
1931 if (tableFrame
->IsBorderCollapse()) {
1932 // border-collapsed tables don't use any of their padding, and
1933 // only part of their border. We need to do this here before we
1934 // try to do anything like handling 'auto' widths,
1935 // '-moz-box-sizing', or 'auto' margins.
1936 mComputedPadding
.SizeTo(0,0,0,0);
1937 mComputedBorderPadding
= tableFrame
->GetIncludedOuterBCBorder();
1939 } else if (frameType
== nsGkAtoms::scrollbarFrame
) {
1940 // scrollbars may have had their width or height smashed to zero
1941 // by the associated scrollframe, in which case we must not report
1942 // any padding or border.
1943 nsSize
size(frame
->GetSize());
1944 if (size
.width
== 0 || size
.height
== 0) {
1945 mComputedPadding
.left
= 0;
1946 mComputedPadding
.right
= 0;
1947 mComputedBorderPadding
.left
= 0;
1948 mComputedBorderPadding
.right
= 0;
1949 mComputedPadding
.top
= 0;
1950 mComputedPadding
.bottom
= 0;
1951 mComputedBorderPadding
.top
= 0;
1952 mComputedBorderPadding
.bottom
= 0;
1957 // This code enforces section 10.3.3 of the CSS2 spec for this formula:
1959 // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' +
1960 // 'padding-right' + 'border-right-width' + 'margin-right'
1961 // = width of containing block
1963 // Note: the width unit is not auto when this is called
1965 nsHTMLReflowState::CalculateBlockSideMargins(nscoord aAvailWidth
,
1966 nscoord aComputedWidth
)
1968 NS_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE
!= aComputedWidth
&&
1969 NS_UNCONSTRAINEDSIZE
!= aAvailWidth
,
1970 "have unconstrained width; this should only result from "
1971 "very large sizes, not attempts at intrinsic width "
1974 nscoord sum
= mComputedMargin
.left
+ mComputedBorderPadding
.left
+
1975 aComputedWidth
+ mComputedBorderPadding
.right
+ mComputedMargin
.right
;
1976 if (sum
== aAvailWidth
)
1977 // The sum is already correct
1980 // Determine the left and right margin values. The width value
1981 // remains constant while we do this.
1983 // Calculate how much space is available for margins
1984 nscoord availMarginSpace
= aAvailWidth
- sum
;
1986 // If the available margin space is negative, then don't follow the
1987 // usual overconstraint rules.
1988 if (availMarginSpace
< 0) {
1989 if (mCBReflowState
&&
1990 mCBReflowState
->mStyleVisibility
->mDirection
== NS_STYLE_DIRECTION_RTL
) {
1991 mComputedMargin
.left
+= availMarginSpace
;
1993 mComputedMargin
.right
+= availMarginSpace
;
1998 // The css2 spec clearly defines how block elements should behave
1999 // in section 10.3.3.
2000 PRBool isAutoLeftMargin
=
2001 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetLeftUnit();
2002 PRBool isAutoRightMargin
=
2003 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetRightUnit();
2004 if (!isAutoLeftMargin
&& !isAutoRightMargin
) {
2005 // Neither margin is 'auto' so we're over constrained. Use the
2006 // 'direction' property of the parent to tell which margin to
2008 // First check if there is an HTML alignment that we should honor
2009 const nsHTMLReflowState
* prs
= parentReflowState
;
2010 if (frame
->GetType() == nsGkAtoms::tableFrame
) {
2011 NS_ASSERTION(prs
->frame
->GetType() == nsGkAtoms::tableOuterFrame
,
2012 "table not inside outer table");
2013 // Center the table within the outer table based on the alignment
2014 // of the outer table's parent.
2015 prs
= prs
->parentReflowState
;
2018 (prs
->mStyleText
->mTextAlign
== NS_STYLE_TEXT_ALIGN_MOZ_LEFT
||
2019 prs
->mStyleText
->mTextAlign
== NS_STYLE_TEXT_ALIGN_MOZ_CENTER
||
2020 prs
->mStyleText
->mTextAlign
== NS_STYLE_TEXT_ALIGN_MOZ_RIGHT
)) {
2022 prs
->mStyleText
->mTextAlign
!= NS_STYLE_TEXT_ALIGN_MOZ_LEFT
;
2024 prs
->mStyleText
->mTextAlign
!= NS_STYLE_TEXT_ALIGN_MOZ_RIGHT
;
2026 // Otherwise apply the CSS rules, and ignore one margin by forcing
2027 // it to 'auto', depending on 'direction'.
2028 else if (mCBReflowState
&&
2029 NS_STYLE_DIRECTION_RTL
== mCBReflowState
->mStyleVisibility
->mDirection
) {
2030 isAutoLeftMargin
= PR_TRUE
;
2033 isAutoRightMargin
= PR_TRUE
;
2037 // Logic which is common to blocks and tables
2038 // The computed margins need not be zero because the 'auto' could come from
2039 // overconstraint or from HTML alignment so values need to be accumulated
2041 if (isAutoLeftMargin
) {
2042 if (isAutoRightMargin
) {
2043 // Both margins are 'auto' so the computed addition should be equal
2044 nscoord forLeft
= availMarginSpace
/ 2;
2045 mComputedMargin
.left
+= forLeft
;
2046 mComputedMargin
.right
+= availMarginSpace
- forLeft
;
2048 mComputedMargin
.left
+= availMarginSpace
;
2050 } else if (isAutoRightMargin
) {
2051 mComputedMargin
.right
+= availMarginSpace
;
2055 #define NORMAL_LINE_HEIGHT_FACTOR 1.2f // in term of emHeight
2056 // For "normal" we use the font's normal line height (em height + leading).
2057 // If both internal leading and external leading specified by font itself
2058 // are zeros, we should compensate this by creating extra (external) leading
2059 // in eCompensateLeading mode. This is necessary because without this
2060 // compensation, normal line height might looks too tight.
2062 // For risk management, we use preference to control the behavior, and
2063 // eNoExternalLeading is the old behavior.
2065 GetNormalLineHeight(nsIFontMetrics
* aFontMetrics
)
2067 NS_PRECONDITION(nsnull
!= aFontMetrics
, "no font metrics");
2069 nscoord normalLineHeight
;
2071 nscoord externalLeading
, internalLeading
, emHeight
;
2072 aFontMetrics
->GetExternalLeading(externalLeading
);
2073 aFontMetrics
->GetInternalLeading(internalLeading
);
2074 aFontMetrics
->GetEmHeight(emHeight
);
2075 switch (GetNormalLineHeightCalcControl()) {
2076 case eIncludeExternalLeading
:
2077 normalLineHeight
= emHeight
+ internalLeading
+ externalLeading
;
2079 case eCompensateLeading
:
2080 if (!internalLeading
&& !externalLeading
)
2081 normalLineHeight
= NSToCoordRound(emHeight
* NORMAL_LINE_HEIGHT_FACTOR
);
2083 normalLineHeight
= emHeight
+ internalLeading
+ externalLeading
;
2086 //case eNoExternalLeading:
2087 normalLineHeight
= emHeight
+ internalLeading
;
2089 return normalLineHeight
;
2093 ComputeLineHeight(nsStyleContext
* aStyleContext
,
2094 nscoord aBlockHeight
)
2096 const nsStyleCoord
& lhCoord
= aStyleContext
->GetStyleText()->mLineHeight
;
2098 if (lhCoord
.GetUnit() == eStyleUnit_Coord
)
2099 return lhCoord
.GetCoordValue();
2101 if (lhCoord
.GetUnit() == eStyleUnit_Factor
)
2102 // For factor units the computed value of the line-height property
2103 // is found by multiplying the factor by the font's computed size
2104 // (adjusted for min-size prefs and text zoom).
2105 return NSToCoordRound(lhCoord
.GetFactorValue() *
2106 aStyleContext
->GetStyleFont()->mFont
.size
);
2108 NS_ASSERTION(lhCoord
.GetUnit() == eStyleUnit_Normal
||
2109 lhCoord
.GetUnit() == eStyleUnit_Enumerated
,
2110 "bad line-height unit");
2112 if (lhCoord
.GetUnit() == eStyleUnit_Enumerated
) {
2113 NS_ASSERTION(lhCoord
.GetIntValue() == NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT
,
2114 "bad line-height value");
2115 if (aBlockHeight
!= NS_AUTOHEIGHT
)
2116 return aBlockHeight
;
2119 nsCOMPtr
<nsIFontMetrics
> fm
;
2120 nsLayoutUtils::GetFontMetricsForStyleContext(aStyleContext
,
2121 getter_AddRefs(fm
));
2122 return GetNormalLineHeight(fm
);
2126 nsHTMLReflowState::CalcLineHeight() const
2128 nscoord blockHeight
=
2129 frame
->IsContainingBlock() ? mComputedHeight
:
2130 (mCBReflowState
? mCBReflowState
->mComputedHeight
: NS_AUTOHEIGHT
);
2132 return CalcLineHeight(frame
->GetStyleContext(), blockHeight
);
2135 /* static */ nscoord
2136 nsHTMLReflowState::CalcLineHeight(nsStyleContext
* aStyleContext
,
2137 nscoord aBlockHeight
)
2139 NS_PRECONDITION(aStyleContext
, "Must have a style context");
2141 nscoord lineHeight
= ComputeLineHeight(aStyleContext
, aBlockHeight
);
2143 NS_ASSERTION(lineHeight
>= 0, "ComputeLineHeight screwed up");
2149 nsCSSOffsetState::ComputeMargin(nscoord aContainingBlockWidth
)
2151 // If style style can provide us the margin directly, then use it.
2152 const nsStyleMargin
*styleMargin
= frame
->GetStyleMargin();
2153 if (!styleMargin
->GetMargin(mComputedMargin
)) {
2154 // We have to compute the value
2155 if (NS_UNCONSTRAINEDSIZE
== aContainingBlockWidth
) {
2156 mComputedMargin
.left
= 0;
2157 mComputedMargin
.right
= 0;
2159 if (eStyleUnit_Coord
== styleMargin
->mMargin
.GetLeftUnit()) {
2160 mComputedMargin
.left
= styleMargin
->mMargin
.GetLeft().GetCoordValue();
2162 if (eStyleUnit_Coord
== styleMargin
->mMargin
.GetRightUnit()) {
2163 mComputedMargin
.right
= styleMargin
->mMargin
.GetRight().GetCoordValue();
2167 mComputedMargin
.left
= nsLayoutUtils::
2168 ComputeWidthDependentValue(aContainingBlockWidth
,
2169 styleMargin
->mMargin
.GetLeft());
2170 mComputedMargin
.right
= nsLayoutUtils::
2171 ComputeWidthDependentValue(aContainingBlockWidth
,
2172 styleMargin
->mMargin
.GetRight());
2175 // According to the CSS2 spec, margin percentages are
2176 // calculated with respect to the *width* of the containing
2177 // block, even for margin-top and margin-bottom.
2178 // XXX This isn't true for page boxes, if we implement them.
2179 mComputedMargin
.top
= nsLayoutUtils::
2180 ComputeWidthDependentValue(aContainingBlockWidth
,
2181 styleMargin
->mMargin
.GetTop());
2182 mComputedMargin
.bottom
= nsLayoutUtils::
2183 ComputeWidthDependentValue(aContainingBlockWidth
,
2184 styleMargin
->mMargin
.GetBottom());
2186 // XXX We need to include 'auto' horizontal margins in this too!
2187 // ... but if we did that, we'd need to fix nsFrame::GetUsedMargin
2188 // to use it even when the margins are all zero (since sometimes
2189 // they get treated as auto)
2190 frame
->Properties().Set(nsIFrame::UsedMarginProperty(),
2191 new nsMargin(mComputedMargin
));
2196 nsCSSOffsetState::ComputePadding(nscoord aContainingBlockWidth
)
2198 // If style can provide us the padding directly, then use it.
2199 const nsStylePadding
*stylePadding
= frame
->GetStylePadding();
2200 if (!stylePadding
->GetPadding(mComputedPadding
)) {
2201 // We have to compute the value
2202 mComputedPadding
.left
= nsLayoutUtils::
2203 ComputeWidthDependentValue(aContainingBlockWidth
,
2204 stylePadding
->mPadding
.GetLeft());
2205 mComputedPadding
.right
= nsLayoutUtils::
2206 ComputeWidthDependentValue(aContainingBlockWidth
,
2207 stylePadding
->mPadding
.GetRight());
2209 // According to the CSS2 spec, percentages are calculated with respect to
2210 // containing block width for padding-top and padding-bottom
2211 mComputedPadding
.top
= nsLayoutUtils::
2212 ComputeWidthDependentValue(aContainingBlockWidth
,
2213 stylePadding
->mPadding
.GetTop());
2214 mComputedPadding
.bottom
= nsLayoutUtils::
2215 ComputeWidthDependentValue(aContainingBlockWidth
,
2216 stylePadding
->mPadding
.GetBottom());
2218 frame
->Properties().Set(nsIFrame::UsedPaddingProperty(),
2219 new nsMargin(mComputedPadding
));
2221 // a table row/col group, row/col doesn't have padding
2222 // XXXldb Neither do border-collapse tables.
2223 nsIAtom
* frameType
= frame
->GetType();
2224 if (nsGkAtoms::tableRowGroupFrame
== frameType
||
2225 nsGkAtoms::tableColGroupFrame
== frameType
||
2226 nsGkAtoms::tableRowFrame
== frameType
||
2227 nsGkAtoms::tableColFrame
== frameType
) {
2228 mComputedPadding
.top
= 0;
2229 mComputedPadding
.right
= 0;
2230 mComputedPadding
.bottom
= 0;
2231 mComputedPadding
.left
= 0;
2236 nsHTMLReflowState::ApplyMinMaxConstraints(nscoord
* aFrameWidth
,
2237 nscoord
* aFrameHeight
) const
2240 if (NS_UNCONSTRAINEDSIZE
!= mComputedMaxWidth
) {
2241 *aFrameWidth
= NS_MIN(*aFrameWidth
, mComputedMaxWidth
);
2243 *aFrameWidth
= NS_MAX(*aFrameWidth
, mComputedMinWidth
);
2247 if (NS_UNCONSTRAINEDSIZE
!= mComputedMaxHeight
) {
2248 *aFrameHeight
= NS_MIN(*aFrameHeight
, mComputedMaxHeight
);
2250 *aFrameHeight
= NS_MAX(*aFrameHeight
, mComputedMinHeight
);
2255 nsHTMLReflowState::ComputeMinMaxValues(nscoord aContainingBlockWidth
,
2256 nscoord aContainingBlockHeight
,
2257 const nsHTMLReflowState
* aContainingBlockRS
)
2259 mComputedMinWidth
= ComputeWidthValue(aContainingBlockWidth
,
2260 mStylePosition
->mBoxSizing
,
2261 mStylePosition
->mMinWidth
);
2263 if (eStyleUnit_None
== mStylePosition
->mMaxWidth
.GetUnit()) {
2264 // Specified value of 'none'
2265 mComputedMaxWidth
= NS_UNCONSTRAINEDSIZE
; // no limit
2267 mComputedMaxWidth
= ComputeWidthValue(aContainingBlockWidth
,
2268 mStylePosition
->mBoxSizing
,
2269 mStylePosition
->mMaxWidth
);
2272 // If the computed value of 'min-width' is greater than the value of
2273 // 'max-width', 'max-width' is set to the value of 'min-width'
2274 if (mComputedMinWidth
> mComputedMaxWidth
) {
2275 mComputedMaxWidth
= mComputedMinWidth
;
2278 // Check for percentage based values and a containing block height that
2279 // depends on the content height. Treat them like 'auto'
2280 if ((NS_AUTOHEIGHT
== aContainingBlockHeight
) &&
2281 (eStyleUnit_Percent
== mStylePosition
->mMinHeight
.GetUnit())) {
2282 mComputedMinHeight
= 0;
2284 mComputedMinHeight
= nsLayoutUtils::
2285 ComputeHeightDependentValue(aContainingBlockHeight
,
2286 mStylePosition
->mMinHeight
);
2288 nsStyleUnit maxHeightUnit
= mStylePosition
->mMaxHeight
.GetUnit();
2289 if (eStyleUnit_None
== maxHeightUnit
) {
2290 // Specified value of 'none'
2291 mComputedMaxHeight
= NS_UNCONSTRAINEDSIZE
; // no limit
2293 // Check for percentage based values and a containing block height that
2294 // depends on the content height. Treat them like 'auto'
2295 if ((NS_AUTOHEIGHT
== aContainingBlockHeight
) &&
2296 (eStyleUnit_Percent
== maxHeightUnit
)) {
2297 mComputedMaxHeight
= NS_UNCONSTRAINEDSIZE
;
2299 mComputedMaxHeight
= nsLayoutUtils::
2300 ComputeHeightDependentValue(aContainingBlockHeight
,
2301 mStylePosition
->mMaxHeight
);
2305 // If the computed value of 'min-height' is greater than the value of
2306 // 'max-height', 'max-height' is set to the value of 'min-height'
2307 if (mComputedMinHeight
> mComputedMaxHeight
) {
2308 mComputedMaxHeight
= mComputedMinHeight
;
2313 nsHTMLReflowState::SetTruncated(const nsHTMLReflowMetrics
& aMetrics
,
2314 nsReflowStatus
* aStatus
) const
2316 if (availableHeight
!= NS_UNCONSTRAINEDSIZE
&&
2317 availableHeight
< aMetrics
.height
&&
2318 !mFlags
.mIsTopOfPage
) {
2319 *aStatus
|= NS_FRAME_TRUNCATED
;
2321 *aStatus
&= ~NS_FRAME_TRUNCATED
;