Author: jmb
Date: Wed Jul 11 00:25:18 2007
New Revision: 3395
URL:
http://source.netsurf-browser.org?rev=3395&view=rev
Log:
Add NamedNodeMap.
Minor fix for NodeList unref function; ensure it unrefs the owner document after it has
finished using it.
Added:
trunk/dom/include/dom/core/namednodemap.h
trunk/dom/src/core/namednodemap.c
trunk/dom/src/core/namednodemap.h
Modified:
trunk/dom/src/core/Makefile
trunk/dom/src/core/document.c
trunk/dom/src/core/document.h
trunk/dom/src/core/nodelist.c
Added: trunk/dom/include/dom/core/namednodemap.h
URL:
http://source.netsurf-browser.org/trunk/dom/include/dom/core/namednodemap...
==============================================================================
--- trunk/dom/include/dom/core/namednodemap.h (added)
+++ trunk/dom/include/dom/core/namednodemap.h Wed Jul 11 00:25:18 2007
@@ -1,0 +1,43 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *
http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2007 John-Mark Bell <jmb(a)netsurf-browser.org>
+ */
+
+#ifndef dom_core_namednodemap_h_
+#define dom_core_namednodemap_h_
+
+#include <dom/core/exceptions.h>
+
+struct dom_node;
+struct dom_namednodemap;
+struct dom_string;
+
+void dom_namednodemap_ref(struct dom_namednodemap *map);
+void dom_namednodemap_unref(struct dom_namednodemap *map);
+
+dom_exception dom_namednodemap_get_length(struct dom_namednodemap *map,
+ unsigned long *length);
+
+dom_exception dom_namednodemap_get_named_item(struct dom_namednodemap *map,
+ struct dom_string *name, struct dom_node **node);
+dom_exception dom_namednodemap_set_named_item(struct dom_namednodemap *map,
+ struct dom_node *arg, struct dom_node **node);
+dom_exception dom_namednodemap_remove_named_item(
+ struct dom_namednodemap *map, struct dom_string *name,
+ struct dom_node **node);
+dom_exception dom_namednodemap_item(struct dom_namednodemap *map,
+ unsigned long index, struct dom_node **node);
+
+dom_exception dom_namednodemap_get_named_item_ns(
+ struct dom_namednodemap *map, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node);
+dom_exception dom_namednodemap_set_named_item_ns(
+ struct dom_namednodemap *map, struct dom_node *arg,
+ struct dom_node **node);
+dom_exception dom_namednodemap_remove_named_item_ns(
+ struct dom_namednodemap *map, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node);
+
+#endif
Modified: trunk/dom/src/core/Makefile
URL:
http://source.netsurf-browser.org/trunk/dom/src/core/Makefile?rev=3395&am...
==============================================================================
--- trunk/dom/src/core/Makefile (original)
+++ trunk/dom/src/core/Makefile Wed Jul 11 00:25:18 2007
@@ -22,7 +22,7 @@
CFLAGS += -I$(CURDIR)
# Objects
-OBJS = attr document node nodelist string
+OBJS = attr document namednodemap node nodelist string
.PHONY: clean debug distclean export release setup test
Modified: trunk/dom/src/core/document.c
URL:
http://source.netsurf-browser.org/trunk/dom/src/core/document.c?rev=3395&...
==============================================================================
--- trunk/dom/src/core/document.c (original)
+++ trunk/dom/src/core/document.c Wed Jul 11 00:25:18 2007
@@ -24,12 +24,24 @@
};
/**
+ * Iten in list of active namednodemaps
+ */
+struct dom_doc_nnm {
+ struct dom_namednodemap *map; /**< Named node map */
+
+ struct dom_doc_nnm *next; /**< Next map */
+ struct dom_doc_nnm *prev; /**< Previous map */
+};
+
+/**
* DOM document
*/
struct dom_document {
struct dom_node base; /**< Base node */
struct dom_doc_nl *nodelists; /**< List of active nodelists */
+
+ struct dom_doc_nnm *maps; /**< List of active namednodemaps */
dom_alloc alloc; /**< Memory (de)allocation function */
void *pw; /**< Pointer to client data */
@@ -809,7 +821,7 @@
* If it did, the nodelist's reference count would never reach zero,
* and the list would remain indefinitely. This is not a problem as
* the list notifies the document of its destruction via
- * dom_document_remove_nodelist.*/
+ * dom_document_remove_nodelist. */
*list = l->list;
@@ -849,3 +861,99 @@
/* And free item */
doc->alloc(l, 0, doc->pw);
}
+
+/**
+ * Get a namednodemap, creating one if necessary
+ *
+ * \param doc The document to get a namednodemap for
+ * \param root Node containing items in map
+ * \param type The type of map
+ * \param map Pointer to location to receive map
+ * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion.
+ *
+ * The returned map will have its reference count increased. It is
+ * the responsibility of the caller to unref the map once it has
+ * finished with it.
+ */
+dom_exception dom_document_get_namednodemap(struct dom_document *doc,
+ struct dom_node *root, dom_namednodemap_type type,
+ struct dom_namednodemap **map)
+{
+ struct dom_doc_nnm *m;
+ dom_exception err;
+
+ for (m = doc->maps; m; m = m->next) {
+ if (dom_namednodemap_match(m->map, root, type))
+ break;
+ }
+
+ if (m != NULL) {
+ /* Found an existing map, so use it */
+ dom_namednodemap_ref(m->map);
+ } else {
+ /* No existing map */
+
+ /* Create active map entry */
+ m = doc->alloc(NULL, sizeof(struct dom_doc_nnm), doc->pw);
+ if (m == NULL)
+ return DOM_NO_MEM_ERR;
+
+ /* Create namednodemap */
+ err = dom_namednodemap_create(doc, root, type, &m->map);
+ if (err != DOM_NO_ERR) {
+ doc->alloc(m, 0, doc->pw);
+ return err;
+ }
+
+ /* Add to document's list of active namednodemaps */
+ m->prev = NULL;
+ m->next = doc->maps;
+ if (doc->maps)
+ doc->maps->prev = m;
+ doc->maps = m;
+ }
+
+ /* Note: the document does not claim a reference on the namednodemap
+ * If it did, the map's reference count would never reach zero,
+ * and the list would remain indefinitely. This is not a problem as
+ * the map notifies the document of its destruction via
+ * dom_document_remove_namednodempa. */
+
+ *map = m->map;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Remove a namednodemap
+ *
+ * \param doc The document to remove the map from
+ * \param map The map to remove
+ */
+void dom_document_remove_namednodemap(struct dom_document *doc,
+ struct dom_namednodemap *map)
+{
+ struct dom_doc_nnm *m;
+
+ for (m = doc->maps; m; m = m->next) {
+ if (m->map == map)
+ break;
+ }
+
+ if (m == NULL) {
+ /* This should never happen; we should probably abort here */
+ return;
+ }
+
+ /* Remove from list */
+ if (m->prev != NULL)
+ m->prev->next = m->next;
+ else
+ doc->maps = m->next;
+
+ if (m->next != NULL)
+ m->next->prev = m->prev;
+
+ /* And free item */
+ doc->alloc(m, 0, doc->pw);
+}
Modified: trunk/dom/src/core/document.h
URL:
http://source.netsurf-browser.org/trunk/dom/src/core/document.h?rev=3395&...
==============================================================================
--- trunk/dom/src/core/document.h (original)
+++ trunk/dom/src/core/document.h Wed Jul 11 00:25:18 2007
@@ -11,7 +11,10 @@
#include <inttypes.h>
#include <stddef.h>
+#include "core/namednodemap.h"
+
struct dom_document;
+struct dom_namednodemap;
struct dom_node;
struct dom_nodelist;
struct dom_string;
@@ -27,9 +30,16 @@
struct dom_node *root, struct dom_string *tagname,
struct dom_string *namespace, struct dom_string *localname,
struct dom_nodelist **list);
-
/* Remove a nodelist */
void dom_document_remove_nodelist(struct dom_document *doc,
struct dom_nodelist *list);
+/* Get a namednodemap, creating one if necessary */
+dom_exception dom_document_get_namednodemap(struct dom_document *doc,
+ struct dom_node *root, dom_namednodemap_type type,
+ struct dom_namednodemap **map);
+/* Remove a namednodemap */
+void dom_document_remove_namednodemap(struct dom_document *doc,
+ struct dom_namednodemap *map);
+
#endif
Added: trunk/dom/src/core/namednodemap.c
URL:
http://source.netsurf-browser.org/trunk/dom/src/core/namednodemap.c?rev=3...
==============================================================================
--- trunk/dom/src/core/namednodemap.c (added)
+++ trunk/dom/src/core/namednodemap.c Wed Jul 11 00:25:18 2007
@@ -1,0 +1,345 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *
http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2007 John-Mark Bell <jmb(a)netsurf-browser.org>
+ */
+
+#include <dom/core/node.h>
+
+#include "core/document.h"
+#include "core/namednodemap.h"
+
+#include "utils/utils.h"
+
+/**
+ * DOM named node map
+ */
+struct dom_namednodemap {
+ struct dom_document *owner; /**< Owning document */
+
+ struct dom_node *root; /**< Node containing items in map */
+
+ dom_namednodemap_type type; /**< Type of map */
+
+ uint32_t refcnt; /**< Reference count */
+};
+
+/**
+ * Create a namednodemap
+ *
+ * \param doc The owning document
+ * \param root Node containing items in map
+ * \param type The type of map
+ * \param map Pointer to location to receive created map
+ * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion
+ *
+ * ::root must be a node owned by ::doc and must be either an Element or
+ * DocumentType node.
+ *
+ * If ::root is of type Element, ::type must be DOM_NAMEDNODEMAP_ATTRIBUTES
+ * If ::root is of type DocumentType, ::type may be either
+ * DOM_NAMEDNODEMAP_ENTITIES or DOM_NAMEDNODEMAP_NOTATIONS.
+ *
+ * The returned map will already be referenced, so the client need not
+ * explicitly reference it. The client must unref the map once it is
+ * finished with it.
+ */
+dom_exception dom_namednodemap_create(struct dom_document *doc,
+ struct dom_node *root, dom_namednodemap_type type,
+ struct dom_namednodemap **map)
+{
+ struct dom_namednodemap *m;
+
+ m = dom_document_alloc(doc, NULL, sizeof(struct dom_namednodemap));
+ if (m == NULL)
+ return DOM_NO_MEM_ERR;
+
+ dom_node_ref((struct dom_node *) doc);
+ m->owner = doc;
+
+ dom_node_ref(root);
+ m->root = root;
+
+ m->type = type;
+
+ m->refcnt = 1;
+
+ *map = m;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Claim a reference on a DOM named node map
+ *
+ * \param map The map to claim a reference on
+ */
+void dom_namednodemap_ref(struct dom_namednodemap *map)
+{
+ map->refcnt++;
+}
+
+/**
+ * Release a reference on a DOM named node map
+ *
+ * \param map The map to release the reference from
+ *
+ * If the reference count reaches zero, any memory claimed by the
+ * map will be released
+ */
+void dom_namednodemap_unref(struct dom_namednodemap *map)
+{
+ if (--map->refcnt == 0) {
+ struct dom_node *owner = (struct dom_node *) map->owner;
+
+ dom_node_unref(map->root);
+
+ /* Remove map from document */
+ dom_document_remove_namednodemap(map->owner, map);
+
+ /* Destroy the map object */
+ dom_document_alloc(map->owner, map, 0);
+
+ /* And release our reference on the owning document
+ * This must be last as, otherwise, it's possible that
+ * the document is destroyed before we are */
+ dom_node_unref(owner);
+ }
+}
+
+/**
+ * Retrieve the length of a named node map
+ *
+ * \param map Map to retrieve length of
+ * \param length Pointer to location to receive length
+ * \return DOM_NO_ERR.
+ */
+dom_exception dom_namednodemap_get_length(struct dom_namednodemap *map,
+ unsigned long *length)
+{
+ UNUSED(map);
+ UNUSED(length);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Retrieve an item by name from a named node map
+ *
+ * \param map The map to retrieve the item from
+ * \param name The name of the item to retrieve
+ * \param node Pointer to location to receive item
+ * \return DOM_NO_ERR.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_get_named_item(struct dom_namednodemap *map,
+ struct dom_string *name, struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(name);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Add a node to a named node map, replacing any matching existing node
+ *
+ * \param map The map to add to
+ * \param arg The node to add
+ * \param node Pointer to location to receive replaced node
+ * \return DOM_NO_ERR on success,
+ * DOM_WRONG_DOCUMENT_ERR if ::arg was created from a
+ * different document than ::map,
+ * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly,
+ * DOM_INUSE_ATTRIBUTE_ERR if ::arg is an Attr that is
+ * already an attribute on another
+ * Element,
+ * DOM_HIERARCHY_REQUEST_ERR if the type of ::arg is not
+ * permitted as a member of ::map.
+ *
+ * ::arg's nodeName attribute will be used to store it in ::map. It will
+ * be accessible using the nodeName attribute as the key for lookup.
+ *
+ * Replacing a node by itself has no effect.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_set_named_item(struct dom_namednodemap *map,
+ struct dom_node *arg, struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(arg);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Remove an item by name from a named node map
+ *
+ * \param map The map to remove from
+ * \param name The name of the item to remove
+ * \param node Pointer to location to receive removed item
+ * \return DOM_NO_ERR on success,
+ * DOM_NOT_FOUND_ERR if there is no node named ::name
+ * in ::map,
+ * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_remove_named_item(
+ struct dom_namednodemap *map, struct dom_string *name,
+ struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(name);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Retrieve an item from a named node map
+ *
+ * \param map The map to retrieve the item from
+ * \param index The map index to retrieve
+ * \param node Pointer to location to receive item
+ * \return DOM_NO_ERR.
+ *
+ * ::index is a zero-based index into ::map.
+ * ::index lies in the range [0, length-1]
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_item(struct dom_namednodemap *map,
+ unsigned long index, struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(index);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Retrieve an item by namespace/localname from a named node map
+ *
+ * \param map The map to retrieve the item from
+ * \param namespace The namespace URI of the item to retrieve
+ * \param localname The local name of the node to retrieve
+ * \param node Pointer to location to receive item
+ * \return DOM_NO_ERR on success,
+ * DOM_NOT_SUPPORTED_ERR if the implementation does not support the
+ * feature "XML" and the language exposed
+ * through the Document does not support
+ * Namespaces.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_get_named_item_ns(
+ struct dom_namednodemap *map, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(namespace);
+ UNUSED(localname);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Add a node to a named node map, replacing any matching existing node
+ *
+ * \param map The map to add to
+ * \param arg The node to add
+ * \param node Pointer to location to receive replaced node
+ * \return DOM_NO_ERR on success,
+ * DOM_WRONG_DOCUMENT_ERR if ::arg was created from a
+ * different document than ::map,
+ * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly,
+ * DOM_INUSE_ATTRIBUTE_ERR if ::arg is an Attr that is
+ * already an attribute on another
+ * Element,
+ * DOM_HIERARCHY_REQUEST_ERR if the type of ::arg is not
+ * permitted as a member of ::map.
+ * DOM_NOT_SUPPORTED_ERR if the implementation does not support the
+ * feature "XML" and the language exposed
+ * through the Document does not support
+ * Namespaces.
+ *
+ * ::arg's namespaceURI and localName attributes will be used to store it in
+ * ::map. It will be accessible using the namespaceURI and localName
+ * attributes as the keys for lookup.
+ *
+ * Replacing a node by itself has no effect.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_set_named_item_ns(
+ struct dom_namednodemap *map, struct dom_node *arg,
+ struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(arg);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Remove an item by namespace/localname from a named node map
+ *
+ * \param map The map to remove from
+ * \param namespace The namespace URI of the item to remove
+ * \param localname The local name of the item to remove
+ * \param node Pointer to location to receive removed item
+ * \return DOM_NO_ERR on success,
+ * DOM_NOT_FOUND_ERR if there is no node named ::name
+ * in ::map,
+ * DOM_NO_MODIFICATION_ALLOWED_ERR if ::map is readonly.
+ * DOM_NOT_SUPPORTED_ERR if the implementation does not support the
+ * feature "XML" and the language exposed
+ * through the Document does not support
+ * Namespaces.
+ *
+ * The returned node will have had its reference count increased. The client
+ * should unref the node once it has finished with it.
+ */
+dom_exception dom_namednodemap_remove_named_item_ns(
+ struct dom_namednodemap *map, struct dom_string *namespace,
+ struct dom_string *localname, struct dom_node **node)
+{
+ UNUSED(map);
+ UNUSED(namespace);
+ UNUSED(localname);
+ UNUSED(node);
+
+ return DOM_NOT_SUPPORTED_ERR;
+}
+
+/**
+ * Match a namednodemap instance against a set of creation parameters
+ *
+ * \param map The map to match
+ * \param root Node containing items in map
+ * \param type The type of map
+ * \return true if list matches, false otherwise
+ */
+bool dom_namednodemap_match(struct dom_namednodemap *map,
+ struct dom_node *root, dom_namednodemap_type type)
+{
+ if (map->root == root && map->type == type)
+ return true;
+
+ return false;
+}
Added: trunk/dom/src/core/namednodemap.h
URL:
http://source.netsurf-browser.org/trunk/dom/src/core/namednodemap.h?rev=3...
==============================================================================
--- trunk/dom/src/core/namednodemap.h (added)
+++ trunk/dom/src/core/namednodemap.h Wed Jul 11 00:25:18 2007
@@ -1,0 +1,39 @@
+/*
+ * This file is part of libdom.
+ * Licensed under the MIT License,
+ *
http://www.opensource.org/licenses/mit-license.php
+ * Copyright 2007 John-Mark Bell <jmb(a)netsurf-browser.org>
+ */
+
+#ifndef dom_internal_namednodemap_h_
+#define dom_internal_namednodemap_h_
+
+#include <stdbool.h>
+
+#include <dom/core/namednodemap.h>
+
+struct dom_document;
+struct dom_node;
+struct dom_namednodemap;
+struct dom_string;
+
+/**
+ * Type of a named node map
+ */
+typedef enum {
+ DOM_NAMEDNODEMAP_ATTRIBUTES,
+ DOM_NAMEDNODEMAP_ENTITIES,
+ DOM_NAMEDNODEMAP_NOTATIONS
+} dom_namednodemap_type;
+
+/* Create a namednodemap */
+dom_exception dom_namednodemap_create(struct dom_document *doc,
+ struct dom_node *root, dom_namednodemap_type type,
+ struct dom_namednodemap **map);
+
+
+/* Match a namednodemap instance against a set of creation parameters */
+bool dom_namednodemap_match(struct dom_namednodemap *map,
+ struct dom_node *root, dom_namednodemap_type type);
+
+#endif
Modified: trunk/dom/src/core/nodelist.c
URL:
http://source.netsurf-browser.org/trunk/dom/src/core/nodelist.c?rev=3395&...
==============================================================================
--- trunk/dom/src/core/nodelist.c (original)
+++ trunk/dom/src/core/nodelist.c Wed Jul 11 00:25:18 2007
@@ -62,7 +62,7 @@
* will match the children of ::root.
*
* The returned list will already be referenced, so the client need not
- * do so explicitly. The client should unref the list once finished with it.
+ * do so explicitly. The client must unref the list once finished with it.
*/
dom_exception dom_nodelist_create(struct dom_document *doc,
struct dom_node *root, struct dom_string *tagname,
@@ -124,6 +124,8 @@
void dom_nodelist_unref(struct dom_nodelist *list)
{
if (--list->refcnt == 0) {
+ struct dom_node *owner = (struct dom_node *) list->owner;
+
switch (list->type) {
case DOM_NODELIST_CHILDREN:
/* Nothing to do */
@@ -139,13 +141,16 @@
dom_node_unref(list->root);
- dom_node_unref((struct dom_node *) list->owner);
-
/* Remove list from document */
dom_document_remove_nodelist(list->owner, list);
- /* And destroy the list object */
+ /* Destroy the list object */
dom_document_alloc(list->owner, list, 0);
+
+ /* And release our reference on the owning document
+ * This must be last as, otherwise, it's possible that
+ * the document is destroyed before we are */
+ dom_node_unref(owner);
}
}