[LFC] Align compute functions styles.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Jun 2018 16:00:56 +0000 (16:00 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Jun 2018 16:00:56 +0000 (16:00 +0000)
https://bugs.webkit.org/show_bug.cgi?id=186649

Reviewed by Antti Koivisto.

Improve code readability.

* layout/FormattingContext.h:
* layout/FormattingContextGeometry.cpp:
(WebCore::Layout::contentHeightForFormattingContextRoot):
(WebCore::Layout::FormattingContext::Geometry::computedValueIfNotAuto):
(WebCore::Layout::FormattingContext::Geometry::outOfFlowReplacedVerticalGeometry):
(WebCore::Layout::FormattingContext::Geometry::outOfFlowReplacedHorizontalGeometry):
(WebCore::Layout::FormattingContext::Geometry::floatingNonReplacedWidthAndMargin):
(WebCore::Layout::FormattingContext::Geometry::floatingReplacedHeightAndMargin):
(WebCore::Layout::FormattingContext::Geometry::floatingReplacedWidthAndMargin):
(WebCore::Layout::FormattingContext::Geometry::inlineReplacedHeightAndMargin):
(WebCore::Layout::FormattingContext::Geometry::inlineReplacedWidthAndMargin):
(WebCore::Layout::FormattingContext::Geometry::computedNonCollapsedHorizontalMarginValue):
(WebCore::Layout::FormattingContext::Geometry::computedNonCollapsedVerticalMarginValue):
(WebCore::Layout::computedValueIfNotAuto): Deleted.
* layout/blockformatting/BlockFormattingContextGeometry.cpp:
(WebCore::Layout::BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMargin):
(WebCore::Layout::BlockFormattingContext::Geometry::inFlowNonReplacedWidthAndMargin):
(WebCore::Layout::BlockFormattingContext::Geometry::inFlowReplacedWidthAndMargin):
(WebCore::Layout::BlockFormattingContext::Geometry::staticPosition):
(WebCore::Layout::BlockFormattingContext::Geometry::inFlowPositionedPosition):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@232871 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/layout/FormattingContext.h
Source/WebCore/layout/FormattingContextGeometry.cpp
Source/WebCore/layout/blockformatting/BlockFormattingContextGeometry.cpp

index 3d33706..44553ce 100644 (file)
@@ -1,5 +1,35 @@
 2018-06-15  Zalan Bujtas  <zalan@apple.com>
 
+        [LFC] Align compute functions styles.
+        https://bugs.webkit.org/show_bug.cgi?id=186649
+
+        Reviewed by Antti Koivisto.
+
+        Improve code readability.
+
+        * layout/FormattingContext.h:
+        * layout/FormattingContextGeometry.cpp:
+        (WebCore::Layout::contentHeightForFormattingContextRoot):
+        (WebCore::Layout::FormattingContext::Geometry::computedValueIfNotAuto):
+        (WebCore::Layout::FormattingContext::Geometry::outOfFlowReplacedVerticalGeometry):
+        (WebCore::Layout::FormattingContext::Geometry::outOfFlowReplacedHorizontalGeometry):
+        (WebCore::Layout::FormattingContext::Geometry::floatingNonReplacedWidthAndMargin):
+        (WebCore::Layout::FormattingContext::Geometry::floatingReplacedHeightAndMargin):
+        (WebCore::Layout::FormattingContext::Geometry::floatingReplacedWidthAndMargin):
+        (WebCore::Layout::FormattingContext::Geometry::inlineReplacedHeightAndMargin):
+        (WebCore::Layout::FormattingContext::Geometry::inlineReplacedWidthAndMargin):
+        (WebCore::Layout::FormattingContext::Geometry::computedNonCollapsedHorizontalMarginValue):
+        (WebCore::Layout::FormattingContext::Geometry::computedNonCollapsedVerticalMarginValue):
+        (WebCore::Layout::computedValueIfNotAuto): Deleted.
+        * layout/blockformatting/BlockFormattingContextGeometry.cpp:
+        (WebCore::Layout::BlockFormattingContext::Geometry::inFlowNonReplacedHeightAndMargin):
+        (WebCore::Layout::BlockFormattingContext::Geometry::inFlowNonReplacedWidthAndMargin):
+        (WebCore::Layout::BlockFormattingContext::Geometry::inFlowReplacedWidthAndMargin):
+        (WebCore::Layout::BlockFormattingContext::Geometry::staticPosition):
+        (WebCore::Layout::BlockFormattingContext::Geometry::inFlowPositionedPosition):
+
+2018-06-15  Zalan Bujtas  <zalan@apple.com>
+
         [LFC] Add FormattingContextLayout logging channel
         https://bugs.webkit.org/show_bug.cgi?id=186637
 
index 53e2c1e..5afff74 100644 (file)
@@ -119,6 +119,8 @@ protected:
         static Display::Box::HorizontalEdges computedNonCollapsedHorizontalMarginValue(const LayoutContext&, const Box&);
         static Display::Box::VerticalEdges computedNonCollapsedVerticalMarginValue(const LayoutContext&, const Box&);
 
+        static std::optional<LayoutUnit> computedValueIfNotAuto(const Length& geometryProperty, LayoutUnit containingBlockWidth);
+
     private:
         static VerticalGeometry outOfFlowReplacedVerticalGeometry(LayoutContext&, const Box&);
         static HorizontalGeometry outOfFlowReplacedHorizontalGeometry(LayoutContext&, const Box&);
index d347d40..6443c09 100644 (file)
@@ -34,6 +34,7 @@ namespace Layout {
 static LayoutUnit contentHeightForFormattingContextRoot(LayoutContext& layoutContext, const Box& layoutBox)
 {
     ASSERT(layoutBox.style().logicalHeight().isAuto() && layoutBox.establishesFormattingContext());
+
     // 10.6.7 'Auto' heights for block formatting context roots
 
     // If it only has inline-level children, the height is the distance between the top of the topmost line box and the bottom of the bottommost line box.
@@ -67,7 +68,7 @@ static LayoutUnit shrinkToFitWidth(LayoutContext&, const Box& layoutBox)
     return { };
 }
 
-static std::optional<LayoutUnit> computedValueIfNotAuto(const Length& geometryProperty, LayoutUnit containingBlockWidth)
+std::optional<LayoutUnit> FormattingContext::Geometry::computedValueIfNotAuto(const Length& geometryProperty, LayoutUnit containingBlockWidth)
 {
     if (geometryProperty.isAuto())
         return std::nullopt;
@@ -335,6 +336,7 @@ FormattingContext::Geometry::HorizontalGeometry FormattingContext::Geometry::out
 FormattingContext::Geometry::VerticalGeometry FormattingContext::Geometry::outOfFlowReplacedVerticalGeometry(LayoutContext& layoutContext, const Box& layoutBox)
 {
     ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced());
+
     // 10.6.5 Absolutely positioned, replaced elements
     //
     // The used value of 'height' is determined as for inline replaced elements.
@@ -403,6 +405,7 @@ FormattingContext::Geometry::VerticalGeometry FormattingContext::Geometry::outOf
 FormattingContext::Geometry::HorizontalGeometry FormattingContext::Geometry::outOfFlowReplacedHorizontalGeometry(LayoutContext& layoutContext, const Box& layoutBox)
 {
     ASSERT(layoutBox.isOutOfFlowPositioned() && layoutBox.replaced());
+
     // 10.3.8 Absolutely positioned, replaced elements
     // In this case, section 10.3.7 applies up through and including the constraint equation, but the rest of section 10.3.7 is replaced by the following rules:
     //
@@ -535,19 +538,24 @@ FormattingContext::Geometry::WidthAndMargin FormattingContext::Geometry::floatin
     // 1. If 'margin-left', or 'margin-right' are computed as 'auto', their used value is '0'.
     // 2. If 'width' is computed as 'auto', the used value is the "shrink-to-fit" width.
 
-    auto& style = layoutBox.style();
-    auto width = style.logicalWidth();
+    auto& containingBlock = *layoutBox.containingBlock();
+    auto& containingBlockDisplayBox = *layoutContext.displayBoxForLayoutBox(containingBlock);
+
     // #1
-    auto computedNonCollapsedHorizontalMarginValues = computedNonCollapsedHorizontalMarginValue(layoutContext, layoutBox);
-    // #2
-    auto computedWidthValue = width.isAuto() ? shrinkToFitWidth(layoutContext, layoutBox) : LayoutUnit(width.value());
-    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Width][Margin] -> floating non-replaced -> width(" << computedWidthValue << "px) margin(" << computedNonCollapsedHorizontalMarginValues.left << "px, " << computedNonCollapsedHorizontalMarginValues.right << "px) -> layoutBox(" << &layoutBox << ")");
-    return FormattingContext::Geometry::WidthAndMargin { computedWidthValue, computedNonCollapsedHorizontalMarginValues };
+    auto margin = computedNonCollapsedHorizontalMarginValue(layoutContext, layoutBox);
+      // #2
+    auto width = computedValueIfNotAuto(layoutBox.style().logicalWidth(), containingBlockDisplayBox.width());
+    if (!width)
+        width = shrinkToFitWidth(layoutContext, layoutBox);
+
+    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Width][Margin] -> floating non-replaced -> width(" << *width << "px) margin(" << margin.left << "px, " << margin.right << "px) -> layoutBox(" << &layoutBox << ")");
+    return FormattingContext::Geometry::WidthAndMargin { *width, margin };
 }
 
 FormattingContext::Geometry::HeightAndMargin FormattingContext::Geometry::floatingReplacedHeightAndMargin(LayoutContext& layoutContext, const Box& layoutBox)
 {
     ASSERT(layoutBox.isFloatingPositioned() && layoutBox.replaced());
+
     // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block'
     // replaced elements in normal flow and floating replaced elements
     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Height][Margin] -> floating replaced -> redirected to inline replaced");
@@ -557,13 +565,15 @@ FormattingContext::Geometry::HeightAndMargin FormattingContext::Geometry::floati
 FormattingContext::Geometry::WidthAndMargin FormattingContext::Geometry::floatingReplacedWidthAndMargin(LayoutContext& layoutContext, const Box& layoutBox)
 {
     ASSERT(layoutBox.isFloatingPositioned() && layoutBox.replaced());
+
     // 10.3.6 Floating, replaced elements
     //
     // 1. If 'margin-left' or 'margin-right' are computed as 'auto', their used value is '0'.
     // 2. The used value of 'width' is determined as for inline replaced elements.
-    auto computedNonCollapsedHorizontalMarginValues = computedNonCollapsedHorizontalMarginValue(layoutContext, layoutBox);
+    auto margin = computedNonCollapsedHorizontalMarginValue(layoutContext, layoutBox);
+
     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Height][Margin] -> floating replaced -> redirected to inline replaced");
-    return inlineReplacedWidthAndMargin(layoutContext, layoutBox, computedNonCollapsedHorizontalMarginValues.left, computedNonCollapsedHorizontalMarginValues.right);
+    return inlineReplacedWidthAndMargin(layoutContext, layoutBox, margin.left, margin.right);
 }
 
 FormattingContext::Geometry::VerticalGeometry FormattingContext::Geometry::outOfFlowVerticalGeometry(LayoutContext& layoutContext, const Box& layoutBox)
