From 13fadb12fb400818e0ccb4c38b3bfce70ccfdad2 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Thu, 13 Aug 2009 09:33:24 +0000 Subject: Merge the Events module (branches/struggleyb/libdom-events) back to trunk. :) svn path=/trunk/dom/; revision=9236 --- src/bootstrap/implementation.c | 4 +- src/core/characterdata.c | 58 ++- src/core/document.c | 21 +- src/core/document.h | 11 +- src/core/element.c | 222 +++++++++- src/core/implementation.c | 3 +- src/core/node.c | 85 +++- src/core/node.h | 5 + src/core/string.c | 26 +- src/core/string.h | 10 + src/events/Makefile | 7 + src/events/custom_event.c | 99 +++++ src/events/custom_event.h | 36 ++ src/events/document_event.c | 188 ++++++++ src/events/document_event.h | 62 +++ src/events/event.c | 354 +++++++++++++++ src/events/event.h | 81 ++++ src/events/event_listener.c | 62 +++ src/events/event_listener.h | 28 ++ src/events/event_target.c | 812 +++++++++++++++++++++++++++++++++++ src/events/event_target.h | 88 ++++ src/events/keyboard_event.c | 354 +++++++++++++++ src/events/keyboard_event.h | 55 +++ src/events/mouse_event.c | 366 ++++++++++++++++ src/events/mouse_event.h | 49 +++ src/events/mouse_multi_wheel_event.c | 152 +++++++ src/events/mouse_multi_wheel_event.h | 44 ++ src/events/mouse_wheel_event.c | 115 +++++ src/events/mouse_wheel_event.h | 40 ++ src/events/mutation_event.c | 226 ++++++++++ src/events/mutation_event.h | 45 ++ src/events/mutation_name_event.c | 159 +++++++ src/events/mutation_name_event.h | 42 ++ src/events/text_event.c | 125 ++++++ src/events/text_event.h | 40 ++ src/events/ui_event.c | 138 ++++++ src/events/ui_event.h | 54 +++ src/utils/hashtable.c | 11 + src/utils/hashtable.h | 3 + 39 files changed, 4234 insertions(+), 46 deletions(-) create mode 100644 src/events/Makefile create mode 100644 src/events/custom_event.c create mode 100644 src/events/custom_event.h create mode 100644 src/events/document_event.c create mode 100644 src/events/document_event.h create mode 100644 src/events/event.c create mode 100644 src/events/event.h create mode 100644 src/events/event_listener.c create mode 100644 src/events/event_listener.h create mode 100644 src/events/event_target.c create mode 100644 src/events/event_target.h create mode 100644 src/events/keyboard_event.c create mode 100644 src/events/keyboard_event.h create mode 100644 src/events/mouse_event.c create mode 100644 src/events/mouse_event.h create mode 100644 src/events/mouse_multi_wheel_event.c create mode 100644 src/events/mouse_multi_wheel_event.h create mode 100644 src/events/mouse_wheel_event.c create mode 100644 src/events/mouse_wheel_event.h create mode 100644 src/events/mutation_event.c create mode 100644 src/events/mutation_event.h create mode 100644 src/events/mutation_name_event.c create mode 100644 src/events/mutation_name_event.h create mode 100644 src/events/text_event.c create mode 100644 src/events/text_event.h create mode 100644 src/events/ui_event.c create mode 100644 src/events/ui_event.h (limited to 'src') diff --git a/src/bootstrap/implementation.c b/src/bootstrap/implementation.c index d14fa5b..bb0e125 100644 --- a/src/bootstrap/implementation.c +++ b/src/bootstrap/implementation.c @@ -59,6 +59,7 @@ static dom_exception impl_implementation_create_document( struct dom_string *qname, struct dom_document_type *doctype, dom_alloc alloc, void *pw, struct lwc_context_s *ctx, + dom_events_default_action_fetcher daf, struct dom_document **doc); static dom_exception impl_implementation_get_feature( struct dom_implementation *impl, @@ -286,6 +287,7 @@ dom_exception impl_implementation_create_document( struct dom_string *qname, struct dom_document_type *doctype, dom_alloc alloc, void *pw, struct lwc_context_s *ctx, + dom_events_default_action_fetcher daf, struct dom_document **doc) { struct dom_document *d; @@ -306,7 +308,7 @@ dom_exception impl_implementation_create_document( } /* Create document object */ - err = dom_document_create(impl, alloc, pw, ctx, &d); + err = dom_document_create(impl, alloc, pw, ctx, daf, &d); if (err != DOM_NO_ERR) return err; diff --git a/src/core/characterdata.c b/src/core/characterdata.c index f5b4094..6bb542d 100644 --- a/src/core/characterdata.c +++ b/src/core/characterdata.c @@ -10,11 +10,13 @@ #include #include +#include #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,15 @@ dom_exception _dom_characterdata_set_data(struct dom_characterdata *cdata, return DOM_NO_MODIFICATION_ALLOWED_ERR; } + /* Dispatch a DOMCharacterDataModified event */ + dom_exception err; + struct dom_document *doc = dom_node_get_owner(cdata); + bool success = true; + err = _dom_dispatch_characterdata_modified_event(doc, c, c->value, + data, &success); + if (err != DOM_NO_ERR) + return err; + if (c->value != NULL) { dom_string_unref(c->value); } @@ -135,7 +146,8 @@ dom_exception _dom_characterdata_set_data(struct dom_characterdata *cdata, dom_string_ref(data); c->value = data; - return DOM_NO_ERR; + success = true; + return _dom_dispatch_subtree_modified_event(doc, c->parent, &success); } /** @@ -223,13 +235,22 @@ dom_exception _dom_characterdata_append_data(struct dom_characterdata *cdata, return err; } + /* Dispatch a DOMCharacterDataModified event */ + struct dom_document *doc = dom_node_get_owner(cdata); + bool success = true; + err = _dom_dispatch_characterdata_modified_event(doc, c, c->value, + temp, &success); + if (err != DOM_NO_ERR) + return err; + if (c->value != NULL) { dom_string_unref(c->value); } c->value = temp; - return DOM_NO_ERR; + success = true; + return _dom_dispatch_subtree_modified_event(doc, c->parent, &success); } /** @@ -270,13 +291,22 @@ dom_exception _dom_characterdata_insert_data(struct dom_characterdata *cdata, return err; } + /* Dispatch a DOMCharacterDataModified event */ + struct dom_document *doc = dom_node_get_owner(cdata); + bool success = true; + err = _dom_dispatch_characterdata_modified_event(doc, c, c->value, + temp, &success); + if (err != DOM_NO_ERR) + return err; + if (c->value != NULL) { dom_string_unref(c->value); } c->value = temp; - return DOM_NO_ERR; + success = true; + return _dom_dispatch_subtree_modified_event(doc, c->parent, &success); } /** @@ -319,13 +349,22 @@ dom_exception _dom_characterdata_delete_data(struct dom_characterdata *cdata, return err; } + /* Dispatch a DOMCharacterDataModified event */ + struct dom_document *doc = dom_node_get_owner(cdata); + bool success = true; + err = _dom_dispatch_characterdata_modified_event(doc, c, c->value, + temp, &success); + if (err != DOM_NO_ERR) + return err; + if (c->value != NULL) { dom_string_unref(c->value); } c->value = temp; - return DOM_NO_ERR; + success = true; + return _dom_dispatch_subtree_modified_event(doc, c->parent, &success); } /** @@ -370,13 +409,22 @@ dom_exception _dom_characterdata_replace_data(struct dom_characterdata *cdata, return err; } + /* Dispatch a DOMCharacterDataModified event */ + struct dom_document *doc = dom_node_get_owner(cdata); + bool success = true; + err = _dom_dispatch_characterdata_modified_event(doc, c, c->value, temp, + &success); + if (err != DOM_NO_ERR) + return err; + if (c->value != NULL) { dom_string_unref(c->value); } c->value = temp; - return DOM_NO_ERR; + success = true; + return _dom_dispatch_subtree_modified_event(doc, c->parent, &success); } diff --git a/src/core/document.c b/src/core/document.c index 6bd0045..b15eef3 100644 --- a/src/core/document.c +++ b/src/core/document.c @@ -76,6 +76,7 @@ static dom_exception dom_document_dup_node(dom_document *doc, * \param pw Pointer to client-specific private data * \param doc Pointer to location to receive created document * \param ctx The intern string context of this document + * \param daf The default action fetcher * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion. * * ::impl will have its reference count increased. @@ -84,6 +85,7 @@ static dom_exception dom_document_dup_node(dom_document *doc, */ dom_exception dom_document_create(struct dom_implementation *impl, dom_alloc alloc, void *pw, struct lwc_context_s *ctx, + dom_events_default_action_fetcher daf, struct dom_document **doc) { struct dom_document *d; @@ -103,7 +105,7 @@ dom_exception dom_document_create(struct dom_implementation *impl, * reaches zero. Documents own themselves (this simplifies the * rest of the code, as it doesn't need to special case Documents) */ - err = _dom_document_initialise(d, impl, alloc, pw, ctx); + err = _dom_document_initialise(d, impl, alloc, pw, ctx, daf); if (err != DOM_NO_ERR) { /* Clean up document */ alloc(d, 0, pw); @@ -118,7 +120,8 @@ dom_exception dom_document_create(struct dom_implementation *impl, /* Initialise the document */ dom_exception _dom_document_initialise(struct dom_document *doc, struct dom_implementation *impl, dom_alloc alloc, void *pw, - struct lwc_context_s *ctx) + struct lwc_context_s *ctx, + dom_events_default_action_fetcher daf) { assert(ctx != NULL); assert(alloc != NULL); @@ -150,7 +153,8 @@ dom_exception _dom_document_initialise(struct dom_document *doc, doc->id_name = NULL; - return err; + /* We should not pass a NULL when all things hook up */ + return _dom_document_event_internal_initialise(doc, &doc->dei, daf); } @@ -185,6 +189,8 @@ bool _dom_document_finalise(struct dom_document *doc) if (doc->id_name != NULL) lwc_context_string_unref(doc->context, doc->id_name); lwc_context_unref(doc->context); + + _dom_document_event_internal_finalise(doc, &doc->dei); return true; } @@ -1302,7 +1308,7 @@ dom_exception _dom_document_create_string(struct dom_document *doc, return dom_string_create(doc->alloc, doc->pw, data, len, result); } -/* +/** * Create a lwc_string * * \param doc The document object @@ -1324,6 +1330,13 @@ dom_exception _dom_document_create_lwcstring(struct dom_document *doc, return _dom_exception_from_lwc_error(lerr); } +/* Unref a lwc_string created by this document */ +void _dom_document_unref_lwcstring(struct dom_document *doc, + struct lwc_string_s *str) +{ + lwc_context_string_unref(doc->context, str); +} + /* Simple accessor for lwc_context of this document */ struct lwc_context_s *_dom_document_get_intern_context( struct dom_document *doc) diff --git a/src/core/document.h b/src/core/document.h index 145eddf..ea961a2 100644 --- a/src/core/document.h +++ b/src/core/document.h @@ -21,6 +21,8 @@ #include "utils/resource_mgr.h" #include "utils/list.h" +#include "events/document_event.h" + struct dom_document; struct dom_namednodemap; struct dom_node; @@ -61,12 +63,16 @@ struct dom_document { /**< The deletion pending list */ struct lwc_string_s *id_name; /**< The ID attribute's name */ + + dom_document_event_internal dei; + /**< The DocumentEVent interface */ }; /* Initialise the document */ dom_exception _dom_document_initialise(struct dom_document *doc, struct dom_implementation *impl, dom_alloc alloc, void *pw, - struct lwc_context_s *ctx); + struct lwc_context_s *ctx, + dom_events_default_action_fetcher daf); /* Finalise the document */ bool _dom_document_finalise(struct dom_document *doc); @@ -77,6 +83,9 @@ dom_exception _dom_document_create_string(struct dom_document *doc, /* Create a lwc_string from C string */ dom_exception _dom_document_create_lwcstring(struct dom_document *doc, const uint8_t *data, size_t len, struct lwc_string_s **result); +/* Unref a lwc_string of this document */ +void _dom_document_unref_lwcstring(struct dom_document *doc, + struct lwc_string_s *str); /* Create a dom_string from a lwc_string */ dom_exception _dom_document_create_string_from_lwcstring( struct dom_document *doc, struct lwc_string_s *str, diff --git a/src/core/element.c b/src/core/element.c index 54bb9d1..7609b94 100644 --- a/src/core/element.c +++ b/src/core/element.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "core/attr.h" #include "core/document.h" @@ -26,6 +27,7 @@ #include "utils/namespace.h" #include "utils/utils.h" #include "utils/hashtable.h" +#include "events/mutation_event.h" /* The three numbers are just random ones, maybe we should change it after some * more consideration */ @@ -67,8 +69,6 @@ static dom_exception _dom_element_has_attr(struct dom_element *element, static dom_exception _dom_element_set_id_attr(struct dom_element *element, struct dom_hash_table *hs, struct dom_string *name, bool is_id); -static unsigned int _dom_element_hash_lwcstring(void *key); - /* The operation set for namednodemap */ static dom_exception attributes_get_length(void *priv, @@ -114,6 +114,7 @@ static void *_value(void *value, void *value_pw, dom_alloc alloc, static void *_nsattributes(void *value, void *value_pw, dom_alloc alloc, void *pw, bool clone); + /*----------------------------------------------------------------------*/ /* Constructors and Destructors */ @@ -183,14 +184,14 @@ dom_exception _dom_element_initialise(struct dom_element *el, assert(doc != NULL); err = _dom_document_create_hashtable(doc, CHAINS_ATTRIBUTES, - _dom_element_hash_lwcstring, &el->attributes); + _dom_hash_hash_lwcstring, &el->attributes); if (err != DOM_NO_ERR) { _dom_document_alloc(doc, el, 0); return err; } err = _dom_document_create_hashtable(doc, CHAINS_NAMESPACE, - _dom_element_hash_lwcstring, &el->ns_attributes); + _dom_hash_hash_lwcstring, &el->ns_attributes); if (err != DOM_NO_ERR) { _dom_document_alloc(doc, el, 0); _dom_document_alloc(doc, el->attributes, 0); @@ -540,7 +541,7 @@ dom_exception _dom_element_set_attribute_ns(struct dom_element *element, doc = dom_node_get_owner(element); assert(doc != NULL); err = _dom_document_create_hashtable(doc, CHAINS_NS_ATTRIBUTES, - _dom_element_hash_lwcstring, &attrs); + _dom_hash_hash_lwcstring, &attrs); if (err != DOM_NO_ERR) return err; @@ -686,7 +687,7 @@ dom_exception _dom_element_set_attribute_node_ns(struct dom_element *element, doc = dom_node_get_owner(element); assert(doc != NULL); err = _dom_document_create_hashtable(doc, CHAINS_NS_ATTRIBUTES, - _dom_element_hash_lwcstring, &attrs); + _dom_hash_hash_lwcstring, &attrs); if (err != DOM_NO_ERR) return err; @@ -1218,7 +1219,7 @@ dom_exception _dom_element_get_attr(struct dom_element *element, struct dom_string **value) { void *a; - dom_exception err; + dom_exception err = DOM_NO_ERR; lwc_string *str; /* Looking for name */ @@ -1232,10 +1233,10 @@ dom_exception _dom_element_get_attr(struct dom_element *element, if (a == NULL) { *value = NULL; } else { - dom_attr_get_value(((struct dom_attr *) a), value); + err = dom_attr_get_value(((struct dom_attr *) a), value); } - return DOM_NO_ERR; + return err; } /** @@ -1275,6 +1276,28 @@ dom_exception _dom_element_set_attr(struct dom_element *element, /* Found an existing attribute, so replace its value */ dom_exception err; + /* Dispatch a DOMAttrModified event */ + dom_string *old = NULL; + struct dom_document *doc = dom_node_get_owner(element); + bool success = true; + err = dom_attr_get_value(a, &old); + /* TODO: We did not support some node type such as entity + * reference, in that case, we should ignore the error to + * make sure the event model work as excepted. */ + if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR) + return err; + err = _dom_dispatch_attr_modified_event(doc, e, old, value, a, + name, DOM_MUTATION_MODIFICATION, &success); + dom_string_unref(old); + if (err != DOM_NO_ERR) + return err; + + success = true; + err = _dom_dispatch_subtree_modified_event(doc, + (dom_event_target *) e, &success); + if (err != DOM_NO_ERR) + return err; + err = dom_attr_set_value((struct dom_attr *) a, value); if (err != DOM_NO_ERR) return err; @@ -1294,6 +1317,26 @@ dom_exception _dom_element_set_attr(struct dom_element *element, return err; } + /* Dispatch a DOMAttrModified event */ + struct dom_document *doc = dom_node_get_owner(element); + bool success = true; + err = _dom_dispatch_attr_modified_event(doc, e, NULL, value, + (dom_event_target *) attr, name, + DOM_MUTATION_ADDITION, &success); + if (err != DOM_NO_ERR) { + dom_node_unref(attr); + return err; + } + + err = _dom_dispatch_node_change_event(doc, + (dom_event_target *) attr, + (dom_event_target *) element, + DOM_MUTATION_ADDITION, &success); + if (err != DOM_NO_ERR) { + dom_node_unref(attr); + return err; + } + added = _dom_hash_add(hs, str, attr, false); if (added == false) { /* If we failed at this step, there must be no memory */ @@ -1304,6 +1347,12 @@ dom_exception _dom_element_set_attr(struct dom_element *element, dom_node_set_parent(attr, element); dom_node_unref(attr); dom_node_remove_pending(attr); + + success = true; + err = _dom_dispatch_subtree_modified_event(doc, + (dom_event_target *) element, &success); + if (err != DOM_NO_ERR) + return err; } return DOM_NO_ERR; @@ -1334,13 +1383,51 @@ dom_exception _dom_element_remove_attr(struct dom_element *element, if (err != DOM_NO_ERR) return err; - a = (dom_node_internal *) _dom_hash_del(hs, str); + a = (dom_node_internal *) _dom_hash_get(hs, str); /* Detach attr node from list */ if (a != NULL) { + /* Disptach DOMNodeRemoval event */ + bool success = true; + struct dom_document *doc = dom_node_get_owner(element); + err = _dom_dispatch_node_change_event(doc, + (dom_event_target *) a, + (dom_event_target *) element, + DOM_MUTATION_REMOVAL, &success); + if (err != DOM_NO_ERR) + return err; + + /* Delete the attribute node */ + _dom_hash_del(hs, str); + /* Claim a reference for later event dispatch */ + dom_node_ref(a); + /* And destroy attr */ dom_node_set_parent(a, NULL); dom_node_try_destroy(a); + + /* Dispatch a DOMAttrModified event */ + success = true; + dom_string *old = NULL; + err = dom_attr_get_value(a, &old); + /* TODO: We did not support some node type such as entity + * reference, in that case, we should ignore the error to + * make sure the event model work as excepted. */ + if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR) + return err; + err = _dom_dispatch_attr_modified_event(doc, e, old, NULL, a, + name, DOM_MUTATION_REMOVAL, &success); + dom_string_unref(old); + /* Release the reference */ + dom_node_unref(a); + if (err != DOM_NO_ERR) + return err; + + success = true; + err = _dom_dispatch_subtree_modified_event(doc, + (dom_event_target *) e, &success); + if (err != DOM_NO_ERR) + return err; } /** \todo defaulted attribute handling */ @@ -1437,14 +1524,50 @@ dom_exception _dom_element_set_attr_node(struct dom_element *element, if (err != DOM_NO_ERR) return err; - a = _dom_hash_del(hs, str); + a = _dom_hash_get(hs, str); *result = NULL; if (a != NULL) { + /* Disptach DOMNodeRemoval event */ + bool success = true; + struct dom_document *doc = dom_node_get_owner(element); + err = _dom_dispatch_node_change_event(doc, + (dom_event_target *) a, + (dom_event_target *) element, + DOM_MUTATION_REMOVAL, &success); + if (err != DOM_NO_ERR) + return err; + + _dom_hash_del(hs, str); dom_node_ref(a); *result = (dom_attr *) a; dom_node_set_parent(a, NULL); dom_node_mark_pending(a); + + /* Dispatch a DOMAttrModified event */ + dom_string *old = NULL; + success = true; + err = dom_attr_get_value(a, &old); + /* TODO: We did not support some node type such as entity + * reference, in that case, we should ignore the error to + * make sure the event model work as excepted. */ + if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR) { + dom_node_unref(a); + return err; + } + err = _dom_dispatch_attr_modified_event(doc, e, old, NULL, + (dom_event_target *) a, name, + DOM_MUTATION_REMOVAL, &success); + dom_string_unref(old); + dom_node_unref(a); + if (err != DOM_NO_ERR) + return err; + + success = true; + err = _dom_dispatch_subtree_modified_event(doc, + (dom_event_target *) e, &success); + if (err != DOM_NO_ERR) + return err; } added = _dom_hash_add(hs, str, attr, false); @@ -1455,10 +1578,39 @@ dom_exception _dom_element_set_attr_node(struct dom_element *element, dom_node_set_parent(attr, element); dom_node_remove_pending(attr); + /* Dispatch a DOMAttrModified event */ + dom_string *new = NULL; + struct dom_document *doc = dom_node_get_owner(element); + bool success = true; + err = dom_attr_get_value(attr, &new); + /* TODO: We did not support some node type such as entity reference, in + * that case, we should ignore the error to make sure the event model + * work as excepted. */ + if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR) + return err; + err = _dom_dispatch_attr_modified_event(doc, e, NULL, new, + (dom_event_target *) attr, name, + DOM_MUTATION_ADDITION, &success); + dom_string_unref(new); + if (err != DOM_NO_ERR) + return err; + + err = _dom_dispatch_node_change_event(doc, (dom_event_target *) attr, + (dom_event_target *) element, DOM_MUTATION_ADDITION, + &success); + if (err != DOM_NO_ERR) + return err; + /* Cleanup */ if (name != NULL) dom_string_unref(name); + success = true; + err = _dom_dispatch_subtree_modified_event(doc, + (dom_event_target *) element, &success); + if (err != DOM_NO_ERR) + return err; + return DOM_NO_ERR; } @@ -1500,7 +1652,7 @@ dom_exception _dom_element_remove_attr_node(struct dom_element *element, if (err != DOM_NO_ERR) return err; - a = _dom_hash_del(hs, str); + a = _dom_hash_get(hs, str); /* Now, cleaup the dom_string and lwc_string */ dom_string_unref(name); @@ -1512,16 +1664,53 @@ dom_exception _dom_element_remove_attr_node(struct dom_element *element, return DOM_NOT_FOUND_ERR; } + /* Dispatch a DOMNodeRemoved event */ + bool success = true; + struct dom_document *doc = dom_node_get_owner(element); + err = _dom_dispatch_node_change_event(doc, (dom_event_target *) a, + (dom_event_target *) element, DOM_MUTATION_REMOVAL, + &success); + if (err != DOM_NO_ERR) + return err; + + /* Delete the attribute node */ + _dom_hash_del(hs, str); + dom_node_ref(a); + + /* Dispatch a DOMAttrModified event */ + dom_string *old = NULL; + success = true; + err = dom_attr_get_value(a, &old); + /* TODO: We did not support some node type such as entity reference, in + * that case, we should ignore the error to make sure the event model + * work as excepted. */ + if (err != DOM_NO_ERR && err != DOM_NOT_SUPPORTED_ERR) { + dom_node_unref(a); + return err; + } + err = _dom_dispatch_attr_modified_event(doc, e, old, NULL, + (dom_event_target *) a, name, + DOM_MUTATION_REMOVAL, &success); + dom_string_unref(old); + dom_node_unref(a); + if (err != DOM_NO_ERR) + return err; + /* When a Node is removed, it should be destroy. When its refcnt is not * zero, it will be added to the document's deletion pending list. * When a Node is removed, its parent should be NULL, but its owner * should remain to be the document. */ - dom_node_ref(a); *result = (dom_attr *) a; dom_node_set_parent(a, NULL); dom_node_mark_pending(a); + success = true; + err = _dom_dispatch_subtree_modified_event(doc, (dom_event_target *) e, + &success); + if (err != DOM_NO_ERR) + return err; + return DOM_NO_ERR; } @@ -1704,13 +1893,6 @@ dom_exception _dom_element_get_id(struct dom_element *ele, lwc_string **id) } -/* The hash function for attributes and id tables */ -unsigned int _dom_element_hash_lwcstring(void *key) -{ - lwc_string *lstr = (lwc_string *) key; - - return lwc_string_hash_value(lstr); -} /*-------------- The dom_namednodemap functions -------------------------*/ diff --git a/src/core/implementation.c b/src/core/implementation.c index e2b6763..30e1eb3 100644 --- a/src/core/implementation.c +++ b/src/core/implementation.c @@ -122,10 +122,11 @@ dom_exception dom_implementation_create_document( struct dom_string *namespace, struct dom_string *qname, struct dom_document_type *doctype, dom_alloc alloc, void *pw, struct lwc_context_s *ctx, + dom_events_default_action_fetcher daf, struct dom_document **doc) { return impl->create_document(impl, namespace, qname, doctype, alloc, - pw, ctx, doc); + pw, ctx, daf, doc); } /** diff --git a/src/core/node.c b/src/core/node.c index 1c0b28f..1bdcade 100644 --- a/src/core/node.c +++ b/src/core/node.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "core/string.h" #include "core/namednodemap.h" @@ -33,15 +34,16 @@ #include "core/text.h" #include "utils/utils.h" #include "utils/resource_mgr.h" +#include "events/mutation_event.h" static bool _dom_node_permitted_child(const dom_node_internal *parent, const dom_node_internal *child); -static inline void _dom_node_attach(dom_node_internal *node, +static inline dom_exception _dom_node_attach(dom_node_internal *node, dom_node_internal *parent, dom_node_internal *previous, dom_node_internal *next); static inline void _dom_node_detach(dom_node_internal *node); -static inline void _dom_node_attach_range(dom_node_internal *first, +static inline dom_exception _dom_node_attach_range(dom_node_internal *first, dom_node_internal *last, dom_node_internal *parent, dom_node_internal *previous, @@ -51,7 +53,6 @@ static inline void _dom_node_detach_range(dom_node_internal *first, static inline void _dom_node_replace(dom_node_internal *old, dom_node_internal *replacement); - static struct dom_node_vtable node_vtable = { DOM_NODE_VTABLE }; @@ -249,7 +250,7 @@ dom_exception _dom_node_initialise_generic( dom_node_mark_pending(node); } - return DOM_NO_ERR; + return _dom_event_target_internal_initialise(doc, &node->eti); } /** @@ -331,7 +332,14 @@ void _dom_node_finalise_generic(dom_node_internal *node, dom_alloc alloc, if (node->name != NULL) lwc_context_string_unref(ctx, node->name); - /* Detach from the pending list, if we are in it */ + /* If the node has no owner document, we need not to finalise its + * dom_event_target_internal structure. + */ + if (node->owner != NULL) + _dom_event_target_internal_finalise(node->owner, &node->eti); + + /* Detach from the pending list, if we are in it, + * this part of code should always be the end of this function. */ if (node->pending_list.prev != &node->pending_list) { assert (node->pending_list.next != &node->pending_list); list_del(&node->pending_list); @@ -351,7 +359,8 @@ void _dom_node_finalise_generic(dom_node_internal *node, dom_alloc alloc, */ void _dom_node_ref(dom_node_internal *node) { - node->refcnt++; + if (node != NULL) + node->refcnt++; } @@ -816,6 +825,8 @@ dom_exception _dom_node_insert_before(dom_node_internal *node, dom_node_internal *new_child, dom_node_internal *ref_child, dom_node_internal **result) { + dom_exception err; + /* Ensure that new_child and node are owned by the same document */ if ((new_child->type == DOM_DOCUMENT_TYPE_NODE && new_child->owner != NULL && @@ -874,24 +885,29 @@ dom_exception _dom_node_insert_before(dom_node_internal *node, return DOM_HIERARCHY_REQUEST_ERR; if (new_child->first_child != NULL) { - _dom_node_attach_range(new_child->first_child, + err = _dom_node_attach_range(new_child->first_child, new_child->last_child, node, ref_child == NULL ? node->last_child : ref_child->previous, ref_child == NULL ? NULL : ref_child); + if (err != DOM_NO_ERR) + return err; new_child->first_child = NULL; new_child->last_child = NULL; } } else { - _dom_node_attach(new_child, + err = _dom_node_attach(new_child, node, ref_child == NULL ? node->last_child : ref_child->previous, ref_child == NULL ? NULL : ref_child); + if (err != DOM_NO_ERR) + return err; + } /* DocumentType nodes are created outside the Document so, @@ -1059,6 +1075,14 @@ dom_exception _dom_node_remove_child(dom_node_internal *node, if (_dom_node_readonly(node)) return DOM_NO_MODIFICATION_ALLOWED_ERR; + /* Dispatch a DOMNodeRemoval event */ + dom_exception err; + bool success = true; + err = _dom_dispatch_node_change_event(node->owner, old_child, node, + DOM_MUTATION_REMOVAL, &success); + if (err != DOM_NO_ERR) + return err; + /* Detach the node */ _dom_node_detach(old_child); @@ -1070,6 +1094,12 @@ dom_exception _dom_node_remove_child(dom_node_internal *node, dom_node_try_destroy(old_child); *result = old_child; + success = true; + err = _dom_dispatch_subtree_modified_event(node->owner, node, + &success); + if (err != DOM_NO_ERR) + return err; + return DOM_NO_ERR; } @@ -2048,7 +2078,8 @@ dom_exception _dom_node_copy(dom_node_internal *new, dom_node_internal *old) * so it should be put in the pending list. */ dom_node_mark_pending(new); - return DOM_NO_ERR; + /* Intialise the EventTarget interface */ + return _dom_event_target_internal_initialise(new->owner, &new->eti); } @@ -2162,11 +2193,13 @@ bool _dom_node_readonly(const dom_node_internal *node) * \param parent Node to attach ::node as child of * \param previous Previous node in sibling list, or NULL if none * \param next Next node in sibling list, or NULL if none + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. */ -void _dom_node_attach(dom_node_internal *node, dom_node_internal *parent, - dom_node_internal *previous, dom_node_internal *next) +dom_exception _dom_node_attach(dom_node_internal *node, + dom_node_internal *parent, dom_node_internal *previous, + dom_node_internal *next) { - _dom_node_attach_range(node, node, parent, previous, next); + return _dom_node_attach_range(node, node, parent, previous, next); } /** @@ -2191,10 +2224,11 @@ void _dom_node_detach(dom_node_internal *node) * \param parent Node to attach range to * \param previous Previous node in sibling list, or NULL if none * \param next Next node in sibling list, or NULL if none + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. * * The range is assumed to be a linked list of sibling nodes. */ -void _dom_node_attach_range(dom_node_internal *first, +dom_exception _dom_node_attach_range(dom_node_internal *first, dom_node_internal *last, dom_node_internal *parent, dom_node_internal *previous, @@ -2213,9 +2247,24 @@ void _dom_node_attach_range(dom_node_internal *first, else parent->last_child = last; + dom_exception err; + bool success = true; for (dom_node_internal *n = first; n != last->next; n = n->next) { n->parent = parent; + /* Dispatch a DOMNodeInserted event */ + err = _dom_dispatch_node_change_event(parent->owner, n, parent, + DOM_MUTATION_ADDITION, &success); + if (err != DOM_NO_ERR) + return err; } + + success = true; + err = _dom_dispatch_subtree_modified_event(parent->owner, parent, + &success); + if (err != DOM_NO_ERR) + return err; + + return DOM_NO_ERR; } /** @@ -2239,10 +2288,20 @@ void _dom_node_detach_range(dom_node_internal *first, else last->parent->last_child = first->previous; + bool success = true; + dom_node_internal *parent = first->parent; for (dom_node_internal *n = first; n != last->next; n = n->next) { + /* Dispatch a DOMNodeRemoval event */ + _dom_dispatch_node_change_event(n->owner, n, n->parent, + DOM_MUTATION_REMOVAL, &success); + n->parent = NULL; } + success = true; + _dom_dispatch_subtree_modified_event(parent->owner, parent, + &success); + first->previous = NULL; last->next = NULL; } diff --git a/src/core/node.h b/src/core/node.h index 68776da..c1a4192 100644 --- a/src/core/node.h +++ b/src/core/node.h @@ -15,6 +15,9 @@ #include #include +#include "events/event_target.h" +#include "events/mutation_event.h" + #include "utils/list.h" /** @@ -76,6 +79,8 @@ struct dom_node_internal { uint32_t refcnt; /**< Reference count */ struct list_entry pending_list; /**< The document delete pending list */ + + dom_event_target_internal eti; /**< The EventTarget interface */ }; dom_node_internal * _dom_node_create(struct dom_document *doc); diff --git a/src/core/string.c b/src/core/string.c index 081e03d..7442c66 100644 --- a/src/core/string.c +++ b/src/core/string.c @@ -56,7 +56,8 @@ static struct dom_string empty_string = { */ void dom_string_ref(struct dom_string *str) { - str->refcnt++; + if (str != NULL) + str->refcnt++; } /** @@ -963,3 +964,26 @@ int _dom_lwc_string_compare_raw(struct lwc_string_s *s1, return memcmp(rs1, rs2, len); } +/** + * Get the raw character data of the dom_string. + * + * \param str The dom_string object + * \return The C string pointer + * + * @note: This function is just provided for the convenience of accessing the + * raw C string character, no change on the result string is allowed. + */ +char *_dom_string_data(struct dom_string *str) +{ + return (char *) str->ptr; +} + +/* Get the string length of this dom_string + * + * \param str The dom_string object + */ +size_t _dom_string_length(struct dom_string *str) +{ + return str->len; +} + diff --git a/src/core/string.h b/src/core/string.h index 8372688..46704d8 100644 --- a/src/core/string.h +++ b/src/core/string.h @@ -28,5 +28,15 @@ int _dom_lwc_string_compare_raw(struct lwc_string_s *s1, /* Map the lwc_error to dom_exception */ dom_exception _dom_exception_from_lwc_error(lwc_error err); +/** + * Get the raw character data of the dom_string. + * @note: This function is just provided for the convenience of accessing the + * raw C string character, no change on the result string is allowed. + */ +char *_dom_string_data(struct dom_string *str); + +/* Get the string length of this dom_string */ +size_t _dom_string_length(struct dom_string *str); + #endif diff --git a/src/events/Makefile b/src/events/Makefile new file mode 100644 index 0000000..5b881b7 --- /dev/null +++ b/src/events/Makefile @@ -0,0 +1,7 @@ +# Sources +DIR_SOURCES := event.c event_target.c document_event.c \ + custom_event.c keyboard_event.c mouse_wheel_event.c \ + text_event.c event_listener.c mouse_event.c mutation_event.c \ + ui_event.c mouse_multi_wheel_event.c mutation_name_event.c + +include build/makefiles/Makefile.subdir diff --git a/src/events/custom_event.c b/src/events/custom_event.c new file mode 100644 index 0000000..920c23e --- /dev/null +++ b/src/events/custom_event.c @@ -0,0 +1,99 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include "events/custom_event.h" + +#include "core/document.h" + +static void _virtual_dom_custom_event_destroy(struct dom_event *evt); + +static struct dom_event_private_vtable _event_vtable = { + _virtual_dom_custom_event_destroy +}; + +/* Constructor */ +dom_exception _dom_custom_event_create(struct dom_document *doc, + struct dom_custom_event **evt) +{ + *evt = _dom_document_alloc(doc, NULL, sizeof(dom_custom_event)); + if (*evt == NULL) + return DOM_NO_MEM_ERR; + + ((struct dom_event *) *evt)->vtable = &_event_vtable; + + return _dom_custom_event_initialise(doc, *evt); +} + +/* Destructor */ +void _dom_custom_event_destroy(struct dom_document *doc, + struct dom_custom_event *evt) +{ + _dom_custom_event_finalise(doc, evt); + + _dom_document_alloc(doc, evt, 0); +} + +/* Initialise function */ +dom_exception _dom_custom_event_initialise(struct dom_document *doc, + struct dom_custom_event *evt) +{ + evt->detail = NULL; + return _dom_event_initialise(doc, &evt->base); +} + +/* Finalise function */ +void _dom_custom_event_finalise(struct dom_document *doc, + struct dom_custom_event *evt) +{ + evt->detail = NULL; + _dom_event_finalise(doc, &evt->base); +} + +/* The virtual destroy function */ +void _virtual_dom_custom_event_destroy(struct dom_event *evt) +{ + _dom_custom_event_destroy(evt->doc, (dom_custom_event *) evt); +} + +/*----------------------------------------------------------------------*/ +/* The public API */ + +/** + * Get the detail object of this custom event + * + * \param evt The Event object + * \param detail The returned detail object + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_custom_event_get_detail(dom_custom_event *evt, + void **detail) +{ + *detail = evt->detail; + + return DOM_NO_ERR; +} + +/** + * Initialise this custom event + * + * \param evt The Event object + * \param namespace The namespace of this new Event + * \param type The Event type + * \param bubble Whether this event can bubble + * \param cancelable Whether this event is cancelable + * \param detail The detail object of this custom event + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_custom_event_init_ns(dom_custom_event *evt, + struct dom_string *namespace, struct dom_string *type, + bool bubble, bool cancelable, void *detail) +{ + evt->detail = detail; + return _dom_event_init_ns(&evt->base, namespace, type, bubble, + cancelable); +} + diff --git a/src/events/custom_event.h b/src/events/custom_event.h new file mode 100644 index 0000000..a50bc23 --- /dev/null +++ b/src/events/custom_event.h @@ -0,0 +1,36 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_interntal_events_custom_event_h_ +#define dom_interntal_events_custom_event_h_ + +#include + +#include "events/event.h" + +struct dom_custom_event { + struct dom_event base; + void *detail; +}; + +/* Constructor */ +dom_exception _dom_custom_event_create(struct dom_document *doc, + struct dom_custom_event **evt); + +/* Destructor */ +void _dom_custom_event_destroy(struct dom_document *doc, + struct dom_custom_event *evt); + +/* Initialise function */ +dom_exception _dom_custom_event_initialise(struct dom_document *doc, + struct dom_custom_event *evt); + +/* Finalise function */ +void _dom_custom_event_finalise(struct dom_document *doc, + struct dom_custom_event *evt); + +#endif diff --git a/src/events/document_event.c b/src/events/document_event.c new file mode 100644 index 0000000..47afed6 --- /dev/null +++ b/src/events/document_event.c @@ -0,0 +1,188 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include + +#include + +#include "core/string.h" +#include "core/node.h" +#include "core/document.h" +#include "events/document_event.h" +#include "events/event.h" +#include "events/ui_event.h" +#include "events/custom_event.h" +#include "events/text_event.h" +#include "events/keyboard_event.h" +#include "events/mouse_event.h" +#include "events/mouse_multi_wheel_event.h" +#include "events/mouse_wheel_event.h" +#include "events/mutation_event.h" +#include "events/mutation_name_event.h" + +#include "utils/utils.h" + +static const char *__event_types[] = { + "Event", + "CustomEvent", + "UIEvent", + "TextEvent", + "KeyboardEvent", + "MouseEvent", + "MouseMultiWheelEvent", + "MouseWheelEvent", + "MutationEvent", + "MutationNameEvent" +}; + +/** + * Initialise this DocumentEvent + * + * \param doc The document object + * \param dei The DocumentEvent internal object + * \param actions The default action fetcher, the browser should provide such + * a function to Event module. + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_document_event_internal_initialise(struct dom_document *doc, + dom_document_event_internal *dei, + dom_events_default_action_fetcher actions) +{ + lwc_error err; + lwc_context *ctx = _dom_document_get_intern_context(doc); + int i = 0; + + for (; i < DOM_EVENT_COUNT; i++) { + err = lwc_context_intern(ctx, __event_types[i], + SLEN(__event_types[i]), &dei->event_types[i]); + if (err != lwc_error_ok) + return _dom_exception_from_lwc_error(err); + } + + dei->actions = actions; + + return DOM_NO_ERR; +} + +/* Finalise this DocumentEvent */ +void _dom_document_event_internal_finalise(struct dom_document *doc, + dom_document_event_internal *dei) +{ + /* Nothing to do here */ + UNUSED(doc); + UNUSED(dei); + return; +} + +/*-------------------------------------------------------------------------*/ +/* Public API */ + +/** + * Create an Event object + * + * \param de The DocumentEvent object + * \param type The Event type + * \param evt The returned Event object + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_document_event_create_event(dom_document_event *de, + struct dom_string *type, struct dom_event **evt) +{ + lwc_context *ctx = NULL; + lwc_string *t = NULL; + dom_exception err; + struct dom_document *doc = de; + + dom_string_get_intern(type, &ctx, &t); + if (t == NULL) { + ctx = _dom_document_get_intern_context(doc); + err = _dom_string_intern(type, ctx, &t); + if (err != DOM_NO_ERR) + return err; + } + + assert(t != NULL); + + int i, et = 0; + dom_document_event_internal *dei = &de->dei; + for (i = 0; i < DOM_EVENT_COUNT; i++) { + if (dei->event_types[i] == t) { + et = i; + break; + } + } + lwc_context_string_unref(ctx, t); + + switch (et) { + case DOM_EVENT: + err = _dom_event_create(doc, evt); + break; + case DOM_CUSTOM_EVENT: + err = _dom_custom_event_create(doc, + (dom_custom_event **) evt); + break; + case DOM_UI_EVENT: + err = _dom_ui_event_create(doc, (dom_ui_event **) evt); + break; + case DOM_TEXT_EVENT: + err = _dom_text_event_create(doc, + (dom_text_event **) evt); + break; + case DOM_KEYBOARD_EVENT: + err = _dom_keyboard_event_create(doc, + (dom_keyboard_event **) evt); + break; + case DOM_MOUSE_EVENT: + err = _dom_mouse_event_create(doc, + (dom_mouse_event **) evt); + break; + case DOM_MOUSE_MULTI_WHEEL_EVENT: + err = _dom_mouse_multi_wheel_event_create(doc, + (dom_mouse_multi_wheel_event **) evt); + break; + case DOM_MOUSE_WHEEL_EVENT: + err = _dom_mouse_wheel_event_create(doc, + (dom_mouse_wheel_event **) evt); + break; + case DOM_MUTATION_EVENT: + err = _dom_mutation_event_create(doc, + (dom_mutation_event **) evt); + break; + case DOM_MUTATION_NAME_EVENT: + err = _dom_mutation_name_event_create(doc, + (dom_mutation_name_event **) evt); + break; + default: + assert("Should never be here" == NULL); + } + + return err; +} + +/** + * Tests if the implementation can generate events of a specified type + * + * \param de The DocumentEvent + * \param namespace The namespace of the event + * \param type The type of the event + * \param can True if we can generate such an event, false otherwise + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + * + * We don't support this API now, so the return value should always + * DOM_NO_SUPPORTED_ERR. + */ +dom_exception _dom_document_event_can_dispatch(dom_document_event *de, + struct dom_string *namespace, struct dom_string *type, + bool *can) +{ + UNUSED(de); + UNUSED(namespace); + UNUSED(type); + UNUSED(can); + + return DOM_NOT_SUPPORTED_ERR; +} diff --git a/src/events/document_event.h b/src/events/document_event.h new file mode 100644 index 0000000..2458508 --- /dev/null +++ b/src/events/document_event.h @@ -0,0 +1,62 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_internal_events_document_event_h_ +#define dom_internal_events_document_event_h_ + +#include + +struct dom_event_listener; +struct lwc_string_s; +struct dom_document; + +/** + * Type of Events + */ +typedef enum { + DOM_EVENT = 0, + DOM_CUSTOM_EVENT, + DOM_UI_EVENT, + DOM_TEXT_EVENT, + DOM_KEYBOARD_EVENT, + DOM_MOUSE_EVENT, + DOM_MOUSE_MULTI_WHEEL_EVENT, + DOM_MOUSE_WHEEL_EVENT, + DOM_MUTATION_EVENT, + DOM_MUTATION_NAME_EVENT, + + DOM_EVENT_COUNT +} dom_event_type; + +/** + * The DocumentEvent internal class + */ +struct dom_document_event_internal { + dom_events_default_action_fetcher actions; + /**< The default action fetecher */ + struct lwc_string_s *event_types[DOM_EVENT_COUNT]; + /**< Events type names */ +}; + +typedef struct dom_document_event_internal dom_document_event_internal; + +/** + * Constructor and destructor: Since this object is not intended to be + * allocated alone, it should be embedded into the Document object, there + * is no constructor and destructor for it. + */ + +/* Initialise this DocumentEvent */ +dom_exception _dom_document_event_internal_initialise(struct dom_document *doc, + dom_document_event_internal *dei, + dom_events_default_action_fetcher actions); + +/* Finalise this DocumentEvent */ +void _dom_document_event_internal_finalise(struct dom_document *doc, + dom_document_event_internal *dei); + +#endif diff --git a/src/events/event.c b/src/events/event.c new file mode 100644 index 0000000..f9caa0b --- /dev/null +++ b/src/events/event.c @@ -0,0 +1,354 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include +#include + +#include "events/event.h" + +#include + +#include "core/string.h" +#include "core/node.h" +#include "core/document.h" + +static void _virtual_dom_event_destroy(struct dom_event *evt); + +static struct dom_event_private_vtable _event_vtable = { + _virtual_dom_event_destroy +}; + +/* Constructor */ +dom_exception _dom_event_create(struct dom_document *doc, + struct dom_event **evt) +{ + *evt = (dom_event *) _dom_document_alloc(doc, NULL, sizeof(dom_event)); + if (*evt == NULL) + return DOM_NO_MEM_ERR; + + (*evt)->vtable = &_event_vtable; + + return _dom_event_initialise(doc, *evt); +} + +/* Destructor */ +void _dom_event_destroy(struct dom_document *doc, struct dom_event *evt) +{ + _dom_event_finalise(doc, evt); + + _dom_document_alloc(doc, evt, sizeof(dom_event)); +} + +/* Initialise function */ +dom_exception _dom_event_initialise(struct dom_document *doc, + struct dom_event *evt) +{ + assert(doc != NULL); + + evt->doc = doc; + evt->stop = false; + evt->stop_now = false; + evt->prevent_default = false; + evt->custom = false; + + evt->type = NULL; + + evt->namespace = NULL; + + evt->timestamp = time(NULL); + + evt->refcnt = 1; + evt->in_dispatch = false; + + return DOM_NO_ERR; +} + +/* Finalise function */ +void _dom_event_finalise(struct dom_document *doc, struct dom_event *evt) +{ + assert(doc != NULL); + lwc_context *ctx = _dom_document_get_intern_context(doc); + assert(ctx != NULL); + + if (evt->type != NULL) + lwc_context_string_unref(ctx, evt->type); + if (evt->namespace != NULL) + lwc_context_string_unref(ctx, evt->namespace); +} + +/* The virtual destroy function */ +void _virtual_dom_event_destroy(struct dom_event *evt) +{ + _dom_event_destroy(evt->doc, evt); +} + +/*----------------------------------------------------------------------*/ +/* The public API */ + +/** + * Claim a reference on this event object + * + * \param evt The Event object + */ +void _dom_event_ref(dom_event *evt) +{ + evt->refcnt++; +} + +/** + * 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--; + + if (evt->refcnt == 0) + dom_event_destroy(evt); +} + + +/** + * Get the event type + * + * \param evt The event object + * \parnm type The returned event type + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_event_get_type(dom_event *evt, struct dom_string **type) +{ + struct dom_document *doc = evt->doc; + dom_exception err; + + err = _dom_document_create_string_from_lwcstring(doc, evt->type, type); + if (err != DOM_NO_ERR) + return err; + + return DOM_NO_ERR; +} + +/** + * Get the target node of this event + * + * \param evt The event object + * \param target The target node + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_event_get_target(dom_event *evt, dom_event_target **target) +{ + *target = evt->target; + dom_node_ref(*target); + + return DOM_NO_ERR; +} + +/** + * Get the current target of this event + * + * \param evt The event object + * \param current The current event target node + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_event_get_current_target(dom_event *evt, + dom_event_target **current) +{ + *current = evt->current; + dom_node_ref(*current); + + return DOM_NO_ERR; +} + +/** + * Get whether this event can bubble + * + * \param evt The Event object + * \param bubbles The returned value + * \return DOM_NO_ERR. + */ +dom_exception _dom_event_get_bubbles(dom_event *evt, bool *bubbles) +{ + *bubbles = evt->bubble; + return DOM_NO_ERR; +} + +/** + * Get whether this event can be cancelable + * + * \param evt The Event object + * \param cancelable The returned value + * \return DOM_NO_ERR. + */ +dom_exception _dom_event_get_cancelable(dom_event *evt, bool *cancelable) +{ + *cancelable = evt->cancelable; + return DOM_NO_ERR; +} + +/** + * Get the event's generation timestamp + * + * \param evt The Event object + * \param timestamp The returned value + * \return DOM_NO_ERR. + */ +dom_exception _dom_event_get_timestamp(dom_event *evt, unsigned int *timestamp) +{ + *timestamp = evt->timestamp; + return DOM_NO_ERR; +} + +/** + * Stop propagation of the event + * + * \param evt The Event object + * \return DOM_NO_ERR. + */ +dom_exception _dom_event_stop_propagation(dom_event *evt) +{ + evt->stop = true; + + return DOM_NO_ERR; +} + +/** + * Prevent the default action of this event + * + * \param evt The Event object + * \return DOM_NO_ERR. + */ +dom_exception _dom_event_prevent_default(dom_event *evt) +{ + evt->prevent_default = true; + return DOM_NO_ERR; +} + +/** + * Initialise the event object + * + * \param evt The event object + * \param type The type of this event + * \param bubble Whether this event can bubble + * \param cancelable Whether this event is cancelable + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_event_init(dom_event *evt, struct dom_string *type, + bool bubble, bool cancelable) +{ + assert(evt->doc != NULL); + lwc_context *ctx = _dom_document_get_intern_context(evt->doc); + lwc_string *str = NULL; + dom_exception err; + + err = _dom_string_intern(type, ctx, &str); + if (err != DOM_NO_ERR) + return err; + + evt->type = str; + evt->bubble = bubble; + evt->cancelable = cancelable; + + return DOM_NO_ERR; +} + +/** + * Get the namespace of this event + * + * \param evt The event object + * \param namespace The returned namespace of this event + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_event_get_namespace(dom_event *evt, + struct dom_string **namespace) +{ + struct dom_document *doc = evt->doc; + dom_exception err; + + err = _dom_document_create_string_from_lwcstring(doc, evt->namespace, + namespace); + if (err != DOM_NO_ERR) + return err; + + return DOM_NO_ERR; +} + +/** + * Whether this is a custom event + * + * \param evt The event object + * \param custom The returned value + * \return DOM_NO_ERR. + */ +dom_exception _dom_event_is_custom(dom_event *evt, bool *custom) +{ + *custom = evt->custom; + + return DOM_NO_ERR; +} + +/** + * Stop the event propagation immediately + * + * \param evt The event object + * \return DOM_NO_ERR. + */ +dom_exception _dom_event_stop_immediate_propagation(dom_event *evt) +{ + evt->stop_now = true; + + return DOM_NO_ERR; +} + +/** + * Whether the default action is prevented + * + * \param evt The event object + * \param prevented The returned value + * \return DOM_NO_ERR. + */ +dom_exception _dom_event_is_default_prevented(dom_event *evt, bool *prevented) +{ + *prevented = evt->prevent_default; + + return DOM_NO_ERR; +} + +/** + * Initialise the event with namespace + * + * \param evt The event object + * \param namespace The namespace of this event + * \param type The event type + * \param bubble Whether this event has a bubble phase + * \param cancelable Whether this event is cancelable + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_event_init_ns(dom_event *evt, struct dom_string *namespace, + struct dom_string *type, bool bubble, bool cancelable) +{ + assert(evt->doc != NULL); + lwc_context *ctx = _dom_document_get_intern_context(evt->doc); + lwc_string *str = NULL; + dom_exception err; + + err = _dom_string_intern(type, ctx, &str); + if (err != DOM_NO_ERR) + return err; + evt->type = str; + + err = _dom_string_intern(namespace, ctx, &str); + if (err != DOM_NO_ERR) + return err; + evt->namespace = str; + + evt->bubble = bubble; + evt->cancelable = cancelable; + + return DOM_NO_ERR; +} + diff --git a/src/events/event.h b/src/events/event.h new file mode 100644 index 0000000..4d094e9 --- /dev/null +++ b/src/events/event.h @@ -0,0 +1,81 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_internal_events_event_h_ +#define dom_internal_events_event_h_ + +#include + +#include +#include + +#include "utils/list.h" + +struct lwc_string_s; +struct dom_document; + +/* The private virtual table */ +struct dom_event_private_vtable { + void (*destroy)(dom_event *evt); +}; + +/** + * The Event Ojbect + */ +struct dom_event { + struct lwc_string_s *type; /**< The type of the event */ + dom_event_target *target; /**< The event target */ + dom_event_target *current; /**< The current event target */ + dom_event_flow_phase phase; /**< The event phase */ + bool bubble; /**< Whether this event is a bubbling event */ + bool cancelable; /**< Whether this event is cancelable */ + unsigned int timestamp; + /**< The timestamp this event is created */ + + struct lwc_string_s *namespace; + /**< The namespace of this event */ + + struct dom_document *doc; + /**< The document which create this event */ + + bool stop; /**< Whether stopPropagation is called */ + bool stop_now; /**< Whether stopImmediatePropagation is called */ + bool prevent_default; + /**< Whether the default action is prevented */ + + bool custom; /**< Whether this is a custom event */ + + uint32_t refcnt; /**< The reference count of this object */ + + struct dom_event_private_vtable *vtable; + /**< The private virtual function table of Event */ + bool in_dispatch; /**< Whether this event is in dispatch */ +}; + +/* Constructor */ +dom_exception _dom_event_create(struct dom_document *doc, + struct dom_event **evt); + +/* Destructor */ +void _dom_event_destroy(struct dom_document *doc, struct dom_event *evt); + +/* Initialise function */ +dom_exception _dom_event_initialise(struct dom_document *doc, + struct dom_event *evt); + +/* Finalise function */ +void _dom_event_finalise(struct dom_document *doc, struct dom_event *evt); + + +static inline void dom_event_destroy(struct dom_event *evt) +{ + evt->vtable->destroy(evt); +} +#define dom_event_destroy(e) dom_event_destroy((struct dom_event *) (e)) + +#endif + diff --git a/src/events/event_listener.c b/src/events/event_listener.c new file mode 100644 index 0000000..3c3c14c --- /dev/null +++ b/src/events/event_listener.c @@ -0,0 +1,62 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include "events/event_listener.h" +#include "core/document.h" + +/** + * Create an EventListener + * + * \param doc The document object + * \param handler The event function + * \param pw The private data + * \param listener The returned EventListener + * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion. + */ +dom_exception dom_event_listener_create(struct dom_document *doc, + handle_event handler, void *pw, dom_event_listener **listener) +{ + dom_event_listener *ret = (dom_event_listener *) _dom_document_alloc( + doc, NULL, sizeof(dom_event_listener)); + if (ret == NULL) + return DOM_NO_MEM_ERR; + + ret->handler = handler; + ret->pw = pw; + ret->refcnt = 1; + ret->doc = doc; + + *listener = ret; + + return DOM_NO_ERR; +} + +/** + * Claim a new reference on the listener object + * + * \param listener The EventListener object + */ +void dom_event_listener_ref(dom_event_listener *listener) +{ + listener->refcnt++; +} + +/** + * 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--; + + if (listener->refcnt == 0) + _dom_document_alloc(listener->doc, listener, + sizeof(dom_event_listener)); +} + diff --git a/src/events/event_listener.h b/src/events/event_listener.h new file mode 100644 index 0000000..c85be85 --- /dev/null +++ b/src/events/event_listener.h @@ -0,0 +1,28 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_internal_events_event_listener_h_ +#define dom_internal_events_event_listener_h_ + +#include + +#include "utils/list.h" + +/** + * The EventListener class + */ +struct dom_event_listener { + handle_event handler; /**< The event handler function */ + void *pw; /**< The private data of this listener */ + + unsigned int refcnt; /**< The reference count of this listener */ + struct dom_document *doc; + /**< The document which create this listener */ +}; + +#endif + diff --git a/src/events/event_target.c b/src/events/event_target.c new file mode 100644 index 0000000..e17aa9c --- /dev/null +++ b/src/events/event_target.c @@ -0,0 +1,812 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include + +#include + +#include "events/event.h" +#include "events/event_listener.h" +#include "events/event_target.h" + +#include "core/document.h" +#include "core/node.h" +#include "core/string.h" + +#include "utils/utils.h" +#include "utils/validate.h" + +/* The number of chains in the hash table used for hash event types */ +#define CHAINS 11 + +/* Entry for a EventTarget, used to record the bubbling list */ +typedef struct dom_event_target_entry { + struct list_entry entry; /**< The list entry */ + dom_event_target *et; /**< The node */ +} dom_event_target_entry; + +/* 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); + + +/* Initialise this EventTarget */ +dom_exception _dom_event_target_internal_initialise(struct dom_document *doc, + dom_event_target_internal *eti) +{ + UNUSED(doc); + eti->listeners = NULL; + eti->ns_listeners = NULL; + + return DOM_NO_ERR; +} + +/* Finalise this EventTarget */ +void _dom_event_target_internal_finalise(struct dom_document *doc, + dom_event_target_internal *eti) +{ + lwc_context *ctx = _dom_document_get_intern_context(doc); + + if (eti->listeners != NULL) + _dom_hash_destroy(eti->listeners, _key, ctx, _value, doc); + /* TODO: Now, we did not support the EventListener with namespace, + * when we support it, we should deal with the ns_listeners hash + * table, too. + */ +} + +/*-------------------------------------------------------------------------*/ +/* The public API */ + +/** + * 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); + assert(doc != NULL); + + struct dom_event_target_internal *eti = &et->eti; + lwc_string *t = NULL; + lwc_context *ctx = NULL; + dom_exception err; + + /* If there is no hash table, we should create one firstly */ + if (eti->listeners == NULL) { + err = _dom_document_create_hashtable(doc, CHAINS, + _dom_hash_hash_lwcstring, &eti->listeners); + if (err != DOM_NO_ERR) + return err; + } + + err = dom_string_get_intern(type, &ctx, &t); + if (err != DOM_NO_ERR) + return err; + + ctx = _dom_document_get_intern_context(doc); + if (t == NULL) { + err = _dom_string_intern(type, ctx, &t); + if (err != DOM_NO_ERR) + return err; + } else { + lwc_context_string_ref(ctx, t); + } + + assert(t != NULL); + + le = (struct listener_entry *) _dom_document_alloc(doc, NULL, + sizeof(struct listener_entry)); + if (le == NULL) + return DOM_NO_MEM_ERR; + + /* Initialise the listener_entry */ + list_init(&le->list); + le->listener = listener; + dom_event_listener_ref(listener); + le->capture = capture; + + /* Find the type of this event */ + struct list_entry *item = (struct list_entry *) _dom_hash_get( + eti->listeners, t); + if (item == NULL) { + /* If there is no item in the hash table, we should add the + * first */ + _dom_hash_add(eti->listeners, t, &le->list, false); + } else { + /* Append this listener to the end of the list */ + list_append(item, &le->list); + } + + return DOM_NO_ERR; +} + +/** + * Remove an EventListener from the EventTarget + * + * \param et The EventTarget object + * \param type The event type this listener is registered for + * \param listener The listener object + * \param capture Whether the listener is registered at the capturing phase + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_event_target_remove_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; + } + + struct dom_event_target_internal *eti = &et->eti; + lwc_string *t = NULL; + lwc_context *ctx = NULL; + dom_exception err; + + err = dom_string_get_intern(type, &ctx, &t); + if (err != DOM_NO_ERR) + return err; + + ctx = _dom_document_get_intern_context(doc); + if (t == NULL) { + err = _dom_string_intern(type, ctx, &t); + if (err != DOM_NO_ERR) + return err; + } else { + lwc_context_string_ref(ctx, t); + } + + assert(t != NULL); + + /* Find the type of this event */ + struct list_entry *item = (struct list_entry *) _dom_hash_get( + eti->listeners, t); + if (item == NULL) { + /* There is no such event listener */ + lwc_context_string_unref(ctx, t); + return DOM_NO_ERR; + } else { + struct list_entry *i = item; + do { + le = (struct listener_entry *) i; + if (le->listener == listener && + le->capture == capture) { + /* We found the listener */ + list_del(i); + dom_event_listener_unref(le->listener); + _dom_document_alloc(doc, le, + sizeof(struct listener_entry)); + break; + } + i = i->next; + } while(i != item); + } + + return DOM_NO_ERR; +} + +/** + * Dispatch an event into the implementation's event model + * + * \param et The EventTarget object + * \param evt The event object + * \param success Indicates whether any of the listeners which handled the + * event called Event.preventDefault(). If + * Event.preventDefault() was called the returned value is + * false, else it is true. + * \return DOM_NO_ERR on success + * DOM_DISPATCH_REQUEST_ERR If the event is already in dispatch + * DOM_UNSPECIFIED_EVENT_TYPE_ERR If the type of the event is Null or + * empty string. + * DOM_NOT_SUPPORTED_ERR If the event is not created by + * Document.createEvent + * DOM_INVALID_CHARACTER_ERR If the type of this event is not a + * valid NCName. + */ +dom_exception _dom_event_target_dispatch_event(dom_event_target *et, + struct dom_event *evt, bool *success) +{ + assert(et != NULL); + + dom_exception err, ret = DOM_NO_ERR; + + /* To test whether this event is in dispatch */ + if (evt->in_dispatch == true) { + return DOM_DISPATCH_REQUEST_ERR; + } else { + evt->in_dispatch = true; + } + + if (evt->type == NULL || lwc_string_length(evt->type) == 0) { + return DOM_UNSPECIFIED_EVENT_TYPE_ERR; + } + + if (evt->doc == NULL) + return DOM_NOT_SUPPORTED_ERR; + + 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; + } + + struct dom_string *type = NULL; + err = _dom_document_create_string_from_lwcstring(doc, evt->type, &type); + if (err != DOM_NO_ERR) + return err; + + if (_dom_validate_ncname(type) == false) { + dom_string_unref(type); + return DOM_INVALID_CHARACTER_ERR; + } + dom_string_unref(type); + + lwc_string *t = evt->type; + lwc_context *ctx = NULL; + dom_event_target_entry list; + dom_event_target *target = et; + + ctx = _dom_document_get_intern_context(doc); + assert(t != NULL); + + *success = true; + + /* Compose the event target list */ + list_init(&list.entry); + list.et = et; + dom_node_ref(et); + target = target->parent; + + while (target != NULL) { + dom_event_target_entry *l = (dom_event_target_entry *) + _dom_document_alloc(doc, NULL, + sizeof(dom_event_target_entry)); + if (l == NULL) { + ret = DOM_NO_MEM_ERR; + goto cleanup; + } + list_append(&list.entry, &l->entry); + l->et = target; + dom_node_ref(target); + target = target->parent; + } + + /* Fill the target of the event */ + evt->target = et; + evt->phase = DOM_CAPTURING_PHASE; + + /* The capture phase */ + struct list_entry *e = list.entry.prev; + for (; e != &list.entry; e = e->prev) { + dom_event_target_entry *l = (dom_event_target_entry *) e; + err = _dom_event_target_dispatch(l->et, evt, + DOM_CAPTURING_PHASE, success); + if (err != DOM_NO_ERR) { + ret = err; + goto cleanup; + } + /* If the stopImmediatePropagation or stopPropagation is + * called, we should break */ + if (evt->stop_now == true || evt->stop == true) + goto cleanup; + } + + /* Target phase */ + evt->phase = DOM_AT_TARGET; + evt->current = et; + err = _dom_event_target_dispatch(et, evt, DOM_AT_TARGET, + success); + if (evt->stop_now == true || evt->stop == true) + goto cleanup; + + /* Bubbling phase */ + evt->phase = DOM_BUBBLING_PHASE; + + e = list.entry.next; + for (; e != &list.entry; e = e->next) { + dom_event_target_entry *l = (dom_event_target_entry *) e; + err = _dom_event_target_dispatch(l->et, evt, + DOM_BUBBLING_PHASE, success); + if (err != DOM_NO_ERR) { + ret = err; + goto cleanup; + } + /* If the stopImmediatePropagation or stopPropagation is + * called, we should break */ + if (evt->stop_now == true || evt->stop == true) + goto cleanup; + } + + struct dom_document_event_internal *dei = &doc->dei; + if (dei->actions == NULL || evt->prevent_default == true) + goto cleanup; + + /* The default action */ + struct dom_string *nodename; + err = dom_node_get_node_name(et, &nodename); + if (err != DOM_NO_ERR) { + ret = err; + goto cleanup; + } + lwc_string *lnodename = NULL; + lwc_context *lctx = NULL; + err = dom_string_get_intern(nodename, &lctx, &lnodename); + if (err != DOM_NO_ERR) { + dom_string_unref(nodename); + ret = err; + goto cleanup; + } + + dom_event_listener *da = dei->actions(lnodename, t); + if (da != NULL) { + da->handler(evt, da->pw); + } + + dom_string_unref(nodename); + lwc_context_string_unref(lctx, lnodename); + lwc_context_unref(lctx); + +cleanup: + if (evt->prevent_default == true) { + *success = false; + } + + while (list.entry.next != &list.entry) { + dom_event_target_entry *e = (dom_event_target_entry *) + list.entry.next; + dom_node_unref(e->et); + list_del(list.entry.next); + _dom_document_alloc(doc, e, 0); + } + + dom_node_unref(et); + + return ret; +} + +/** + * Add an EventListener + * + * \param et The EventTarget object + * \param namespace The namespace of this listener + * \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. + * + * We don't support this API now, so it always return DOM_NOT_SUPPORTED_ERR. + */ +dom_exception _dom_event_target_add_event_listener_ns(dom_event_target *et, + struct dom_string *namespace, struct dom_string *type, + struct dom_event_listener *listener, bool capture) +{ + UNUSED(et); + UNUSED(namespace); + UNUSED(type); + UNUSED(listener); + UNUSED(capture); + + return DOM_NOT_SUPPORTED_ERR; +} + +/** + * Remove an EventListener + * + * \param et The EventTarget object + * \param namespace The namespace of this listener + * \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. + * + * We don't support this API now, so it always return DOM_NOT_SUPPORTED_ERR. + */ +dom_exception _dom_event_target_remove_event_listener_ns(dom_event_target *et, + struct dom_string *namespace, struct dom_string *type, + struct dom_event_listener *listener, bool capture) +{ + UNUSED(et); + UNUSED(namespace); + UNUSED(type); + UNUSED(listener); + UNUSED(capture); + + return DOM_NOT_SUPPORTED_ERR; +} + +/*-------------------------------------------------------------------------*/ + +/* The key process function of the hash table, see utils/hash_table.h for + * detail */ +static void *_key(void *key, void *key_pw, dom_alloc alloc, void *pw, + bool clone) +{ + UNUSED(alloc); + UNUSED(pw); + /* There should never be the requirement of clone the event listener + * list */ + assert(clone == false); + UNUSED(clone); + + lwc_context *ctx = (lwc_context *) key_pw; + lwc_context_string_unref(ctx, (lwc_string *) key); + + return NULL; +} + +/* The value process function of the hash table, see utils/hash_table.h for + * detail */ +static void *_value(void *value, void *value_pw, dom_alloc alloc, + void *pw, bool clone) +{ + UNUSED(alloc); + UNUSED(pw); + /* There should never be the requirement of clone the event listener + * list */ + assert(clone == false); + UNUSED(clone); + + struct listener_entry *le = NULL; + struct dom_document *doc = (struct dom_document *) value_pw; + struct list_entry *i = (struct list_entry *) value; + + while(i != i->next) { + le = (struct listener_entry *) i->next; + list_del(i->next); + dom_event_listener_unref(le->listener); + _dom_document_alloc(doc, le, sizeof(struct listener_entry)); + } + + le = (struct listener_entry *) i; + list_del(i); + dom_event_listener_unref(le->listener); + _dom_document_alloc(doc, le, sizeof(struct listener_entry)); + + return NULL; +} + +/*-------------------------------------------------------------------------*/ + +/** + * Dispatch an event on certain EventTarget + * + * \param et The EventTarget object + * \param evt The event object + * \param success Indicates whether any of the listeners which handled the + * event called Event.preventDefault(). If + * Event.preventDefault() was called the returned value is + * false, else it is true. + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_event_target_dispatch(dom_event_target *et, + struct dom_event *evt, dom_event_flow_phase phase, + bool *success) +{ + struct dom_event_target_internal *eti = &et->eti; + lwc_string *t = evt->type; + + struct list_entry *item = (struct list_entry *) _dom_hash_get( + eti->listeners, t); + if (item == NULL) { + /* There is no such event listener */ + return DOM_NO_ERR; + } else { + /* Call the handler for each listener */ + struct list_entry *i = item; + /* Fill the Event fields */ + evt->current = et; + do { + struct listener_entry *le = + (struct listener_entry *) i; + assert(le->listener->handler != NULL); + if ((le->capture == true && + phase == DOM_CAPTURING_PHASE) || + (le->capture == false && + phase == DOM_BUBBLING_PHASE) || + (evt->target == evt->current && + phase == DOM_AT_TARGET)) { + /* We found the listener */ + le->listener->handler(evt, le->listener->pw); + /* If the handler call + * stopImmediatedPropagation, we should + * break */ + if (evt->stop_now == true) + break; + } + i = i->next; + } while(i != item); + } + + if (evt->prevent_default == true) + *success = false; + + return DOM_NO_ERR; +} + +/** + * 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 *) "DOMNodeRemovedFromDocument", + 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); + if (err != DOM_NO_ERR) + goto cleanup; + + err = dom_event_target_dispatch_event(target, evt, success); + if (err != DOM_NO_ERR) + goto cleanup; + + dom_event_target *p = dom_node_get_parent(target); + if (target->first_child != NULL) { + target = target->first_child; + } else if (target->next != NULL) { + target = target->next; + } else { + while (p != et && target == p->first_child) { + target = p; + p = dom_node_get_parent(p); + } + + target = target->next; + } + /* Finalise the event for reuse in next iteration */ + _dom_mutation_event_finalise(doc, evt); + } + +cleanup: + _dom_mutation_event_destroy(doc, evt); + + return err; +} + +/** + * Dispatch a DOMAttrModified event + * + * \param doc The Document object + * \param et The EventTarget + * \param prev The previous value before change + * \param new The new value after change + * \param related The related EventTarget + * \param attr_name The Attribute name + * \param change How this attribute change + * \param success Whether this event's default handler get called + * \return DOM_NO_ERR on success, appropirate dom_exception on failure. + */ +dom_exception _dom_dispatch_attr_modified_event(struct dom_document *doc, + dom_event_target *et, dom_string *prev, dom_string *new, + dom_event_target *related, dom_string *attr_name, + 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; + err = _dom_document_create_lwcstring(doc, + (const uint8_t *) "DOMAttrModified", + SLEN("DOMAttrModified"), &type); + if (err != DOM_NO_ERR) + goto cleanup; + + 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, prev, new, + attr_name, change); + dom_string_unref(t); + if (err != DOM_NO_ERR) { + goto cleanup; + } + + err = dom_event_target_dispatch_event(et, evt, success); + +cleanup: + _dom_mutation_event_destroy(doc, evt); + + return err; +} + +/** + * Dispatch a DOMCharacterDataModified event + * + * \param et The EventTarget object + * \param prev The preValue of the DOMCharacterData + * \param new The newValue of the DOMCharacterData + * \return DOM_NO_ERR on success, appropirate dom_exception on failure. + * + * TODO: + * The character_data object may be a part of a Attr node, if so, another + * DOMAttrModified event should be dispatched, too. But for now, we did not + * support any XML feature, so just leave it as this. + */ +dom_exception _dom_dispatch_characterdata_modified_event( + struct dom_document *doc, dom_event_target *et, + dom_string *prev, dom_string *new, 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; + err = _dom_document_create_lwcstring(doc, + (const uint8_t *) "DOMCharacterDataModified", + SLEN("DOMCharacterDataModified"), &type); + if (err != DOM_NO_ERR) + goto cleanup; + + 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; + + err = dom_mutation_event_init(evt, t, true, false, et, prev, new, NULL, + DOM_MUTATION_MODIFICATION); + dom_string_unref(t); + if (err != DOM_NO_ERR) { + goto cleanup; + } + + err = dom_event_target_dispatch_event(et, evt, success); + +cleanup: + _dom_mutation_event_destroy(doc, evt); + + return err; +} + +/** + * Dispatch a DOMSubtreeModified event + * + * \param doc The Document + * \param et The EventTarget object + * \param success The newValue of the DOMCharacterData + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_dispatch_subtree_modified_event(struct dom_document *doc, + dom_event_target *et, 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; + err = _dom_document_create_lwcstring(doc, + (const uint8_t *) "DOMSubtreeModified", + SLEN("DOMSubtreeModified"), &type); + if (err != DOM_NO_ERR) + goto cleanup; + + 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; + + err = dom_mutation_event_init(evt, t, true, false, et, NULL, NULL, NULL, + DOM_MUTATION_MODIFICATION); + dom_string_unref(t); + if (err != DOM_NO_ERR) { + goto cleanup; + } + + err = dom_event_target_dispatch_event(et, evt, success); + +cleanup: + _dom_mutation_event_destroy(doc, evt); + + return err; +} + diff --git a/src/events/event_target.h b/src/events/event_target.h new file mode 100644 index 0000000..a92963e --- /dev/null +++ b/src/events/event_target.h @@ -0,0 +1,88 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_internal_events_event_target_h_ +#define dom_internal_events_event_target_h_ + +#include +#include +#include +#include + +#include "utils/list.h" +#include "utils/hashtable.h" + +struct dom_document; +struct dom_string; + +/** + * Listener Entry + */ +struct listener_entry { + struct list_entry list; + /**< The listener list registered at the same + * EventTarget */ + dom_event_listener *listener; /**< The EventListener */ + bool capture; /**< Whether this listener is in capture phase */ +}; + +/** + * EventTarget internal class + */ +struct dom_event_target_internal { + struct dom_hash_table *listeners; + /**< The listeners of this EventTarget. + * The listeners are organized by the + * type of events they listen for + */ + struct dom_hash_table *ns_listeners; + /**< The listeners with namespace of thie EventTarget */ +}; + +typedef struct dom_event_target_internal dom_event_target_internal; + +/** + * Constructor and destructor: Since this object is not intended to be + * allocated alone, it should be embedded into the Node object, there is + * no constructor and destructor for it. + */ + +/* Initialise this EventTarget */ +dom_exception _dom_event_target_internal_initialise(struct dom_document *doc, + dom_event_target_internal *eti); + +/* Finalise this EventTarget */ +void _dom_event_target_internal_finalise(struct dom_document *doc, + dom_event_target_internal *eti); + +/* Dispatch the event on this node */ +dom_exception _dom_event_target_dispatch(dom_event_target *et, + struct dom_event *evt, dom_event_flow_phase phase, + bool *success); + +/* Dispatch a DOMNodeInserted/DOMNodeRemoved event */ +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); + +/* Dispatch a DOMCharacterDataModified event */ +dom_exception _dom_dispatch_characterdata_modified_event( + struct dom_document *doc, dom_event_target *et, + struct dom_string *prev, struct dom_string *new, bool *success); + +/* Dispatch a DOMAttrModified event */ +dom_exception _dom_dispatch_attr_modified_event(struct dom_document *doc, + dom_event_target *et, struct dom_string *prev, + struct dom_string *new, dom_event_target *related, + struct dom_string *attr_name, dom_mutation_type change, + bool *success); + +/* Dispatch a DOMSubtreeModified event */ +dom_exception _dom_dispatch_subtree_modified_event(struct dom_document *doc, + dom_event_target *et, bool *success); + +#endif diff --git a/src/events/keyboard_event.c b/src/events/keyboard_event.c new file mode 100644 index 0000000..b8fc3ba --- /dev/null +++ b/src/events/keyboard_event.c @@ -0,0 +1,354 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include + +#include "events/keyboard_event.h" +#include "core/document.h" + +#include "utils/utils.h" + +static void _virtual_dom_keyboard_event_destroy(struct dom_event *evt); + +static struct dom_event_private_vtable _event_vtable = { + _virtual_dom_keyboard_event_destroy +}; + +/* Constructor */ +dom_exception _dom_keyboard_event_create(struct dom_document *doc, + struct dom_keyboard_event **evt) +{ + *evt = _dom_document_alloc(doc, NULL, sizeof(dom_keyboard_event)); + if (*evt == NULL) + return DOM_NO_MEM_ERR; + + ((struct dom_event *) *evt)->vtable = &_event_vtable; + + return _dom_keyboard_event_initialise(doc, *evt); +} + +/* Destructor */ +void _dom_keyboard_event_destroy(struct dom_document *doc, + struct dom_keyboard_event *evt) +{ + _dom_keyboard_event_finalise(doc, evt); + + _dom_document_alloc(doc, evt, 0); +} + +/* Initialise function */ +dom_exception _dom_keyboard_event_initialise(struct dom_document *doc, + struct dom_keyboard_event *evt) +{ + evt->key_ident = NULL; + evt->modifier_state = 0; + + return _dom_ui_event_initialise(doc, &evt->base); +} + +/* Finalise function */ +void _dom_keyboard_event_finalise(struct dom_document *doc, + struct dom_keyboard_event *evt) +{ + _dom_ui_event_finalise(doc, &evt->base); +} + +/* The virtual destroy function */ +void _virtual_dom_keyboard_event_destroy(struct dom_event *evt) +{ + _dom_keyboard_event_destroy(evt->doc, (dom_keyboard_event *) evt); +} + +/*----------------------------------------------------------------------*/ +/* The public API */ + +/** + * Get the key identifier + * + * \param evt The Event object + * \param ident The returned key identifier + * \return DOM_NO_ERR. + */ +dom_exception _dom_keyboard_event_get_key_identifier(dom_keyboard_event *evt, + struct dom_string **ident) +{ + *ident = evt->key_ident; + dom_string_ref(*ident); + + return DOM_NO_ERR; +} + +/** + * Get the key location + * + * \param evt The Event object + * \param loc The returned key location + * \return DOM_NO_ERR. + */ +dom_exception _dom_keyboard_event_get_key_location(dom_keyboard_event *evt, + dom_key_location *loc) +{ + *loc = evt->key_loc; + + return DOM_NO_ERR; +} + +/** + * Get the ctrl key state + * + * \param evt The Event object + * \param key Whether the Control key is pressed down + * \return DOM_NO_ERR. + */ +dom_exception _dom_keyboard_event_get_ctrl_key(dom_keyboard_event *evt, + bool *key) +{ + *key = ((evt->modifier_state & DOM_MOD_CTRL) != 0); + + return DOM_NO_ERR; +} + +/** + * Get the shift key state + * + * \param evt The Event object + * \param key Whether the Shift key is pressed down + * \return DOM_NO_ERR. + */ +dom_exception _dom_keyboard_event_get_shift_key(dom_keyboard_event *evt, + bool *key) +{ + *key = ((evt->modifier_state & DOM_MOD_SHIFT) != 0); + + return DOM_NO_ERR; +} + +/** + * Get the alt key state + * + * \param evt The Event object + * \param key Whether the Alt key is pressed down + * \return DOM_NO_ERR. + */ +dom_exception _dom_keyboard_event_get_alt_key(dom_keyboard_event *evt, + bool *key) +{ + *key = ((evt->modifier_state & DOM_MOD_ALT) != 0); + + return DOM_NO_ERR; +} + +/** + * Get the meta key state + * + * \param evt The Event object + * \param key Whether the Meta key is pressed down + * \return DOM_NO_ERR. + */ +dom_exception _dom_keyboard_event_get_meta_key(dom_keyboard_event *evt, + bool *key) +{ + *key = ((evt->modifier_state & DOM_MOD_META) != 0); + + return DOM_NO_ERR; +} + +/** + * 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 (len == SLEN("AltGraph") && strncmp(data, "AltGraph", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_ALT_GRAPH) != 0); + } else if (len == SLEN("Alt") && strncmp(data, "Alt", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_ALT) != 0); + } else if (len == SLEN("CapsLock") && + strncmp(data, "CapsLock", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_CAPS_LOCK) != 0); + } else if (len == SLEN("Control") && + strncmp(data, "Control", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_CTRL) != 0); + } else if (len == SLEN("Meta") && strncmp(data, "Meta", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_META) != 0); + } else if (len == SLEN("NumLock") && + strncmp(data, "NumLock", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_NUM_LOCK) != 0); + } else if (len == SLEN("Scroll") && + strncmp(data, "Scroll", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_SCROLL) != 0); + } else if (len == SLEN("Shift") && strncmp(data, "Shift", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_SHIFT) != 0); + } + + return DOM_NO_ERR; +} + +/** + * Initialise the keyboard event + * + * \param evt The Event object + * \param type The event's type + * \param bubble Whether this is a bubbling event + * \param cancelable Whether this is a cancelable event + * \param view The AbstractView associated with this event + * \param key_indent The key identifier of pressed key + * \param key_loc The key location of the preesed key + * \param modifier_list A string of modifier key identifiers, separated with + * space + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_keyboard_event_init(dom_keyboard_event *evt, + struct dom_string *type, bool bubble, bool cancelable, + struct dom_abstract_view *view, struct dom_string *key_ident, + dom_key_location key_loc, struct dom_string *modifier_list) +{ + dom_exception err; + + evt->key_ident = key_ident; + dom_string_ref(evt->key_ident); + evt->key_loc = key_loc; + + err = _dom_parse_modifier_list(modifier_list, &evt->modifier_state); + if (err != DOM_NO_ERR) + return err; + + return _dom_ui_event_init(&evt->base, type, bubble, cancelable, + view, 0); +} + +/** + * Initialise the keyboard event with namespace + * + * \param evt The Event object + * \param namespace The namespace of this event + * \param type The event's type + * \param bubble Whether this is a bubbling event + * \param cancelable Whether this is a cancelable event + * \param view The AbstractView associated with this event + * \param key_indent The key identifier of pressed key + * \param key_loc The key location of the preesed key + * \param modifier_list A string of modifier key identifiers, separated with + * space + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_keyboard_event_init_ns(dom_keyboard_event *evt, + struct dom_string *namespace, struct dom_string *type, + bool bubble, bool cancelable, struct dom_abstract_view *view, + struct dom_string *key_ident, dom_key_location key_loc, + struct dom_string *modifier_list) +{ + dom_exception err; + + evt->key_ident = key_ident; + dom_string_ref(evt->key_ident); + evt->key_loc = key_loc; + + err = _dom_parse_modifier_list(modifier_list, &evt->modifier_state); + if (err != DOM_NO_ERR) + return err; + + return _dom_ui_event_init_ns(&evt->base, namespace, type, bubble, + cancelable, view, 0); +} + + +/*-------------------------------------------------------------------------*/ + +/** + * Parse the modifier list string to corresponding bool variable state + * + * \param modifier_list The modifier list string + * \param modifier_state The returned state + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_parse_modifier_list(struct dom_string *modifier_list, + uint32_t *modifier_state) +{ + *modifier_state = 0; + + if (modifier_list == NULL) + return DOM_NO_ERR; + + char *data = _dom_string_data(modifier_list); + char *m = data; + size_t len = 0; + + while (true) { + /* If we reach a space or end of the string, we should parse + * the new token. */ + if (*data == ' ' || *data == '\0') { + if (len == SLEN("AltGraph") && + strncmp(data, "AltGraph", len) == 0) { + *modifier_state = *modifier_state | + DOM_MOD_ALT_GRAPH; + } else if (len == SLEN("Alt") && + strncmp(data, "Alt", len) == 0) { + *modifier_state = *modifier_state | + DOM_MOD_ALT; + } else if (len == SLEN("CapsLock") && + strncmp(data, "CapsLock", len) == 0) { + *modifier_state = *modifier_state | + DOM_MOD_CAPS_LOCK; + } else if (len == SLEN("Control") && + strncmp(data, "Control", len) == 0) { + *modifier_state = *modifier_state | + DOM_MOD_CTRL; + } else if (len == SLEN("Meta") && + strncmp(data, "Meta", len) == 0) { + *modifier_state = *modifier_state | + DOM_MOD_META; + } else if (len == SLEN("NumLock") && + strncmp(data, "NumLock", len) == 0) { + *modifier_state = *modifier_state | + DOM_MOD_NUM_LOCK; + } else if (len == SLEN("Scroll") && + strncmp(data, "Scroll", len) == 0) { + *modifier_state = *modifier_state | + DOM_MOD_SCROLL; + } else if (len == SLEN("Shift") && + strncmp(data, "Shift", len) == 0) { + *modifier_state = *modifier_state | + DOM_MOD_SHIFT; + } + + while (*data == ' ') { + data++; + } + /* Finished parsing and break */ + if (*data == '\0') + break; + + m = data; + len = 0; + } + + data++; + len++; + } + + return DOM_NO_ERR; +} + diff --git a/src/events/keyboard_event.h b/src/events/keyboard_event.h new file mode 100644 index 0000000..4d2777c --- /dev/null +++ b/src/events/keyboard_event.h @@ -0,0 +1,55 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_interntal_events_keyboard_event_h_ +#define dom_interntal_events_keyboard_event_h_ + +#include + +#include "events/ui_event.h" + +/** + * 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 + */ + + uint32_t modifier_state; /**< The modifier keys state */ +}; + +/* Constructor */ +dom_exception _dom_keyboard_event_create(struct dom_document *doc, + struct dom_keyboard_event **evt); + +/* Destructor */ +void _dom_keyboard_event_destroy(struct dom_document *doc, + struct dom_keyboard_event *evt); + +/* Initialise function */ +dom_exception _dom_keyboard_event_initialise(struct dom_document *doc, + struct dom_keyboard_event *evt); + +/* Finalise function */ +void _dom_keyboard_event_finalise(struct dom_document *doc, + struct dom_keyboard_event *evt); + + +/* Parse the modifier list string to corresponding bool variable state */ +dom_exception _dom_parse_modifier_list(struct dom_string *modifier_list, + uint32_t *modifier_state); + +#endif diff --git a/src/events/mouse_event.c b/src/events/mouse_event.c new file mode 100644 index 0000000..1b31012 --- /dev/null +++ b/src/events/mouse_event.c @@ -0,0 +1,366 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include + +#include "events/mouse_event.h" +#include "core/document.h" + +#include "utils/utils.h" + +static void _virtual_dom_mouse_event_destroy(struct dom_event *evt); + +static struct dom_event_private_vtable _event_vtable = { + _virtual_dom_mouse_event_destroy +}; + +/* Constructor */ +dom_exception _dom_mouse_event_create(struct dom_document *doc, + struct dom_mouse_event **evt) +{ + *evt = _dom_document_alloc(doc, NULL, sizeof(dom_mouse_event)); + if (*evt == NULL) + return DOM_NO_MEM_ERR; + + ((struct dom_event *) *evt)->vtable = &_event_vtable; + + return _dom_mouse_event_initialise(doc, *evt); +} + +/* Destructor */ +void _dom_mouse_event_destroy(struct dom_document *doc, + struct dom_mouse_event *evt) +{ + _dom_mouse_event_finalise(doc, (dom_ui_event *) evt); + + _dom_document_alloc(doc, evt, 0); +} + +/* Initialise function */ +dom_exception _dom_mouse_event_initialise(struct dom_document *doc, + struct dom_mouse_event *evt) +{ + evt->modifier_state = 0; + + return _dom_ui_event_initialise(doc, (dom_ui_event *) evt); +} + +/* The virtual destroy function */ +void _virtual_dom_mouse_event_destroy(struct dom_event *evt) +{ + _dom_mouse_event_destroy(evt->doc, (dom_mouse_event *) evt); +} + +/*----------------------------------------------------------------------*/ +/* The public API */ + +/** + * Get screenX + * + * \param evt The Event object + * \param x The returned screenX + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_event_get_screen_x(dom_mouse_event *evt, + long *x) +{ + *x = evt->sx; + + return DOM_NO_ERR; +} + +/** + * Get screenY + * + * \param evt The Event object + * \param y The returned screenY + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_event_get_screen_y(dom_mouse_event *evt, + long *y) +{ + *y = evt->sy; + + return DOM_NO_ERR; +} + +/** + * Get clientX + * + * \param evt The Event object + * \param x The returned clientX + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_event_get_client_x(dom_mouse_event *evt, + long *x) +{ + *x = evt->cx; + + return DOM_NO_ERR; +} + +/** + * Get clientY + * + * \param evt The Event object + * \param y The returned clientY + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_event_get_client_y(dom_mouse_event *evt, + long *y) +{ + *y = evt->cy; + + return DOM_NO_ERR; +} + +/** + * Get the ctrl key state + * + * \param evt The Event object + * \param key Whether the Control key is pressed down + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_event_get_ctrl_key(dom_mouse_event *evt, + bool *key) +{ + *key = ((evt->modifier_state & DOM_MOD_CTRL) != 0); + + return DOM_NO_ERR; +} + +/** + * Get the shift key state + * + * \param evt The Event object + * \param key Whether the Shift key is pressed down + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_event_get_shift_key(dom_mouse_event *evt, + bool *key) +{ + *key = ((evt->modifier_state & DOM_MOD_SHIFT) != 0); + + return DOM_NO_ERR; +} + +/** + * Get the alt key state + * + * \param evt The Event object + * \param key Whether the Alt key is pressed down + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_event_get_alt_key(dom_mouse_event *evt, + bool *key) +{ + *key = ((evt->modifier_state & DOM_MOD_ALT) != 0); + + return DOM_NO_ERR; +} + +/** + * Get the meta key state + * + * \param evt The Event object + * \param key Whether the Meta key is pressed down + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_event_get_meta_key(dom_mouse_event *evt, + bool *key) +{ + *key = ((evt->modifier_state & DOM_MOD_META) != 0); + + return DOM_NO_ERR; +} + +/** + * Get the button which get pressed + * + * \param evt The Event object + * \param button The pressed mouse button + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_event_get_button(dom_mouse_event *evt, + unsigned short *button) +{ + *button = evt->button; + + return DOM_NO_ERR; +} + +/** + * Get the related target + * + * \param evt The Event object + * \param et The related EventTarget + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_event_get_related_target(dom_mouse_event *evt, + dom_event_target **et) +{ + *et = evt->related_target; + + return DOM_NO_ERR; +} + +/** + * 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 (len == SLEN("AltGraph") && strncmp(data, "AltGraph", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_ALT_GRAPH) != 0); + } else if (len == SLEN("Alt") && strncmp(data, "Alt", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_ALT) != 0); + } else if (len == SLEN("CapsLock") && + strncmp(data, "CapsLock", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_CAPS_LOCK) != 0); + } else if (len == SLEN("Control") && + strncmp(data, "Control", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_CTRL) != 0); + } else if (len == SLEN("Meta") && strncmp(data, "Meta", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_META) != 0); + } else if (len == SLEN("NumLock") && + strncmp(data, "NumLock", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_NUM_LOCK) != 0); + } else if (len == SLEN("Scroll") && + strncmp(data, "Scroll", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_SCROLL) != 0); + } else if (len == SLEN("Shift") && strncmp(data, "Shift", len) == 0) { + *state = ((evt->modifier_state & DOM_MOD_SHIFT) != 0); + } + + return DOM_NO_ERR; +} + +/** + * Initialise this mouse event + * + * \param evt The Event object + * \param type The event's type + * \param bubble Whether this is a bubbling event + * \param cancelable Whether this is a cancelable event + * \param view The AbstractView associated with this event + * \param detail The detail information of this mouse event + * \param screen_x The x position of the mouse pointer in screen + * \param screen_y The y position of the mouse pointer in screen + * \param client_x The x position of the mouse pointer in client window + * \param client_y The y position of the mouse pointer in client window + * \param alt The state of Alt key, true for pressed, false otherwise + * \param shift The state of Shift key, true for pressed, false otherwise + * \param mata The state of Meta key, true for pressed, false otherwise + * \param button The mouse button pressed + * \param et The related target of this event, may be NULL + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_mouse_event_init(dom_mouse_event *evt, + struct dom_string *type, bool bubble, bool cancelable, + struct dom_abstract_view *view, long detail, long screen_x, + long screen_y, long client_x, long client_y, bool ctrl, + bool alt, bool shift, bool meta, unsigned short button, + dom_event_target *et) +{ + evt->sx = screen_x; + evt->sy = screen_y; + evt->cx = client_x; + evt->cy = client_y; + + evt->modifier_state = 0; + if (ctrl == true) { + evt->modifier_state = evt->modifier_state | DOM_MOD_CTRL; + } + if (alt == true) { + evt->modifier_state = evt->modifier_state | DOM_MOD_ALT; + } + if (shift == true) { + evt->modifier_state = evt->modifier_state | DOM_MOD_SHIFT; + } + if (meta == true) { + evt->modifier_state = evt->modifier_state | DOM_MOD_META; + } + + evt->button = button; + evt->related_target = et; + + return _dom_ui_event_init(&evt->base, type, bubble, cancelable, view, + detail); +} + +/** + * Initialise the event with namespace + * + * \param evt The Event object + * \param namespace The namespace of this event + * \param type The event's type + * \param bubble Whether this is a bubbling event + * \param cancelable Whether this is a cancelable event + * \param view The AbstractView associated with this event + * \param detail The detail information of this mouse event + * \param screen_x The x position of the mouse pointer in screen + * \param screen_y The y position of the mouse pointer in screen + * \param client_x The x position of the mouse pointer in client window + * \param client_y The y position of the mouse pointer in client window + * \param alt The state of Alt key, true for pressed, false otherwise + * \param shift The state of Shift key, true for pressed, false otherwise + * \param mata The state of Meta key, true for pressed, false otherwise + * \param button The mouse button pressed + * \param et The related target of this event, may be NULL + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_mouse_event_init_ns(dom_mouse_event *evt, + struct dom_string *namespace, struct dom_string *type, + bool bubble, bool cancelable, struct dom_abstract_view *view, + long detail, long screen_x, long screen_y, long client_x, + long client_y, bool ctrl, bool alt, bool shift, bool meta, + unsigned short button, dom_event_target *et) +{ + evt->sx = screen_x; + evt->sy = screen_y; + evt->cx = client_x; + evt->cy = client_y; + + evt->modifier_state = 0; + if (ctrl == true) { + evt->modifier_state = evt->modifier_state | DOM_MOD_CTRL; + } + if (alt == true) { + evt->modifier_state = evt->modifier_state | DOM_MOD_ALT; + } + if (shift == true) { + evt->modifier_state = evt->modifier_state | DOM_MOD_SHIFT; + } + if (meta == true) { + evt->modifier_state = evt->modifier_state | DOM_MOD_META; + } + + evt->button = button; + evt->related_target = et; + + return _dom_ui_event_init_ns(&evt->base, namespace, type, bubble, + cancelable, view, detail); +} + diff --git a/src/events/mouse_event.h b/src/events/mouse_event.h new file mode 100644 index 0000000..f5117a1 --- /dev/null +++ b/src/events/mouse_event.h @@ -0,0 +1,49 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_interntal_events_mouse_event_h_ +#define dom_interntal_events_mouse_event_h_ + +#include + +#include "events/ui_event.h" + +/** + * 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 */ + + uint32_t modifier_state; /**< The modifier keys state */ + + unsigned short button; /**< Which button is clicked */ + dom_event_target *related_target; /**< The related target */ +}; + +/* Constructor */ +dom_exception _dom_mouse_event_create(struct dom_document *doc, + struct dom_mouse_event **evt); + +/* Destructor */ +void _dom_mouse_event_destroy(struct dom_document *doc, + struct dom_mouse_event *evt); + +/* Initialise function */ +dom_exception _dom_mouse_event_initialise(struct dom_document *doc, + struct dom_mouse_event *evt); + +/* Finalise function */ +#define _dom_mouse_event_finalise _dom_ui_event_finalise + + +#endif + diff --git a/src/events/mouse_multi_wheel_event.c b/src/events/mouse_multi_wheel_event.c new file mode 100644 index 0000000..bca9c97 --- /dev/null +++ b/src/events/mouse_multi_wheel_event.c @@ -0,0 +1,152 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include "events/mouse_multi_wheel_event.h" +#include "events/keyboard_event.h" +#include "core/document.h" + +#include "utils/utils.h" + +static void _virtual_dom_mouse_multi_wheel_event_destroy( + struct dom_event *evt); + +static struct dom_event_private_vtable _event_vtable = { + _virtual_dom_mouse_multi_wheel_event_destroy +}; + +/* Constructor */ +dom_exception _dom_mouse_multi_wheel_event_create(struct dom_document *doc, + struct dom_mouse_multi_wheel_event **evt) +{ + *evt = _dom_document_alloc(doc, NULL, + sizeof(dom_mouse_multi_wheel_event)); + if (*evt == NULL) + return DOM_NO_MEM_ERR; + + ((struct dom_event *) *evt)->vtable = &_event_vtable; + + return _dom_mouse_multi_wheel_event_initialise(doc, *evt); +} + +/* Destructor */ +void _dom_mouse_multi_wheel_event_destroy(struct dom_document *doc, + struct dom_mouse_multi_wheel_event *evt) +{ + _dom_mouse_multi_wheel_event_finalise(doc, (dom_ui_event *) evt); + + _dom_document_alloc(doc, evt, 0); +} + +/* Initialise function */ +dom_exception _dom_mouse_multi_wheel_event_initialise(struct dom_document *doc, + struct dom_mouse_multi_wheel_event *evt) +{ + return _dom_mouse_event_initialise(doc, (dom_mouse_event *) evt); +} + +/* The virtual destroy function */ +void _virtual_dom_mouse_multi_wheel_event_destroy(struct dom_event *evt) +{ + _dom_mouse_multi_wheel_event_destroy(evt->doc, + (dom_mouse_multi_wheel_event *) evt); +} + +/*----------------------------------------------------------------------*/ +/* The public API */ + +/** + * Get wheelDeltaX + * + * \param evt The Event object + * \param x The returned wheelDeltaX + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_multi_wheel_event_get_wheel_delta_x( + dom_mouse_multi_wheel_event *evt, long *x) +{ + *x = evt->x; + + return DOM_NO_ERR; +} + +/** + * Get wheelDeltaY + * + * \param evt The Event object + * \param y The returned wheelDeltaY + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_multi_wheel_event_get_wheel_delta_y( + dom_mouse_multi_wheel_event *evt, long *y) +{ + *y = evt->y; + + return DOM_NO_ERR; +} + +/** + * Get wheelDeltaZ + * + * \param evt The Event object + * \param z The returned wheelDeltaZ + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_multi_wheel_event_get_wheel_delta_z( + dom_mouse_multi_wheel_event *evt, long *z) +{ + *z = evt->z; + + return DOM_NO_ERR; +} + +/** + * Intialise this event with namespace + * + * \param evt The Event object + * \param namespace The namespace of this event + * \param type The event's type + * \param bubble Whether this is a bubbling event + * \param cancelable Whether this is a cancelable event + * \param view The AbstractView associated with this event + * \param detail The detail information of this mouse event + * \param screen_x The x position of the mouse pointer in screen + * \param screen_y The y position of the mouse pointer in screen + * \param client_x The x position of the mouse pointer in client window + * \param client_y The y position of the mouse pointer in client window + * \param button The mouse button pressed + * \param et The related target of this event, may be NULL + * \param modifier_list The string contains the modifier identifier strings + * \param wheel_delta_x The wheelDeltaX + * \param wheel_delta_y The wheelDeltaY + * \param wheel_delta_z The wheelDeltaZ + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_mouse_multi_wheel_event_init_ns( + dom_mouse_multi_wheel_event *evt, struct dom_string *namespace, + struct dom_string *type, bool bubble, bool cancelable, + struct dom_abstract_view *view, long detail, long screen_x, + long screen_y, long client_x, long client_y, + unsigned short button, dom_event_target *et, + struct dom_string *modifier_list, long wheel_delta_x, + long wheel_delta_y, long wheel_delta_z) +{ + dom_exception err; + evt->x = wheel_delta_x; + evt->y = wheel_delta_y; + evt->z = wheel_delta_z; + + dom_mouse_event *e = (dom_mouse_event *) evt; + + err = _dom_parse_modifier_list(modifier_list, &e->modifier_state); + if (err != DOM_NO_ERR) + return err; + + return _dom_mouse_event_init_ns(&evt->base, namespace, type, bubble, + cancelable, view, detail ,screen_x, screen_y, client_x, + client_y, false, false, false, false, button, et); +} + diff --git a/src/events/mouse_multi_wheel_event.h b/src/events/mouse_multi_wheel_event.h new file mode 100644 index 0000000..043efb8 --- /dev/null +++ b/src/events/mouse_multi_wheel_event.h @@ -0,0 +1,44 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_events_internal_mouse_multi_wheel_event_h_ +#define dom_events_internal_mouse_multi_wheel_event_h_ + +#include + +#include "events/mouse_event.h" + +/** + * The MouseMultiWheelEvent + */ +struct dom_mouse_multi_wheel_event { + struct dom_mouse_event base; /**< The base class */ + + long x; /**< The wheelDeltaX */ + long y; /**< The wheelDeltaY */ + long z; /**< The wheelDeltaZ */ +}; + +/* Constructor */ +dom_exception _dom_mouse_multi_wheel_event_create(struct dom_document *doc, + struct dom_mouse_multi_wheel_event **evt); + +/* Destructor */ +void _dom_mouse_multi_wheel_event_destroy(struct dom_document *doc, + struct dom_mouse_multi_wheel_event *evt); + +/* Initialise function */ +dom_exception _dom_mouse_multi_wheel_event_initialise(struct dom_document *doc, + struct dom_mouse_multi_wheel_event *evt); + +/* Finalise function */ +#define _dom_mouse_multi_wheel_event_finalise _dom_mouse_event_finalise + + +#endif + + diff --git a/src/events/mouse_wheel_event.c b/src/events/mouse_wheel_event.c new file mode 100644 index 0000000..c38ae3e --- /dev/null +++ b/src/events/mouse_wheel_event.c @@ -0,0 +1,115 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include "events/mouse_wheel_event.h" +#include "events/keyboard_event.h" +#include "core/document.h" + +#include "utils/utils.h" + +static void _virtual_dom_mouse_wheel_event_destroy(struct dom_event *evt); + +static struct dom_event_private_vtable _event_vtable = { + _virtual_dom_mouse_wheel_event_destroy +}; + +/* Constructor */ +dom_exception _dom_mouse_wheel_event_create(struct dom_document *doc, + struct dom_mouse_wheel_event **evt) +{ + *evt = _dom_document_alloc(doc, NULL, sizeof(dom_mouse_wheel_event)); + if (*evt == NULL) + return DOM_NO_MEM_ERR; + + ((struct dom_event *) *evt)->vtable = &_event_vtable; + + return _dom_mouse_wheel_event_initialise(doc, + (dom_mouse_wheel_event *) *evt); +} + +/* Destructor */ +void _dom_mouse_wheel_event_destroy(struct dom_document *doc, + struct dom_mouse_wheel_event *evt) +{ + _dom_mouse_wheel_event_finalise(doc, (dom_ui_event *) evt); + + _dom_document_alloc(doc, evt, 0); +} + +/* Initialise function */ +dom_exception _dom_mouse_wheel_event_initialise(struct dom_document *doc, + struct dom_mouse_wheel_event *evt) +{ + return _dom_mouse_event_initialise(doc, (dom_mouse_event *) evt); +} + +/* The virtual destroy function */ +void _virtual_dom_mouse_wheel_event_destroy(struct dom_event *evt) +{ + _dom_mouse_wheel_event_destroy(evt->doc, (dom_mouse_wheel_event *) evt); +} + +/*----------------------------------------------------------------------*/ +/* The public API */ + +/** + * Get wheelDelta + * + * \param evt The Event object + * \param d The wheelDelta + * \return DOM_NO_ERR. + */ +dom_exception _dom_mouse_wheel_event_get_wheel_delta( + dom_mouse_wheel_event *evt, long *d) +{ + *d = evt->delta; + + return DOM_NO_ERR; +} + +/** + * Intialise this event with namespace + * + * \param evt The Event object + * \param namespace The namespace of this event + * \param type The event's type + * \param bubble Whether this is a bubbling event + * \param cancelable Whether this is a cancelable event + * \param view The AbstractView associated with this event + * \param detail The detail information of this mouse event + * \param screen_x The x position of the mouse pointer in screen + * \param screen_y The y position of the mouse pointer in screen + * \param client_x The x position of the mouse pointer in client window + * \param client_y The y position of the mouse pointer in client window + * \param button The mouse button pressed + * \param et The related target of this event, may be NULL + * \param modifier_list The string contains the modifier identifier strings + * \param wheel_delta The wheelDelta + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_mouse_wheel_event_init_ns( + dom_mouse_wheel_event *evt, struct dom_string *namespace, + struct dom_string *type, bool bubble, bool cancelable, + struct dom_abstract_view *view, long detail, long screen_x, + long screen_y, long client_x, long client_y, + unsigned short button, dom_event_target *et, + struct dom_string *modifier_list, long wheel_delta) +{ + dom_exception err; + evt->delta = wheel_delta; + dom_mouse_event *e = (dom_mouse_event *) evt; + + err = _dom_parse_modifier_list(modifier_list, &e->modifier_state); + if (err != DOM_NO_ERR) + return err; + + return _dom_mouse_event_init_ns(&evt->base, namespace, type, bubble, + cancelable, view, detail ,screen_x, screen_y, + client_x, client_y, false, false, false, false, + button, et); +} + diff --git a/src/events/mouse_wheel_event.h b/src/events/mouse_wheel_event.h new file mode 100644 index 0000000..ba613e5 --- /dev/null +++ b/src/events/mouse_wheel_event.h @@ -0,0 +1,40 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_events_internal_mouse_wheel_event_h_ +#define dom_events_internal_mouse_wheel_event_h_ + +#include + +#include "events/mouse_event.h" + +/** + * The MouseWheelEvent + */ +struct dom_mouse_wheel_event { + struct dom_mouse_event base; /**< The base class */ + + long delta; /**< The wheelDelta */ +}; + +/* Constructor */ +dom_exception _dom_mouse_wheel_event_create(struct dom_document *doc, + struct dom_mouse_wheel_event **evt); + +/* Destructor */ +void _dom_mouse_wheel_event_destroy(struct dom_document *doc, + struct dom_mouse_wheel_event *evt); + +/* Initialise function */ +dom_exception _dom_mouse_wheel_event_initialise(struct dom_document *doc, + struct dom_mouse_wheel_event *evt); + +/* Finalise function */ +#define _dom_mouse_wheel_event_finalise _dom_mouse_event_finalise + +#endif + diff --git a/src/events/mutation_event.c b/src/events/mutation_event.c new file mode 100644 index 0000000..ea7163c --- /dev/null +++ b/src/events/mutation_event.c @@ -0,0 +1,226 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include "events/mutation_event.h" +#include "core/document.h" + +static void _virtual_dom_mutation_event_destroy(struct dom_event *evt); + +static struct dom_event_private_vtable _event_vtable = { + _virtual_dom_mutation_event_destroy +}; + +/* Constructor */ +dom_exception _dom_mutation_event_create(struct dom_document *doc, + struct dom_mutation_event **evt) +{ + *evt = _dom_document_alloc(doc, NULL, sizeof(dom_mutation_event)); + if (*evt == NULL) + return DOM_NO_MEM_ERR; + + ((struct dom_event *) *evt)->vtable = &_event_vtable; + + return _dom_mutation_event_initialise(doc, *evt); +} + +/* Destructor */ +void _dom_mutation_event_destroy(struct dom_document *doc, + struct dom_mutation_event *evt) +{ + _dom_mutation_event_finalise(doc, evt); + + _dom_document_alloc(doc, evt, 0); +} + +/* Initialise function */ +dom_exception _dom_mutation_event_initialise(struct dom_document *doc, + struct dom_mutation_event *evt) +{ + evt->related_node = NULL; + evt->prev_value = NULL; + evt->new_value = NULL; + evt->attr_name = NULL; + + return _dom_event_initialise(doc, &evt->base); +} + +/* Finalise function */ +void _dom_mutation_event_finalise(struct dom_document *doc, + struct dom_mutation_event *evt) +{ + dom_node_unref(evt->related_node); + dom_string_unref(evt->prev_value); + dom_string_unref(evt->new_value); + dom_string_unref(evt->attr_name); + + _dom_event_finalise(doc, &evt->base); +} + +/* The virtual destroy function */ +void _virtual_dom_mutation_event_destroy(struct dom_event *evt) +{ + _dom_mutation_event_destroy(evt->doc, (dom_mutation_event *) evt); +} + +/*----------------------------------------------------------------------*/ +/* The public API */ + +/** + * Get the related node + * + * \param evt The Event object + * \param node The related node + * \return DOM_NO_ERR. + */ +dom_exception _dom_mutation_event_get_related_node(dom_mutation_event *evt, + struct dom_node **node) +{ + *node = evt->related_node; + dom_node_ref(*node); + + return DOM_NO_ERR; +} + +/** + * Get the old value + * + * \param evt The Event object + * \param ret The old value + * \return DOM_NO_ERR. + */ +dom_exception _dom_mutation_event_get_prev_value(dom_mutation_event *evt, + struct dom_string **ret) +{ + *ret = evt->prev_value; + dom_string_ref(*ret); + + return DOM_NO_ERR; +} + +/** + * Get the new value + * + * \param evt The Event object + * \param ret The new value + * \return DOM_NO_ERR. + */ +dom_exception _dom_mutation_event_get_new_value(dom_mutation_event *evt, + struct dom_string **ret) +{ + *ret = evt->new_value; + dom_string_ref(*ret); + + return DOM_NO_ERR; +} + +/** + * Get the attr name + * + * \param evt The Event object + * \param ret The attribute name + * \return DOM_NO_ERR. + */ +dom_exception _dom_mutation_event_get_attr_name(dom_mutation_event *evt, + struct dom_string **ret) +{ + *ret = evt->attr_name; + dom_string_ref(*ret); + + return DOM_NO_ERR; +} + +/** + * Get the way the attribute change + * + * \param evt The Event object + * \param type The change type + * \return DOM_NO_ERR. + */ +dom_exception _dom_mutation_event_get_attr_change(dom_mutation_event *evt, + dom_mutation_type *type) +{ + *type = evt->change; + + return DOM_NO_ERR; +} + +/** + * Initialise the MutationEvent + * + * \param evt The Event object + * \param type The type of this UIEvent + * \param bubble Whether this event can bubble + * \param cancelable Whether this event is cancelable + * \param node The mutation node + * \param prev_value The old value + * \param new_value The new value + * \param attr_name The attribute's name + * \param change The change type + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_mutation_event_init(dom_mutation_event *evt, + struct dom_string *type, bool bubble, bool cancelable, + struct dom_node *node, struct dom_string *prev_value, + struct dom_string *new_value, struct dom_string *attr_name, + dom_mutation_type change) +{ + evt->related_node = node; + dom_node_ref(node); + + evt->prev_value = prev_value; + dom_string_ref(prev_value); + + evt->new_value = new_value; + dom_string_ref(new_value); + + evt->attr_name = attr_name; + dom_string_ref(attr_name); + + evt->change = change; + + return _dom_event_init(&evt->base, type, bubble, cancelable); +} + +/** + * Initialise the MutationEvent with namespace + * + * \param evt The Event object + * \param namespace The namespace + * \param type The type of this UIEvent + * \param bubble Whether this event can bubble + * \param cancelable Whether this event is cancelable + * \param node The mutation node + * \param prev_value The old value + * \param new_value The new value + * \param attr_name The attribute's name + * \param change The change type + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_mutation_event_init_ns(dom_mutation_event *evt, + struct dom_string *namespace, struct dom_string *type, + bool bubble, bool cancelable, struct dom_node *node, + struct dom_string *prev_value, struct dom_string *new_value, + struct dom_string *attr_name, dom_mutation_type change) +{ + evt->related_node = node; + dom_node_ref(node); + + evt->prev_value = prev_value; + dom_string_ref(prev_value); + + evt->new_value = new_value; + dom_string_ref(new_value); + + evt->attr_name = attr_name; + dom_string_ref(attr_name); + + evt->change = change; + + return _dom_event_init_ns(&evt->base, namespace, type, bubble, + cancelable); +} + diff --git a/src/events/mutation_event.h b/src/events/mutation_event.h new file mode 100644 index 0000000..d6cd733 --- /dev/null +++ b/src/events/mutation_event.h @@ -0,0 +1,45 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_interntal_events_mutation_event_h_ +#define dom_interntal_events_mutation_event_h_ + +#include + +#include "events/event.h" + +/** + * The MutationEvent + */ +struct dom_mutation_event { + struct dom_event base; + + struct dom_node *related_node; + struct dom_string *prev_value; + struct dom_string *new_value; + struct dom_string *attr_name; + dom_mutation_type change; +}; + +/* Constructor */ +dom_exception _dom_mutation_event_create(struct dom_document *doc, + struct dom_mutation_event **evt); + +/* Destructor */ +void _dom_mutation_event_destroy(struct dom_document *doc, + struct dom_mutation_event *evt); + +/* Initialise function */ +dom_exception _dom_mutation_event_initialise(struct dom_document *doc, + struct dom_mutation_event *evt); + +/* Finalise function */ +void _dom_mutation_event_finalise(struct dom_document *doc, + struct dom_mutation_event *evt); + +#endif + diff --git a/src/events/mutation_name_event.c b/src/events/mutation_name_event.c new file mode 100644 index 0000000..34b9288 --- /dev/null +++ b/src/events/mutation_name_event.c @@ -0,0 +1,159 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include "events/mutation_name_event.h" +#include "core/document.h" + +#include "utils/utils.h" + +static void _virtual_dom_mutation_name_event_destroy(struct dom_event *evt); + +static struct dom_event_private_vtable _event_vtable = { + _virtual_dom_mutation_name_event_destroy +}; + +/* Constructor */ +dom_exception _dom_mutation_name_event_create(struct dom_document *doc, + struct dom_mutation_name_event **evt) +{ + *evt = _dom_document_alloc(doc, NULL, sizeof(dom_mutation_name_event)); + if (*evt == NULL) + return DOM_NO_MEM_ERR; + + ((struct dom_event *) *evt)->vtable = &_event_vtable; + + return _dom_mutation_name_event_initialise(doc, *evt); +} + +/* Destructor */ +void _dom_mutation_name_event_destroy(struct dom_document *doc, + struct dom_mutation_name_event *evt) +{ + _dom_mutation_name_event_finalise(doc, evt); + + _dom_document_alloc(doc, evt, 0); +} + +/* Initialise function */ +dom_exception _dom_mutation_name_event_initialise(struct dom_document *doc, + struct dom_mutation_name_event *evt) +{ + evt->prev_namespace = NULL; + evt->prev_nodename = NULL; + + return _dom_event_initialise(doc, (dom_event *) evt); +} + +/* Finalise function */ +void _dom_mutation_name_event_finalise(struct dom_document *doc, + struct dom_mutation_name_event *evt) +{ + dom_string_unref(evt->prev_namespace); + dom_string_unref(evt->prev_nodename); + + _dom_event_finalise(doc, (dom_event *) evt); +} + +/* The virtual destroy function */ +void _virtual_dom_mutation_name_event_destroy(struct dom_event *evt) +{ + _dom_mutation_name_event_destroy(evt->doc, + (dom_mutation_name_event *) evt); +} + +/*----------------------------------------------------------------------*/ +/* The public API */ + +/** + * Get the previous namespace + * + * \param evt The Event object + * \param namespace The previous namespace of this event + * \return DOM_NO_ERR. + */ +dom_exception _dom_mutation_name_event_get_prev_namespace( + dom_mutation_name_event *evt, struct dom_string **namespace) +{ + *namespace = evt->prev_namespace; + dom_string_ref(*namespace); + + return DOM_NO_ERR; +} + +/** + * Get the previous node name + * + * \param evt The Event object + * \param name The previous node name + * \return DOM_NO_ERR. + */ +dom_exception _dom_mutation_name_event_get_prev_node_name( + dom_mutation_name_event *evt, struct dom_string **name) +{ + *name = evt->prev_nodename; + dom_string_ref(*name); + + return DOM_NO_ERR; +} + +/** + * Initialise the MutationNameEvent + * + * \param evt The Event object + * \param type The type of this UIEvent + * \param bubble Whether this event can bubble + * \param cancelable Whether this event is cancelable + * \param node The node whose name change + * \param prev_ns The old namespace + * \param prev_name The old name + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_mutation_name_event_init(dom_mutation_name_event *evt, + struct dom_string *type, bool bubble, bool cancelable, + struct dom_node *node, struct dom_string *prev_ns, + struct dom_string *prev_name) +{ + evt->prev_namespace = prev_ns; + dom_string_ref(prev_ns); + + evt->prev_nodename = prev_name; + dom_string_ref(prev_name); + + return _dom_mutation_event_init((dom_mutation_event *) evt, type, + bubble, cancelable, node, NULL, NULL, NULL, + DOM_MUTATION_MODIFICATION); +} + +/** + * Initialise the MutationNameEvent with namespace + * + * \param evt The Event object + * \param namespace The namespace + * \param type The type of this UIEvent + * \param bubble Whether this event can bubble + * \param cancelable Whether this event is cancelable + * \param node The node whose name change + * \param prev_ns The old namespace + * \param prev_name The old name + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_mutation_name_event_init_ns(dom_mutation_name_event *evt, + struct dom_string *namespace, struct dom_string *type, + bool bubble, bool cancelable, struct dom_node *node, + struct dom_string *prev_ns, struct dom_string *prev_name) +{ + evt->prev_namespace = prev_ns; + dom_string_ref(prev_ns); + + evt->prev_nodename = prev_name; + dom_string_ref(prev_name); + + return _dom_mutation_event_init_ns((dom_mutation_event *) evt, + namespace, type, bubble, cancelable, node, NULL, + NULL, NULL, DOM_MUTATION_MODIFICATION); +} + diff --git a/src/events/mutation_name_event.h b/src/events/mutation_name_event.h new file mode 100644 index 0000000..2ba74de --- /dev/null +++ b/src/events/mutation_name_event.h @@ -0,0 +1,42 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_interntal_events_mutation_name_event_h_ +#define dom_interntal_events_mutation_name_event_h_ + +#include + +#include "events/mutation_event.h" + +/** + * The MutationName event + */ +struct dom_mutation_name_event { + struct dom_mutation_event base; + + struct dom_string *prev_namespace; + struct dom_string *prev_nodename; +}; + +/* Constructor */ +dom_exception _dom_mutation_name_event_create(struct dom_document *doc, + struct dom_mutation_name_event **evt); + +/* Destructor */ +void _dom_mutation_name_event_destroy(struct dom_document *doc, + struct dom_mutation_name_event *evt); + +/* Initialise function */ +dom_exception _dom_mutation_name_event_initialise(struct dom_document *doc, + struct dom_mutation_name_event *evt); + +/* Finalise function */ +void _dom_mutation_name_event_finalise(struct dom_document *doc, + struct dom_mutation_name_event *evt); + +#endif + diff --git a/src/events/text_event.c b/src/events/text_event.c new file mode 100644 index 0000000..24c921a --- /dev/null +++ b/src/events/text_event.c @@ -0,0 +1,125 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include "events/text_event.h" +#include "core/document.h" + +static void _virtual_dom_text_event_destroy(struct dom_event *evt); + +static struct dom_event_private_vtable _event_vtable = { + _virtual_dom_text_event_destroy +}; + +/* Constructor */ +dom_exception _dom_text_event_create(struct dom_document *doc, + struct dom_text_event **evt) +{ + *evt = _dom_document_alloc(doc, NULL, sizeof(dom_text_event)); + if (*evt == NULL) + return DOM_NO_MEM_ERR; + + ((struct dom_event *) *evt)->vtable = &_event_vtable; + + return _dom_text_event_initialise(doc, *evt); +} + +/* Destructor */ +void _dom_text_event_destroy(struct dom_document *doc, + struct dom_text_event *evt) +{ + _dom_text_event_finalise(doc, evt); + + _dom_document_alloc(doc, evt, 0); +} + +/* Initialise function */ +dom_exception _dom_text_event_initialise(struct dom_document *doc, + struct dom_text_event *evt) +{ + evt->data = NULL; + return _dom_ui_event_initialise(doc, &evt->base); +} + +/* Finalise function */ +void _dom_text_event_finalise(struct dom_document *doc, + struct dom_text_event *evt) +{ + dom_string_unref(evt->data); + _dom_ui_event_finalise(doc, &evt->base); +} + +/* The virtual destroy function */ +void _virtual_dom_text_event_destroy(struct dom_event *evt) +{ + _dom_text_event_destroy(evt->doc, (dom_text_event *) evt); +} + +/*----------------------------------------------------------------------*/ +/* The public API */ + +/** + * Get the internal data of this event + * + * \param evt The Event object + * \param data The internal data of this Event + * \return DOM_NO_ERR. + */ +dom_exception _dom_text_event_get_data(dom_text_event *evt, + struct dom_string **data) +{ + *data = evt->data; + dom_string_ref(*data); + + return DOM_NO_ERR; +} + +/** + * Initialise the TextEvent + * + * \param evt The Event object + * \param type The type of this UIEvent + * \param bubble Whether this event can bubble + * \param cancelable Whether this event is cancelable + * \param view The AbstractView of this UIEvent + * \param data The text data + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_text_event_init(dom_text_event *evt, + struct dom_string *type, bool bubble, bool cancelable, + struct dom_abstract_view *view, struct dom_string *data) +{ + evt->data = data; + dom_string_ref(data); + + return _dom_ui_event_init(&evt->base, type, bubble, cancelable, + view, 0); +} + +/** + * Initialise the TextEvent with namespace + * + * \param evt The Event object + * \param namespace The namespace of this Event + * \param type The type of this UIEvent + * \param bubble Whether this event can bubble + * \param cancelable Whether this event is cancelable + * \param view The AbstractView of this UIEvent + * \param data The text data + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_text_event_init_ns(dom_text_event *evt, + struct dom_string *namespace, struct dom_string *type, + bool bubble, bool cancelable, struct dom_abstract_view *view, + struct dom_string *data) +{ + evt->data = data; + dom_string_ref(data); + + return _dom_ui_event_init_ns(&evt->base, namespace, type, bubble, + cancelable, view, 0); +} + diff --git a/src/events/text_event.h b/src/events/text_event.h new file mode 100644 index 0000000..754a4f6 --- /dev/null +++ b/src/events/text_event.h @@ -0,0 +1,40 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_internal_events_text_event_h_ +#define dom_internal_events_text_event_h_ + +#include + +#include "events/ui_event.h" + +/** + * The TextEvent + */ +struct dom_text_event { + struct dom_ui_event base; + struct dom_string *data; +}; + +/* Constructor */ +dom_exception _dom_text_event_create(struct dom_document *doc, + struct dom_text_event **evt); + +/* Destructor */ +void _dom_text_event_destroy(struct dom_document *doc, + struct dom_text_event *evt); + +/* Initialise function */ +dom_exception _dom_text_event_initialise(struct dom_document *doc, + struct dom_text_event *evt); + +/* Finalise function */ +void _dom_text_event_finalise(struct dom_document *doc, + struct dom_text_event *evt); + +#endif + diff --git a/src/events/ui_event.c b/src/events/ui_event.c new file mode 100644 index 0000000..f18e44f --- /dev/null +++ b/src/events/ui_event.c @@ -0,0 +1,138 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#include "events/ui_event.h" +#include "core/document.h" + +static void _virtual_dom_ui_event_destroy(struct dom_event *evt); + +static struct dom_event_private_vtable _event_vtable = { + _virtual_dom_ui_event_destroy +}; + +/* Constructor */ +dom_exception _dom_ui_event_create(struct dom_document *doc, + struct dom_ui_event **evt) +{ + *evt = _dom_document_alloc(doc, NULL, sizeof(dom_ui_event)); + if (*evt == NULL) + return DOM_NO_MEM_ERR; + + ((struct dom_event *) *evt)->vtable = &_event_vtable; + + return _dom_ui_event_initialise(doc, *evt); +} + +/* Destructor */ +void _dom_ui_event_destroy(struct dom_document *doc, + struct dom_ui_event *evt) +{ + _dom_ui_event_finalise(doc, evt); + + _dom_document_alloc(doc, evt, 0); +} + +/* Initialise function */ +dom_exception _dom_ui_event_initialise(struct dom_document *doc, + struct dom_ui_event *evt) +{ + evt->view = NULL; + return _dom_event_initialise(doc, &evt->base); +} + +/* Finalise function */ +void _dom_ui_event_finalise(struct dom_document *doc, + struct dom_ui_event *evt) +{ + evt->view = NULL; + _dom_event_finalise(doc, &evt->base); +} + +/* The virtual destroy function */ +void _virtual_dom_ui_event_destroy(struct dom_event *evt) +{ + _dom_ui_event_destroy(evt->doc, (dom_ui_event *) evt); +} + +/*----------------------------------------------------------------------*/ +/* The public API */ + +/** + * Get the AbstractView inside this event + * + * \param evt The Event object + * \param view The returned AbstractView + * \return DOM_NO_ERR. + */ +dom_exception _dom_ui_event_get_view(dom_ui_event *evt, + struct dom_abstract_view **view) +{ + *view = evt->view; + + return DOM_NO_ERR; +} + +/** + * Get the detail param of this event + * + * \param evt The Event object + * \param detail The detail object + * \return DOM_NO_ERR. + */ +dom_exception _dom_ui_event_get_detail(dom_ui_event *evt, + long *detail) +{ + *detail = evt->detail; + + return DOM_NO_ERR; +} + +/** + * Initialise the UIEvent + * + * \param evt The Event object + * \param type The type of this UIEvent + * \param bubble Whether this event can bubble + * \param cancelable Whether this event is cancelable + * \param view The AbstractView of this UIEvent + * \param detail The detail object + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_ui_event_init(dom_ui_event *evt, struct dom_string *type, + bool bubble, bool cancelable, struct dom_abstract_view *view, + long detail) +{ + evt->view = view; + evt->detail = detail; + + return _dom_event_init(&evt->base, type, bubble, cancelable); +} + +/** + * Initialise the UIEvent with namespace + * + * \param evt The Event object + * \param namespace The namespace of this Event + * \param type The type of this UIEvent + * \param bubble Whether this event can bubble + * \param cancelable Whether this event is cancelable + * \param view The AbstractView of this UIEvent + * \param detail The detail object + * \return DOM_NO_ERR on success, appropriate dom_exception on failure. + */ +dom_exception _dom_ui_event_init_ns(dom_ui_event *evt, + struct dom_string *namespace, struct dom_string *type, + bool bubble, bool cancelable, struct dom_abstract_view *view, + long detail) +{ + evt->view = view; + evt->detail = detail; + + return _dom_event_init_ns(&evt->base, namespace, type, bubble, + cancelable); +} + diff --git a/src/events/ui_event.h b/src/events/ui_event.h new file mode 100644 index 0000000..3a245ab --- /dev/null +++ b/src/events/ui_event.h @@ -0,0 +1,54 @@ +/* + * This file is part of libdom. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2009 Bo Yang + */ + +#ifndef dom_interntal_events_ui_event_h_ +#define dom_interntal_events_ui_event_h_ + +#include + +#include "events/event.h" + +/** + * The modifier key state + */ +typedef enum { + DOM_MOD_CTRL = (1<<0), + DOM_MOD_META = (1<<1), + DOM_MOD_SHIFT = (1<<2), + DOM_MOD_ALT = (1<<3), + DOM_MOD_ALT_GRAPH = (1<<4), + DOM_MOD_CAPS_LOCK = (1<<5), + DOM_MOD_NUM_LOCK = (1<<6), + DOM_MOD_SCROLL = (1<<7) +} dom_modifier_key; + +/** + * The UIEvent + */ +struct dom_ui_event { + struct dom_event base; /**< The base class */ + struct dom_abstract_view *view; /**< The AbstractView */ + long detail; /**< Some private data for this event */ +}; + +/* Constructor */ +dom_exception _dom_ui_event_create(struct dom_document *doc, + struct dom_ui_event **evt); + +/* Destructor */ +void _dom_ui_event_destroy(struct dom_document *doc, + struct dom_ui_event *evt); + +/* Initialise function */ +dom_exception _dom_ui_event_initialise(struct dom_document *doc, + struct dom_ui_event *evt); + +/* Finalise function */ +void _dom_ui_event_finalise(struct dom_document *doc, + struct dom_ui_event *evt); + +#endif diff --git a/src/utils/hashtable.c b/src/utils/hashtable.c index c2ff8ce..f1dc076 100644 --- a/src/utils/hashtable.c +++ b/src/utils/hashtable.c @@ -16,6 +16,8 @@ #endif #include "utils/hashtable.h" +#include + /* The hash table entry */ struct _dom_hash_entry { void *key; /**< The key pointer */ @@ -353,6 +355,15 @@ dom_hash_func _dom_hash_get_func(struct dom_hash_table *ht) return ht->hash; } +/*-----------------------------------------------------------------------*/ +/* The hash function for lwc_string type */ +unsigned int _dom_hash_hash_lwcstring(void *key) +{ + lwc_string *lstr = (lwc_string *) key; + + return lwc_string_hash_value(lstr); +} + /* A simple test rig. To compile, use: * gcc -g -o hashtest -I../ -I../../include -DTEST_RIG hashtable.c * diff --git a/src/utils/hashtable.h b/src/utils/hashtable.h index 3cfe95d..625e440 100644 --- a/src/utils/hashtable.h +++ b/src/utils/hashtable.h @@ -39,4 +39,7 @@ unsigned int _dom_hash_get_length(struct dom_hash_table *ht); unsigned int _dom_hash_get_chains(struct dom_hash_table *ht); dom_hash_func _dom_hash_get_func(struct dom_hash_table *ht); +/*-----------------------------------------------------------------------*/ +unsigned int _dom_hash_hash_lwcstring(void *key); + #endif -- cgit v1.2.3