Bläddra i källkod

LibWeb: Add hit testing API in `internals` object

Introduces `internals.hitTest(x, y)` that is going to allow us write
tests for hit testing :)
Aliaksandr Kalenik 2 år sedan
förälder
incheckning
bf4e2f3e9c

+ 1 - 0
Tests/LibWeb/Text/expected/hit_testing/basic.txt

@@ -0,0 +1 @@
+   true

+ 1 - 0
Tests/LibWeb/Text/expected/hit_testing/text.txt

@@ -0,0 +1 @@
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque eu ante est. Integer ipsum sem, tincidunt quis felis quis, efficitur fringilla neque. Aliquam erat volutpat. Donec feugiat euismod sapien. Donec vel egestas arcu. Suspendisse luctus rhoncus mi quis elementum. Maecenas vel nisi maximus, viverra tellus quis, ultrices elit. Quisque congue velit quis lectus congue, ut consectetur nulla pharetra. Nullam euismod leo eget magna auctor, et bibendum urna tincidunt. Morbi molestie gravida ex ac consectetur. Duis pretium gravida augue eu sagittis.   193

+ 17 - 0
Tests/LibWeb/Text/input/hit_testing/basic.html

@@ -0,0 +1,17 @@
+<style>
+    * {
+        border: 1px solid black;
+    }
+
+    #box {
+        width: 100px;
+        height: 100px;
+    }
+</style>
+<div id="box"></div>
+<script src="../include.js"></script>
+<script>
+    test(() => {
+        println(internals.hitTest(50, 50).node === document.getElementById("box"));
+    });
+</script>

+ 18 - 0
Tests/LibWeb/Text/input/hit_testing/text.html

@@ -0,0 +1,18 @@
+<style>
+    * {
+        border: 1px solid black;
+    }
+</style>
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque eu ante est. Integer ipsum sem,
+tincidunt quis felis quis, efficitur fringilla neque. Aliquam erat volutpat. Donec feugiat euismod
+sapien. Donec vel egestas arcu. Suspendisse luctus rhoncus mi quis elementum. Maecenas vel nisi
+maximus, viverra tellus quis, ultrices elit. Quisque congue velit quis lectus congue, ut consectetur
+nulla pharetra. Nullam euismod leo eget magna auctor, et bibendum urna tincidunt. Morbi molestie
+gravida ex ac consectetur. Duis pretium gravida augue eu sagittis.
+<script src="../include.js"></script>
+<script>
+    test(() => {
+        const hitTestingResult = internals.hitTest(50, 50);
+        println(hitTestingResult.indexInNode);
+    });
+</script>

+ 21 - 0
Userland/Libraries/LibWeb/Internals/Internals.cpp

@@ -7,7 +7,11 @@
 #include <LibJS/Runtime/VM.h>
 #include <LibWeb/Bindings/InternalsPrototype.h>
 #include <LibWeb/Bindings/Intrinsics.h>
+#include <LibWeb/DOM/Document.h>
+#include <LibWeb/HTML/BrowsingContext.h>
+#include <LibWeb/HTML/Window.h>
 #include <LibWeb/Internals/Internals.h>
+#include <LibWeb/Painting/PaintableBox.h>
 
 namespace Web::Internals {
 
@@ -29,4 +33,21 @@ void Internals::gc()
     vm().heap().collect_garbage();
 }
 
+JS::Object* Internals::hit_test(double x, double y)
+{
+    auto* active_document = global_object().browsing_context()->top_level_browsing_context().active_document();
+    // NOTE: Force a layout update just before hit testing. This is because the current layout tree, which is required
+    //       for stacking context traversal, might not exist if this call occurs between the tear_down_layout_tree()
+    //       and update_layout() calls
+    active_document->update_layout();
+    auto result = active_document->paintable_box()->hit_test({ x, y }, Painting::HitTestType::Exact);
+    if (result.has_value()) {
+        auto hit_tеsting_result = JS::Object::create(realm(), nullptr);
+        hit_tеsting_result->define_direct_property("node", result->dom_node(), JS::default_attributes);
+        hit_tеsting_result->define_direct_property("indexInNode", JS::Value(result->index_in_node), JS::default_attributes);
+        return hit_tеsting_result;
+    }
+    return nullptr;
+}
+
 }

+ 1 - 0
Userland/Libraries/LibWeb/Internals/Internals.h

@@ -17,6 +17,7 @@ public:
     virtual ~Internals() override;
 
     void gc();
+    JS::Object* hit_test(double x, double y);
 
 private:
     explicit Internals(JS::Realm&);

+ 1 - 0
Userland/Libraries/LibWeb/Internals/Internals.idl

@@ -1,5 +1,6 @@
 [Exposed=Nobody] interface Internals {
 
     undefined gc();
+    object hitTest(double x, double y);
 
 };