mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 09:28:11 +00:00
LibWeb: Clip hidden overflow by absolute rect of containing block
Since handling overflow: hidden in PaintableBox::before_children_paint while following paint traversal order can't result in correctly computed clip rectangle for elements that create their own stacking context (because before_children_paint is called only for parent but overflow: hidden can be set somewhere deeper but not in direct ancestor), here introduced new function PaintableBox::clip_rect() that computes clip rectangle by looking into containing block. should_clip_overflow flag that disables clip for absolutely positioned elements in before_children_paint and after_children_paint is removed because after changing clip rectangle to be computed from not parent but containing block it is not needed anymore (absolutely positioned item is clipped if it's containing block has hidden overflow)
This commit is contained in:
parent
c1401b37c4
commit
f3d57e1157
10 changed files with 55 additions and 40 deletions
|
@ -310,34 +310,53 @@ BorderRadiiData PaintableBox::normalized_border_radii_data(ShrinkRadiiForBorders
|
|||
return border_radius_data;
|
||||
}
|
||||
|
||||
void PaintableBox::before_children_paint(PaintContext& context, PaintPhase phase, ShouldClipOverflow should_clip_overflow) const
|
||||
Optional<Gfx::IntRect> PaintableBox::clip_rect() const
|
||||
{
|
||||
if (!m_clip_rect.has_value()) {
|
||||
if (containing_block() && containing_block()->paint_box())
|
||||
m_clip_rect = containing_block()->paint_box()->clip_rect();
|
||||
|
||||
auto overflow_x = computed_values().overflow_x();
|
||||
auto overflow_y = computed_values().overflow_y();
|
||||
|
||||
if (overflow_x == CSS::Overflow::Hidden && overflow_y == CSS::Overflow::Hidden) {
|
||||
if (m_clip_rect.has_value()) {
|
||||
m_clip_rect->intersect(absolute_padding_box_rect().to_rounded<int>());
|
||||
} else {
|
||||
m_clip_rect = absolute_padding_box_rect().to_rounded<int>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_clip_rect;
|
||||
}
|
||||
|
||||
void PaintableBox::before_children_paint(PaintContext& context, PaintPhase phase) const
|
||||
{
|
||||
if (!AK::first_is_one_of(phase, PaintPhase::Background, PaintPhase::Border, PaintPhase::Foreground))
|
||||
return;
|
||||
|
||||
if (should_clip_overflow == ShouldClipOverflow::No)
|
||||
return;
|
||||
|
||||
// FIXME: Support more overflow variations.
|
||||
auto clip_rect = absolute_padding_box_rect().to_rounded<int>();
|
||||
auto clip_rect = this->clip_rect();
|
||||
auto overflow_x = computed_values().overflow_x();
|
||||
auto overflow_y = computed_values().overflow_y();
|
||||
|
||||
auto clip_overflow = [&] {
|
||||
if (!m_clipping_overflow) {
|
||||
context.painter().save();
|
||||
context.painter().add_clip_rect(clip_rect);
|
||||
context.painter().add_clip_rect(*clip_rect);
|
||||
m_clipping_overflow = true;
|
||||
}
|
||||
};
|
||||
|
||||
if (overflow_x == CSS::Overflow::Hidden && overflow_y == CSS::Overflow::Hidden) {
|
||||
if (clip_rect.has_value()) {
|
||||
clip_overflow();
|
||||
}
|
||||
|
||||
if (overflow_y == CSS::Overflow::Hidden || overflow_x == CSS::Overflow::Hidden) {
|
||||
auto border_radii_data = normalized_border_radii_data(ShrinkRadiiForBorders::Yes);
|
||||
if (border_radii_data.has_any_radius()) {
|
||||
auto corner_clipper = BorderRadiusCornerClipper::create(clip_rect, border_radii_data, CornerClip::Outside, BorderRadiusCornerClipper::UseCachedBitmap::No);
|
||||
auto corner_clipper = BorderRadiusCornerClipper::create(absolute_padding_box_rect().to_rounded<int>(), border_radii_data, CornerClip::Outside, BorderRadiusCornerClipper::UseCachedBitmap::No);
|
||||
if (corner_clipper.is_error()) {
|
||||
dbgln("Failed to create overflow border-radius corner clipper: {}", corner_clipper.error());
|
||||
return;
|
||||
|
@ -349,14 +368,11 @@ void PaintableBox::before_children_paint(PaintContext& context, PaintPhase phase
|
|||
}
|
||||
}
|
||||
|
||||
void PaintableBox::after_children_paint(PaintContext& context, PaintPhase phase, ShouldClipOverflow should_clip_overflow) const
|
||||
void PaintableBox::after_children_paint(PaintContext& context, PaintPhase phase) const
|
||||
{
|
||||
if (!AK::first_is_one_of(phase, PaintPhase::Background, PaintPhase::Border, PaintPhase::Foreground))
|
||||
return;
|
||||
|
||||
if (should_clip_overflow == ShouldClipOverflow::No)
|
||||
return;
|
||||
|
||||
// FIXME: Support more overflow variations.
|
||||
if (m_clipping_overflow) {
|
||||
context.painter().restore();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue