Skip to content

Commit ce3c533

Browse files
Add deinit for EventTarget (eventTargetRemoveAllEventListeners)
And unify the way allocator is used on eventTarget add/remove listener Signed-off-by: Francis Bouvier <[email protected]>
1 parent 9ba4c69 commit ce3c533

File tree

3 files changed

+78
-30
lines changed

3 files changed

+78
-30
lines changed

src/dom/event_target.zig

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,11 @@ pub const EventTarget = struct {
5050
return;
5151
}
5252

53-
// NOTE: this allocation will be removed either if removeEventListener
54-
// or at EventTarget deinit
55-
const cbk_ptr = try alloc.create(Callback);
56-
cbk_ptr.* = cbk;
5753
try parser.eventTargetAddEventListener(
5854
self,
55+
alloc,
5956
eventType,
60-
cbk_ptr,
57+
cbk,
6158
capture orelse false,
6259
);
6360
}
@@ -84,26 +81,21 @@ pub const EventTarget = struct {
8481
}
8582

8683
// remove listener
87-
const cbk_handler = try parser.eventTargetRemoveEventListener(
84+
try parser.eventTargetRemoveEventListener(
8885
self,
86+
alloc,
8987
eventType,
9088
lst.?,
9189
capture orelse false,
9290
);
93-
if (cbk_handler) |cbk_ptr| {
94-
cbk_ptr.deinit(alloc);
95-
alloc.destroy(cbk_ptr);
96-
}
9791
}
9892

9993
pub fn _dispatchEvent(self: *parser.EventTarget, event: *parser.Event) !bool {
10094
return try parser.eventTargetDispatchEvent(self, event);
10195
}
10296

103-
pub fn deinit(_: *parser.EventTarget, _: std.mem.Allocator) void {
104-
// TODO:
105-
// - deinit and destroy all cbk_handler
106-
// - remove all listeners
97+
pub fn deinit(self: *parser.EventTarget, alloc: std.mem.Allocator) void {
98+
parser.eventTargetRemoveAllEventListeners(self, alloc) catch unreachable;
10799
}
108100
};
109101

src/netsurf.zig

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,6 @@ pub fn eventPreventDefault(evt: *Event) !void {
444444
}
445445

446446
// EventHandler
447-
pub const EventHandler = fn (?*Event, ?*anyopaque) callconv(.C) void;
448-
449447
fn event_handler_cbk(data: *anyopaque) *Callback {
450448
const ptr: *align(@alignOf(*Callback)) anyopaque = @alignCast(data);
451449
return @as(*Callback, @ptrCast(ptr));
@@ -458,16 +456,16 @@ const event_handler = struct {
458456
func.call(.{event}) catch unreachable;
459457
// NOTE: we can not call func.deinit here
460458
// b/c the handler can be called several times
461-
// as the event goes through the ancestors
462-
// TODO: check the event phase to call func.deinit and free func
459+
// either on this dispatch event or in anoter one
463460
}
464461
}
465462
}.handle;
466463

467464
// EventListener
468465
pub const EventListener = c.dom_event_listener;
466+
const EventListenerEntry = c.listener_entry;
469467