@@ -605,6 +615,7 @@ FormattingContext::Geometry::WidthAndMargin FormattingContext::Geometry::floatin
 FormattingContext::Geometry::HeightAndMargin FormattingContext::Geometry::inlineReplacedHeightAndMargin(LayoutContext& layoutContext, const Box& layoutBox)
 {
     ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced());
+
     // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' replaced elements in normal flow and floating replaced elements
     //
     // 1. If 'margin-top', or 'margin-bottom' are 'auto', their used value is 0.
@@ -616,39 +627,40 @@ FormattingContext::Geometry::HeightAndMargin FormattingContext::Geometry::inline
     //    the height of the largest rectangle that has a 2:1 ratio, has a height not greater than 150px, and has a width not greater than the device width.
 
     // #1
-    auto computedNonCollapsedVerticalMarginValues = computedNonCollapsedVerticalMarginValue(layoutContext, layoutBox);
+    auto margin = computedNonCollapsedVerticalMarginValue(layoutContext, layoutBox);
 
     auto& style = layoutBox.style();
-    auto height = style.logicalHeight();
-    LayoutUnit computedHeightValue;
-    if (height.isAuto()) {
-        auto width = style.logicalWidth();
-        auto replaced = layoutBox.replaced();
-
-        if (width.isAuto() && replaced->hasIntrinsicHeight()) {
-            // #2
-            computedHeightValue = replaced->intrinsicHeight();
-        } else if (replaced->hasIntrinsicRatio()) {
-            // #3
-            computedHeightValue = width.value() / replaced->intrinsicRatio();
-        } else if (replaced->hasIntrinsicHeight()) {
-            // #4
-            computedHeightValue = replaced->intrinsicHeight();
-        } else {
-            // #5
-            computedHeightValue = 150;
-        }
-    } else
-        computedHeightValue = height.value();
+    auto replaced = layoutBox.replaced();
+    auto& containingBlock = *layoutBox.containingBlock();
+    auto& containingBlockDisplayBox = *layoutContext.displayBoxForLayoutBox(containingBlock);
+    auto height = computedValueIfNotAuto(style.logicalHeight(), containingBlockDisplayBox.height());
+    auto width = computedValueIfNotAuto(style.logicalWidth(), containingBlockDisplayBox.width());
 
