Add changes missing from r234925.
[WebKit-https.git] / Source / WebCore / layout / blockformatting / BlockFormattingContextGeometry.cpp
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "BlockFormattingContext.h"
28
29 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
30
31 #include "FormattingContext.h"
32 #include "LayoutChildIterator.h"
33 #include "Logging.h"
34 #include <wtf/text/TextStream.h>
35
36 namespace WebCore {
37 namespace Layout {
38
39 static const Container& initialContainingBlock(const Box& layoutBox)
40 {
41     auto* containingBlock = layoutBox.containingBlock();
42     while (containingBlock->containingBlock())
43         containingBlock = containingBlock->containingBlock();
44     return *containingBlock;
45 }
46
47 static bool isStretchedToInitialContainingBlock(const LayoutContext& layoutContext, const Box& layoutBox)
48 {
49     ASSERT(layoutBox.isInFlow());
50     // In quirks mode, body and html stretch to the viewport.
51     if (!layoutContext.inQuirksMode())
52         return false;
53
54     if (!layoutBox.isDocumentBox() && !layoutBox.isBodyBox())
55         return false;
56
57     return layoutBox.style().logicalHeight().isAuto();
58 }
59
60 static HeightAndMargin stretchHeightToInitialContainingBlock(HeightAndMargin heightAndMargin, LayoutUnit initialContainingBlockHeight)
61 {
62     auto verticalMargins = heightAndMargin.margin.top + heightAndMargin.margin.bottom;
63     // Stretch but never overstretch with the margins.
64     if (heightAndMargin.height + verticalMargins < initialContainingBlockHeight)
65         heightAndMargin.height = initialContainingBlockHeight - verticalMargins;
66
67     return heightAndMargin;
68 }
69
70 static WidthAndMargin stretchWidthToInitialContainingBlock(WidthAndMargin widthAndMargin, LayoutUnit initialContainingBlockWidth)
71 {
72     auto horizontalMargins = widthAndMargin.margin.left + widthAndMargin.margin.right;
73     // Stretch but never overstretch with the margins.
74     if (widthAndMargin.width + horizontalMargins < initialContainingBlockWidth)
75         widthAndMargin.width = initialContainingBlockWidth - horizontalMargins;
76
77     return widthAndMargin;
78 }
79
80 HeightAndMargin BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMargin(LayoutContext& layoutContext, const Box& layoutBox)
81 {
82     ASSERT(layoutBox.isInFlow() && !layoutBox.replaced());
83     ASSERT(layoutBox.isOverflowVisible());
84
85     auto compute = [&]() -> HeightAndMargin {
86
87         // 10.6.3 Block-level non-replaced elements in normal flow when 'overflow' computes to 'visible'
88         //
89         // If 'margin-top', or 'margin-bottom' are 'auto', their used value is 0.
90         // If 'height' is 'auto', the height depends on whether the element has any block-level children and whether it has padding or borders:
91         // The element's height is the distance from its top content edge to the first applicable of the following:
92         // 1. the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines
93         // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin
94         //    does not collapse with the element's bottom margin
95         // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin
96         // 4. zero, otherwise
97         // Only children in the normal flow are taken into account (i.e., floating boxes and absolutely positioned boxes are ignored,
98         // and relatively positioned boxes are considered without their offset). Note that the child box may be an anonymous block box.
99
100         auto& style = layoutBox.style();
101         auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->contentBoxWidth();
102         auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox);
103
104         VerticalEdges nonCollapsedMargin = { FormattingContext::Geometry::computedValueIfNotAuto(style.marginTop(), containingBlockWidth).value_or(0),
105             FormattingContext::Geometry::computedValueIfNotAuto(style.marginBottom(), containingBlockWidth).value_or(0) }; 
106         VerticalEdges collapsedMargin = { MarginCollapse::marginTop(layoutContext, layoutBox), MarginCollapse::marginBottom(layoutContext, layoutBox) };
107         auto borderAndPaddingTop = displayBox.borderTop() + displayBox.paddingTop().value_or(0);
108         
109         auto height = style.logicalHeight();
110         if (!height.isAuto()) {
111             if (height.isFixed())
112                 return { style.logicalHeight().value(), nonCollapsedMargin, collapsedMargin };
113
114             // Most notably height percentage.
115             ASSERT_NOT_IMPLEMENTED_YET();
116         }
117
118         if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowChild())
119             return { 0, nonCollapsedMargin, collapsedMargin };
120
121         // 1. the bottom edge of the last line box, if the box establishes a inline formatting context with one or more lines
122         if (layoutBox.establishesInlineFormattingContext()) {
123             // height = lastLineBox().bottom();
124             return { 0, nonCollapsedMargin, collapsedMargin };
125         }
126
127         // 2. the bottom edge of the bottom (possibly collapsed) margin of its last in-flow child, if the child's bottom margin...
128         auto* lastInFlowChild = downcast<Container>(layoutBox).lastInFlowChild();
129         ASSERT(lastInFlowChild);
130         if (!MarginCollapse::isMarginBottomCollapsedWithParent(layoutContext, *lastInFlowChild)) {
131             auto* lastInFlowDisplayBox = layoutContext.displayBoxForLayoutBox(*lastInFlowChild);
132             ASSERT(lastInFlowDisplayBox);
133             return { lastInFlowDisplayBox->bottom() + lastInFlowDisplayBox->marginBottom() - borderAndPaddingTop, nonCollapsedMargin, collapsedMargin };
134         }
135
136         // 3. the bottom border edge of the last in-flow child whose top margin doesn't collapse with the element's bottom margin
137         auto* inFlowChild = lastInFlowChild;
138         while (inFlowChild && MarginCollapse::isMarginTopCollapsedWithParentMarginBottom(*inFlowChild))
139             inFlowChild = inFlowChild->previousInFlowSibling();
140         if (inFlowChild) {
141             auto* inFlowDisplayBox = layoutContext.displayBoxForLayoutBox(*inFlowChild);
142             ASSERT(inFlowDisplayBox);
143             return { inFlowDisplayBox->top() + inFlowDisplayBox->borderBox().height() - borderAndPaddingTop, nonCollapsedMargin, collapsedMargin };
144         }
145
146         // 4. zero, otherwise
147         return { 0, nonCollapsedMargin, collapsedMargin };
148     };
149
150     auto heightAndMargin = compute();
151
152     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Height][Margin] -> inflow non-replaced -> height(" << heightAndMargin.height << "px) margin(" << heightAndMargin.margin.top << "px, " << heightAndMargin.margin.bottom << "px) -> layoutBox(" << &layoutBox << ")");
153     return heightAndMargin;
154 }
155
156 WidthAndMargin BlockFormattingContext::Geometry::inFlowNonReplacedWidthAndMargin(LayoutContext& layoutContext, const Box& layoutBox,
157     std::optional<LayoutUnit> precomputedWidth)
158 {
159     ASSERT(layoutBox.isInFlow() && !layoutBox.replaced());
160
161     auto compute = [&]() {
162
163         // 10.3.3 Block-level, non-replaced elements in normal flow
164         //
165         // The following constraints must hold among the used values of the other properties:
166         // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block
167         //
168         // 1. If 'width' is not 'auto' and 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' 
169         //    (plus any of 'margin-left' or 'margin-right' that are not 'auto') is larger than the width of the containing block, then
170         //    any 'auto' values for 'margin-left' or 'margin-right' are, for the following rules, treated as zero.
171         //
172         // 2. If all of the above have a computed value other than 'auto', the values are said to be "over-constrained" and one of the used values will
173         //    have to be different from its computed value. If the 'direction' property of the containing block has the value 'ltr', the specified value
174         //    of 'margin-right' is ignored and the value is calculated so as to make the equality true. If the value of 'direction' is 'rtl',
175         //    this happens to 'margin-left' instead.
176         //
177         // 3. If there is exactly one value specified as 'auto', its used value follows from the equality.
178         //
179         // 4. If 'width' is set to 'auto', any other 'auto' values become '0' and 'width' follows from the resulting equality.
180         //
181         // 5. If both 'margin-left' and 'margin-right' are 'auto', their used values are equal. This horizontally centers the element with respect to the
182         //    edges of the containing block.
183
184         auto& style = layoutBox.style();
185         auto* containingBlock = layoutBox.containingBlock();
186         auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*containingBlock)->contentBoxWidth();
187         auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox);
188
189         auto width = FormattingContext::Geometry::computedValueIfNotAuto(precomputedWidth ? Length { precomputedWidth.value(), Fixed } : style.logicalWidth(), containingBlockWidth);
190         auto marginLeft = FormattingContext::Geometry::computedValueIfNotAuto(style.marginLeft(), containingBlockWidth);
191         auto marginRight = FormattingContext::Geometry::computedValueIfNotAuto(style.marginRight(), containingBlockWidth);
192         auto borderLeft = displayBox.borderLeft();
193         auto borderRight = displayBox.borderRight();
194         auto paddingLeft = displayBox.paddingLeft().value_or(0);
195         auto paddingRight = displayBox.paddingRight().value_or(0);
196
197         // #1
198         if (width) {
199             auto horizontalSpaceForMargin = containingBlockWidth - (marginLeft.value_or(0) + borderLeft + paddingLeft + *width + paddingRight + borderRight + marginRight.value_or(0));
200             if (horizontalSpaceForMargin < 0) {
201                 marginLeft = marginLeft.value_or(0);
202                 marginRight = marginRight.value_or(0);
203             }
204         }
205
206         // #2
207         if (width && marginLeft && marginRight) {
208             if (containingBlock->style().isLeftToRightDirection())
209                 marginRight = containingBlockWidth - (*marginLeft + borderLeft + paddingLeft  + *width + paddingRight + borderRight);
210             else
211                 marginLeft = containingBlockWidth - (borderLeft + paddingLeft + *width + paddingRight + borderRight + *marginRight);
212         }
213
214         // #3
215         if (!marginLeft && width && marginRight)
216             marginLeft = containingBlockWidth - (borderLeft + paddingLeft  + *width + paddingRight + borderRight + *marginRight);
217         else if (marginLeft && !width && marginRight)
218             width = containingBlockWidth - (*marginLeft + borderLeft + paddingLeft + paddingRight + borderRight + *marginRight);
219         else if (marginLeft && width && !marginRight)
220             marginRight = containingBlockWidth - (*marginLeft + borderLeft + paddingLeft + *width + paddingRight + borderRight);
221
222         // #4
223         if (!width) {
224             marginLeft = marginLeft.value_or(0);
225             marginRight = marginRight.value_or(0);
226             width = containingBlockWidth - (*marginLeft + borderLeft + paddingLeft + paddingRight + borderRight + *marginRight);
227         }
228
229         // #5
230         if (!marginLeft && !marginRight) {
231             auto horizontalSpaceForMargin = containingBlockWidth - (borderLeft + paddingLeft  + *width + paddingRight + borderRight);
232             marginLeft = marginRight = horizontalSpaceForMargin / 2;
233         }
234
235         ASSERT(width);
236         ASSERT(marginLeft);
237         ASSERT(marginRight);
238
239         return WidthAndMargin { *width, { *marginLeft, *marginRight } };
240     };
241
242     auto widthAndMargin = compute();
243     if (!isStretchedToInitialContainingBlock(layoutContext, layoutBox)) {
244         LOG_WITH_STREAM(FormattingContextLayout, stream << "[Width][Margin] -> inflow non-replaced -> width(" << widthAndMargin.width << "px) margin(" << widthAndMargin.margin.left << "px, " << widthAndMargin.margin.right << "px) -> layoutBox(" << &layoutBox << ")");
245         return widthAndMargin;
246     }
247
248     auto initialContainingBlockWidth = layoutContext.displayBoxForLayoutBox(initialContainingBlock(layoutBox))->contentBoxWidth();
249     widthAndMargin = stretchWidthToInitialContainingBlock(widthAndMargin, initialContainingBlockWidth);
250
251     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Width][Margin] -> inflow non-replaced -> streched to viewport-> width(" << widthAndMargin.width << "px) margin(" << widthAndMargin.margin.left << "px, " << widthAndMargin.margin.right << "px) -> layoutBox(" << &layoutBox << ")");
252     return widthAndMargin;
253 }
254
255 WidthAndMargin BlockFormattingContext::Geometry::inFlowReplacedWidthAndMargin(LayoutContext& layoutContext, const Box& layoutBox)
256 {
257     ASSERT(layoutBox.isInFlow() && layoutBox.replaced());
258
259     // 10.3.4 Block-level, replaced elements in normal flow
260     //
261     // 1. The used value of 'width' is determined as for inline replaced elements.
262     // 2. Then the rules for non-replaced block-level elements are applied to determine the margins.
263
264     // #1
265     auto width = FormattingContext::Geometry::inlineReplacedWidthAndMargin(layoutContext, layoutBox).width;
266     // #2
267     auto margin = inFlowNonReplacedWidthAndMargin(layoutContext, layoutBox, width).margin;
268
269     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Width][Margin] -> inflow replaced -> width(" << width << "px) margin(" << margin.left << "px, " << margin.left << "px) -> layoutBox(" << &layoutBox << ")");
270     return { width, margin };
271 }
272
273 Position BlockFormattingContext::Geometry::staticPosition(LayoutContext& layoutContext, const Box& layoutBox)
274 {
275     // https://www.w3.org/TR/CSS22/visuren.html#block-formatting
276     // In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block.
277     // The vertical distance between two sibling boxes is determined by the 'margin' properties.
278     // Vertical margins between adjacent block-level boxes in a block formatting context collapse.
279     // In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch).
280
281     LayoutUnit top;
282     auto& containingBlockDisplayBox = *layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock());
283     if (auto* previousInFlowSibling = layoutBox.previousInFlowSibling()) {
284         auto& previousInFlowDisplayBox = *layoutContext.displayBoxForLayoutBox(*previousInFlowSibling);
285         top = previousInFlowDisplayBox.bottom() + previousInFlowDisplayBox.marginBottom();
286     } else
287         top = containingBlockDisplayBox.contentBoxTop();
288
289     auto left = containingBlockDisplayBox.contentBoxLeft();
290     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Position] -> static -> top(" << top << "px) left(" << left << "px) layoutBox(" << &layoutBox << ")");
291     return { left, top };
292 }
293
294 Position BlockFormattingContext::Geometry::inFlowPositionedPosition(LayoutContext& layoutContext, const Box& layoutBox)
295 {
296     ASSERT(layoutBox.isInFlowPositioned());
297
298     // 9.4.3 Relative positioning
299     //
300     // The 'top' and 'bottom' properties move relatively positioned element(s) up or down without changing their size.
301     // Top' moves the boxes down, and 'bottom' moves them up. Since boxes are not split or stretched as a result of 'top' or 'bottom', the used values are always: top = -bottom.
302     //
303     // 1. If both are 'auto', their used values are both '0'.
304     // 2. If one of them is 'auto', it becomes the negative of the other.
305     // 3. If neither is 'auto', 'bottom' is ignored (i.e., the used value of 'bottom' will be minus the value of 'top').
306
307     auto& style = layoutBox.style();
308     auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox);
309     auto& containingBlock = *layoutBox.containingBlock();
310     auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(containingBlock)->contentBoxWidth();
311
312     auto top = FormattingContext::Geometry::computedValueIfNotAuto(style.logicalTop(), containingBlockWidth);
313     auto bottom = FormattingContext::Geometry::computedValueIfNotAuto(style.logicalBottom(), containingBlockWidth);
314
315     if (!top && !bottom) {
316         // #1
317         top = bottom = { 0 };
318     } else if (!top) {
319         // #2
320         top = -*bottom;
321     } else if (!bottom) {
322         // #3
323         bottom = -*top;
324     } else {
325         // #4
326         bottom = std::nullopt;
327     }
328
329     // For relatively positioned elements, 'left' and 'right' move the box(es) horizontally, without changing their size.
330     // 'Left' moves the boxes to the right, and 'right' moves them to the left.
331     // Since boxes are not split or stretched as a result of 'left' or 'right', the used values are always: left = -right.
332     //
333     // 1. If both 'left' and 'right' are 'auto' (their initial values), the used values are '0' (i.e., the boxes stay in their original position).
334     // 2. If 'left' is 'auto', its used value is minus the value of 'right' (i.e., the boxes move to the left by the value of 'right').
335     // 3. If 'right' is specified as 'auto', its used value is minus the value of 'left'.
336     // 4. If neither 'left' nor 'right' is 'auto', the position is over-constrained, and one of them has to be ignored.
337     //    If the 'direction' property of the containing block is 'ltr', the value of 'left' wins and 'right' becomes -'left'.
338     //    If 'direction' of the containing block is 'rtl', 'right' wins and 'left' is ignored.
339
340     auto left = FormattingContext::Geometry::computedValueIfNotAuto(style.logicalLeft(), containingBlockWidth);
341     auto right = FormattingContext::Geometry::computedValueIfNotAuto(style.logicalRight(), containingBlockWidth);
342
343     if (!left && !right) {
344         // #1
345         left = right = { 0 };
346     } else if (!left) {
347         // #2
348         left = -*right;
349     } else if (!right) {
350         // #3
351         right = -*left;
352     } else {
353         // #4
354         auto isLeftToRightDirection = containingBlock.style().isLeftToRightDirection();
355         if (isLeftToRightDirection)
356             right = -*left;
357         else
358             left = std::nullopt;
359     }
360
361     ASSERT(!bottom || *top == -*bottom);
362     ASSERT(!left || *left == -*right);
363
364     auto newTopPosition = displayBox.top() + *top;
365     auto newLeftPosition = displayBox.left() + left.value_or(-*right);
366
367     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Position] -> positioned inflow -> top(" << newTopPosition << "px) left(" << newLeftPosition << "px) layoutBox(" << &layoutBox << ")");
368     return { newLeftPosition, newTopPosition };
369 }
370
371 HeightAndMargin BlockFormattingContext::Geometry::inFlowHeightAndMargin(LayoutContext& layoutContext, const Box& layoutBox)
372 {
373     ASSERT(layoutBox.isInFlow());
374
375     // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block'
376     // replaced elements in normal flow and floating replaced elements
377     if (layoutBox.replaced())
378         return FormattingContext::Geometry::inlineReplacedHeightAndMargin(layoutContext, layoutBox);
379
380     HeightAndMargin heightAndMargin;
381     // TODO: Figure out the case for the document element. Let's just complicated-case it for now.
382     if (layoutBox.isOverflowVisible() && !layoutBox.isDocumentBox())
383         heightAndMargin = inFlowNonReplacedHeightAndMargin(layoutContext, layoutBox);
384     else {
385         // 10.6.6 Complicated cases
386         // Block-level, non-replaced elements in normal flow when 'overflow' does not compute to 'visible' (except if the 'overflow' property's value has been propagated to the viewport).
387         heightAndMargin = FormattingContext::Geometry::complicatedCases(layoutContext, layoutBox);
388     }
389
390     if (!isStretchedToInitialContainingBlock(layoutContext, layoutBox))
391         return heightAndMargin;
392
393     auto initialContainingBlockHeight = layoutContext.displayBoxForLayoutBox(initialContainingBlock(layoutBox))->contentBoxHeight();
394     heightAndMargin = stretchHeightToInitialContainingBlock(heightAndMargin, initialContainingBlockHeight);
395
396     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Height][Margin] -> inflow non-replaced -> streched to viewport -> height(" << heightAndMargin.height << "px) margin(" << heightAndMargin.margin.top << "px, " << heightAndMargin.margin.bottom << "px) -> layoutBox(" << &layoutBox << ")");
397     return heightAndMargin;
398 }
399
400 WidthAndMargin BlockFormattingContext::Geometry::inFlowWidthAndMargin(LayoutContext& layoutContext, const Box& layoutBox)
401 {
402     ASSERT(layoutBox.isInFlow());
403
404     if (!layoutBox.replaced())
405         return inFlowNonReplacedWidthAndMargin(layoutContext, layoutBox);
406     return inFlowReplacedWidthAndMargin(layoutContext, layoutBox);
407 }
408
409 bool BlockFormattingContext::Geometry::instrinsicWidthConstraintsNeedChildrenWidth(const Box& layoutBox)
410 {
411     if (!is<Container>(layoutBox) || !downcast<Container>(layoutBox).hasInFlowOrFloatingChild())
412         return false;
413     return layoutBox.style().width().isAuto();
414 }
415
416 FormattingContext::InstrinsicWidthConstraints BlockFormattingContext::Geometry::instrinsicWidthConstraints(LayoutContext& layoutContext, const Box& layoutBox)
417 {
418     auto& style = layoutBox.style();
419     if (auto width = FormattingContext::Geometry::fixedValue(style.logicalWidth()))
420         return { *width, *width };
421
422     // Minimum/maximum width can't be depending on the containing block's width.
423     if (!style.logicalWidth().isAuto())
424         return { };
425
426     if (!is<Container>(layoutBox))
427         return { };
428
429     LayoutUnit minimumIntrinsicWidth;
430     LayoutUnit maximumIntrinsicWidth;
431
432     for (auto& child : childrenOfType<Box>(downcast<Container>(layoutBox))) {
433         if (child.isOutOfFlowPositioned())
434             continue;
435         auto& formattingState = layoutContext.formattingStateForBox(child);
436         ASSERT(formattingState.isBlockFormattingState());
437         auto childInstrinsicWidthConstraints = formattingState.instrinsicWidthConstraints(child);
438         ASSERT(childInstrinsicWidthConstraints);
439         
440         auto& style = child.style();
441         auto horizontalMarginBorderAndPadding = FormattingContext::Geometry::fixedValue(style.marginLeft()).value_or(0)
442             + LayoutUnit { style.borderLeftWidth() }
443             + FormattingContext::Geometry::fixedValue(style.paddingLeft()).value_or(0)
444             + FormattingContext::Geometry::fixedValue(style.paddingRight()).value_or(0)
445             + LayoutUnit { style.borderRightWidth() }
446             + FormattingContext::Geometry::fixedValue(style.marginRight()).value_or(0);
447
448         minimumIntrinsicWidth = std::max(minimumIntrinsicWidth, childInstrinsicWidthConstraints->minimum + horizontalMarginBorderAndPadding); 
449         maximumIntrinsicWidth = std::max(maximumIntrinsicWidth, childInstrinsicWidthConstraints->maximum + horizontalMarginBorderAndPadding); 
450     }
451
452     return { minimumIntrinsicWidth, maximumIntrinsicWidth };
453 }
454
455 }
456 }
457
458 #endif