diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 6a025ff0f0..5984a6f376 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -539,7 +539,10 @@ set(SOURCES ReferrerPolicy/AbstractOperations.cpp ReferrerPolicy/ReferrerPolicy.cpp RequestIdleCallback/IdleDeadline.cpp + ResizeObserver/ResizeObservation.cpp ResizeObserver/ResizeObserver.cpp + ResizeObserver/ResizeObserverEntry.cpp + ResizeObserver/ResizeObserverSize.cpp SecureContexts/AbstractOperations.cpp SRI/SRI.cpp Streams/AbstractOperations.cpp diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 25e60707a3..9eb02dbddf 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -95,6 +95,8 @@ #include #include #include +#include +#include #include #include #include @@ -453,6 +455,9 @@ void Document::visit_edges(Cell::Visitor& visitor) for (auto& observer : m_intersection_observers) visitor.visit(observer); + for (auto& observer : m_resize_observers) + visitor.visit(observer); + for (auto& image : m_shared_image_requests) visitor.visit(image.value); @@ -3161,6 +3166,18 @@ void Document::unregister_intersection_observer(Badge, ResizeObserver::ResizeObserver& observer) +{ + m_resize_observers.append(observer); +} + +void Document::unregister_resize_observer(Badge, ResizeObserver::ResizeObserver& observer) +{ + m_resize_observers.remove_first_matching([&](auto& registered_observer) { + return registered_observer.ptr() == &observer; + }); +} + // https://www.w3.org/TR/intersection-observer/#queue-an-intersection-observer-task void Document::queue_intersection_observer_task() { diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h index e08d5a27d8..55a040d5a8 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.h +++ b/Userland/Libraries/LibWeb/DOM/Document.h @@ -525,6 +525,9 @@ public: void register_intersection_observer(Badge, IntersectionObserver::IntersectionObserver&); void unregister_intersection_observer(Badge, IntersectionObserver::IntersectionObserver&); + void register_resize_observer(Badge, ResizeObserver::ResizeObserver&); + void unregister_resize_observer(Badge, ResizeObserver::ResizeObserver&); + void run_the_update_intersection_observations_steps(HighResolutionTime::DOMHighResTimeStamp time); void start_intersection_observing_a_lazy_loading_element(Element&); @@ -782,6 +785,8 @@ private: // Each Document has a lazy load intersection observer, initially set to null but can be set to an IntersectionObserver instance. JS::GCPtr m_lazy_load_intersection_observer; + Vector> m_resize_observers; + // https://html.spec.whatwg.org/multipage/semantics.html#will-declaratively-refresh // A Document object has an associated will declaratively refresh (a boolean). It is initially false. bool m_will_declaratively_refresh { false }; diff --git a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObservation.cpp b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObservation.cpp new file mode 100644 index 0000000000..0a6ed721d5 --- /dev/null +++ b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObservation.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +namespace Web::ResizeObserver { + +JS_DEFINE_ALLOCATOR(ResizeObservation); + +WebIDL::ExceptionOr> ResizeObservation::create(JS::Realm& realm, DOM::Element& target, Bindings::ResizeObserverBoxOptions observed_box) +{ + return realm.heap().allocate(realm, realm, target, observed_box); +} + +ResizeObservation::ResizeObservation(JS::Realm& realm, DOM::Element& target, Bindings::ResizeObserverBoxOptions observed_box) + : m_realm(realm) + , m_target(target) + , m_observed_box(observed_box) +{ + auto computed_size = realm.heap().allocate(realm, realm); + m_last_reported_sizes.append(computed_size); +} + +void ResizeObservation::visit_edges(JS::Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_target); + for (auto& size : m_last_reported_sizes) + visitor.visit(size); +} + +// https://drafts.csswg.org/resize-observer-1/#dom-resizeobservation-isactive +bool ResizeObservation::is_active() +{ + // 1. Set currentSize by calculate box size given target and observedBox. + auto current_size = ResizeObserverSize::calculate_box_size(m_realm, m_target, m_observed_box); + + // 2. Return true if currentSize is not equal to the first entry in this.lastReportedSizes. + VERIFY(!m_last_reported_sizes.is_empty()); + if (!m_last_reported_sizes.first()->equals(*current_size)) + return true; + + // 3. Return false. + return false; +} + +} diff --git a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObservation.h b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObservation.h new file mode 100644 index 0000000000..0beeb82ddc --- /dev/null +++ b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObservation.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Web::ResizeObserver { + +// https://drafts.csswg.org/resize-observer-1/#resize-observation-interface +class ResizeObservation : public JS::Cell { + JS_CELL(ResizeObservation, JS::Cell); + JS_DECLARE_ALLOCATOR(ResizeObservation); + +public: + static WebIDL::ExceptionOr> create(JS::Realm&, DOM::Element&, Bindings::ResizeObserverBoxOptions); + + bool is_active(); + + JS::NonnullGCPtr target() const { return m_target; } + Bindings::ResizeObserverBoxOptions observed_box() const { return m_observed_box; } + + Vector>& last_reported_sizes() { return m_last_reported_sizes; } + + explicit ResizeObservation(JS::Realm& realm, DOM::Element& target, Bindings::ResizeObserverBoxOptions observed_box); + +private: + virtual void visit_edges(JS::Cell::Visitor&) override; + + JS::NonnullGCPtr m_realm; + JS::NonnullGCPtr m_target; + Bindings::ResizeObserverBoxOptions m_observed_box; + Vector> m_last_reported_sizes; +}; + +} diff --git a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.cpp b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.cpp index 379bbdc3e1..83ec505478 100644 --- a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.cpp +++ b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.cpp @@ -1,12 +1,16 @@ /* * Copyright (c) 2021, Andreas Kling + * Copyright (c) 2024, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ #include -#include +#include +#include +#include #include +#include namespace Web::ResizeObserver { @@ -15,14 +19,16 @@ JS_DEFINE_ALLOCATOR(ResizeObserver); // https://drafts.csswg.org/resize-observer/#dom-resizeobserver-resizeobserver WebIDL::ExceptionOr> ResizeObserver::construct_impl(JS::Realm& realm, WebIDL::CallbackType* callback) { - // FIXME: Implement - (void)callback; - return realm.heap().allocate(realm, realm); + return realm.heap().allocate(realm, realm, callback); } -ResizeObserver::ResizeObserver(JS::Realm& realm) +ResizeObserver::ResizeObserver(JS::Realm& realm, WebIDL::CallbackType* callback) : PlatformObject(realm) + , m_callback(callback) { + auto navigable = verify_cast(HTML::relevant_global_object(*this)).navigable(); + m_document = navigable->active_document().ptr(); + m_document->register_resize_observer({}, *this); } ResizeObserver::~ResizeObserver() = default; @@ -33,12 +39,40 @@ void ResizeObserver::initialize(JS::Realm& realm) set_prototype(&Bindings::ensure_web_prototype(realm, "ResizeObserver"_fly_string)); } -// https://drafts.csswg.org/resize-observer/#dom-resizeobserver-observe +void ResizeObserver::visit_edges(JS::Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_callback); + for (auto& observation : m_observation_targets) + visitor.visit(observation); + for (auto& observation : m_active_targets) + visitor.visit(observation); + for (auto& observation : m_skipped_targets) + visitor.visit(observation); +} + +void ResizeObserver::finalize() +{ + if (m_document) + m_document->unregister_resize_observer({}, *this); +} + +// https://drafts.csswg.org/resize-observer-1/#dom-resizeobserver-observe void ResizeObserver::observe(DOM::Element& target, ResizeObserverOptions options) { - // FIXME: Implement - (void)target; - (void)options; + // 1. If target is in [[observationTargets]] slot, call unobserve() with argument target. + auto observation = m_observation_targets.find_if([&](auto& observation) { return observation->target().ptr() == ⌖ }); + if (!observation.is_end()) + unobserve(target); + + // 2. Let observedBox be the value of the box dictionary member of options. + auto observed_box = options.box; + + // 3. Let resizeObservation be new ResizeObservation(target, observedBox). + auto resize_observation = MUST(ResizeObservation::create(realm(), target, observed_box)); + + // 4. Add the resizeObservation to the [[observationTargets]] slot. + m_observation_targets.append(resize_observation); } // https://drafts.csswg.org/resize-observer/#dom-resizeobserver-unobserve @@ -54,4 +88,21 @@ void ResizeObserver::disconnect() // FIXME: Implement } +void ResizeObserver::invoke_callback(Vector>& entries) const +{ + auto& callback = *m_callback; + auto& realm = callback.callback_context->realm(); + + auto wrapped_records = MUST(JS::Array::create(realm, 0)); + for (size_t i = 0; i < entries.size(); ++i) { + auto& record = entries.at(i); + auto property_index = JS::PropertyKey { i }; + MUST(wrapped_records->create_data_property(property_index, record.ptr())); + } + + auto result = WebIDL::invoke_callback(callback, JS::js_undefined(), wrapped_records); + if (result.is_abrupt()) + HTML::report_exception(result, realm); +} + } diff --git a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.h b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.h index 4a05669aea..0d0f0891c4 100644 --- a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.h +++ b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Andreas Kling + * Copyright (c) 2024, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ @@ -7,6 +8,8 @@ #pragma once #include +#include +#include namespace Web::ResizeObserver { @@ -14,7 +17,7 @@ struct ResizeObserverOptions { Bindings::ResizeObserverBoxOptions box; }; -// https://drafts.csswg.org/resize-observer/#resize-observer-interface +// https://drafts.csswg.org/resize-observer-1/#resize-observer-interface class ResizeObserver : public Bindings::PlatformObject { WEB_PLATFORM_OBJECT(ResizeObserver, Bindings::PlatformObject); JS_DECLARE_ALLOCATOR(ResizeObserver); @@ -28,10 +31,26 @@ public: void unobserve(DOM::Element& target); void disconnect(); + void invoke_callback(Vector>& entries) const; + + Vector>& observation_targets() { return m_observation_targets; } + Vector>& active_targets() { return m_active_targets; } + Vector>& skipped_targets() { return m_skipped_targets; } + private: - explicit ResizeObserver(JS::Realm&); + explicit ResizeObserver(JS::Realm&, WebIDL::CallbackType* callback); virtual void initialize(JS::Realm&) override; + virtual void visit_edges(JS::Cell::Visitor&) override; + virtual void finalize() override; + + JS::GCPtr m_callback; + Vector> m_observation_targets; + Vector> m_active_targets; + Vector> m_skipped_targets; + + // AD-HOC: This is the document where we've registered the observer. + WeakPtr m_document; }; } diff --git a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.idl b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.idl index e0d964d7c7..695ee742b3 100644 --- a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.idl +++ b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserver.idl @@ -1,6 +1,6 @@ #import -// https://drafts.csswg.org/resize-observer/#resize-observer-interface +// https://drafts.csswg.org/resize-observer-1/#resize-observer-interface [Exposed=(Window)] interface ResizeObserver { @@ -19,5 +19,5 @@ dictionary ResizeObserverOptions { ResizeObserverBoxOptions box = "content-box"; }; -// https://drafts.csswg.org/resize-observer/#resize-observer-callback +// https://drafts.csswg.org/resize-observer-1/#resize-observer-callback callback ResizeObserverCallback = undefined (sequence entries, ResizeObserver observer); diff --git a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverEntry.cpp b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverEntry.cpp new file mode 100644 index 0000000000..9f04005fa9 --- /dev/null +++ b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverEntry.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +namespace Web::ResizeObserver { + +JS_DEFINE_ALLOCATOR(ResizeObserverEntry); + +// https://drafts.csswg.org/resize-observer-1/#create-and-populate-resizeobserverentry-h +WebIDL::ExceptionOr> ResizeObserverEntry::create_and_populate(JS::Realm& realm, DOM::Element& target) +{ + // 1. Let this be a new ResizeObserverEntry. + // 2. Set this.target slot to target. + auto resize_observer_entry = realm.heap().allocate(realm, realm, target); + + // 3. Set this.borderBoxSize slot to result of calculating box size given target and observedBox of "border-box". + auto border_box_size = ResizeObserverSize::calculate_box_size(realm, target, Bindings::ResizeObserverBoxOptions::BorderBox); + resize_observer_entry->m_border_box_size.append(border_box_size); + + // 4. Set this.contentBoxSize slot to result of calculating box size given target and observedBox of "content-box". + auto content_box_size = ResizeObserverSize::calculate_box_size(realm, target, Bindings::ResizeObserverBoxOptions::ContentBox); + resize_observer_entry->m_content_box_size.append(content_box_size); + + // 5. Set this.devicePixelContentBoxSize slot to result of calculating box size given target and observedBox of "device-pixel-content-box". + auto device_pixel_content_box_size = ResizeObserverSize::calculate_box_size(realm, target, Bindings::ResizeObserverBoxOptions::DevicePixelContentBox); + resize_observer_entry->m_device_pixel_content_box_size.append(device_pixel_content_box_size); + + // 6. Set this.contentRect to logical this.contentBoxSize given target and observedBox of "content-box". + double x = 0; + double y = 0; + double width = content_box_size->inline_size(); + double height = content_box_size->block_size(); + + // 7. If target is not an SVG element or target is an SVG element with an associated CSS layout box do these steps: + if (!target.is_svg_element() && target.paintable_box()) { + auto const& paintable_box = *target.paintable_box(); + auto absolute_padding_rect = paintable_box.absolute_padding_box_rect(); + // Set this.contentRect.top to target.padding top. + y = absolute_padding_rect.y().to_double(); + // Set this.contentRect.left to target.padding left. + x = absolute_padding_rect.x().to_double(); + } else if (target.is_svg_element() && target.paintable_box()) { + // 8. If target is an SVG element without an associated CSS layout box do these steps: + // Set this.contentRect.top and this.contentRect.left to 0. + // NOTE: This is already done by the default constructor. + } + resize_observer_entry->m_content_rect = MUST(Geometry::DOMRectReadOnly::construct_impl(realm, x, y, width, height)); + + return resize_observer_entry; +} + +void ResizeObserverEntry::initialize(JS::Realm& realm) +{ + Base::initialize(realm); + set_prototype(&Bindings::ensure_web_prototype(realm, "ResizeObserverEntry"_fly_string)); +} + +void ResizeObserverEntry::visit_edges(JS::Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_target); + for (auto& size : m_content_box_size) + visitor.visit(size); + for (auto& size : m_border_box_size) + visitor.visit(size); +} + +static JS::NonnullGCPtr to_js_array(JS::Realm& realm, Vector> const& sizes) +{ + Vector vector; + for (auto const& size : sizes) + vector.append(JS::Value(size.ptr())); + auto array = JS::Array::create_from(realm, vector); + MUST(array->set_integrity_level(JS::Object::IntegrityLevel::Frozen)); + return array; +} + +JS::NonnullGCPtr ResizeObserverEntry::border_box_size_js_array() const +{ + return to_js_array(realm(), m_border_box_size); +} + +JS::NonnullGCPtr ResizeObserverEntry::content_box_size_js_array() const +{ + return to_js_array(realm(), m_content_box_size); +} + +JS::NonnullGCPtr ResizeObserverEntry::device_pixel_content_box_size_js_array() const +{ + return to_js_array(realm(), m_device_pixel_content_box_size); +} + +} diff --git a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverEntry.h b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverEntry.h new file mode 100644 index 0000000000..12aa1f8016 --- /dev/null +++ b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverEntry.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Web::ResizeObserver { + +// https://drafts.csswg.org/resize-observer-1/#resize-observer-entry-interface +class ResizeObserverEntry : public Bindings::PlatformObject { + WEB_PLATFORM_OBJECT(ResizeObserverEntry, Bindings::PlatformObject); + JS_DECLARE_ALLOCATOR(ResizeObserverEntry); + +public: + static WebIDL::ExceptionOr> create_and_populate(JS::Realm&, DOM::Element& target); + + JS::NonnullGCPtr content_rect() const { return *m_content_rect; } + JS::NonnullGCPtr target() const { return m_target; } + + Vector> const& border_box_size() const { return m_border_box_size; } + Vector> const& content_box_size() const { return m_content_box_size; } + Vector> const& device_pixel_content_box_size() const { return m_device_pixel_content_box_size; } + + JS::NonnullGCPtr border_box_size_js_array() const; + JS::NonnullGCPtr content_box_size_js_array() const; + JS::NonnullGCPtr device_pixel_content_box_size_js_array() const; + +private: + explicit ResizeObserverEntry(JS::Realm& realm, DOM::Element& target) + : PlatformObject(realm) + , m_target(target) + { + } + + virtual void initialize(JS::Realm&) override; + virtual void visit_edges(JS::Cell::Visitor&) override; + + JS::NonnullGCPtr m_target; + + Vector> m_content_box_size; + Vector> m_border_box_size; + Vector> m_device_pixel_content_box_size; + + JS::GCPtr m_content_rect; +}; + +} diff --git a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverEntry.idl b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverEntry.idl new file mode 100644 index 0000000000..8ff54e12df --- /dev/null +++ b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverEntry.idl @@ -0,0 +1,15 @@ +#import +#import + +// https://drafts.csswg.org/resize-observer-1/#resize-observer-entry-interface +[Exposed=Window] +interface ResizeObserverEntry { + readonly attribute Element target; + readonly attribute DOMRectReadOnly contentRect; + // FIXME: Return FrozenArray instead of any. + [ImplementedAs=border_box_size_js_array] readonly attribute any borderBoxSize; + // FIXME: Return FrozenArray instead of any. + [ImplementedAs=content_box_size_js_array] readonly attribute any contentBoxSize; + // FIXME: Return FrozenArray instead of any. + [ImplementedAs=device_pixel_content_box_size_js_array] readonly attribute any devicePixelContentBoxSize; +}; diff --git a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverSize.cpp b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverSize.cpp new file mode 100644 index 0000000000..85d3533575 --- /dev/null +++ b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverSize.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +namespace Web::ResizeObserver { + +JS_DEFINE_ALLOCATOR(ResizeObserverSize); + +void ResizeObserverSize::initialize(JS::Realm& realm) +{ + Base::initialize(realm); + set_prototype(&Bindings::ensure_web_prototype(realm, "ResizeObserverSize"_fly_string)); +} + +// https://drafts.csswg.org/resize-observer-1/#calculate-box-size +JS::NonnullGCPtr ResizeObserverSize::calculate_box_size(JS::Realm& realm, DOM::Element& target, Bindings::ResizeObserverBoxOptions observed_box) +{ + // 1. Let computedSize be a new ResizeObserverSize object. + auto computed_size = realm.heap().allocate(realm, realm); + + // FIXME: 2. If target is an SVGGraphicsElement that does not have an associated CSS layout box: + // Otherwise: + if (target.paintable_box()) { + auto const& paintable_box = *target.paintable_box(); + switch (observed_box) { + case Bindings::ResizeObserverBoxOptions::BorderBox: + // 1. Set computedSize’s inlineSize attribute to target’s border area inline length. + computed_size->set_inline_size(paintable_box.border_box_width().to_double()); + // 2. Set computedSize’s blockSize attribute to target’s border area block length. + computed_size->set_block_size(paintable_box.border_box_height().to_double()); + break; + case Bindings::ResizeObserverBoxOptions::ContentBox: + // 1. Set computedSize’s inlineSize attribute to target’s content area inline length. + computed_size->set_inline_size(paintable_box.content_width().to_double()); + // 2. Set computedSize’s blockSize attribute to target’s content area block length. + computed_size->set_block_size(paintable_box.content_height().to_double()); + break; + case Bindings::ResizeObserverBoxOptions::DevicePixelContentBox: { + auto device_pixel_ratio = target.document().window().device_pixel_ratio(); + // 1. Set computedSize’s inlineSize attribute to target’s content area inline length, in integral device pixels. + computed_size->set_inline_size(paintable_box.border_box_width().to_double() * device_pixel_ratio); + // 2. Set computedSize’s blockSize attribute to target’s content area block length, in integral device pixels. + computed_size->set_block_size(paintable_box.border_box_height().to_double() * device_pixel_ratio); + break; + } + default: + VERIFY_NOT_REACHED(); + } + } + + // 3. Return computedSize.s + return computed_size; +} + +bool ResizeObserverSize::equals(ResizeObserverSize const& other) const +{ + return m_inline_size == other.m_inline_size && m_block_size == other.m_block_size; +} + +} diff --git a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverSize.h b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverSize.h new file mode 100644 index 0000000000..3fa74feece --- /dev/null +++ b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverSize.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::ResizeObserver { + +// https://drafts.csswg.org/resize-observer-1/#resizeobserversize +class ResizeObserverSize : public Bindings::PlatformObject { + WEB_PLATFORM_OBJECT(ResizeObserverSize, Bindings::PlatformObject); + JS_DECLARE_ALLOCATOR(ResizeObserverSize); + +public: + static JS::NonnullGCPtr calculate_box_size(JS::Realm& realm, DOM::Element& target, Bindings::ResizeObserverBoxOptions observed_box); + + double inline_size() const { return m_inline_size; } + void set_inline_size(double inline_size) { m_inline_size = inline_size; } + + double block_size() const { return m_block_size; } + void set_block_size(double block_size) { m_block_size = block_size; } + + bool equals(ResizeObserverSize const& other) const; + +private: + explicit ResizeObserverSize(JS::Realm& realm) + : PlatformObject(realm) + { + } + + virtual void initialize(JS::Realm&) override; + + double m_inline_size { 0 }; + double m_block_size { 0 }; +}; + +} diff --git a/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverSize.idl b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverSize.idl new file mode 100644 index 0000000000..490714ec76 --- /dev/null +++ b/Userland/Libraries/LibWeb/ResizeObserver/ResizeObserverSize.idl @@ -0,0 +1,6 @@ +// https://drafts.csswg.org/resize-observer-1/#resizeobserversize +[Exposed=Window] +interface ResizeObserverSize { + readonly attribute unrestricted double inlineSize; + readonly attribute unrestricted double blockSize; +}; diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake index 7039a11b54..f78a802b25 100644 --- a/Userland/Libraries/LibWeb/idl_files.cmake +++ b/Userland/Libraries/LibWeb/idl_files.cmake @@ -216,6 +216,8 @@ libweb_js_bindings(PerformanceTimeline/PerformanceObserver) libweb_js_bindings(PerformanceTimeline/PerformanceObserverEntryList) libweb_js_bindings(RequestIdleCallback/IdleDeadline) libweb_js_bindings(ResizeObserver/ResizeObserver) +libweb_js_bindings(ResizeObserver/ResizeObserverEntry) +libweb_js_bindings(ResizeObserver/ResizeObserverSize) libweb_js_bindings(Streams/ByteLengthQueuingStrategy) libweb_js_bindings(Streams/CountQueuingStrategy) libweb_js_bindings(Streams/ReadableByteStreamController)