ソースを参照

LibWeb: Use actual line height to calculate float y in IFC

Before, we were using the line height from NodeWithStyle::line_height()
 to calculate the y offset for floats inside the IFC. However, this
value doesn't always correspond to the actual height of a line box. For
instance, adding a fragment for an inline-block might change the height
of the line box. With this change, we recalculate the height of the
line box after adding a new fragment and use this recalculated height
value to determine the y position for floats.

Fixes https://github.com/SerenityOS/serenity/issues/20982
Aliaksandr Kalenik 1 年間 前
コミット
df2bc8187c

+ 28 - 0
Tests/LibWeb/Layout/expected/block-and-inline/float-should-avoid-inline-block.txt

@@ -0,0 +1,28 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+  BlockContainer <html> at (1,1) content-size 798x250.03125 [BFC] children: not-inline
+    BlockContainer <body> at (10,10) content-size 780x21.46875 children: not-inline
+      BlockContainer <div.Layout-sidebar> at (11,11) content-size 220x19.46875 children: inline
+        line 0 width: 102, height: 19.46875, bottom: 19.46875, baseline: 14.53125
+          frag 0 from BlockContainer start: 0, length: 0, rect: [12,12 100x17.46875]
+        BlockContainer <div.d-inline-block> at (12,12) content-size 100x17.46875 inline-block [BFC] children: inline
+          line 0 width: 69.734375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
+            frag 0 from TextNode start: 0, length: 12, rect: [12,12 69.734375x17.46875]
+              "floats!!!!!!"
+          TextNode <#text>
+        BlockContainer <div.float-left> at (12,31.46875) content-size 232.71875x218.5625 floating [BFC] children: inline
+          line 0 width: 232.71875, height: 109.1875, bottom: 109.1875, baseline: 84.578125
+            frag 0 from TextNode start: 0, length: 5, rect: [12,31.46875 232.71875x109.1875]
+              "float"
+          line 1 width: 164.0625, height: 109.375, bottom: 218.5625, baseline: 84.578125
+            frag 0 from TextNode start: 6, length: 4, rect: [12,140.46875 164.0625x109.1875]
+              "left"
+          TextNode <#text>
+
+ViewportPaintable (Viewport<#document>) [0,0 800x600]
+  PaintableWithLines (BlockContainer<HTML>) [0,0 800x252.03125]
+    PaintableWithLines (BlockContainer<BODY>) [9,9 782x23.46875]
+      PaintableWithLines (BlockContainer<DIV>.Layout-sidebar) [10,10 222x21.46875]
+        PaintableWithLines (BlockContainer<DIV>.d-inline-block) [11,11 102x19.46875]
+          TextPaintable (TextNode<#text>)
+        PaintableWithLines (BlockContainer<DIV>.float-left) [11,30.46875 234.71875x220.5625]
+          TextPaintable (TextNode<#text>)

+ 18 - 0
Tests/LibWeb/Layout/input/block-and-inline/float-should-avoid-inline-block.html

@@ -0,0 +1,18 @@
+<!DOCTYPE html><style type="text/css">
+    * {
+      border: 1px solid black;
+    }
+    .float-left {
+      float: left;
+      font-size: 100px;
+    }
+    .d-inline-block {
+      display: inline-block;
+      width: 100px;
+      background-color: sandybrown;
+    }
+    .Layout-sidebar {
+      width: 220px;
+      background-color: beige;
+    }
+  </style><div class="Layout-sidebar"><div class="d-inline-block">floats!!!!!!</div><div class="float-left">float left</div></div>

+ 1 - 0
Userland/Libraries/LibWeb/Layout/LineBox.cpp

@@ -29,6 +29,7 @@ void LineBox::add_fragment(Node const& layout_node, int start, int length, CSSPi
         m_fragments.append(LineBoxFragment { layout_node, start, length, CSSPixelPoint(x_offset, y_offset), CSSPixelSize(content_width, content_height), border_box_top, border_box_bottom });
     }
     m_width += leading_margin + leading_size + content_width + trailing_size + trailing_margin;
+    m_height = max(m_height, content_height + border_box_top + border_box_bottom);
 }
 
 void LineBox::trim_trailing_whitespace()

+ 3 - 3
Userland/Libraries/LibWeb/Layout/LineBuilder.cpp

@@ -111,11 +111,11 @@ CSSPixels LineBuilder::y_for_float_to_be_inserted_here(Box const& box)
 
     CSSPixels candidate_y = m_current_y;
 
-    CSSPixels current_line_width = ensure_last_line_box().width();
+    auto const& current_line = ensure_last_line_box();
     // If there's already inline content on the current line, check if the new float can fit
     // alongside the content. If not, place it on the next line.
-    if (current_line_width > 0 && (current_line_width + width) > m_available_width_for_current_line)
-        candidate_y += m_context.containing_block().line_height();
+    if (current_line.width() > 0 && (current_line.width() + width) > m_available_width_for_current_line)
+        candidate_y += current_line.height();
 
     // Then, look for the next Y position where we can fit the new float.
     // FIXME: This is super dumb, we move 1px downwards per iteration and stop