Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /* struct containing the input to nsIFrame::Reflow */
7 :
8 : #include "mozilla/ReflowInput.h"
9 :
10 : #include "LayoutLogging.h"
11 : #include "nsStyleConsts.h"
12 : #include "nsCSSAnonBoxes.h"
13 : #include "nsFrame.h"
14 : #include "nsIContent.h"
15 : #include "nsGkAtoms.h"
16 : #include "nsPresContext.h"
17 : #include "nsIPresShell.h"
18 : #include "nsFontMetrics.h"
19 : #include "nsBlockFrame.h"
20 : #include "nsLineBox.h"
21 : #include "nsImageFrame.h"
22 : #include "nsTableFrame.h"
23 : #include "nsTableCellFrame.h"
24 : #include "nsIPercentBSizeObserver.h"
25 : #include "nsLayoutUtils.h"
26 : #include "mozilla/Preferences.h"
27 : #include "nsFontInflationData.h"
28 : #include "StickyScrollContainer.h"
29 : #include "nsIFrameInlines.h"
30 : #include "CounterStyleManager.h"
31 : #include <algorithm>
32 : #include "mozilla/dom/HTMLInputElement.h"
33 :
34 : #ifdef DEBUG
35 : #undef NOISY_VERTICAL_ALIGN
36 : #else
37 : #undef NOISY_VERTICAL_ALIGN
38 : #endif
39 :
40 : using namespace mozilla;
41 : using namespace mozilla::css;
42 : using namespace mozilla::dom;
43 : using namespace mozilla::layout;
44 :
45 : enum eNormalLineHeightControl {
46 : eUninitialized = -1,
47 : eNoExternalLeading = 0, // does not include external leading
48 : eIncludeExternalLeading, // use whatever value font vendor provides
49 : eCompensateLeading // compensate leading if leading provided by font vendor is not enough
50 : };
51 :
52 : static eNormalLineHeightControl sNormalLineHeightControl = eUninitialized;
53 :
54 : // Initialize a <b>root</b> reflow state with a rendering context to
55 : // use for measuring things.
56 200 : ReflowInput::ReflowInput(nsPresContext* aPresContext,
57 : nsIFrame* aFrame,
58 : gfxContext* aRenderingContext,
59 : const LogicalSize& aAvailableSpace,
60 200 : uint32_t aFlags)
61 : : SizeComputationInput(aFrame, aRenderingContext)
62 : , mBlockDelta(0)
63 : , mOrthogonalLimit(NS_UNCONSTRAINEDSIZE)
64 : , mContainingBlockSize(mWritingMode)
65 200 : , mReflowDepth(0)
66 : {
67 200 : NS_PRECONDITION(aRenderingContext, "no rendering context");
68 200 : MOZ_ASSERT(aPresContext, "no pres context");
69 200 : MOZ_ASSERT(aFrame, "no frame");
70 200 : MOZ_ASSERT(aPresContext == aFrame->PresContext(), "wrong pres context");
71 200 : mParentReflowInput = nullptr;
72 200 : AvailableISize() = aAvailableSpace.ISize(mWritingMode);
73 200 : AvailableBSize() = aAvailableSpace.BSize(mWritingMode);
74 200 : mFloatManager = nullptr;
75 200 : mLineLayout = nullptr;
76 200 : mDiscoveredClearance = nullptr;
77 200 : mPercentBSizeObserver = nullptr;
78 :
79 200 : if (aFlags & DUMMY_PARENT_REFLOW_STATE) {
80 126 : mFlags.mDummyParentReflowInput = true;
81 : }
82 200 : if (aFlags & COMPUTE_SIZE_SHRINK_WRAP) {
83 0 : mFlags.mShrinkWrap = true;
84 : }
85 200 : if (aFlags & COMPUTE_SIZE_USE_AUTO_BSIZE) {
86 0 : mFlags.mUseAutoBSize = true;
87 : }
88 200 : if (aFlags & STATIC_POS_IS_CB_ORIGIN) {
89 0 : mFlags.mStaticPosIsCBOrigin = true;
90 : }
91 200 : if (aFlags & I_CLAMP_MARGIN_BOX_MIN_SIZE) {
92 0 : mFlags.mIClampMarginBoxMinSize = true;
93 : }
94 200 : if (aFlags & B_CLAMP_MARGIN_BOX_MIN_SIZE) {
95 0 : mFlags.mBClampMarginBoxMinSize = true;
96 : }
97 200 : if (aFlags & I_APPLY_AUTO_MIN_SIZE) {
98 0 : mFlags.mApplyAutoMinSize = true;
99 : }
100 :
101 200 : if (!(aFlags & CALLER_WILL_INIT)) {
102 130 : Init(aPresContext);
103 : }
104 200 : }
105 :
106 0 : static bool CheckNextInFlowParenthood(nsIFrame* aFrame, nsIFrame* aParent)
107 : {
108 0 : nsIFrame* frameNext = aFrame->GetNextInFlow();
109 0 : nsIFrame* parentNext = aParent->GetNextInFlow();
110 0 : return frameNext && parentNext && frameNext->GetParent() == parentNext;
111 : }
112 :
113 : /**
114 : * Adjusts the margin for a list (ol, ul), if necessary, depending on
115 : * font inflation settings. Unfortunately, because bullets from a list are
116 : * placed in the margin area, we only have ~40px in which to place the
117 : * bullets. When they are inflated, however, this causes problems, since
118 : * the text takes up more space than is available in the margin.
119 : *
120 : * This method will return a small amount (in app units) by which the
121 : * margin can be adjusted, so that the space is available for list
122 : * bullets to be rendered with font inflation enabled.
123 : */
124 : static nscoord
125 652 : FontSizeInflationListMarginAdjustment(const nsIFrame* aFrame)
126 : {
127 652 : float inflation = nsLayoutUtils::FontSizeInflationFor(aFrame);
128 652 : if (aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
129 172 : const nsBlockFrame* blockFrame = static_cast<const nsBlockFrame*>(aFrame);
130 :
131 : // We only want to adjust the margins if we're dealing with an ordered
132 : // list.
133 172 : if (inflation > 1.0f &&
134 172 : blockFrame->HasBullet() &&
135 : inflation > 1.0f) {
136 :
137 0 : auto listStyleType = aFrame->StyleList()->mCounterStyle->GetStyle();
138 0 : if (listStyleType != NS_STYLE_LIST_STYLE_NONE &&
139 0 : listStyleType != NS_STYLE_LIST_STYLE_DISC &&
140 0 : listStyleType != NS_STYLE_LIST_STYLE_CIRCLE &&
141 0 : listStyleType != NS_STYLE_LIST_STYLE_SQUARE &&
142 0 : listStyleType != NS_STYLE_LIST_STYLE_DISCLOSURE_CLOSED &&
143 : listStyleType != NS_STYLE_LIST_STYLE_DISCLOSURE_OPEN) {
144 : // The HTML spec states that the default padding for ordered lists
145 : // begins at 40px, indicating that we have 40px of space to place a
146 : // bullet. When performing font inflation calculations, we add space
147 : // equivalent to this, but simply inflated at the same amount as the
148 : // text, in app units.
149 0 : return nsPresContext::CSSPixelsToAppUnits(40) * (inflation - 1);
150 : }
151 :
152 : }
153 : }
154 :
155 652 : return 0;
156 : }
157 :
158 : // NOTE: If we ever want to use SizeComputationInput for a flex item or a
159 : // grid item, we need to make it take the containing-block block-size as
160 : // well as the inline-size, since flex items and grid items resolve
161 : // block-direction percent margins and padding against the
162 : // containing-block block-size, rather than its inline-size.
163 0 : SizeComputationInput::SizeComputationInput(nsIFrame *aFrame,
164 : gfxContext *aRenderingContext,
165 : WritingMode aContainingBlockWritingMode,
166 0 : nscoord aContainingBlockISize)
167 : : mFrame(aFrame)
168 : , mRenderingContext(aRenderingContext)
169 0 : , mWritingMode(aFrame->GetWritingMode())
170 : {
171 0 : MOZ_ASSERT(!aFrame->IsFlexOrGridItem(),
172 : "We're about to resolve percent margin & padding "
173 : "values against CB inline size, which is incorrect for "
174 : "flex/grid items. "
175 : "Additionally for grid items, this path doesn't handle baseline "
176 : "padding contribution - see SizeComputationInput::InitOffsets");
177 : LogicalSize cbSize(aContainingBlockWritingMode, aContainingBlockISize,
178 0 : aContainingBlockISize);
179 0 : ReflowInputFlags flags;
180 0 : InitOffsets(aContainingBlockWritingMode, cbSize, mFrame->Type(), flags);
181 0 : }
182 :
183 : // Initialize a reflow state for a child frame's reflow. Some state
184 : // is copied from the parent reflow state; the remaining state is
185 : // computed.
186 523 : ReflowInput::ReflowInput(
187 : nsPresContext* aPresContext,
188 : const ReflowInput& aParentReflowInput,
189 : nsIFrame* aFrame,
190 : const LogicalSize& aAvailableSpace,
191 : const LogicalSize* aContainingBlockSize,
192 523 : uint32_t aFlags)
193 523 : : SizeComputationInput(aFrame, aParentReflowInput.mRenderingContext)
194 : , mBlockDelta(0)
195 : , mOrthogonalLimit(NS_UNCONSTRAINEDSIZE)
196 : , mContainingBlockSize(mWritingMode)
197 : , mFlags(aParentReflowInput.mFlags)
198 523 : , mReflowDepth(aParentReflowInput.mReflowDepth + 1)
199 : {
200 523 : MOZ_ASSERT(aPresContext, "no pres context");
201 523 : MOZ_ASSERT(aFrame, "no frame");
202 523 : MOZ_ASSERT(aPresContext == aFrame->PresContext(), "wrong pres context");
203 523 : NS_PRECONDITION(!mFlags.mSpecialBSizeReflow ||
204 : !NS_SUBTREE_DIRTY(aFrame),
205 : "frame should be clean when getting special bsize reflow");
206 :
207 523 : mParentReflowInput = &aParentReflowInput;
208 :
209 523 : AvailableISize() = aAvailableSpace.ISize(mWritingMode);
210 523 : AvailableBSize() = aAvailableSpace.BSize(mWritingMode);
211 :
212 523 : if (mWritingMode.IsOrthogonalTo(aParentReflowInput.GetWritingMode())) {
213 : // If we're setting up for an orthogonal flow, and the parent reflow state
214 : // had a constrained ComputedBSize, we can use that as our AvailableISize
215 : // in preference to leaving it unconstrained.
216 0 : if (AvailableISize() == NS_UNCONSTRAINEDSIZE &&
217 0 : aParentReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE) {
218 0 : AvailableISize() = aParentReflowInput.ComputedBSize();
219 : }
220 : }
221 :
222 523 : mFloatManager = aParentReflowInput.mFloatManager;
223 523 : if (mFrame->IsFrameOfType(nsIFrame::eLineParticipant))
224 9 : mLineLayout = aParentReflowInput.mLineLayout;
225 : else
226 514 : mLineLayout = nullptr;
227 :
228 : // Note: mFlags was initialized as a copy of aParentReflowInput.mFlags up in
229 : // this constructor's init list, so the only flags that we need to explicitly
230 : // initialize here are those that may need a value other than our parent's.
231 523 : mFlags.mNextInFlowUntouched = aParentReflowInput.mFlags.mNextInFlowUntouched &&
232 0 : CheckNextInFlowParenthood(aFrame, aParentReflowInput.mFrame);
233 523 : mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = false;
234 523 : mFlags.mIsColumnBalancing = false;
235 523 : mFlags.mIsFlexContainerMeasuringHeight = false;
236 523 : mFlags.mDummyParentReflowInput = false;
237 523 : mFlags.mShrinkWrap = !!(aFlags & COMPUTE_SIZE_SHRINK_WRAP);
238 523 : mFlags.mUseAutoBSize = !!(aFlags & COMPUTE_SIZE_USE_AUTO_BSIZE);
239 523 : mFlags.mStaticPosIsCBOrigin = !!(aFlags & STATIC_POS_IS_CB_ORIGIN);
240 523 : mFlags.mIOffsetsNeedCSSAlign = mFlags.mBOffsetsNeedCSSAlign = false;
241 523 : mFlags.mIClampMarginBoxMinSize = !!(aFlags & I_CLAMP_MARGIN_BOX_MIN_SIZE);
242 523 : mFlags.mBClampMarginBoxMinSize = !!(aFlags & B_CLAMP_MARGIN_BOX_MIN_SIZE);
243 523 : mFlags.mApplyAutoMinSize = !!(aFlags & I_APPLY_AUTO_MIN_SIZE);
244 :
245 523 : mDiscoveredClearance = nullptr;
246 1046 : mPercentBSizeObserver = (aParentReflowInput.mPercentBSizeObserver &&
247 0 : aParentReflowInput.mPercentBSizeObserver->NeedsToObserve(*this))
248 523 : ? aParentReflowInput.mPercentBSizeObserver : nullptr;
249 :
250 1046 : if ((aFlags & DUMMY_PARENT_REFLOW_STATE) ||
251 435 : (mParentReflowInput->mFlags.mDummyParentReflowInput &&
252 38 : mFrame->IsTableFrame())) {
253 126 : mFlags.mDummyParentReflowInput = true;
254 : }
255 :
256 523 : if (!(aFlags & CALLER_WILL_INIT)) {
257 360 : Init(aPresContext, aContainingBlockSize);
258 : }
259 523 : }
260 :
261 : inline nscoord
262 106 : SizeComputationInput::ComputeISizeValue(nscoord aContainingBlockISize,
263 : nscoord aContentEdgeToBoxSizing,
264 : nscoord aBoxSizingToMarginEdge,
265 : const nsStyleCoord& aCoord) const
266 : {
267 106 : return mFrame->ComputeISizeValue(mRenderingContext,
268 : aContainingBlockISize,
269 : aContentEdgeToBoxSizing,
270 : aBoxSizingToMarginEdge,
271 106 : aCoord);
272 : }
273 :
274 : nscoord
275 106 : SizeComputationInput::ComputeISizeValue(nscoord aContainingBlockISize,
276 : StyleBoxSizing aBoxSizing,
277 : const nsStyleCoord& aCoord) const
278 : {
279 106 : WritingMode wm = GetWritingMode();
280 212 : nscoord inside = 0, outside = ComputedLogicalBorderPadding().IStartEnd(wm) +
281 106 : ComputedLogicalMargin().IStartEnd(wm);
282 106 : if (aBoxSizing == StyleBoxSizing::Border) {
283 106 : inside = ComputedLogicalBorderPadding().IStartEnd(wm);
284 : }
285 106 : outside -= inside;
286 :
287 : return ComputeISizeValue(aContainingBlockISize, inside,
288 106 : outside, aCoord);
289 : }
290 :
291 : nscoord
292 92 : SizeComputationInput::ComputeBSizeValue(nscoord aContainingBlockBSize,
293 : StyleBoxSizing aBoxSizing,
294 : const nsStyleCoord& aCoord) const
295 : {
296 92 : WritingMode wm = GetWritingMode();
297 92 : nscoord inside = 0;
298 92 : if (aBoxSizing == StyleBoxSizing::Border) {
299 92 : inside = ComputedLogicalBorderPadding().BStartEnd(wm);
300 : }
301 : return nsLayoutUtils::ComputeBSizeValue(aContainingBlockBSize,
302 92 : inside, aCoord);
303 : }
304 :
305 : void
306 288 : ReflowInput::SetComputedWidth(nscoord aComputedWidth)
307 : {
308 288 : NS_ASSERTION(mFrame, "Must have a frame!");
309 : // It'd be nice to assert that |frame| is not in reflow, but this fails for
310 : // two reasons:
311 : //
312 : // 1) Viewport frames reset the computed width on a copy of their reflow
313 : // state when reflowing fixed-pos kids. In that case we actually don't
314 : // want to mess with the resize flags, because comparing the frame's rect
315 : // to the munged computed width is pointless.
316 : // 2) nsFrame::BoxReflow creates a reflow state for its parent. This reflow
317 : // state is not used to reflow the parent, but just as a parent for the
318 : // frame's own reflow state. So given a nsBoxFrame inside some non-XUL
319 : // (like a text control, for example), we'll end up creating a reflow
320 : // state for the parent while the parent is reflowing.
321 :
322 288 : NS_PRECONDITION(aComputedWidth >= 0, "Invalid computed width");
323 288 : if (ComputedWidth() != aComputedWidth) {
324 40 : ComputedWidth() = aComputedWidth;
325 40 : LayoutFrameType frameType = mFrame->Type();
326 40 : if (frameType != LayoutFrameType::Viewport || // Or check GetParent()?
327 0 : mWritingMode.IsVertical()) {
328 40 : InitResizeFlags(mFrame->PresContext(), frameType);
329 : }
330 : }
331 288 : }
332 :
333 : void
334 499 : ReflowInput::SetComputedHeight(nscoord aComputedHeight)
335 : {
336 499 : NS_ASSERTION(mFrame, "Must have a frame!");
337 : // It'd be nice to assert that |frame| is not in reflow, but this fails
338 : // because:
339 : //
340 : // nsFrame::BoxReflow creates a reflow state for its parent. This reflow
341 : // state is not used to reflow the parent, but just as a parent for the
342 : // frame's own reflow state. So given a nsBoxFrame inside some non-XUL
343 : // (like a text control, for example), we'll end up creating a reflow
344 : // state for the parent while the parent is reflowing.
345 :
346 499 : NS_PRECONDITION(aComputedHeight >= 0, "Invalid computed height");
347 499 : if (ComputedHeight() != aComputedHeight) {
348 317 : ComputedHeight() = aComputedHeight;
349 317 : LayoutFrameType frameType = mFrame->Type();
350 317 : if (frameType != LayoutFrameType::Viewport || !mWritingMode.IsVertical()) {
351 317 : InitResizeFlags(mFrame->PresContext(), frameType);
352 : }
353 : }
354 499 : }
355 :
356 : void
357 723 : ReflowInput::Init(nsPresContext* aPresContext,
358 : const LogicalSize* aContainingBlockSize,
359 : const nsMargin* aBorder,
360 : const nsMargin* aPadding)
361 : {
362 1099 : if ((mFrame->GetStateBits() & NS_FRAME_IS_DIRTY) &&
363 376 : !mFrame->IsXULBoxFrame()) {
364 : // Mark all child frames as dirty.
365 : //
366 : // We don't do this for XUL boxes because they handle their child
367 : // reflow separately.
368 : //
369 : // FIXME (bug 1376530): It would be better for memory locality if we
370 : // did this as we went. However, we need to be careful not to do
371 : // this twice for any particular child if we reflow it twice. The
372 : // easiest way to accomplish that is to do it at the start.
373 894 : for (nsIFrame::ChildListIterator childLists(mFrame);
374 629 : !childLists.IsDone(); childLists.Next()) {
375 383 : for (nsIFrame* childFrame : childLists.CurrentList()) {
376 201 : if (!childFrame->IsTableColGroupFrame()) {
377 201 : childFrame->AddStateBits(NS_FRAME_IS_DIRTY);
378 : }
379 : }
380 : }
381 : }
382 :
383 723 : if (AvailableISize() == NS_UNCONSTRAINEDSIZE) {
384 : // Look up the parent chain for an orthogonal inline limit,
385 : // and reset AvailableISize() if found.
386 0 : for (const ReflowInput *parent = mParentReflowInput;
387 0 : parent != nullptr; parent = parent->mParentReflowInput) {
388 0 : if (parent->GetWritingMode().IsOrthogonalTo(mWritingMode) &&
389 0 : parent->mOrthogonalLimit != NS_UNCONSTRAINEDSIZE) {
390 0 : AvailableISize() = parent->mOrthogonalLimit;
391 0 : break;
392 : }
393 : }
394 : }
395 :
396 723 : LAYOUT_WARN_IF_FALSE(AvailableISize() != NS_UNCONSTRAINEDSIZE,
397 : "have unconstrained inline-size; this should only "
398 : "result from very large sizes, not attempts at "
399 : "intrinsic inline-size calculation");
400 :
401 723 : mStylePosition = mFrame->StylePosition();
402 723 : mStyleDisplay = mFrame->StyleDisplay();
403 723 : mStyleVisibility = mFrame->StyleVisibility();
404 723 : mStyleBorder = mFrame->StyleBorder();
405 723 : mStyleMargin = mFrame->StyleMargin();
406 723 : mStylePadding = mFrame->StylePadding();
407 723 : mStyleText = mFrame->StyleText();
408 :
409 723 : LayoutFrameType type = mFrame->Type();
410 723 : if (type == mozilla::LayoutFrameType::Placeholder) {
411 : // Placeholders have a no-op Reflow method that doesn't need the rest of
412 : // this initialization, so we bail out early.
413 71 : ComputedBSize() = ComputedISize() = 0;
414 71 : return;
415 : }
416 :
417 652 : InitFrameType(type);
418 652 : InitCBReflowInput();
419 :
420 652 : LogicalSize cbSize(mWritingMode, -1, -1);
421 652 : if (aContainingBlockSize) {
422 77 : cbSize = *aContainingBlockSize;
423 : }
424 :
425 652 : InitConstraints(aPresContext, cbSize, aBorder, aPadding, type);
426 :
427 652 : InitResizeFlags(aPresContext, type);
428 :
429 652 : nsIFrame *parent = mFrame->GetParent();
430 1238 : if (parent &&
431 764 : (parent->GetStateBits() & NS_FRAME_IN_CONSTRAINED_BSIZE) &&
432 102 : !(parent->IsScrollFrame() &&
433 46 : parent->StyleDisplay()->mOverflowY != NS_STYLE_OVERFLOW_HIDDEN)) {
434 56 : mFrame->AddStateBits(NS_FRAME_IN_CONSTRAINED_BSIZE);
435 596 : } else if (type == LayoutFrameType::SVGForeignObject) {
436 : // An SVG foreignObject frame is inherently constrained block-size.
437 0 : mFrame->AddStateBits(NS_FRAME_IN_CONSTRAINED_BSIZE);
438 : } else {
439 596 : const nsStyleCoord& bSizeCoord = mStylePosition->BSize(mWritingMode);
440 596 : const nsStyleCoord& maxBSizeCoord = mStylePosition->MaxBSize(mWritingMode);
441 1734 : if ((bSizeCoord.GetUnit() != eStyleUnit_Auto ||
442 796 : maxBSizeCoord.GetUnit() != eStyleUnit_None) &&
443 : // Don't set NS_FRAME_IN_CONSTRAINED_BSIZE on body or html elements.
444 200 : (mFrame->GetContent() &&
445 100 : !(mFrame->GetContent()->IsAnyOfHTMLElements(nsGkAtoms::body,
446 : nsGkAtoms::html)))) {
447 :
448 : // If our block-size was specified as a percentage, then this could
449 : // actually resolve to 'auto', based on:
450 : // http://www.w3.org/TR/CSS21/visudet.html#the-height-property
451 100 : nsIFrame* containingBlk = mFrame;
452 116 : while (containingBlk) {
453 108 : const nsStylePosition* stylePos = containingBlk->StylePosition();
454 108 : const nsStyleCoord& bSizeCoord = stylePos->BSize(mWritingMode);
455 108 : const nsStyleCoord& maxBSizeCoord = stylePos->MaxBSize(mWritingMode);
456 270 : if ((bSizeCoord.IsCoordPercentCalcUnit() &&
457 262 : !bSizeCoord.HasPercent()) ||
458 108 : (maxBSizeCoord.IsCoordPercentCalcUnit() &&
459 46 : !maxBSizeCoord.HasPercent())) {
460 92 : mFrame->AddStateBits(NS_FRAME_IN_CONSTRAINED_BSIZE);
461 92 : break;
462 40 : } else if ((bSizeCoord.IsCoordPercentCalcUnit() &&
463 32 : bSizeCoord.HasPercent()) ||
464 8 : (maxBSizeCoord.IsCoordPercentCalcUnit() &&
465 0 : maxBSizeCoord.HasPercent())) {
466 8 : if (!(containingBlk = containingBlk->GetContainingBlock())) {
467 : // If we've reached the top of the tree, then we don't have
468 : // a constrained block-size.
469 0 : mFrame->RemoveStateBits(NS_FRAME_IN_CONSTRAINED_BSIZE);
470 0 : break;
471 : }
472 :
473 8 : continue;
474 : } else {
475 8 : mFrame->RemoveStateBits(NS_FRAME_IN_CONSTRAINED_BSIZE);
476 8 : break;
477 : }
478 : }
479 : } else {
480 496 : mFrame->RemoveStateBits(NS_FRAME_IN_CONSTRAINED_BSIZE);
481 : }
482 : }
483 :
484 2408 : if (mParentReflowInput &&
485 2008 : mParentReflowInput->GetWritingMode().IsOrthogonalTo(mWritingMode)) {
486 : // Orthogonal frames are always reflowed with an unconstrained
487 : // dimension to avoid incomplete reflow across an orthogonal
488 : // boundary. Normally this is the block-size, but for column sets
489 : // with auto-height it's the inline-size, so that they can add
490 : // columns in the container's block direction
491 0 : if (type == LayoutFrameType::ColumnSet &&
492 0 : eStyleUnit_Auto == mStylePosition->ISize(mWritingMode).GetUnit()) {
493 0 : ComputedISize() = NS_UNCONSTRAINEDSIZE;
494 : } else {
495 0 : AvailableBSize() = NS_UNCONSTRAINEDSIZE;
496 : }
497 : }
498 :
499 652 : LAYOUT_WARN_IF_FALSE((mFrameType == NS_CSS_FRAME_TYPE_INLINE &&
500 : !mFrame->IsFrameOfType(nsIFrame::eReplaced)) ||
501 : type == LayoutFrameType::Text ||
502 : ComputedISize() != NS_UNCONSTRAINEDSIZE,
503 : "have unconstrained inline-size; this should only "
504 : "result from very large sizes, not attempts at "
505 : "intrinsic inline-size calculation");
506 : }
507 :
508 652 : void ReflowInput::InitCBReflowInput()
509 : {
510 652 : if (!mParentReflowInput) {
511 200 : mCBReflowInput = nullptr;
512 200 : return;
513 : }
514 452 : if (mParentReflowInput->mFlags.mDummyParentReflowInput) {
515 93 : mCBReflowInput = mParentReflowInput;
516 93 : return;
517 : }
518 :
519 359 : if (mParentReflowInput->mFrame == mFrame->GetContainingBlock(0, mStyleDisplay)) {
520 : // Inner table frames need to use the containing block of the outer
521 : // table frame.
522 359 : if (mFrame->IsTableFrame()) {
523 0 : mCBReflowInput = mParentReflowInput->mCBReflowInput;
524 : } else {
525 359 : mCBReflowInput = mParentReflowInput;
526 : }
527 : } else {
528 0 : mCBReflowInput = mParentReflowInput->mCBReflowInput;
529 : }
530 : }
531 :
532 : /* Check whether CalcQuirkContainingBlockHeight would stop on the
533 : * given reflow state, using its block as a height. (essentially
534 : * returns false for any case in which CalcQuirkContainingBlockHeight
535 : * has a "continue" in its main loop.)
536 : *
537 : * XXX Maybe refactor CalcQuirkContainingBlockHeight so it uses
538 : * this function as well
539 : */
540 : static bool
541 0 : IsQuirkContainingBlockHeight(const ReflowInput* rs, LayoutFrameType aFrameType)
542 : {
543 0 : if (LayoutFrameType::Block == aFrameType ||
544 : #ifdef MOZ_XUL
545 0 : LayoutFrameType::XULLabel == aFrameType ||
546 : #endif
547 : LayoutFrameType::Scroll == aFrameType) {
548 : // Note: This next condition could change due to a style change,
549 : // but that would cause a style reflow anyway, which means we're ok.
550 0 : if (NS_AUTOHEIGHT == rs->ComputedHeight()) {
551 0 : if (!rs->mFrame->IsAbsolutelyPositioned(rs->mStyleDisplay)) {
552 0 : return false;
553 : }
554 : }
555 : }
556 0 : return true;
557 : }
558 :
559 : void
560 1009 : ReflowInput::InitResizeFlags(nsPresContext* aPresContext,
561 : LayoutFrameType aFrameType)
562 : {
563 1009 : SetBResize(false);
564 1009 : SetIResize(false);
565 :
566 1009 : const WritingMode wm = mWritingMode; // just a shorthand
567 : // We should report that we have a resize in the inline dimension if
568 : // *either* the border-box size or the content-box size in that
569 : // dimension has changed. It might not actually be necessary to do
570 : // this if the border-box size has changed and the content-box size
571 : // has not changed, but since we've historically used the flag to mean
572 : // border-box size change, continue to do that. (It's possible for
573 : // the content-box size to change without a border-box size change or
574 : // a style change given (1) a fixed width (possibly fixed by max-width
575 : // or min-width), (2) box-sizing:border-box or padding-box, and
576 : // (3) percentage padding.)
577 : //
578 : // However, we don't actually have the information at this point to
579 : // tell whether the content-box size has changed, since both style
580 : // data and the UsedPaddingProperty() have already been updated. So,
581 : // instead, we explicitly check for the case where it's possible for
582 : // the content-box size to have changed without either (a) a change in
583 : // the border-box size or (b) an nsChangeHint_NeedDirtyReflow change
584 : // hint due to change in border or padding. Thus we test using the
585 : // conditions from the previous paragraph, except without testing (1)
586 : // since it's complicated to test properly and less likely to help
587 : // with optimizing cases away.
588 : bool isIResize =
589 : // is the border-box resizing?
590 1009 : mFrame->ISize(wm) !=
591 5045 : ComputedISize() + ComputedLogicalBorderPadding().IStartEnd(wm) ||
592 : // or is the content-box resizing? (see comment above)
593 741 : (mStylePosition->mBoxSizing != StyleBoxSizing::Content &&
594 1196 : mStylePadding->IsWidthDependent());
595 :
596 1461 : if ((mFrame->GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT) &&
597 452 : nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
598 : // Create our font inflation data if we don't have it already, and
599 : // give it our current width information.
600 0 : bool dirty = nsFontInflationData::UpdateFontInflationDataISizeFor(*this) &&
601 : // Avoid running this at the box-to-block interface
602 : // (where we shouldn't be inflating anyway, and where
603 : // reflow state construction is probably to construct a
604 : // dummy parent reflow state anyway).
605 0 : !mFlags.mDummyParentReflowInput;
606 :
607 0 : if (dirty || (!mFrame->GetParent() && isIResize)) {
608 : // When font size inflation is enabled, a change in either:
609 : // * the effective width of a font inflation flow root
610 : // * the width of the frame
611 : // needs to cause a dirty reflow since they change the font size
612 : // inflation calculations, which in turn change the size of text,
613 : // line-heights, etc. This is relatively similar to a classic
614 : // case of style change reflow, except that because inflation
615 : // doesn't affect the intrinsic sizing codepath, there's no need
616 : // to invalidate intrinsic sizes.
617 : //
618 : // Note that this makes horizontal resizing a good bit more
619 : // expensive. However, font size inflation is targeted at a set of
620 : // devices (zoom-and-pan devices) where the main use case for
621 : // horizontal resizing needing to be efficient (window resizing) is
622 : // not present. It does still increase the cost of dynamic changes
623 : // caused by script where a style or content change in one place
624 : // causes a resize in another (e.g., rebalancing a table).
625 :
626 : // FIXME: This isn't so great for the cases where
627 : // ReflowInput::SetComputedWidth is called, if the first time
628 : // we go through InitResizeFlags we set IsHResize() to true, and then
629 : // the second time we'd set it to false even without the
630 : // NS_FRAME_IS_DIRTY bit already set.
631 0 : if (mFrame->IsSVGForeignObjectFrame()) {
632 : // Foreign object frames use dirty bits in a special way.
633 0 : mFrame->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
634 0 : nsIFrame *kid = mFrame->PrincipalChildList().FirstChild();
635 0 : if (kid) {
636 0 : kid->AddStateBits(NS_FRAME_IS_DIRTY);
637 : }
638 : } else {
639 0 : mFrame->AddStateBits(NS_FRAME_IS_DIRTY);
640 : }
641 :
642 : // Mark intrinsic widths on all descendants dirty. We need to do
643 : // this (1) since we're changing the size of text and need to
644 : // clear text runs on text frames and (2) since we actually are
645 : // changing some intrinsic widths, but only those that live inside
646 : // of containers.
647 :
648 : // It makes sense to do this for descendants but not ancestors
649 : // (which is unusual) because we're only changing the unusual
650 : // inflation-dependent intrinsic widths (i.e., ones computed with
651 : // nsPresContext::mInflationDisabledForShrinkWrap set to false),
652 : // which should never affect anything outside of their inflation
653 : // flow root (or, for that matter, even their inflation
654 : // container).
655 :
656 : // This is also different from what PresShell::FrameNeedsReflow
657 : // does because it doesn't go through placeholders. It doesn't
658 : // need to because we're actually doing something that cares about
659 : // frame tree geometry (the width on an ancestor) rather than
660 : // style.
661 :
662 0 : AutoTArray<nsIFrame*, 32> stack;
663 0 : stack.AppendElement(mFrame);
664 :
665 0 : do {
666 0 : nsIFrame *f = stack.ElementAt(stack.Length() - 1);
667 0 : stack.RemoveElementAt(stack.Length() - 1);
668 :
669 0 : nsIFrame::ChildListIterator lists(f);
670 0 : for (; !lists.IsDone(); lists.Next()) {
671 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
672 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
673 0 : nsIFrame* kid = childFrames.get();
674 0 : kid->MarkIntrinsicISizesDirty();
675 0 : stack.AppendElement(kid);
676 : }
677 : }
678 0 : } while (stack.Length() != 0);
679 : }
680 : }
681 :
682 1009 : SetIResize(!(mFrame->GetStateBits() & NS_FRAME_IS_DIRTY) &&
683 1009 : isIResize);
684 :
685 : // XXX Should we really need to null check mCBReflowInput? (We do for
686 : // at least nsBoxFrame).
687 2018 : if (IS_TABLE_CELL(aFrameType) &&
688 0 : (mFlags.mSpecialBSizeReflow ||
689 0 : (mFrame->FirstInFlow()->GetStateBits() &
690 1009 : NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) &&
691 0 : (mFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_BSIZE)) {
692 : // Need to set the bit on the cell so that
693 : // mCBReflowInput->IsBResize() is set correctly below when
694 : // reflowing descendant.
695 0 : SetBResize(true);
696 1009 : } else if (mCBReflowInput && mFrame->IsBlockWrapper()) {
697 : // XXX Is this problematic for relatively positioned inlines acting
698 : // as containing block for absolutely positioned elements?
699 : // Possibly; in that case we should at least be checking
700 : // NS_SUBTREE_DIRTY, I'd think.
701 0 : SetBResize(mCBReflowInput->IsBResizeForWM(wm));
702 1009 : } else if (mCBReflowInput && !nsLayoutUtils::GetAsBlock(mFrame)) {
703 : // Some non-block frames (e.g. table frames) aggressively optimize out their
704 : // BSize recomputation when they don't have the BResize flag set. This
705 : // means that if they go from having a computed non-auto height to having an
706 : // auto height and don't have that flag set, they will not actually compute
707 : // their auto height and will just remain at whatever size they already
708 : // were. We can end up in that situation if the child has a percentage
709 : // specified height and the parent changes from non-auto height to auto
710 : // height. When that happens, the parent will typically have the BResize
711 : // flag set, and we want to propagate that flag to the kid.
712 : //
713 : // Ideally it seems like we'd do this for blocks too, of course... but we'd
714 : // really want to restrict it to the percentage height case or something, to
715 : // avoid extra reflows in common cases. Maybe we should be examining
716 : // mStylePosition->BSize(wm).GetUnit() for that purpose?
717 : //
718 : // Note that we _also_ need to set the BResize flag if we have auto
719 : // ComputedBSize() and a dirty subtree, since that might require us to
720 : // change BSize due to kids having been added or removed.
721 531 : SetBResize(mCBReflowInput->IsBResizeForWM(wm));
722 531 : if (ComputedBSize() == NS_AUTOHEIGHT) {
723 298 : SetBResize(IsBResize() || NS_SUBTREE_DIRTY(mFrame));
724 : }
725 478 : } else if (ComputedBSize() == NS_AUTOHEIGHT) {
726 309 : if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() &&
727 26 : mCBReflowInput) {
728 18 : SetBResize(mCBReflowInput->IsBResizeForWM(wm));
729 : } else {
730 265 : SetBResize(IsIResize());
731 : }
732 283 : SetBResize(IsBResize() || NS_SUBTREE_DIRTY(mFrame));
733 : } else {
734 : // not 'auto' block-size
735 390 : SetBResize(mFrame->BSize(wm) !=
736 390 : ComputedBSize() + ComputedLogicalBorderPadding().BStartEnd(wm));
737 : }
738 :
739 : bool dependsOnCBBSize =
740 1958 : (mStylePosition->BSizeDependsOnContainer(wm) &&
741 : // FIXME: condition this on not-abspos?
742 1950 : mStylePosition->BSize(wm).GetUnit() != eStyleUnit_Auto) ||
743 2002 : mStylePosition->MinBSizeDependsOnContainer(wm) ||
744 2002 : mStylePosition->MaxBSizeDependsOnContainer(wm) ||
745 2000 : mStylePosition->OffsetHasPercent(wm.PhysicalSide(eLogicalSideBStart)) ||
746 3007 : mStylePosition->mOffset.GetBEndUnit(wm) != eStyleUnit_Auto ||
747 2008 : mFrame->IsXULBoxFrame();
748 :
749 1009 : if (mStyleText->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
750 189 : NS_ASSERTION(mStyleText->mLineHeight.GetIntValue() ==
751 : NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT,
752 : "bad line-height value");
753 :
754 : // line-height depends on block bsize
755 189 : mFrame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
756 : // but only on containing blocks if this frame is not a suitable block
757 189 : dependsOnCBBSize |= !nsLayoutUtils::IsNonWrapperBlock(mFrame);
758 : }
759 :
760 : // If we're the descendant of a table cell that performs special bsize
761 : // reflows and we could be the child that requires them, always set
762 : // the block-axis resize in case this is the first pass before the
763 : // special bsize reflow. However, don't do this if it actually is
764 : // the special bsize reflow, since in that case it will already be
765 : // set correctly above if we need it set.
766 2573 : if (!IsBResize() && mCBReflowInput &&
767 460 : (IS_TABLE_CELL(mCBReflowInput->mFrame->Type()) ||
768 230 : mCBReflowInput->mFlags.mHeightDependsOnAncestorCell) &&
769 1009 : !mCBReflowInput->mFlags.mSpecialBSizeReflow &&
770 : dependsOnCBBSize) {
771 0 : SetBResize(true);
772 0 : mFlags.mHeightDependsOnAncestorCell = true;
773 : }
774 :
775 : // Set NS_FRAME_CONTAINS_RELATIVE_BSIZE if it's needed.
776 :
777 : // It would be nice to check that |ComputedBSize != NS_AUTOHEIGHT|
778 : // &&ed with the percentage bsize check. However, this doesn't get
779 : // along with table special bsize reflows, since a special bsize
780 : // reflow (a quirk that makes such percentage height work on children
781 : // of table cells) can cause not just a single percentage height to
782 : // become fixed, but an entire descendant chain of percentage height
783 : // to become fixed.
784 1009 : if (dependsOnCBBSize && mCBReflowInput) {
785 189 : const ReflowInput *rs = this;
786 189 : bool hitCBReflowInput = false;
787 29 : do {
788 189 : rs = rs->mParentReflowInput;
789 189 : if (!rs) {
790 0 : break;
791 : }
792 :
793 189 : if (rs->mFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_BSIZE)
794 160 : break; // no need to go further
795 29 : rs->mFrame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
796 :
797 : // Keep track of whether we've hit the containing block, because
798 : // we need to go at least that far.
799 29 : if (rs == mCBReflowInput) {
800 29 : hitCBReflowInput = true;
801 : }
802 :
803 : // XXX What about orthogonal flows? It doesn't make sense to
804 : // keep propagating this bit across an orthogonal boundary,
805 : // where the meaning of BSize changes. Bug 1175517.
806 58 : } while (!hitCBReflowInput ||
807 29 : (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() &&
808 0 : !IsQuirkContainingBlockHeight(rs, rs->mFrame->Type())));
809 : // Note: We actually don't need to set the
810 : // NS_FRAME_CONTAINS_RELATIVE_BSIZE bit for the cases
811 : // where we hit the early break statements in
812 : // CalcQuirkContainingBlockHeight. But it doesn't hurt
813 : // us to set the bit in these cases.
814 :
815 : }
816 1009 : if (mFrame->GetStateBits() & NS_FRAME_IS_DIRTY) {
817 : // If we're reflowing everything, then we'll find out if we need
818 : // to re-set this.
819 482 : mFrame->RemoveStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
820 : }
821 1009 : }
822 :
823 : nscoord
824 0 : ReflowInput::GetContainingBlockContentISize(WritingMode aWritingMode) const
825 : {
826 0 : if (!mCBReflowInput) {
827 0 : return 0;
828 : }
829 0 : return mCBReflowInput->GetWritingMode().IsOrthogonalTo(aWritingMode)
830 0 : ? mCBReflowInput->ComputedBSize()
831 0 : : mCBReflowInput->ComputedISize();
832 : }
833 :
834 : void
835 652 : ReflowInput::InitFrameType(LayoutFrameType aFrameType)
836 : {
837 652 : const nsStyleDisplay *disp = mStyleDisplay;
838 : nsCSSFrameType frameType;
839 :
840 : // Section 9.7 of the CSS2 spec indicates that absolute position
841 : // takes precedence over float which takes precedence over display.
842 : // XXXldb nsRuleNode::ComputeDisplayData should take care of this, right?
843 : // Make sure the frame was actually moved out of the flow, and don't
844 : // just assume what the style says, because we might not have had a
845 : // useful float/absolute containing block
846 :
847 1304 : DISPLAY_INIT_TYPE(mFrame, this);
848 :
849 652 : if (aFrameType == LayoutFrameType::Table) {
850 0 : mFrameType = NS_CSS_FRAME_TYPE_BLOCK;
851 0 : return;
852 : }
853 :
854 652 : NS_ASSERTION(mFrame->StyleDisplay()->IsAbsolutelyPositionedStyle() ==
855 : disp->IsAbsolutelyPositionedStyle(),
856 : "Unexpected position style");
857 652 : NS_ASSERTION(mFrame->StyleDisplay()->IsFloatingStyle() ==
858 : disp->IsFloatingStyle(), "Unexpected float style");
859 652 : if (mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
860 77 : if (disp->IsAbsolutelyPositioned(mFrame)) {
861 77 : frameType = NS_CSS_FRAME_TYPE_ABSOLUTE;
862 : //XXXfr hack for making frames behave properly when in overflow container lists
863 : // see bug 154892; need to revisit later
864 77 : if (mFrame->GetPrevInFlow())
865 0 : frameType = NS_CSS_FRAME_TYPE_BLOCK;
866 : }
867 0 : else if (disp->IsFloating(mFrame)) {
868 0 : frameType = NS_CSS_FRAME_TYPE_FLOATING;
869 : } else {
870 0 : NS_ASSERTION(disp->mDisplay == StyleDisplay::MozPopup,
871 : "unknown out of flow frame type");
872 0 : frameType = NS_CSS_FRAME_TYPE_UNKNOWN;
873 : }
874 : }
875 : else {
876 575 : switch (GetDisplay()) {
877 : case StyleDisplay::Block:
878 : case StyleDisplay::ListItem:
879 : case StyleDisplay::Table:
880 : case StyleDisplay::TableCaption:
881 : case StyleDisplay::Flex:
882 : case StyleDisplay::WebkitBox:
883 : case StyleDisplay::Grid:
884 : case StyleDisplay::FlowRoot:
885 : case StyleDisplay::RubyTextContainer:
886 358 : frameType = NS_CSS_FRAME_TYPE_BLOCK;
887 358 : break;
888 :
889 : case StyleDisplay::Inline:
890 : case StyleDisplay::InlineBlock:
891 : case StyleDisplay::InlineTable:
892 : case StyleDisplay::MozInlineBox:
893 : case StyleDisplay::MozInlineGrid:
894 : case StyleDisplay::MozInlineStack:
895 : case StyleDisplay::InlineFlex:
896 : case StyleDisplay::WebkitInlineBox:
897 : case StyleDisplay::InlineGrid:
898 : case StyleDisplay::Ruby:
899 : case StyleDisplay::RubyBase:
900 : case StyleDisplay::RubyText:
901 : case StyleDisplay::RubyBaseContainer:
902 71 : frameType = NS_CSS_FRAME_TYPE_INLINE;
903 71 : break;
904 :
905 : case StyleDisplay::TableCell:
906 : case StyleDisplay::TableRowGroup:
907 : case StyleDisplay::TableColumn:
908 : case StyleDisplay::TableColumnGroup:
909 : case StyleDisplay::TableHeaderGroup:
910 : case StyleDisplay::TableFooterGroup:
911 : case StyleDisplay::TableRow:
912 0 : frameType = NS_CSS_FRAME_TYPE_INTERNAL_TABLE;
913 0 : break;
914 :
915 : case StyleDisplay::None:
916 : default:
917 146 : frameType = NS_CSS_FRAME_TYPE_UNKNOWN;
918 146 : break;
919 : }
920 : }
921 :
922 : // See if the frame is replaced
923 652 : if (mFrame->IsFrameOfType(nsIFrame::eReplacedContainsBlock)) {
924 166 : frameType = NS_FRAME_REPLACED_CONTAINS_BLOCK(frameType);
925 486 : } else if (mFrame->IsFrameOfType(nsIFrame::eReplaced)) {
926 9 : frameType = NS_FRAME_REPLACED(frameType);
927 : }
928 :
929 652 : mFrameType = frameType;
930 : }
931 :
932 : /* static */ void
933 0 : ReflowInput::ComputeRelativeOffsets(WritingMode aWM,
934 : nsIFrame* aFrame,
935 : const LogicalSize& aCBSize,
936 : nsMargin& aComputedOffsets)
937 : {
938 0 : LogicalMargin offsets(aWM);
939 0 : mozilla::Side inlineStart = aWM.PhysicalSide(eLogicalSideIStart);
940 0 : mozilla::Side inlineEnd = aWM.PhysicalSide(eLogicalSideIEnd);
941 0 : mozilla::Side blockStart = aWM.PhysicalSide(eLogicalSideBStart);
942 0 : mozilla::Side blockEnd = aWM.PhysicalSide(eLogicalSideBEnd);
943 :
944 0 : const nsStylePosition* position = aFrame->StylePosition();
945 :
946 : // Compute the 'inlineStart' and 'inlineEnd' values. 'inlineStart'
947 : // moves the boxes to the end of the line, and 'inlineEnd' moves the
948 : // boxes to the start of the line. The computed values are always:
949 : // inlineStart=-inlineEnd
950 : bool inlineStartIsAuto =
951 0 : eStyleUnit_Auto == position->mOffset.GetUnit(inlineStart);
952 : bool inlineEndIsAuto =
953 0 : eStyleUnit_Auto == position->mOffset.GetUnit(inlineEnd);
954 :
955 : // If neither 'inlineStart' nor 'inlineEnd' is auto, then we're
956 : // over-constrained and we ignore one of them
957 0 : if (!inlineStartIsAuto && !inlineEndIsAuto) {
958 0 : inlineEndIsAuto = true;
959 : }
960 :
961 0 : if (inlineStartIsAuto) {
962 0 : if (inlineEndIsAuto) {
963 : // If both are 'auto' (their initial values), the computed values are 0
964 0 : offsets.IStart(aWM) = offsets.IEnd(aWM) = 0;
965 : } else {
966 : // 'inlineEnd' isn't 'auto' so compute its value
967 0 : offsets.IEnd(aWM) = nsLayoutUtils::
968 0 : ComputeCBDependentValue(aCBSize.ISize(aWM),
969 0 : position->mOffset.Get(inlineEnd));
970 :
971 : // Computed value for 'inlineStart' is minus the value of 'inlineEnd'
972 0 : offsets.IStart(aWM) = -offsets.IEnd(aWM);
973 : }
974 :
975 : } else {
976 0 : NS_ASSERTION(inlineEndIsAuto, "unexpected specified constraint");
977 :
978 : // 'InlineStart' isn't 'auto' so compute its value
979 0 : offsets.IStart(aWM) = nsLayoutUtils::
980 0 : ComputeCBDependentValue(aCBSize.ISize(aWM),
981 0 : position->mOffset.Get(inlineStart));
982 :
983 : // Computed value for 'inlineEnd' is minus the value of 'inlineStart'
984 0 : offsets.IEnd(aWM) = -offsets.IStart(aWM);
985 : }
986 :
987 : // Compute the 'blockStart' and 'blockEnd' values. The 'blockStart'
988 : // and 'blockEnd' properties move relatively positioned elements in
989 : // the block progression direction. They also must be each other's
990 : // negative
991 : bool blockStartIsAuto =
992 0 : eStyleUnit_Auto == position->mOffset.GetUnit(blockStart);
993 : bool blockEndIsAuto =
994 0 : eStyleUnit_Auto == position->mOffset.GetUnit(blockEnd);
995 :
996 : // Check for percentage based values and a containing block block-size
997 : // that depends on the content block-size. Treat them like 'auto'
998 0 : if (NS_AUTOHEIGHT == aCBSize.BSize(aWM)) {
999 0 : if (position->OffsetHasPercent(blockStart)) {
1000 0 : blockStartIsAuto = true;
1001 : }
1002 0 : if (position->OffsetHasPercent(blockEnd)) {
1003 0 : blockEndIsAuto = true;
1004 : }
1005 : }
1006 :
1007 : // If neither is 'auto', 'block-end' is ignored
1008 0 : if (!blockStartIsAuto && !blockEndIsAuto) {
1009 0 : blockEndIsAuto = true;
1010 : }
1011 :
1012 0 : if (blockStartIsAuto) {
1013 0 : if (blockEndIsAuto) {
1014 : // If both are 'auto' (their initial values), the computed values are 0
1015 0 : offsets.BStart(aWM) = offsets.BEnd(aWM) = 0;
1016 : } else {
1017 : // 'blockEnd' isn't 'auto' so compute its value
1018 0 : offsets.BEnd(aWM) = nsLayoutUtils::
1019 0 : ComputeBSizeDependentValue(aCBSize.BSize(aWM),
1020 0 : position->mOffset.Get(blockEnd));
1021 :
1022 : // Computed value for 'blockStart' is minus the value of 'blockEnd'
1023 0 : offsets.BStart(aWM) = -offsets.BEnd(aWM);
1024 : }
1025 :
1026 : } else {
1027 0 : NS_ASSERTION(blockEndIsAuto, "unexpected specified constraint");
1028 :
1029 : // 'blockStart' isn't 'auto' so compute its value
1030 0 : offsets.BStart(aWM) = nsLayoutUtils::
1031 0 : ComputeBSizeDependentValue(aCBSize.BSize(aWM),
1032 0 : position->mOffset.Get(blockStart));
1033 :
1034 : // Computed value for 'blockEnd' is minus the value of 'blockStart'
1035 0 : offsets.BEnd(aWM) = -offsets.BStart(aWM);
1036 : }
1037 :
1038 : // Convert the offsets to physical coordinates and store them on the frame
1039 0 : aComputedOffsets = offsets.GetPhysicalMargin(aWM);
1040 : nsMargin* physicalOffsets =
1041 0 : aFrame->GetProperty(nsIFrame::ComputedOffsetProperty());
1042 0 : if (physicalOffsets) {
1043 0 : *physicalOffsets = aComputedOffsets;
1044 : } else {
1045 0 : aFrame->AddProperty(nsIFrame::ComputedOffsetProperty(),
1046 0 : new nsMargin(aComputedOffsets));
1047 : }
1048 0 : }
1049 :
1050 : /* static */ void
1051 55 : ReflowInput::ApplyRelativePositioning(nsIFrame* aFrame,
1052 : const nsMargin& aComputedOffsets,
1053 : nsPoint* aPosition)
1054 : {
1055 55 : if (!aFrame->IsRelativelyPositioned()) {
1056 55 : NS_ASSERTION(!aFrame->GetProperty(nsIFrame::NormalPositionProperty()),
1057 : "We assume that changing the 'position' property causes "
1058 : "frame reconstruction. If that ever changes, this code "
1059 : "should call "
1060 : "aFrame->DeleteProperty(nsIFrame::NormalPositionProperty())");
1061 55 : return;
1062 : }
1063 :
1064 : // Store the normal position
1065 : nsPoint* normalPosition =
1066 0 : aFrame->GetProperty(nsIFrame::NormalPositionProperty());
1067 0 : if (normalPosition) {
1068 0 : *normalPosition = *aPosition;
1069 : } else {
1070 0 : aFrame->AddProperty(nsIFrame::NormalPositionProperty(),
1071 0 : new nsPoint(*aPosition));
1072 : }
1073 :
1074 0 : const nsStyleDisplay* display = aFrame->StyleDisplay();
1075 0 : if (NS_STYLE_POSITION_RELATIVE == display->mPosition) {
1076 0 : *aPosition += nsPoint(aComputedOffsets.left, aComputedOffsets.top);
1077 0 : } else if (NS_STYLE_POSITION_STICKY == display->mPosition &&
1078 0 : !aFrame->GetNextContinuation() &&
1079 0 : !aFrame->GetPrevContinuation() &&
1080 0 : !(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
1081 : // Sticky positioning for elements with multiple frames needs to be
1082 : // computed all at once. We can't safely do that here because we might be
1083 : // partway through (re)positioning the frames, so leave it until the scroll
1084 : // container reflows and calls StickyScrollContainer::UpdatePositions.
1085 : // For single-frame sticky positioned elements, though, go ahead and apply
1086 : // it now to avoid unnecessary overflow updates later.
1087 : StickyScrollContainer* ssc =
1088 0 : StickyScrollContainer::GetStickyScrollContainerForFrame(aFrame);
1089 0 : if (ssc) {
1090 0 : *aPosition = ssc->ComputePosition(aFrame);
1091 : }
1092 : }
1093 : }
1094 :
1095 : nsIFrame*
1096 77 : ReflowInput::GetHypotheticalBoxContainer(nsIFrame* aFrame,
1097 : nscoord& aCBIStartEdge,
1098 : LogicalSize& aCBSize) const
1099 : {
1100 77 : aFrame = aFrame->GetContainingBlock();
1101 77 : NS_ASSERTION(aFrame != mFrame, "How did that happen?");
1102 :
1103 : /* Now aFrame is the containing block we want */
1104 :
1105 : /* Check whether the containing block is currently being reflowed.
1106 : If so, use the info from the reflow state. */
1107 : const ReflowInput* state;
1108 77 : if (aFrame->GetStateBits() & NS_FRAME_IN_REFLOW) {
1109 0 : for (state = mParentReflowInput; state && state->mFrame != aFrame;
1110 0 : state = state->mParentReflowInput) {
1111 : /* do nothing */
1112 : }
1113 : } else {
1114 77 : state = nullptr;
1115 : }
1116 :
1117 77 : if (state) {
1118 0 : WritingMode wm = state->GetWritingMode();
1119 0 : NS_ASSERTION(wm == aFrame->GetWritingMode(), "unexpected writing mode");
1120 0 : aCBIStartEdge = state->ComputedLogicalBorderPadding().IStart(wm);
1121 0 : aCBSize = state->ComputedSize(wm);
1122 : } else {
1123 : /* Didn't find a reflow state for aFrame. Just compute the information we
1124 : want, on the assumption that aFrame already knows its size. This really
1125 : ought to be true by now. */
1126 77 : NS_ASSERTION(!(aFrame->GetStateBits() & NS_FRAME_IN_REFLOW),
1127 : "aFrame shouldn't be in reflow; we'll lie if it is");
1128 77 : WritingMode wm = aFrame->GetWritingMode();
1129 77 : LogicalMargin borderPadding = aFrame->GetLogicalUsedBorderAndPadding(wm);
1130 77 : aCBIStartEdge = borderPadding.IStart(wm);
1131 77 : aCBSize = aFrame->GetLogicalSize(wm) - borderPadding.Size(wm);
1132 : }
1133 :
1134 77 : return aFrame;
1135 : }
1136 :
1137 77 : struct nsHypotheticalPosition {
1138 : // offset from inline-start edge of containing block (which is a padding edge)
1139 : nscoord mIStart;
1140 : // offset from block-start edge of containing block (which is a padding edge)
1141 : nscoord mBStart;
1142 : WritingMode mWritingMode;
1143 : };
1144 :
1145 : static bool
1146 0 : GetIntrinsicSizeFor(nsIFrame* aFrame,
1147 : nsSize& aIntrinsicSize,
1148 : LayoutFrameType aFrameType)
1149 : {
1150 : // See if it is an image frame
1151 0 : bool success = false;
1152 :
1153 : // Currently the only type of replaced frame that we can get the intrinsic
1154 : // size for is an image frame
1155 : // XXX We should add back the GetReflowOutput() function and one of the
1156 : // things should be the intrinsic size...
1157 0 : if (aFrameType == LayoutFrameType::Image) {
1158 0 : nsImageFrame* imageFrame = (nsImageFrame*)aFrame;
1159 :
1160 0 : if (NS_SUCCEEDED(imageFrame->GetIntrinsicImageSize(aIntrinsicSize))) {
1161 0 : success = (aIntrinsicSize != nsSize(0, 0));
1162 : }
1163 : }
1164 0 : return success;
1165 : }
1166 :
1167 : /**
1168 : * aInsideBoxSizing returns the part of the padding, border, and margin
1169 : * in the aAxis dimension that goes inside the edge given by box-sizing;
1170 : * aOutsideBoxSizing returns the rest.
1171 : */
1172 : void
1173 77 : ReflowInput::CalculateBorderPaddingMargin(
1174 : LogicalAxis aAxis,
1175 : nscoord aContainingBlockSize,
1176 : nscoord* aInsideBoxSizing,
1177 : nscoord* aOutsideBoxSizing) const
1178 : {
1179 77 : WritingMode wm = GetWritingMode();
1180 : mozilla::Side startSide =
1181 77 : wm.PhysicalSide(MakeLogicalSide(aAxis, eLogicalEdgeStart));
1182 : mozilla::Side endSide =
1183 77 : wm.PhysicalSide(MakeLogicalSide(aAxis, eLogicalEdgeEnd));
1184 :
1185 77 : nsMargin styleBorder = mStyleBorder->GetComputedBorder();
1186 : nscoord borderStartEnd =
1187 77 : styleBorder.Side(startSide) + styleBorder.Side(endSide);
1188 :
1189 : nscoord paddingStartEnd, marginStartEnd;
1190 :
1191 : // See if the style system can provide us the padding directly
1192 77 : nsMargin stylePadding;
1193 77 : if (mStylePadding->GetPadding(stylePadding)) {
1194 77 : paddingStartEnd =
1195 77 : stylePadding.Side(startSide) + stylePadding.Side(endSide);
1196 : } else {
1197 : // We have to compute the start and end values
1198 : nscoord start, end;
1199 : start = nsLayoutUtils::
1200 : ComputeCBDependentValue(aContainingBlockSize,
1201 0 : mStylePadding->mPadding.Get(startSide));
1202 : end = nsLayoutUtils::
1203 : ComputeCBDependentValue(aContainingBlockSize,
1204 0 : mStylePadding->mPadding.Get(endSide));
1205 0 : paddingStartEnd = start + end;
1206 : }
1207 :
1208 : // See if the style system can provide us the margin directly
1209 77 : nsMargin styleMargin;
1210 77 : if (mStyleMargin->GetMargin(styleMargin)) {
1211 77 : marginStartEnd =
1212 77 : styleMargin.Side(startSide) + styleMargin.Side(endSide);
1213 : } else {
1214 : nscoord start, end;
1215 : // We have to compute the start and end values
1216 0 : if (eStyleUnit_Auto == mStyleMargin->mMargin.GetUnit(startSide)) {
1217 : // XXX FIXME (or does CalculateBlockSideMargins do this?)
1218 0 : start = 0; // just ignore
1219 : } else {
1220 : start = nsLayoutUtils::
1221 : ComputeCBDependentValue(aContainingBlockSize,
1222 0 : mStyleMargin->mMargin.Get(startSide));
1223 : }
1224 0 : if (eStyleUnit_Auto == mStyleMargin->mMargin.GetUnit(endSide)) {
1225 : // XXX FIXME (or does CalculateBlockSideMargins do this?)
1226 0 : end = 0; // just ignore
1227 : } else {
1228 : end = nsLayoutUtils::
1229 : ComputeCBDependentValue(aContainingBlockSize,
1230 0 : mStyleMargin->mMargin.Get(endSide));
1231 : }
1232 0 : marginStartEnd = start + end;
1233 : }
1234 :
1235 77 : nscoord outside = paddingStartEnd + borderStartEnd + marginStartEnd;
1236 77 : nscoord inside = 0;
1237 77 : if (mStylePosition->mBoxSizing == StyleBoxSizing::Border) {
1238 77 : inside = borderStartEnd + paddingStartEnd;
1239 : }
1240 77 : outside -= inside;
1241 77 : *aInsideBoxSizing = inside;
1242 77 : *aOutsideBoxSizing = outside;
1243 77 : return;
1244 : }
1245 :
1246 : /**
1247 : * Returns true iff a pre-order traversal of the normal child
1248 : * frames rooted at aFrame finds no non-empty frame before aDescendant.
1249 : */
1250 : static bool
1251 0 : AreAllEarlierInFlowFramesEmpty(nsIFrame* aFrame,
1252 : nsIFrame* aDescendant,
1253 : bool* aFound)
1254 : {
1255 0 : if (aFrame == aDescendant) {
1256 0 : *aFound = true;
1257 0 : return true;
1258 : }
1259 0 : if (aFrame->IsPlaceholderFrame()) {
1260 0 : auto ph = static_cast<nsPlaceholderFrame*>(aFrame);
1261 0 : MOZ_ASSERT(ph->IsSelfEmpty() && ph->PrincipalChildList().IsEmpty());
1262 0 : ph->SetLineIsEmptySoFar(true);
1263 : } else {
1264 0 : if (!aFrame->IsSelfEmpty()) {
1265 0 : *aFound = false;
1266 0 : return false;
1267 : }
1268 0 : for (nsIFrame* f : aFrame->PrincipalChildList()) {
1269 0 : bool allEmpty = AreAllEarlierInFlowFramesEmpty(f, aDescendant, aFound);
1270 0 : if (*aFound || !allEmpty) {
1271 0 : return allEmpty;
1272 : }
1273 : }
1274 : }
1275 0 : *aFound = false;
1276 0 : return true;
1277 : }
1278 :
1279 : // Calculate the position of the hypothetical box that the element would have
1280 : // if it were in the flow.
1281 : // The values returned are relative to the padding edge of the absolute
1282 : // containing block. The writing-mode of the hypothetical box position will
1283 : // have the same block direction as the absolute containing block, but may
1284 : // differ in inline-bidi direction.
1285 : // In the code below, |cbrs->frame| is the absolute containing block, while
1286 : // |containingBlock| is the nearest block container of the placeholder frame,
1287 : // which may be different from the absolute containing block.
1288 : void
1289 77 : ReflowInput::CalculateHypotheticalPosition(
1290 : nsPresContext* aPresContext,
1291 : nsPlaceholderFrame* aPlaceholderFrame,
1292 : const ReflowInput* cbrs,
1293 : nsHypotheticalPosition& aHypotheticalPos,
1294 : LayoutFrameType aFrameType) const
1295 : {
1296 77 : NS_ASSERTION(mStyleDisplay->mOriginalDisplay != StyleDisplay::None,
1297 : "mOriginalDisplay has not been properly initialized");
1298 :
1299 : // Find the nearest containing block frame to the placeholder frame,
1300 : // and its inline-start edge and width.
1301 : nscoord blockIStartContentEdge;
1302 : // Dummy writing mode for blockContentSize, will be changed as needed by
1303 : // GetHypotheticalBoxContainer.
1304 77 : WritingMode cbwm = cbrs->GetWritingMode();
1305 77 : LogicalSize blockContentSize(cbwm);
1306 : nsIFrame* containingBlock =
1307 : GetHypotheticalBoxContainer(aPlaceholderFrame, blockIStartContentEdge,
1308 77 : blockContentSize);
1309 : // Now blockContentSize is in containingBlock's writing mode.
1310 :
1311 : // If it's a replaced element and it has a 'auto' value for
1312 : //'inline size', see if we can get the intrinsic size. This will allow
1313 : // us to exactly determine both the inline edges
1314 77 : WritingMode wm = containingBlock->GetWritingMode();
1315 :
1316 154 : nsStyleCoord styleISize = mStylePosition->ISize(wm);
1317 77 : bool isAutoISize = styleISize.GetUnit() == eStyleUnit_Auto;
1318 77 : nsSize intrinsicSize;
1319 77 : bool knowIntrinsicSize = false;
1320 77 : if (NS_FRAME_IS_REPLACED(mFrameType) && isAutoISize) {
1321 : // See if we can get the intrinsic size of the element
1322 0 : knowIntrinsicSize = GetIntrinsicSizeFor(mFrame, intrinsicSize, aFrameType);
1323 : }
1324 :
1325 : // See if we can calculate what the box inline size would have been if
1326 : // the element had been in the flow
1327 : nscoord boxISize;
1328 77 : bool knowBoxISize = false;
1329 77 : if ((StyleDisplay::Inline == mStyleDisplay->mOriginalDisplay) &&
1330 0 : !NS_FRAME_IS_REPLACED(mFrameType)) {
1331 : // For non-replaced inline-level elements the 'inline size' property
1332 : // doesn't apply, so we don't know what the inline size would have
1333 : // been without reflowing it
1334 :
1335 : } else {
1336 : // It's either a replaced inline-level element or a block-level element
1337 :
1338 : // Determine the total amount of inline direction
1339 : // border/padding/margin that the element would have had if it had
1340 : // been in the flow. Note that we ignore any 'auto' and 'inherit'
1341 : // values
1342 : nscoord insideBoxSizing, outsideBoxSizing;
1343 77 : CalculateBorderPaddingMargin(eLogicalAxisInline,
1344 77 : blockContentSize.ISize(wm),
1345 77 : &insideBoxSizing, &outsideBoxSizing);
1346 :
1347 77 : if (NS_FRAME_IS_REPLACED(mFrameType) && isAutoISize) {
1348 : // It's a replaced element with an 'auto' inline size so the box
1349 : // inline size is its intrinsic size plus any border/padding/margin
1350 0 : if (knowIntrinsicSize) {
1351 0 : boxISize = LogicalSize(wm, intrinsicSize).ISize(wm) +
1352 0 : outsideBoxSizing + insideBoxSizing;
1353 0 : knowBoxISize = true;
1354 : }
1355 :
1356 77 : } else if (isAutoISize) {
1357 : // The box inline size is the containing block inline size
1358 77 : boxISize = blockContentSize.ISize(wm);
1359 77 : knowBoxISize = true;
1360 :
1361 : } else {
1362 : // We need to compute it. It's important we do this, because if it's
1363 : // percentage based this computed value may be different from the computed
1364 : // value calculated using the absolute containing block width
1365 0 : boxISize = ComputeISizeValue(blockContentSize.ISize(wm),
1366 : insideBoxSizing, outsideBoxSizing,
1367 0 : styleISize) +
1368 0 : insideBoxSizing + outsideBoxSizing;
1369 0 : knowBoxISize = true;
1370 : }
1371 : }
1372 :
1373 : // Get the placeholder x-offset and y-offset in the coordinate
1374 : // space of its containing block
1375 : // XXXbz the placeholder is not fully reflowed yet if our containing block is
1376 : // relatively positioned...
1377 77 : nsSize containerSize = containingBlock->GetStateBits() & NS_FRAME_IN_REFLOW
1378 : ? cbrs->ComputedSizeAsContainerIfConstrained()
1379 77 : : containingBlock->GetSize();
1380 : LogicalPoint
1381 154 : placeholderOffset(wm, aPlaceholderFrame->GetOffsetTo(containingBlock),
1382 77 : containerSize);
1383 :
1384 : // First, determine the hypothetical box's mBStart. We want to check the
1385 : // content insertion frame of containingBlock for block-ness, but make
1386 : // sure to compute all coordinates in the coordinate system of
1387 : // containingBlock.
1388 : nsBlockFrame* blockFrame =
1389 77 : nsLayoutUtils::GetAsBlock(containingBlock->GetContentInsertionFrame());
1390 77 : if (blockFrame) {
1391 : // Use a null containerSize to convert a LogicalPoint functioning as a
1392 : // vector into a physical nsPoint vector.
1393 0 : const nsSize nullContainerSize;
1394 0 : LogicalPoint blockOffset(wm, blockFrame->GetOffsetTo(containingBlock),
1395 0 : nullContainerSize);
1396 : bool isValid;
1397 0 : nsBlockInFlowLineIterator iter(blockFrame, aPlaceholderFrame, &isValid);
1398 0 : if (!isValid) {
1399 : // Give up. We're probably dealing with somebody using
1400 : // position:absolute inside native-anonymous content anyway.
1401 0 : aHypotheticalPos.mBStart = placeholderOffset.B(wm);
1402 : } else {
1403 0 : NS_ASSERTION(iter.GetContainer() == blockFrame,
1404 : "Found placeholder in wrong block!");
1405 0 : nsBlockFrame::LineIterator lineBox = iter.GetLine();
1406 :
1407 : // How we determine the hypothetical box depends on whether the element
1408 : // would have been inline-level or block-level
1409 : LogicalRect lineBounds =
1410 0 : lineBox->GetBounds().ConvertTo(wm, lineBox->mWritingMode,
1411 0 : lineBox->mContainerSize);
1412 0 : if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle()) {
1413 : // Use the block-start of the inline box which the placeholder lives in
1414 : // as the hypothetical box's block-start.
1415 0 : aHypotheticalPos.mBStart = lineBounds.BStart(wm) + blockOffset.B(wm);
1416 : } else {
1417 : // The element would have been block-level which means it would
1418 : // be below the line containing the placeholder frame, unless
1419 : // all the frames before it are empty. In that case, it would
1420 : // have been just before this line.
1421 : // XXXbz the line box is not fully reflowed yet if our
1422 : // containing block is relatively positioned...
1423 0 : if (lineBox != iter.End()) {
1424 0 : nsIFrame* firstFrame = lineBox->mFirstChild;
1425 0 : bool allEmpty = false;
1426 0 : if (firstFrame == aPlaceholderFrame) {
1427 0 : aPlaceholderFrame->SetLineIsEmptySoFar(true);
1428 0 : allEmpty = true;
1429 : } else {
1430 0 : auto prev = aPlaceholderFrame->GetPrevSibling();
1431 0 : if (prev && prev->IsPlaceholderFrame()) {
1432 0 : auto ph = static_cast<nsPlaceholderFrame*>(prev);
1433 0 : if (ph->GetLineIsEmptySoFar(&allEmpty)) {
1434 0 : aPlaceholderFrame->SetLineIsEmptySoFar(allEmpty);
1435 : }
1436 : }
1437 : }
1438 0 : if (!allEmpty) {
1439 0 : bool found = false;
1440 0 : while (firstFrame) { // See bug 223064
1441 0 : allEmpty = AreAllEarlierInFlowFramesEmpty(firstFrame,
1442 : aPlaceholderFrame, &found);
1443 0 : if (found || !allEmpty) {
1444 : break;
1445 : }
1446 0 : firstFrame = firstFrame->GetNextSibling();
1447 : }
1448 0 : aPlaceholderFrame->SetLineIsEmptySoFar(allEmpty);
1449 : }
1450 0 : NS_ASSERTION(firstFrame, "Couldn't find placeholder!");
1451 :
1452 0 : if (allEmpty) {
1453 : // The top of the hypothetical box is the top of the line
1454 : // containing the placeholder, since there is nothing in the
1455 : // line before our placeholder except empty frames.
1456 0 : aHypotheticalPos.mBStart =
1457 0 : lineBounds.BStart(wm) + blockOffset.B(wm);
1458 : } else {
1459 : // The top of the hypothetical box is just below the line
1460 : // containing the placeholder.
1461 0 : aHypotheticalPos.mBStart =
1462 0 : lineBounds.BEnd(wm) + blockOffset.B(wm);
1463 : }
1464 : } else {
1465 : // Just use the placeholder's block-offset wrt the containing block
1466 0 : aHypotheticalPos.mBStart = placeholderOffset.B(wm);
1467 : }
1468 : }
1469 : }
1470 : } else {
1471 : // The containing block is not a block, so it's probably something
1472 : // like a XUL box, etc.
1473 : // Just use the placeholder's block-offset
1474 77 : aHypotheticalPos.mBStart = placeholderOffset.B(wm);
1475 : }
1476 :
1477 : // Second, determine the hypothetical box's mIStart.
1478 : // How we determine the hypothetical box depends on whether the element
1479 : // would have been inline-level or block-level
1480 154 : if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle() ||
1481 77 : mFlags.mIOffsetsNeedCSSAlign) {
1482 : // The placeholder represents the IStart edge of the hypothetical box.
1483 : // (Or if mFlags.mIOffsetsNeedCSSAlign is set, it represents the IStart
1484 : // edge of the Alignment Container.)
1485 0 : aHypotheticalPos.mIStart = placeholderOffset.I(wm);
1486 : } else {
1487 77 : aHypotheticalPos.mIStart = blockIStartContentEdge;
1488 : }
1489 :
1490 : // The current coordinate space is that of the nearest block to the placeholder.
1491 : // Convert to the coordinate space of the absolute containing block
1492 : // One weird thing here is that for fixed-positioned elements we want to do
1493 : // the conversion incorrectly; specifically we want to ignore any scrolling
1494 : // that may have happened;
1495 77 : nsPoint cbOffset;
1496 154 : if (mStyleDisplay->mPosition == NS_STYLE_POSITION_FIXED &&
1497 : // Exclude cases inside -moz-transform where fixed is like absolute.
1498 77 : nsLayoutUtils::IsReallyFixedPos(mFrame)) {
1499 : // In this case, cbrs->frame will likely be an ancestor of
1500 : // containingBlock, so can just walk our way up the frame tree.
1501 : // Make sure to not add positions of frames whose parent is a
1502 : // scrollFrame, since we're doing fixed positioning, which assumes
1503 : // everything is scrolled to (0,0).
1504 77 : cbOffset.MoveTo(0, 0);
1505 776 : do {
1506 853 : cbOffset += containingBlock->GetPositionIgnoringScrolling();
1507 853 : nsContainerFrame* parent = containingBlock->GetParent();
1508 853 : if (!parent) {
1509 : // Oops, our absolute containing block isn't an ancestor of the
1510 : // placeholder's containing block. This can happen if the placeholder
1511 : // is pushed to a different page in a printing context. 'cbOffset' is
1512 : // currently relative to the root frame (containingBlock) - so just
1513 : // subtract the offset to the absolute containing block to make it
1514 : // relative to that.
1515 0 : cbOffset -= containingBlock->GetOffsetTo(cbrs->mFrame);
1516 0 : break;
1517 : }
1518 853 : containingBlock = parent;
1519 853 : } while (containingBlock != cbrs->mFrame);
1520 : } else {
1521 : // XXXldb We need to either ignore scrolling for the absolute
1522 : // positioning case too (and take the incompatibility) or figure out
1523 : // how to make these positioned elements actually *move* when we
1524 : // scroll, and thus avoid the resulting incremental reflow bugs.
1525 0 : cbOffset = containingBlock->GetOffsetTo(cbrs->mFrame);
1526 : }
1527 77 : nsSize cbrsSize = cbrs->ComputedSizeAsContainerIfConstrained();
1528 77 : LogicalPoint logCBOffs(wm, cbOffset, cbrsSize - containerSize);
1529 77 : aHypotheticalPos.mIStart += logCBOffs.I(wm);
1530 77 : aHypotheticalPos.mBStart += logCBOffs.B(wm);
1531 :
1532 : // The specified offsets are relative to the absolute containing block's
1533 : // padding edge and our current values are relative to the border edge, so
1534 : // translate.
1535 : LogicalMargin border =
1536 77 : cbrs->ComputedLogicalBorderPadding() - cbrs->ComputedLogicalPadding();
1537 77 : border = border.ConvertTo(wm, cbrs->GetWritingMode());
1538 77 : aHypotheticalPos.mIStart -= border.IStart(wm);
1539 77 : aHypotheticalPos.mBStart -= border.BStart(wm);
1540 :
1541 : // At this point, we have computed aHypotheticalPos using the writing mode
1542 : // of the placeholder's containing block.
1543 :
1544 77 : if (cbwm.GetBlockDir() != wm.GetBlockDir()) {
1545 : // If the block direction we used in calculating aHypotheticalPos does not
1546 : // match the absolute containing block's, we need to convert here so that
1547 : // aHypotheticalPos is usable in relation to the absolute containing block.
1548 : // This requires computing or measuring the abspos frame's block-size,
1549 : // which is not otherwise required/used here (as aHypotheticalPos
1550 : // records only the block-start coordinate).
1551 :
1552 : // This is similar to the inline-size calculation for a replaced
1553 : // inline-level element or a block-level element (above), except that
1554 : // 'auto' sizing is handled differently in the block direction for non-
1555 : // replaced elements and replaced elements lacking an intrinsic size.
1556 :
1557 : // Determine the total amount of block direction
1558 : // border/padding/margin that the element would have had if it had
1559 : // been in the flow. Note that we ignore any 'auto' and 'inherit'
1560 : // values.
1561 : nscoord insideBoxSizing, outsideBoxSizing;
1562 0 : CalculateBorderPaddingMargin(eLogicalAxisBlock,
1563 0 : blockContentSize.BSize(wm),
1564 0 : &insideBoxSizing, &outsideBoxSizing);
1565 :
1566 : nscoord boxBSize;
1567 0 : nsStyleCoord styleBSize = mStylePosition->BSize(wm);
1568 0 : bool isAutoBSize = styleBSize.GetUnit() == eStyleUnit_Auto;
1569 0 : if (isAutoBSize) {
1570 0 : if (NS_FRAME_IS_REPLACED(mFrameType) && knowIntrinsicSize) {
1571 : // It's a replaced element with an 'auto' block size so the box
1572 : // block size is its intrinsic size plus any border/padding/margin
1573 0 : boxBSize = LogicalSize(wm, intrinsicSize).BSize(wm) +
1574 0 : outsideBoxSizing + insideBoxSizing;
1575 : } else {
1576 : // XXX Bug 1191801
1577 : // Figure out how to get the correct boxBSize here (need to reflow the
1578 : // positioned frame?)
1579 0 : boxBSize = 0;
1580 : }
1581 : } else {
1582 : // We need to compute it. It's important we do this, because if it's
1583 : // percentage-based this computed value may be different from the
1584 : // computed value calculated using the absolute containing block height.
1585 0 : boxBSize = nsLayoutUtils::ComputeBSizeValue(blockContentSize.BSize(wm),
1586 0 : insideBoxSizing, styleBSize) +
1587 0 : insideBoxSizing + outsideBoxSizing;
1588 : }
1589 :
1590 0 : LogicalSize boxSize(wm, knowBoxISize ? boxISize : 0, boxBSize);
1591 :
1592 : LogicalPoint origin(wm, aHypotheticalPos.mIStart,
1593 0 : aHypotheticalPos.mBStart);
1594 0 : origin = origin.ConvertTo(cbwm, wm, cbrsSize -
1595 0 : boxSize.GetPhysicalSize(wm));
1596 :
1597 0 : aHypotheticalPos.mIStart = origin.I(cbwm);
1598 0 : aHypotheticalPos.mBStart = origin.B(cbwm);
1599 0 : aHypotheticalPos.mWritingMode = cbwm;
1600 : } else {
1601 77 : aHypotheticalPos.mWritingMode = wm;
1602 : }
1603 77 : }
1604 :
1605 : void
1606 77 : ReflowInput::InitAbsoluteConstraints(nsPresContext* aPresContext,
1607 : const ReflowInput* cbrs,
1608 : const LogicalSize& aCBSize,
1609 : LayoutFrameType aFrameType)
1610 : {
1611 77 : WritingMode wm = GetWritingMode();
1612 77 : WritingMode cbwm = cbrs->GetWritingMode();
1613 77 : NS_PRECONDITION(aCBSize.BSize(cbwm) != NS_AUTOHEIGHT,
1614 : "containing block bsize must be constrained");
1615 :
1616 77 : NS_ASSERTION(aFrameType != LayoutFrameType::Table,
1617 : "InitAbsoluteConstraints should not be called on table frames");
1618 77 : NS_ASSERTION(mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW,
1619 : "Why are we here?");
1620 :
1621 77 : const auto& styleOffset = mStylePosition->mOffset;
1622 77 : bool iStartIsAuto = styleOffset.GetIStartUnit(cbwm) == eStyleUnit_Auto;
1623 77 : bool iEndIsAuto = styleOffset.GetIEndUnit(cbwm) == eStyleUnit_Auto;
1624 77 : bool bStartIsAuto = styleOffset.GetBStartUnit(cbwm) == eStyleUnit_Auto;
1625 77 : bool bEndIsAuto = styleOffset.GetBEndUnit(cbwm) == eStyleUnit_Auto;
1626 :
1627 : // If both 'left' and 'right' are 'auto' or both 'top' and 'bottom' are
1628 : // 'auto', then compute the hypothetical box position where the element would
1629 : // have been if it had been in the flow
1630 77 : nsHypotheticalPosition hypotheticalPos;
1631 77 : if ((iStartIsAuto && iEndIsAuto) || (bStartIsAuto && bEndIsAuto)) {
1632 77 : nsPlaceholderFrame* placeholderFrame = mFrame->GetPlaceholderFrame();
1633 77 : MOZ_ASSERT(placeholderFrame, "no placeholder frame");
1634 :
1635 77 : if (placeholderFrame->HasAnyStateBits(
1636 : PLACEHOLDER_STATICPOS_NEEDS_CSSALIGN)) {
1637 0 : DebugOnly<nsIFrame*> placeholderParent = placeholderFrame->GetParent();
1638 0 : MOZ_ASSERT(placeholderParent, "shouldn't have unparented placeholders");
1639 0 : MOZ_ASSERT(placeholderParent->IsFlexOrGridContainer(),
1640 : "This flag should only be set on grid/flex children");
1641 :
1642 : // If the (as-yet unknown) static position will determine the inline
1643 : // and/or block offsets, set flags to note those offsets aren't valid
1644 : // until we can do CSS Box Alignment on the OOF frame.
1645 0 : mFlags.mIOffsetsNeedCSSAlign = (iStartIsAuto && iEndIsAuto);
1646 0 : mFlags.mBOffsetsNeedCSSAlign = (bStartIsAuto && bEndIsAuto);
1647 : }
1648 :
1649 77 : if (mFlags.mStaticPosIsCBOrigin) {
1650 0 : hypotheticalPos.mWritingMode = cbwm;
1651 0 : hypotheticalPos.mIStart = nscoord(0);
1652 0 : hypotheticalPos.mBStart = nscoord(0);
1653 : } else {
1654 : CalculateHypotheticalPosition(aPresContext, placeholderFrame, cbrs,
1655 77 : hypotheticalPos, aFrameType);
1656 : }
1657 : }
1658 :
1659 : // Initialize the 'left' and 'right' computed offsets
1660 : // XXX Handle new 'static-position' value...
1661 :
1662 : // Size of the containing block in its writing mode
1663 77 : LogicalSize cbSize = aCBSize;
1664 77 : LogicalMargin offsets = ComputedLogicalOffsets().ConvertTo(cbwm, wm);
1665 :
1666 77 : if (iStartIsAuto) {
1667 77 : offsets.IStart(cbwm) = 0;
1668 : } else {
1669 0 : offsets.IStart(cbwm) = nsLayoutUtils::
1670 0 : ComputeCBDependentValue(cbSize.ISize(cbwm), styleOffset.GetIStart(cbwm));
1671 : }
1672 77 : if (iEndIsAuto) {
1673 77 : offsets.IEnd(cbwm) = 0;
1674 : } else {
1675 0 : offsets.IEnd(cbwm) = nsLayoutUtils::
1676 0 : ComputeCBDependentValue(cbSize.ISize(cbwm), styleOffset.GetIEnd(cbwm));
1677 : }
1678 :
1679 77 : if (iStartIsAuto && iEndIsAuto) {
1680 77 : if (cbwm.IsBidiLTR() != hypotheticalPos.mWritingMode.IsBidiLTR()) {
1681 0 : offsets.IEnd(cbwm) = hypotheticalPos.mIStart;
1682 0 : iEndIsAuto = false;
1683 : } else {
1684 77 : offsets.IStart(cbwm) = hypotheticalPos.mIStart;
1685 77 : iStartIsAuto = false;
1686 : }
1687 : }
1688 :
1689 77 : if (bStartIsAuto) {
1690 77 : offsets.BStart(cbwm) = 0;
1691 : } else {
1692 0 : offsets.BStart(cbwm) = nsLayoutUtils::
1693 0 : ComputeBSizeDependentValue(cbSize.BSize(cbwm),
1694 0 : styleOffset.GetBStart(cbwm));
1695 : }
1696 77 : if (bEndIsAuto) {
1697 77 : offsets.BEnd(cbwm) = 0;
1698 : } else {
1699 0 : offsets.BEnd(cbwm) = nsLayoutUtils::
1700 0 : ComputeBSizeDependentValue(cbSize.BSize(cbwm),
1701 0 : styleOffset.GetBEnd(cbwm));
1702 : }
1703 :
1704 77 : if (bStartIsAuto && bEndIsAuto) {
1705 : // Treat 'top' like 'static-position'
1706 77 : offsets.BStart(cbwm) = hypotheticalPos.mBStart;
1707 77 : bStartIsAuto = false;
1708 : }
1709 :
1710 77 : SetComputedLogicalOffsets(offsets.ConvertTo(wm, cbwm));
1711 :
1712 : typedef nsIFrame::ComputeSizeFlags ComputeSizeFlags;
1713 77 : ComputeSizeFlags computeSizeFlags = ComputeSizeFlags::eDefault;
1714 77 : if (mFlags.mIClampMarginBoxMinSize) {
1715 0 : computeSizeFlags = ComputeSizeFlags(computeSizeFlags |
1716 : ComputeSizeFlags::eIClampMarginBoxMinSize);
1717 : }
1718 77 : if (mFlags.mBClampMarginBoxMinSize) {
1719 0 : computeSizeFlags = ComputeSizeFlags(computeSizeFlags |
1720 : ComputeSizeFlags::eBClampMarginBoxMinSize);
1721 : }
1722 77 : if (mFlags.mApplyAutoMinSize) {
1723 0 : computeSizeFlags = ComputeSizeFlags(computeSizeFlags |
1724 : ComputeSizeFlags::eIApplyAutoMinSize);
1725 : }
1726 77 : if (mFlags.mShrinkWrap) {
1727 0 : computeSizeFlags =
1728 0 : ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
1729 : }
1730 77 : if (mFlags.mUseAutoBSize) {
1731 0 : computeSizeFlags =
1732 0 : ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eUseAutoBSize);
1733 : }
1734 77 : if (wm.IsOrthogonalTo(cbwm)) {
1735 0 : if (bStartIsAuto || bEndIsAuto) {
1736 0 : computeSizeFlags =
1737 0 : ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
1738 : }
1739 : } else {
1740 77 : if (iStartIsAuto || iEndIsAuto) {
1741 77 : computeSizeFlags =
1742 77 : ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
1743 : }
1744 : }
1745 :
1746 77 : LogicalSize computedSize(wm);
1747 : {
1748 154 : AutoMaybeDisableFontInflation an(mFrame);
1749 :
1750 : computedSize =
1751 308 : mFrame->ComputeSize(mRenderingContext, wm, cbSize.ConvertTo(wm, cbwm),
1752 154 : cbSize.ConvertTo(wm, cbwm).ISize(wm), // XXX or AvailableISize()?
1753 154 : ComputedLogicalMargin().Size(wm) +
1754 154 : ComputedLogicalOffsets().Size(wm),
1755 154 : ComputedLogicalBorderPadding().Size(wm) -
1756 154 : ComputedLogicalPadding().Size(wm),
1757 154 : ComputedLogicalPadding().Size(wm),
1758 308 : computeSizeFlags);
1759 77 : ComputedISize() = computedSize.ISize(wm);
1760 77 : ComputedBSize() = computedSize.BSize(wm);
1761 77 : NS_ASSERTION(ComputedISize() >= 0, "Bogus inline-size");
1762 77 : NS_ASSERTION(ComputedBSize() == NS_UNCONSTRAINEDSIZE ||
1763 : ComputedBSize() >= 0, "Bogus block-size");
1764 : }
1765 77 : computedSize = computedSize.ConvertTo(cbwm, wm);
1766 :
1767 : // XXX Now that we have ComputeSize, can we condense many of the
1768 : // branches off of widthIsAuto?
1769 :
1770 77 : LogicalMargin margin = ComputedLogicalMargin().ConvertTo(cbwm, wm);
1771 : const LogicalMargin borderPadding =
1772 77 : ComputedLogicalBorderPadding().ConvertTo(cbwm, wm);
1773 :
1774 77 : bool iSizeIsAuto = eStyleUnit_Auto == mStylePosition->ISize(cbwm).GetUnit();
1775 77 : if (iStartIsAuto) {
1776 : // We know 'right' is not 'auto' anymore thanks to the hypothetical
1777 : // box code above.
1778 : // Solve for 'left'.
1779 0 : if (iSizeIsAuto) {
1780 : // XXXldb This, and the corresponding code in
1781 : // nsAbsoluteContainingBlock.cpp, could probably go away now that
1782 : // we always compute widths.
1783 0 : offsets.IStart(cbwm) = NS_AUTOOFFSET;
1784 : } else {
1785 0 : offsets.IStart(cbwm) =
1786 0 : cbSize.ISize(cbwm) - offsets.IEnd(cbwm) -
1787 0 : computedSize.ISize(cbwm) - margin.IStartEnd(cbwm) -
1788 0 : borderPadding.IStartEnd(cbwm);
1789 : }
1790 77 : } else if (iEndIsAuto) {
1791 : // We know 'left' is not 'auto' anymore thanks to the hypothetical
1792 : // box code above.
1793 : // Solve for 'right'.
1794 77 : if (iSizeIsAuto) {
1795 : // XXXldb This, and the corresponding code in
1796 : // nsAbsoluteContainingBlock.cpp, could probably go away now that
1797 : // we always compute widths.
1798 77 : offsets.IEnd(cbwm) = NS_AUTOOFFSET;
1799 : } else {
1800 0 : offsets.IEnd(cbwm) =
1801 0 : cbSize.ISize(cbwm) - offsets.IStart(cbwm) -
1802 0 : computedSize.ISize(cbwm) - margin.IStartEnd(cbwm) -
1803 0 : borderPadding.IStartEnd(cbwm);
1804 : }
1805 : } else {
1806 : // Neither 'inline-start' nor 'inline-end' is 'auto'.
1807 :
1808 0 : if (wm.IsOrthogonalTo(cbwm)) {
1809 : // For orthogonal blocks, we need to handle the case where the block had
1810 : // unconstrained block-size, which mapped to unconstrained inline-size
1811 : // in the containing block's writing mode.
1812 0 : nscoord autoISize = cbSize.ISize(cbwm) - margin.IStartEnd(cbwm) -
1813 0 : borderPadding.IStartEnd(cbwm) - offsets.IStartEnd(cbwm);
1814 0 : if (autoISize < 0) {
1815 0 : autoISize = 0;
1816 : }
1817 :
1818 0 : if (computedSize.ISize(cbwm) == NS_UNCONSTRAINEDSIZE) {
1819 : // For non-replaced elements with block-size auto, the block-size
1820 : // fills the remaining space.
1821 0 : computedSize.ISize(cbwm) = autoISize;
1822 :
1823 : // XXX Do these need box-sizing adjustments?
1824 0 : LogicalSize maxSize = ComputedMaxSize(cbwm);
1825 0 : LogicalSize minSize = ComputedMinSize(cbwm);
1826 0 : if (computedSize.ISize(cbwm) > maxSize.ISize(cbwm)) {
1827 0 : computedSize.ISize(cbwm) = maxSize.ISize(cbwm);
1828 : }
1829 0 : if (computedSize.ISize(cbwm) < minSize.ISize(cbwm)) {
1830 0 : computedSize.ISize(cbwm) = minSize.ISize(cbwm);
1831 : }
1832 : }
1833 : }
1834 :
1835 : // However, the inline-size might
1836 : // still not fill all the available space (even though we didn't
1837 : // shrink-wrap) in case:
1838 : // * inline-size was specified
1839 : // * we're dealing with a replaced element
1840 : // * width was constrained by min- or max-inline-size.
1841 :
1842 : nscoord availMarginSpace =
1843 0 : aCBSize.ISize(cbwm) - offsets.IStartEnd(cbwm) - margin.IStartEnd(cbwm) -
1844 0 : borderPadding.IStartEnd(cbwm) - computedSize.ISize(cbwm);
1845 : bool marginIStartIsAuto =
1846 0 : eStyleUnit_Auto == mStyleMargin->mMargin.GetIStartUnit(cbwm);
1847 : bool marginIEndIsAuto =
1848 0 : eStyleUnit_Auto == mStyleMargin->mMargin.GetIEndUnit(cbwm);
1849 :
1850 0 : if (marginIStartIsAuto) {
1851 0 : if (marginIEndIsAuto) {
1852 0 : if (availMarginSpace < 0) {
1853 : // Note that this case is different from the neither-'auto'
1854 : // case below, where the spec says to ignore 'left'/'right'.
1855 : // Ignore the specified value for 'margin-right'.
1856 0 : margin.IEnd(cbwm) = availMarginSpace;
1857 : } else {
1858 : // Both 'margin-left' and 'margin-right' are 'auto', so they get
1859 : // equal values
1860 0 : margin.IStart(cbwm) = availMarginSpace / 2;
1861 0 : margin.IEnd(cbwm) = availMarginSpace - margin.IStart(cbwm);
1862 : }
1863 : } else {
1864 : // Just 'margin-left' is 'auto'
1865 0 : margin.IStart(cbwm) = availMarginSpace;
1866 : }
1867 : } else {
1868 0 : if (marginIEndIsAuto) {
1869 : // Just 'margin-right' is 'auto'
1870 0 : margin.IEnd(cbwm) = availMarginSpace;
1871 : } else {
1872 : // We're over-constrained so use the direction of the containing
1873 : // block to dictate which value to ignore. (And note that the
1874 : // spec says to ignore 'left' or 'right' rather than
1875 : // 'margin-left' or 'margin-right'.)
1876 : // Note that this case is different from the both-'auto' case
1877 : // above, where the spec says to ignore
1878 : // 'margin-left'/'margin-right'.
1879 : // Ignore the specified value for 'right'.
1880 0 : offsets.IEnd(cbwm) += availMarginSpace;
1881 : }
1882 : }
1883 : }
1884 :
1885 77 : bool bSizeIsAuto = eStyleUnit_Auto == mStylePosition->BSize(cbwm).GetUnit();
1886 77 : if (bStartIsAuto) {
1887 : // solve for block-start
1888 0 : if (bSizeIsAuto) {
1889 0 : offsets.BStart(cbwm) = NS_AUTOOFFSET;
1890 : } else {
1891 0 : offsets.BStart(cbwm) = cbSize.BSize(cbwm) - margin.BStartEnd(cbwm) -
1892 0 : borderPadding.BStartEnd(cbwm) - computedSize.BSize(cbwm) -
1893 0 : offsets.BEnd(cbwm);
1894 : }
1895 77 : } else if (bEndIsAuto) {
1896 : // solve for block-end
1897 77 : if (bSizeIsAuto) {
1898 77 : offsets.BEnd(cbwm) = NS_AUTOOFFSET;
1899 : } else {
1900 0 : offsets.BEnd(cbwm) = cbSize.BSize(cbwm) - margin.BStartEnd(cbwm) -
1901 0 : borderPadding.BStartEnd(cbwm) - computedSize.BSize(cbwm) -
1902 0 : offsets.BStart(cbwm);
1903 : }
1904 : } else {
1905 : // Neither block-start nor -end is 'auto'.
1906 0 : nscoord autoBSize = cbSize.BSize(cbwm) - margin.BStartEnd(cbwm) -
1907 0 : borderPadding.BStartEnd(cbwm) - offsets.BStartEnd(cbwm);
1908 0 : if (autoBSize < 0) {
1909 0 : autoBSize = 0;
1910 : }
1911 :
1912 0 : if (computedSize.BSize(cbwm) == NS_UNCONSTRAINEDSIZE) {
1913 : // For non-replaced elements with block-size auto, the block-size
1914 : // fills the remaining space.
1915 0 : computedSize.BSize(cbwm) = autoBSize;
1916 :
1917 : // XXX Do these need box-sizing adjustments?
1918 0 : LogicalSize maxSize = ComputedMaxSize(cbwm);
1919 0 : LogicalSize minSize = ComputedMinSize(cbwm);
1920 0 : if (computedSize.BSize(cbwm) > maxSize.BSize(cbwm)) {
1921 0 : computedSize.BSize(cbwm) = maxSize.BSize(cbwm);
1922 : }
1923 0 : if (computedSize.BSize(cbwm) < minSize.BSize(cbwm)) {
1924 0 : computedSize.BSize(cbwm) = minSize.BSize(cbwm);
1925 : }
1926 : }
1927 :
1928 : // The block-size might still not fill all the available space in case:
1929 : // * bsize was specified
1930 : // * we're dealing with a replaced element
1931 : // * bsize was constrained by min- or max-bsize.
1932 0 : nscoord availMarginSpace = autoBSize - computedSize.BSize(cbwm);
1933 : bool marginBStartIsAuto =
1934 0 : eStyleUnit_Auto == mStyleMargin->mMargin.GetBStartUnit(cbwm);
1935 : bool marginBEndIsAuto =
1936 0 : eStyleUnit_Auto == mStyleMargin->mMargin.GetBEndUnit(cbwm);
1937 :
1938 0 : if (marginBStartIsAuto) {
1939 0 : if (marginBEndIsAuto) {
1940 : // Both 'margin-top' and 'margin-bottom' are 'auto', so they get
1941 : // equal values
1942 0 : margin.BStart(cbwm) = availMarginSpace / 2;
1943 0 : margin.BEnd(cbwm) = availMarginSpace - margin.BStart(cbwm);
1944 : } else {
1945 : // Just margin-block-start is 'auto'
1946 0 : margin.BStart(cbwm) = availMarginSpace;
1947 : }
1948 : } else {
1949 0 : if (marginBEndIsAuto) {
1950 : // Just margin-block-end is 'auto'
1951 0 : margin.BEnd(cbwm) = availMarginSpace;
1952 : } else {
1953 : // We're over-constrained so ignore the specified value for
1954 : // block-end. (And note that the spec says to ignore 'bottom'
1955 : // rather than 'margin-bottom'.)
1956 0 : offsets.BEnd(cbwm) += availMarginSpace;
1957 : }
1958 : }
1959 : }
1960 77 : ComputedBSize() = computedSize.ConvertTo(wm, cbwm).BSize(wm);
1961 77 : ComputedISize() = computedSize.ConvertTo(wm, cbwm).ISize(wm);
1962 :
1963 77 : SetComputedLogicalOffsets(offsets.ConvertTo(wm, cbwm));
1964 77 : SetComputedLogicalMargin(margin.ConvertTo(wm, cbwm));
1965 77 : }
1966 :
1967 : // This will not be converted to abstract coordinates because it's only
1968 : // used in CalcQuirkContainingBlockHeight
1969 : nscoord
1970 0 : GetBlockMarginBorderPadding(const ReflowInput* aReflowInput)
1971 : {
1972 0 : nscoord result = 0;
1973 0 : if (!aReflowInput) return result;
1974 :
1975 : // zero auto margins
1976 0 : nsMargin margin = aReflowInput->ComputedPhysicalMargin();
1977 0 : if (NS_AUTOMARGIN == margin.top)
1978 0 : margin.top = 0;
1979 0 : if (NS_AUTOMARGIN == margin.bottom)
1980 0 : margin.bottom = 0;
1981 :
1982 0 : result += margin.top + margin.bottom;
1983 0 : result += aReflowInput->ComputedPhysicalBorderPadding().top +
1984 0 : aReflowInput->ComputedPhysicalBorderPadding().bottom;
1985 :
1986 0 : return result;
1987 : }
1988 :
1989 : /* Get the height based on the viewport of the containing block specified
1990 : * in aReflowInput when the containing block has mComputedHeight == NS_AUTOHEIGHT
1991 : * This will walk up the chain of containing blocks looking for a computed height
1992 : * until it finds the canvas frame, or it encounters a frame that is not a block,
1993 : * area, or scroll frame. This handles compatibility with IE (see bug 85016 and bug 219693)
1994 : *
1995 : * When we encounter scrolledContent block frames, we skip over them,
1996 : * since they are guaranteed to not be useful for computing the containing block.
1997 : *
1998 : * See also IsQuirkContainingBlockHeight.
1999 : */
2000 : static nscoord
2001 0 : CalcQuirkContainingBlockHeight(const ReflowInput* aCBReflowInput)
2002 : {
2003 0 : const ReflowInput* firstAncestorRI = nullptr; // a candidate for html frame
2004 0 : const ReflowInput* secondAncestorRI = nullptr; // a candidate for body frame
2005 :
2006 : // initialize the default to NS_AUTOHEIGHT as this is the containings block
2007 : // computed height when this function is called. It is possible that we
2008 : // don't alter this height especially if we are restricted to one level
2009 0 : nscoord result = NS_AUTOHEIGHT;
2010 :
2011 0 : const ReflowInput* rs = aCBReflowInput;
2012 0 : for (; rs; rs = rs->mParentReflowInput) {
2013 0 : LayoutFrameType frameType = rs->mFrame->Type();
2014 : // if the ancestor is auto height then skip it and continue up if it
2015 : // is the first block frame and possibly the body/html
2016 0 : if (LayoutFrameType::Block == frameType ||
2017 : #ifdef MOZ_XUL
2018 0 : LayoutFrameType::XULLabel == frameType ||
2019 : #endif
2020 : LayoutFrameType::Scroll == frameType) {
2021 :
2022 0 : secondAncestorRI = firstAncestorRI;
2023 0 : firstAncestorRI = rs;
2024 :
2025 : // If the current frame we're looking at is positioned, we don't want to
2026 : // go any further (see bug 221784). The behavior we want here is: 1) If
2027 : // not auto-height, use this as the percentage base. 2) If auto-height,
2028 : // keep looking, unless the frame is positioned.
2029 0 : if (NS_AUTOHEIGHT == rs->ComputedHeight()) {
2030 0 : if (rs->mFrame->IsAbsolutelyPositioned(rs->mStyleDisplay)) {
2031 0 : break;
2032 : } else {
2033 0 : continue;
2034 : }
2035 : }
2036 0 : } else if (LayoutFrameType::Canvas == frameType) {
2037 : // Always continue on to the height calculation
2038 0 : } else if (LayoutFrameType::PageContent == frameType) {
2039 0 : nsIFrame* prevInFlow = rs->mFrame->GetPrevInFlow();
2040 : // only use the page content frame for a height basis if it is the first in flow
2041 0 : if (prevInFlow)
2042 0 : break;
2043 : }
2044 : else {
2045 0 : break;
2046 : }
2047 :
2048 : // if the ancestor is the page content frame then the percent base is
2049 : // the avail height, otherwise it is the computed height
2050 0 : result = (LayoutFrameType::PageContent == frameType) ? rs->AvailableHeight()
2051 : : rs->ComputedHeight();
2052 : // if unconstrained - don't sutract borders - would result in huge height
2053 0 : if (NS_AUTOHEIGHT == result) return result;
2054 :
2055 : // if we got to the canvas or page content frame, then subtract out
2056 : // margin/border/padding for the BODY and HTML elements
2057 0 : if ((LayoutFrameType::Canvas == frameType) ||
2058 : (LayoutFrameType::PageContent == frameType)) {
2059 :
2060 0 : result -= GetBlockMarginBorderPadding(firstAncestorRI);
2061 0 : result -= GetBlockMarginBorderPadding(secondAncestorRI);
2062 :
2063 : #ifdef DEBUG
2064 : // make sure the first ancestor is the HTML and the second is the BODY
2065 0 : if (firstAncestorRI) {
2066 0 : nsIContent* frameContent = firstAncestorRI->mFrame->GetContent();
2067 0 : if (frameContent) {
2068 0 : NS_ASSERTION(frameContent->IsHTMLElement(nsGkAtoms::html),
2069 : "First ancestor is not HTML");
2070 : }
2071 : }
2072 0 : if (secondAncestorRI) {
2073 0 : nsIContent* frameContent = secondAncestorRI->mFrame->GetContent();
2074 0 : if (frameContent) {
2075 0 : NS_ASSERTION(frameContent->IsHTMLElement(nsGkAtoms::body),
2076 : "Second ancestor is not BODY");
2077 : }
2078 0 : }
2079 : #endif
2080 :
2081 : }
2082 : // if we got to the html frame (a block child of the canvas) ...
2083 0 : else if (LayoutFrameType::Block == frameType && rs->mParentReflowInput &&
2084 0 : rs->mParentReflowInput->mFrame->IsCanvasFrame()) {
2085 : // ... then subtract out margin/border/padding for the BODY element
2086 0 : result -= GetBlockMarginBorderPadding(secondAncestorRI);
2087 : }
2088 0 : break;
2089 : }
2090 :
2091 : // Make sure not to return a negative height here!
2092 0 : return std::max(result, 0);
2093 : }
2094 :
2095 : // Called by InitConstraints() to compute the containing block rectangle for
2096 : // the element. Handles the special logic for absolutely positioned elements
2097 : LogicalSize
2098 320 : ReflowInput::ComputeContainingBlockRectangle(
2099 : nsPresContext* aPresContext,
2100 : const ReflowInput* aContainingBlockRI) const
2101 : {
2102 : // Unless the element is absolutely positioned, the containing block is
2103 : // formed by the content edge of the nearest block-level ancestor
2104 320 : LogicalSize cbSize = aContainingBlockRI->ComputedSize();
2105 :
2106 320 : WritingMode wm = aContainingBlockRI->GetWritingMode();
2107 :
2108 : // mFrameType for abs-pos tables is NS_CSS_FRAME_TYPE_BLOCK, so we need to
2109 : // special case them here.
2110 640 : if (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE ||
2111 320 : (mFrame->IsTableFrame() && mFrame->IsAbsolutelyPositioned(mStyleDisplay) &&
2112 0 : (mFrame->GetParent()->GetStateBits() & NS_FRAME_OUT_OF_FLOW))) {
2113 : // See if the ancestor is block-level or inline-level
2114 0 : if (NS_FRAME_GET_TYPE(aContainingBlockRI->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) {
2115 : // Base our size on the actual size of the frame. In cases when this is
2116 : // completely bogus (eg initial reflow), this code shouldn't even be
2117 : // called, since the code in nsInlineFrame::Reflow will pass in
2118 : // the containing block dimensions to our constructor.
2119 : // XXXbz we should be taking the in-flows into account too, but
2120 : // that's very hard.
2121 :
2122 : LogicalMargin computedBorder =
2123 0 : aContainingBlockRI->ComputedLogicalBorderPadding() -
2124 0 : aContainingBlockRI->ComputedLogicalPadding();
2125 0 : cbSize.ISize(wm) = aContainingBlockRI->mFrame->ISize(wm) -
2126 0 : computedBorder.IStartEnd(wm);
2127 0 : NS_ASSERTION(cbSize.ISize(wm) >= 0,
2128 : "Negative containing block isize!");
2129 0 : cbSize.BSize(wm) = aContainingBlockRI->mFrame->BSize(wm) -
2130 0 : computedBorder.BStartEnd(wm);
2131 0 : NS_ASSERTION(cbSize.BSize(wm) >= 0,
2132 : "Negative containing block bsize!");
2133 : } else {
2134 : // If the ancestor is block-level, the containing block is formed by the
2135 : // padding edge of the ancestor
2136 0 : cbSize.ISize(wm) +=
2137 0 : aContainingBlockRI->ComputedLogicalPadding().IStartEnd(wm);
2138 0 : cbSize.BSize(wm) +=
2139 0 : aContainingBlockRI->ComputedLogicalPadding().BStartEnd(wm);
2140 : }
2141 : } else {
2142 : // an element in quirks mode gets a containing block based on looking for a
2143 : // parent with a non-auto height if the element has a percent height
2144 : // Note: We don't emulate this quirk for percents in calc() or in
2145 : // vertical writing modes.
2146 640 : if (!wm.IsVertical() &&
2147 320 : NS_AUTOHEIGHT == cbSize.BSize(wm)) {
2148 88 : if (eCompatibility_NavQuirks == aPresContext->CompatibilityMode() &&
2149 24 : (mStylePosition->mHeight.GetUnit() == eStyleUnit_Percent ||
2150 12 : (mFrame->IsTableWrapperFrame() &&
2151 0 : mFrame->PrincipalChildList().FirstChild()->StylePosition()->
2152 0 : mHeight.GetUnit() == eStyleUnit_Percent))) {
2153 0 : cbSize.BSize(wm) = CalcQuirkContainingBlockHeight(aContainingBlockRI);
2154 : }
2155 : }
2156 : }
2157 :
2158 320 : return cbSize.ConvertTo(GetWritingMode(), wm);
2159 : }
2160 :
2161 147 : static eNormalLineHeightControl GetNormalLineHeightCalcControl(void)
2162 : {
2163 147 : if (sNormalLineHeightControl == eUninitialized) {
2164 : // browser.display.normal_lineheight_calc_control is not user
2165 : // changeable, so no need to register callback for it.
2166 : int32_t val =
2167 : Preferences::GetInt("browser.display.normal_lineheight_calc_control",
2168 2 : eNoExternalLeading);
2169 2 : sNormalLineHeightControl = static_cast<eNormalLineHeightControl>(val);
2170 : }
2171 147 : return sNormalLineHeightControl;
2172 : }
2173 :
2174 : static inline bool
2175 257 : IsSideCaption(nsIFrame* aFrame, const nsStyleDisplay* aStyleDisplay,
2176 : WritingMode aWM)
2177 : {
2178 257 : if (aStyleDisplay->mDisplay != StyleDisplay::TableCaption) {
2179 257 : return false;
2180 : }
2181 0 : uint8_t captionSide = aFrame->StyleTableBorder()->mCaptionSide;
2182 0 : return captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
2183 0 : captionSide == NS_STYLE_CAPTION_SIDE_RIGHT;
2184 : }
2185 :
2186 : // Flex/grid items resolve block-axis percentage margin & padding against the
2187 : // containing block block-size (also for abs/fixed-pos child frames).
2188 : // For everything else: the CSS21 spec requires that margin and padding
2189 : // percentage values are calculated with respect to the inline-size of the
2190 : // containing block, even for margin & padding in the block axis.
2191 : static LogicalSize
2192 652 : OffsetPercentBasis(const nsIFrame* aFrame,
2193 : WritingMode aWM,
2194 : const LogicalSize& aContainingBlockSize)
2195 : {
2196 652 : LogicalSize offsetPercentBasis = aContainingBlockSize;
2197 652 : if (MOZ_LIKELY(!aFrame->GetParent() ||
2198 : !aFrame->GetParent()->IsFlexOrGridContainer())) {
2199 652 : offsetPercentBasis.BSize(aWM) = offsetPercentBasis.ISize(aWM);
2200 0 : } else if (offsetPercentBasis.BSize(aWM) == NS_AUTOHEIGHT) {
2201 0 : offsetPercentBasis.BSize(aWM) = 0;
2202 : }
2203 :
2204 652 : return offsetPercentBasis;
2205 : }
2206 :
2207 : // XXX refactor this code to have methods for each set of properties
2208 : // we are computing: width,height,line-height; margin; offsets
2209 :
2210 : void
2211 652 : ReflowInput::InitConstraints(nsPresContext* aPresContext,
2212 : const LogicalSize& aContainingBlockSize,
2213 : const nsMargin* aBorder,
2214 : const nsMargin* aPadding,
2215 : LayoutFrameType aFrameType)
2216 : {
2217 652 : WritingMode wm = GetWritingMode();
2218 1304 : DISPLAY_INIT_CONSTRAINTS(mFrame, this,
2219 : aContainingBlockSize.ISize(wm),
2220 : aContainingBlockSize.BSize(wm),
2221 : aBorder, aPadding);
2222 :
2223 : // If this is a reflow root, then set the computed width and
2224 : // height equal to the available space
2225 652 : if (nullptr == mParentReflowInput || mFlags.mDummyParentReflowInput) {
2226 : // XXXldb This doesn't mean what it used to!
2227 510 : InitOffsets(wm, OffsetPercentBasis(mFrame, wm, aContainingBlockSize),
2228 255 : aFrameType, mFlags, aBorder, aPadding, mStyleDisplay);
2229 : // Override mComputedMargin since reflow roots start from the
2230 : // frame's boundary, which is inside the margin.
2231 255 : ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
2232 255 : ComputedPhysicalOffsets().SizeTo(0, 0, 0, 0);
2233 :
2234 510 : ComputedISize() =
2235 510 : AvailableISize() - ComputedLogicalBorderPadding().IStartEnd(wm);
2236 255 : if (ComputedISize() < 0) {
2237 14 : ComputedISize() = 0;
2238 : }
2239 255 : if (AvailableBSize() != NS_UNCONSTRAINEDSIZE) {
2240 154 : ComputedBSize() =
2241 154 : AvailableBSize() - ComputedLogicalBorderPadding().BStartEnd(wm);
2242 77 : if (ComputedBSize() < 0) {
2243 1 : ComputedBSize() = 0;
2244 : }
2245 : } else {
2246 178 : ComputedBSize() = NS_UNCONSTRAINEDSIZE;
2247 : }
2248 :
2249 255 : ComputedMinWidth() = ComputedMinHeight() = 0;
2250 255 : ComputedMaxWidth() = ComputedMaxHeight() = NS_UNCONSTRAINEDSIZE;
2251 : } else {
2252 : // Get the containing block reflow state
2253 397 : const ReflowInput* cbrs = mCBReflowInput;
2254 397 : MOZ_ASSERT(cbrs, "no containing block");
2255 397 : MOZ_ASSERT(mFrame->GetParent());
2256 :
2257 : // If we weren't given a containing block width and height, then
2258 : // compute one
2259 794 : LogicalSize cbSize = (aContainingBlockSize == LogicalSize(wm, -1, -1))
2260 : ? ComputeContainingBlockRectangle(aPresContext, cbrs)
2261 397 : : aContainingBlockSize;
2262 :
2263 : // See if the containing block height is based on the size of its
2264 : // content
2265 : LayoutFrameType fType;
2266 397 : if (NS_AUTOHEIGHT == cbSize.BSize(wm)) {
2267 : // See if the containing block is a cell frame which needs
2268 : // to use the mComputedHeight of the cell instead of what the cell block passed in.
2269 : // XXX It seems like this could lead to bugs with min-height and friends
2270 76 : if (cbrs->mParentReflowInput) {
2271 76 : fType = cbrs->mFrame->Type();
2272 76 : if (IS_TABLE_CELL(fType)) {
2273 : // use the cell's computed block size
2274 0 : cbSize.BSize(wm) = cbrs->ComputedSize(wm).BSize(wm);
2275 : }
2276 : }
2277 : }
2278 :
2279 : // XXX Might need to also pass the CB height (not width) for page boxes,
2280 : // too, if we implement them.
2281 :
2282 : // For calculating positioning offsets, margins, borders and
2283 : // padding, we use the writing mode of the containing block
2284 397 : WritingMode cbwm = cbrs->GetWritingMode();
2285 1191 : InitOffsets(cbwm, OffsetPercentBasis(mFrame, cbwm,
2286 794 : cbSize.ConvertTo(cbwm, wm)),
2287 397 : aFrameType, mFlags, aBorder, aPadding, mStyleDisplay);
2288 :
2289 : // For calculating the size of this box, we use its own writing mode
2290 397 : const nsStyleCoord &blockSize = mStylePosition->BSize(wm);
2291 397 : nsStyleUnit blockSizeUnit = blockSize.GetUnit();
2292 :
2293 : // Check for a percentage based block size and a containing block
2294 : // block size that depends on the content block size
2295 : // XXX twiddling blockSizeUnit doesn't help anymore
2296 : // FIXME Shouldn't we fix that?
2297 397 : if (blockSize.HasPercent()) {
2298 8 : if (NS_AUTOHEIGHT == cbSize.BSize(wm)) {
2299 : // this if clause enables %-blockSize on replaced inline frames,
2300 : // such as images. See bug 54119. The else clause "blockSizeUnit = eStyleUnit_Auto;"
2301 : // used to be called exclusively.
2302 0 : if (NS_FRAME_REPLACED(NS_CSS_FRAME_TYPE_INLINE) == mFrameType ||
2303 : NS_FRAME_REPLACED_CONTAINS_BLOCK(
2304 0 : NS_CSS_FRAME_TYPE_INLINE) == mFrameType) {
2305 : // Get the containing block reflow state
2306 0 : NS_ASSERTION(nullptr != cbrs, "no containing block");
2307 : // in quirks mode, get the cb height using the special quirk method
2308 0 : if (!wm.IsVertical() &&
2309 0 : eCompatibility_NavQuirks == aPresContext->CompatibilityMode()) {
2310 0 : if (!IS_TABLE_CELL(fType)) {
2311 0 : cbSize.BSize(wm) = CalcQuirkContainingBlockHeight(cbrs);
2312 0 : if (cbSize.BSize(wm) == NS_AUTOHEIGHT) {
2313 0 : blockSizeUnit = eStyleUnit_Auto;
2314 : }
2315 : }
2316 : else {
2317 0 : blockSizeUnit = eStyleUnit_Auto;
2318 : }
2319 : }
2320 : // in standard mode, use the cb block size. if it's "auto",
2321 : // as will be the case by default in BODY, use auto block size
2322 : // as per CSS2 spec.
2323 : else
2324 : {
2325 0 : nscoord computedBSize = cbrs->ComputedSize(wm).BSize(wm);
2326 0 : if (NS_AUTOHEIGHT != computedBSize) {
2327 0 : cbSize.BSize(wm) = computedBSize;
2328 : }
2329 : else {
2330 0 : blockSizeUnit = eStyleUnit_Auto;
2331 : }
2332 0 : }
2333 : }
2334 : else {
2335 : // default to interpreting the blockSize like 'auto'
2336 0 : blockSizeUnit = eStyleUnit_Auto;
2337 : }
2338 : }
2339 : }
2340 :
2341 : // Compute our offsets if the element is relatively positioned. We
2342 : // need the correct containing block inline-size and block-size
2343 : // here, which is why we need to do it after all the quirks-n-such
2344 : // above. (If the element is sticky positioned, we need to wait
2345 : // until the scroll container knows its size, so we compute offsets
2346 : // from StickyScrollContainer::UpdatePositions.)
2347 397 : if (mStyleDisplay->IsRelativelyPositioned(mFrame) &&
2348 0 : NS_STYLE_POSITION_RELATIVE == mStyleDisplay->mPosition) {
2349 0 : ComputeRelativeOffsets(cbwm, mFrame, cbSize.ConvertTo(cbwm, wm),
2350 0 : ComputedPhysicalOffsets());
2351 : } else {
2352 : // Initialize offsets to 0
2353 397 : ComputedPhysicalOffsets().SizeTo(0, 0, 0, 0);
2354 : }
2355 :
2356 : // Calculate the computed values for min and max properties. Note that
2357 : // this MUST come after we've computed our border and padding.
2358 397 : ComputeMinMaxValues(cbSize);
2359 :
2360 : // Calculate the computed inlineSize and blockSize.
2361 : // This varies by frame type.
2362 :
2363 397 : if (NS_CSS_FRAME_TYPE_INTERNAL_TABLE == mFrameType) {
2364 : // Internal table elements. The rules vary depending on the type.
2365 : // Calculate the computed isize
2366 0 : bool rowOrRowGroup = false;
2367 0 : const nsStyleCoord &inlineSize = mStylePosition->ISize(wm);
2368 0 : nsStyleUnit inlineSizeUnit = inlineSize.GetUnit();
2369 0 : if ((StyleDisplay::TableRow == mStyleDisplay->mDisplay) ||
2370 0 : (StyleDisplay::TableRowGroup == mStyleDisplay->mDisplay)) {
2371 : // 'inlineSize' property doesn't apply to table rows and row groups
2372 0 : inlineSizeUnit = eStyleUnit_Auto;
2373 0 : rowOrRowGroup = true;
2374 : }
2375 :
2376 : // calc() with percentages acts like auto on internal table elements
2377 0 : if (eStyleUnit_Auto == inlineSizeUnit ||
2378 0 : (inlineSize.IsCalcUnit() && inlineSize.CalcHasPercent())) {
2379 0 : ComputedISize() = AvailableISize();
2380 :
2381 0 : if ((ComputedISize() != NS_UNCONSTRAINEDSIZE) && !rowOrRowGroup){
2382 : // Internal table elements don't have margins. Only tables and
2383 : // cells have border and padding
2384 0 : ComputedISize() -= ComputedLogicalBorderPadding().IStartEnd(wm);
2385 0 : if (ComputedISize() < 0)
2386 0 : ComputedISize() = 0;
2387 : }
2388 0 : NS_ASSERTION(ComputedISize() >= 0, "Bogus computed isize");
2389 :
2390 : } else {
2391 0 : NS_ASSERTION(inlineSizeUnit == inlineSize.GetUnit(),
2392 : "unexpected inline size unit change");
2393 0 : ComputedISize() = ComputeISizeValue(cbSize.ISize(wm),
2394 0 : mStylePosition->mBoxSizing,
2395 : inlineSize);
2396 : }
2397 :
2398 : // Calculate the computed block size
2399 0 : if ((StyleDisplay::TableColumn == mStyleDisplay->mDisplay) ||
2400 0 : (StyleDisplay::TableColumnGroup == mStyleDisplay->mDisplay)) {
2401 : // 'blockSize' property doesn't apply to table columns and column groups
2402 0 : blockSizeUnit = eStyleUnit_Auto;
2403 : }
2404 : // calc() with percentages acts like 'auto' on internal table elements
2405 0 : if (eStyleUnit_Auto == blockSizeUnit ||
2406 0 : (blockSize.IsCalcUnit() && blockSize.CalcHasPercent())) {
2407 0 : ComputedBSize() = NS_AUTOHEIGHT;
2408 : } else {
2409 0 : NS_ASSERTION(blockSizeUnit == blockSize.GetUnit(),
2410 : "unexpected block size unit change");
2411 0 : ComputedBSize() = ComputeBSizeValue(cbSize.BSize(wm),
2412 0 : mStylePosition->mBoxSizing,
2413 : blockSize);
2414 : }
2415 :
2416 : // Doesn't apply to table elements
2417 0 : ComputedMinWidth() = ComputedMinHeight() = 0;
2418 0 : ComputedMaxWidth() = ComputedMaxHeight() = NS_UNCONSTRAINEDSIZE;
2419 :
2420 397 : } else if (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE) {
2421 : // XXX not sure if this belongs here or somewhere else - cwk
2422 77 : InitAbsoluteConstraints(aPresContext, cbrs, cbSize.ConvertTo(cbrs->GetWritingMode(), wm), aFrameType);
2423 : } else {
2424 640 : AutoMaybeDisableFontInflation an(mFrame);
2425 :
2426 320 : bool isBlock = NS_CSS_FRAME_TYPE_BLOCK == NS_FRAME_GET_TYPE(mFrameType);
2427 : typedef nsIFrame::ComputeSizeFlags ComputeSizeFlags;
2428 : ComputeSizeFlags computeSizeFlags =
2429 320 : isBlock ? ComputeSizeFlags::eDefault : ComputeSizeFlags::eShrinkWrap;
2430 320 : if (mFlags.mIClampMarginBoxMinSize) {
2431 0 : computeSizeFlags = ComputeSizeFlags(computeSizeFlags |
2432 : ComputeSizeFlags::eIClampMarginBoxMinSize);
2433 : }
2434 320 : if (mFlags.mBClampMarginBoxMinSize) {
2435 0 : computeSizeFlags = ComputeSizeFlags(computeSizeFlags |
2436 : ComputeSizeFlags::eBClampMarginBoxMinSize);
2437 : }
2438 320 : if (mFlags.mApplyAutoMinSize) {
2439 0 : computeSizeFlags = ComputeSizeFlags(computeSizeFlags |
2440 : ComputeSizeFlags::eIApplyAutoMinSize);
2441 : }
2442 320 : if (mFlags.mShrinkWrap) {
2443 0 : computeSizeFlags =
2444 0 : ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
2445 : }
2446 320 : if (mFlags.mUseAutoBSize) {
2447 0 : computeSizeFlags =
2448 0 : ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eUseAutoBSize);
2449 : }
2450 :
2451 320 : nsIFrame* alignCB = mFrame->GetParent();
2452 320 : if (alignCB->IsTableWrapperFrame() && alignCB->GetParent()) {
2453 : // XXX grid-specific for now; maybe remove this check after we address bug 799725
2454 0 : if (alignCB->GetParent()->IsGridContainerFrame()) {
2455 0 : alignCB = alignCB->GetParent();
2456 : }
2457 : }
2458 320 : if (alignCB->IsGridContainerFrame()) {
2459 : // Shrink-wrap grid items that will be aligned (rather than stretched)
2460 : // in its inline axis.
2461 : auto inlineAxisAlignment =
2462 0 : wm.IsOrthogonalTo(cbwm)
2463 0 : ? mStylePosition->UsedAlignSelf(alignCB->StyleContext())
2464 0 : : mStylePosition->UsedJustifySelf(alignCB->StyleContext());
2465 0 : if ((inlineAxisAlignment != NS_STYLE_ALIGN_STRETCH &&
2466 0 : inlineAxisAlignment != NS_STYLE_ALIGN_NORMAL) ||
2467 0 : mStyleMargin->mMargin.GetIStartUnit(wm) == eStyleUnit_Auto ||
2468 0 : mStyleMargin->mMargin.GetIEndUnit(wm) == eStyleUnit_Auto) {
2469 0 : computeSizeFlags =
2470 0 : ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
2471 : }
2472 : } else {
2473 : // Make sure legend frames with display:block and width:auto still
2474 : // shrink-wrap.
2475 : // Also shrink-wrap blocks that are orthogonal to their container.
2476 703 : if (isBlock &&
2477 0 : ((aFrameType == LayoutFrameType::Legend &&
2478 257 : mFrame->StyleContext()->GetPseudo() != nsCSSAnonBoxes::scrolledContent) ||
2479 43 : (aFrameType == LayoutFrameType::Scroll &&
2480 300 : mFrame->GetContentInsertionFrame()->IsLegendFrame()) ||
2481 771 : (mCBReflowInput &&
2482 1091 : mCBReflowInput->GetWritingMode().IsOrthogonalTo(mWritingMode)))) {
2483 0 : computeSizeFlags =
2484 0 : ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
2485 : }
2486 :
2487 320 : if (alignCB->IsFlexContainerFrame()) {
2488 0 : computeSizeFlags =
2489 0 : ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eShrinkWrap);
2490 :
2491 : // If we're inside of a flex container that needs to measure our
2492 : // auto height, pass that information along to ComputeSize().
2493 0 : if (mFlags.mIsFlexContainerMeasuringHeight) {
2494 0 : computeSizeFlags =
2495 0 : ComputeSizeFlags(computeSizeFlags | ComputeSizeFlags::eUseAutoBSize);
2496 : }
2497 : } else {
2498 320 : MOZ_ASSERT(!mFlags.mIsFlexContainerMeasuringHeight,
2499 : "We're not in a flex container, so the flag "
2500 : "'mIsFlexContainerMeasuringHeight' shouldn't be set");
2501 : }
2502 : }
2503 :
2504 320 : if (cbSize.ISize(wm) == NS_UNCONSTRAINEDSIZE) {
2505 : // For orthogonal flows, where we found a parent orthogonal-limit
2506 : // for AvailableISize() in Init(), we'll use the same here as well.
2507 0 : cbSize.ISize(wm) = AvailableISize();
2508 : }
2509 :
2510 : LogicalSize size =
2511 960 : mFrame->ComputeSize(mRenderingContext, wm, cbSize, AvailableISize(),
2512 640 : ComputedLogicalMargin().Size(wm),
2513 640 : ComputedLogicalBorderPadding().Size(wm) -
2514 640 : ComputedLogicalPadding().Size(wm),
2515 640 : ComputedLogicalPadding().Size(wm),
2516 960 : computeSizeFlags);
2517 :
2518 320 : ComputedISize() = size.ISize(wm);
2519 320 : ComputedBSize() = size.BSize(wm);
2520 320 : NS_ASSERTION(ComputedISize() >= 0, "Bogus inline-size");
2521 320 : NS_ASSERTION(ComputedBSize() == NS_UNCONSTRAINEDSIZE ||
2522 : ComputedBSize() >= 0, "Bogus block-size");
2523 :
2524 : // Exclude inline tables, side captions, flex and grid items from block
2525 : // margin calculations.
2526 834 : if (isBlock && !IsSideCaption(mFrame, mStyleDisplay, cbwm) &&
2527 834 : mStyleDisplay->mDisplay != StyleDisplay::InlineTable &&
2528 257 : !alignCB->IsFlexOrGridContainer()) {
2529 257 : CalculateBlockSideMargins(aFrameType);
2530 : }
2531 : }
2532 : }
2533 :
2534 : // Save our containing block dimensions
2535 652 : mContainingBlockSize = aContainingBlockSize;
2536 652 : }
2537 :
2538 : static void
2539 1304 : UpdateProp(nsIFrame* aFrame,
2540 : const FramePropertyDescriptor<nsMargin>* aProperty,
2541 : bool aNeeded,
2542 : nsMargin& aNewValue)
2543 : {
2544 1304 : if (aNeeded) {
2545 22 : nsMargin* propValue = aFrame->GetProperty(aProperty);
2546 22 : if (propValue) {
2547 14 : *propValue = aNewValue;
2548 : } else {
2549 8 : aFrame->AddProperty(aProperty, new nsMargin(aNewValue));
2550 : }
2551 : } else {
2552 1282 : aFrame->DeleteProperty(aProperty);
2553 : }
2554 1304 : }
2555 :
2556 : void
2557 652 : SizeComputationInput::InitOffsets(WritingMode aWM,
2558 : const LogicalSize& aPercentBasis,
2559 : LayoutFrameType aFrameType,
2560 : ReflowInputFlags aFlags,
2561 : const nsMargin* aBorder,
2562 : const nsMargin* aPadding,
2563 : const nsStyleDisplay* aDisplay)
2564 : {
2565 1304 : DISPLAY_INIT_OFFSETS(mFrame, this, aPercentBasis, aWM, aBorder, aPadding);
2566 :
2567 : // Since we are in reflow, we don't need to store these properties anymore
2568 : // unless they are dependent on width, in which case we store the new value.
2569 652 : nsPresContext *presContext = mFrame->PresContext();
2570 652 : mFrame->DeleteProperty(nsIFrame::UsedBorderProperty());
2571 :
2572 : // Compute margins from the specified margin style information. These
2573 : // become the default computed values, and may be adjusted below
2574 : // XXX fix to provide 0,0 for the top&bottom margins for
2575 : // inline-non-replaced elements
2576 652 : bool needMarginProp = ComputeMargin(aWM, aPercentBasis);
2577 : // XXX We need to include 'auto' horizontal margins in this too!
2578 : // ... but if we did that, we'd need to fix nsFrame::GetUsedMargin
2579 : // to use it even when the margins are all zero (since sometimes
2580 : // they get treated as auto)
2581 652 : ::UpdateProp(mFrame, nsIFrame::UsedMarginProperty(), needMarginProp,
2582 652 : ComputedPhysicalMargin());
2583 :
2584 :
2585 652 : const nsStyleDisplay* disp = mFrame->StyleDisplayWithOptionalParam(aDisplay);
2586 652 : bool isThemed = mFrame->IsThemed(disp);
2587 : bool needPaddingProp;
2588 652 : nsIntMargin widget;
2589 660 : if (isThemed &&
2590 16 : presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
2591 8 : mFrame, disp->mAppearance,
2592 8 : &widget)) {
2593 0 : ComputedPhysicalPadding().top = presContext->DevPixelsToAppUnits(widget.top);
2594 0 : ComputedPhysicalPadding().right = presContext->DevPixelsToAppUnits(widget.right);
2595 0 : ComputedPhysicalPadding().bottom = presContext->DevPixelsToAppUnits(widget.bottom);
2596 0 : ComputedPhysicalPadding().left = presContext->DevPixelsToAppUnits(widget.left);
2597 0 : needPaddingProp = false;
2598 : }
2599 652 : else if (nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
2600 0 : ComputedPhysicalPadding().SizeTo(0, 0, 0, 0);
2601 0 : needPaddingProp = false;
2602 : }
2603 652 : else if (aPadding) { // padding is an input arg
2604 167 : ComputedPhysicalPadding() = *aPadding;
2605 334 : needPaddingProp = mFrame->StylePadding()->IsWidthDependent() ||
2606 167 : (mFrame->GetStateBits() & NS_FRAME_REFLOW_ROOT);
2607 : }
2608 : else {
2609 485 : needPaddingProp = ComputePadding(aWM, aPercentBasis, aFrameType);
2610 : }
2611 :
2612 : // Add [align|justify]-content:baseline padding contribution.
2613 : typedef const FramePropertyDescriptor<SmallValueHolder<nscoord>>* Prop;
2614 : auto ApplyBaselinePadding = [this, &needPaddingProp]
2615 1304 : (LogicalAxis aAxis, Prop aProp) {
2616 : bool found;
2617 1304 : nscoord val = mFrame->GetProperty(aProp, &found);
2618 1304 : if (found) {
2619 0 : NS_ASSERTION(val != nscoord(0), "zero in this property is useless");
2620 0 : WritingMode wm = GetWritingMode();
2621 : LogicalSide side;
2622 0 : if (val > 0) {
2623 0 : side = MakeLogicalSide(aAxis, eLogicalEdgeStart);
2624 : } else {
2625 0 : side = MakeLogicalSide(aAxis, eLogicalEdgeEnd);
2626 0 : val = -val;
2627 : }
2628 0 : mComputedPadding.Side(wm.PhysicalSide(side)) += val;
2629 0 : needPaddingProp = true;
2630 : }
2631 1956 : };
2632 652 : if (!aFlags.mUseAutoBSize) {
2633 652 : ApplyBaselinePadding(eLogicalAxisBlock, nsIFrame::BBaselinePadProperty());
2634 : }
2635 652 : if (!aFlags.mShrinkWrap) {
2636 652 : ApplyBaselinePadding(eLogicalAxisInline, nsIFrame::IBaselinePadProperty());
2637 : }
2638 :
2639 652 : if (isThemed) {
2640 8 : nsIntMargin widget;
2641 16 : presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
2642 8 : mFrame, disp->mAppearance,
2643 16 : &widget);
2644 16 : ComputedPhysicalBorderPadding().top =
2645 8 : presContext->DevPixelsToAppUnits(widget.top);
2646 16 : ComputedPhysicalBorderPadding().right =
2647 8 : presContext->DevPixelsToAppUnits(widget.right);
2648 16 : ComputedPhysicalBorderPadding().bottom =
2649 8 : presContext->DevPixelsToAppUnits(widget.bottom);
2650 16 : ComputedPhysicalBorderPadding().left =
2651 8 : presContext->DevPixelsToAppUnits(widget.left);
2652 : }
2653 644 : else if (nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
2654 0 : ComputedPhysicalBorderPadding().SizeTo(0, 0, 0, 0);
2655 : }
2656 644 : else if (aBorder) { // border is an input arg
2657 0 : ComputedPhysicalBorderPadding() = *aBorder;
2658 : }
2659 : else {
2660 644 : ComputedPhysicalBorderPadding() = mFrame->StyleBorder()->GetComputedBorder();
2661 : }
2662 652 : ComputedPhysicalBorderPadding() += ComputedPhysicalPadding();
2663 :
2664 652 : if (aFrameType == LayoutFrameType::Table) {
2665 0 : nsTableFrame *tableFrame = static_cast<nsTableFrame*>(mFrame);
2666 :
2667 0 : if (tableFrame->IsBorderCollapse()) {
2668 : // border-collapsed tables don't use any of their padding, and
2669 : // only part of their border. We need to do this here before we
2670 : // try to do anything like handling 'auto' widths,
2671 : // 'box-sizing', or 'auto' margins.
2672 0 : ComputedPhysicalPadding().SizeTo(0,0,0,0);
2673 : SetComputedLogicalBorderPadding(
2674 0 : tableFrame->GetIncludedOuterBCBorder(mWritingMode));
2675 : }
2676 :
2677 : // The margin is inherited to the table wrapper frame via
2678 : // the ::-moz-table-wrapper rule in ua.css.
2679 0 : ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
2680 652 : } else if (aFrameType == LayoutFrameType::Scrollbar) {
2681 : // scrollbars may have had their width or height smashed to zero
2682 : // by the associated scrollframe, in which case we must not report
2683 : // any padding or border.
2684 4 : nsSize size(mFrame->GetSize());
2685 4 : if (size.width == 0 || size.height == 0) {
2686 4 : ComputedPhysicalPadding().SizeTo(0,0,0,0);
2687 4 : ComputedPhysicalBorderPadding().SizeTo(0,0,0,0);
2688 : }
2689 : }
2690 652 : ::UpdateProp(mFrame, nsIFrame::UsedPaddingProperty(), needPaddingProp,
2691 652 : ComputedPhysicalPadding());
2692 652 : }
2693 :
2694 : // This code enforces section 10.3.3 of the CSS2 spec for this formula:
2695 : //
2696 : // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' +
2697 : // 'padding-right' + 'border-right-width' + 'margin-right'
2698 : // = width of containing block
2699 : //
2700 : // Note: the width unit is not auto when this is called
2701 : void
2702 257 : ReflowInput::CalculateBlockSideMargins(LayoutFrameType aFrameType)
2703 : {
2704 : // Calculations here are done in the containing block's writing mode,
2705 : // which is where margins will eventually be applied: we're calculating
2706 : // margins that will be used by the container in its inline direction,
2707 : // which in the case of an orthogonal contained block will correspond to
2708 : // the block direction of this reflow state. So in the orthogonal-flow
2709 : // case, "CalculateBlock*Side*Margins" will actually end up adjusting
2710 : // the BStart/BEnd margins; those are the "sides" of the block from its
2711 : // container's point of view.
2712 : WritingMode cbWM =
2713 257 : mCBReflowInput ? mCBReflowInput->GetWritingMode(): GetWritingMode();
2714 :
2715 257 : nscoord availISizeCBWM = AvailableSize(cbWM).ISize(cbWM);
2716 257 : nscoord computedISizeCBWM = ComputedSize(cbWM).ISize(cbWM);
2717 257 : if (computedISizeCBWM == NS_UNCONSTRAINEDSIZE) {
2718 : // For orthogonal flows, where we found a parent orthogonal-limit
2719 : // for AvailableISize() in Init(), we'll use the same here as well.
2720 0 : computedISizeCBWM = availISizeCBWM;
2721 : }
2722 :
2723 257 : LAYOUT_WARN_IF_FALSE(NS_UNCONSTRAINEDSIZE != computedISizeCBWM &&
2724 : NS_UNCONSTRAINEDSIZE != availISizeCBWM,
2725 : "have unconstrained inline-size; this should only "
2726 : "result from very large sizes, not attempts at "
2727 : "intrinsic inline-size calculation");
2728 :
2729 : LogicalMargin margin =
2730 257 : ComputedLogicalMargin().ConvertTo(cbWM, mWritingMode);
2731 : LogicalMargin borderPadding =
2732 257 : ComputedLogicalBorderPadding().ConvertTo(cbWM, mWritingMode);
2733 514 : nscoord sum = margin.IStartEnd(cbWM) +
2734 514 : borderPadding.IStartEnd(cbWM) + computedISizeCBWM;
2735 257 : if (sum == availISizeCBWM) {
2736 : // The sum is already correct
2737 514 : return;
2738 : }
2739 :
2740 : // Determine the start and end margin values. The isize value
2741 : // remains constant while we do this.
2742 :
2743 : // Calculate how much space is available for margins
2744 0 : nscoord availMarginSpace = availISizeCBWM - sum;
2745 :
2746 : // If the available margin space is negative, then don't follow the
2747 : // usual overconstraint rules.
2748 0 : if (availMarginSpace < 0) {
2749 0 : margin.IEnd(cbWM) += availMarginSpace;
2750 0 : SetComputedLogicalMargin(margin.ConvertTo(mWritingMode, cbWM));
2751 0 : return;
2752 : }
2753 :
2754 : // The css2 spec clearly defines how block elements should behave
2755 : // in section 10.3.3.
2756 0 : const nsStyleSides& styleSides = mStyleMargin->mMargin;
2757 0 : bool isAutoStartMargin = eStyleUnit_Auto == styleSides.GetIStartUnit(cbWM);
2758 0 : bool isAutoEndMargin = eStyleUnit_Auto == styleSides.GetIEndUnit(cbWM);
2759 0 : if (!isAutoStartMargin && !isAutoEndMargin) {
2760 : // Neither margin is 'auto' so we're over constrained. Use the
2761 : // 'direction' property of the parent to tell which margin to
2762 : // ignore
2763 : // First check if there is an HTML alignment that we should honor
2764 0 : const ReflowInput* prs = mParentReflowInput;
2765 0 : if (aFrameType == LayoutFrameType::Table) {
2766 0 : NS_ASSERTION(prs->mFrame->IsTableWrapperFrame(),
2767 : "table not inside table wrapper");
2768 : // Center the table within the table wrapper based on the alignment
2769 : // of the table wrapper's parent.
2770 0 : prs = prs->mParentReflowInput;
2771 : }
2772 0 : if (prs &&
2773 0 : (prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_LEFT ||
2774 0 : prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
2775 0 : prs->mStyleText->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)) {
2776 0 : if (prs->mWritingMode.IsBidiLTR()) {
2777 0 : isAutoStartMargin =
2778 0 : prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_LEFT;
2779 0 : isAutoEndMargin =
2780 0 : prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_RIGHT;
2781 : } else {
2782 0 : isAutoStartMargin =
2783 0 : prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_RIGHT;
2784 0 : isAutoEndMargin =
2785 0 : prs->mStyleText->mTextAlign != NS_STYLE_TEXT_ALIGN_MOZ_LEFT;
2786 : }
2787 : }
2788 : // Otherwise apply the CSS rules, and ignore one margin by forcing
2789 : // it to 'auto', depending on 'direction'.
2790 : else {
2791 0 : isAutoEndMargin = true;
2792 : }
2793 : }
2794 :
2795 : // Logic which is common to blocks and tables
2796 : // The computed margins need not be zero because the 'auto' could come from
2797 : // overconstraint or from HTML alignment so values need to be accumulated
2798 :
2799 0 : if (isAutoStartMargin) {
2800 0 : if (isAutoEndMargin) {
2801 : // Both margins are 'auto' so the computed addition should be equal
2802 0 : nscoord forStart = availMarginSpace / 2;
2803 0 : margin.IStart(cbWM) += forStart;
2804 0 : margin.IEnd(cbWM) += availMarginSpace - forStart;
2805 : } else {
2806 0 : margin.IStart(cbWM) += availMarginSpace;
2807 : }
2808 0 : } else if (isAutoEndMargin) {
2809 0 : margin.IEnd(cbWM) += availMarginSpace;
2810 : }
2811 0 : SetComputedLogicalMargin(margin.ConvertTo(mWritingMode, cbWM));
2812 : }
2813 :
2814 : #define NORMAL_LINE_HEIGHT_FACTOR 1.2f // in term of emHeight
2815 : // For "normal" we use the font's normal line height (em height + leading).
2816 : // If both internal leading and external leading specified by font itself
2817 : // are zeros, we should compensate this by creating extra (external) leading
2818 : // in eCompensateLeading mode. This is necessary because without this
2819 : // compensation, normal line height might looks too tight.
2820 :
2821 : // For risk management, we use preference to control the behavior, and
2822 : // eNoExternalLeading is the old behavior.
2823 : static nscoord
2824 147 : GetNormalLineHeight(nsFontMetrics* aFontMetrics)
2825 : {
2826 147 : NS_PRECONDITION(nullptr != aFontMetrics, "no font metrics");
2827 :
2828 : nscoord normalLineHeight;
2829 :
2830 147 : nscoord externalLeading = aFontMetrics->ExternalLeading();
2831 147 : nscoord internalLeading = aFontMetrics->InternalLeading();
2832 147 : nscoord emHeight = aFontMetrics->EmHeight();
2833 147 : switch (GetNormalLineHeightCalcControl()) {
2834 : case eIncludeExternalLeading:
2835 0 : normalLineHeight = emHeight+ internalLeading + externalLeading;
2836 0 : break;
2837 : case eCompensateLeading:
2838 147 : if (!internalLeading && !externalLeading)
2839 0 : normalLineHeight = NSToCoordRound(emHeight * NORMAL_LINE_HEIGHT_FACTOR);
2840 : else
2841 147 : normalLineHeight = emHeight+ internalLeading + externalLeading;
2842 147 : break;
2843 : default:
2844 : //case eNoExternalLeading:
2845 0 : normalLineHeight = emHeight + internalLeading;
2846 : }
2847 147 : return normalLineHeight;
2848 : }
2849 :
2850 : static inline nscoord
2851 192 : ComputeLineHeight(nsStyleContext* aStyleContext,
2852 : nscoord aBlockBSize,
2853 : float aFontSizeInflation)
2854 : {
2855 192 : const nsStyleCoord& lhCoord = aStyleContext->StyleText()->mLineHeight;
2856 :
2857 192 : if (lhCoord.GetUnit() == eStyleUnit_Coord) {
2858 0 : nscoord result = lhCoord.GetCoordValue();
2859 0 : if (aFontSizeInflation != 1.0f) {
2860 0 : result = NSToCoordRound(result * aFontSizeInflation);
2861 : }
2862 0 : return result;
2863 : }
2864 :
2865 192 : if (lhCoord.GetUnit() == eStyleUnit_Factor)
2866 : // For factor units the computed value of the line-height property
2867 : // is found by multiplying the factor by the font's computed size
2868 : // (adjusted for min-size prefs and text zoom).
2869 0 : return NSToCoordRound(lhCoord.GetFactorValue() * aFontSizeInflation *
2870 0 : aStyleContext->StyleFont()->mFont.size);
2871 :
2872 192 : NS_ASSERTION(lhCoord.GetUnit() == eStyleUnit_Normal ||
2873 : lhCoord.GetUnit() == eStyleUnit_Enumerated,
2874 : "bad line-height unit");
2875 :
2876 192 : if (lhCoord.GetUnit() == eStyleUnit_Enumerated) {
2877 46 : NS_ASSERTION(lhCoord.GetIntValue() == NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT,
2878 : "bad line-height value");
2879 46 : if (aBlockBSize != NS_AUTOHEIGHT) {
2880 45 : return aBlockBSize;
2881 : }
2882 : }
2883 :
2884 : RefPtr<nsFontMetrics> fm = nsLayoutUtils::
2885 294 : GetFontMetricsForStyleContext(aStyleContext, aFontSizeInflation);
2886 147 : return GetNormalLineHeight(fm);
2887 : }
2888 :
2889 : nscoord
2890 171 : ReflowInput::CalcLineHeight() const
2891 : {
2892 : nscoord blockBSize =
2893 180 : nsLayoutUtils::IsNonWrapperBlock(mFrame) ? ComputedBSize() :
2894 180 : (mCBReflowInput ? mCBReflowInput->ComputedBSize() : NS_AUTOHEIGHT);
2895 :
2896 171 : return CalcLineHeight(mFrame->GetContent(), mFrame->StyleContext(), blockBSize,
2897 342 : nsLayoutUtils::FontSizeInflationFor(mFrame));
2898 : }
2899 :
2900 : /* static */ nscoord
2901 192 : ReflowInput::CalcLineHeight(nsIContent* aContent,
2902 : nsStyleContext* aStyleContext,
2903 : nscoord aBlockBSize,
2904 : float aFontSizeInflation)
2905 : {
2906 192 : NS_PRECONDITION(aStyleContext, "Must have a style context");
2907 :
2908 : nscoord lineHeight =
2909 192 : ComputeLineHeight(aStyleContext, aBlockBSize, aFontSizeInflation);
2910 :
2911 192 : NS_ASSERTION(lineHeight >= 0, "ComputeLineHeight screwed up");
2912 :
2913 192 : HTMLInputElement* input = HTMLInputElement::FromContentOrNull(aContent);
2914 192 : if (input && input->IsSingleLineTextControl()) {
2915 : // For Web-compatibility, single-line text input elements cannot
2916 : // have a line-height smaller than one.
2917 : nscoord lineHeightOne =
2918 20 : aFontSizeInflation * aStyleContext->StyleFont()->mFont.size;
2919 20 : if (lineHeight < lineHeightOne) {
2920 0 : lineHeight = lineHeightOne;
2921 : }
2922 : }
2923 :
2924 192 : return lineHeight;
2925 : }
2926 :
2927 : bool
2928 652 : SizeComputationInput::ComputeMargin(WritingMode aWM,
2929 : const LogicalSize& aPercentBasis)
2930 : {
2931 : // SVG text frames have no margin.
2932 652 : if (nsSVGUtils::IsInSVGTextSubtree(mFrame)) {
2933 0 : return false;
2934 : }
2935 :
2936 : // If style style can provide us the margin directly, then use it.
2937 652 : const nsStyleMargin *styleMargin = mFrame->StyleMargin();
2938 :
2939 652 : bool isCBDependent = !styleMargin->GetMargin(ComputedPhysicalMargin());
2940 652 : if (isCBDependent) {
2941 : // We have to compute the value. Note that this calculation is
2942 : // performed according to the writing mode of the containing block
2943 : // (http://dev.w3.org/csswg/css-writing-modes-3/#orthogonal-flows)
2944 0 : LogicalMargin m(aWM);
2945 0 : m.IStart(aWM) = nsLayoutUtils::
2946 0 : ComputeCBDependentValue(aPercentBasis.ISize(aWM),
2947 0 : styleMargin->mMargin.GetIStart(aWM));
2948 0 : m.IEnd(aWM) = nsLayoutUtils::
2949 0 : ComputeCBDependentValue(aPercentBasis.ISize(aWM),
2950 0 : styleMargin->mMargin.GetIEnd(aWM));
2951 :
2952 0 : m.BStart(aWM) = nsLayoutUtils::
2953 0 : ComputeCBDependentValue(aPercentBasis.BSize(aWM),
2954 0 : styleMargin->mMargin.GetBStart(aWM));
2955 0 : m.BEnd(aWM) = nsLayoutUtils::
2956 0 : ComputeCBDependentValue(aPercentBasis.BSize(aWM),
2957 0 : styleMargin->mMargin.GetBEnd(aWM));
2958 :
2959 0 : SetComputedLogicalMargin(aWM, m);
2960 : }
2961 :
2962 : // ... but font-size-inflation-based margin adjustment uses the
2963 : // frame's writing mode
2964 652 : nscoord marginAdjustment = FontSizeInflationListMarginAdjustment(mFrame);
2965 :
2966 652 : if (marginAdjustment > 0) {
2967 0 : LogicalMargin m = ComputedLogicalMargin();
2968 0 : m.IStart(mWritingMode) += marginAdjustment;
2969 0 : SetComputedLogicalMargin(m);
2970 : }
2971 :
2972 652 : return isCBDependent;
2973 : }
2974 :
2975 : bool
2976 485 : SizeComputationInput::ComputePadding(WritingMode aWM,
2977 : const LogicalSize& aPercentBasis,
2978 : LayoutFrameType aFrameType)
2979 : {
2980 : // If style can provide us the padding directly, then use it.
2981 485 : const nsStylePadding *stylePadding = mFrame->StylePadding();
2982 485 : bool isCBDependent = !stylePadding->GetPadding(ComputedPhysicalPadding());
2983 : // a table row/col group, row/col doesn't have padding
2984 : // XXXldb Neither do border-collapse tables.
2985 485 : if (LayoutFrameType::TableRowGroup == aFrameType ||
2986 485 : LayoutFrameType::TableColGroup == aFrameType ||
2987 485 : LayoutFrameType::TableRow == aFrameType ||
2988 : LayoutFrameType::TableCol == aFrameType) {
2989 0 : ComputedPhysicalPadding().SizeTo(0,0,0,0);
2990 : }
2991 485 : else if (isCBDependent) {
2992 : // We have to compute the value. This calculation is performed
2993 : // according to the writing mode of the containing block
2994 : // (http://dev.w3.org/csswg/css-writing-modes-3/#orthogonal-flows)
2995 : // clamp negative calc() results to 0
2996 0 : LogicalMargin p(aWM);
2997 0 : p.IStart(aWM) = std::max(0, nsLayoutUtils::
2998 0 : ComputeCBDependentValue(aPercentBasis.ISize(aWM),
2999 0 : stylePadding->mPadding.GetIStart(aWM)));
3000 0 : p.IEnd(aWM) = std::max(0, nsLayoutUtils::
3001 0 : ComputeCBDependentValue(aPercentBasis.ISize(aWM),
3002 0 : stylePadding->mPadding.GetIEnd(aWM)));
3003 :
3004 0 : p.BStart(aWM) = std::max(0, nsLayoutUtils::
3005 0 : ComputeCBDependentValue(aPercentBasis.BSize(aWM),
3006 0 : stylePadding->mPadding.GetBStart(aWM)));
3007 0 : p.BEnd(aWM) = std::max(0, nsLayoutUtils::
3008 0 : ComputeCBDependentValue(aPercentBasis.BSize(aWM),
3009 0 : stylePadding->mPadding.GetBEnd(aWM)));
3010 :
3011 0 : SetComputedLogicalPadding(aWM, p);
3012 : }
3013 485 : return isCBDependent;
3014 : }
3015 :
3016 : void
3017 397 : ReflowInput::ComputeMinMaxValues(const LogicalSize&aCBSize)
3018 : {
3019 397 : WritingMode wm = GetWritingMode();
3020 :
3021 397 : const nsStyleCoord& minISize = mStylePosition->MinISize(wm);
3022 397 : const nsStyleCoord& maxISize = mStylePosition->MaxISize(wm);
3023 397 : const nsStyleCoord& minBSize = mStylePosition->MinBSize(wm);
3024 397 : const nsStyleCoord& maxBSize = mStylePosition->MaxBSize(wm);
3025 :
3026 : // NOTE: min-width:auto resolves to 0, except on a flex item. (But
3027 : // even there, it's supposed to be ignored (i.e. treated as 0) until
3028 : // the flex container explicitly resolves & considers it.)
3029 397 : if (eStyleUnit_Auto == minISize.GetUnit()) {
3030 345 : ComputedMinISize() = 0;
3031 : } else {
3032 104 : ComputedMinISize() = ComputeISizeValue(aCBSize.ISize(wm),
3033 52 : mStylePosition->mBoxSizing,
3034 : minISize);
3035 : }
3036 :
3037 397 : if (eStyleUnit_None == maxISize.GetUnit()) {
3038 : // Specified value of 'none'
3039 343 : ComputedMaxISize() = NS_UNCONSTRAINEDSIZE; // no limit
3040 : } else {
3041 108 : ComputedMaxISize() = ComputeISizeValue(aCBSize.ISize(wm),
3042 54 : mStylePosition->mBoxSizing,
3043 : maxISize);
3044 : }
3045 :
3046 : // If the computed value of 'min-width' is greater than the value of
3047 : // 'max-width', 'max-width' is set to the value of 'min-width'
3048 397 : if (ComputedMinISize() > ComputedMaxISize()) {
3049 0 : ComputedMaxISize() = ComputedMinISize();
3050 : }
3051 :
3052 : // Check for percentage based values and a containing block height that
3053 : // depends on the content height. Treat them like 'auto'
3054 : // Likewise, check for calc() with percentages on internal table elements;
3055 : // that's treated as 'auto' too.
3056 : // Likewise, if we're a child of a flex container who's measuring our
3057 : // intrinsic height, then we want to disregard our min-height.
3058 :
3059 : // NOTE: min-height:auto resolves to 0, except on a flex item. (But
3060 : // even there, it's supposed to be ignored (i.e. treated as 0) until
3061 : // the flex container explicitly resolves & considers it.)
3062 840 : if (eStyleUnit_Auto == minBSize.GetUnit() ||
3063 46 : (NS_AUTOHEIGHT == aCBSize.BSize(wm) &&
3064 46 : minBSize.HasPercent()) ||
3065 46 : (mFrameType == NS_CSS_FRAME_TYPE_INTERNAL_TABLE &&
3066 443 : minBSize.IsCalcUnit() && minBSize.CalcHasPercent()) ||
3067 46 : mFlags.mIsFlexContainerMeasuringHeight) {
3068 351 : ComputedMinBSize() = 0;
3069 : } else {
3070 92 : ComputedMinBSize() = ComputeBSizeValue(aCBSize.BSize(wm),
3071 46 : mStylePosition->mBoxSizing,
3072 : minBSize);
3073 : }
3074 397 : nsStyleUnit maxBSizeUnit = maxBSize.GetUnit();
3075 397 : if (eStyleUnit_None == maxBSizeUnit) {
3076 : // Specified value of 'none'
3077 351 : ComputedMaxBSize() = NS_UNCONSTRAINEDSIZE; // no limit
3078 : } else {
3079 : // Check for percentage based values and a containing block height that
3080 : // depends on the content height. Treat them like 'none'
3081 : // Likewise, check for calc() with percentages on internal table elements;
3082 : // that's treated as 'auto' too.
3083 : // Likewise, if we're a child of a flex container who's measuring our
3084 : // intrinsic height, then we want to disregard our max-height.
3085 92 : if ((NS_AUTOHEIGHT == aCBSize.BSize(wm) &&
3086 46 : maxBSize.HasPercent()) ||
3087 46 : (mFrameType == NS_CSS_FRAME_TYPE_INTERNAL_TABLE &&
3088 92 : maxBSize.IsCalcUnit() && maxBSize.CalcHasPercent()) ||
3089 46 : mFlags.mIsFlexContainerMeasuringHeight) {
3090 0 : ComputedMaxBSize() = NS_UNCONSTRAINEDSIZE;
3091 : } else {
3092 92 : ComputedMaxBSize() = ComputeBSizeValue(aCBSize.BSize(wm),
3093 46 : mStylePosition->mBoxSizing,
3094 : maxBSize);
3095 : }
3096 : }
3097 :
3098 : // If the computed value of 'min-height' is greater than the value of
3099 : // 'max-height', 'max-height' is set to the value of 'min-height'
3100 397 : if (ComputedMinBSize() > ComputedMaxBSize()) {
3101 0 : ComputedMaxBSize() = ComputedMinBSize();
3102 : }
3103 397 : }
3104 :
3105 : bool
3106 54 : ReflowInput::IsFloating() const
3107 : {
3108 54 : return mStyleDisplay->IsFloating(mFrame);
3109 : }
3110 :
3111 : mozilla::StyleDisplay
3112 575 : ReflowInput::GetDisplay() const
3113 : {
3114 575 : return mStyleDisplay->GetDisplay(mFrame);
3115 : }
|