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 // Prefs-driven control for |text-decoration: blink|
71 static PRPackedBool sPrefIsLoaded
= PR_FALSE
;
72 static PRPackedBool sBlinkIsAllowed
= PR_TRUE
;
74 enum eNormalLineHeightControl
{
76 eNoExternalLeading
= 0, // does not include external leading
77 eIncludeExternalLeading
, // use whatever value font vendor provides
78 eCompensateLeading
// compensate leading if leading provided by font vendor is not enough
81 static eNormalLineHeightControl sNormalLineHeightControl
= eUninitialized
;
83 // Initialize a <b>root</b> reflow state with a rendering context to
84 // use for measuring things.
85 nsHTMLReflowState::nsHTMLReflowState(nsPresContext
* aPresContext
,
87 nsIRenderingContext
* aRenderingContext
,
88 const nsSize
& aAvailableSpace
)
89 : nsCSSOffsetState(aFrame
, aRenderingContext
)
93 NS_PRECONDITION(aPresContext
, "no pres context");
94 NS_PRECONDITION(aRenderingContext
, "no rendering context");
95 NS_PRECONDITION(aFrame
, "no frame");
96 parentReflowState
= nsnull
;
97 availableWidth
= aAvailableSpace
.width
;
98 availableHeight
= aAvailableSpace
.height
;
99 mFloatManager
= nsnull
;
100 mLineLayout
= nsnull
;
101 mFlags
.mSpecialHeightReflow
= PR_FALSE
;
102 mFlags
.mIsTopOfPage
= PR_FALSE
;
103 mFlags
.mTableIsSplittable
= PR_FALSE
;
104 mFlags
.mNextInFlowUntouched
= PR_FALSE
;
105 mFlags
.mAssumingHScrollbar
= mFlags
.mAssumingVScrollbar
= PR_FALSE
;
106 mFlags
.mHasClearance
= PR_FALSE
;
107 mFlags
.mHeightDependsOnAncestorCell
= PR_FALSE
;
108 mDiscoveredClearance
= nsnull
;
109 mPercentHeightObserver
= nsnull
;
113 static PRBool
CheckNextInFlowParenthood(nsIFrame
* aFrame
, nsIFrame
* aParent
)
115 nsIFrame
* frameNext
= aFrame
->GetNextInFlow();
116 nsIFrame
* parentNext
= aParent
->GetNextInFlow();
117 return frameNext
&& parentNext
&& frameNext
->GetParent() == parentNext
;
120 // Initialize a reflow state for a child frames reflow. Some state
121 // is copied from the parent reflow state; the remaining state is
123 nsHTMLReflowState::nsHTMLReflowState(nsPresContext
* aPresContext
,
124 const nsHTMLReflowState
& aParentReflowState
,
126 const nsSize
& aAvailableSpace
,
127 nscoord aContainingBlockWidth
,
128 nscoord aContainingBlockHeight
,
130 : nsCSSOffsetState(aFrame
, aParentReflowState
.rendContext
)
132 , mReflowDepth(aParentReflowState
.mReflowDepth
+ 1)
133 , mFlags(aParentReflowState
.mFlags
)
135 NS_PRECONDITION(aPresContext
, "no pres context");
136 NS_PRECONDITION(aFrame
, "no frame");
137 NS_PRECONDITION((aContainingBlockWidth
== -1) ==
138 (aContainingBlockHeight
== -1),
139 "cb width and height should only be non-default together");
140 NS_PRECONDITION(aInit
== PR_TRUE
|| aInit
== PR_FALSE
,
141 "aInit out of range for PRBool");
142 NS_PRECONDITION(!mFlags
.mSpecialHeightReflow
||
143 !NS_SUBTREE_DIRTY(aFrame
),
144 "frame should be clean when getting special height reflow");
146 parentReflowState
= &aParentReflowState
;
148 // If the parent is dirty, then the child is as well.
149 // XXX Are the other cases where the parent reflows a child a second
150 // time, as a resize?
151 if (!mFlags
.mSpecialHeightReflow
)
152 frame
->AddStateBits(parentReflowState
->frame
->GetStateBits() &
155 availableWidth
= aAvailableSpace
.width
;
156 availableHeight
= aAvailableSpace
.height
;
158 mFloatManager
= aParentReflowState
.mFloatManager
;
159 if (frame
->IsFrameOfType(nsIFrame::eLineParticipant
))
160 mLineLayout
= aParentReflowState
.mLineLayout
;
162 mLineLayout
= nsnull
;
163 mFlags
.mIsTopOfPage
= aParentReflowState
.mFlags
.mIsTopOfPage
;
164 mFlags
.mNextInFlowUntouched
= aParentReflowState
.mFlags
.mNextInFlowUntouched
&&
165 CheckNextInFlowParenthood(aFrame
, aParentReflowState
.frame
);
166 mFlags
.mAssumingHScrollbar
= mFlags
.mAssumingVScrollbar
= PR_FALSE
;
167 mFlags
.mHasClearance
= PR_FALSE
;
168 mDiscoveredClearance
= nsnull
;
169 mPercentHeightObserver
= (aParentReflowState
.mPercentHeightObserver
&&
170 aParentReflowState
.mPercentHeightObserver
->NeedsToObserve(*this))
171 ? aParentReflowState
.mPercentHeightObserver
: nsnull
;
174 Init(aPresContext
, aContainingBlockWidth
, aContainingBlockHeight
);
179 nsCSSOffsetState::ComputeWidthValue(nscoord aContainingBlockWidth
,
180 nscoord aContentEdgeToBoxSizing
,
181 nscoord aBoxSizingToMarginEdge
,
182 const nsStyleCoord
& aCoord
)
184 return nsLayoutUtils::ComputeWidthValue(rendContext
, frame
,
185 aContainingBlockWidth
,
186 aContentEdgeToBoxSizing
,
187 aBoxSizingToMarginEdge
,
192 nsCSSOffsetState::ComputeWidthValue(nscoord aContainingBlockWidth
,
194 const nsStyleCoord
& aCoord
)
196 nscoord inside
= 0, outside
= mComputedBorderPadding
.LeftRight() +
197 mComputedMargin
.LeftRight();
198 switch (aBoxSizing
) {
199 case NS_STYLE_BOX_SIZING_BORDER
:
200 inside
= mComputedBorderPadding
.LeftRight();
202 case NS_STYLE_BOX_SIZING_PADDING
:
203 inside
= mComputedPadding
.LeftRight();
208 return ComputeWidthValue(aContainingBlockWidth
, inside
,
213 nsHTMLReflowState::SetComputedWidth(nscoord aComputedWidth
)
215 NS_ASSERTION(frame
, "Must have a frame!");
216 // It'd be nice to assert that |frame| is not in reflow, but this fails for
219 // 1) Viewport frames reset the computed width on a copy of their reflow
220 // state when reflowing fixed-pos kids. In that case we actually don't
221 // want to mess with the resize flags, because comparing the frame's rect
222 // to the munged computed width is pointless.
223 // 2) nsFrame::BoxReflow creates a reflow state for its parent. This reflow
224 // state is not used to reflow the parent, but just as a parent for the
225 // frame's own reflow state. So given a nsBoxFrame inside some non-XUL
226 // (like a text control, for example), we'll end up creating a reflow
227 // state for the parent while the parent is reflowing.
229 NS_PRECONDITION(aComputedWidth
>= 0, "Invalid computed width");
230 if (mComputedWidth
!= aComputedWidth
) {
231 mComputedWidth
= aComputedWidth
;
232 if (frame
->GetType() != nsGkAtoms::viewportFrame
) { // Or check GetParent()?
233 InitResizeFlags(frame
->PresContext());
239 nsHTMLReflowState::SetComputedHeight(nscoord aComputedHeight
)
241 NS_ASSERTION(frame
, "Must have a frame!");
242 // It'd be nice to assert that |frame| is not in reflow, but this fails
245 // nsFrame::BoxReflow creates a reflow state for its parent. This reflow
246 // state is not used to reflow the parent, but just as a parent for the
247 // frame's own reflow state. So given a nsBoxFrame inside some non-XUL
248 // (like a text control, for example), we'll end up creating a reflow
249 // state for the parent while the parent is reflowing.
251 NS_PRECONDITION(aComputedHeight
>= 0, "Invalid computed height");
252 if (mComputedHeight
!= aComputedHeight
) {
253 mComputedHeight
= aComputedHeight
;
254 InitResizeFlags(frame
->PresContext());
259 nsHTMLReflowState::Init(nsPresContext
* aPresContext
,
260 nscoord aContainingBlockWidth
,
261 nscoord aContainingBlockHeight
,
262 const nsMargin
* aBorder
,
263 const nsMargin
* aPadding
)
265 NS_ASSERTION(availableWidth
!= NS_UNCONSTRAINEDSIZE
,
266 "shouldn't use unconstrained widths anymore");
268 mStylePosition
= frame
->GetStylePosition();
269 mStyleDisplay
= frame
->GetStyleDisplay();
270 mStyleVisibility
= frame
->GetStyleVisibility();
271 mStyleBorder
= frame
->GetStyleBorder();
272 mStyleMargin
= frame
->GetStyleMargin();
273 mStylePadding
= frame
->GetStylePadding();
274 mStyleText
= frame
->GetStyleText();
279 InitConstraints(aPresContext
, aContainingBlockWidth
, aContainingBlockHeight
, aBorder
, aPadding
);
281 InitResizeFlags(aPresContext
);
283 NS_ASSERTION((mFrameType
== NS_CSS_FRAME_TYPE_INLINE
&&
284 !frame
->IsFrameOfType(nsIFrame::eReplaced
)) ||
285 frame
->GetType() == nsGkAtoms::textFrame
||
286 mComputedWidth
!= NS_UNCONSTRAINEDSIZE
,
287 "shouldn't use unconstrained widths anymore");
290 void nsHTMLReflowState::InitCBReflowState()
292 if (!parentReflowState
) {
293 mCBReflowState
= nsnull
;
297 // If outer tables ever become containing blocks, we need to make sure to use
298 // their mCBReflowState in the non-absolutely-positioned case for inner
300 NS_ASSERTION(frame
->GetType() != nsGkAtoms::tableFrame
||
301 !frame
->GetParent()->IsContainingBlock(),
302 "Outer table should not be containing block");
304 if (parentReflowState
->frame
->IsContainingBlock() ||
305 // Absolutely positioned frames should always be kids of the frames that
306 // determine their containing block
307 (NS_FRAME_GET_TYPE(mFrameType
) == NS_CSS_FRAME_TYPE_ABSOLUTE
)) {
308 // a block inside a table cell needs to use the table cell, and an
309 // absolutely positioned inner table needs to use the parent of the outer
311 if (parentReflowState
->parentReflowState
&&
312 (IS_TABLE_CELL(parentReflowState
->parentReflowState
->frame
->GetType()) ||
313 frame
->GetType() == nsGkAtoms::tableFrame
)) {
314 mCBReflowState
= parentReflowState
->parentReflowState
;
316 mCBReflowState
= parentReflowState
;
322 mCBReflowState
= parentReflowState
->mCBReflowState
;
325 /* Check whether CalcQuirkContainingBlockHeight would stop on the
326 * given reflow state, using its block as a height. (essentially
327 * returns false for any case in which CalcQuirkContainingBlockHeight
328 * has a "continue" in its main loop.)
330 * XXX Maybe refactor CalcQuirkContainingBlockHeight so it uses
331 * this function as well
334 IsQuirkContainingBlockHeight(const nsHTMLReflowState
* rs
)
336 nsIAtom
* frameType
= rs
->frame
->GetType();
337 if (nsGkAtoms::blockFrame
== frameType
||
339 nsGkAtoms::XULLabelFrame
== frameType
||
341 nsGkAtoms::scrollFrame
== frameType
) {
342 // Note: This next condition could change due to a style change,
343 // but that would cause a style reflow anyway, which means we're ok.
344 if (NS_AUTOHEIGHT
== rs
->ComputedHeight()) {
345 if (!rs
->frame
->GetStyleDisplay()->IsAbsolutelyPositioned()) {
355 nsHTMLReflowState::InitResizeFlags(nsPresContext
* aPresContext
)
357 mFlags
.mHResize
= !(frame
->GetStateBits() & NS_FRAME_IS_DIRTY
) &&
358 frame
->GetSize().width
!=
359 mComputedWidth
+ mComputedBorderPadding
.LeftRight();
361 // XXX Should we really need to null check mCBReflowState? (We do for
362 // at least nsBoxFrame).
363 if (IS_TABLE_CELL(frame
->GetType()) &&
364 (mFlags
.mSpecialHeightReflow
||
365 (frame
->GetFirstInFlow()->GetStateBits() &
366 NS_TABLE_CELL_HAD_SPECIAL_REFLOW
)) &&
367 (frame
->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT
)) {
368 // Need to set the bit on the cell so that
369 // mCBReflowState->mFlags.mVResize is set correctly below when
370 // reflowing descendant.
371 mFlags
.mVResize
= PR_TRUE
;
372 } else if (mCBReflowState
&& !frame
->IsContainingBlock()) {
373 // XXX Is this problematic for relatively positioned inlines acting
374 // as containing block for absolutely positioned elements?
375 mFlags
.mVResize
= mCBReflowState
->mFlags
.mVResize
;
376 } else if (mComputedHeight
== NS_AUTOHEIGHT
) {
377 if (eCompatibility_NavQuirks
== aPresContext
->CompatibilityMode() &&
379 mFlags
.mVResize
= mCBReflowState
->mFlags
.mVResize
;
381 mFlags
.mVResize
= mFlags
.mHResize
|| NS_SUBTREE_DIRTY(frame
);
385 mFlags
.mVResize
= frame
->GetSize().height
!=
386 mComputedHeight
+ mComputedBorderPadding
.TopBottom();
389 PRBool dependsOnCBHeight
=
390 mStylePosition
->mHeight
.GetUnit() == eStyleUnit_Percent
||
391 mStylePosition
->mMinHeight
.GetUnit() == eStyleUnit_Percent
||
392 mStylePosition
->mMaxHeight
.GetUnit() == eStyleUnit_Percent
||
393 mStylePosition
->mOffset
.GetTopUnit() == eStyleUnit_Percent
||
394 mStylePosition
->mOffset
.GetBottomUnit() != eStyleUnit_Auto
||
395 frame
->IsBoxFrame() ||
396 (mStylePosition
->mHeight
.GetUnit() == eStyleUnit_Auto
&&
397 frame
->GetIntrinsicSize().height
.GetUnit() == eStyleUnit_Percent
);
399 if (mStyleText
->mLineHeight
.GetUnit() == eStyleUnit_Enumerated
) {
400 NS_ASSERTION(mStyleText
->mLineHeight
.GetIntValue() ==
401 NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT
,
402 "bad line-height value");
404 // line-height depends on block height
405 frame
->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT
);
406 // but only on containing blocks if this frame is not a suitable block
407 dependsOnCBHeight
|= !frame
->IsContainingBlock();
410 // If we're the descendant of a table cell that performs special height
411 // reflows and we could be the child that requires them, always set
412 // the vertical resize in case this is the first pass before the
413 // special height reflow. However, don't do this if it actually is
414 // the special height reflow, since in that case it will already be
415 // set correctly above if we need it set.
416 if (!mFlags
.mVResize
&& mCBReflowState
&&
417 (IS_TABLE_CELL(mCBReflowState
->frame
->GetType()) ||
418 mCBReflowState
->mFlags
.mHeightDependsOnAncestorCell
) &&
419 !mCBReflowState
->mFlags
.mSpecialHeightReflow
&&
421 mFlags
.mVResize
= PR_TRUE
;
422 mFlags
.mHeightDependsOnAncestorCell
= PR_TRUE
;
425 // Set NS_FRAME_CONTAINS_RELATIVE_HEIGHT if it's needed.
427 // It would be nice to check that |mComputedHeight != NS_AUTOHEIGHT|
428 // &&ed with the percentage height check. However, this doesn't get
429 // along with table special height reflows, since a special height
430 // reflow (a quirk that makes such percentage heights work on children
431 // of table cells) can cause not just a single percentage height to
432 // become fixed, but an entire descendant chain of percentage heights
434 if (dependsOnCBHeight
&& mCBReflowState
) {
435 const nsHTMLReflowState
*rs
= this;
436 PRBool hitCBReflowState
= PR_FALSE
;
438 rs
= rs
->parentReflowState
;
443 if (rs
->frame
->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT
)
444 break; // no need to go further
445 rs
->frame
->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT
);
447 // Keep track of whether we've hit the containing block, because
448 // we need to go at least that far.
449 if (rs
== mCBReflowState
) {
450 hitCBReflowState
= PR_TRUE
;
453 } while (!hitCBReflowState
||
454 (eCompatibility_NavQuirks
== aPresContext
->CompatibilityMode() &&
455 !IsQuirkContainingBlockHeight(rs
)));
456 // Note: We actually don't need to set the
457 // NS_FRAME_CONTAINS_RELATIVE_HEIGHT bit for the cases
458 // where we hit the early break statements in
459 // CalcQuirkContainingBlockHeight. But it doesn't hurt
460 // us to set the bit in these cases.
463 if (frame
->GetStateBits() & NS_FRAME_IS_DIRTY
) {
464 // If we're reflowing everything, then we'll find out if we need
466 frame
->RemoveStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT
);
472 nsHTMLReflowState::GetContainingBlockContentWidth(const nsHTMLReflowState
* aReflowState
)
474 const nsHTMLReflowState
* rs
= aReflowState
->mCBReflowState
;
477 return rs
->mComputedWidth
;
482 nsHTMLReflowState::GetContainingBlockFor(const nsIFrame
* aFrame
)
484 NS_PRECONDITION(aFrame
, "Must have frame to work with");
485 nsIFrame
* container
= aFrame
->GetParent();
486 if (aFrame
->GetStyleDisplay()->IsAbsolutelyPositioned()) {
487 // Absolutely positioned frames are just kids of their containing
488 // blocks (which may happen to be inlines).
491 while (container
&& !container
->IsContainingBlock()) {
492 container
= container
->GetParent();
498 nsHTMLReflowState::InitFrameType()
500 const nsStyleDisplay
*disp
= mStyleDisplay
;
501 nsCSSFrameType frameType
;
503 // Section 9.7 of the CSS2 spec indicates that absolute position
504 // takes precedence over float which takes precedence over display.
505 // XXXldb nsRuleNode::ComputeDisplayData should take care of this, right?
506 // Make sure the frame was actually moved out of the flow, and don't
508 // just assume what the style says, because we might not have had a
509 // useful float/absolute containing block
510 nsIFrame
* frameToTest
=
511 frame
->GetType() == nsGkAtoms::tableFrame
? frame
->GetParent() : frame
;
512 NS_ASSERTION(frameToTest
->GetStyleDisplay()->IsAbsolutelyPositioned() ==
513 disp
->IsAbsolutelyPositioned(),
514 "Unexpected position style");
515 NS_ASSERTION(frameToTest
->GetStyleDisplay()->IsFloating() ==
516 disp
->IsFloating(), "Unexpected float style");
517 if (frameToTest
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
) {
518 if (disp
->IsAbsolutelyPositioned()) {
519 frameType
= NS_CSS_FRAME_TYPE_ABSOLUTE
;
520 //XXXfr hack for making frames behave properly when in overflow container lists
521 // see bug 154892; need to revisit later
522 if (frameToTest
->GetPrevInFlow())
523 frameType
= NS_CSS_FRAME_TYPE_BLOCK
;
525 else if (disp
->IsFloating()) {
526 frameType
= NS_CSS_FRAME_TYPE_FLOATING
;
528 NS_ASSERTION(disp
->mDisplay
== NS_STYLE_DISPLAY_POPUP
,
529 "unknown out of flow frame type");
530 frameType
= NS_CSS_FRAME_TYPE_UNKNOWN
;
534 switch (disp
->mDisplay
) {
535 case NS_STYLE_DISPLAY_BLOCK
:
536 case NS_STYLE_DISPLAY_LIST_ITEM
:
537 case NS_STYLE_DISPLAY_TABLE
:
538 case NS_STYLE_DISPLAY_TABLE_CAPTION
:
539 frameType
= NS_CSS_FRAME_TYPE_BLOCK
;
542 case NS_STYLE_DISPLAY_INLINE
:
543 case NS_STYLE_DISPLAY_INLINE_BLOCK
:
544 case NS_STYLE_DISPLAY_MARKER
:
545 case NS_STYLE_DISPLAY_INLINE_TABLE
:
546 case NS_STYLE_DISPLAY_INLINE_BOX
:
547 case NS_STYLE_DISPLAY_INLINE_GRID
:
548 case NS_STYLE_DISPLAY_INLINE_STACK
:
549 frameType
= NS_CSS_FRAME_TYPE_INLINE
;
552 case NS_STYLE_DISPLAY_RUN_IN
:
553 case NS_STYLE_DISPLAY_COMPACT
:
554 // XXX need to look ahead at the frame's sibling
555 frameType
= NS_CSS_FRAME_TYPE_BLOCK
;
558 case NS_STYLE_DISPLAY_TABLE_CELL
:
559 case NS_STYLE_DISPLAY_TABLE_ROW_GROUP
:
560 case NS_STYLE_DISPLAY_TABLE_COLUMN
:
561 case NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
:
562 case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP
:
563 case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP
:
564 case NS_STYLE_DISPLAY_TABLE_ROW
:
565 frameType
= NS_CSS_FRAME_TYPE_INTERNAL_TABLE
;
568 case NS_STYLE_DISPLAY_NONE
:
570 frameType
= NS_CSS_FRAME_TYPE_UNKNOWN
;
575 // See if the frame is replaced
576 if (frame
->IsFrameOfType(nsIFrame::eReplacedContainsBlock
)) {
577 frameType
= NS_FRAME_REPLACED_CONTAINS_BLOCK(frameType
);
578 } else if (frame
->IsFrameOfType(nsIFrame::eReplaced
)) {
579 frameType
= NS_FRAME_REPLACED(frameType
);
582 mFrameType
= frameType
;
586 nsPointDtor(void *aFrame
, nsIAtom
*aPropertyName
,
587 void *aPropertyValue
, void *aDtorData
)
589 nsPoint
*point
= static_cast<nsPoint
*>(aPropertyValue
);
594 nsHTMLReflowState::ComputeRelativeOffsets(const nsHTMLReflowState
* cbrs
,
595 nscoord aContainingBlockWidth
,
596 nscoord aContainingBlockHeight
,
597 nsPresContext
* aPresContext
)
599 // Compute the 'left' and 'right' values. 'Left' moves the boxes to the right,
600 // and 'right' moves the boxes to the left. The computed values are always:
602 PRBool leftIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetLeftUnit();
603 PRBool rightIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetRightUnit();
605 // Check for percentage based values and an unconstrained containing
606 // block width. Treat them like 'auto'
607 if (NS_UNCONSTRAINEDSIZE
== aContainingBlockWidth
) {
608 if (eStyleUnit_Percent
== mStylePosition
->mOffset
.GetLeftUnit()) {
609 leftIsAuto
= PR_TRUE
;
611 if (eStyleUnit_Percent
== mStylePosition
->mOffset
.GetRightUnit()) {
612 rightIsAuto
= PR_TRUE
;
616 // If neither 'left' not 'right' are auto, then we're over-constrained and
617 // we ignore one of them
618 if (!leftIsAuto
&& !rightIsAuto
) {
619 if (mCBReflowState
&&
620 NS_STYLE_DIRECTION_RTL
== mCBReflowState
->mStyleVisibility
->mDirection
) {
621 leftIsAuto
= PR_TRUE
;
623 rightIsAuto
= PR_TRUE
;
629 // If both are 'auto' (their initial values), the computed values are 0
630 mComputedOffsets
.left
= mComputedOffsets
.right
= 0;
632 // 'Right' isn't 'auto' so compute its value
633 mComputedOffsets
.right
= nsLayoutUtils::
634 ComputeWidthDependentValue(aContainingBlockWidth
,
635 mStylePosition
->mOffset
.GetRight());
637 // Computed value for 'left' is minus the value of 'right'
638 mComputedOffsets
.left
= -mComputedOffsets
.right
;
642 NS_ASSERTION(rightIsAuto
, "unexpected specified constraint");
644 // 'Left' isn't 'auto' so compute its value
645 mComputedOffsets
.left
= nsLayoutUtils::
646 ComputeWidthDependentValue(aContainingBlockWidth
,
647 mStylePosition
->mOffset
.GetLeft());
649 // Computed value for 'right' is minus the value of 'left'
650 mComputedOffsets
.right
= -mComputedOffsets
.left
;
653 // Compute the 'top' and 'bottom' values. The 'top' and 'bottom' properties
654 // move relatively positioned elements up and down. They also must be each
656 PRBool topIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetTopUnit();
657 PRBool bottomIsAuto
= eStyleUnit_Auto
== mStylePosition
->mOffset
.GetBottomUnit();
659 // Check for percentage based values and a containing block height that
660 // depends on the content height. Treat them like 'auto'
661 if (NS_AUTOHEIGHT
== aContainingBlockHeight
) {
662 if (eStyleUnit_Percent
== mStylePosition
->mOffset
.GetTopUnit()) {
665 if (eStyleUnit_Percent
== mStylePosition
->mOffset
.GetBottomUnit()) {
666 bottomIsAuto
= PR_TRUE
;
670 // If neither is 'auto', 'bottom' is ignored
671 if (!topIsAuto
&& !bottomIsAuto
) {
672 bottomIsAuto
= PR_TRUE
;
677 // If both are 'auto' (their initial values), the computed values are 0
678 mComputedOffsets
.top
= mComputedOffsets
.bottom
= 0;
680 // 'Bottom' isn't 'auto' so compute its value
681 mComputedOffsets
.bottom
= nsLayoutUtils::
682 ComputeHeightDependentValue(aContainingBlockHeight
,
683 mStylePosition
->mOffset
.GetBottom());
685 // Computed value for 'top' is minus the value of 'bottom'
686 mComputedOffsets
.top
= -mComputedOffsets
.bottom
;
690 NS_ASSERTION(bottomIsAuto
, "unexpected specified constraint");
692 // 'Top' isn't 'auto' so compute its value
693 mComputedOffsets
.top
= nsLayoutUtils::
694 ComputeHeightDependentValue(aContainingBlockHeight
,
695 mStylePosition
->mOffset
.GetTop());
697 // Computed value for 'bottom' is minus the value of 'top'
698 mComputedOffsets
.bottom
= -mComputedOffsets
.top
;
702 nsPropertyTable
* propTable
= aPresContext
->PropertyTable();
703 nsPoint
* offsets
= static_cast<nsPoint
*>
704 (propTable
->GetProperty(frame
, nsGkAtoms::computedOffsetProperty
));
706 offsets
->MoveTo(mComputedOffsets
.left
, mComputedOffsets
.top
);
708 offsets
= new nsPoint(mComputedOffsets
.left
, mComputedOffsets
.top
);
710 propTable
->SetProperty(frame
, nsGkAtoms::computedOffsetProperty
,
711 offsets
, nsPointDtor
, nsnull
);
716 IsAnonBlockPseudo(nsIAtom
*aPseudo
)
718 return aPseudo
== nsCSSAnonBoxes::mozAnonymousBlock
||
719 aPseudo
== nsCSSAnonBoxes::mozAnonymousPositionedBlock
;
723 nsHTMLReflowState::GetHypotheticalBoxContainer(nsIFrame
* aFrame
,
724 nscoord
& aCBLeftEdge
,
728 aFrame
= aFrame
->GetParent();
729 NS_ASSERTION(aFrame
, "Must find containing block somewhere");
730 } while (!(aFrame
->IsContainingBlock() ||
731 (aFrame
->IsFrameOfType(nsIFrame::eBlockFrame
) &&
732 IsAnonBlockPseudo(aFrame
->GetStyleContext()->GetPseudoType()))));
734 NS_ASSERTION(aFrame
!= frame
, "How did that happen?");
736 /* Now aFrame is the containing block we want */
738 /* Check whether the containing block is currently being reflowed.
739 If so, use the info from the reflow state. */
740 const nsHTMLReflowState
* state
;
741 if (aFrame
->GetStateBits() & NS_FRAME_IN_REFLOW
) {
742 for (state
= parentReflowState
; state
&& state
->frame
!= aFrame
;
743 state
= state
->parentReflowState
) {
751 aCBLeftEdge
= state
->mComputedBorderPadding
.left
;
752 aCBWidth
= state
->mComputedWidth
;
754 /* Didn't find a reflow state for aFrame. Just compute the information we
755 want, on the assumption that aFrame already knows its size. This really
756 ought to be true by now. */
757 NS_ASSERTION(!(aFrame
->GetStateBits() & NS_FRAME_IN_REFLOW
),
758 "aFrame shouldn't be in reflow; we'll lie if it is");
759 nsMargin borderPadding
= aFrame
->GetUsedBorderAndPadding();
760 aCBLeftEdge
= borderPadding
.left
;
761 aCBWidth
= aFrame
->GetSize().width
- borderPadding
.LeftRight();
768 GetNearestContainingBlock(nsIFrame
*aFrame
)
770 nsIFrame
*cb
= aFrame
;
772 cb
= cb
->GetParent();
773 } while (!cb
->IsContainingBlock());
777 // When determining the hypothetical box that would have been if the element
778 // had been in the flow we may not be able to exactly determine both the left
779 // and right edges. For example, if the element is a non-replaced inline-level
780 // element we would have to reflow it in order to determine it desired width.
781 // In that case depending on the progression direction either the left or
782 // right edge would be marked as not being exact
783 struct nsHypotheticalBox
{
784 // offsets from left edge of containing block (which is a padding edge)
785 nscoord mLeft
, mRight
;
786 // offset from top edge of containing block (which is a padding edge)
789 PRPackedBool mLeftIsExact
, mRightIsExact
;
792 nsHypotheticalBox() {
794 mLeftIsExact
= mRightIsExact
= PR_FALSE
;
800 GetIntrinsicSizeFor(nsIFrame
* aFrame
, nsSize
& aIntrinsicSize
)
802 // See if it is an image frame
803 PRBool result
= PR_FALSE
;
805 // Currently the only type of replaced frame that we can get the intrinsic
806 // size for is an image frame
807 // XXX We should add back the GetReflowMetrics() function and one of the
808 // things should be the intrinsic size...
809 if (aFrame
->GetType() == nsGkAtoms::imageFrame
) {
810 nsImageFrame
* imageFrame
= (nsImageFrame
*)aFrame
;
812 imageFrame
->GetIntrinsicImageSize(aIntrinsicSize
);
813 result
= (aIntrinsicSize
!= nsSize(0, 0));
819 * aInsideBoxSizing returns the part of the horizontal padding, border,
820 * and margin that goes inside the edge given by -moz-box-sizing;
821 * aOutsideBoxSizing returns the rest.
824 nsHTMLReflowState::CalculateHorizBorderPaddingMargin(
825 nscoord aContainingBlockWidth
,
826 nscoord
* aInsideBoxSizing
,
827 nscoord
* aOutsideBoxSizing
)
829 const nsMargin
& border
= mStyleBorder
->GetActualBorder();
830 nsMargin padding
, margin
;
832 // See if the style system can provide us the padding directly
833 if (!mStylePadding
->GetPadding(padding
)) {
834 // We have to compute the left and right values
835 padding
.left
= nsLayoutUtils::
836 ComputeWidthDependentValue(aContainingBlockWidth
,
837 mStylePadding
->mPadding
.GetLeft());
838 padding
.right
= nsLayoutUtils::
839 ComputeWidthDependentValue(aContainingBlockWidth
,
840 mStylePadding
->mPadding
.GetRight());
843 // See if the style system can provide us the margin directly
844 if (!mStyleMargin
->GetMargin(margin
)) {
845 // We have to compute the left and right values
846 if (eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetLeftUnit()) {
847 // XXX FIXME (or does CalculateBlockSideMargins do this?)
848 margin
.left
= 0; // just ignore
850 margin
.left
= nsLayoutUtils::
851 ComputeWidthDependentValue(aContainingBlockWidth
,
852 mStyleMargin
->mMargin
.GetLeft());
854 if (eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetRightUnit()) {
855 // XXX FIXME (or does CalculateBlockSideMargins do this?)
856 margin
.right
= 0; // just ignore
858 margin
.right
= nsLayoutUtils::
859 ComputeWidthDependentValue(aContainingBlockWidth
,
860 mStyleMargin
->mMargin
.GetRight());
865 padding
.LeftRight() + border
.LeftRight() + margin
.LeftRight();
867 switch (mStylePosition
->mBoxSizing
) {
868 case NS_STYLE_BOX_SIZING_BORDER
:
869 inside
+= border
.LeftRight();
871 case NS_STYLE_BOX_SIZING_PADDING
:
872 inside
+= padding
.LeftRight();
875 *aInsideBoxSizing
= inside
;
876 *aOutsideBoxSizing
= outside
;
881 * Returns PR_TRUE iff a pre-order traversal of the normal child
882 * frames rooted at aFrame finds no non-empty frame before aDescendant.
884 static PRBool
AreAllEarlierInFlowFramesEmpty(nsIFrame
* aFrame
,
885 nsIFrame
* aDescendant
, PRBool
* aFound
) {
886 if (aFrame
== aDescendant
) {
890 if (!aFrame
->IsSelfEmpty()) {
894 for (nsIFrame
* f
= aFrame
->GetFirstChild(nsnull
); f
; f
= f
->GetNextSibling()) {
895 PRBool allEmpty
= AreAllEarlierInFlowFramesEmpty(f
, aDescendant
, aFound
);
896 if (*aFound
|| !allEmpty
) {
904 // Calculate the hypothetical box that the element would have if it were in
905 // the flow. The values returned are relative to the padding edge of the
906 // absolute containing block
907 // aContainingBlock is the placeholder's containing block (XXX rename it?)
908 // cbrs->frame is the actual containing block
910 nsHTMLReflowState::CalculateHypotheticalBox(nsPresContext
* aPresContext
,
911 nsIFrame
* aPlaceholderFrame
,
912 nsIFrame
* aContainingBlock
,
913 nscoord aBlockLeftContentEdge
,
914 nscoord aBlockContentWidth
,
915 const nsHTMLReflowState
* cbrs
,
916 nsHypotheticalBox
& aHypotheticalBox
)
918 NS_ASSERTION(mStyleDisplay
->mOriginalDisplay
!= NS_STYLE_DISPLAY_NONE
,
919 "mOriginalDisplay has not been properly initialized");
921 // If it's a replaced element and it has a 'auto' value for 'width', see if we
922 // can get the intrinsic size. This will allow us to exactly determine both the
923 // left and right edges
924 PRBool isAutoWidth
= mStylePosition
->mWidth
.GetUnit() == eStyleUnit_Auto
;
925 nsSize intrinsicSize
;
926 PRBool knowIntrinsicSize
= PR_FALSE
;
927 if (NS_FRAME_IS_REPLACED(mFrameType
) && isAutoWidth
) {
928 // See if we can get the intrinsic size of the element
929 knowIntrinsicSize
= GetIntrinsicSizeFor(frame
, intrinsicSize
);
932 // See if we can calculate what the box width would have been if the
933 // element had been in the flow
935 PRBool knowBoxWidth
= PR_FALSE
;
936 if ((NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) &&
937 !NS_FRAME_IS_REPLACED(mFrameType
)) {
938 // For non-replaced inline-level elements the 'width' property doesn't apply,
939 // so we don't know what the width would have been without reflowing it
942 // It's either a replaced inline-level element or a block-level element
944 // Determine the total amount of horizontal border/padding/margin that
945 // the element would have had if it had been in the flow. Note that we
946 // ignore any 'auto' and 'inherit' values
947 nscoord insideBoxSizing
, outsideBoxSizing
;
948 CalculateHorizBorderPaddingMargin(aBlockContentWidth
,
949 &insideBoxSizing
, &outsideBoxSizing
);
951 if (NS_FRAME_IS_REPLACED(mFrameType
) && isAutoWidth
) {
952 // It's a replaced element with an 'auto' width so the box width is
953 // its intrinsic size plus any border/padding/margin
954 if (knowIntrinsicSize
) {
955 boxWidth
= intrinsicSize
.width
+ outsideBoxSizing
+ insideBoxSizing
;
956 knowBoxWidth
= PR_TRUE
;
959 } else if (isAutoWidth
) {
960 // The box width is the containing block width
961 boxWidth
= aBlockContentWidth
;
962 knowBoxWidth
= PR_TRUE
;
965 // We need to compute it. It's important we do this, because if it's
966 // percentage based this computed value may be different from the computed
967 // value calculated using the absolute containing block width
968 boxWidth
= ComputeWidthValue(aBlockContentWidth
,
969 insideBoxSizing
, outsideBoxSizing
,
970 mStylePosition
->mWidth
) +
971 insideBoxSizing
+ outsideBoxSizing
;
972 knowBoxWidth
= PR_TRUE
;
976 // Get the 'direction' of the block
977 const nsStyleVisibility
* blockVis
= aContainingBlock
->GetStyleVisibility();
979 // Get the placeholder x-offset and y-offset in the coordinate
980 // space of the block frame that contains it
981 // XXXbz the placeholder is not fully reflowed yet if our containing block is
982 // relatively positioned...
983 nsPoint placeholderOffset
= aPlaceholderFrame
->GetOffsetTo(aContainingBlock
);
985 // First, determine the hypothetical box's mTop
986 nsBlockFrame
* blockFrame
= nsLayoutUtils::GetAsBlock(aContainingBlock
);
989 nsBlockInFlowLineIterator
iter(blockFrame
, aPlaceholderFrame
, &isValid
);
990 NS_ASSERTION(isValid
, "Can't find placeholder!");
991 NS_ASSERTION(iter
.GetContainer() == blockFrame
, "Found placeholder in wrong block!");
992 nsBlockFrame::line_iterator lineBox
= iter
.GetLine();
994 // How we determine the hypothetical box depends on whether the element
995 // would have been inline-level or block-level
996 if (NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) {
997 // Use the top of the inline box which the placeholder lives in as the
998 // hypothetical box's top.
999 aHypotheticalBox
.mTop
= lineBox
->mBounds
.y
;
1001 // The element would have been block-level which means it would be below
1002 // the line containing the placeholder frame, unless all the frames
1003 // before it are empty. In that case, it would have been just before
1005 // XXXbz the line box is not fully reflowed yet if our containing block is
1006 // relatively positioned...
1007 if (lineBox
!= iter
.End()) {
1008 nsIFrame
* firstFrame
= lineBox
->mFirstChild
;
1009 PRBool found
= PR_FALSE
;
1010 PRBool allEmpty
= PR_TRUE
;
1011 while (firstFrame
) { // See bug 223064
1012 allEmpty
= AreAllEarlierInFlowFramesEmpty(firstFrame
,
1013 aPlaceholderFrame
, &found
);
1014 if (found
|| !allEmpty
)
1016 firstFrame
= firstFrame
->GetNextSibling();
1018 NS_ASSERTION(firstFrame
, "Couldn't find placeholder!");
1021 // The top of the hypothetical box is the top of the line containing
1022 // the placeholder, since there is nothing in the line before our
1023 // placeholder except empty frames.
1024 aHypotheticalBox
.mTop
= lineBox
->mBounds
.y
;
1026 // The top of the hypothetical box is just below the line containing
1028 aHypotheticalBox
.mTop
= lineBox
->mBounds
.YMost();
1031 // Just use the placeholder's y-offset
1032 aHypotheticalBox
.mTop
= placeholderOffset
.y
;
1036 // The containing block is not a block, so it's probably something
1037 // like a XUL box, etc.
1038 // Just use the placeholder's y-offset
1039 aHypotheticalBox
.mTop
= placeholderOffset
.y
;
1042 // Second, determine the hypothetical box's mLeft & mRight
1043 // To determine the left and right offsets we need to look at the block's 'direction'
1044 if (NS_STYLE_DIRECTION_LTR
== blockVis
->mDirection
) {
1045 // How we determine the hypothetical box depends on whether the element
1046 // would have been inline-level or block-level
1047 if (NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) {
1048 // The placeholder represents the left edge of the hypothetical box
1049 aHypotheticalBox
.mLeft
= placeholderOffset
.x
;
1051 aHypotheticalBox
.mLeft
= aBlockLeftContentEdge
;
1054 aHypotheticalBox
.mLeftIsExact
= PR_TRUE
;
1058 aHypotheticalBox
.mRight
= aHypotheticalBox
.mLeft
+ boxWidth
;
1060 aHypotheticalBox
.mRightIsExact
= PR_TRUE
;
1063 // We can't compute the right edge because we don't know the desired
1064 // width. So instead use the right content edge of the block parent,
1065 // but remember it's not exact
1066 aHypotheticalBox
.mRight
= aBlockLeftContentEdge
+ aBlockContentWidth
;
1068 aHypotheticalBox
.mRightIsExact
= PR_FALSE
;
1073 // The placeholder represents the right edge of the hypothetical box
1074 if (NS_STYLE_DISPLAY_INLINE
== mStyleDisplay
->mOriginalDisplay
) {
1075 aHypotheticalBox
.mRight
= placeholderOffset
.x
;
1077 aHypotheticalBox
.mRight
= aBlockLeftContentEdge
+ aBlockContentWidth
;
1080 aHypotheticalBox
.mRightIsExact
= PR_TRUE
;
1084 aHypotheticalBox
.mLeft
= aHypotheticalBox
.mRight
- boxWidth
;
1086 aHypotheticalBox
.mLeftIsExact
= PR_TRUE
;
1089 // We can't compute the left edge because we don't know the desired
1090 // width. So instead use the left content edge of the block parent,
1091 // but remember it's not exact
1092 aHypotheticalBox
.mLeft
= aBlockLeftContentEdge
;
1094 aHypotheticalBox
.mLeftIsExact
= PR_FALSE
;
1100 // The current coordinate space is that of the nearest block to the placeholder.
1101 // Convert to the coordinate space of the absolute containing block
1102 // One weird thing here is that for fixed-positioned elements we want to do
1103 // the conversion incorrectly; specifically we want to ignore any scrolling
1104 // that may have happened;
1106 if (mStyleDisplay
->mPosition
== NS_STYLE_POSITION_FIXED
&&
1107 // Exclude cases inside -moz-transform where fixed is like absolute.
1108 nsLayoutUtils::IsReallyFixedPos(frame
)) {
1109 // In this case, cbrs->frame will always be an ancestor of
1110 // aContainingBlock, so can just walk our way up the frame tree.
1111 // Make sure to not add positions of frames whose parent is a
1112 // scrollFrame, since we're doing fixed positioning, which assumes
1113 // everything is scrolled to (0,0).
1114 cbOffset
.MoveTo(0, 0);
1116 NS_ASSERTION(aContainingBlock
,
1117 "Should hit cbrs->frame before we run off the frame tree!");
1118 cbOffset
+= aContainingBlock
->GetPositionIgnoringScrolling();
1119 aContainingBlock
= aContainingBlock
->GetParent();
1120 } while (aContainingBlock
!= cbrs
->frame
);
1122 // XXXldb We need to either ignore scrolling for the absolute
1123 // positioning case too (and take the incompatibility) or figure out
1124 // how to make these positioned elements actually *move* when we
1125 // scroll, and thus avoid the resulting incremental reflow bugs.
1126 cbOffset
= aContainingBlock
->GetOffsetTo(cbrs
->frame
);
1128 aHypotheticalBox
.mLeft
+= cbOffset
.x
;
1129 aHypotheticalBox
.mTop
+= cbOffset
.y
;
1130 aHypotheticalBox
.mRight
+= cbOffset
.x
;
1132 // The specified offsets are relative to the absolute containing block's
1133 // padding edge and our current values are relative to the border edge, so
1135 nsMargin border
= cbrs
->mComputedBorderPadding
- cbrs
->mComputedPadding
;
1136 aHypotheticalBox
.mLeft
-= border
.left
;
1137 aHypotheticalBox
.mRight
-= border
.left
;
1138 aHypotheticalBox
.mTop
-= border
.top
;
1142 nsHTMLReflowState::InitAbsoluteConstraints(nsPresContext
* aPresContext
,
1143 const nsHTMLReflowState
* cbrs
,
1144 nscoord containingBlockWidth
,
1145 nscoord containingBlockHeight
)
1147 NS_PRECONDITION(containingBlockHeight
!= NS_AUTOHEIGHT
,
1148 "containing block height must be constrained");
1150 nsIFrame
* outOfFlow
=
1151 frame
->GetType() == nsGkAtoms::tableFrame
? frame
->GetParent() : frame
;
1152 NS_ASSERTION(outOfFlow
->GetStateBits() & NS_FRAME_OUT_OF_FLOW
,
1153 "Why are we here?");
1155 // Get the placeholder frame
1156 nsIFrame
* placeholderFrame
;
1158 aPresContext
->PresShell()->GetPlaceholderFrameFor(outOfFlow
,
1160 NS_ASSERTION(nsnull
!= placeholderFrame
, "no placeholder frame");
1162 // If both 'left' and 'right' are 'auto' or both 'top' and 'bottom' are
1163 // 'auto', then compute the hypothetical box of where the element would
1164 // have been if it had been in the flow
1165 nsHypotheticalBox hypotheticalBox
;
1166 if (((eStyleUnit_Auto
== mStylePosition
->mOffset
.GetLeftUnit()) &&
1167 (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetRightUnit())) ||
1168 ((eStyleUnit_Auto
== mStylePosition
->mOffset
.GetTopUnit()) &&
1169 (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetBottomUnit()))) {
1170 // Find the nearest containing block frame to the placeholder frame,
1171 // and return its left edge and width.
1172 nscoord cbLeftEdge
, cbWidth
;
1173 nsIFrame
* cbFrame
= GetHypotheticalBoxContainer(placeholderFrame
,
1177 CalculateHypotheticalBox(aPresContext
, placeholderFrame
, cbFrame
,
1178 cbLeftEdge
, cbWidth
, cbrs
, hypotheticalBox
);
1181 // Initialize the 'left' and 'right' computed offsets
1182 // XXX Handle new 'static-position' value...
1183 PRBool leftIsAuto
= PR_FALSE
, rightIsAuto
= PR_FALSE
;
1184 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetLeftUnit()) {
1185 mComputedOffsets
.left
= 0;
1186 leftIsAuto
= PR_TRUE
;
1188 mComputedOffsets
.left
= nsLayoutUtils::
1189 ComputeWidthDependentValue(containingBlockWidth
,
1190 mStylePosition
->mOffset
.GetLeft());
1192 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetRightUnit()) {
1193 mComputedOffsets
.right
= 0;
1194 rightIsAuto
= PR_TRUE
;
1196 mComputedOffsets
.right
= nsLayoutUtils::
1197 ComputeWidthDependentValue(containingBlockWidth
,
1198 mStylePosition
->mOffset
.GetRight());
1201 // Use the horizontal component of the hypothetical box in the cases
1202 // where it's needed.
1203 if (leftIsAuto
&& rightIsAuto
) {
1204 // Use the direction of the original ("static-position") containing block
1205 // to dictate whether 'left' or 'right' is treated like 'static-position'.
1206 if (NS_STYLE_DIRECTION_LTR
== GetNearestContainingBlock(placeholderFrame
)
1207 ->GetStyleVisibility()->mDirection
) {
1208 NS_ASSERTION(hypotheticalBox
.mLeftIsExact
, "should always have "
1209 "exact value on containing block's start side");
1210 mComputedOffsets
.left
= hypotheticalBox
.mLeft
;
1211 leftIsAuto
= PR_FALSE
;
1213 NS_ASSERTION(hypotheticalBox
.mRightIsExact
, "should always have "
1214 "exact value on containing block's start side");
1215 mComputedOffsets
.right
= containingBlockWidth
- hypotheticalBox
.mRight
;
1216 rightIsAuto
= PR_FALSE
;
1220 // Initialize the 'top' and 'bottom' computed offsets
1221 PRBool topIsAuto
= PR_FALSE
, bottomIsAuto
= PR_FALSE
;
1222 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetTopUnit()) {
1223 mComputedOffsets
.top
= 0;
1224 topIsAuto
= PR_TRUE
;
1226 mComputedOffsets
.top
= nsLayoutUtils::
1227 ComputeHeightDependentValue(containingBlockHeight
,
1228 mStylePosition
->mOffset
.GetTop());
1230 if (eStyleUnit_Auto
== mStylePosition
->mOffset
.GetBottomUnit()) {
1231 mComputedOffsets
.bottom
= 0;
1232 bottomIsAuto
= PR_TRUE
;
1234 mComputedOffsets
.bottom
= nsLayoutUtils::
1235 ComputeHeightDependentValue(containingBlockHeight
,
1236 mStylePosition
->mOffset
.GetBottom());
1239 if (topIsAuto
&& bottomIsAuto
) {
1240 // Treat 'top' like 'static-position'
1241 mComputedOffsets
.top
= hypotheticalBox
.mTop
;
1242 topIsAuto
= PR_FALSE
;
1245 PRBool widthIsAuto
= eStyleUnit_Auto
== mStylePosition
->mWidth
.GetUnit();
1246 PRBool heightIsAuto
= eStyleUnit_Auto
== mStylePosition
->mHeight
.GetUnit();
1248 PRBool shrinkWrap
= leftIsAuto
|| rightIsAuto
;
1250 frame
->ComputeSize(rendContext
,
1251 nsSize(containingBlockWidth
,
1252 containingBlockHeight
),
1253 containingBlockWidth
, // XXX or availableWidth?
1254 nsSize(mComputedMargin
.LeftRight() +
1255 mComputedOffsets
.LeftRight(),
1256 mComputedMargin
.TopBottom() +
1257 mComputedOffsets
.TopBottom()),
1258 nsSize(mComputedBorderPadding
.LeftRight() -
1259 mComputedPadding
.LeftRight(),
1260 mComputedBorderPadding
.TopBottom() -
1261 mComputedPadding
.TopBottom()),
1262 nsSize(mComputedPadding
.LeftRight(),
1263 mComputedPadding
.TopBottom()),
1265 mComputedWidth
= size
.width
;
1266 mComputedHeight
= size
.height
;
1267 NS_ASSERTION(mComputedWidth
>= 0, "Bogus width");
1268 NS_ASSERTION(mComputedHeight
== NS_UNCONSTRAINEDSIZE
||
1269 mComputedHeight
>= 0, "Bogus height");
1271 // XXX Now that we have ComputeSize, can we condense many of the
1272 // branches off of widthIsAuto?
1275 // We know 'right' is not 'auto' anymore thanks to the hypothetical
1277 // Solve for 'left'.
1279 // XXXldb This, and the corresponding code in
1280 // nsAbsoluteContainingBlock.cpp, could probably go away now that
1281 // we always compute widths.
1282 mComputedOffsets
.left
= NS_AUTOOFFSET
;
1284 mComputedOffsets
.left
= containingBlockWidth
- mComputedMargin
.left
-
1285 mComputedBorderPadding
.left
- mComputedWidth
- mComputedBorderPadding
.right
-
1286 mComputedMargin
.right
- mComputedOffsets
.right
;
1289 } else if (rightIsAuto
) {
1290 // We know 'left' is not 'auto' anymore thanks to the hypothetical
1292 // Solve for 'right'.
1294 // XXXldb This, and the corresponding code in
1295 // nsAbsoluteContainingBlock.cpp, could probably go away now that
1296 // we always compute widths.
1297 mComputedOffsets
.right
= NS_AUTOOFFSET
;
1299 mComputedOffsets
.right
= containingBlockWidth
- mComputedOffsets
.left
-
1300 mComputedMargin
.left
- mComputedBorderPadding
.left
- mComputedWidth
-
1301 mComputedBorderPadding
.right
- mComputedMargin
.right
;
1304 // Neither 'left' nor 'right' is 'auto'. However, the width might
1305 // still not fill all the available space (even though we didn't
1306 // shrink-wrap) in case:
1307 // * width was specified
1308 // * we're dealing with a replaced element
1309 // * width was constrained by min-width or max-width.
1311 nscoord availMarginSpace
= containingBlockWidth
-
1312 mComputedOffsets
.LeftRight() -
1313 mComputedMargin
.LeftRight() -
1314 mComputedBorderPadding
.LeftRight() -
1316 PRBool marginLeftIsAuto
=
1317 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetLeftUnit();
1318 PRBool marginRightIsAuto
=
1319 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetRightUnit();
1321 if (availMarginSpace
< 0 ||
1322 (!marginLeftIsAuto
&& !marginRightIsAuto
)) {
1323 // We're over-constrained so use the direction of the containing block
1324 // to dictate which value to ignore. (And note that the spec says to ignore
1325 // 'left' or 'right' rather than 'margin-left' or 'margin-right'.)
1327 NS_STYLE_DIRECTION_RTL
== cbrs
->mStyleVisibility
->mDirection
) {
1328 // Ignore the specified value for 'left'.
1329 mComputedOffsets
.left
+= availMarginSpace
;
1331 // Ignore the specified value for 'right'.
1332 mComputedOffsets
.right
+= availMarginSpace
;
1334 } else if (marginLeftIsAuto
) {
1335 if (marginRightIsAuto
) {
1336 // Both 'margin-left' and 'margin-right' are 'auto', so they get
1338 mComputedMargin
.left
= availMarginSpace
/ 2;
1339 mComputedMargin
.right
= availMarginSpace
- mComputedMargin
.left
;
1341 // Just 'margin-left' is 'auto'
1342 mComputedMargin
.left
= availMarginSpace
;
1345 // Just 'margin-right' is 'auto'
1346 mComputedMargin
.right
= availMarginSpace
;
1353 mComputedOffsets
.top
= NS_AUTOOFFSET
;
1355 mComputedOffsets
.top
= containingBlockHeight
- mComputedMargin
.top
-
1356 mComputedBorderPadding
.top
- mComputedHeight
- mComputedBorderPadding
.bottom
-
1357 mComputedMargin
.bottom
- mComputedOffsets
.bottom
;
1359 } else if (bottomIsAuto
) {
1360 // solve for 'bottom'
1362 mComputedOffsets
.bottom
= NS_AUTOOFFSET
;
1364 mComputedOffsets
.bottom
= containingBlockHeight
- mComputedOffsets
.top
-
1365 mComputedMargin
.top
- mComputedBorderPadding
.top
- mComputedHeight
-
1366 mComputedBorderPadding
.bottom
- mComputedMargin
.bottom
;
1369 // Neither 'top' nor 'bottom' is 'auto'.
1370 nscoord autoHeight
= containingBlockHeight
-
1371 mComputedOffsets
.TopBottom() -
1372 mComputedMargin
.TopBottom() -
1373 mComputedBorderPadding
.TopBottom();
1374 if (autoHeight
< 0) {
1378 if (mComputedHeight
== NS_UNCONSTRAINEDSIZE
) {
1379 // For non-replaced elements with 'height' auto, the 'height'
1380 // fills the remaining space.
1381 mComputedHeight
= autoHeight
;
1383 // XXX Do these need box-sizing adjustments?
1384 if (mComputedHeight
> mComputedMaxHeight
)
1385 mComputedHeight
= mComputedMaxHeight
;
1386 if (mComputedHeight
< mComputedMinHeight
)
1387 mComputedHeight
= mComputedMinHeight
;
1390 // The height might still not fill all the available space in case:
1391 // * height was specified
1392 // * we're dealing with a replaced element
1393 // * height was constrained by min-height or max-height.
1394 nscoord availMarginSpace
= autoHeight
- mComputedHeight
;
1395 PRBool marginTopIsAuto
=
1396 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetTopUnit();
1397 PRBool marginBottomIsAuto
=
1398 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetBottomUnit();
1400 if (availMarginSpace
< 0 || (!marginTopIsAuto
&& !marginBottomIsAuto
)) {
1401 // We're over-constrained so ignore the specified value for
1402 // 'bottom'. (And note that the spec says to ignore 'bottom'
1403 // rather than 'margin-bottom'.)
1404 mComputedOffsets
.bottom
+= availMarginSpace
;
1405 } else if (marginTopIsAuto
) {
1406 if (marginBottomIsAuto
) {
1407 // Both 'margin-top' and 'margin-bottom' are 'auto', so they get
1409 mComputedMargin
.top
= availMarginSpace
/ 2;
1410 mComputedMargin
.bottom
= availMarginSpace
- mComputedMargin
.top
;
1412 // Just 'margin-top' is 'auto'
1413 mComputedMargin
.top
= availMarginSpace
- mComputedMargin
.bottom
;
1416 // Just 'margin-bottom' is 'auto'
1417 mComputedMargin
.bottom
= availMarginSpace
- mComputedMargin
.top
;
1423 GetVerticalMarginBorderPadding(const nsHTMLReflowState
* aReflowState
)
1426 if (!aReflowState
) return result
;
1428 // zero auto margins
1429 nsMargin margin
= aReflowState
->mComputedMargin
;
1430 if (NS_AUTOMARGIN
== margin
.top
)
1432 if (NS_AUTOMARGIN
== margin
.bottom
)
1435 result
+= margin
.top
+ margin
.bottom
;
1436 result
+= aReflowState
->mComputedBorderPadding
.top
+
1437 aReflowState
->mComputedBorderPadding
.bottom
;
1442 /* Get the height based on the viewport of the containing block specified
1443 * in aReflowState when the containing block has mComputedHeight == NS_AUTOHEIGHT
1444 * This will walk up the chain of containing blocks looking for a computed height
1445 * until it finds the canvas frame, or it encounters a frame that is not a block,
1446 * area, or scroll frame. This handles compatibility with IE (see bug 85016 and bug 219693)
1448 * When we encounter scrolledContent block frames, we skip over them, since they are guaranteed to not be useful for computing the containing block.
1450 * See also IsQuirkContainingBlockHeight.
1453 CalcQuirkContainingBlockHeight(const nsHTMLReflowState
* aCBReflowState
)
1455 nsHTMLReflowState
* firstAncestorRS
= nsnull
; // a candidate for html frame
1456 nsHTMLReflowState
* secondAncestorRS
= nsnull
; // a candidate for body frame
1458 // initialize the default to NS_AUTOHEIGHT as this is the containings block
1459 // computed height when this function is called. It is possible that we
1460 // don't alter this height especially if we are restricted to one level
1461 nscoord result
= NS_AUTOHEIGHT
;
1463 const nsHTMLReflowState
* rs
= aCBReflowState
;
1464 for (; rs
; rs
= (nsHTMLReflowState
*)(rs
->parentReflowState
)) {
1465 nsIAtom
* frameType
= rs
->frame
->GetType();
1466 // if the ancestor is auto height then skip it and continue up if it
1467 // is the first block frame and possibly the body/html
1468 if (nsGkAtoms::blockFrame
== frameType
||
1470 nsGkAtoms::XULLabelFrame
== frameType
||
1472 nsGkAtoms::scrollFrame
== frameType
) {
1474 secondAncestorRS
= firstAncestorRS
;
1475 firstAncestorRS
= (nsHTMLReflowState
*)rs
;
1477 // If the current frame we're looking at is positioned, we don't want to
1478 // go any further (see bug 221784). The behavior we want here is: 1) If
1479 // not auto-height, use this as the percentage base. 2) If auto-height,
1480 // keep looking, unless the frame is positioned.
1481 if (NS_AUTOHEIGHT
== rs
->ComputedHeight()) {
1482 if (rs
->frame
->GetStyleDisplay()->IsAbsolutelyPositioned()) {
1489 else if (nsGkAtoms::canvasFrame
== frameType
) {
1490 // Always continue on to the height calculation
1492 else if (nsGkAtoms::pageContentFrame
== frameType
) {
1493 nsIFrame
* prevInFlow
= rs
->frame
->GetPrevInFlow();
1494 // only use the page content frame for a height basis if it is the first in flow
1502 // if the ancestor is the page content frame then the percent base is
1503 // the avail height, otherwise it is the computed height
1504 result
= (nsGkAtoms::pageContentFrame
== frameType
)
1505 ? rs
->availableHeight
: rs
->ComputedHeight();
1506 // if unconstrained - don't sutract borders - would result in huge height
1507 if (NS_AUTOHEIGHT
== result
) return result
;
1509 // if we got to the canvas or page content frame, then subtract out
1510 // margin/border/padding for the BODY and HTML elements
1511 if ((nsGkAtoms::canvasFrame
== frameType
) ||
1512 (nsGkAtoms::pageContentFrame
== frameType
)) {
1514 result
-= GetVerticalMarginBorderPadding(firstAncestorRS
);
1515 result
-= GetVerticalMarginBorderPadding(secondAncestorRS
);
1518 // make sure the first ancestor is the HTML and the second is the BODY
1519 if (firstAncestorRS
) {
1520 nsIContent
* frameContent
= firstAncestorRS
->frame
->GetContent();
1522 nsIAtom
*contentTag
= frameContent
->Tag();
1523 NS_ASSERTION(contentTag
== nsGkAtoms::html
, "First ancestor is not HTML");
1526 if (secondAncestorRS
) {
1527 nsIContent
* frameContent
= secondAncestorRS
->frame
->GetContent();
1529 nsIAtom
*contentTag
= frameContent
->Tag();
1530 NS_ASSERTION(contentTag
== nsGkAtoms::body
, "Second ancestor is not BODY");
1536 // if we got to the html frame (a block child of the canvas) ...
1537 else if (nsGkAtoms::blockFrame
== frameType
&&
1538 nsGkAtoms::canvasFrame
==
1539 rs
->parentReflowState
->frame
->GetType()) {
1540 // ... then subtract out margin/border/padding for the BODY element
1541 result
-= GetVerticalMarginBorderPadding(secondAncestorRS
);
1546 // Make sure not to return a negative height here!
1547 return PR_MAX(result
, 0);
1549 // Called by InitConstraints() to compute the containing block rectangle for
1550 // the element. Handles the special logic for absolutely positioned elements
1552 nsHTMLReflowState::ComputeContainingBlockRectangle(nsPresContext
* aPresContext
,
1553 const nsHTMLReflowState
* aContainingBlockRS
,
1554 nscoord
& aContainingBlockWidth
,
1555 nscoord
& aContainingBlockHeight
)
1557 // Unless the element is absolutely positioned, the containing block is
1558 // formed by the content edge of the nearest block-level ancestor
1559 aContainingBlockWidth
= aContainingBlockRS
->mComputedWidth
;
1560 aContainingBlockHeight
= aContainingBlockRS
->mComputedHeight
;
1562 if (NS_FRAME_GET_TYPE(mFrameType
) == NS_CSS_FRAME_TYPE_ABSOLUTE
) {
1563 // See if the ancestor is block-level or inline-level
1564 if (NS_FRAME_GET_TYPE(aContainingBlockRS
->mFrameType
) == NS_CSS_FRAME_TYPE_INLINE
) {
1565 // Base our size on the actual size of the frame. In cases when this is
1566 // completely bogus (eg initial reflow), this code shouldn't even be
1567 // called, since the code in nsPositionedInlineFrame::Reflow will pass in
1568 // the containing block dimensions to our constructor.
1569 // XXXbz we should be taking the in-flows into account too, but
1570 // that's very hard.
1571 nsMargin computedBorder
= aContainingBlockRS
->mComputedBorderPadding
-
1572 aContainingBlockRS
->mComputedPadding
;
1573 aContainingBlockWidth
= aContainingBlockRS
->frame
->GetRect().width
-
1574 computedBorder
.LeftRight();;
1575 NS_ASSERTION(aContainingBlockWidth
>= 0,
1576 "Negative containing block width!");
1577 aContainingBlockHeight
= aContainingBlockRS
->frame
->GetRect().height
-
1578 computedBorder
.TopBottom();
1579 NS_ASSERTION(aContainingBlockHeight
>= 0,
1580 "Negative containing block height!");
1582 // If the ancestor is block-level, the containing block is formed by the
1583 // padding edge of the ancestor
1584 aContainingBlockWidth
+= aContainingBlockRS
->mComputedPadding
.LeftRight();
1585 aContainingBlockHeight
+= aContainingBlockRS
->mComputedPadding
.TopBottom();
1588 // an element in quirks mode gets a containing block based on looking for a
1589 // parent with a non-auto height if the element has a percent height
1590 if (NS_AUTOHEIGHT
== aContainingBlockHeight
) {
1591 if (eCompatibility_NavQuirks
== aPresContext
->CompatibilityMode() &&
1592 mStylePosition
->mHeight
.GetUnit() == eStyleUnit_Percent
) {
1593 aContainingBlockHeight
= CalcQuirkContainingBlockHeight(aContainingBlockRS
);
1599 // Prefs callback to pick up changes
1601 PrefsChanged(const char *aPrefName
, void *instance
)
1604 nsContentUtils::GetBoolPref("browser.blink_allowed", sBlinkIsAllowed
);
1606 return 0; /* PREF_OK */
1609 // Check to see if |text-decoration: blink| is allowed. The first time
1610 // called, register the callback and then force-load the pref. After that,
1611 // just use the cached value.
1612 static PRBool
BlinkIsAllowed(void)
1614 if (!sPrefIsLoaded
) {
1615 // Set up a listener and check the initial value
1616 nsContentUtils::RegisterPrefCallback("browser.blink_allowed", PrefsChanged
,
1618 PrefsChanged(nsnull
, nsnull
);
1619 sPrefIsLoaded
= PR_TRUE
;
1621 return sBlinkIsAllowed
;
1624 static eNormalLineHeightControl
GetNormalLineHeightCalcControl(void)
1626 if (sNormalLineHeightControl
== eUninitialized
) {
1627 // browser.display.normal_lineheight_calc_control is not user
1628 // changeable, so no need to register callback for it.
1629 sNormalLineHeightControl
=
1630 static_cast<eNormalLineHeightControl
>
1631 (nsContentUtils::GetIntPref("browser.display.normal_lineheight_calc_control", eNoExternalLeading
));
1633 return sNormalLineHeightControl
;
1636 static inline PRBool
1637 IsSideCaption(nsIFrame
* aFrame
, const nsStyleDisplay
* aStyleDisplay
)
1639 if (aStyleDisplay
->mDisplay
!= NS_STYLE_DISPLAY_TABLE_CAPTION
)
1641 PRUint8 captionSide
= aFrame
->GetStyleTableBorder()->mCaptionSide
;
1642 return captionSide
== NS_STYLE_CAPTION_SIDE_LEFT
||
1643 captionSide
== NS_STYLE_CAPTION_SIDE_RIGHT
;
1646 // XXX refactor this code to have methods for each set of properties
1647 // we are computing: width,height,line-height; margin; offsets
1650 nsHTMLReflowState::InitConstraints(nsPresContext
* aPresContext
,
1651 nscoord aContainingBlockWidth
,
1652 nscoord aContainingBlockHeight
,
1653 const nsMargin
* aBorder
,
1654 const nsMargin
* aPadding
)
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
);
1692 nsFrame::ListTag(stdout
, frame
); printf(": cb=");
1693 nsFrame::ListTag(stdout
, cbrs
->frame
); printf(" size=%d,%d\n", aContainingBlockWidth
, aContainingBlockHeight
);
1696 // See if the containing block height is based on the size of its
1699 if (NS_AUTOHEIGHT
== aContainingBlockHeight
) {
1700 // See if the containing block is a cell frame which needs
1701 // to use the mComputedHeight of the cell instead of what the cell block passed in.
1702 // XXX It seems like this could lead to bugs with min-height and friends
1703 if (cbrs
->parentReflowState
) {
1704 fType
= cbrs
->frame
->GetType();
1705 if (IS_TABLE_CELL(fType
)) {
1706 // use the cell's computed height
1707 aContainingBlockHeight
= cbrs
->mComputedHeight
;
1712 InitOffsets(aContainingBlockWidth
, aBorder
, aPadding
);
1714 nsStyleUnit heightUnit
= mStylePosition
->mHeight
.GetUnit();
1716 // Check for a percentage based height and a containing block height
1717 // that depends on the content height
1718 // XXX twiddling heightUnit doesn't help anymore
1719 if (eStyleUnit_Percent
== heightUnit
) {
1720 if (NS_AUTOHEIGHT
== aContainingBlockHeight
) {
1721 // this if clause enables %-height on replaced inline frames,
1722 // such as images. See bug 54119. The else clause "heightUnit = eStyleUnit_Auto;"
1723 // used to be called exclusively.
1724 if (NS_FRAME_REPLACED(NS_CSS_FRAME_TYPE_INLINE
) == mFrameType
||
1725 NS_FRAME_REPLACED_CONTAINS_BLOCK(
1726 NS_CSS_FRAME_TYPE_INLINE
) == mFrameType
) {
1727 // Get the containing block reflow state
1728 NS_ASSERTION(nsnull
!= cbrs
, "no containing block");
1729 // in quirks mode, get the cb height using the special quirk method
1730 if (eCompatibility_NavQuirks
== aPresContext
->CompatibilityMode()) {
1731 if (!IS_TABLE_CELL(fType
)) {
1732 aContainingBlockHeight
= CalcQuirkContainingBlockHeight(cbrs
);
1733 if (aContainingBlockHeight
== NS_AUTOHEIGHT
) {
1734 heightUnit
= eStyleUnit_Auto
;
1738 heightUnit
= eStyleUnit_Auto
;
1741 // in standard mode, use the cb height. if it's "auto", as will be the case
1742 // by default in BODY, use auto height as per CSS2 spec.
1745 if (NS_AUTOHEIGHT
!= cbrs
->mComputedHeight
)
1746 aContainingBlockHeight
= cbrs
->mComputedHeight
;
1748 heightUnit
= eStyleUnit_Auto
;
1752 // default to interpreting the height like 'auto'
1753 heightUnit
= eStyleUnit_Auto
;
1758 // Compute our offsets if the element is relatively positioned. We need
1759 // the correct containing block width and height here, which is why we need
1760 // to do it after all the quirks-n-such above.
1761 if (NS_STYLE_POSITION_RELATIVE
== mStyleDisplay
->mPosition
) {
1762 ComputeRelativeOffsets(cbrs
, aContainingBlockWidth
, aContainingBlockHeight
, aPresContext
);
1764 // Initialize offsets to 0
1765 mComputedOffsets
.SizeTo(0, 0, 0, 0);
1768 // Calculate the computed values for min and max properties. Note that
1769 // this MUST come after we've computed our border and padding.
1770 ComputeMinMaxValues(aContainingBlockWidth
, aContainingBlockHeight
, cbrs
);
1772 // Calculate the computed width and height. This varies by frame type
1774 if (NS_CSS_FRAME_TYPE_INTERNAL_TABLE
== mFrameType
) {
1775 // Internal table elements. The rules vary depending on the type.
1776 // Calculate the computed width
1777 PRBool rowOrRowGroup
= PR_FALSE
;
1778 nsStyleUnit widthUnit
= mStylePosition
->mWidth
.GetUnit();
1779 if ((NS_STYLE_DISPLAY_TABLE_ROW
== mStyleDisplay
->mDisplay
) ||
1780 (NS_STYLE_DISPLAY_TABLE_ROW_GROUP
== mStyleDisplay
->mDisplay
)) {
1781 // 'width' property doesn't apply to table rows and row groups
1782 widthUnit
= eStyleUnit_Auto
;
1783 rowOrRowGroup
= PR_TRUE
;
1786 if (eStyleUnit_Auto
== widthUnit
) {
1787 mComputedWidth
= availableWidth
;
1789 if ((mComputedWidth
!= NS_UNCONSTRAINEDSIZE
) && !rowOrRowGroup
){
1790 // Internal table elements don't have margins. Only tables and
1791 // cells have border and padding
1792 mComputedWidth
-= mComputedBorderPadding
.left
+
1793 mComputedBorderPadding
.right
;
1794 if (mComputedWidth
< 0)
1797 NS_ASSERTION(mComputedWidth
>= 0, "Bogus computed width");
1800 NS_ASSERTION(widthUnit
== mStylePosition
->mWidth
.GetUnit(),
1801 "unexpected width unit change");
1802 mComputedWidth
= ComputeWidthValue(aContainingBlockWidth
,
1803 mStylePosition
->mBoxSizing
,
1804 mStylePosition
->mWidth
);
1807 // Calculate the computed height
1808 if ((NS_STYLE_DISPLAY_TABLE_COLUMN
== mStyleDisplay
->mDisplay
) ||
1809 (NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP
== mStyleDisplay
->mDisplay
)) {
1810 // 'height' property doesn't apply to table columns and column groups
1811 heightUnit
= eStyleUnit_Auto
;
1813 if (eStyleUnit_Auto
== heightUnit
) {
1814 mComputedHeight
= NS_AUTOHEIGHT
;
1816 NS_ASSERTION(heightUnit
== mStylePosition
->mHeight
.GetUnit(),
1817 "unexpected height unit change");
1818 mComputedHeight
= nsLayoutUtils::
1819 ComputeHeightDependentValue(aContainingBlockHeight
,
1820 mStylePosition
->mHeight
);
1823 // Doesn't apply to table elements
1824 mComputedMinWidth
= mComputedMinHeight
= 0;
1825 mComputedMaxWidth
= mComputedMaxHeight
= NS_UNCONSTRAINEDSIZE
;
1827 } else if (NS_FRAME_GET_TYPE(mFrameType
) == NS_CSS_FRAME_TYPE_ABSOLUTE
) {
1828 // XXX not sure if this belongs here or somewhere else - cwk
1829 InitAbsoluteConstraints(aPresContext
, cbrs
, aContainingBlockWidth
,
1830 aContainingBlockHeight
);
1833 NS_CSS_FRAME_TYPE_BLOCK
== NS_FRAME_GET_TYPE(mFrameType
);
1834 // make sure legend frames with display:block and width:auto still
1836 PRBool shrinkWrap
= !isBlock
|| frame
->GetType() == nsGkAtoms::legendFrame
;
1838 frame
->ComputeSize(rendContext
,
1839 nsSize(aContainingBlockWidth
,
1840 aContainingBlockHeight
),
1842 nsSize(mComputedMargin
.LeftRight(),
1843 mComputedMargin
.TopBottom()),
1844 nsSize(mComputedBorderPadding
.LeftRight() -
1845 mComputedPadding
.LeftRight(),
1846 mComputedBorderPadding
.TopBottom() -
1847 mComputedPadding
.TopBottom()),
1848 nsSize(mComputedPadding
.LeftRight(),
1849 mComputedPadding
.TopBottom()),
1852 mComputedWidth
= size
.width
;
1853 mComputedHeight
= size
.height
;
1854 NS_ASSERTION(mComputedWidth
>= 0, "Bogus width");
1855 NS_ASSERTION(mComputedHeight
== NS_UNCONSTRAINEDSIZE
||
1856 mComputedHeight
>= 0, "Bogus height");
1858 if (isBlock
&& !IsSideCaption(frame
, mStyleDisplay
))
1859 CalculateBlockSideMargins(availableWidth
, mComputedWidth
);
1862 // Check for blinking text and permission to display it
1863 mFlags
.mBlinks
= (parentReflowState
&& parentReflowState
->mFlags
.mBlinks
);
1864 if (!mFlags
.mBlinks
&& BlinkIsAllowed()) {
1865 const nsStyleTextReset
* st
= frame
->GetStyleTextReset();
1867 ((st
->mTextDecoration
& NS_STYLE_TEXT_DECORATION_BLINK
) != 0);
1872 nsCSSOffsetState::InitOffsets(nscoord aContainingBlockWidth
,
1873 const nsMargin
*aBorder
,
1874 const nsMargin
*aPadding
)
1876 // Compute margins from the specified margin style information. These
1877 // become the default computed values, and may be adjusted below
1878 // XXX fix to provide 0,0 for the top&bottom margins for
1879 // inline-non-replaced elements
1880 ComputeMargin(aContainingBlockWidth
);
1882 const nsStyleDisplay
*disp
= frame
->GetStyleDisplay();
1883 PRBool isThemed
= frame
->IsThemed(disp
);
1884 nsPresContext
*presContext
= frame
->PresContext();
1888 presContext
->GetTheme()->GetWidgetPadding(presContext
->DeviceContext(),
1889 frame
, disp
->mAppearance
,
1891 mComputedPadding
.top
= presContext
->DevPixelsToAppUnits(widget
.top
);
1892 mComputedPadding
.right
= presContext
->DevPixelsToAppUnits(widget
.right
);
1893 mComputedPadding
.bottom
= presContext
->DevPixelsToAppUnits(widget
.bottom
);
1894 mComputedPadding
.left
= presContext
->DevPixelsToAppUnits(widget
.left
);
1896 else if (aPadding
) { // padding is an input arg
1897 mComputedPadding
.top
= aPadding
->top
;
1898 mComputedPadding
.right
= aPadding
->right
;
1899 mComputedPadding
.bottom
= aPadding
->bottom
;
1900 mComputedPadding
.left
= aPadding
->left
;
1903 ComputePadding(aContainingBlockWidth
);
1908 presContext
->GetTheme()->GetWidgetBorder(presContext
->DeviceContext(),
1909 frame
, disp
->mAppearance
,
1911 mComputedBorderPadding
.top
=
1912 presContext
->DevPixelsToAppUnits(widget
.top
);
1913 mComputedBorderPadding
.right
=
1914 presContext
->DevPixelsToAppUnits(widget
.right
);
1915 mComputedBorderPadding
.bottom
=
1916 presContext
->DevPixelsToAppUnits(widget
.bottom
);
1917 mComputedBorderPadding
.left
=
1918 presContext
->DevPixelsToAppUnits(widget
.left
);
1920 else if (aBorder
) { // border is an input arg
1921 mComputedBorderPadding
= *aBorder
;
1924 mComputedBorderPadding
= frame
->GetStyleBorder()->GetActualBorder();
1926 mComputedBorderPadding
+= mComputedPadding
;
1928 nsIAtom
* frameType
= frame
->GetType();
1929 if (frameType
== nsGkAtoms::tableFrame
) {
1930 nsTableFrame
*tableFrame
= static_cast<nsTableFrame
*>(frame
);
1932 if (tableFrame
->IsBorderCollapse()) {
1933 // border-collapsed tables don't use any of their padding, and
1934 // only part of their border. We need to do this here before we
1935 // try to do anything like handling 'auto' widths,
1936 // '-moz-box-sizing', or 'auto' margins.
1937 mComputedPadding
.SizeTo(0,0,0,0);
1938 mComputedBorderPadding
= tableFrame
->GetIncludedOuterBCBorder();
1940 } else if (frameType
== nsGkAtoms::scrollbarFrame
) {
1941 // scrollbars may have had their width or height smashed to zero
1942 // by the associated scrollframe, in which case we must not report
1943 // any padding or border.
1944 nsSize
size(frame
->GetSize());
1945 if (size
.width
== 0 || size
.height
== 0) {
1946 mComputedPadding
.left
= 0;
1947 mComputedPadding
.right
= 0;
1948 mComputedBorderPadding
.left
= 0;
1949 mComputedBorderPadding
.right
= 0;
1950 mComputedPadding
.top
= 0;
1951 mComputedPadding
.bottom
= 0;
1952 mComputedBorderPadding
.top
= 0;
1953 mComputedBorderPadding
.bottom
= 0;
1958 // This code enforces section 10.3.3 of the CSS2 spec for this formula:
1960 // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' +
1961 // 'padding-right' + 'border-right-width' + 'margin-right'
1962 // = width of containing block
1964 // Note: the width unit is not auto when this is called
1966 nsHTMLReflowState::CalculateBlockSideMargins(nscoord aAvailWidth
,
1967 nscoord aComputedWidth
)
1969 NS_ASSERTION(NS_UNCONSTRAINEDSIZE
!= aComputedWidth
&&
1970 NS_UNCONSTRAINEDSIZE
!= aAvailWidth
,
1971 "this shouldn't happen anymore");
1973 nscoord sum
= mComputedMargin
.left
+ mComputedBorderPadding
.left
+
1974 aComputedWidth
+ mComputedBorderPadding
.right
+ mComputedMargin
.right
;
1975 if (sum
== aAvailWidth
)
1976 // The sum is already correct
1979 // Determine the left and right margin values. The width value
1980 // remains constant while we do this.
1982 // Calculate how much space is available for margins
1983 nscoord availMarginSpace
= aAvailWidth
- sum
;
1985 // If the available margin space is negative, then don't follow the
1986 // usual overconstraint rules.
1987 if (availMarginSpace
< 0) {
1988 if (mCBReflowState
&&
1989 mCBReflowState
->mStyleVisibility
->mDirection
== NS_STYLE_DIRECTION_RTL
) {
1990 mComputedMargin
.left
+= availMarginSpace
;
1992 mComputedMargin
.right
+= availMarginSpace
;
1997 // The css2 spec clearly defines how block elements should behave
1998 // in section 10.3.3.
1999 PRBool isAutoLeftMargin
=
2000 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetLeftUnit();
2001 PRBool isAutoRightMargin
=
2002 eStyleUnit_Auto
== mStyleMargin
->mMargin
.GetRightUnit();
2003 if (!isAutoLeftMargin
&& !isAutoRightMargin
) {
2004 // Neither margin is 'auto' so we're over constrained. Use the
2005 // 'direction' property of the parent to tell which margin to
2007 // First check if there is an HTML alignment that we should honor
2008 const nsHTMLReflowState
* prs
= parentReflowState
;
2009 if (frame
->GetType() == nsGkAtoms::tableFrame
) {
2010 NS_ASSERTION(prs
->frame
->GetType() == nsGkAtoms::tableOuterFrame
,
2011 "table not inside outer table");
2012 // Center the table within the outer table based on the alignment
2013 // of the outer table's parent.
2014 prs
= prs
->parentReflowState
;
2017 (prs
->mStyleText
->mTextAlign
== NS_STYLE_TEXT_ALIGN_MOZ_LEFT
||
2018 prs
->mStyleText
->mTextAlign
== NS_STYLE_TEXT_ALIGN_MOZ_CENTER
||
2019 prs
->mStyleText
->mTextAlign
== NS_STYLE_TEXT_ALIGN_MOZ_RIGHT
)) {
2021 prs
->mStyleText
->mTextAlign
!= NS_STYLE_TEXT_ALIGN_MOZ_LEFT
;
2023 prs
->mStyleText
->mTextAlign
!= NS_STYLE_TEXT_ALIGN_MOZ_RIGHT
;
2025 // Otherwise apply the CSS rules, and ignore one margin by forcing
2026 // it to 'auto', depending on 'direction'.
2027 else if (mCBReflowState
&&
2028 NS_STYLE_DIRECTION_RTL
== mCBReflowState
->mStyleVisibility
->mDirection
) {
2029 isAutoLeftMargin
= PR_TRUE
;
2032 isAutoRightMargin
= PR_TRUE
;
2036 // Logic which is common to blocks and tables
2037 // The computed margins need not be zero because the 'auto' could come from
2038 // overconstraint or from HTML alignment so values need to be accumulated
2040 if (isAutoLeftMargin
) {
2041 if (isAutoRightMargin
) {
2042 // Both margins are 'auto' so the computed addition should be equal
2043 nscoord forLeft
= availMarginSpace
/ 2;
2044 mComputedMargin
.left
+= forLeft
;
2045 mComputedMargin
.right
+= availMarginSpace
- forLeft
;
2047 mComputedMargin
.left
+= availMarginSpace
;
2049 } else if (isAutoRightMargin
) {
2050 mComputedMargin
.right
+= availMarginSpace
;
2054 #define NORMAL_LINE_HEIGHT_FACTOR 1.2f // in term of emHeight
2055 // For "normal" we use the font's normal line height (em height + leading).
2056 // If both internal leading and external leading specified by font itself
2057 // are zeros, we should compensate this by creating extra (external) leading
2058 // in eCompensateLeading mode. This is necessary because without this
2059 // compensation, normal line height might looks too tight.
2061 // For risk management, we use preference to control the behavior, and
2062 // eNoExternalLeading is the old behavior.
2064 GetNormalLineHeight(nsIFontMetrics
* aFontMetrics
)
2066 NS_PRECONDITION(nsnull
!= aFontMetrics
, "no font metrics");
2068 nscoord normalLineHeight
;
2070 nscoord externalLeading
, internalLeading
, emHeight
;
2071 aFontMetrics
->GetExternalLeading(externalLeading
);
2072 aFontMetrics
->GetInternalLeading(internalLeading
);
2073 aFontMetrics
->GetEmHeight(emHeight
);
2074 switch (GetNormalLineHeightCalcControl()) {
2075 case eIncludeExternalLeading
:
2076 normalLineHeight
= emHeight
+ internalLeading
+ externalLeading
;
2078 case eCompensateLeading
:
2079 if (!internalLeading
&& !externalLeading
)
2080 normalLineHeight
= NSToCoordRound(emHeight
* NORMAL_LINE_HEIGHT_FACTOR
);
2082 normalLineHeight
= emHeight
+ internalLeading
+ externalLeading
;
2085 //case eNoExternalLeading:
2086 normalLineHeight
= emHeight
+ internalLeading
;
2088 return normalLineHeight
;
2092 ComputeLineHeight(nsStyleContext
* aStyleContext
,
2093 nscoord aBlockHeight
)
2095 const nsStyleCoord
& lhCoord
= aStyleContext
->GetStyleText()->mLineHeight
;
2097 if (lhCoord
.GetUnit() == eStyleUnit_Coord
)
2098 return lhCoord
.GetCoordValue();
2100 if (lhCoord
.GetUnit() == eStyleUnit_Factor
)
2101 // For factor units the computed value of the line-height property
2102 // is found by multiplying the factor by the font's computed size
2103 // (adjusted for min-size prefs and text zoom).
2104 return NSToCoordRound(lhCoord
.GetFactorValue() *
2105 aStyleContext
->GetStyleFont()->mFont
.size
);
2107 NS_ASSERTION(lhCoord
.GetUnit() == eStyleUnit_Normal
||
2108 lhCoord
.GetUnit() == eStyleUnit_Enumerated
,
2109 "bad line-height unit");
2111 if (lhCoord
.GetUnit() == eStyleUnit_Enumerated
) {
2112 NS_ASSERTION(lhCoord
.GetIntValue() == NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT
,
2113 "bad line-height value");
2114 if (aBlockHeight
!= NS_AUTOHEIGHT
)
2115 return aBlockHeight
;
2118 nsCOMPtr
<nsIFontMetrics
> fm
;
2119 nsLayoutUtils::GetFontMetricsForStyleContext(aStyleContext
,
2120 getter_AddRefs(fm
));
2121 return GetNormalLineHeight(fm
);
2125 nsHTMLReflowState::CalcLineHeight() const
2127 nscoord blockHeight
=
2128 frame
->IsContainingBlock() ? mComputedHeight
:
2129 (mCBReflowState
? mCBReflowState
->mComputedHeight
: NS_AUTOHEIGHT
);
2131 return CalcLineHeight(frame
->GetStyleContext(), blockHeight
);
2134 /* static */ nscoord
2135 nsHTMLReflowState::CalcLineHeight(nsStyleContext
* aStyleContext
,
2136 nscoord aBlockHeight
)
2138 NS_PRECONDITION(aStyleContext
, "Must have a style context");
2140 nscoord lineHeight
= ComputeLineHeight(aStyleContext
, aBlockHeight
);
2142 NS_ASSERTION(lineHeight
>= 0, "ComputeLineHeight screwed up");
2149 nsCSSOffsetState::DestroyMarginFunc(void* aFrame
,
2150 nsIAtom
* aPropertyName
,
2151 void* aPropertyValue
,
2154 delete static_cast<nsMargin
*>(aPropertyValue
);
2158 nsCSSOffsetState::ComputeMargin(nscoord aContainingBlockWidth
)
2160 // If style style can provide us the margin directly, then use it.
2161 const nsStyleMargin
*styleMargin
= frame
->GetStyleMargin();
2162 if (!styleMargin
->GetMargin(mComputedMargin
)) {
2163 // We have to compute the value
2164 if (NS_UNCONSTRAINEDSIZE
== aContainingBlockWidth
) {
2165 mComputedMargin
.left
= 0;
2166 mComputedMargin
.right
= 0;
2168 if (eStyleUnit_Coord
== styleMargin
->mMargin
.GetLeftUnit()) {
2169 mComputedMargin
.left
= styleMargin
->mMargin
.GetLeft().GetCoordValue();
2171 if (eStyleUnit_Coord
== styleMargin
->mMargin
.GetRightUnit()) {
2172 mComputedMargin
.right
= styleMargin
->mMargin
.GetRight().GetCoordValue();
2176 mComputedMargin
.left
= nsLayoutUtils::
2177 ComputeWidthDependentValue(aContainingBlockWidth
,
2178 styleMargin
->mMargin
.GetLeft());
2179 mComputedMargin
.right
= nsLayoutUtils::
2180 ComputeWidthDependentValue(aContainingBlockWidth
,
2181 styleMargin
->mMargin
.GetRight());
2184 // According to the CSS2 spec, margin percentages are
2185 // calculated with respect to the *width* of the containing
2186 // block, even for margin-top and margin-bottom.
2187 // XXX This isn't true for page boxes, if we implement them.
2188 mComputedMargin
.top
= nsLayoutUtils::
2189 ComputeWidthDependentValue(aContainingBlockWidth
,
2190 styleMargin
->mMargin
.GetTop());
2191 mComputedMargin
.bottom
= nsLayoutUtils::
2192 ComputeWidthDependentValue(aContainingBlockWidth
,
2193 styleMargin
->mMargin
.GetBottom());
2195 // XXX We need to include 'auto' horizontal margins in this too!
2196 // ... but if we did that, we'd need to fix nsFrame::GetUsedMargin
2197 // to use it even when the margins are all zero (since sometimes
2198 // they get treated as auto)
2199 frame
->SetProperty(nsGkAtoms::usedMarginProperty
,
2200 new nsMargin(mComputedMargin
),
2206 nsCSSOffsetState::ComputePadding(nscoord aContainingBlockWidth
)
2208 // If style can provide us the padding directly, then use it.
2209 const nsStylePadding
*stylePadding
= frame
->GetStylePadding();
2210 if (!stylePadding
->GetPadding(mComputedPadding
)) {
2211 // We have to compute the value
2212 mComputedPadding
.left
= nsLayoutUtils::
2213 ComputeWidthDependentValue(aContainingBlockWidth
,
2214 stylePadding
->mPadding
.GetLeft());
2215 mComputedPadding
.right
= nsLayoutUtils::
2216 ComputeWidthDependentValue(aContainingBlockWidth
,
2217 stylePadding
->mPadding
.GetRight());
2219 // According to the CSS2 spec, percentages are calculated with respect to
2220 // containing block width for padding-top and padding-bottom
2221 mComputedPadding
.top
= nsLayoutUtils::
2222 ComputeWidthDependentValue(aContainingBlockWidth
,
2223 stylePadding
->mPadding
.GetTop());
2224 mComputedPadding
.bottom
= nsLayoutUtils::
2225 ComputeWidthDependentValue(aContainingBlockWidth
,
2226 stylePadding
->mPadding
.GetBottom());
2228 frame
->SetProperty(nsGkAtoms::usedPaddingProperty
,
2229 new nsMargin(mComputedPadding
),
2232 // a table row/col group, row/col doesn't have padding
2233 // XXXldb Neither do border-collapse tables.
2234 nsIAtom
* frameType
= frame
->GetType();
2235 if (nsGkAtoms::tableRowGroupFrame
== frameType
||
2236 nsGkAtoms::tableColGroupFrame
== frameType
||
2237 nsGkAtoms::tableRowFrame
== frameType
||
2238 nsGkAtoms::tableColFrame
== frameType
) {
2239 mComputedPadding
.top
= 0;
2240 mComputedPadding
.right
= 0;
2241 mComputedPadding
.bottom
= 0;
2242 mComputedPadding
.left
= 0;
2247 nsHTMLReflowState::ApplyMinMaxConstraints(nscoord
* aFrameWidth
,
2248 nscoord
* aFrameHeight
) const
2251 if (NS_UNCONSTRAINEDSIZE
!= mComputedMaxWidth
) {
2252 *aFrameWidth
= PR_MIN(*aFrameWidth
, mComputedMaxWidth
);
2254 *aFrameWidth
= PR_MAX(*aFrameWidth
, mComputedMinWidth
);
2258 if (NS_UNCONSTRAINEDSIZE
!= mComputedMaxHeight
) {
2259 *aFrameHeight
= PR_MIN(*aFrameHeight
, mComputedMaxHeight
);
2261 *aFrameHeight
= PR_MAX(*aFrameHeight
, mComputedMinHeight
);
2266 nsHTMLReflowState::ComputeMinMaxValues(nscoord aContainingBlockWidth
,
2267 nscoord aContainingBlockHeight
,
2268 const nsHTMLReflowState
* aContainingBlockRS
)
2270 mComputedMinWidth
= ComputeWidthValue(aContainingBlockWidth
,
2271 mStylePosition
->mBoxSizing
,
2272 mStylePosition
->mMinWidth
);
2274 if (eStyleUnit_None
== mStylePosition
->mMaxWidth
.GetUnit()) {
2275 // Specified value of 'none'
2276 mComputedMaxWidth
= NS_UNCONSTRAINEDSIZE
; // no limit
2278 mComputedMaxWidth
= ComputeWidthValue(aContainingBlockWidth
,
2279 mStylePosition
->mBoxSizing
,
2280 mStylePosition
->mMaxWidth
);
2283 // If the computed value of 'min-width' is greater than the value of
2284 // 'max-width', 'max-width' is set to the value of 'min-width'
2285 if (mComputedMinWidth
> mComputedMaxWidth
) {
2286 mComputedMaxWidth
= mComputedMinWidth
;
2289 // Check for percentage based values and a containing block height that
2290 // depends on the content height. Treat them like 'auto'
2291 if ((NS_AUTOHEIGHT
== aContainingBlockHeight
) &&
2292 (eStyleUnit_Percent
== mStylePosition
->mMinHeight
.GetUnit())) {
2293 mComputedMinHeight
= 0;
2295 mComputedMinHeight
= nsLayoutUtils::
2296 ComputeHeightDependentValue(aContainingBlockHeight
,
2297 mStylePosition
->mMinHeight
);
2299 nsStyleUnit maxHeightUnit
= mStylePosition
->mMaxHeight
.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 if ((NS_AUTOHEIGHT
== aContainingBlockHeight
) &&
2307 (eStyleUnit_Percent
== maxHeightUnit
)) {
2308 mComputedMaxHeight
= NS_UNCONSTRAINEDSIZE
;
2310 mComputedMaxHeight
= nsLayoutUtils::
2311 ComputeHeightDependentValue(aContainingBlockHeight
,
2312 mStylePosition
->mMaxHeight
);
2316 // If the computed value of 'min-height' is greater than the value of
2317 // 'max-height', 'max-height' is set to the value of 'min-height'
2318 if (mComputedMinHeight
> mComputedMaxHeight
) {
2319 mComputedMaxHeight
= mComputedMinHeight
;
2324 nsHTMLReflowState::SetTruncated(const nsHTMLReflowMetrics
& aMetrics
,
2325 nsReflowStatus
* aStatus
) const
2327 if (availableHeight
!= NS_UNCONSTRAINEDSIZE
&&
2328 availableHeight
< aMetrics
.height
&&
2329 !mFlags
.mIsTopOfPage
) {
2330 *aStatus
|= NS_FRAME_TRUNCATED
;
2332 *aStatus
&= ~NS_FRAME_TRUNCATED
;