Browse Source

LibWeb: Add DOMRect and Element.getBoundingClientRect()

This marks our entry into the Web::Geometry namespace, based on the
"Geometry" spec at https://drafts.fxtf.org/geometry/
Andreas Kling 3 năm trước cách đây
mục cha
commit
43d378940f

+ 12 - 1
Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp

@@ -588,7 +588,7 @@ int main(int argc, char** argv)
         return 1;
     }
 
-    if (namespace_.is_one_of("CSS", "DOM", "HTML", "UIEvents", "HighResolutionTime", "NavigationTiming", "RequestIdleCallback", "SVG", "XHR", "URL")) {
+    if (namespace_.is_one_of("CSS", "DOM", "HTML", "UIEvents", "Geometry", "HighResolutionTime", "NavigationTiming", "RequestIdleCallback", "SVG", "XHR", "URL")) {
         StringBuilder builder;
         builder.append(namespace_);
         builder.append("::");
@@ -1107,6 +1107,8 @@ static void generate_header(IDL::Interface const& interface)
 #    include <LibWeb/CSS/@name@.h>
 #elif __has_include(<LibWeb/DOM/@name@.h>)
 #    include <LibWeb/DOM/@name@.h>
+#elif __has_include(<LibWeb/Geometry/@name@.h>)
+#    include <LibWeb/Geometry/@name@.h>
 #elif __has_include(<LibWeb/HTML/@name@.h>)
 #    include <LibWeb/HTML/@name@.h>
 #elif __has_include(<LibWeb/UIEvents/@name@.h>)
@@ -1244,6 +1246,7 @@ void generate_implementation(IDL::Interface const& interface)
 #include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>
 #include <LibWeb/Bindings/CommentWrapper.h>
 #include <LibWeb/Bindings/DOMImplementationWrapper.h>
+#include <LibWeb/Bindings/DOMRectWrapper.h>
 #include <LibWeb/Bindings/DocumentFragmentWrapper.h>
 #include <LibWeb/Bindings/DocumentTypeWrapper.h>
 #include <LibWeb/Bindings/DocumentWrapper.h>
@@ -1271,6 +1274,7 @@ void generate_implementation(IDL::Interface const& interface)
 // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
 using namespace Web::CSS;
 using namespace Web::DOM;
+using namespace Web::Geometry;
 using namespace Web::HTML;
 using namespace Web::RequestIdleCallback;
 
@@ -2170,6 +2174,8 @@ void generate_constructor_implementation(IDL::Interface const& interface)
 #    include <LibWeb/CSS/@name@.h>
 #elif __has_include(<LibWeb/DOM/@name@.h>)
 #    include <LibWeb/DOM/@name@.h>
+#elif __has_include(<LibWeb/Geometry/@name@.h>)
+#    include <LibWeb/Geometry/@name@.h>
 #elif __has_include(<LibWeb/HTML/@name@.h>)
 #    include <LibWeb/HTML/@name@.h>
 #elif __has_include(<LibWeb/UIEvents/@name@.h>)
@@ -2191,6 +2197,7 @@ void generate_constructor_implementation(IDL::Interface const& interface)
 // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
 using namespace Web::CSS;
 using namespace Web::DOM;
+using namespace Web::Geometry;
 using namespace Web::HTML;
 using namespace Web::RequestIdleCallback;
 
@@ -2406,6 +2413,7 @@ void generate_prototype_implementation(IDL::Interface const& interface)
 #include <LibWeb/Bindings/CanvasRenderingContext2DWrapper.h>
 #include <LibWeb/Bindings/CommentWrapper.h>
 #include <LibWeb/Bindings/DOMImplementationWrapper.h>
+#include <LibWeb/Bindings/DOMRectWrapper.h>
 #include <LibWeb/Bindings/DOMStringMapWrapper.h>
 #include <LibWeb/Bindings/DocumentFragmentWrapper.h>
 #include <LibWeb/Bindings/DocumentTypeWrapper.h>
@@ -2447,6 +2455,8 @@ void generate_prototype_implementation(IDL::Interface const& interface)
 #    include <LibWeb/CSS/@name@.h>
 #elif __has_include(<LibWeb/DOM/@name@.h>)
 #    include <LibWeb/DOM/@name@.h>
+#elif __has_include(<LibWeb/Geometry/@name@.h>)
+#    include <LibWeb/Geometry/@name@.h>
 #elif __has_include(<LibWeb/HTML/@name@.h>)
 #    include <LibWeb/HTML/@name@.h>
 #elif __has_include(<LibWeb/UIEvents/@name@.h>)
@@ -2468,6 +2478,7 @@ void generate_prototype_implementation(IDL::Interface const& interface)
 // FIXME: This is a total hack until we can figure out the namespace for a given type somehow.
 using namespace Web::CSS;
 using namespace Web::DOM;
+using namespace Web::Geometry;
 using namespace Web::HTML;
 using namespace Web::NavigationTiming;
 using namespace Web::RequestIdleCallback;

+ 1 - 0
Userland/Libraries/LibWeb/CMakeLists.txt

@@ -342,6 +342,7 @@ libweb_js_wrapper(DOM/ShadowRoot)
 libweb_js_wrapper(DOM/Node)
 libweb_js_wrapper(DOM/Range)
 libweb_js_wrapper(DOM/Text)
+libweb_js_wrapper(Geometry/DOMRect)
 libweb_js_wrapper(HTML/CanvasRenderingContext2D)
 libweb_js_wrapper(HTML/CloseEvent)
 libweb_js_wrapper(HTML/DOMParser)

+ 17 - 0
Userland/Libraries/LibWeb/DOM/Element.cpp

@@ -18,6 +18,7 @@
 #include <LibWeb/DOM/ShadowRoot.h>
 #include <LibWeb/DOM/Text.h>
 #include <LibWeb/DOMParsing/InnerHTML.h>
+#include <LibWeb/Geometry/DOMRect.h>
 #include <LibWeb/HTML/EventLoop/EventLoop.h>
 #include <LibWeb/HTML/Parser/HTMLParser.h>
 #include <LibWeb/Layout/BlockBox.h>
@@ -29,6 +30,7 @@
 #include <LibWeb/Layout/TableRowGroupBox.h>
 #include <LibWeb/Layout/TreeBuilder.h>
 #include <LibWeb/Namespace.h>
+#include <LibWeb/Page/BrowsingContext.h>
 
 namespace Web::DOM {
 
@@ -325,4 +327,19 @@ bool Element::serializes_as_void() const
     return is_void_element() || local_name().is_one_of(HTML::TagNames::basefont, HTML::TagNames::bgsound, HTML::TagNames::frame, HTML::TagNames::keygen);
 }
 
+// https://drafts.csswg.org/cssom-view/#dom-element-getboundingclientrect
+NonnullRefPtr<Geometry::DOMRect> Element::get_bounding_client_rect() const
+{
+    // FIXME: Support inline layout nodes as well.
+
+    if (!layout_node() || !layout_node()->is_box())
+        return Geometry::DOMRect::create(0, 0, 0, 0);
+
+    VERIFY(document().browsing_context());
+    auto viewport_offset = document().browsing_context()->viewport_scroll_offset();
+
+    auto& box = static_cast<Layout::Box const&>(*layout_node());
+    return Geometry::DOMRect::create(box.absolute_rect().translated(-viewport_offset.x(), -viewport_offset.y()));
+}
+
 }

+ 2 - 0
Userland/Libraries/LibWeb/DOM/Element.h

@@ -109,6 +109,8 @@ public:
     bool is_void_element() const;
     bool serializes_as_void() const;
 
+    NonnullRefPtr<Geometry::DOMRect> get_bounding_client_rect() const;
+
 protected:
     RefPtr<Layout::Node> create_layout_node() override;
 

+ 3 - 0
Userland/Libraries/LibWeb/DOM/Element.idl

@@ -34,4 +34,7 @@ interface Element : Node {
     ArrayFromVector querySelectorAll(DOMString selectors);
 
     [SameObject] readonly attribute HTMLCollection children;
+
+    DOMRect getBoundingClientRect();
+
 };

+ 5 - 0
Userland/Libraries/LibWeb/Forward.h

@@ -90,6 +90,10 @@ template<typename ValueType>
 class ExceptionOr;
 }
 
