ladybird/Libraries/LibWeb/UIEvents/MouseEvent.h
Andreas Kling 4daec8f6e0 LibWeb: Use Event storage for MouseEvent relatedTarget
Store MouseEvent's relatedTarget in the inherited Event field instead of
keeping a second slot on MouseEvent.

Event dispatch retargets and updates the inherited field while building
the event path. The second slot left JS listeners observing stale or
null relatedTarget values during mouse and pointer boundary events.

Add coverage for boundary events between sibling elements.
2026-06-18 12:40:37 +02:00

119 lines
4.5 KiB
C++

/*
* Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/TypeCasts.h>
#include <LibWeb/Bindings/EventModifier.h>
#include <LibWeb/Bindings/MouseEvent.h>
#include <LibWeb/Export.h>
#include <LibWeb/PixelUnits.h>
#include <LibWeb/UIEvents/UIEvent.h>
namespace Web::UIEvents {
class WEB_API MouseEvent : public UIEvent {
WEB_PLATFORM_OBJECT(MouseEvent, UIEvent);
GC_DECLARE_ALLOCATOR(MouseEvent);
public:
[[nodiscard]] static GC::Ref<MouseEvent> create(JS::Realm&, FlyString const& event_name, Bindings::MouseEventInit const& = {}, double page_x = 0, double page_y = 0, double offset_x = 0, double offset_y = 0);
static WebIDL::ExceptionOr<GC::Ref<MouseEvent>> create_from_platform_event(JS::Realm&, GC::Ptr<HTML::WindowProxy>, FlyString const& event_name, CSSPixelPoint screen, CSSPixelPoint page, CSSPixelPoint client, CSSPixelPoint offset, Optional<CSSPixelPoint> movement, unsigned button, unsigned buttons, unsigned modifiers, int detail = 0);
static WebIDL::ExceptionOr<GC::Ref<MouseEvent>> construct_impl(JS::Realm&, FlyString const& event_name, Bindings::MouseEventInit const&);
virtual ~MouseEvent() override;
virtual double screen_x() const { return is_trusted() ? m_screen_x : AK::floor(m_screen_x); }
virtual double screen_y() const { return is_trusted() ? m_screen_y : AK::floor(m_screen_y); }
virtual double page_x() const { return is_trusted() ? m_page_x : AK::floor(m_page_x); }
virtual double page_y() const { return is_trusted() ? m_page_y : AK::floor(m_page_y); }
virtual double client_x() const { return is_trusted() ? m_client_x : AK::floor(m_client_x); }
virtual double client_y() const { return is_trusted() ? m_client_y : AK::floor(m_client_y); }
double x() const { return client_x(); }
double y() const { return client_y(); }
virtual double offset_x() const { return is_trusted() ? m_offset_x : AK::floor(m_offset_x); }
virtual double offset_y() const { return is_trusted() ? m_offset_y : AK::floor(m_offset_y); }
bool ctrl_key() const { return m_ctrl_key; }
bool shift_key() const { return m_shift_key; }
bool alt_key() const { return m_alt_key; }
bool meta_key() const { return m_meta_key; }
bool platform_ctrl_key() const
{
#if defined(AK_OS_MACOS)
return meta_key();
#else
return ctrl_key();
#endif
}
double movement_x() const { return m_movement_x; }
double movement_y() const { return m_movement_y; }
i16 button() const { return m_button; }
u16 buttons() const { return m_buttons; }
bool get_modifier_state(String const& key_arg) const;
virtual u32 which() const override { return m_button + 1; }
void init_mouse_event(String const& type, bool bubbles, bool cancelable, GC::Ptr<HTML::WindowProxy> view, WebIDL::Long detail, WebIDL::Long screen_x, WebIDL::Long screen_y, WebIDL::Long client_x, WebIDL::Long client_y, bool ctrl_key, bool alt_key, bool shift_key, bool meta_key, WebIDL::Short button, DOM::EventTarget* related_target);
[[nodiscard]] virtual GC::Ref<MouseEvent> clone() const;
void set_offset_x(double offset_x) { m_offset_x = offset_x; }
void set_offset_y(double offset_y) { m_offset_y = offset_y; }
protected:
MouseEvent(JS::Realm&, FlyString const& event_name, Bindings::MouseEventInit const& event_init, double page_x, double page_y, double offset_x, double offset_y);
virtual void initialize(JS::Realm&) override;
double m_screen_x { 0 };
double m_screen_y { 0 };
double m_page_x { 0 };
double m_page_y { 0 };
double m_client_x { 0 };
double m_client_y { 0 };
double m_offset_x { 0 };
double m_offset_y { 0 };
private:
virtual bool is_mouse_event() const override { return true; }
bool m_ctrl_key { false };
bool m_shift_key { false };
bool m_alt_key { false };
bool m_meta_key { false };
bool m_modifier_alt_graph { false };
bool m_modifier_caps_lock { false };
bool m_modifier_fn { false };
bool m_modifier_fn_lock { false };
bool m_modifier_hyper { false };
bool m_modifier_num_lock { false };
bool m_modifier_scroll_lock { false };
bool m_modifier_super { false };
bool m_modifier_symbol { false };
bool m_modifier_symbol_lock { false };
double m_movement_x { 0 };
double m_movement_y { 0 };
i16 m_button { 0 };
u16 m_buttons { 0 };
};
}
namespace Web::DOM {
template<>
inline bool Event::fast_is<UIEvents::MouseEvent>() const { return is_mouse_event(); }
}