ソースを参照

LibWeb: Fix background clip for elements nested into scrollable boxes

add_clip_rect() accepts a rectangle in viewport-relative coordinates,
so it must be translated by the enclosing scroll offset to be displayed
correctly inside a scrollable box.
Aliaksandr Kalenik 1 年間 前
コミット
040653311e

+ 23 - 0
Tests/LibWeb/Ref/reference/scrollable-contains-box-with-gradient-background-ref.html

@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<style type="text/css">
+    * {
+        scrollbar-width: none;
+    }
+
+    .box {
+        width: 180px;
+        height: 64px;
+        background: linear-gradient(rgb(109, 152, 204), rgb(138, 100, 229));
+        border-radius: 100px;
+    }
+
+    .scrollable {
+        width: 200px;
+        height: 200px;
+        overflow: scroll;
+        border: 10px solid orchid;
+    }
+</style>
+<div class="scrollable">
+    <div class="box"></div>
+</div>

+ 30 - 0
Tests/LibWeb/Ref/scrollable-contains-box-with-gradient-background.html

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<link rel="match" href="reference/scrollable-contains-box-with-gradient-background-ref.html" />
+<style type="text/css">
+    * {
+        scrollbar-width: none;
+    }
+
+    .box {
+        width: 180px;
+        height: 64px;
+        background: linear-gradient(rgb(109, 152, 204), rgb(138, 100, 229));
+        border-radius: 100px;
+    }
+
+    #scrollable {
+        width: 200px;
+        height: 200px;
+        overflow: scroll;
+        border: 10px solid orchid;
+    }
+</style>
+<div id="scrollable">
+    <div style="height: 100px"></div>
+    <div class="box"></div>
+    <div style="height: 200px"></div>
+</div>
+<script>
+    const scrollContainer = document.getElementById("scrollable");
+    scrollContainer.scrollTop = 100;
+</script>

+ 11 - 2
Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp

@@ -159,6 +159,15 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
         clip_shrink.right = context.rounded_device_pixels(border_right.width);
     }
 
+    CSSPixelPoint enclosing_scroll_offset;
+    if (is<PaintableBox>(layout_node.paintable())) {
+        auto const& paintable_box = static_cast<PaintableBox const&>(*layout_node.paintable());
+        enclosing_scroll_offset = paintable_box.enclosing_scroll_frame_offset().value_or({});
+    } else if (is<InlinePaintable>(layout_node.paintable())) {
+        auto const& inline_paintable = static_cast<InlinePaintable const&>(*layout_node.paintable());
+        enclosing_scroll_offset = inline_paintable.enclosing_scroll_frame_offset().value_or({});
+    }
+
     // Note: Background layers are ordered front-to-back, so we paint them in reverse
     for (auto& layer : resolved_background.layers.in_reverse()) {
         DisplayListRecorderStateSaver state { display_list_recorder };
@@ -167,9 +176,9 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
         auto clip_box = get_box(layer.clip, border_box, layout_node);
 
         CSSPixelRect const& css_clip_rect = clip_box.rect;
-        auto clip_rect = context.rounded_device_rect(css_clip_rect);
+        auto clip_rect = context.rounded_device_rect(css_clip_rect.translated(enclosing_scroll_offset));
         display_list_recorder.add_clip_rect(clip_rect.to_type<int>());
-        ScopedCornerRadiusClip corner_clip { context, clip_rect, clip_box.radii };
+        ScopedCornerRadiusClip corner_clip { context, context.rounded_device_rect(css_clip_rect), clip_box.radii };
 
         if (layer.clip == CSS::BackgroundBox::BorderBox) {
             // Shrink the effective clip rect if to account for the bits the borders will definitely paint over