summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2022-03-21 12:12:50 +0100
committerAndreas Kling <kling@serenityos.org>2022-03-21 13:03:33 +0100
commit996f3228a2e518fb5562a4b2f91743ba435df9c3 (patch)
tree988d4dbcd0b937f890a289e95ec7ea5204a6d26c
parentf7cfd47b48fdaa9629d762e7204cfdd8e21a0596 (diff)
downloadserenity-996f3228a2e518fb5562a4b2f91743ba435df9c3.zip
LibWeb: Fix O(n^2) traversal in hit testing
We already walk the entire paint tree within each stacking context in the main hit testing function (StackingContext::hit_test()), so there's no need for each individual paintable to walk its own children again. By not doing that, we remove a source of O(n^2) traversal which made hit testing on deeply nested web pages unbearably slow.
-rw-r--r--Userland/Libraries/LibWeb/Painting/PaintableBox.cpp11
-rw-r--r--Userland/Libraries/LibWeb/Painting/StackingContext.cpp15
2 files changed, 8 insertions, 18 deletions
diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp
index 8e7f59d797..4dbcf2349a 100644
--- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp
+++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp
@@ -535,16 +535,9 @@ Optional<HitTestResult> PaintableBox::hit_test(Gfx::FloatPoint const& position,
return stacking_context()->hit_test(position, type);
}
- Optional<HitTestResult> result;
if (absolute_border_box_rect().contains(position.x(), position.y()))
- result = HitTestResult { *this };
- for_each_child_in_paint_order([&](auto& child) {
- if (child.paintable()) {
- if (auto child_result = child.paintable()->hit_test(position, type); child_result.has_value())
- result = move(child_result);
- }
- });
- return result;
+ return HitTestResult { *this };
+ return {};
}
Optional<HitTestResult> PaintableWithLines::hit_test(const Gfx::FloatPoint& position, HitTestType type) const
diff --git a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp
index 2cf8aa97e3..c8349e4fd3 100644
--- a/Userland/Libraries/LibWeb/Painting/StackingContext.cpp
+++ b/Userland/Libraries/LibWeb/Painting/StackingContext.cpp
@@ -297,9 +297,8 @@ Optional<HitTestResult> StackingContext::hit_test(Gfx::FloatPoint const& positio
// 6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
m_box.for_each_in_subtree_of_type<Layout::Box>([&](Layout::Box const& box) {
if (box.is_positioned() && !box.paint_box()->stacking_context()) {
- result = box.paint_box()->hit_test(transformed_position, type);
- if (result.has_value())
- return IterationDecision::Break;
+ if (auto candidate = box.paint_box()->hit_test(transformed_position, type); candidate.has_value())
+ result = move(candidate);
}
return IterationDecision::Continue;
});
@@ -316,9 +315,8 @@ Optional<HitTestResult> StackingContext::hit_test(Gfx::FloatPoint const& positio
// 4. the non-positioned floats.
m_box.for_each_in_subtree_of_type<Layout::Box>([&](Layout::Box const& box) {
if (box.is_floating()) {
- result = box.paint_box()->hit_test(transformed_position, type);
- if (result.has_value())
- return IterationDecision::Break;
+ if (auto candidate = box.paint_box()->hit_test(transformed_position, type); candidate.has_value())
+ result = move(candidate);
}
return IterationDecision::Continue;
});
@@ -329,9 +327,8 @@ Optional<HitTestResult> StackingContext::hit_test(Gfx::FloatPoint const& positio
if (!m_box.children_are_inline()) {
m_box.for_each_in_subtree_of_type<Layout::Box>([&](Layout::Box const& box) {
if (!box.is_absolutely_positioned() && !box.is_floating()) {
- result = box.paint_box()->hit_test(transformed_position, type);
- if (result.has_value())
- return IterationDecision::Break;
+ if (auto candidate = box.paint_box()->hit_test(transformed_position, type); candidate.has_value())
+ result = move(candidate);
}
return IterationDecision::Continue;
});