diff options
Diffstat (limited to 'test/dom')
-rw-r--r-- | test/dom/Makefile | 13 | ||||
-rw-r--r-- | test/dom/debug.c | 103 | ||||
-rw-r--r-- | test/dom/debug.h | 41 | ||||
-rw-r--r-- | test/dom/watcher.c | 231 | ||||
-rw-r--r-- | test/dom/watcher.h | 71 |
5 files changed, 459 insertions, 0 deletions
diff --git a/test/dom/Makefile b/test/dom/Makefile new file mode 100644 index 0000000..0b345cb --- /dev/null +++ b/test/dom/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for libnslayout +# +# Copyright 2015 Michael Drake <tlsa@netsurf-browser.org> +# +# Released under the ISC License (see COPYING file) + +# Sources +DIR_SOURCES := \ + debug.c \ + watcher.c + +include $(NSBUILD)/Makefile.subdir diff --git a/test/dom/debug.c b/test/dom/debug.c new file mode 100644 index 0000000..9e3e0b0 --- /dev/null +++ b/test/dom/debug.c @@ -0,0 +1,103 @@ +/* + * This file is part of LibNSLayout + * Licensed under the ISC License, http://opensource.org/licenses/ISC + * Copyright 2015-2017 Michael Drake <tlsa@netsurf-browser.org> + */ + +/** \file src/dom/debug.c + * DOM debug + */ + +#include <stdio.h> + +#include <dom/dom.h> + +#include "debug.h" + + +#ifdef NSL_DOM_TRACE + +/** + * Convert a dom node type to a string + * + * \param[in] type DOM node type + * \return appropriate string. + */ +static inline const char *nsl__dom_node_type_to_string(dom_node_type type) +{ + static const char *str[DOM_NODE_TYPE_COUNT] = { + [DOM_ELEMENT_NODE] = "ELEMENT_NODE", + [DOM_ATTRIBUTE_NODE] = "ATTRIBUTE_NODE", + [DOM_TEXT_NODE] = "TEXT_NODE", + [DOM_CDATA_SECTION_NODE] = "CDATA_SECTION_NODE", + [DOM_ENTITY_REFERENCE_NODE] = "ENTITY_REFERENCE_NODE", + [DOM_ENTITY_NODE] = "ENTITY_NODE", + [DOM_PROCESSING_INSTRUCTION_NODE] = "PROCESSING_INSTRUCTION_NODE", + [DOM_COMMENT_NODE] = "COMMENT_NODE", + [DOM_DOCUMENT_NODE] = "DOCUMENT_NODE", + [DOM_DOCUMENT_TYPE_NODE] = "DOCUMENT_TYPE_NODE", + [DOM_DOCUMENT_FRAGMENT_NODE] = "DOCUMENT_FRAGMENT_NODE", + [DOM_NOTATION_NODE] = "NOTATION_NODE" + }; + + return str[type]; +} + + +/* Exported function, documented in src/dom/debug.h */ +void nsl__dom_debug_dump_event(const struct dom_event *evt) +{ + dom_event_target *node = NULL; + dom_node_type node_type; + dom_string *name = NULL; + dom_string *type = NULL; + dom_exception exc; + + printf(" DOM Event: "); + + /* Ugly test to see what events come out */ + exc = dom_event_get_target(evt, &node); + if ((exc != DOM_NO_ERR) || (node == NULL)) { + printf("FAILED to get target node!\n"); + goto fail; + } + + exc = dom_node_get_node_type(node, &node_type); + if (exc != DOM_NO_ERR) { + printf("FAILED to get target node type!\n"); + goto fail; + } + + if (node_type == DOM_ELEMENT_NODE) { + exc = dom_node_get_node_name(node, &name); + if ((exc != DOM_NO_ERR) || (name == NULL)) { + printf("FAILED to get target node name!\n"); + goto fail; + } + } + + exc = dom_event_get_type(evt, &type); + if ((exc != DOM_NO_ERR) || (type == NULL)) { + printf("FAILED to get event type!\n"); + goto fail; + } + + if (node_type == DOM_ELEMENT_NODE) { + printf("<%s> %s", + dom_string_data(name), + dom_string_data(type)); + } else { + printf("%s %s", + nsl__dom_node_type_to_string(node_type), + dom_string_data(type)); + } + +fail: + if (type != NULL) dom_string_unref(type); + if (name != NULL) dom_string_unref(name); + if (node != NULL) dom_node_unref(node); + + printf("\n"); +} + +#endif diff --git a/test/dom/debug.h b/test/dom/debug.h new file mode 100644 index 0000000..cbe8559 --- /dev/null +++ b/test/dom/debug.h @@ -0,0 +1,41 @@ +/* + * This file is part of LibNSLayout + * Licensed under the ISC License, http://opensource.org/licenses/ISC + * Copyright 2015-2017 Michael Drake <tlsa@netsurf-browser.org> + */ + +/** \file src/dom/debug.h + * DOM debug + */ + +#ifndef nsl_dom_debug_h_ +#define nsl_dom_debug_h_ + +/** Define to enable DOM trace debug output */ +#undef NSL_DOM_TRACE +#define NSL_DOM_TRACE + +#include "util/util.h" + +struct dom_event; + +/** Don't use directly */ +void nsl__dom_debug_dump_event(const struct dom_event *evt); + + +/** + * Dump debug for dom event + * + * \param[in] evt Dump debug concerning a DOM event. + */ +static inline void nsl_dom_debug_dump_event(const struct dom_event *evt) +{ +#ifdef NSL_DOM_TRACE + nsl__dom_debug_dump_event(evt); +#else + UNUSED(evt); +#endif +} + + +#endif diff --git a/test/dom/watcher.c b/test/dom/watcher.c new file mode 100644 index 0000000..312dbf2 --- /dev/null +++ b/test/dom/watcher.c @@ -0,0 +1,231 @@ +/* + * This file is part of LibNSLayout + * Licensed under the ISC License, http://opensource.org/licenses/ISC + * Copyright 2015 Michael Drake <tlsa@netsurf-browser.org> + */ + +/** \file src/dom/watcher.c + * Implementation of DOM mutation watching. + * + * TODO: LibDOM mutation event listeners are really slow. + * Need to find a better way to get DOM change notifications. + * LibDOM probably needs to gain Mutation Observer support, or + * gain a LibDOM-specific extension API. + */ + +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> + +#include "libnslayout/nslayout.h" + +#include "debug.h" +#include "watcher.h" +#include "util/dom-str.h" +#include "util/util.h" + + +/** + * A dom watcher object + */ +struct nsl_dom_watcher { + dom_document *document; /**< DOM document */ + dom_event_listener *listener; /**< DOM event listener object */ + nsl_dom_watcher_cb watcher_cb; /**< Client callback */ + void *pw; /**< Client data */ +}; + +/** + * LibDOM event handler + * + * \param[in] evt The LibDOM event object + * \param[in] pw Pointer to our dom watcher object + */ +static void nsl__dom_event_handler(struct dom_event *evt, void *pw) +{ + const struct nsl_dom_watcher *watcher = pw; + enum nsl_dom_watcher_type type; + dom_event_target *node = NULL; + dom_string *evt_type = NULL; + dom_node_type node_type; + dom_exception exc; + + nsl_dom_debug_dump_event(evt); + + exc = dom_event_get_target(evt, &node); + if ((exc != DOM_NO_ERR) || (node == NULL)) { + printf("FAILED to get target node!\n"); + goto fail; + } + + exc = dom_node_get_node_type(node, &node_type); + if (exc != DOM_NO_ERR) { + printf("FAILED to get target node type!\n"); + goto fail; + } + + exc = dom_event_get_type(evt, &evt_type); + if ((exc != DOM_NO_ERR) || (evt_type == NULL)) { + printf("FAILED to get event type!\n"); + goto fail; + } + + if (dom_string_isequal(evt_type, + nsl_dom_str_node_inserted)) { + type = NSL_DOM_WATCHER_NODE_INSERTED; + + } else if (dom_string_isequal(evt_type, + nsl_dom_str_node_removed)) { + type = NSL_DOM_WATCHER_NODE_REMOVED; + + } else if (dom_string_isequal(evt_type, + nsl_dom_str_subtree_modified)) { + type = NSL_DOM_WATCHER_SUBTREE_MODIFIED; + + } else if (dom_string_isequal(evt_type, + nsl_dom_str_attr_modified)) { + type = NSL_DOM_WATCHER_ATTR_MODIFIED; + + } else if (dom_string_isequal(evt_type, + nsl_dom_str_characterdata_modified)) { + type = NSL_DOM_WATCHER_CHAR_DATA_MODIFIED; + } else { + printf("FAILED: unrecognised event type: '%s'", + dom_string_data(evt_type)); + goto fail; + } + + dom_string_unref(evt_type); + + watcher->watcher_cb(type, node, node_type, watcher->pw); + return; + +fail: + if (evt_type != NULL) dom_string_unref(evt_type); + if (node != NULL) dom_node_unref(node); +} + + +/** + * Destroy a DOM document's event listener + * + * \param[in] listener The listener to destroy + * \param[in] document The document that the listener was registerd for. + * \return NSL_OK on success, appropriate error otherwise. + */ +static nsl_error nsl__dom_listener_destroy( + dom_event_listener *listener, + dom_document *document) +{ + dom_exception exc; + + /* Passing NULL as type, removes listener for all event types. */ + exc = dom_event_target_remove_event_listener( + document, NULL, listener, false); + if (exc != DOM_NO_ERR) { + return NSL_DOM_ERR(exc); + } + + dom_event_listener_unref(listener); + + return NSL_OK; +} + + +/** + * Create a dom event listener. + * + * \param[out] listener_out Returns a dom listener for watcher's document. + * \param[in] watcher DOM watcher object that listener is used for. + * \return NSL_OK on success, appropriate error otherwise. + */ +static nsl_error nsl__dom_listener_create( + dom_event_listener **listener_out, + const struct nsl_dom_watcher *watcher) +{ + dom_event_listener *listener; + dom_exception exc; + + /* Create listener */ + exc = dom_event_listener_create(nsl__dom_event_handler, + (void *) watcher, &listener); + if (exc != DOM_NO_ERR) { + goto error; + } + + /* Set the event types it should listen to */ + exc = dom_event_target_add_event_listener(watcher->document, + nsl_dom_str_node_inserted, listener, false); + if (exc != DOM_NO_ERR) { + goto error; + } + exc = dom_event_target_add_event_listener(watcher->document, + nsl_dom_str_subtree_modified, listener, false); + if (exc != DOM_NO_ERR) { + goto error; + } + exc = dom_event_target_add_event_listener(watcher->document, + nsl_dom_str_node_removed, listener, false); + if (exc != DOM_NO_ERR) { + goto error; + } + exc = dom_event_target_add_event_listener(watcher->document, + nsl_dom_str_attr_modified, listener, false); + if (exc != DOM_NO_ERR) { + goto error; + } + exc = dom_event_target_add_event_listener(watcher->document, + nsl_dom_str_characterdata_modified, listener, false); + if (exc != DOM_NO_ERR) { + goto error; + } + + *listener_out = listener; + return NSL_OK; + +error: + nsl__dom_listener_destroy(listener, watcher->document); + + return NSL_DOM_ERR(exc); +} + +/* Exported function, documented in src/dom/watcher.h */ +bool nsl_dom_watcher_create( + struct nsl_dom_watcher **watcher_out, + dom_document *document, + nsl_dom_watcher_cb watcher_cb, + void *pw) +{ + struct nsl_dom_watcher *watcher; + nsl_error err; + + watcher = malloc(sizeof(*watcher)); + if (watcher == NULL) { + return false; + } + + watcher->document = document; + watcher->watcher_cb = watcher_cb; + watcher->pw = pw; + + err = nsl__dom_listener_create(&watcher->listener, watcher); + if (err != NSL_OK) { + free(watcher); + return false; + } + + *watcher_out = watcher; + return true; +} + +/* Exported function, documented in src/dom/watcher.h */ +bool nsl_dom_watcher_destroy( + struct nsl_dom_watcher *watcher) +{ + nsl__dom_listener_destroy(watcher->listener, watcher->document); + free(watcher); + + return true; +} diff --git a/test/dom/watcher.h b/test/dom/watcher.h new file mode 100644 index 0000000..cf26a56 --- /dev/null +++ b/test/dom/watcher.h @@ -0,0 +1,71 @@ +/* + * This file is part of LibNSLayout + * Licensed under the ISC License, http://opensource.org/licenses/ISC + * Copyright 2015 Michael Drake <tlsa@netsurf-browser.org> + */ + +/** \file src/dom/watcher.h + * Interface to DOM mutation watching. + */ + +#ifndef nsl_dom_watcher_h_ +#define nsl_dom_watcher_h_ + +struct dom_document; +struct nsl_dom_watcher; + +/** + * DOM watcher's mutation types + */ +enum nsl_dom_watcher_type { + NSL_DOM_WATCHER_NODE_INSERTED, + NSL_DOM_WATCHER_NODE_REMOVED, + NSL_DOM_WATCHER_SUBTREE_MODIFIED, + NSL_DOM_WATCHER_ATTR_MODIFIED, + NSL_DOM_WATCHER_CHAR_DATA_MODIFIED, + NSL_DOM_WATCHER__COUNT, +}; + + +/** + * Callback function for dom modifications. + * + * \param[in] type The mutation type. + * \param[in] node The target node. (Caller yields ownership.) + * \param[in] node_type The type of node. + * \param[in] pw The dom watcher owner's private data. + * \return NSL_OK on success, appropriate error otherwise. + */ +typedef bool (*nsl_dom_watcher_cb)( + enum nsl_dom_watcher_type type, + dom_event_target *node, + dom_node_type node_type, + void *pw); + + +/** + * Create DOM change watcher for a DOM document. + * + * \param[out] watcher_out Returns a dom watcher object for layout. + * \param[in] document DOM document to create watcher for. + * \param[in] watcher_cb Function to call when dom modification happens. + * \param[in] pw Private data passed back to `watcher_cb`. + * \return NSL_OK on success, appropriate error otherwise. + */ +bool nsl_dom_watcher_create( + struct nsl_dom_watcher **watcher_out, + dom_document *document, + nsl_dom_watcher_cb watcher_cb, + void *pw); + + +/** + * Destroy a document change DOM change watcher. + * + * \param[in] watcher DOM change watcher to destroy. + * \return NSL_OK on success, appropriate error otherwise. + */ +bool nsl_dom_watcher_destroy( + struct nsl_dom_watcher *watcher); + +#endif |