mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-28 11:49:44 +00:00
LibWeb: Reorder paintable hit-testing to account for pointer-events
Instead of ignoring any paintable immediately when they're invisible to hit-testing, consider every candidate and while the most specific candidate is invisible to hit-testing, traverse up to its parent paintable. This more closely reflects the behavior expected when wrapping block elements inside inline elements, where although the block element might have `pointer-events: none`, it still becomes part of the hit-test body of the inline parent. This makes the following link work as expected: <a href="https://ladybird.org"> <div style="pointer-events: none">Ladybird</div> </a>
This commit is contained in:
parent
e076cb9b0e
commit
b7a554d1f2
Notes:
github-actions[bot]
2025-01-23 08:34:09 +00:00
Author: https://github.com/gmta
Commit: b7a554d1f2
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3276
Reviewed-by: https://github.com/kalenikaliaksandr ✅
4 changed files with 76 additions and 10 deletions
|
@ -965,9 +965,6 @@ TraversalDecision PaintableBox::hit_test(CSSPixelPoint position, HitTestType typ
|
|||
return TraversalDecision::Break;
|
||||
}
|
||||
|
||||
if (!visible_for_hit_testing())
|
||||
return TraversalDecision::Continue;
|
||||
|
||||
if (!absolute_border_box_rect().contains(position_adjusted_by_scroll_offset))
|
||||
return TraversalDecision::Continue;
|
||||
|
||||
|
@ -978,18 +975,38 @@ Optional<HitTestResult> PaintableBox::hit_test(CSSPixelPoint position, HitTestTy
|
|||
{
|
||||
Optional<HitTestResult> result;
|
||||
(void)PaintableBox::hit_test(position, type, [&](HitTestResult candidate) {
|
||||
if (candidate.paintable->visible_for_hit_testing()) {
|
||||
if (!result.has_value()
|
||||
|| candidate.vertical_distance.value_or(CSSPixels::max_integer_value) < result->vertical_distance.value_or(CSSPixels::max_integer_value)
|
||||
|| candidate.horizontal_distance.value_or(CSSPixels::max_integer_value) < result->horizontal_distance.value_or(CSSPixels::max_integer_value)) {
|
||||
result = move(candidate);
|
||||
}
|
||||
if (!result.has_value()
|
||||
|| candidate.vertical_distance.value_or(CSSPixels::max_integer_value) < result->vertical_distance.value_or(CSSPixels::max_integer_value)
|
||||
|| candidate.horizontal_distance.value_or(CSSPixels::max_integer_value) < result->horizontal_distance.value_or(CSSPixels::max_integer_value)) {
|
||||
result = move(candidate);
|
||||
}
|
||||
|
||||
if (result.has_value() && (type == HitTestType::Exact || (result->vertical_distance == 0 && result->horizontal_distance == 0)))
|
||||
return TraversalDecision::Break;
|
||||
return TraversalDecision::Continue;
|
||||
});
|
||||
|
||||
// If our hit-testing has resulted in a hit on a paintable, we know that it is the most specific hit. If that
|
||||
// paintable turns out to be invisible for hit-testing, we need to traverse up the paintable tree to find the next
|
||||
// paintable that is visible for hit-testing. This implements the behavior expected for pointer-events.
|
||||
while (result.has_value() && !result->paintable->visible_for_hit_testing()) {
|
||||
result->index_in_node = result->paintable->dom_node() ? result->paintable->dom_node()->index() : 0;
|
||||
result->paintable = result->paintable->parent();
|
||||
|
||||
// If the new parent is an anonymous box part of a continuation, we need to follow the chain to the inline node
|
||||
// that spawned the anonymous "middle" part of the continuation, since that inline node is the actual parent.
|
||||
if (is<PaintableBox>(*result->paintable)) {
|
||||
auto const& box_layout_node = static_cast<PaintableBox&>(*result->paintable).layout_node_with_style_and_box_metrics();
|
||||
if (box_layout_node.is_anonymous() && box_layout_node.continuation_of_node()) {
|
||||
auto const* original_inline_node = &box_layout_node;
|
||||
while (original_inline_node->continuation_of_node())
|
||||
original_inline_node = original_inline_node->continuation_of_node();
|
||||
|
||||
result->paintable = const_cast<Paintable*>(original_inline_node->first_paintable());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue