Browse Source

LibWeb: Stretch-fit flex items with aspect ratio but no fixed sizes

This solves a particular issue with SVG as flex items, where the SVG has
an intrinsic aspect ratio via its viewBox, but no explicit natural width
or height.

Makes all corporate sponsor logos show up on https://ziglang.org/ :^)
Andreas Kling 1 year ago
parent
commit
a61f09a010

+ 3 - 3
Tests/LibWeb/Layout/expected/flex/flex-item-with-intrinsic-aspect-ratio-and-max-height.txt

@@ -1,11 +1,11 @@
 Viewport <#document> at (0,0) content-size 800x600 children: not-inline
   BlockContainer <html> at (1,1) content-size 798x69.984375 [BFC] children: not-inline
     Box <body> at (10,10) content-size 780x51.984375 flex-container(row) [FFC] children: not-inline
-      ImageBox <img> at (11,11) content-size 66.65625x49.984375 flex-item children: not-inline
+      ImageBox <img> at (11,11) content-size 66.65625x50 flex-item children: not-inline
       BlockContainer <(anonymous)> (not painted) [BFC] children: inline
         TextNode <#text>
 
 ViewportPaintable (Viewport<#document>) [0,0 800x600]
   PaintableWithLines (BlockContainer<HTML>) [0,0 800x71.984375]
-    PaintableBox (Box<BODY>) [9,9 782x53.984375]
-      ImagePaintable (ImageBox<IMG>) [10,10 68.65625x51.984375]
+    PaintableBox (Box<BODY>) [9,9 782x53.984375] overflow: [10,10 780x52]
+      ImagePaintable (ImageBox<IMG>) [10,10 68.65625x52]

+ 9 - 9
Tests/LibWeb/Layout/expected/flex/intrinsic-height-of-flex-container-with-svg-item-that-only-has-natural-aspect-ratio.txt

@@ -1,11 +1,11 @@
 Viewport <#document> at (0,0) content-size 800x600 children: not-inline
-  BlockContainer <html> at (0,0) content-size 800x16 [BFC] children: not-inline
-    Box <body> at (8,8) content-size 784x0 flex-container(column) [FFC] children: not-inline
-      SVGSVGBox <svg> at (400,8) content-size 0x0 flex-item [SVG] children: not-inline
-        SVGGeometryBox <rect> at (400,8) content-size 0x0 children: not-inline
+  BlockContainer <html> at (0,0) content-size 800x800 [BFC] children: not-inline
+    Box <body> at (8,8) content-size 784x784 flex-container(column) [FFC] children: not-inline
+      SVGSVGBox <svg> at (8,8) content-size 784x784 flex-item [SVG] children: not-inline
+        SVGGeometryBox <rect> at (8,8) content-size 392x392 children: not-inline
 
-ViewportPaintable (Viewport<#document>) [0,0 800x600]
-  PaintableWithLines (BlockContainer<HTML>) [0,0 800x16]
-    PaintableBox (Box<BODY>) [8,8 784x0]
-      SVGSVGPaintable (SVGSVGBox<svg>) [400,8 0x0]
-        SVGPathPaintable (SVGGeometryBox<rect>) [400,8 0x0]
+ViewportPaintable (Viewport<#document>) [0,0 800x600] overflow: [0,0 800x800]
+  PaintableWithLines (BlockContainer<HTML>) [0,0 800x800]
+    PaintableBox (Box<BODY>) [8,8 784x784]
+      SVGSVGPaintable (SVGSVGBox<svg>) [8,8 784x784]
+        SVGPathPaintable (SVGGeometryBox<rect>) [8,8 392x392]

+ 13 - 0
Tests/LibWeb/Layout/expected/flex/stretch-fit-width-for-column-layout-svg-item-that-only-has-natural-aspect-ratio.txt

@@ -0,0 +1,13 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+  BlockContainer <html> at (0,0) content-size 800x800 [BFC] children: not-inline
+    Box <body> at (8,8) content-size 784x784 flex-container(row) [FFC] children: not-inline
+      SVGSVGBox <svg> at (8,8) content-size 784x784 flex-item [SVG] children: not-inline
+        SVGGeometryBox <rect> at (8,8) content-size 392x392 children: not-inline
+      BlockContainer <(anonymous)> (not painted) [BFC] children: inline
+        TextNode <#text>
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600] overflow: [0,0 800x800]
+  PaintableWithLines (BlockContainer<HTML>) [0,0 800x800]
+    PaintableBox (Box<BODY>) [8,8 784x784]
+      SVGSVGPaintable (SVGSVGBox<svg>) [8,8 784x784]
+        SVGPathPaintable (SVGGeometryBox<rect>) [8,8 392x392]

+ 6 - 0
Tests/LibWeb/Layout/input/flex/stretch-fit-width-for-column-layout-svg-item-that-only-has-natural-aspect-ratio.html

@@ -0,0 +1,6 @@
+<!DOCTYPE html><style>
+    body {
+        display: flex;
+        flex-direction: row;
+    }
+</style><body><svg viewBox="0 0 24 24"><rect x=0 y=0 width=12 height=12></svg>

+ 12 - 3
Userland/Libraries/LibWeb/Layout/FlexFormattingContext.cpp

@@ -628,8 +628,13 @@ void FlexFormattingContext::determine_flex_base_size_and_hypothetical_main_size(
     }();
 
     // AD-HOC: This is not mentioned in the spec, but if the item has an aspect ratio,
-    //         we may need to adjust the main size in response to cross size min/max constraints.
+    //         we may need to adjust the main size in these ways:
+    //         - using stretch-fit main size if the flex basis is indefinite.
+    //         - in response to cross size min/max constraints.
     if (item.box->has_preferred_aspect_ratio()) {
+        if (!item.used_flex_basis_is_definite) {
+            item.flex_base_size = inner_main_size(m_flex_container_state);
+        }
         item.flex_base_size = adjust_main_size_through_aspect_ratio_for_cross_size_min_max_constraints(child_box, item.flex_base_size, computed_cross_min_size(child_box), computed_cross_max_size(child_box));
     }
 
@@ -1038,8 +1043,12 @@ void FlexFormattingContext::determine_hypothetical_cross_size_of_item(FlexItem&
         return;
     }
 
-    if (item.box->has_preferred_aspect_ratio() && item.main_size.has_value()) {
-        item.hypothetical_cross_size = calculate_cross_size_from_main_size_and_aspect_ratio(item.main_size.value(), item.box->preferred_aspect_ratio().value());
+    if (item.box->has_preferred_aspect_ratio()) {
+        if (item.used_flex_basis_is_definite) {
+            item.hypothetical_cross_size = calculate_cross_size_from_main_size_and_aspect_ratio(item.main_size.value(), item.box->preferred_aspect_ratio().value());
+            return;
+        }
+        item.hypothetical_cross_size = inner_cross_size(m_flex_container_state);
         return;
     }