/* * 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); } }