-    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Height][Margin] -> inflow replaced -> height(" << computedHeightValue << "px) margin(" << computedNonCollapsedVerticalMarginValues.top << "px, " << computedNonCollapsedVerticalMarginValues.bottom << "px) -> layoutBox(" << &layoutBox << ")");
-    return { computedHeightValue, computedNonCollapsedVerticalMarginValues };
+    if (!height && !width && replaced->hasIntrinsicHeight()) {
+        // #2
+        height = replaced->intrinsicHeight();
+    } else if (!height && replaced->hasIntrinsicRatio()) {
+        // #3
+        height = *width / replaced->intrinsicRatio();
+    } else if (!height && replaced->hasIntrinsicHeight()) {
+        // #4
+        height = replaced->intrinsicHeight();
+    } else if (!height) {
+        // #5
+        height = { 150 };
+    }
+
+    ASSERT(height);
+
+    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Height][Margin] -> inflow replaced -> height(" << *height << "px) margin(" << margin.top << "px, " << margin.bottom << "px) -> layoutBox(" << &layoutBox << ")");
+    return { *height, margin };
 }
 
 FormattingContext::Geometry::WidthAndMargin FormattingContext::Geometry::inlineReplacedWidthAndMargin(LayoutContext& layoutContext, const Box& layoutBox,
     std::optional<LayoutUnit> precomputedMarginLeft, std::optional<LayoutUnit> precomputedMarginRight)
 {
     ASSERT((layoutBox.isOutOfFlowPositioned() || layoutBox.isFloatingPositioned() || layoutBox.isInFlow()) && layoutBox.replaced());
+
     // 10.3.2 Inline, replaced elements
     //
     // A computed value of 'auto' for 'margin-left' or 'margin-right' becomes a used value of '0'.
@@ -667,53 +679,56 @@ FormattingContext::Geometry::WidthAndMargin FormattingContext::Geometry::inlineR
     //
     // 5. Otherwise, if 'width' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'width' becomes 300px.
     //    If 300px is too wide to fit the device, UAs should use the width of the largest rectangle that has a 2:1 ratio and fits the device instead.
+
     auto& style = layoutBox.style();
-    auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width();
+    auto& containingBlock = *layoutBox.containingBlock();
+    auto& containingBlockDisplayBox = *layoutContext.displayBoxForLayoutBox(containingBlock);
 
     auto computeMarginRight = [&]() {
         if (precomputedMarginRight)
             return precomputedMarginRight.value();
-        auto marginRight = style.marginRight();
-        return marginRight.isAuto() ? LayoutUnit { 0 } : valueForLength(marginRight, containingBlockWidth);
+        auto marginRight = computedValueIfNotAuto(style.marginRight(), containingBlockDisplayBox.width());
+        return marginRight.value_or(LayoutUnit { 0 });
     };
 
     auto computeMarginLeft = [&]() {
         if (precomputedMarginLeft)
             return precomputedMarginLeft.value();
-        auto marginLeft = style.marginLeft();
-        return marginLeft.isAuto() ? LayoutUnit { 0 } : valueForLength(marginLeft, containingBlockWidth);
+        auto marginLeft = computedValueIfNotAuto(style.marginLeft(), containingBlockDisplayBox.width());
+        return marginLeft.value_or(LayoutUnit { 0 });
     };
 
-    LayoutUnit computedMarginLeftValue = computeMarginLeft();
-    LayoutUnit computedMarginRightValue = computeMarginRight();
+    LayoutUnit marginLeft = computeMarginLeft();
+    LayoutUnit marginRight = computeMarginRight();
 
-    LayoutUnit computedWidthValue;
-    auto width = style.logicalWidth();
-    auto height = style.logicalHeight();
     auto replaced = layoutBox.replaced();
+    auto height = computedValueIfNotAuto(style.logicalHeight(), containingBlockDisplayBox.height());
+    auto width = computedValueIfNotAuto(style.logicalWidth(), containingBlockDisplayBox.width());
+
     ASSERT(replaced);
 
-    if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicWidth()) {
+    if (!width && !height && replaced->hasIntrinsicWidth()) {
         // #1
-        computedWidthValue = replaced->intrinsicWidth();
-    } else if (width.isAuto() && (height.isCalculated() || replaced->hasIntrinsicHeight()) && replaced->hasIntrinsicRatio()) {
+        width = replaced->intrinsicWidth();
+    } else if ((!width && !height && !replaced->hasIntrinsicWidth() && replaced->hasIntrinsicHeight() && replaced->hasIntrinsicRatio())
+        || (!width && height && replaced->hasIntrinsicRatio())) { 
         // #2
-        auto usedHeight = height.isCalculated() ? LayoutUnit(height.value()) : replaced->intrinsicHeight();
-        computedWidthValue = usedHeight * replaced->intrinsicRatio();
-    } else if (width.isAuto() && height.isAuto() && replaced->hasIntrinsicRatio()) {
+        auto usedHeight = height.value_or(replaced->intrinsicHeight());
+        width = usedHeight * replaced->intrinsicRatio();
+    } else if (!width && !height && replaced->hasIntrinsicRatio() && !replaced->hasIntrinsicWidth() && !replaced->hasIntrinsicHeight()) {
         // #3
         // FIXME: undefined but surely doable.
         ASSERT_NOT_IMPLEMENTED_YET();
-    } else if (width.isAuto() && replaced->hasIntrinsicWidth()) {
+    } else if (!width && replaced->hasIntrinsicWidth()) {
         // #4
-        computedWidthValue = replaced->intrinsicWidth();
+        width = replaced->intrinsicWidth();
     } else {
         // #5
-        computedWidthValue = 300;
+        width = { 300 };
     }
 
-    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Width][Margin] -> inflow replaced -> width(" << computedWidthValue << "px) margin(" << computedMarginLeftValue << "px, " << computedMarginRightValue << "px) -> layoutBox(" << &layoutBox << ")");
-    return { computedWidthValue, { computedMarginLeftValue, computedMarginRightValue } };
+    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Width][Margin] -> inflow replaced -> width(" << *width << "px) margin(" << marginLeft << "px, " << marginRight << "px) -> layoutBox(" << &layoutBox << ")");
+    return { *width, { marginLeft, marginRight } };
 }
 
 Display::Box::Edges FormattingContext::Geometry::computedBorder(LayoutContext&, const Box& layoutBox)
