LibWeb: Enable different overflow along the x and y axis

This commit is contained in:
Psychpsyo 2025-05-03 11:36:28 +02:00 committed by Alexander Kalenik
commit ed7374783d
Notes: github-actions[bot] 2025-05-13 12:32:37 +00:00
15 changed files with 518 additions and 8 deletions

View file

@ -127,7 +127,8 @@ void ViewportPaintable::assign_clip_frames()
for_each_in_subtree_of_type<PaintableBox>([&](auto const& paintable_box) { for_each_in_subtree_of_type<PaintableBox>([&](auto const& paintable_box) {
auto overflow_x = paintable_box.computed_values().overflow_x(); auto overflow_x = paintable_box.computed_values().overflow_x();
auto overflow_y = paintable_box.computed_values().overflow_y(); auto overflow_y = paintable_box.computed_values().overflow_y();
auto has_hidden_overflow = overflow_x != CSS::Overflow::Visible && overflow_y != CSS::Overflow::Visible; // Note: Overflow may be clip on one axis and visible on the other.
auto has_hidden_overflow = overflow_x != CSS::Overflow::Visible || overflow_y != CSS::Overflow::Visible;
if (has_hidden_overflow || paintable_box.get_clip_rect().has_value()) { if (has_hidden_overflow || paintable_box.get_clip_rect().has_value()) {
auto clip_frame = adopt_ref(*new ClipFrame()); auto clip_frame = adopt_ref(*new ClipFrame());
clip_state.set(paintable_box, move(clip_frame)); clip_state.set(paintable_box, move(clip_frame));
@ -166,14 +167,40 @@ void ViewportPaintable::assign_clip_frames()
continue; continue;
} }
auto const& block_paintable_box = static_cast<PaintableBox const&>(*paintable); auto const& block_paintable_box = static_cast<PaintableBox const&>(*paintable);
auto block_overflow_x = block_paintable_box.computed_values().overflow_x(); bool clip_x = paintable->computed_values().overflow_x() != CSS::Overflow::Visible;
auto block_overflow_y = block_paintable_box.computed_values().overflow_y(); bool clip_y = paintable->computed_values().overflow_y() != CSS::Overflow::Visible;
if (block_overflow_x != CSS::Overflow::Visible && block_overflow_y != CSS::Overflow::Visible) {
auto rect = block_paintable_box.absolute_padding_box_rect(); auto clip_rect = block_paintable_box.overflow_clip_edge_rect();
clip_frame.add_clip_rect(rect, block_paintable_box.normalized_border_radii_data(ShrinkRadiiForBorders::Yes), block_paintable_box.enclosing_scroll_frame()); if (block_paintable_box.get_clip_rect().has_value()) {
clip_rect.intersect(block_paintable_box.get_clip_rect().value());
clip_x = true;
clip_y = true;
}
if (clip_x || clip_y) {
// https://drafts.csswg.org/css-overflow-3/#corner-clipping
// As mentioned in CSS Backgrounds 3 §4.3 Corner Clipping, the clipping region established by overflow can be
// rounded:
if (clip_x && clip_y) {
// - When overflow-x and overflow-y compute to hidden, scroll, or auto, the clipping region is rounded
// based on the border radius, adjusted to the padding edge, as described in CSS Backgrounds 3 §4.2 Corner
// Shaping.
// - When both overflow-x and overflow-y compute to clip, the clipping region is rounded as described in §3.2
// Expanding Clipping Bounds: the overflow-clip-margin property.
// FIXME: Implement overflow-clip-margin
clip_frame.add_clip_rect(clip_rect, block_paintable_box.normalized_border_radii_data(ShrinkRadiiForBorders::Yes), block_paintable_box.enclosing_scroll_frame());
} else {
// - However, when one of overflow-x or overflow-y computes to clip and the other computes to visible, the
// clipping region is not rounded.
if (clip_x) {
clip_rect.set_top(0);
clip_rect.set_bottom(CSSPixels::max_integer_value);
} else {
clip_rect.set_left(0);
clip_rect.set_right(CSSPixels::max_integer_value);
}
clip_frame.add_clip_rect(clip_rect, {}, block_paintable_box.enclosing_scroll_frame());
} }
if (auto css_clip_property_rect = block_paintable_box.get_clip_rect(); css_clip_property_rect.has_value()) {
clip_frame.add_clip_rect(css_clip_property_rect.value(), {}, block_paintable_box.enclosing_scroll_frame());
} }
if (block->has_css_transform()) { if (block->has_css_transform()) {
break; break;

View file

@ -0,0 +1,35 @@
<!doctype html>
<meta charset="utf-8">
<title>Reference: overflow: clip can be combined with overflow: visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<style>
.outer {
width: 50px;
height: 50px;
margin-left: 100px;
margin-top: 100px;
background: black;
}
.inner {
position: relative;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer">
<div class="inner" style="width:50px; height:50px;"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer">
<div class="inner" style="top:-20px; width:50px"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer">
<div class="inner" style="left:-40px; height:50px"></div>
</div>

View file

@ -0,0 +1,61 @@
<!doctype html>
<meta charset="utf-8">
<title>Reference: overflow:clip can be combined with overflow:visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<style>
.wrapper {
margin-left: 30px;
margin-bottom: 20px;
width: 50px;
height: 50px;
}
.outer {
width: 50px;
height: 50px;
background: black;
}
.inner {
position: relative;
top: -10px;
left: -10px;
height: 100px;
width: 100px;
background: blue;
opacity: 0.5;
}
</style>
<!-- there should be no scrollbars -->
<div class="wrapper" style="overflow: hidden">
<div class="outer">
<div class="inner"></div>
</div>
</div>
<!-- there should be no white areas inside the outline -->
<div class="wrapper" style="outline: solid">
<div class="outer">
<div class="inner" style="left:0; width:50px"></div>
</div>
</div>
<!-- there should be a vertical scrollbar, but not a horizontal one -->
<div class="wrapper" style="overflow: hidden scroll; margin-top:50px">
<div class="outer">
<div class="inner" style="width:1px"></div>
</div>
</div>
<!-- there should be no white areas inside the outline -->
<div class="wrapper" style="outline: solid">
<div class="outer">
<div class="inner" style="top:0; height:50px"></div>
</div>
</div>
<!-- there should be horizontal scrollbar, but not a vertical one -->
<div class="wrapper" style="overflow: scroll hidden">
<div class="outer">
<div class="inner" style="height:1px"></div>
</div>
</div>

View file

@ -0,0 +1,35 @@
<!doctype html>
<meta charset="utf-8">
<title>Reference: overflow: clip can be combined with overflow: visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<style>
.outer {
width: 50px;
height: 50px;
margin-left: 100px;
margin-top: 100px;
background: black;
}
.inner {
position: relative;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer">
<div class="inner" style="width:50px; height:50px;"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer">
<div class="inner" style="top:-10px; width:50px"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer">
<div class="inner" style="left:-30px; height:50px"></div>
</div>

View file

@ -0,0 +1,36 @@
<!doctype html>
<meta charset="utf-8">
<title>Reference: overflow:clip doesn't affect the box' own outline</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<style>
.outer {
width: 50px;
height: 50px;
margin-left: 100px;
margin-top: 100px;
background: black;
outline: 2px solid grey;
}
.inner {
position: relative;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer">
<div class="inner" style="width:50px; height:50px;"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer">
<div class="inner" style="top:-10px; width:50px"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer">
<div class="inner" style="left:-30px; height:50px"></div>
</div>

View file

@ -0,0 +1,36 @@
<!doctype html>
<meta charset="utf-8">
<title>Overflow: verifies content visual overflow is shown</title>
<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#valdef-overflow-clip">
<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org">
<style>
body {
margin: 0
}
.shadow {
width: 100px;
height: 100px;
will-change: transform;
background: black;
box-shadow: 10px 50px 5px red;
}
.cover {
width: 200px;
height: 200px;
background: white;
position: absolute;
}
.spacer {
width: 100px;
height: 150px;
}
</style>
<div class="shadow"></div>
<div class="cover" style="left: 100px; top: 0"></div>
<div class="spacer"></div>
<div class="shadow"></div>
<div class="cover" style="top: 350px"></div>
</script>

View file

@ -0,0 +1,13 @@
<!doctype html>
<meta charset="utf-8">
<title>Overflow: can have different clip and visible value in x/y directions with svg</title>
<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#valdef-overflow-clip">
<link rel="author" title="Khushal Sagar" href="mailto:khushalsagar@chromium.org">
<style>
div {
width: 100px;
height: 150px;
background: green;
}
</style>
<div></div>

View file

@ -0,0 +1,13 @@
<!doctype html>
<meta charset="utf-8">
<title>Overflow: can have different clip and visible value in x/y directions with svg</title>
<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#valdef-overflow-clip">
<link rel="author" title="Khushal Sagar" href="mailto:khushalsagar@chromium.org">
<style>
div {
width: 150px;
height: 100px;
background: green;
}
</style>
<div></div>

View file

@ -0,0 +1,39 @@
<!doctype html>
<meta charset="utf-8">
<title>CSS Test: overflow:clip can be combined with overflow:visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<link rel="help" href="https://drafts.csswg.org/css-overflow/#valdef-overflow-clip">
<link rel="match" href="../../../../expected/wpt-import/css/css-overflow/clip-002-ref.html">
<style>
.outer {
width: 50px;
height: 50px;
margin-left: 100px;
margin-top: 100px;
background: black;
}
.inner {
position: relative;
top: -20px;
left: -40px;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer" style="overflow:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer" style="overflow-x:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer" style="overflow-y:clip">
<div class="inner"></div>
</div>

View file

@ -0,0 +1,63 @@
<!doctype html>
<meta charset="utf-8">
<title>CSS Test: overflow:clip can be combined with overflow:visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<link rel="help" href="https://drafts.csswg.org/css-overflow/#valdef-overflow-clip">
<link rel="match" href="../../../../expected/wpt-import/css/css-overflow/clip-003-ref.html">
<style>
.wrapper {
margin-left: 30px;
margin-bottom: 20px;
width: 50px;
height: 50px;
}
.outer {
width: 50px;
height: 50px;
background: black;
}
.inner {
position: relative;
top: -10px;
left: -10px;
height: 100px;
width: 100px;
background: blue;
opacity: 0.5;
}
</style>
<!-- there should be no scrollbars -->
<div class="wrapper" style="overflow: auto">
<div class="outer" style="overflow:clip; outline:solid red">
<div class="inner"></div>
</div>
</div>
<!-- there should be no white areas inside the outline -->
<div class="wrapper" style="outline: solid">
<div class="outer" style="overflow-x:clip">
<div class="inner"></div>
</div>
</div>
<!-- there should be a vertical scrollbar, but not a horizontal one -->
<div class="wrapper" style="overflow: auto; margin-top:50px">
<div class="outer" style="overflow-x:clip">
<div class="inner" style="width:1px"></div>
</div>
</div>
<!-- there should be no white areas inside the outline -->
<div class="wrapper" style="outline: solid">
<div class="outer" style="overflow-y:clip">
<div class="inner"></div>
</div>
</div>
<!-- there should be horizontal scrollbar, but not a vertical one -->
<div class="wrapper" style="overflow: auto">
<div class="outer" style="overflow-y:clip">
<div class="inner" style="height:1px"></div>
</div>
</div>

View file

@ -0,0 +1,40 @@
<!doctype html>
<meta charset="utf-8">
<title>CSS Test: overflow:clip can be combined with overflow:visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<link rel="help" href="https://drafts.csswg.org/css-overflow/#valdef-overflow-clip">
<link rel="match" href="../../../../expected/wpt-import/css/css-overflow/clip-004-ref.html">
<style>
.outer {
width: 30px;
height: 30px;
padding: 10px;
margin-left: 100px;
margin-top: 100px;
background: black;
}
.inner {
position: relative;
top: -20px;
left: -40px;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer" style="overflow:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer" style="overflow-x:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer" style="overflow-y:clip">
<div class="inner"></div>
</div>

View file

@ -0,0 +1,41 @@
<!doctype html>
<meta charset="utf-8">
<title>CSS Test: overflow:clip doesn't affect the box' own outline</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<link rel="help" href="https://drafts.csswg.org/css-overflow/#valdef-overflow-clip">
<link rel="match" href="../../../../expected/wpt-import/css/css-overflow/clip-005-ref.html">
<style>
.outer {
width: 30px;
height: 30px;
padding: 10px;
margin-left: 100px;
margin-top: 100px;
background: black;
outline: 2px solid grey;
}
.inner {
position: relative;
top: -20px;
left: -40px;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer" style="overflow:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer" style="overflow-x:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer" style="overflow-y:clip">
<div class="inner"></div>
</div>

View file

@ -0,0 +1,37 @@
<!doctype html>
<meta charset="utf-8">
<title>Overflow: verifies content visual overflow is shown</title>
<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#valdef-overflow-clip">
<link rel="author" title="Scott Violet" href="mailto:sky@chromium.org">
<link rel="match" href="../../../../expected/wpt-import/css/css-overflow/overflow-clip-content-visual-overflow-ref.html">
<style>
body {
margin: 0
}
.parent {
width: 100px;
height: 100px;
will-change: transform;
}
.child {
width: 100px;
height: 100px;
background: black;
box-shadow: 10px 50px 5px red;
}
.spacer {
width: 100px;
height: 150px;
}
</style>
<div class="parent" style="overflow-x: clip; overflow-y: visible">
<div class="child"></div>
</div>
<div class="spacer"></div>
<div class="parent" style="overflow-x: visible; overflow-y: clip">
<div class="child"></div>
</div>
</script>

View file

@ -0,0 +1,17 @@
<!doctype html>
<meta charset="utf-8">
<title>Overflow: can have different clip and visible value in x/y directions with svg</title>
<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#valdef-overflow-clip">
<link rel="author" title="Khushal Sagar" href="mailto:khushalsagar@chromium.org">
<link rel="match" href="../../../../expected/wpt-import/css/css-overflow/overflow-clip-x-visible-y-svg-ref.html">
<style>
svg {
width: 100px;
height: 100px;
overflow-y: visible;
overflow-x: clip;
}
</style>
<svg>
<rect width="150" height="150" fill="green"></rect>
</svg>

View file

@ -0,0 +1,17 @@
<!doctype html>
<meta charset="utf-8">
<title>Overflow: can have different clip and visible value in x/y directions with svg</title>
<link rel="help" href="https://www.w3.org/TR/css-overflow-3/#valdef-overflow-clip">
<link rel="author" title="Khushal Sagar" href="mailto:khushalsagar@chromium.org">
<link rel="match" href="../../../../expected/wpt-import/css/css-overflow/overflow-clip-y-visible-x-svg-ref.html">
<style>
svg {
width: 100px;
height: 100px;
overflow-x: visible;
overflow-y: clip;
}
</style>
<svg>
<rect width="150" height="150" fill="green"></rect>
</svg>