diff options
Diffstat (limited to 'src/dom/watcher.c')
-rw-r--r-- | src/dom/watcher.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/src/dom/watcher.c b/src/dom/watcher.c new file mode 100644 index 0000000..a4e8d64 --- /dev/null +++ b/src/dom/watcher.c @@ -0,0 +1,176 @@ +/* + * 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 + * DOM mutation handling + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "layout.h" +#include "dom/watcher.h" +#include "util/dom-str.h" +#include "util/util.h" + +/** + * Convert a dom node type to a string + * + * \param[in] type DOM node type + * \return appropriate string. + */ +static const char *nsl__dom_node_type_to_string(dom_node_type type) +{ + const char *str[] = { + "ELEMENT_NODE", + "ATTRIBUTE_NODE", + "TEXT_NODE", + "CDATA_SECTION_NODE", + "ENTITY_REFERENCE_NODE", + "ENTITY_NODE", + "PROCESSING_INSTRUCTION_NODE", + "COMMENT_NODE", + "DOCUMENT_NODE", + "DOCUMENT_TYPE_NODE", + "DOCUMENT_FRAGMENT_NODE", + "NOTATION_NODE" + }; + assert(DOM_NODE_TYPE_COUNT == 12); + + return str[type - 1]; +} + +/** + * LibDOM event handler + * + * \param[in] evt The LibDOM event object + * \param[in] pw Pointer to our nslayout_layout object + */ +static void nsl__dom_event_handler(struct dom_event *evt, void *pw) +{ + dom_event_target *node = NULL; + dom_node_type node_type; + dom_string *name = NULL; + dom_string *type = NULL; + dom_exception exc; + + UNUSED(pw); + + 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"); +} + +/* Exported function, documented in src/dom/event.h */ +nslayout_error nsl_dom_watcher_add_for_layout(nslayout_layout *layout) +{ + nslayout_error err; + dom_exception exc; + + /* TODO: LibDOM event listeners are really slow. Need to find a better + * way to get DOM change notifications. + */ + + exc = dom_event_listener_create(layout->doc, nsl__dom_event_handler, + layout, &layout->listener); + if (exc != DOM_NO_ERR) { + return NSL_DOM_ERR(exc); + } + exc = dom_event_target_add_event_listener( + layout->doc, nsl_dom_str_node_inserted, + layout->listener, false); + if (exc != DOM_NO_ERR) { + err = NSL_DOM_ERR(exc); + goto fail; + } + exc = dom_event_target_add_event_listener( + layout->doc, nsl_dom_str_subtree_modified, + layout->listener, false); + if (exc != DOM_NO_ERR) { + (void) dom_event_target_remove_event_listener( + layout->doc, nsl_dom_str_node_inserted, + layout->listener, false); + err = NSL_DOM_ERR(exc); + goto fail; + } + + return NSLAYOUT_OK; + +fail: + dom_event_listener_unref(layout->listener); + layout->listener = NULL; + + return err; +} + +/* Exported function, documented in src/dom/event.h */ +nslayout_error nsl_dom_watcher_remove_for_layout(nslayout_layout *layout) +{ + dom_exception exc1, exc2; + + exc1 = dom_event_target_remove_event_listener( + layout->doc, nsl_dom_str_node_inserted, + layout->listener, false); + exc2 = dom_event_target_remove_event_listener( + layout->doc, nsl_dom_str_subtree_modified, + layout->listener, false); + + if (exc1 != DOM_NO_ERR) { + return NSL_DOM_ERR(exc1); + } + if (exc2 != DOM_NO_ERR) { + return NSL_DOM_ERR(exc2); + } + + dom_event_listener_unref(layout->listener); + layout->listener = NULL; + + return NSLAYOUT_OK; +} |