+namespace Web::Geometry {
+class DOMRect;
+}
+
 namespace Web::HTML {
 class CanvasRenderingContext2D;
 class CloseEvent;
@@ -261,6 +265,7 @@ class DocumentWrapper;
 class DOMExceptionWrapper;
 class DOMImplementationWrapper;
 class DOMParserWrapper;
+class DOMRectWrapper;
 class DOMStringMapWrapper;
 class ElementWrapper;
 class EventListenerWrapper;

+ 57 - 0
Userland/Libraries/LibWeb/Geometry/DOMRect.h

@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/RefCounted.h>
+#include <LibGfx/Rect.h>
+#include <LibWeb/Bindings/Wrappable.h>
+#include <LibWeb/Forward.h>
+
+namespace Web::Geometry {
+
+// FIXME: Split this into DOMRectReadOnly and DOMRect
+// https://drafts.fxtf.org/geometry/#DOMRect
+class DOMRect final
+    : public RefCounted<DOMRect>
+    , public Bindings::Wrappable {
+public:
+    using WrapperType = Bindings::DOMRectWrapper;
+
+    static NonnullRefPtr<DOMRect> create_with_global_object(Bindings::WindowObject&, double x = 0, double y = 0, double width = 0, double height = 0)
+    {
+        return DOMRect::create(x, y, width, height);
+    }
+
+    static NonnullRefPtr<DOMRect> create(double x = 0, double y = 0, double width = 0, double height = 0)
+    {
+        return adopt_ref(*new DOMRect(x, y, width, height));
+    }
+
+    static NonnullRefPtr<DOMRect> create(Gfx::FloatRect const& rect)
+    {
+        return adopt_ref(*new DOMRect(rect.x(), rect.y(), rect.width(), rect.height()));
+    }
+
+    double x() const { return m_rect.x(); }
+    double y() const { return m_rect.y(); }
+    double width() const { return m_rect.width(); }
+    double height() const { return m_rect.height(); }
+
+    double top() const { return min(y(), y() + height()); }
+    double right() const { return max(x(), x() + width()); }
+    double bottom() const { return max(y(), y() + height()); }
+    double left() const { return min(x(), x() + width()); }
+
+private:
+    DOMRect(float x, float y, float width, float height)
+        : m_rect(x, y, width, height)
+    {
+    }
+
+    Gfx::FloatRect m_rect;
+};
+}

+ 15 - 0
Userland/Libraries/LibWeb/Geometry/DOMRect.idl

@@ -0,0 +1,15 @@
+interface DOMRect {
+
+    constructor(optional double x = 0, optional double y = 0, optional double width = 0, optional double height = 0);
+
+    readonly attribute double x;
+    readonly attribute double y;
+    readonly attribute double width;
+    readonly attribute double height;
+
+    readonly attribute double top;
+    readonly attribute double right;
+    readonly attribute double bottom;
+    readonly attribute double left;
+
+};