@@ -743,29 +758,25 @@ std::optional<Display::Box::Edges> FormattingContext::Geometry::computedPadding(
 Display::Box::HorizontalEdges FormattingContext::Geometry::computedNonCollapsedHorizontalMarginValue(const LayoutContext& layoutContext, const Box& layoutBox)
 {
     auto& style = layoutBox.style();
-    auto marginLeft = style.marginLeft();
-    auto marginRight = style.marginRight();
-
     auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width();
-    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Margin] -> non collapsed horizontal -> layoutBox: " << &layoutBox);
-    return {
-        marginLeft.isAuto() ? LayoutUnit { 0 } : valueForLength(marginLeft, containingBlockWidth),
-        marginRight.isAuto() ? LayoutUnit { 0 } : valueForLength(marginRight, containingBlockWidth)
-    };
+
+    auto marginLeft = computedValueIfNotAuto(style.marginLeft(), containingBlockWidth).value_or(LayoutUnit { 0 });
+    auto marginRight = computedValueIfNotAuto(style.marginRight(), containingBlockWidth).value_or(LayoutUnit { 0 });
+
+    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Margin] -> non collapsed horizontal -> margin(" << marginLeft << "px, " << marginRight << "px) -> layoutBox: " << &layoutBox);
+    return { marginLeft, marginRight };
 }
 
 Display::Box::VerticalEdges FormattingContext::Geometry::computedNonCollapsedVerticalMarginValue(const LayoutContext& layoutContext, const Box& layoutBox)
 {
     auto& style = layoutBox.style();
-    auto marginTop = style.marginTop();
-    auto marginBottom = style.marginBottom();
-
     auto containingBlockWidth = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->width();
-    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Margin] -> non collapsed vertical -> layoutBox: " << &layoutBox);
-    return {
-        marginTop.isAuto() ? LayoutUnit { 0 } : valueForLength(marginTop, containingBlockWidth),
-        marginBottom.isAuto() ? LayoutUnit { 0 } : valueForLength(marginBottom, containingBlockWidth)
-    };
+
+    auto marginTop = computedValueIfNotAuto(style.marginTop(), containingBlockWidth).value_or(LayoutUnit { 0 });
+    auto marginBottom = computedValueIfNotAuto(style.marginBottom(), containingBlockWidth).value_or(LayoutUnit { 0 });
+
+    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Margin] -> non collapsed vertical -> margin(" << marginTop << "px, " << marginBottom << "px) -> layoutBox: " << &layoutBox);
+    return { marginTop, marginBottom };
 }
 
 }
