Ver Fonte

LibWeb: Support flex-basis: calc(...)

1. Propagate calc() values from StyleProperties to ComputedValues.
2. Actually resolve calc() values when determining the used flex basis.

This makes the "support" section on https://shopify.com/ show up
correctly as a 2x2 grid (instead of 1x4). :^)
Andreas Kling há 2 anos atrás
pai
commit
2e13f65ff4

+ 24 - 0
Tests/LibWeb/Layout/expected/flex/calc-flex-basis.txt

@@ -0,0 +1,24 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+  BlockContainer <html> at (1,1) content-size 798x80 [BFC] children: not-inline
+    BlockContainer <body> at (10,10) content-size 780x62 children: not-inline
+      Box <div.flex-container> at (11,11) content-size 778x60 flex-container(row) [FFC] children: not-inline
+        BlockContainer <div.flex-item> at (12,12) content-size 386x28 flex-item [BFC] children: inline
+          line 0 width: 58.398437, height: 21.835937, bottom: 21.835937, baseline: 16.914062
+            frag 0 from TextNode start: 0, length: 6, rect: [12,12 58.398437x21.835937]
+              "Item 1"
+          TextNode <#text>
+        BlockContainer <div.flex-item> at (401,12) content-size 386x28 flex-item [BFC] children: inline
+          line 0 width: 61.484375, height: 21.835937, bottom: 21.835937, baseline: 16.914062
+            frag 0 from TextNode start: 0, length: 6, rect: [401,12 61.484375x21.835937]
+              "Item 2"
+          TextNode <#text>
+        BlockContainer <div.flex-item> at (12,42) content-size 386x28 flex-item [BFC] children: inline
+          line 0 width: 61.835937, height: 21.835937, bottom: 21.835937, baseline: 16.914062
+            frag 0 from TextNode start: 0, length: 6, rect: [12,42 61.835937x21.835937]
+              "Item 3"
+          TextNode <#text>
+        BlockContainer <div.flex-item> at (401,42) content-size 386x28 flex-item [BFC] children: inline
+          line 0 width: 60.15625, height: 21.835937, bottom: 21.835937, baseline: 16.914062
+            frag 0 from TextNode start: 0, length: 6, rect: [401,42 60.15625x21.835937]
+              "Item 4"
+          TextNode <#text>

+ 18 - 0
Tests/LibWeb/Layout/input/flex/calc-flex-basis.html

@@ -0,0 +1,18 @@
+<!doctype html><style>
+* {
+    border: 1px solid black;
+    box-sizing: border-box;
+    font: 20px SerenitySans;
+}
+.flex-container {
+    display: flex;
+    flex-wrap: wrap;
+    background: pink;
+    column-gap: 1px;
+}
+.flex-item {
+    flex-basis: calc(50% - 1px);
+    background: orange;
+    height: 30px;
+}
+</style><div class="flex-container"><div class="flex-item">Item 1</div><div class="flex-item">Item 2</div><div class="flex-item">Item 3</div><div class="flex-item">Item 4</div></div>

+ 3 - 0
Userland/Libraries/LibWeb/CSS/StyleProperties.cpp

@@ -294,6 +294,9 @@ Optional<CSS::FlexBasisData> StyleProperties::flex_basis() const
     if (value->has_length())
         return { { CSS::FlexBasis::LengthPercentage, value->to_length() } };
 
+    if (value->is_calculated())
+        return { { CSS::FlexBasis::LengthPercentage, CSS::LengthPercentage { value->as_calculated() } } };
+
     return {};
 }
 

+ 14 - 4
Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp

@@ -34,6 +34,8 @@ static CSS::Size to_css_size(CSS::LengthPercentage const& length_percentage)
         return CSS::Size::make_auto();
     if (length_percentage.is_length())
         return CSS::Size::make_length(length_percentage.length());
+    if (length_percentage.is_calculated())
+        return CSS::Size::make_calculated(length_percentage.calculated());
     return CSS::Size::make_percentage(length_percentage.percentage());
 }
 
@@ -612,13 +614,21 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(
                 return false;
             if (flex_basis.length_percentage->is_length())
                 return true;
+
+            bool can_resolve_percentages = is_row_layout()
+                ? m_flex_container_state.has_definite_width()
+                : m_flex_container_state.has_definite_height();
+
             if (flex_basis.length_percentage->is_calculated()) {
-                // FIXME: Handle calc() in used flex basis.
+                auto const& calc_value = *flex_basis.length_percentage->calculated();
+                if (calc_value.resolves_to_length())
+                    return true;
+                if (calc_value.resolves_to_percentage() || (calc_value.resolves_to_length() && calc_value.contains_percentage()))
+                    return can_resolve_percentages;
                 return false;
             }
-            if (is_row_layout())
-                return m_flex_container_state.has_definite_width();
-            return m_flex_container_state.has_definite_height();
+            VERIFY(flex_basis.length_percentage->is_percentage());
+            return can_resolve_percentages;
         }(item.used_flex_basis);
 
         // A. If the item has a definite used flex basis, that’s the flex base size.