diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index f33a17ff8d1c6a..afe4b5392b88a1 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -62,6 +62,7 @@ static bool is_platform_object(Type const& type) "Path2D"sv, "PerformanceEntry"sv, "PerformanceMark"sv, + "PointerEvent"sv, "ReadableStreamBYOBReader"sv, "ReadableStreamDefaultReader"sv, "RadioNodeList"sv, diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 973ab5efd4b427..2601a6314913e9 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -635,6 +635,7 @@ set(SOURCES UIEvents/FocusEvent.cpp UIEvents/KeyboardEvent.cpp UIEvents/MouseEvent.cpp + UIEvents/PointerEvent.cpp UIEvents/UIEvent.cpp UIEvents/WheelEvent.cpp UserTiming/PerformanceMark.cpp diff --git a/Userland/Libraries/LibWeb/DOM/Event.h b/Userland/Libraries/LibWeb/DOM/Event.h index f9cc2f74e612d2..be41c492721ea1 100644 --- a/Userland/Libraries/LibWeb/DOM/Event.h +++ b/Userland/Libraries/LibWeb/DOM/Event.h @@ -148,6 +148,7 @@ class Event : public Bindings::PlatformObject { bool fast_is() const = delete; virtual bool is_mouse_event() const { return false; } + virtual bool is_pointer_event() const { return false; } protected: void initialize_event(String const&, bool, bool); diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 7fb2c23685117f..17fd97c4a72c5b 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -656,6 +656,7 @@ class SVGTitleElement; namespace Web::UIEvents { class KeyboardEvent; class MouseEvent; +class PointerEvent; class UIEvents; } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp index d8003b881b170c..72db0e0e96ea08 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include diff --git a/Userland/Libraries/LibWeb/UIEvents/PointerEvent.cpp b/Userland/Libraries/LibWeb/UIEvents/PointerEvent.cpp new file mode 100644 index 00000000000000..d810087c9799bc --- /dev/null +++ b/Userland/Libraries/LibWeb/UIEvents/PointerEvent.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024, Shannon Booth + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +namespace Web::UIEvents { + +JS_DEFINE_ALLOCATOR(PointerEvent); + +PointerEvent::PointerEvent(JS::Realm& realm, FlyString const& type, PointerEventInit const& event_init, double page_x, double page_y, double offset_x, double offset_y) + : MouseEvent(realm, type, event_init, page_x, page_y, offset_x, offset_y) + , m_pointer_id(event_init.pointer_id) + , m_width(event_init.width) + , m_height(event_init.height) + , m_pressure(event_init.pressure) + , m_tangential_pressure(event_init.tangential_pressure) + , m_tilt_x(event_init.tilt_x.value_or(0)) + , m_tilt_y(event_init.tilt_y.value_or(0)) + , m_twist(event_init.twist) + , m_altitude_angle(event_init.altitude_angle.value_or(DEFAULT_ALTITUDE_ANGLE)) + , m_azimuth_angle(event_init.azimuth_angle.value_or(0)) + , m_pointer_type(event_init.pointer_type) + , m_is_primary(event_init.is_primary) +{ +} + +PointerEvent::~PointerEvent() = default; + +void PointerEvent::initialize(JS::Realm& realm) +{ + Base::initialize(realm); + WEB_SET_PROTOTYPE_FOR_INTERFACE(PointerEvent); +} + +JS::NonnullGCPtr PointerEvent::create(JS::Realm& realm, FlyString const& type, PointerEventInit const& event_init, double page_x, double page_y, double offset_x, double offset_y) +{ + return realm.heap().allocate(realm, realm, type, event_init, page_x, page_y, offset_x, offset_y); +} + +WebIDL::ExceptionOr> PointerEvent::construct_impl(JS::Realm& realm, FlyString const& type, PointerEventInit const& event_init) +{ + return create(realm, type, event_init); +} + +} diff --git a/Userland/Libraries/LibWeb/UIEvents/PointerEvent.h b/Userland/Libraries/LibWeb/UIEvents/PointerEvent.h new file mode 100644 index 00000000000000..5c6189121def84 --- /dev/null +++ b/Userland/Libraries/LibWeb/UIEvents/PointerEvent.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2024, Shannon Booth + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::UIEvents { + +struct PointerEventInit : public MouseEventInit { + WebIDL::Long pointer_id { 0 }; + double width { 1 }; + double height { 1 }; + float pressure { 0 }; + float tangential_pressure { 0 }; + Optional tilt_x; + Optional tilt_y; + WebIDL::Long twist { 0 }; + Optional altitude_angle; + Optional azimuth_angle; + String pointer_type; + bool is_primary { false }; +}; + +// https://w3c.github.io/pointerevents/#pointerevent-interface +class PointerEvent : public MouseEvent { + WEB_PLATFORM_OBJECT(PointerEvent, MouseEvent); + JS_DECLARE_ALLOCATOR(PointerEvent); + +public: + [[nodiscard]] static JS::NonnullGCPtr create(JS::Realm&, FlyString const& type, PointerEventInit const& = {}, double page_x = 0, double page_y = 0, double offset_x = 0, double offset_y = 0); + static WebIDL::ExceptionOr> construct_impl(JS::Realm&, FlyString const& type, PointerEventInit const&); + + virtual ~PointerEvent() override; + + WebIDL::Long pointer_id() const { return m_pointer_id; } + double width() const { return m_width; } + double height() const { return m_height; } + float pressure() const { return m_pressure; } + float tangential_pressure() const { return m_tangential_pressure; } + WebIDL::Long tilt_x() const { return m_tilt_x; } + WebIDL::Long tilt_y() const { return m_tilt_y; } + WebIDL::Long twist() const { return m_twist; } + double altitude_angle() const { return m_altitude_angle; } + double azimuth_angle() const { return m_azimuth_angle; } + String const& pointer_type() const { return m_pointer_type; } + bool is_primary() const { return m_is_primary; } + + // https://w3c.github.io/pointerevents/#dom-pointerevent-pressure + // For hardware and platforms that do not support pressure, the value MUST be 0.5 when in the active buttons state and 0 otherwise. + static constexpr float ACTIVE_PRESSURE_DEFAULT_IN_ACTIVE_BUTTON_STATE { 0.5 }; + +protected: + PointerEvent(JS::Realm&, FlyString const& type, PointerEventInit const&, double page_x, double page_y, double offset_x, double offset_y); + + virtual void initialize(JS::Realm&) override; + +private: + virtual bool is_pointer_event() const final { return true; } + + // A unique identifier for the pointer causing the event. + // https://w3c.github.io/pointerevents/#dom-pointerevent-pointerid + WebIDL::Long m_pointer_id { 0 }; + + // The width (magnitude on the X axis), in CSS pixels (see [CSS21]), of the contact geometry of the pointer + // https://w3c.github.io/pointerevents/#dom-pointerevent-width + double m_width { 1 }; + + // The height (magnitude on the Y axis), in CSS pixels (see [CSS21]), of the contact geometry of the pointer. + // https://w3c.github.io/pointerevents/#dom-pointerevent-width + double m_height { 1 }; + + // The normalized pressure of the pointer input in the range of [0,1], where 0 and 1 represent the minimum and + // maximum pressure the hardware is capable of detecting, respectively + // https://w3c.github.io/pointerevents/#dom-pointerevent-pressure + float m_pressure { 0 }; + + // The normalized tangential pressure (also known as barrel pressure), typically set by an additional control + // (e.g. a finger wheel on an airbrush stylus), of the pointer input in the range of [-1,1], where 0 is the + // neutral position of the control + // https://w3c.github.io/pointerevents/#dom-pointerevent-tangentialpressure + float m_tangential_pressure { 0 }; + + // The plane angle (in degrees, in the range of [-90,90]) between the Y-Z plane and the plane containing both the + // transducer (e.g. pen/stylus) axis and the Y axis + // https://w3c.github.io/pointerevents/#dom-pointerevent-tiltx + WebIDL::Long m_tilt_x { 0 }; + + // The plane angle (in degrees, in the range of [-90,90]) between the X-Z plane and the plane containing both the + // transducer (e.g. pen/stylus) axis and the X axis + // https://w3c.github.io/pointerevents/#dom-pointerevent-tilty + WebIDL::Long m_tilt_y { 0 }; + + // The clockwise rotation (in degrees, in the range of [0,359]) of a transducer (e.g. pen/stylus) around its own major axis + // https://w3c.github.io/pointerevents/#dom-pointerevent-twist + WebIDL::Long m_twist { 0 }; + + // The altitude (in radians) of the transducer (e.g. pen/stylus), in the range [0,π/2] — where 0 is parallel to the surface + // (X-Y plane), and π/2 is perpendicular to the surface + // For hardware and platforms that do not report tilt or angle, the value MUST be π/2. + // https://w3c.github.io/pointerevents/#dom-pointerevent-altitudeangle + static constexpr double DEFAULT_ALTITUDE_ANGLE { AK::Pi / 2 }; + double m_altitude_angle { DEFAULT_ALTITUDE_ANGLE }; + + // The azimuth angle (in radians) of the transducer (e.g. pen/stylus), in the range [0, 2π] — where 0 represents a transducer + // whose cap is pointing in the direction of increasing X values (point to "3 o'clock" if looking straight down) on the X-Y + // plane, and the values progressively increase when going clockwise (π/2 at "6 o'clock", π at "9 o'clock", 3π/2 at "12 o'clock"). + // https://w3c.github.io/pointerevents/#dom-pointerevent-azimuthangle + double m_azimuth_angle { 0 }; + + // Indicates the device type that caused the event (mouse, pen, touch, etc.) + // https://w3c.github.io/pointerevents/#dom-pointerevent-pointertype + String m_pointer_type; + + // Indicates if the pointer represents the primary pointer of this pointer type + // https://w3c.github.io/pointerevents/#dom-pointerevent-isprimary + bool m_is_primary { false }; +}; + +} + +namespace Web::DOM { + +template<> +inline bool Event::fast_is() const { return is_pointer_event(); } + +} diff --git a/Userland/Libraries/LibWeb/UIEvents/PointerEvent.idl b/Userland/Libraries/LibWeb/UIEvents/PointerEvent.idl new file mode 100644 index 00000000000000..81ea58cb2c234a --- /dev/null +++ b/Userland/Libraries/LibWeb/UIEvents/PointerEvent.idl @@ -0,0 +1,38 @@ +#import + +dictionary PointerEventInit : MouseEventInit { + long pointerId = 0; + double width = 1; + double height = 1; + float pressure = 0; + float tangentialPressure = 0; + long tiltX; + long tiltY; + long twist = 0; + double altitudeAngle; + double azimuthAngle; + DOMString pointerType = ""; + boolean isPrimary = false; + // FIXME: sequence coalescedEvents = []; + // FIXME: sequence predictedEvents = []; +}; + +// https://w3c.github.io/pointerevents/#pointerevent-interface +[Exposed=Window] +interface PointerEvent : MouseEvent { + constructor(DOMString type, optional PointerEventInit eventInitDict = {}); + readonly attribute long pointerId; + readonly attribute double width; + readonly attribute double height; + readonly attribute float pressure; + readonly attribute float tangentialPressure; + readonly attribute long tiltX; + readonly attribute long tiltY; + readonly attribute long twist; + readonly attribute double altitudeAngle; + readonly attribute double azimuthAngle; + readonly attribute DOMString pointerType; + readonly attribute boolean isPrimary; + // FIXME: [SecureContext] sequence getCoalescedEvents(); + // FIXME: sequence getPredictedEvents(); +}; diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake index 4d276ca96f11e1..d7ea43128587bf 100644 --- a/Userland/Libraries/LibWeb/idl_files.cmake +++ b/Userland/Libraries/LibWeb/idl_files.cmake @@ -279,6 +279,7 @@ libweb_js_bindings(Selection/Selection) libweb_js_bindings(UIEvents/FocusEvent) libweb_js_bindings(UIEvents/KeyboardEvent) libweb_js_bindings(UIEvents/MouseEvent) +libweb_js_bindings(UIEvents/PointerEvent) libweb_js_bindings(UIEvents/UIEvent) libweb_js_bindings(UIEvents/WheelEvent) libweb_js_bindings(UserTiming/PerformanceMark)