diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/node.c | 99 |
1 files changed, 74 insertions, 25 deletions
diff --git a/src/core/node.c b/src/core/node.c index 45db915..8800a4b 100644 --- a/src/core/node.c +++ b/src/core/node.c @@ -2316,11 +2316,43 @@ dom_exception _dom_node_remove_event_listener_ns(dom_event_target *et, namespace, type, listener, capture); } + +/** Helper for allocating/expanding array of event targets */ +static inline dom_exception _dom_event_targets_expand( + uint32_t *ntargets_allocated, + dom_event_target ***targets) +{ + dom_event_target **t = *targets; + uint32_t size = *ntargets_allocated; + + if (t == NULL) { + /* Create the event target list */ + size = 64; + t = calloc(sizeof(*t), size); + if (targets == NULL) { + return DOM_NO_MEM_ERR; + } + } else { + /* Extend events target list */ + dom_event_target **tmp = realloc(t, size * 2 * sizeof(*t)); + if (tmp == NULL) { + return DOM_NO_MEM_ERR; + } + memset(tmp + size, 0, size * sizeof(*tmp)); + t = tmp; + size *= 2; + } + + *ntargets_allocated = size; + *targets = t; + + return DOM_NO_ERR; +} + /** * Dispatch an event into the implementation's event model * * \param et The EventTarget object - * \param eti Internal EventTarget * \param evt The event object * \param success Indicates whether any of the listeners which handled the * event called Event.preventDefault(). If @@ -2369,31 +2401,46 @@ dom_exception _dom_node_dispatch_event(dom_event_target *et, *success = true; - /* Compose the event target list */ + /* Initialise array of targets for capture/bubbling phases */ + targets = NULL; + ntargets_allocated = 0; ntargets = 0; - ntargets_allocated = 64; - targets = calloc(sizeof(*targets), ntargets_allocated); - if (targets == NULL) { - /** \todo Report memory exhaustion? */ - return DOM_NO_ERR; - } - targets[ntargets++] = (dom_event_target *)dom_node_ref(et); - target = target->parent; - while (target != NULL) { + /* Add interested event listeners to array */ + for (; target != NULL; target = target->parent) { + struct listener_entry *le = target->eti.listeners; + bool target_has_listener = false; + + if (le == NULL) { + /* This event target isn't listening to anything */ + continue; + } + + /* Check whether the event target is listening for this + * event type */ + do { + if (dom_string_isequal(le->type, evt->type)) { + target_has_listener = true; + break; + } + le = (struct listener_entry *) le->list.next; + } while (le != target->eti.listeners); + + if (target_has_listener == false) { + continue; + } + + /* The event target is listening for this event type, + * so add it to the array. */ if (ntargets == ntargets_allocated) { - dom_event_target **newtargets = realloc( - targets, - ntargets_allocated * 2 * sizeof(*targets)); - if (newtargets == NULL) + err = _dom_event_targets_expand(&ntargets_allocated, + &targets); + if (err != DOM_NO_ERR) { + ret = err; goto cleanup; - memset(newtargets + ntargets_allocated, - 0, ntargets_allocated * sizeof(*newtargets)); - targets = newtargets; - ntargets_allocated *= 2; + } } targets[ntargets++] = (dom_event_target *)dom_node_ref(target); - target = target->parent; } /* Fill the target of the event */ @@ -2412,7 +2459,7 @@ dom_exception _dom_node_dispatch_event(dom_event_target *et, } /* The capture phase */ - for (targetnr = ntargets; targetnr > 1; --targetnr) { + for (targetnr = ntargets; targetnr > 0; --targetnr) { dom_node_internal *node = (dom_node_internal *) targets[targetnr - 1]; @@ -2443,7 +2490,7 @@ dom_exception _dom_node_dispatch_event(dom_event_target *et, /* Bubbling phase */ evt->phase = DOM_BUBBLING_PHASE; - for (targetnr = 1; targetnr < ntargets; ++targetnr) { + for (targetnr = 0; targetnr < ntargets; ++targetnr) { dom_node_internal *node = (dom_node_internal *) targets[targetnr]; err = _dom_event_target_dispatch(targets[targetnr], @@ -2465,8 +2512,8 @@ dom_exception _dom_node_dispatch_event(dom_event_target *et, dom_default_action_phase phase = DOM_DEFAULT_ACTION_END; if (evt->prevent_default == true) phase = DOM_DEFAULT_ACTION_PREVENTED; - dom_default_action_callback cb = dei->actions(evt->type, phase, - &pw); + dom_default_action_callback cb = dei->actions( + evt->type, phase, &pw); if (cb != NULL) { cb(evt, pw); } @@ -2480,7 +2527,9 @@ cleanup: while (ntargets--) { dom_node_unref(targets[ntargets]); } - free(targets); + if (targets != NULL) { + free(targets); + } if (dei != NULL && dei->actions != NULL) { dom_default_action_callback cb = dei->actions(evt->type, |