Skip to content

Commit

Permalink
LibWeb: Use clip rectangles assigned to paintables in hit-testing
Browse files Browse the repository at this point in the history
This change makes hit-testing more consistent in the handling of hidden
overflow by reusing the same clip-rectangles.

Also, it fixes bugs where the box is visible for hit-testing even
though it is clipped by the hidden overflow of the containing block.
  • Loading branch information
kalenikaliaksandr committed Jan 30, 2024
1 parent 5dcd68f commit 8eceb9f
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<HTML >
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse accumsan semper massa ut pharetra. Nunc vitae lorem at odio facilisis vehicula nec ut nibh. Duis ornare nibh orci, nec mollis est mollis ac. Aenean ultricies condimentum interdum. In eu elit vestibulum, sollicitudin lectus vel, congue nibh. Morbi vitae nunc in tortor ultrices aliquet sit amet a turpis. Phasellus ut dui sodales, dictum sem ut, efficitur tellus. Etiam eu orci et magna suscipit dignissim nec et sem. Aenean quam erat, euismod eu faucibus et, placerat ut dolor. <HTML >
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script src="../include.js"></script>
<style>
.overflow-hidden {
overflow: hidden;
border: 1px solid black;
width: 200px;
height: 200px;
}

#box {
width: 400px;
height: 400px;
background-color: red;
}
</style>
<div class="overflow-hidden">
<div id="box"></div>
</div>
<script type="text/javascript">
test(() => {
printElement(internals.hitTest(300, 300).node);
});
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script src="../include.js"></script>
<style>
.overflow-hidden {
overflow: hidden;
border: 1px solid black;
width: 200px;
height: 200px;
}

#box {
width: 400px;
height: 400px;
}
</style>
<div class="overflow-hidden">
<div id="box">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse accumsan semper massa
ut pharetra. Nunc vitae lorem at odio facilisis vehicula nec ut nibh. Duis ornare nibh orci,
nec mollis est mollis ac. Aenean ultricies condimentum interdum. In eu elit vestibulum,
sollicitudin lectus vel, congue nibh. Morbi vitae nunc in tortor ultrices aliquet sit amet a
turpis. Phasellus ut dui sodales, dictum sem ut, efficitur tellus. Etiam eu orci et magna
suscipit dignissim nec et sem. Aenean quam erat, euismod eu faucibus et, placerat ut dolor.
</div>
</div>
<script type="text/javascript">
test(() => {
printElement(internals.hitTest(300, 300).node);
});
</script>
3 changes: 3 additions & 0 deletions Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ void InlinePaintable::for_each_fragment(Callback callback) const

Optional<HitTestResult> InlinePaintable::hit_test(CSSPixelPoint position, HitTestType type) const
{
if (m_clip_rect.has_value() && !m_clip_rect.value().contains(position))
return {};

auto position_adjusted_by_scroll_offset = position;
if (m_enclosing_scroll_frame_offset.has_value())
position_adjusted_by_scroll_offset.translate_by(-m_enclosing_scroll_frame_offset.value());
Expand Down
6 changes: 6 additions & 0 deletions Userland/Libraries/LibWeb/Painting/PaintableBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,9 @@ Layout::BlockContainer& PaintableWithLines::layout_box()

Optional<HitTestResult> PaintableBox::hit_test(CSSPixelPoint position, HitTestType type) const
{
if (clip_rect().has_value() && !clip_rect()->contains(position))
return {};

auto position_adjusted_by_scroll_offset = position;
if (enclosing_scroll_frame_offset().has_value())
position_adjusted_by_scroll_offset.translate_by(-enclosing_scroll_frame_offset().value());
Expand Down Expand Up @@ -712,6 +715,9 @@ Optional<HitTestResult> PaintableBox::hit_test(CSSPixelPoint position, HitTestTy

Optional<HitTestResult> PaintableWithLines::hit_test(CSSPixelPoint position, HitTestType type) const
{
if (clip_rect().has_value() && !clip_rect()->contains(position))
return {};

auto position_adjusted_by_scroll_offset = position;
if (enclosing_scroll_frame_offset().has_value())
position_adjusted_by_scroll_offset.translate_by(-enclosing_scroll_frame_offset().value());
Expand Down
1 change: 1 addition & 0 deletions Userland/Libraries/LibWeb/Painting/PaintableBox.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ class PaintableBox : public Paintable {
virtual CSSPixelRect compute_absolute_paint_rect() const;

Optional<CSSPixelPoint> enclosing_scroll_frame_offset() const { return m_enclosing_scroll_frame_offset; }
Optional<CSSPixelRect> clip_rect() const { return m_clip_rect; }

private:
[[nodiscard]] virtual bool is_paintable_box() const final { return true; }
Expand Down
28 changes: 0 additions & 28 deletions Userland/Libraries/LibWeb/Painting/StackingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,14 +372,6 @@ Optional<HitTestResult> StackingContext::hit_test(CSSPixelPoint position, HitTes
transformed_position.translate_by(-scroll_offset);
}

// FIXME: Support more overflow variations.
if (paintable().computed_values().overflow_x() == CSS::Overflow::Hidden && paintable().computed_values().overflow_y() == CSS::Overflow::Hidden) {
if (paintable().is_paintable_box()) {
if (!paintable_box().absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
return {};
}
}

// NOTE: Hit testing basically happens in reverse painting order.
// https://www.w3.org/TR/CSS22/visuren.html#z-index

Expand All @@ -402,12 +394,6 @@ Optional<HitTestResult> StackingContext::hit_test(CSSPixelPoint position, HitTes

auto const& paintable_box = verify_cast<PaintableBox>(paintable);

// FIXME: Support more overflow variations.
if (paintable_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paintable_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
if (!paintable_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
return TraversalDecision::SkipChildrenAndContinue;
}

auto const& z_index = paintable_box.computed_values().z_index();
if (z_index.value_or(0) == 0 && paintable_box.is_positioned() && !paintable_box.stacking_context()) {
auto candidate = paintable_box.hit_test(transformed_position, type);
Expand Down Expand Up @@ -445,13 +431,6 @@ Optional<HitTestResult> StackingContext::hit_test(CSSPixelPoint position, HitTes
return TraversalDecision::Continue;

auto const& paintable_box = verify_cast<PaintableBox>(paintable);

// FIXME: Support more overflow variations.
if (paintable_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paintable_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
if (!paintable_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
return TraversalDecision::SkipChildrenAndContinue;
}

if (paintable_box.is_floating()) {
if (auto candidate = paintable_box.hit_test(transformed_position, type); candidate.has_value()) {
result = move(candidate);
Expand All @@ -470,13 +449,6 @@ Optional<HitTestResult> StackingContext::hit_test(CSSPixelPoint position, HitTes
return TraversalDecision::Continue;

auto const& paintable_box = verify_cast<PaintableBox>(paintable);

// FIXME: Support more overflow variations.
if (paintable_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paintable_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
if (!paintable_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
return TraversalDecision::SkipChildrenAndContinue;
}

if (!paintable_box.is_absolutely_positioned() && !paintable_box.is_floating()) {
if (auto candidate = paintable_box.hit_test(transformed_position, type); candidate.has_value()) {
result = move(candidate);
Expand Down

0 comments on commit 8eceb9f

Please sign in to comment.