From 43d378940f218f977f5dfa01b56ce5df48612e37 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 27 Sep 2021 00:55:13 +0200 Subject: [PATCH] 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/ --- .../LibWeb/WrapperGenerator.cpp | 13 ++++- Userland/Libraries/LibWeb/CMakeLists.txt | 1 + Userland/Libraries/LibWeb/DOM/Element.cpp | 17 ++++++ Userland/Libraries/LibWeb/DOM/Element.h | 2 + Userland/Libraries/LibWeb/DOM/Element.idl | 3 + Userland/Libraries/LibWeb/Forward.h | 5 ++ Userland/Libraries/LibWeb/Geometry/DOMRect.h | 57 +++++++++++++++++++ .../Libraries/LibWeb/Geometry/DOMRect.idl | 15 +++++ 8 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 Userland/Libraries/LibWeb/Geometry/DOMRect.h create mode 100644 Userland/Libraries/LibWeb/Geometry/DOMRect.idl diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp index 87b6e935c5..ef1ed3d681 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/WrapperGenerator.cpp +++ b/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 #elif __has_include() # include +#elif __has_include() +# include #elif __has_include() # include #elif __has_include() @@ -1244,6 +1246,7 @@ void generate_implementation(IDL::Interface const& interface) #include #include #include +#include #include #include #include @@ -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 #elif __has_include() # include +#elif __has_include() +# include #elif __has_include() # include #elif __has_include() @@ -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 #include #include +#include #include #include #include @@ -2447,6 +2455,8 @@ void generate_prototype_implementation(IDL::Interface const& interface) # include #elif __has_include() # include +#elif __has_include() +# include #elif __has_include() # include #elif __has_include() @@ -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; diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 79293e8254..7df24978b9 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/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) diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index 33df862680..ded522b47a 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include 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 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_node()); + return Geometry::DOMRect::create(box.absolute_rect().translated(-viewport_offset.x(), -viewport_offset.y())); +} + } diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h index a1f36de618..b02d77b7c7 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.h +++ b/Userland/Libraries/LibWeb/DOM/Element.h @@ -109,6 +109,8 @@ public: bool is_void_element() const; bool serializes_as_void() const; + NonnullRefPtr get_bounding_client_rect() const; + protected: RefPtr create_layout_node() override; diff --git a/Userland/Libraries/LibWeb/DOM/Element.idl b/Userland/Libraries/LibWeb/DOM/Element.idl index 87c5ba58d7..6b3f04676b 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.idl +++ b/Userland/Libraries/LibWeb/DOM/Element.idl @@ -34,4 +34,7 @@ interface Element : Node { ArrayFromVector querySelectorAll(DOMString selectors); [SameObject] readonly attribute HTMLCollection children; + + DOMRect getBoundingClientRect(); + }; diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 4683bced38..ae4e408a8b 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -90,6 +90,10 @@ template 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; diff --git a/Userland/Libraries/LibWeb/Geometry/DOMRect.h b/Userland/Libraries/LibWeb/Geometry/DOMRect.h new file mode 100644 index 0000000000..bed9698107 --- /dev/null +++ b/Userland/Libraries/LibWeb/Geometry/DOMRect.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Web::Geometry { + +// FIXME: Split this into DOMRectReadOnly and DOMRect +// https://drafts.fxtf.org/geometry/#DOMRect +class DOMRect final + : public RefCounted + , public Bindings::Wrappable { +public: + using WrapperType = Bindings::DOMRectWrapper; + + static NonnullRefPtr 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 create(double x = 0, double y = 0, double width = 0, double height = 0) + { + return adopt_ref(*new DOMRect(x, y, width, height)); + } + + static NonnullRefPtr 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; +}; +} diff --git a/Userland/Libraries/LibWeb/Geometry/DOMRect.idl b/Userland/Libraries/LibWeb/Geometry/DOMRect.idl new file mode 100644 index 0000000000..0e0c599f6b --- /dev/null +++ b/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; + +};