summaryrefslogtreecommitdiff
path: root/src/dom/watcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dom/watcher.c')
-rw-r--r--src/dom/watcher.c176
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;
+}