index 8efa333..58fa0aa 100644 (file)
@@ -73,6 +73,7 @@ FormattingContext::Geometry::HeightAndMargin BlockFormattingContext::Geometry::i
         // 4. zero, otherwise
         // Only children in the normal flow are taken into account (i.e., floating boxes and absolutely positioned boxes are ignored,
         // and relatively positioned boxes are considered without their offset). Note that the child box may be an anonymous block box.
+
         if (!layoutBox.style().logicalHeight().isAuto()) {
             // FIXME: Only fixed values yet.
             return layoutBox.style().logicalHeight().value();
@@ -227,20 +228,20 @@ FormattingContext::Geometry::WidthAndMargin BlockFormattingContext::Geometry::in
         return FormattingContext::Geometry::WidthAndMargin { computedWidthValue, { *computedMarginLeftValue, *computedMarginRightValue } };
     };
 
-    auto computedWidthAndMarginValue = compute();
+    auto widthAndMargin = compute();
     if (!isStretchedToViewport(layoutContext, layoutBox)) {
-        LOG_WITH_STREAM(FormattingContextLayout, stream << "[Width][Margin] -> inflow non-replaced -> width(" << computedWidthAndMarginValue.width << "px) margin(" << computedWidthAndMarginValue.margin.left << "px, " << computedWidthAndMarginValue.margin.right << "px) -> layoutBox(" << &layoutBox << ")");
-        return computedWidthAndMarginValue;
+        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 << ")");
+        return widthAndMargin;
     }
 
     auto initialContainingBlockWidth = layoutContext.displayBoxForLayoutBox(initialContainingBlock(layoutBox))->contentBox().width();
