|
@@ -407,6 +407,33 @@ Gfx::FloatPoint StackingContext::compute_transform_origin() const
|
|
return { x, y };
|
|
return { x, y };
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+template<typename U, typename Callback>
|
|
|
|
+static TraversalDecision for_each_in_inclusive_subtree_of_type_within_same_stacking_context_in_reverse(Paintable const& paintable, Callback callback)
|
|
|
|
+{
|
|
|
|
+ if (is<PaintableBox>(paintable) && static_cast<PaintableBox const&>(paintable).stacking_context())
|
|
|
|
+ return TraversalDecision::SkipChildrenAndContinue;
|
|
|
|
+
|
|
|
|
+ for (auto* child = paintable.last_child(); child; child = child->previous_sibling()) {
|
|
|
|
+ if (for_each_in_inclusive_subtree_of_type_within_same_stacking_context_in_reverse<U>(*child, callback) == TraversalDecision::Break)
|
|
|
|
+ return TraversalDecision::Break;
|
|
|
|
+ }
|
|
|
|
+ if (is<U>(paintable)) {
|
|
|
|
+ if (auto decision = callback(static_cast<U const&>(paintable)); decision != TraversalDecision::Continue)
|
|
|
|
+ return decision;
|
|
|
|
+ }
|
|
|
|
+ return TraversalDecision::Continue;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+template<typename U, typename Callback>
|
|
|
|
+static TraversalDecision for_each_in_subtree_of_type_within_same_stacking_context_in_reverse(Paintable const& paintable, Callback callback)
|
|
|
|
+{
|
|
|
|
+ for (auto* child = paintable.last_child(); child; child = child->previous_sibling()) {
|
|
|
|
+ if (for_each_in_inclusive_subtree_of_type_within_same_stacking_context_in_reverse<U>(*child, callback) == TraversalDecision::Break)
|
|
|
|
+ return TraversalDecision::Break;
|
|
|
|
+ }
|
|
|
|
+ return TraversalDecision::Continue;
|
|
|
|
+}
|
|
|
|
+
|
|
Optional<HitTestResult> StackingContext::hit_test(Gfx::FloatPoint const& position, HitTestType type) const
|
|
Optional<HitTestResult> StackingContext::hit_test(Gfx::FloatPoint const& position, HitTestType type) const
|
|
{
|
|
{
|
|
if (!m_box.is_visible())
|
|
if (!m_box.is_visible())
|
|
@@ -428,7 +455,7 @@ Optional<HitTestResult> StackingContext::hit_test(Gfx::FloatPoint const& positio
|
|
// NOTE: Hit testing follows reverse painting order, that's why the conditions here are reversed.
|
|
// NOTE: Hit testing follows reverse painting order, that's why the conditions here are reversed.
|
|
for (ssize_t i = m_children.size() - 1; i >= 0; --i) {
|
|
for (ssize_t i = m_children.size() - 1; i >= 0; --i) {
|
|
auto const& child = *m_children[i];
|
|
auto const& child = *m_children[i];
|
|
- if (child.m_box.computed_values().z_index().value_or(0) < 0)
|
|
|
|
|
|
+ if (child.m_box.computed_values().z_index().value_or(0) <= 0)
|
|
break;
|
|
break;
|
|
auto result = child.hit_test(transformed_position, type);
|
|
auto result = child.hit_test(transformed_position, type);
|
|
if (result.has_value() && result->paintable->visible_for_hit_testing())
|
|
if (result.has_value() && result->paintable->visible_for_hit_testing())
|
|
@@ -437,17 +464,31 @@ Optional<HitTestResult> StackingContext::hit_test(Gfx::FloatPoint const& positio
|
|
|
|
|
|
Optional<HitTestResult> result;
|
|
Optional<HitTestResult> result;
|
|
// 6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
|
|
// 6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
|
|
- paintable().for_each_in_subtree_of_type<PaintableBox>([&](auto& paint_box) {
|
|
|
|
|
|
+
|
|
|
|
+ for_each_in_subtree_of_type_within_same_stacking_context_in_reverse<PaintableBox>(paintable(), [&](PaintableBox const& paint_box) {
|
|
// FIXME: Support more overflow variations.
|
|
// FIXME: Support more overflow variations.
|
|
if (paint_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paint_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
|
|
if (paint_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paint_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
|
|
if (!paint_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
|
|
if (!paint_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
|
|
return TraversalDecision::SkipChildrenAndContinue;
|
|
return TraversalDecision::SkipChildrenAndContinue;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (paint_box.stacking_context()) {
|
|
|
|
+ auto const& z_index = paint_box.computed_values().z_index();
|
|
|
|
+ if (!z_index.has_value() || z_index.value() == 0) {
|
|
|
|
+ auto candidate = paint_box.stacking_context()->hit_test(transformed_position, type);
|
|
|
|
+ if (candidate.has_value() && candidate->paintable->visible_for_hit_testing()) {
|
|
|
|
+ result = move(candidate);
|
|
|
|
+ return TraversalDecision::Break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
auto& layout_box = paint_box.layout_box();
|
|
auto& layout_box = paint_box.layout_box();
|
|
if (layout_box.is_positioned() && !paint_box.stacking_context()) {
|
|
if (layout_box.is_positioned() && !paint_box.stacking_context()) {
|
|
- if (auto candidate = paint_box.hit_test(transformed_position, type); candidate.has_value())
|
|
|
|
|
|
+ if (auto candidate = paint_box.hit_test(transformed_position, type); candidate.has_value()) {
|
|
result = move(candidate);
|
|
result = move(candidate);
|
|
|
|
+ return TraversalDecision::Break;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
return TraversalDecision::Continue;
|
|
return TraversalDecision::Continue;
|
|
});
|
|
});
|
|
@@ -462,7 +503,7 @@ Optional<HitTestResult> StackingContext::hit_test(Gfx::FloatPoint const& positio
|
|
}
|
|
}
|
|
|
|
|
|
// 4. the non-positioned floats.
|
|
// 4. the non-positioned floats.
|
|
- paintable().for_each_in_subtree_of_type<PaintableBox>([&](auto const& paint_box) {
|
|
|
|
|
|
+ for_each_in_subtree_of_type_within_same_stacking_context_in_reverse<PaintableBox>(paintable(), [&](auto const& paint_box) {
|
|
// FIXME: Support more overflow variations.
|
|
// FIXME: Support more overflow variations.
|
|
if (paint_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paint_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
|
|
if (paint_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paint_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
|
|
if (!paint_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
|
|
if (!paint_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
|
|
@@ -471,8 +512,10 @@ Optional<HitTestResult> StackingContext::hit_test(Gfx::FloatPoint const& positio
|
|
|
|
|
|
auto& layout_box = paint_box.layout_box();
|
|
auto& layout_box = paint_box.layout_box();
|
|
if (layout_box.is_floating()) {
|
|
if (layout_box.is_floating()) {
|
|
- if (auto candidate = paint_box.hit_test(transformed_position, type); candidate.has_value())
|
|
|
|
|
|
+ if (auto candidate = paint_box.hit_test(transformed_position, type); candidate.has_value()) {
|
|
result = move(candidate);
|
|
result = move(candidate);
|
|
|
|
+ return TraversalDecision::Break;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
return TraversalDecision::Continue;
|
|
return TraversalDecision::Continue;
|
|
});
|
|
});
|
|
@@ -481,7 +524,7 @@ Optional<HitTestResult> StackingContext::hit_test(Gfx::FloatPoint const& positio
|
|
|
|
|
|
// 3. the in-flow, non-inline-level, non-positioned descendants.
|
|
// 3. the in-flow, non-inline-level, non-positioned descendants.
|
|
if (!m_box.children_are_inline()) {
|
|
if (!m_box.children_are_inline()) {
|
|
- paintable().for_each_in_subtree_of_type<PaintableBox>([&](auto const& paint_box) {
|
|
|
|
|
|
+ for_each_in_subtree_of_type_within_same_stacking_context_in_reverse<PaintableBox>(paintable(), [&](auto const& paint_box) {
|
|
// FIXME: Support more overflow variations.
|
|
// FIXME: Support more overflow variations.
|
|
if (paint_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paint_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
|
|
if (paint_box.computed_values().overflow_x() == CSS::Overflow::Hidden && paint_box.computed_values().overflow_y() == CSS::Overflow::Hidden) {
|
|
if (!paint_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
|
|
if (!paint_box.absolute_border_box_rect().contains(transformed_position.x(), transformed_position.y()))
|
|
@@ -490,8 +533,10 @@ Optional<HitTestResult> StackingContext::hit_test(Gfx::FloatPoint const& positio
|
|
|
|
|
|
auto& layout_box = paint_box.layout_box();
|
|
auto& layout_box = paint_box.layout_box();
|
|
if (!layout_box.is_absolutely_positioned() && !layout_box.is_floating()) {
|
|
if (!layout_box.is_absolutely_positioned() && !layout_box.is_floating()) {
|
|
- if (auto candidate = paint_box.hit_test(transformed_position, type); candidate.has_value())
|
|
|
|
|
|
+ if (auto candidate = paint_box.hit_test(transformed_position, type); candidate.has_value()) {
|
|
result = move(candidate);
|
|
result = move(candidate);
|
|
|
|
+ return TraversalDecision::Break;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
return TraversalDecision::Continue;
|
|
return TraversalDecision::Continue;
|
|
});
|
|
});
|