On Wed, 2009-08-12 at 15:34 +0100, John-Mark Bell wrote:
> Index: include/dom/events/event.h
> ===================================================================
> --- /dev/null 2009-04-16 19:17:07.000000000 +0100
> +++ include/dom/events/event.h 2009-08-12 15:12:46.000000000 +0100
> @@ -0,0 +1,93 @@
> +/*
> + * This file is part of libdom.
> + * Licensed under the MIT License,
> + * http://www.opensource.org/licenses/mit-license.php
> + * Copyright 2009 Bo Yang <[email protected]>
> + */
> +
> +#ifndef dom_events_event_h_
> +#define dom_events_event_h_
> +
> +#include <stdbool.h>
> +#include <dom/core/exceptions.h>
> +#include <dom/events/event_target.h>
> +
> +struct dom_string;
> +
> +typedef enum {
> + DOM_CAPTURING_PHASE = 1,
> + DOM_AT_TARGET = 2,
> + DOM_BUBBLING_PHASE = 3
> +} dom_event_flow_phase;
Whitespace: use spaces here, not tabs.
> Index: src/events/mouse_event.h
> ===================================================================
> --- /dev/null 2009-04-16 19:17:07.000000000 +0100
> +++ src/events/mouse_event.h 2009-08-12 15:12:50.000000000 +0100
> +/**
> + * The mouse event
> + */
> +struct dom_mouse_event {
> + struct dom_ui_event base; /**< Base class */
> +
> + long sx; /**< ScreenX */
> + long sy; /**< ScreenY */
> + long cx; /**< ClientX */
> + long cy; /**< ClientY */
> +
> + bool ctrl; /**< Whether the Control key is down */
> + bool meta; /**< Whether the Meta key is down */
> + bool shift; /**< Whether the shift key is down */
> + bool alt; /**< Whether the Alt key is down */
> +
> + bool alt_graph; /**< Whether AltGraph key is down */
> + bool caps_lock; /**< Whether CapsLock key is down */
> + bool num_lock; /**< Whether NumLock key is down */
> + bool scroll; /**< Whether Scroll key is down */
The above would be better as:
enum {
MOUSE_MOD_CTRL = (1<<0),
MOUSE_MOD_META = (1<<1),
MOUSE_MOD_SHIFT = (1<<2),
/* etc */
};
uint32_t modifier_state;
> Index: src/events/mutation_name_event.c
> ===================================================================
> --- /dev/null 2009-04-16 19:17:07.000000000 +0100
> +++ src/events/mutation_name_event.c 2009-08-12 15:12:50.000000000 +0100
> @@ -0,0 +1,157 @@
> +/*
> + * This file is part of libdom.
> + * Licensed under the MIT License,
> + * http://www.opensource.org/licenses/mit-license.php
> + * Copyright 2009 Bo Yang <[email protected]>
> + */
> +
> +#include "events/mutation_name_event.h"
> +#include "core/document.h"
> +
> +#include "utils/utils.h"
> +
> +static struct dom_event_private_vtable _event_vtable = {
> + __dom_mutation_name_event_destory
> +};
"destroy".
> Index: src/events/mutation_event.c
> ===================================================================
> --- /dev/null 2009-04-16 19:17:07.000000000 +0100
> +++ src/events/mutation_event.c 2009-08-12 15:12:50.000000000 +0100
> @@ -0,0 +1,224 @@
> +/*
> + * This file is part of libdom.
> + * Licensed under the MIT License,
> + * http://www.opensource.org/licenses/mit-license.php
> + * Copyright 2009 Bo Yang <[email protected]>
> + */
> +
> +#include "events/mutation_event.h"
> +#include "core/document.h"
> +
> +static struct dom_event_private_vtable _event_vtable = {
> + __dom_mutation_event_destory
> +};
Ditto. I'll not highlight any more of these.
Note also that identifiers beginning __ are reserved in C, so this needs
to be changed.
> Index: src/events/keyboard_event.c
> ===================================================================
> --- /dev/null 2009-04-16 19:17:07.000000000 +0100
> +++ src/events/keyboard_event.c 2009-08-12 15:12:50.000000000 +0100
> +/**
> + * Query the state of a modifier using a key identifier
> + *
> + * \param evt The event object
> + * \param ml The modifier identifier, such as "Alt", "Control", "Meta",
> + * "AltGraph", "CapsLock", "NumLock", "Scroll", "Shift".
> + * \param state Whether the modifier key is pressed
> + * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
> + *
> + * @note: If an application wishes to distinguish between right and left
> + * modifiers, this information could be deduced using keyboard events and
> + * KeyboardEvent.keyLocation.
> + */
> +dom_exception _dom_keyboard_event_get_modifier_state(dom_keyboard_event *evt,
> + struct dom_string *m, bool *state)
> +{
> + if (m == NULL) {
> + *state = false;
> + return DOM_NO_ERR;
> + }
> +
> + const char *data = _dom_string_data(m);
> + size_t len = _dom_string_length(m);
> +
> + if (strncmp(data, "AltGraph", len) == 0) {
> + *state = evt->alt_graph;
> + }
The point of interning strings is that you don't need to call strncmp to
compare them.
The subsequent comparisons should be else if, so that early termination
occurs.
> +/**
> + * Parse the modifier list string to corresponding bool variable state
> + *
> + * \param modifier_list The modifier list string
> + * \param alt_graph Whether AltGraph is in the modifier list
> + * \param alt Whether Alt is in the modifier list
> + * \param caps_lock Whether CapsLock is in the modifier list
> + * \param ctrl Whether Control is in the modifier list
> + * \param meta Whether Meta is in the modifier list
> + * \param num_lock Whether NumLock is in the modifier list
> + * \param scroll Whether Scroll is in the modifier list
> + * \param shift Whether Shift is in the modifier list
> + * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
> + */
> +dom_exception _dom_parse_modifier_list(struct dom_string *modifier_list,
> + bool *alt_graph, bool *alt, bool *caps_lock, bool *ctrl,
> + bool *meta, bool *num_lock, bool *scroll, bool *shift)
> +{
> + *alt_graph = false;
> + *alt = false;
> + *caps_lock = false;
> + *ctrl = false;
> + *meta = false;
> + *num_lock = false;
> + *scroll = false;
> + *shift = false;
> +
> + if (modifier_list == NULL)
> + return DOM_NO_ERR;
> +
> + char *data = _dom_string_data(modifier_list);
> + char *m = NULL;
> +
> + m = strtok(data, " ");
I'd rather not see strtok used, ever. It's simple enough to do this kind
of tokenisation manually.
> + while (m != NULL) {
> + size_t len = strlen(m);
This is redundant if you do it manually; just keep a pointer to the
start of the current token and subtract it from the current pointer to
retrieve the token length.
> + if (strncmp(m, "AltGraph", len) == 0) {
> + *alt_graph = true;
> + }
It's more efficient to compare the lengths first.
> + if (strncmp(m, "Alt", len) == 0) {
> + *alt = true;
> + }
These should be else if.
> Index: src/events/keyboard_event.h
> ===================================================================
> --- /dev/null 2009-04-16 19:17:07.000000000 +0100
> +++ src/events/keyboard_event.h 2009-08-12 15:12:50.000000000 +0100
> +/**
> + * The keyboard event
> + */
> +struct dom_keyboard_event {
> + struct dom_ui_event base; /**< The base class */
> +
> + struct dom_string *key_ident; /**< The identifier of the key in this
> + * event, please refer:
> + *
> http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set
> + * for detail
> + */
> +
> + dom_key_location key_loc; /**< Indicate the location of the key on
> + * the keyboard
> + */
> +
> + bool ctrl; /**< Whether the Control key is down */
> + bool meta; /**< Whether the Meta key is down */
> + bool shift; /**< Whether the Shift key is down */
> + bool alt; /**< Whether the Alt key is down */
> +
> + bool alt_graph; /**< Whether AltGraph key is down */
> + bool caps_lock; /**< Whether CapsLock key is down */
> + bool num_lock; /**< Whether NumLock key is down */
> + bool scroll; /**< Whether Scroll key is down */
These, too, can be a bitfield.
> Index: src/events/event.c
> ===================================================================
> --- /dev/null 2009-04-16 19:17:07.000000000 +0100
> +++ src/events/event.c 2009-08-12 15:12:50.000000000 +0100
> +/**
> + * Claim a reference on this event object
> + *
> + * \param evt The Event object
> + */
> +void _dom_event_ref(dom_event *evt)
> +{
> + evt->refcnt ++;
> +}
Lose the space.
> +/**
> + * Release a reference on this event object
> + *
> + * \param evt The Event object
> + */
> +void _dom_event_unref(dom_event *evt)
> +{
> + if (evt->refcnt > 0) {
> + evt->refcnt --;
> + return ;
> + }
> + dom_event_destroy(evt);
> +}
This is wrong. The object should be destroyed when the reference count
reaches zero, not -1.
> Index: src/events/event_listener.c
> ===================================================================
> --- /dev/null 2009-04-16 19:17:07.000000000 +0100
> +++ src/events/event_listener.c 2009-08-12 15:12:50.000000000 +0100
> +/**
> + * Claim a new reference on the listener object
> + *
> + * \param listener The EventListener object
> + */
> +void dom_event_listener_ref(dom_event_listener *listener)
> +{
> + listener->refcnt ++;
> +}
Whitespace.
> +/**
> + * Release a reference on the listener object
> + *
> + * \param listener The EventListener object
> + */
> +void dom_event_listener_unref(dom_event_listener *listener)
> +{
> + if (listener->refcnt > 0) {
> + listener->refcnt --;
Ditto.
> + return;
> + }
> +
> + _dom_document_alloc(listener->doc, listener,
> + sizeof(dom_event_listener));
> +}
Should destroy when refcnt reaches zero.
> Index: src/events/event_target.c
> ===================================================================
> --- /dev/null 2009-04-16 19:17:07.000000000 +0100
> +++ src/events/event_target.c 2009-08-12 15:12:50.000000000 +0100
> +
> +/* Hash key/value functions */
> +static void *_key(void *key, void *key_pw, dom_alloc alloc, void *pw,
> + bool clone);
> +static void *_value(void *value, void *value_pw, dom_alloc alloc,
> + void *pw, bool clone);
> +static unsigned int _dom_element_hash_lwcstring(void *key);
This needs renaming. More importantly, can it be put somewhere central
-- in src/utils, perhaps? I'd like to avoid duplicating this kind of
functionality.
> +/**
> + * Add an EventListener to the EventTarget
> + *
> + * \param et The EventTarget object
> + * \param type The event type which this event listener listens for
> + * \param listener The event listener object
> + * \param capture Whether add this listener in the capturing phase
> + * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
> + */
> +dom_exception _dom_event_target_add_event_listener(dom_event_target *et,
> + struct dom_string *type, struct dom_event_listener *listener,
> + bool capture)
> +{
> + struct listener_entry *le = NULL;
> + struct dom_document *doc = dom_node_get_owner(et);
> + if (doc == NULL) {
> + /* TODO: In the progress of parsing, many Nodes in the DTD
> + * has no document at all, do nothing for this kind of node */
> + return DOM_NO_ERR;
> + }
This seems odd. Can you explain why it's needed in more detail?
> +/**
> + * Dispatch a DOMNodeInserted/DOMNodeRemoved event
> + *
> + * \param doc The document object
> + * \param et The EventTarget object
> + * \param type "DOMNodeInserted" or "DOMNodeRemoved"
> + * \param related The parent of the removed/inserted node
> + * \param success Whether this event's default action get called
> + * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
> + */
> +dom_exception _dom_dispatch_node_change_event(struct dom_document *doc,
> + dom_event_target *et, dom_event_target *related,
> + dom_mutation_type change, bool *success)
> +{
> + struct dom_mutation_event *evt;
> + dom_exception err;
> +
> + err = _dom_mutation_event_create(doc, &evt);
> + if (err != DOM_NO_ERR)
> + return err;
> +
> + lwc_string *type = NULL;
> + if (change == DOM_MUTATION_ADDITION) {
> + err = _dom_document_create_lwcstring(doc,
> + (const uint8_t *) "DOMNodeInserted",
> + SLEN("DOMNodeInserted"), &type);
> + if (err != DOM_NO_ERR)
> + goto cleanup;
> + } else if (change == DOM_MUTATION_REMOVAL) {
> + err = _dom_document_create_lwcstring(doc,
> + (const uint8_t *) "DOMNodeRemoval",
> + SLEN("DOMNodeRemoved"), &type);
> + if (err != DOM_NO_ERR)
> + goto cleanup;
> + } else {
> + assert("Should never be here" == NULL);
> + }
> +
> + dom_string *t = NULL;
> + err = _dom_document_create_string_from_lwcstring(doc, type, &t);
> + _dom_document_unref_lwcstring(doc, type);
> + if (err != DOM_NO_ERR)
> + goto cleanup;
> +
> + /* Initiliase the event with corresponding parameters */
> + err = dom_mutation_event_init(evt, t, true, false, related, NULL, NULL,
> + NULL, change);
> + dom_string_unref(t);
> + if (err != DOM_NO_ERR) {
> + goto cleanup;
> + }
> +
> + err = dom_event_target_dispatch_event(et, evt, success);
> + if (err != DOM_NO_ERR)
> + goto cleanup;
> +
> + /* Finalise the evt, and reuse it */
> + _dom_mutation_event_finalise(doc, evt);
> + /* Dispatch the DOMNodeInsertedIntoDocument/DOMNodeRemovedFromDocument
> + * event */
> + if (change == DOM_MUTATION_ADDITION) {
> + err = _dom_document_create_lwcstring(doc,
> + (const uint8_t *)
> + "DOMNodeInsertedIntoDocument",
> + SLEN("DOMNodeInsertedIntoDocument"), &type);
> + if (err != DOM_NO_ERR)
> + goto cleanup;
> + } else if (change == DOM_MUTATION_REMOVAL) {
> + err = _dom_document_create_lwcstring(doc,
> + (const uint8_t *) "DOMNodeRemovalFromDocument",
> + SLEN("DOMNodeRemovedFromDocument"), &type);
> + if (err != DOM_NO_ERR)
> + goto cleanup;
> + } else {
> + assert("Should never be here" == NULL);
> + }
> +
> + err = _dom_document_create_string_from_lwcstring(doc, type, &t);
> + _dom_document_unref_lwcstring(doc, type);
> + if (err != DOM_NO_ERR)
> + goto cleanup;
> +
> + dom_event_target *target = et;
> + while (target != NULL) {
> + err = dom_mutation_event_init(evt, t, true, false, NULL,
> + NULL, NULL, NULL, change);
> + dom_string_unref(t);
You're unreffing 't' for every iteration of this loop. That seems wrong.
> +/**
> + * Query the state of a modifier using a key identifier
> + *
> + * \param evt The event object
> + * \param ml The modifier identifier, such as "Alt", "Control", "Meta",
> + * "AltGraph", "CapsLock", "NumLock", "Scroll", "Shift".
> + * \param state Whether the modifier key is pressed
> + * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
> + *
> + * @note: If an application wishes to distinguish between right and left
> + * modifiers, this information could be deduced using keyboard events and
> + * KeyboardEvent.keyLocation.
> + */
> +dom_exception _dom_mouse_event_get_modifier_state(dom_mouse_event *evt,
> + struct dom_string *m, bool *state)
> +{
> + if (m == NULL) {
> + *state = false;
> + return DOM_NO_ERR;
> + }
> +
> + const char *data = _dom_string_data(m);
> + size_t len = _dom_string_length(m);
> +
> + if (strncmp(data, "AltGraph", len) == 0) {
> + *state = evt->alt_graph;
> + }
Same commentary applies here as before.
> Index: src/utils/namespace.c
> ===================================================================
> --- src/utils/namespace.c (revision 9213)
> +++ src/utils/namespace.c (working copy)
> @@ -151,13 +151,6 @@
>
> if (colon == (uint32_t) -1) {
> /* No prefix */
> - /* If namespace URI is for xmlns, ensure qname == "xmlns" */
> - if (namespace != NULL &&
> - dom_string_cmp(namespace,
> - dom_namespaces[DOM_NAMESPACE_XMLNS]) == 0 &&
> - dom_string_cmp(qname, xmlns) != 0) {
> - return DOM_NAMESPACE_ERR;
> - }
> /* If qname == "xmlns", ensure namespace URI is for xmlns */
> if (namespace != NULL &&
> dom_string_cmp(qname, xmlns) == 0 &&
It turns out that I got the merge wrong here. Ignore this change.
> Index: src/core/string.c
> ===================================================================
> --- src/core/string.c (revision 9213)
> +++ src/core/string.c (working copy)
> @@ -56,7 +56,8 @@
> */
> void dom_string_ref(struct dom_string *str)
> {
> - str->refcnt++;
> + if (str != NULL)
> + str->refcnt++;
> }
Surely it's a bug if str is ever NULL here?
> Index: src/core/characterdata.c
> ===================================================================
> --- src/core/characterdata.c (revision 9213)
> +++ src/core/characterdata.c (working copy)
> @@ -10,11 +10,13 @@
>
> #include <dom/core/characterdata.h>
> #include <dom/core/string.h>
> +#include <dom/events/events.h>
>
> #include "core/characterdata.h"
> #include "core/document.h"
> #include "core/node.h"
> #include "utils/utils.h"
> +#include "events/mutation_event.h"
>
> /* The virtual functions for dom_characterdata, we make this vtable
> * public to each child class */
> @@ -128,6 +130,11 @@
> return DOM_NO_MODIFICATION_ALLOWED_ERR;
> }
>
> + /* Dispatch a DOMCharacterDataModified event */
> + struct dom_document *doc = dom_node_get_owner(cdata);
> + bool success = true;
> + _dom_dispatch_characterdata_modified_event(doc, c, c->value, data,
> &success);
> +
Do we care if the dispatch failed? If so, how should it be handled?
> if (c->value != NULL) {
> dom_string_unref(c->value);
> }
> @@ -135,6 +142,9 @@
> dom_string_ref(data);
> c->value = data;
>
> + success = true;
> + _dom_dispatch_subtree_modified_event(doc, c->parent, &success);
> +
Ditto (and, indeed, everywhere else).
> Index: src/core/node.c
> ===================================================================
> --- src/core/node.c (revision 9213)
> +++ src/core/node.c (working copy)
> @@ -351,7 +359,8 @@
> */
> void _dom_node_ref(dom_node_internal *node)
> {
> - node->refcnt++;
> + if (node != NULL)
> + node->refcnt++;
> }
Similarly, how can node be NULL here?
>
> @@ -1007,10 +1016,6 @@
> _dom_node_detach(new_child);
> }
>
> - /* When a Node is attached, it should be removed from the pending
> - * list */
> - dom_node_remove_pending(new_child);
> -
Where does it get removed from the pending list now?
Other than the above, this looks fine. Please ensure it's wrapped to 80
columns -- there's still a bunch of cases where it isn't.
J.