-    auto horizontalMargins = computedWidthAndMarginValue.margin.left + computedWidthAndMarginValue.margin.right;
+    auto horizontalMargins = widthAndMargin.margin.left + widthAndMargin.margin.right;
     // Stretch but never overstretch with the margins.
-    if (computedWidthAndMarginValue.width + horizontalMargins < initialContainingBlockWidth)
-        computedWidthAndMarginValue.width = initialContainingBlockWidth - horizontalMargins;
+    if (widthAndMargin.width + horizontalMargins < initialContainingBlockWidth)
+        widthAndMargin.width = initialContainingBlockWidth - horizontalMargins;
 
-    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Width][Margin] -> inflow non-replaced -> streched to viewport-> width(" << computedWidthAndMarginValue.width << "px) margin(" << computedWidthAndMarginValue.margin.left << "px, " << computedWidthAndMarginValue.margin.right << "px) -> layoutBox(" << &layoutBox << ")");
-    return { computedWidthAndMarginValue.width, computedWidthAndMarginValue.margin };
+    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 << ")");
+    return widthAndMargin;
 }
 
 FormattingContext::Geometry::WidthAndMargin BlockFormattingContext::Geometry::inFlowReplacedWidthAndMargin(LayoutContext& layoutContext, const Box& layoutBox)