470-
pub fn eventListenerGetData(lst: *EventListener) ?*anyopaque {
468+
fn eventListenerGetData(lst: *EventListener) ?*anyopaque {
471469
return c.dom_event_listener_get_data(lst);
472470
}
473471

@@ -486,7 +484,6 @@ pub fn eventTargetHasListener(
486484
) !?*EventListener {
487485
const str = try strFromData(typ);
488486

489-
const EventListenerEntry = c.listener_entry;
490487
var current: ?*EventListenerEntry = null;
491488
var next: ?*EventListenerEntry = undefined;
492489
var lst: ?*EventListener = undefined;
@@ -504,14 +501,16 @@ pub fn eventTargetHasListener(
504501
try DOMErr(err);
505502

506503
if (lst) |listener| {
507-
// the EventTarget has a listener for this event type,
508-
// let's check if the callback is the same
504+
// the EventTarget has a listener for this event type
505+
// and capture property,
506+
// let's check if the callback handler is the same
509507
defer c.dom_event_listener_unref(listener);
510508
const data = eventListenerGetData(listener);
511509
if (data) |d| {
512510
const cbk = event_handler_cbk(d);
513-
if (cbk_id == cbk.id())
511+
if (cbk_id == cbk.id()) {
514512
return lst;
513+
}
515514
}
516515
}
517516

@@ -529,34 +528,91 @@ pub fn eventTargetHasListener(
529528

530529
pub fn eventTargetAddEventListener(
531530
et: *EventTarget,
531+
alloc: std.mem.Allocator,
532532
typ: []const u8,
533-
cbk_ptr: *Callback,
533+
cbk: Callback,
534534
capture: bool,
535535
) !void {
536-
const s = try strFromData(typ);
536+
// this allocation will be removed either on
537+
// eventTargetRemoveEventListener or eventTargetRemoveAllEventListeners
538+
const cbk_ptr = try alloc.create(Callback);
539+
cbk_ptr.* = cbk;
540+
537541
const ctx = @as(*anyopaque, @ptrCast(cbk_ptr));
538542
var listener: ?*EventListener = undefined;
539543
const errLst = c.dom_event_listener_create(event_handler, ctx, &listener);
540544
try DOMErr(errLst);
545+
defer c.dom_event_listener_unref(listener);
546+
547+
const s = try strFromData(typ);
541548
const err = eventTargetVtable(et).add_event_listener.?(et, s, listener, capture);
542549
try DOMErr(err);
543550
}
544551

545552
pub fn eventTargetRemoveEventListener(
546553
et: *EventTarget,
554+
alloc: std.mem.Allocator,
547555
typ: []const u8,
548556
lst: *EventListener,
549557
capture: bool,
550-
) !?*Callback {
558+
) !void {
551559
const data = eventListenerGetData(lst);
552-
var cbk_ptr: ?*Callback = null;
560+
// free cbk allocation made on eventTargetAddEventListener
553561
if (data) |d| {
554-
cbk_ptr = event_handler_cbk(d);
562+
const cbk_ptr = event_handler_cbk(d);
563+
cbk_ptr.deinit(alloc);
564+
alloc.destroy(cbk_ptr);
555565
}
566+
556567
const s = try strFromData(typ);
557568
const err = eventTargetVtable(et).remove_event_listener.?(et, s, lst, capture);
558569
try DOMErr(err);
559-
return cbk_ptr;
570+
}
571+
572+
pub fn eventTargetRemoveAllEventListeners(
573+
et: *EventTarget,
574+
alloc: std.mem.Allocator,
575+
) !void {
576+
var next: ?*EventListenerEntry = undefined;
577+
var lst: ?*EventListener = undefined;
578+
579+
// iterate over the EventTarget's listeners
580+
while (true) {
581+
const errIter = eventTargetVtable(et).iter_event_listener.?(
582+
et,
583+
null,
584+
false,
585+
null,
586+
&next,
587+
&lst,
588+
);
589+
try DOMErr(errIter);
590+
591+
if (lst) |listener| {
592+
defer c.dom_event_listener_unref(listener);
593+
const data = eventListenerGetData(listener);
594+
if (data) |d| {
595+
// free cbk allocation made on eventTargetAddEventListener
596+
const cbk = event_handler_cbk(d);
597+
cbk.deinit(alloc);
598+
alloc.destroy(cbk);
599+
}
600+
const err = eventTargetVtable(et).remove_event_listener.?(
601+
et,
602+
null,
603+
lst,
604+
false,
605+
);
606+
try DOMErr(err);
607+
}
608+
609+
if (next == null) {
610+
// no more listeners, end of the iteration
611+
break;
612+
}
613+
614+
// next iteration
615+
}
560616
}
561617

562618
pub fn eventTargetDispatchEvent(et: *EventTarget, event: *Event) !bool {

vendor/jsruntime-lib

0 commit comments

Comments
 (0)