mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 04:34:44 +00:00
Add a hasDirectListeners to EventManager
Allows checking if a direct listener exists, if it doesn't, event creation can be skipped. I looked at a couple sites, the benefits of this is small. Most sites don't seem to trigger that many direct dispatches and when they do, they seem to have a listener 50-75% of the time.
This commit is contained in:
@@ -365,6 +365,29 @@ fn getFunction(handler: anytype, local: *const js.Local) ?js.Function {
|
||||
};
|
||||
}
|
||||
|
||||
/// Check if there are any listeners for a direct dispatch (non-DOM target).
|
||||
/// Use this to avoid creating an event when there are no listeners.
|
||||
pub fn hasDirectListeners(self: *EventManager, target: *EventTarget, typ: []const u8, handler: anytype) bool {
|
||||
if (hasHandler(handler)) {
|
||||
return true;
|
||||
}
|
||||
return self.lookup.get(.{
|
||||
.event_target = @intFromPtr(target),
|
||||
.type_string = .wrap(typ),
|
||||
}) != null;
|
||||
}
|
||||
|
||||
fn hasHandler(handler: anytype) bool {
|
||||
const ti = @typeInfo(@TypeOf(handler));
|
||||
if (ti == .null) {
|
||||
return false;
|
||||
}
|
||||
if (ti == .optional) {
|
||||
return handler != null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn dispatchNode(self: *EventManager, target: *Node, event: *Event, comptime opts: DispatchOpts) !void {
|
||||
const ShadowRoot = @import("webapi/ShadowRoot.zig");
|
||||
|
||||
|
||||
@@ -791,24 +791,19 @@ fn _documentIsComplete(self: *Page) !void {
|
||||
try self.dispatchLoad();
|
||||
|
||||
// Dispatch window.load event.
|
||||
const event = try Event.initTrusted(comptime .wrap("load"), .{}, self);
|
||||
// This event is weird, it's dispatched directly on the window, but
|
||||
// with the document as the target.
|
||||
event._target = self.document.asEventTarget();
|
||||
try self._event_manager.dispatchDirect(
|
||||
self.window.asEventTarget(),
|
||||
event,
|
||||
self.window._on_load,
|
||||
.{ .inject_target = false, .context = "page load" },
|
||||
);
|
||||
const window_target = self.window.asEventTarget();
|
||||
if (self._event_manager.hasDirectListeners(window_target, "load", self.window._on_load)) {
|
||||
const event = try Event.initTrusted(comptime .wrap("load"), .{}, self);
|
||||
// This event is weird, it's dispatched directly on the window, but
|
||||
// with the document as the target.
|
||||
event._target = self.document.asEventTarget();
|
||||
try self._event_manager.dispatchDirect(window_target, event, self.window._on_load, .{ .inject_target = false, .context = "page load" });
|
||||
}
|
||||
|
||||
const pageshow_event = (try PageTransitionEvent.initTrusted(comptime .wrap("pageshow"), .{}, self)).asEvent();
|
||||
try self._event_manager.dispatchDirect(
|
||||
self.window.asEventTarget(),
|
||||
pageshow_event,
|
||||
self.window._on_pageshow,
|
||||
.{ .context = "page show" },
|
||||
);
|
||||
if (self._event_manager.hasDirectListeners(window_target, "pageshow", self.window._on_pageshow)) {
|
||||
const pageshow_event = (try PageTransitionEvent.initTrusted(comptime .wrap("pageshow"), .{}, self)).asEvent();
|
||||
try self._event_manager.dispatchDirect(window_target, pageshow_event, self.window._on_pageshow, .{ .context = "page show" });
|
||||
}
|
||||
|
||||
self.notifyParentLoadComplete();
|
||||
}
|
||||
|
||||
@@ -76,13 +76,11 @@ pub fn abort(self: *AbortSignal, reason_: ?Reason, page: *Page) !void {
|
||||
}
|
||||
|
||||
// Dispatch abort event
|
||||
const event = try Event.initTrusted(comptime .wrap("abort"), .{}, page);
|
||||
try page._event_manager.dispatchDirect(
|
||||
self.asEventTarget(),
|
||||
event,
|
||||
self._on_abort,
|
||||
.{ .context = "abort signal" },
|
||||
);
|
||||
const target = self.asEventTarget();
|
||||
if (page._event_manager.hasDirectListeners(target, "abort", self._on_abort)) {
|
||||
const event = try Event.initTrusted(comptime .wrap("abort"), .{}, page);
|
||||
try page._event_manager.dispatchDirect(target, event, self._on_abort, .{ .context = "abort signal" });
|
||||
}
|
||||
}
|
||||
|
||||
// Static method to create an already-aborted signal
|
||||
|
||||
@@ -138,6 +138,7 @@ pub fn format(self: *EventTarget, writer: *std.Io.Writer) !void {
|
||||
.screen => writer.writeAll("<Screen>"),
|
||||
.screen_orientation => writer.writeAll("<ScreenOrientation>"),
|
||||
.visual_viewport => writer.writeAll("<VisualViewport>"),
|
||||
.file_reader => writer.writeAll("<FileReader>"),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -79,13 +79,11 @@ fn goInner(delta: i32, page: *Page) !void {
|
||||
|
||||
if (entry._url) |url| {
|
||||
if (try page.isSameOrigin(url)) {
|
||||
const event = (try PopStateEvent.initTrusted(comptime .wrap("popstate"), .{ .state = entry._state.value }, page)).asEvent();
|
||||
try page._event_manager.dispatchDirect(
|
||||
page.window.asEventTarget(),
|
||||
event,
|
||||
page.window._on_popstate,
|
||||
.{ .context = "Pop State" },
|
||||
);
|
||||
const target = page.window.asEventTarget();
|
||||
if (page._event_manager.hasDirectListeners(target, "popstate", page.window._on_popstate)) {
|
||||
const event = (try PopStateEvent.initTrusted(comptime .wrap("popstate"), .{ .state = entry._state.value }, page)).asEvent();
|
||||
try page._event_manager.dispatchDirect(target, event, page.window._on_popstate, .{ .context = "Pop State" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,23 +122,21 @@ const PostMessageCallback = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
const event = (MessageEvent.initTrusted(comptime .wrap("message"), .{
|
||||
.data = self.message,
|
||||
.origin = "",
|
||||
.source = null,
|
||||
}, page) catch |err| {
|
||||
log.err(.dom, "MessagePort.postMessage", .{ .err = err });
|
||||
return null;
|
||||
}).asEvent();
|
||||
const target = self.port.asEventTarget();
|
||||
if (page._event_manager.hasDirectListeners(target, "message", self.port._on_message)) {
|
||||
const event = (MessageEvent.initTrusted(comptime .wrap("message"), .{
|
||||
.data = self.message,
|
||||
.origin = "",
|
||||
.source = null,
|
||||
}, page) catch |err| {
|
||||
log.err(.dom, "MessagePort.postMessage", .{ .err = err });
|
||||
return null;
|
||||
}).asEvent();
|
||||
|
||||
page._event_manager.dispatchDirect(
|
||||
self.port.asEventTarget(),
|
||||
event,
|
||||
self.port._on_message,
|
||||
.{ .context = "MessagePort message" },
|
||||
) catch |err| {
|
||||
log.err(.dom, "MessagePort.postMessage", .{ .err = err });
|
||||
};
|
||||
page._event_manager.dispatchDirect(target, event, self.port._on_message, .{ .context = "MessagePort message" }) catch |err| {
|
||||
log.err(.dom, "MessagePort.postMessage", .{ .err = err });
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -551,17 +551,14 @@ pub fn unhandledPromiseRejection(self: *Window, rejection: js.PromiseRejection,
|
||||
});
|
||||
}
|
||||
|
||||
const event = (try @import("event/PromiseRejectionEvent.zig").init("unhandledrejection", .{
|
||||
.reason = if (rejection.reason()) |r| try r.temp() else null,
|
||||
.promise = try rejection.promise().temp(),
|
||||
}, page)).asEvent();
|
||||
|
||||
try page._event_manager.dispatchDirect(
|
||||
self.asEventTarget(),
|
||||
event,
|
||||
self._on_unhandled_rejection,
|
||||
.{ .inject_target = true, .context = "window.unhandledrejection" },
|
||||
);
|
||||
const target = self.asEventTarget();
|
||||
if (page._event_manager.hasDirectListeners(target, "unhandledrejection", self._on_unhandled_rejection)) {
|
||||
const event = (try @import("event/PromiseRejectionEvent.zig").init("unhandledrejection", .{
|
||||
.reason = if (rejection.reason()) |r| try r.temp() else null,
|
||||
.promise = try rejection.promise().temp(),
|
||||
}, page)).asEvent();
|
||||
try page._event_manager.dispatchDirect(target, event, self._on_unhandled_rejection, .{ .context = "window.unhandledrejection" });
|
||||
}
|
||||
}
|
||||
|
||||
const ScheduleOpts = struct {
|
||||
|
||||
@@ -508,13 +508,11 @@ fn stateChanged(self: *XMLHttpRequest, state: ReadyState, page: *Page) !void {
|
||||
|
||||
self._ready_state = state;
|
||||
|
||||
const event = try Event.initTrusted(.wrap("readystatechange"), .{}, page);
|
||||
try page._event_manager.dispatchDirect(
|
||||
self.asEventTarget(),
|
||||
event,
|
||||
self._on_ready_state_change,
|
||||
.{ .context = "XHR state change" },
|
||||
);
|
||||
const target = self.asEventTarget();
|
||||
if (page._event_manager.hasDirectListeners(target, "readystatechange", self._on_ready_state_change)) {
|
||||
const event = try Event.initTrusted(.wrap("readystatechange"), .{}, page);
|
||||
try page._event_manager.dispatchDirect(target, event, self._on_ready_state_change, .{ .context = "XHR state change" });
|
||||
}
|
||||
}
|
||||
|
||||
fn parseMethod(method: []const u8) !Http.Method {
|
||||
|
||||
Reference in New Issue
Block a user