@@ -253,12 +254,12 @@ FormattingContext::Geometry::WidthAndMargin BlockFormattingContext::Geometry::in
     // 2. Then the rules for non-replaced block-level elements are applied to determine the margins.
 
     // #1
-    auto inlineReplacedWidthAndMargin = FormattingContext::Geometry::inlineReplacedWidthAndMargin(layoutContext, layoutBox);
+    auto width = FormattingContext::Geometry::inlineReplacedWidthAndMargin(layoutContext, layoutBox).width;
     // #2
-    auto inlineReplacedWidthAndBlockNonReplacedMargin = inFlowNonReplacedWidthAndMargin(layoutContext, layoutBox, inlineReplacedWidthAndMargin.width);
-    ASSERT(inlineReplacedWidthAndMargin.width == inlineReplacedWidthAndBlockNonReplacedMargin.width);
-    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Width][Margin] -> inflow replaced -> width(" << inlineReplacedWidthAndBlockNonReplacedMargin.width << "px) margin(" << inlineReplacedWidthAndBlockNonReplacedMargin.margin.left << "px, " << inlineReplacedWidthAndBlockNonReplacedMargin.margin.left << "px) -> layoutBox(" << &layoutBox << ")");
-    return inlineReplacedWidthAndBlockNonReplacedMargin;
+    auto margin = inFlowNonReplacedWidthAndMargin(layoutContext, layoutBox, width).margin;
+
+    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Width][Margin] -> inflow replaced -> width(" << width << "px) margin(" << margin.left << "px, " << margin.left << "px) -> layoutBox(" << &layoutBox << ")");
+    return { width, margin };
 }
 
 LayoutPoint BlockFormattingContext::Geometry::staticPosition(LayoutContext& layoutContext, const Box& layoutBox)
