فهرست منبع

LibWeb: Resolve auto margins on abspos elements in more cases

Specifically, we now handle cases where all three of `left`, `width`
and `right` are non-`auto`.
Andreas Kling 2 سال پیش
والد
کامیت
41da9a4231

+ 6 - 0
Tests/LibWeb/Layout/expected/block-and-inline/abspos-with-auto-margins-in-inline-axis.txt

@@ -0,0 +1,6 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+  BlockContainer <html> at (1,1) content-size 798x18 [BFC] children: not-inline
+    BlockContainer <body> at (10,10) content-size 780x0 children: not-inline
+      BlockContainer <div#foo> at (350,1) content-size 100x100 positioned [BFC] children: not-inline
+      BlockContainer <div#bar> at (699,101) content-size 100x100 positioned [BFC] children: not-inline
+      BlockContainer <div#baz> at (1,201) content-size 100x100 positioned [BFC] children: not-inline

+ 31 - 0
Tests/LibWeb/Layout/input/block-and-inline/abspos-with-auto-margins-in-inline-axis.html

@@ -0,0 +1,31 @@
+<!DOCTYPE html><style>
+    * {
+        border: 1px solid black;
+    }
+    div {
+        height: 100px;
+        width: 100px;
+        position: absolute;
+        height: 100px;
+    }
+    #foo {
+        margin: auto;
+        left: 0px;
+        right: 0px;
+        top: 0px;
+    }
+    #bar {
+        margin-left: auto;
+        margin-right: 0px;
+        left: 0px;
+        right: 0px;
+        top: 100px;
+    }
+    #baz {
+        margin-left: 0px;
+        margin-right: auto;
+        left: 0px;
+        right: 0px;
+        top: 200px;
+    }
+</style><div id=foo></div><div id=bar></div><div id=baz></div>

+ 27 - 10
Userland/Libraries/LibWeb/Layout/FormattingContext.cpp

@@ -598,8 +598,34 @@ void FormattingContext::compute_width_for_absolutely_positioned_non_replaced_ele
             goto Rule3;
         }
 
+        // If none of the three is auto:
         if (!computed_left.is_auto() && !width.is_auto() && !computed_right.is_auto()) {
-            // FIXME: This should be solved in a more complicated way.
+            // If both margin-left and margin-right are auto,
+            // solve the equation under the extra constraint that the two margins get equal values
+            // FIXME: unless this would make them negative, in which case when direction of the containing block is ltr (rtl), set margin-left (margin-right) to 0 and solve for margin-right (margin-left).
+            auto size_available_for_margins = width_of_containing_block - border_left - padding_left - width.to_px(box) - padding_right - border_right - right;
+            if (margin_left.is_auto() && margin_right.is_auto()) {
+                margin_left = CSS::Length::make_px(size_available_for_margins / 2);
+                margin_right = CSS::Length::make_px(size_available_for_margins / 2);
+                return width;
+            }
+
+            // If one of margin-left or margin-right is auto, solve the equation for that value.
+            if (margin_left.is_auto()) {
+                margin_left = CSS::Length::make_px(size_available_for_margins);
+                return width;
+            }
+            if (margin_right.is_auto()) {
+                margin_right = CSS::Length::make_px(size_available_for_margins);
+                return width;
+            }
+            // If the values are over-constrained, ignore the value for left
+            // (in case the direction property of the containing block is rtl)
+            // or right (in case direction is ltr) and solve for that value.
+
+            // NOTE: At this point we *are* over-constrained since none of margin-left, left, width, right, or margin-right are auto.
+            // FIXME: Check direction.
+            right = solve_for_right();
             return width;
         }
 
@@ -995,9 +1021,7 @@ void FormattingContext::layout_absolutely_positioned_element(Box const& box, Ava
 
     compute_height_for_absolutely_positioned_element(box, available_space, BeforeOrAfterInsideLayout::After);
 
-    box_state.margin_left = box.computed_values().margin().left().to_px(box, width_of_containing_block);
     box_state.margin_top = box.computed_values().margin().top().to_px(box, width_of_containing_block);
-    box_state.margin_right = box.computed_values().margin().right().to_px(box, width_of_containing_block);
     box_state.margin_bottom = box.computed_values().margin().bottom().to_px(box, width_of_containing_block);
 
     box_state.border_left = box.computed_values().border_left().width;
@@ -1015,13 +1039,6 @@ void FormattingContext::layout_absolutely_positioned_element(Box const& box, Ava
     box_state.inset_right = computed_right.to_px(box, width_of_containing_block);
     box_state.inset_bottom = computed_bottom.to_px(box, height_of_containing_block);
 
-    if (computed_left.is_auto() && box.computed_values().width().is_auto() && computed_right.is_auto()) {
-        if (box.computed_values().margin().left().is_auto())
-            box_state.margin_left = 0;
-        if (box.computed_values().margin().right().is_auto())
-            box_state.margin_right = 0;
-    }
-
     auto static_position = calculate_static_position(box);
 
     CSSPixelPoint used_offset;