Jelajahi Sumber

LibWeb: Improve painting of nested inline elements

PaintableWithLines created from inline nodes need to examine their
children to fully compute their size and offset as nested children
might have textnodes that are placed before their parent.

Fixes #1286
Christoffer Sandberg 7 bulan lalu
induk
melakukan
879af72850

+ 36 - 11
Libraries/LibWeb/Layout/LayoutState.cpp

@@ -312,8 +312,9 @@ void LayoutState::commit(Box& root)
         auto* paintable = inline_node->first_paintable();
         if (paintable)
             continue;
-        paintable = inline_node->create_paintable_for_line_with_index(0);
-        inline_node->add_paintable(paintable);
+        auto line_paintable = inline_node->create_paintable_for_line_with_index(0);
+        inline_node->add_paintable(line_paintable);
+        inline_node_paintables.set(line_paintable.ptr());
     }
 
     // Resolve relative positions for regular boxes (not line box fragments):
@@ -377,17 +378,42 @@ void LayoutState::commit(Box& root)
             continue;
         }
 
-        auto const& fragments = paintable_with_lines->fragments();
-        if (fragments.is_empty()) {
-            continue;
+        Optional<CSSPixelPoint> offset;
+        CSSPixelSize size;
+        auto line_index = paintable_with_lines->line_index();
+        paintable_with_lines->for_each_in_inclusive_subtree_of_type<Painting::PaintableWithLines>([&offset, &size, &line_index](auto& paintable) {
+            if (paintable.line_index() == line_index) {
+                auto const& fragments = paintable.fragments();
+                if (!fragments.is_empty()) {
+                    if (!offset.has_value() || (fragments.first().offset().x() < offset.value().x())) {
+                        offset = fragments.first().offset();
+                    }
+                }
+                for (auto const& fragment : fragments) {
+                    // FIXME: Padding and margin of nested inlines not included in fragment width
+                    size.set_width(size.width() + fragment.width());
+                }
+            }
+            return TraversalDecision::Continue;
+        });
+
+        if (offset.has_value()) {
+            if (!paintable_with_lines->fragments().is_empty()) {
+                offset.value().set_y(paintable_with_lines->fragments().first().offset().y());
+            }
+            // FIXME: If this paintable does not have any fragment we do no know the y offset. It should be where text should
+            // start if there had been any for this node. Pick y offset of the leftmost fragment in the inclusive subtree in the meantime.
+            paintable_with_lines->set_offset(offset.value());
         }
 
-        paintable_with_lines->set_offset(fragments.first().offset());
-        CSSPixelSize size;
-        for (auto const& fragment : fragments) {
-            size.set_width(size.width() + fragment.width());
-            size.set_height(max(size.height(), fragment.height()));
+        if (!paintable_with_lines->fragments().is_empty()) {
+            for (auto const& fragment : paintable_with_lines->fragments()) {
+                size.set_height(max(size.height(), fragment.height()));
+            }
+        } else {
+            size.set_height(paintable_with_lines->layout_node().computed_values().line_height());
         }
+
         paintable_with_lines->set_content_size(size.width(), size.height());
     }
 
@@ -686,5 +712,4 @@ void LayoutState::UsedValues::set_indefinite_content_height()
 {
     m_has_definite_height = false;
 }
-
 }

+ 20 - 0
Tests/LibWeb/Ref/expected/inline-nested-node-ref.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<style>
+  .bluebg {
+    background-color: #0000FF7F;
+  }
+</style>
+<body>
+    <div>
+        <span class="bluebg">12</span>
+    </div>
+    <div>
+        <span class="bluebg">12</span>
+    </div>
+    <div>
+        <span class="bluebg">1234</span><span>consecutive inline item</span>
+    </div>
+    <div>
+        <span class="bluebg">24</span>
+    </div>
+</body>

+ 21 - 0
Tests/LibWeb/Ref/input/inline-nested-node.html

@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<link rel="match" href="../expected/inline-nested-node-ref.html">
+<style>
+  .bluebg {
+    background-color: #0000FF7F;
+  }
+</style>
+<body>
+    <div>
+        <span class="bluebg">1<span>2</span></span>
+    </div>
+    <div>
+        <span class="bluebg"><span>1</span>2</span>
+    </div>
+    <div>
+        <span class="bluebg">1<span>2</span>3<span>4</span></span><span>consecutive inline item</span>
+    </div>
+    <div>
+        <span class="bluebg"><span>2</span><span>4</span></span>
+    </div>
+</body>

+ 3 - 3
Tests/LibWeb/Text/expected/HTML/dimension-attributes.txt

@@ -52,9 +52,9 @@ Test embed.vspace = "120." maps to marginBottom: 120px
 Test embed.width = "100" maps to width: 0px
 Test embed.width = " 00110 " maps to width: 0px
 Test embed.width = "120." maps to width: 0px
-Test embed.height = "100" maps to height: 0px
-Test embed.height = " 00110 " maps to height: 0px
-Test embed.height = "120." maps to height: 0px
+Test embed.height = "100" maps to height: 17px
+Test embed.height = " 00110 " maps to height: 17px
+Test embed.height = "120." maps to height: 17px
 Test tr.height = "100" maps to height: 100px
 Test tr.height = " 00110 " maps to height: 110px
 Test tr.height = "120." maps to height: 120px