summaryrefslogtreecommitdiff
path: root/Libraries/LibWeb/Layout
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-07-01 19:02:28 +0200
committerAndreas Kling <kling@serenityos.org>2020-07-01 19:10:58 +0200
commit392b05580690b271d21dde89a9f9b2b05988f234 (patch)
tree2834e39d37bf47e46b299b5277d6f64a81fb2bae /Libraries/LibWeb/Layout
parentf7a900367f802796d94742c5bbb272aa07b4450e (diff)
downloadserenity-392b05580690b271d21dde89a9f9b2b05988f234.zip
LibWeb: Use the StackingContext tree for hit testing
This makes it possible to click links that are above other content due to stacking context order (e.g via CSS z-index.)
Diffstat (limited to 'Libraries/LibWeb/Layout')
-rw-r--r--Libraries/LibWeb/Layout/LayoutBlock.cpp2
-rw-r--r--Libraries/LibWeb/Layout/LayoutBox.cpp2
-rw-r--r--Libraries/LibWeb/Layout/LayoutBox.h1
-rw-r--r--Libraries/LibWeb/Layout/LayoutDocument.cpp5
-rw-r--r--Libraries/LibWeb/Layout/LayoutDocument.h3
-rw-r--r--Libraries/LibWeb/Layout/LayoutNode.cpp4
6 files changed, 16 insertions, 1 deletions
diff --git a/Libraries/LibWeb/Layout/LayoutBlock.cpp b/Libraries/LibWeb/Layout/LayoutBlock.cpp
index a043f3c216..d475fc37a9 100644
--- a/Libraries/LibWeb/Layout/LayoutBlock.cpp
+++ b/Libraries/LibWeb/Layout/LayoutBlock.cpp
@@ -725,6 +725,8 @@ HitTestResult LayoutBlock::hit_test(const Gfx::IntPoint& position) const
HitTestResult last_good_candidate;
for (auto& line_box : m_line_boxes) {
for (auto& fragment : line_box.fragments()) {
+ if (is<LayoutBox>(fragment.layout_node()) && to<LayoutBox>(fragment.layout_node()).stacking_context())
+ continue;
if (enclosing_int_rect(fragment.absolute_rect()).contains(position)) {
if (fragment.layout_node().is_block())
return to<LayoutBlock>(fragment.layout_node()).hit_test(position);
diff --git a/Libraries/LibWeb/Layout/LayoutBox.cpp b/Libraries/LibWeb/Layout/LayoutBox.cpp
index cfddbf21bd..4e84d22324 100644
--- a/Libraries/LibWeb/Layout/LayoutBox.cpp
+++ b/Libraries/LibWeb/Layout/LayoutBox.cpp
@@ -231,6 +231,8 @@ HitTestResult LayoutBox::hit_test(const Gfx::IntPoint& position) const
// m_rect.contains() since inline text rects can't be trusted..
HitTestResult result { absolute_rect().contains(position.x(), position.y()) ? this : nullptr };
for_each_child([&](auto& child) {
+ if (is<LayoutBox>(child) && to<LayoutBox>(child).stacking_context())
+ return;
auto child_result = child.hit_test(position);
if (child_result.layout_node)
result = child_result;
diff --git a/Libraries/LibWeb/Layout/LayoutBox.h b/Libraries/LibWeb/Layout/LayoutBox.h
index c719994a8d..1387a9ad0d 100644
--- a/Libraries/LibWeb/Layout/LayoutBox.h
+++ b/Libraries/LibWeb/Layout/LayoutBox.h
@@ -64,6 +64,7 @@ public:
bool establishes_stacking_context() const;
StackingContext* stacking_context() { return m_stacking_context; }
+ const StackingContext* stacking_context() const { return m_stacking_context; }
void set_stacking_context(NonnullOwnPtr<StackingContext> context) { m_stacking_context = move(context); }
StackingContext* enclosing_stacking_context();
diff --git a/Libraries/LibWeb/Layout/LayoutDocument.cpp b/Libraries/LibWeb/Layout/LayoutDocument.cpp
index 3f0fd27603..b30b6486ef 100644
--- a/Libraries/LibWeb/Layout/LayoutDocument.cpp
+++ b/Libraries/LibWeb/Layout/LayoutDocument.cpp
@@ -113,4 +113,9 @@ void LayoutDocument::paint(PaintContext& context, PaintPhase phase)
stacking_context()->paint(context, phase);
}
+HitTestResult LayoutDocument::hit_test(const Gfx::IntPoint& position) const
+{
+ return stacking_context()->hit_test(position);
+}
+
}
diff --git a/Libraries/LibWeb/Layout/LayoutDocument.h b/Libraries/LibWeb/Layout/LayoutDocument.h
index 6a3c04bfe5..eb37187e65 100644
--- a/Libraries/LibWeb/Layout/LayoutDocument.h
+++ b/Libraries/LibWeb/Layout/LayoutDocument.h
@@ -41,9 +41,10 @@ public:
virtual void layout(LayoutMode = LayoutMode::Default) override;
void paint_all_phases(PaintContext&);
-
virtual void paint(PaintContext&, PaintPhase) override;
+ virtual HitTestResult hit_test(const Gfx::IntPoint&) const override;
+
const LayoutRange& selection() const { return m_selection; }
LayoutRange& selection() { return m_selection; }
diff --git a/Libraries/LibWeb/Layout/LayoutNode.cpp b/Libraries/LibWeb/Layout/LayoutNode.cpp
index a410c930a5..0e6647de1e 100644
--- a/Libraries/LibWeb/Layout/LayoutNode.cpp
+++ b/Libraries/LibWeb/Layout/LayoutNode.cpp
@@ -106,6 +106,10 @@ HitTestResult LayoutNode::hit_test(const Gfx::IntPoint& position) const
{
HitTestResult result;
for_each_child([&](auto& child) {
+ // Skip over children that establish their own stacking context.
+ // The outer loop who called us will take care of those.
+ if (is<LayoutBox>(child) && to<LayoutBox>(child).stacking_context())
+ return;
auto child_result = child.hit_test(position);
if (child_result.layout_node)
result = child_result;