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.
This commit is contained in:
Aliaksandr Kalenik 2024-08-05 21:02:20 +03:00 committed by Andreas Kling
commit 040653311e
Notes: github-actions[bot] 2024-08-06 07:41:17 +00:00
3 changed files with 64 additions and 2 deletions

View file

@ -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>

View file

@ -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>

View file

@ -159,6 +159,15 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet
clip_shrink.right = context.rounded_device_pixels(border_right.width); 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 // Note: Background layers are ordered front-to-back, so we paint them in reverse
for (auto& layer : resolved_background.layers.in_reverse()) { for (auto& layer : resolved_background.layers.in_reverse()) {
DisplayListRecorderStateSaver state { display_list_recorder }; 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); auto clip_box = get_box(layer.clip, border_box, layout_node);
CSSPixelRect const& css_clip_rect = clip_box.rect; 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>()); 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) { if (layer.clip == CSS::BackgroundBox::BorderBox) {
// Shrink the effective clip rect if to account for the bits the borders will definitely paint over // Shrink the effective clip rect if to account for the bits the borders will definitely paint over