@@ -268,6 +269,7 @@ LayoutPoint BlockFormattingContext::Geometry::staticPosition(LayoutContext& layo
     // The vertical distance between two sibling boxes is determined by the 'margin' properties.
     // Vertical margins between adjacent block-level boxes in a block formatting context collapse.
     // 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).
+
     auto containingBlockContentBox = layoutContext.displayBoxForLayoutBox(*layoutBox.containingBlock())->contentBox();
     // Start from the top of the container's content box.
     auto top = containingBlockContentBox.top();
@@ -283,6 +285,7 @@ LayoutPoint BlockFormattingContext::Geometry::staticPosition(LayoutContext& layo
 LayoutPoint BlockFormattingContext::Geometry::inFlowPositionedPosition(LayoutContext& layoutContext, const Box& layoutBox)
 {
     ASSERT(layoutBox.isInFlowPositioned());
+
     // 9.4.3 Relative positioning
     //
     // The 'top' and 'bottom' properties move relatively positioned element(s) up or down without changing their size.
@@ -291,22 +294,28 @@ LayoutPoint BlockFormattingContext::Geometry::inFlowPositionedPosition(LayoutCon
     // 1. If both are 'auto', their used values are both '0'.
     // 2. If one of them is 'auto', it becomes the negative of the other.
     // 3. If neither is 'auto', 'bottom' is ignored (i.e., the used value of 'bottom' will be minus the value of 'top').
-    auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox);
+
     auto& style = layoutBox.style();
+    auto& displayBox = *layoutContext.displayBoxForLayoutBox(layoutBox);
+    auto& containingBlock = *layoutBox.containingBlock();
+    auto& containingBlockDisplayBox = *layoutContext.displayBoxForLayoutBox(containingBlock);
+    auto containingBlockWidth = containingBlockDisplayBox.width();
 
-    auto top = style.logicalTop();
-    auto bottom = style.logicalBottom();
-    LayoutUnit topDelta;
+    auto top = FormattingContext::Geometry::computedValueIfNotAuto(style.logicalTop(), containingBlockWidth);
+    auto bottom = FormattingContext::Geometry::computedValueIfNotAuto(style.logicalBottom(), containingBlockWidth);
 
-    if (top.isAuto() && bottom.isAuto()) {
+    if (!top && !bottom) {
         // #1
-        topDelta = 0;
-    } else if (top.isAuto()) {
+        top = bottom = { 0 };
+    } else if (!top) {
         // #2
-        topDelta = -bottom.value();
-    } else if (bottom.isAuto()) {
-        // #3 #4
-        topDelta = top.value();
+        top = -*bottom;
+    } else if (!bottom) {
+        // #3
+        bottom = -*top;
+    } else {
+        // #4
+        bottom = std::nullopt;
     }
 
     // For relatively positioned elements, 'left' and 'right' move the box(es) horizontally, without changing their size.
@@ -319,30 +328,36 @@ LayoutPoint BlockFormattingContext::Geometry::inFlowPositionedPosition(LayoutCon
     // 4. If neither 'left' nor 'right' is 'auto', the position is over-constrained, and one of them has to be ignored.
     //    If the 'direction' property of the containing block is 'ltr', the value of 'left' wins and 'right' becomes -'left'.
     //    If 'direction' of the containing block is 'rtl', 'right' wins and 'left' is ignored.
-    //
-    auto left = style.logicalLeft();
-    auto right = style.logicalRight();
-    LayoutUnit leftDelta;
 
-    if (left.isAuto() && right.isAuto()) {
+    auto left = FormattingContext::Geometry::computedValueIfNotAuto(style.logicalLeft(), containingBlockWidth);
+    auto right = FormattingContext::Geometry::computedValueIfNotAuto(style.logicalRight(), containingBlockWidth);
+
+    if (!left && !right) {
         // #1
-        leftDelta = 0;
-    } else if (left.isAuto()) {
+        left = right = { 0 };
+    } else if (!left) {
         // #2
-        leftDelta = -right.value();
-    } else if (right.isAuto()) {
+        left = -*right;
+    } else if (!right) {
         // #3
-        leftDelta = left.value();
+        right = -*left;
     } else {
         // #4
-        // FIXME: take direction into account
-        leftDelta = left.value();
+        auto isLeftToRightDirection = containingBlock.style().isLeftToRightDirection();
+        if (isLeftToRightDirection)
+            right = -*left;
+        else
+            left = std::nullopt;
     }
 
-    auto computedLeft = displayBox.left() + leftDelta;
-    auto computedTop = displayBox.top() + topDelta;
-    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Position] -> positioned inflow -> top(" << top << "px) left(" << left << "px) layoutBox(" << &layoutBox << ")");
-    return { computedLeft, computedTop };
+    ASSERT(!bottom || *top == -*bottom);
+    ASSERT(!left || *left == -*right);
+
+    auto newTopPosition = displayBox.top() + *top;
+    auto newLeftPosition = displayBox.left() + left.value_or(-*right);
+
+    LOG_WITH_STREAM(FormattingContextLayout, stream << "[Position] -> positioned inflow -> top(" << newTopPosition << "px) left(" << newLeftPosition << "px) layoutBox(" << &layoutBox << ")");
+    return { newTopPosition, newLeftPosition };
 }
 
 FormattingContext::Geometry::HeightAndMargin BlockFormattingContext::Geometry::inFlowHeightAndMargin(LayoutContext& layoutContext, const Box& layoutBox)