From b19debff147d4539ac53a7daf9151966885692d8 Mon Sep 17 00:00:00 2001 From: Halil Durak Date: Wed, 4 Feb 2026 16:05:06 +0300 Subject: [PATCH] move everything to `global_event_handlers.zig` --- src/browser/Page.zig | 14 +- src/browser/webapi/Element.zig | 123 ---------------- src/browser/webapi/element/Html.zig | 6 +- src/browser/webapi/global_event_handlers.zig | 145 +++++++++++++++++++ 4 files changed, 159 insertions(+), 129 deletions(-) create mode 100644 src/browser/webapi/global_event_handlers.zig diff --git a/src/browser/Page.zig b/src/browser/Page.zig index abdb7845..657dad01 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -65,6 +65,9 @@ const timestamp = @import("../datetime.zig").timestamp; const milliTimestamp = @import("../datetime.zig").milliTimestamp; const WebApiURL = @import("webapi/URL.zig"); +const global_event_handlers = @import("webapi/global_event_handlers.zig"); +const GlobalEventHandlersLookup = global_event_handlers.Lookup; +const GlobalEventHandler = global_event_handlers.Handler; var default_url = WebApiURL{ ._raw = "about:blank" }; pub var default_location: Location = Location{ ._url = &default_url }; @@ -119,7 +122,7 @@ _element_assigned_slots: Element.AssignedSlotLookup = .{}, /// ```js /// img.setAttribute("onload", "(() => { ... })()"); /// ``` -_element_attr_listeners: Element.AttrListenerLookup = .{}, +_element_attr_listeners: GlobalEventHandlersLookup = .{}, _script_manager: ScriptManager, @@ -1215,7 +1218,7 @@ pub fn getElementByIdFromNode(self: *Page, node: *Node, id: []const u8) ?*Elemen pub fn setAttrListener( self: *Page, element: *Element, - listener_type: Element.KnownListener, + listener_type: GlobalEventHandler, listener_callback: JS.Function.Global, ) !void { if (comptime IS_DEBUG) { @@ -1225,7 +1228,7 @@ pub fn setAttrListener( }); } - const key = element.calcAttrListenerKey(listener_type); + const key = global_event_handlers.calculateKey(element.asEventTarget(), listener_type); const gop = try self._element_attr_listeners.getOrPut(self.arena, key); gop.value_ptr.* = listener_callback; } @@ -1234,9 +1237,10 @@ pub fn setAttrListener( pub fn getAttrListener( self: *const Page, element: *Element, - listener_type: Element.KnownListener, + listener_type: GlobalEventHandler, ) ?JS.Function.Global { - return self._element_attr_listeners.get(element.calcAttrListenerKey(listener_type)); + const key = global_event_handlers.calculateKey(element.asEventTarget(), listener_type); + return self._element_attr_listeners.get(key); } pub fn registerPerformanceObserver(self: *Page, observer: *PerformanceObserver) !void { diff --git a/src/browser/webapi/Element.zig b/src/browser/webapi/Element.zig index 23da8d03..4a12f390 100644 --- a/src/browser/webapi/Element.zig +++ b/src/browser/webapi/Element.zig @@ -49,129 +49,6 @@ pub const RelListLookup = std.AutoHashMapUnmanaged(*Element, *collections.DOMTok pub const ShadowRootLookup = std.AutoHashMapUnmanaged(*Element, *ShadowRoot); pub const AssignedSlotLookup = std.AutoHashMapUnmanaged(*Element, *Html.Slot); -/// Better to discriminate it since not directly a pointer int. -/// -/// See `calcAttrListenerKey` to obtain one. -const AttrListenerKey = u64; -/// Use `getAttrListenerKey` to create a key. -pub const AttrListenerLookup = std.AutoHashMapUnmanaged(AttrListenerKey, js.Function.Global); - -/// Enum of known event listeners; increasing the size of it (u7) -/// can cause `AttrListenerKey` to behave incorrectly. -pub const KnownListener = enum(u7) { - onabort, - onanimationcancel, - onanimationend, - onanimationiteration, - onanimationstart, - onauxclick, - onbeforeinput, - onbeforematch, - onbeforetoggle, - onblur, - oncancel, - oncanplay, - oncanplaythrough, - onchange, - onclick, - onclose, - oncommand, - oncontentvisibilityautostatechange, - oncontextlost, - oncontextmenu, - oncontextrestored, - oncopy, - oncuechange, - oncut, - ondblclick, - ondrag, - ondragend, - ondragenter, - ondragexit, - ondragleave, - ondragover, - ondragstart, - ondrop, - ondurationchange, - onemptied, - onended, - onerror, - onfocus, - onformdata, - onfullscreenchange, - onfullscreenerror, - ongotpointercapture, - oninput, - oninvalid, - onkeydown, - onkeypress, - onkeyup, - onload, - onloadeddata, - onloadedmetadata, - onloadstart, - onlostpointercapture, - onmousedown, - onmousemove, - onmouseout, - onmouseover, - onmouseup, - onpaste, - onpause, - onplay, - onplaying, - onpointercancel, - onpointerdown, - onpointerenter, - onpointerleave, - onpointermove, - onpointerout, - onpointerover, - onpointerrawupdate, - onpointerup, - onprogress, - onratechange, - onreset, - onresize, - onscroll, - onscrollend, - onsecuritypolicyviolation, - onseeked, - onseeking, - onselect, - onselectionchange, - onselectstart, - onslotchange, - onstalled, - onsubmit, - onsuspend, - ontimeupdate, - ontoggle, - ontransitioncancel, - ontransitionend, - ontransitionrun, - ontransitionstart, - onvolumechange, - onwaiting, - onwheel, -}; - -/// Calculates a lookup key (`AttrListenerKey`) to use with `AttrListenerLookup` for an element. -/// NEVER use generated key to retrieve a pointer back. Portability is not guaranteed. -pub fn calcAttrListenerKey(self: *Element, event_type: KnownListener) AttrListenerKey { - // We can use `Element` for the key too; `EventTarget` is strict about - // its size and alignment, though. - const target = self.asEventTarget(); - // Check if we have 3 bits available from alignment of 8. - lp.assert(@alignOf(@TypeOf(target)) == 8, "calcAttrListenerKey: incorrect alignment", .{ - .event_target_alignment = @alignOf(@TypeOf(target)), - }); - - const ptr = @intFromPtr(target) >> 3; - lp.assert(ptr < (1 << 57), "calcAttrListenerKey: pointer overflow", .{ .ptr = ptr }); - return ptr | (@as(u64, @intFromEnum(event_type)) << 57); -} - pub const Namespace = enum(u8) { html, svg, diff --git a/src/browser/webapi/element/Html.zig b/src/browser/webapi/element/Html.zig index 4f5669c7..cc20622a 100644 --- a/src/browser/webapi/element/Html.zig +++ b/src/browser/webapi/element/Html.zig @@ -21,6 +21,10 @@ const js = @import("../../js/js.zig"); const reflect = @import("../../reflect.zig"); const log = @import("../../../log.zig"); +const global_event_handlers = @import("../global_event_handlers.zig"); +const GlobalEventHandlersLookup = global_event_handlers.Lookup; +const GlobalEventHandler = global_event_handlers.Handler; + const Page = @import("../../Page.zig"); const Node = @import("../Node.zig"); const Element = @import("../Element.zig"); @@ -335,7 +339,7 @@ pub fn click(self: *HtmlElement, page: *Page) !void { fn getAttributeFunction( self: *HtmlElement, - listener_type: Element.KnownListener, + listener_type: GlobalEventHandler, page: *Page, ) !?js.Function.Global { const element = self.asElement(); diff --git a/src/browser/webapi/global_event_handlers.zig b/src/browser/webapi/global_event_handlers.zig new file mode 100644 index 00000000..251fa8c6 --- /dev/null +++ b/src/browser/webapi/global_event_handlers.zig @@ -0,0 +1,145 @@ +// Copyright (C) 2023-2026 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +const std = @import("std"); +const lp = @import("lightpanda"); + +const js = @import("../js/js.zig"); + +const EventTarget = @import("EventTarget.zig"); + +/// Better to discriminate it since not directly a pointer int. +/// +/// See `calculateKey` to obtain one. +const Key = u64; + +/// Use `calculateKey` to create a key. +pub const Lookup = std.AutoHashMapUnmanaged(Key, js.Function.Global); + +/// Enum of known event listeners; increasing the size of it (u7) +/// can cause `Key` to behave incorrectly. +pub const Handler = enum(u7) { + onabort, + onanimationcancel, + onanimationend, + onanimationiteration, + onanimationstart, + onauxclick, + onbeforeinput, + onbeforematch, + onbeforetoggle, + onblur, + oncancel, + oncanplay, + oncanplaythrough, + onchange, + onclick, + onclose, + oncommand, + oncontentvisibilityautostatechange, + oncontextlost, + oncontextmenu, + oncontextrestored, + oncopy, + oncuechange, + oncut, + ondblclick, + ondrag, + ondragend, + ondragenter, + ondragexit, + ondragleave, + ondragover, + ondragstart, + ondrop, + ondurationchange, + onemptied, + onended, + onerror, + onfocus, + onformdata, + onfullscreenchange, + onfullscreenerror, + ongotpointercapture, + oninput, + oninvalid, + onkeydown, + onkeypress, + onkeyup, + onload, + onloadeddata, + onloadedmetadata, + onloadstart, + onlostpointercapture, + onmousedown, + onmousemove, + onmouseout, + onmouseover, + onmouseup, + onpaste, + onpause, + onplay, + onplaying, + onpointercancel, + onpointerdown, + onpointerenter, + onpointerleave, + onpointermove, + onpointerout, + onpointerover, + onpointerrawupdate, + onpointerup, + onprogress, + onratechange, + onreset, + onresize, + onscroll, + onscrollend, + onsecuritypolicyviolation, + onseeked, + onseeking, + onselect, + onselectionchange, + onselectstart, + onslotchange, + onstalled, + onsubmit, + onsuspend, + ontimeupdate, + ontoggle, + ontransitioncancel, + ontransitionend, + ontransitionrun, + ontransitionstart, + onvolumechange, + onwaiting, + onwheel, +}; + +/// Calculates a lookup key to use with lookup for event target. +/// NEVER use generated key to retrieve a pointer back. Portability is not guaranteed. +pub fn calculateKey(event_target: *EventTarget, handler_type: Handler) Key { + // Check if we have 3 bits available from alignment of 8. + lp.assert(@alignOf(EventTarget) == 8, "calculateKey: incorrect alignment", .{ + .event_target_alignment = @alignOf(EventTarget), + }); + + const ptr = @intFromPtr(event_target) >> 3; + lp.assert(ptr < (1 << 57), "calculateKey: pointer overflow", .{ .ptr = ptr }); + return ptr | (@as(Key, @intFromEnum(handler_type)) << 57); +}