Add deinit for EventTarget (eventTargetRemoveAllEventListeners)

And unify the way allocator is used on eventTarget add/remove listener

Signed-off-by: Francis Bouvier <francis@lightpanda.io>
This commit is contained in:
Francis Bouvier
2024-01-29 08:01:35 +01:00
parent 9ba4c69a92
commit ce3c533680
3 changed files with 78 additions and 30 deletions

View File

@@ -50,14 +50,11 @@ pub const EventTarget = struct {
return;
}
// NOTE: this allocation will be removed either if removeEventListener
// or at EventTarget deinit
const cbk_ptr = try alloc.create(Callback);
cbk_ptr.* = cbk;
try parser.eventTargetAddEventListener(
self,
alloc,
eventType,
cbk_ptr,
cbk,
capture orelse false,
);
}
@@ -84,26 +81,21 @@ pub const EventTarget = struct {
}
// remove listener
const cbk_handler = try parser.eventTargetRemoveEventListener(
try parser.eventTargetRemoveEventListener(
self,
alloc,
eventType,
lst.?,
capture orelse false,
);
if (cbk_handler) |cbk_ptr| {
cbk_ptr.deinit(alloc);
alloc.destroy(cbk_ptr);
}
}
pub fn _dispatchEvent(self: *parser.EventTarget, event: *parser.Event) !bool {
return try parser.eventTargetDispatchEvent(self, event);
}
pub fn deinit(_: *parser.EventTarget, _: std.mem.Allocator) void {
// TODO:
// - deinit and destroy all cbk_handler
// - remove all listeners
pub fn deinit(self: *parser.EventTarget, alloc: std.mem.Allocator) void {
parser.eventTargetRemoveAllEventListeners(self, alloc) catch unreachable;
}
};

View File

@@ -444,8 +444,6 @@ pub fn eventPreventDefault(evt: *Event) !void {
}
// EventHandler
pub const EventHandler = fn (?*Event, ?*anyopaque) callconv(.C) void;
fn event_handler_cbk(data: *anyopaque) *Callback {
const ptr: *align(@alignOf(*Callback)) anyopaque = @alignCast(data);
return @as(*Callback, @ptrCast(ptr));
@@ -458,16 +456,16 @@ const event_handler = struct {
func.call(.{event}) catch unreachable;
// NOTE: we can not call func.deinit here
// b/c the handler can be called several times
// as the event goes through the ancestors
// TODO: check the event phase to call func.deinit and free func
// either on this dispatch event or in anoter one
}
}
}.handle;
// EventListener
pub const EventListener = c.dom_event_listener;
const EventListenerEntry = c.listener_entry;
pub fn eventListenerGetData(lst: *EventListener) ?*anyopaque {
fn eventListenerGetData(lst: *EventListener) ?*anyopaque {
return c.dom_event_listener_get_data(lst);
}
@@ -486,7 +484,6 @@ pub fn eventTargetHasListener(
) !?*EventListener {
const str = try strFromData(typ);
const EventListenerEntry = c.listener_entry;
var current: ?*EventListenerEntry = null;
var next: ?*EventListenerEntry = undefined;
var lst: ?*EventListener = undefined;
@@ -504,14 +501,16 @@ pub fn eventTargetHasListener(
try DOMErr(err);
if (lst) |listener| {
// the EventTarget has a listener for this event type,
// let's check if the callback is the same
// the EventTarget has a listener for this event type
// and capture property,
// let's check if the callback handler is the same
defer c.dom_event_listener_unref(listener);
const data = eventListenerGetData(listener);
if (data) |d| {
const cbk = event_handler_cbk(d);
if (cbk_id == cbk.id())
if (cbk_id == cbk.id()) {
return lst;
}
}
}
@@ -529,34 +528,91 @@ pub fn eventTargetHasListener(
pub fn eventTargetAddEventListener(
et: *EventTarget,
alloc: std.mem.Allocator,
typ: []const u8,
cbk_ptr: *Callback,
cbk: Callback,
capture: bool,
) !void {
const s = try strFromData(typ);
// this allocation will be removed either on
// eventTargetRemoveEventListener or eventTargetRemoveAllEventListeners
const cbk_ptr = try alloc.create(Callback);
cbk_ptr.* = cbk;
const ctx = @as(*anyopaque, @ptrCast(cbk_ptr));
var listener: ?*EventListener = undefined;
const errLst = c.dom_event_listener_create(event_handler, ctx, &listener);
try DOMErr(errLst);
defer c.dom_event_listener_unref(listener);
const s = try strFromData(typ);
const err = eventTargetVtable(et).add_event_listener.?(et, s, listener, capture);
try DOMErr(err);
}
pub fn eventTargetRemoveEventListener(
et: *EventTarget,
alloc: std.mem.Allocator,
typ: []const u8,
lst: *EventListener,
capture: bool,
) !?*Callback {
) !void {
const data = eventListenerGetData(lst);
var cbk_ptr: ?*Callback = null;
// free cbk allocation made on eventTargetAddEventListener
if (data) |d| {
cbk_ptr = event_handler_cbk(d);
const cbk_ptr = event_handler_cbk(d);
cbk_ptr.deinit(alloc);
alloc.destroy(cbk_ptr);
}
const s = try strFromData(typ);
const err = eventTargetVtable(et).remove_event_listener.?(et, s, lst, capture);
try DOMErr(err);
return cbk_ptr;
}
pub fn eventTargetRemoveAllEventListeners(
et: *EventTarget,
alloc: std.mem.Allocator,
) !void {
var next: ?*EventListenerEntry = undefined;
var lst: ?*EventListener = undefined;
// iterate over the EventTarget's listeners
while (true) {
const errIter = eventTargetVtable(et).iter_event_listener.?(
et,
null,
false,
null,
&next,
&lst,
);
try DOMErr(errIter);
if (lst) |listener| {
defer c.dom_event_listener_unref(listener);
const data = eventListenerGetData(listener);
if (data) |d| {
// free cbk allocation made on eventTargetAddEventListener
const cbk = event_handler_cbk(d);
cbk.deinit(alloc);
alloc.destroy(cbk);
}
const err = eventTargetVtable(et).remove_event_listener.?(
et,
null,
lst,
false,
);
try DOMErr(err);
}
if (next == null) {
// no more listeners, end of the iteration
break;
}
// next iteration
}
}
pub fn eventTargetDispatchEvent(et: *EventTarget, event: *Event) !bool {