r3554 jmb - /trunk/dom/src/core/node.c
by netsurf@semichrome.net
Author: jmb
Date: Sat Sep 22 01:35:13 2007
New Revision: 3554
URL: http://source.netsurf-browser.org?rev=3554&view=rev
Log:
Move cardinality constraint checking for Document Element and DocumentType children to _dom_node_permitted_child().
Break tree insertion/removal code out from dom_node_insert_before() and into their own utility routines.
Modified:
trunk/dom/src/core/node.c
Modified: trunk/dom/src/core/node.c
URL: http://source.netsurf-browser.org/trunk/dom/src/core/node.c?rev=3554&r1=3...
==============================================================================
--- trunk/dom/src/core/node.c (original)
+++ trunk/dom/src/core/node.c Sat Sep 22 01:35:13 2007
@@ -27,6 +27,18 @@
static bool _dom_node_permitted_child(const struct dom_node *parent,
const struct dom_node *child);
static bool _dom_node_readonly(const struct dom_node *node);
+static inline void _dom_node_attach(struct dom_node *node,
+ struct dom_node *parent,
+ struct dom_node *previous,
+ struct dom_node *next);
+static inline void _dom_node_detach(struct dom_node *node);
+static inline void _dom_node_attach_range(struct dom_node *first,
+ struct dom_node *last,
+ struct dom_node *parent,
+ struct dom_node *previous,
+ struct dom_node *next);
+static inline void _dom_node_detach_range(struct dom_node *first,
+ struct dom_node *last);
/**
* Destroy a DOM node
@@ -603,26 +615,6 @@
return DOM_HIERARCHY_REQUEST_ERR;
}
- /* Ensure that the document doesn't already have a root element */
- if (node->type == DOM_DOCUMENT_NODE &&
- new_child->type == DOM_ELEMENT_NODE) {
- for (struct dom_node *n = node->first_child;
- n != NULL; n = n->next) {
- if (n->type == DOM_ELEMENT_NODE)
- return DOM_HIERARCHY_REQUEST_ERR;
- }
- }
-
- /* Ensure that the document doesn't already have a document type */
- if (node->type == DOM_DOCUMENT_NODE &&
- new_child->type == DOM_DOCUMENT_TYPE_NODE) {
- for (struct dom_node *n = node->first_child;
- n != NULL; n = n->next) {
- if (n->type == DOM_DOCUMENT_TYPE_NODE)
- return DOM_HIERARCHY_REQUEST_ERR;
- }
- }
-
/* Ensure that new_child is permitted as a child of node */
if (!_dom_node_permitted_child(node, new_child))
return DOM_HIERARCHY_REQUEST_ERR;
@@ -646,83 +638,31 @@
}
/* If new_child is already in the tree, remove it */
- if (new_child->parent != NULL) {
- if (new_child->previous != NULL)
- new_child->previous->next = new_child->next;
- else
- new_child->parent->first_child = new_child->next;
-
- if (new_child->next != NULL)
- new_child->next->previous = new_child->previous;
- else
- new_child->parent->last_child = new_child->previous;
- }
+ if (new_child->parent != NULL)
+ _dom_node_detach(new_child);
/* If new_child is a DocumentFragment, insert its children
* Otherwise, insert new_child */
if (new_child->type == DOM_DOCUMENT_FRAGMENT_NODE) {
if (new_child->first_child != NULL) {
- /* Reparent children */
- for (struct dom_node *c = new_child->first_child;
- c != NULL; c = c->next)
- c->parent = node;
-
- if (ref_child == NULL) {
- new_child->first_child->previous =
- node->last_child;
-
- if (node->last_child != NULL) {
- node->last_child->next =
- new_child->first_child;
- } else {
- node->first_child =
- new_child->first_child;
- }
-
- node->last_child = new_child->last_child;
- } else {
- new_child->first_child->previous =
- ref_child->previous;
-
- if (ref_child->previous != NULL) {
- ref_child->previous->next =
- new_child->first_child;
- } else {
- node->first_child =
- new_child->first_child;
- }
-
- new_child->last_child->next = ref_child;
- ref_child->previous = new_child->last_child;
- }
+ _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);
new_child->first_child = NULL;
new_child->last_child = NULL;
}
} else {
- new_child->parent = node;
-
- if (ref_child == NULL) {
- new_child->previous = node->last_child;
- new_child->next = NULL;
-
- if (node->last_child != NULL)
- node->last_child->next = new_child;
- else
- node->first_child = new_child;
-
- node->last_child = new_child;
- } else {
- new_child->previous = ref_child->previous;
- new_child->next = ref_child;
-
- if (ref_child->previous != NULL)
- ref_child->previous->next = new_child;
- else
- node->first_child = new_child;
-
- ref_child->previous = new_child;
- }
+ _dom_node_attach(new_child,
+ node,
+ ref_child == NULL ? node->last_child
+ : ref_child->previous,
+ ref_child == NULL ? NULL
+ : ref_child);
}
/** \todo Is it correct to return DocumentFragments? */
@@ -1421,12 +1361,31 @@
break;
case DOM_DOCUMENT_NODE:
- /* Cardinality constraints (for Element & DocumentType) are
- * handled by _insert_before and friends */
valid = (child->type == DOM_ELEMENT_NODE ||
child->type == DOM_PROCESSING_INSTRUCTION_NODE ||
child->type == DOM_COMMENT_NODE ||
child->type == DOM_DOCUMENT_TYPE_NODE);
+
+ /* Ensure that the document doesn't already
+ * have a root element */
+ if (child->type == DOM_ELEMENT_NODE) {
+ for (struct dom_node *n = parent->first_child;
+ n != NULL; n = n->next) {
+ if (n->type == DOM_ELEMENT_NODE)
+ valid = false;
+ }
+ }
+
+ /* Ensure that the document doesn't already
+ * have a document type */
+ if (child->type == DOM_DOCUMENT_TYPE_NODE) {
+ for (struct dom_node *n = parent->first_child;
+ n != NULL; n = n->next) {
+ if (n->type == DOM_DOCUMENT_TYPE_NODE)
+ valid = false;
+ }
+ }
+
break;
}
@@ -1461,4 +1420,86 @@
return false;
}
-
+/**
+ * Attach a node to the tree
+ *
+ * \param node The node to attach
+ * \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
+ */
+inline void _dom_node_attach(struct dom_node *node, struct dom_node *parent,
+ struct dom_node *previous, struct dom_node *next)
+{
+ _dom_node_attach_range(node, node, parent, previous, next);
+}
+
+/**
+ * Detach a node from the tree
+ *
+ * \param node The node to detach
+ */
+inline void _dom_node_detach(struct dom_node *node)
+{
+ _dom_node_detach_range(node, node);
+}
+
+/**
+ * Attach a range of nodes to the tree
+ *
+ * \param first First node in the range
+ * \param last Last node in the range
+ * \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
+ *
+ * The range is assumed to be a linked list of sibling nodes.
+ */
+inline void _dom_node_attach_range(struct dom_node *first,
+ struct dom_node *last,
+ struct dom_node *parent,
+ struct dom_node *previous,
+ struct dom_node *next)
+{
+ first->previous = previous;
+ last->next = next;
+
+ if (previous != NULL)
+ previous->next = first;
+ else
+ parent->first_child = first;
+
+ if (next != NULL)
+ next->previous = last;
+ else
+ parent->last_child = last;
+
+ for (struct dom_node *n = first; n != last->next; n = n->next)
+ n->parent = parent;
+}
+
+/**
+ * Detach a range of nodes from the tree
+ *
+ * \param first The first node in the range
+ * \param last The last node in the range
+ *
+ * The range is assumed to be a linked list of sibling nodes.
+ */
+inline void _dom_node_detach_range(struct dom_node *first,
+ struct dom_node *last)
+{
+ if (first->previous != NULL)
+ first->previous->next = last->next;
+ else
+ first->parent->first_child = last->next;
+
+ if (last->next != NULL)
+ last->next->previous = first->previous;
+ else
+ last->parent->last_child = first->previous;
+
+ for (struct dom_node *n = first; n != last->next; n = n->next)
+ n->parent = NULL;
+}
+
15 years, 8 months
r3553 jmb - /trunk/dom/src/core/node.c
by netsurf@semichrome.net
Author: jmb
Date: Fri Sep 21 00:22:41 2007
New Revision: 3553
URL: http://source.netsurf-browser.org?rev=3553&view=rev
Log:
Implement dom_node_get_node_name()
Implement dom_node_get_node_value()
Implement dom_node_set_node_value()
Implement utility routines to determine if a given node type is permitted as a child of a node and to detect if a given node is read only.
Modified:
trunk/dom/src/core/node.c
Modified: trunk/dom/src/core/node.c
URL: http://source.netsurf-browser.org/trunk/dom/src/core/node.c?rev=3553&r1=3...
==============================================================================
--- trunk/dom/src/core/node.c (original)
+++ trunk/dom/src/core/node.c Fri Sep 21 00:22:41 2007
@@ -6,6 +6,7 @@
*/
#include <assert.h>
+#include <stdbool.h>
#include <dom/core/document.h>
#include <dom/core/string.h>
@@ -22,6 +23,10 @@
#include "core/pi.h"
#include "core/text.h"
#include "utils/utils.h"
+
+static bool _dom_node_permitted_child(const struct dom_node *parent,
+ const struct dom_node *child);
+static bool _dom_node_readonly(const struct dom_node *node);
/**
* Destroy a DOM node
@@ -269,10 +274,12 @@
dom_exception dom_node_get_node_name(struct dom_node *node,
struct dom_string **result)
{
- UNUSED(node);
- UNUSED(result);
-
- return DOM_NOT_SUPPORTED_ERR;
+ if (node->name != NULL)
+ dom_string_ref(node->name);
+
+ *result = node->name;
+
+ return DOM_NO_ERR;
}
/**
@@ -292,10 +299,12 @@
dom_exception dom_node_get_node_value(struct dom_node *node,
struct dom_string **result)
{
- UNUSED(node);
- UNUSED(result);
-
- return DOM_NOT_SUPPORTED_ERR;
+ if (node->value != NULL)
+ dom_string_ref(node->value);
+
+ *result = node->value;
+
+ return DOM_NO_ERR;
}
/**
@@ -314,10 +323,30 @@
dom_exception dom_node_set_node_value(struct dom_node *node,
struct dom_string *value)
{
- UNUSED(node);
- UNUSED(value);
-
- return DOM_NOT_SUPPORTED_ERR;
+ /* This is a NOP if the value is defined to be null. */
+ if (node->type == DOM_DOCUMENT_NODE ||
+ node->type == DOM_DOCUMENT_FRAGMENT_NODE ||
+ node->type == DOM_DOCUMENT_TYPE_NODE ||
+ node->type == DOM_ELEMENT_NODE ||
+ node->type == DOM_ENTITY_NODE ||
+ node->type == DOM_ENTITY_REFERENCE_NODE ||
+ node->type == DOM_NOTATION_NODE) {
+ return DOM_NO_ERR;
+ }
+
+ /* Ensure node is writable */
+ if (_dom_node_readonly(node))
+ return DOM_NO_MODIFICATION_ALLOWED_ERR;
+
+ if (node->value != NULL)
+ dom_string_unref(node->value);
+
+ if (value != NULL)
+ dom_string_ref(value);
+
+ node->value = value;
+
+ return DOM_NO_ERR;
}
/**
@@ -327,7 +356,8 @@
* \param result Pointer to location to receive node type
* \return DOM_NO_ERR.
*/
-dom_exception dom_node_get_node_type(struct dom_node *node, dom_node_type *result)
+dom_exception dom_node_get_node_type(struct dom_node *node,
+ dom_node_type *result)
{
*result = node->type;
@@ -559,7 +589,9 @@
new_child->owner != node->owner))
return DOM_WRONG_DOCUMENT_ERR;
- /** \todo ensure ::node may be written to */
+ /* Ensure node isn't read only */
+ if (_dom_node_readonly(node))
+ return DOM_NO_MODIFICATION_ALLOWED_ERR;
/* Ensure that ref_child (if any) is a child of node */
if (ref_child != NULL && ref_child->parent != node)
@@ -591,7 +623,9 @@
}
}
- /** \todo ensure ::new_child is permitted as a child of ::node */
+ /* Ensure that new_child is permitted as a child of node */
+ if (!_dom_node_permitted_child(node, new_child))
+ return DOM_HIERARCHY_REQUEST_ERR;
/* DocumentType nodes are created outside the Document so,
* if we're trying to attach a DocumentType node, then we
@@ -1341,3 +1375,90 @@
return DOM_NO_ERR;
}
+/* */
+/*----------------------------------------------------------------------------*/
+/* */
+
+/**
+ * Determine if a node is permitted as a child of another node
+ *
+ * \param parent Prospective parent
+ * \param child Prospective child
+ * \return true if ::child is permitted as a child of ::parent, false otherwise.
+ */
+bool _dom_node_permitted_child(const struct dom_node *parent,
+ const struct dom_node *child)
+{
+ bool valid;
+
+ /* See DOM3Core $1.1.1 for details */
+
+ switch (parent->type) {
+ case DOM_ELEMENT_NODE:
+ case DOM_ENTITY_REFERENCE_NODE:
+ case DOM_ENTITY_NODE:
+ case DOM_DOCUMENT_FRAGMENT_NODE:
+ valid = (child->type == DOM_ELEMENT_NODE ||
+ child->type == DOM_TEXT_NODE ||
+ child->type == DOM_COMMENT_NODE ||
+ child->type == DOM_PROCESSING_INSTRUCTION_NODE ||
+ child->type == DOM_CDATA_SECTION_NODE ||
+ child->type == DOM_ENTITY_REFERENCE_NODE);
+ break;
+
+ case DOM_ATTRIBUTE_NODE:
+ valid = (child->type == DOM_TEXT_NODE ||
+ child->type == DOM_ENTITY_REFERENCE_NODE);
+ break;
+
+ case DOM_TEXT_NODE:
+ case DOM_CDATA_SECTION_NODE:
+ case DOM_PROCESSING_INSTRUCTION_NODE:
+ case DOM_COMMENT_NODE:
+ case DOM_DOCUMENT_TYPE_NODE:
+ case DOM_NOTATION_NODE:
+ valid = false;
+ break;
+
+ case DOM_DOCUMENT_NODE:
+ /* Cardinality constraints (for Element & DocumentType) are
+ * handled by _insert_before and friends */
+ valid = (child->type == DOM_ELEMENT_NODE ||
+ child->type == DOM_PROCESSING_INSTRUCTION_NODE ||
+ child->type == DOM_COMMENT_NODE ||
+ child->type == DOM_DOCUMENT_TYPE_NODE);
+ break;
+ }
+
+ return valid;
+}
+
+/**
+ * Determine if a node is read only
+ *
+ * \param node The node to consider
+ */
+bool _dom_node_readonly(const struct dom_node *node)
+{
+ /* DocumentType and Notation nodes are read only */
+ if (node->type == DOM_DOCUMENT_TYPE_NODE ||
+ node->type == DOM_NOTATION_NODE)
+ return true;
+
+ /* Entity nodes and their descendants are read only */
+ for (; node != NULL; node = node->parent) {
+ if (node->type == DOM_ENTITY_NODE)
+ return true;
+ }
+
+ /* EntityReference nodes and their descendants are read only */
+ for (; node != NULL; node = node->parent) {
+ if (node->type == DOM_ENTITY_REFERENCE_NODE)
+ return true;
+ }
+
+ /* Otherwise, it's writable */
+ return false;
+}
+
+
15 years, 8 months
r3552 jmb - in /trunk/dom/test: binding.c testutils.h
by netsurf@semichrome.net
Author: jmb
Date: Thu Sep 20 00:00:22 2007
New Revision: 3552
URL: http://source.netsurf-browser.org?rev=3552&view=rev
Log:
Stop TestObject appending .xml to the filename -- the auto-generated testcases already have it appended.
Fixup binding testcase appropriately.
Modified:
trunk/dom/test/binding.c
trunk/dom/test/testutils.h
Modified: trunk/dom/test/binding.c
URL: http://source.netsurf-browser.org/trunk/dom/test/binding.c?rev=3552&r1=35...
==============================================================================
--- trunk/dom/test/binding.c (original)
+++ trunk/dom/test/binding.c Thu Sep 20 00:00:22 2007
@@ -9,7 +9,7 @@
dom_exception err;
TestObject *staff;
- staff = test_object_create(argc, argv, "staff", false);
+ staff = test_object_create(argc, argv, "staff.xml", false);
assert(staff != NULL);
doc = test_object_get_doc(staff);
Modified: trunk/dom/test/testutils.h
URL: http://source.netsurf-browser.org/trunk/dom/test/testutils.h?rev=3552&r1=...
==============================================================================
--- trunk/dom/test/testutils.h (original)
+++ trunk/dom/test/testutils.h Thu Sep 20 00:00:22 2007
@@ -90,7 +90,7 @@
xml_parser_initialised = true;
}
- snprintf(fnbuf, sizeof fnbuf, "%s/%s.xml", argv[1], uri);
+ snprintf(fnbuf, sizeof fnbuf, "%s/%s", argv[1], uri);
ret = malloc(sizeof(TestObject));
if (ret == NULL)
15 years, 8 months
r3551 jmb - in /trunk/dom: bindings/xml/xmlbinding.c bindings/xml/xmlparser.c include/dom/bootstrap/implpriv.h src/core/document.c src/core/document_type.c src/core/document_type.h src/core/node.c
by netsurf@semichrome.net
Author: jmb
Date: Wed Sep 19 23:06:26 2007
New Revision: 3551
URL: http://source.netsurf-browser.org?rev=3551&view=rev
Log:
Begin implementation of DocumentType class
Remove dom_document_set_doctype() -- dom_node_insert_before() (and thus _append_child()) can be used to achieve the same effect.
DocumentType node is now a child of the Document node (as it should have been) rather than a hidden field.
Make dom_node_destroy() aware of DocumentType nodes potentially having no owner.
Make dom_node_finalise() aware of it, too.
Make dom_node_get_owner_document() return NULL for Document nodes, as per the spec.
Fix bug in dom_node_insert_before() -- previously it failed to catch attempts to insert a second root element.
Make dom_node_insert_before() handle DocumentType nodes appropriately.
Implement XML binding's dom_implementation_create_document_type() function.
Fix XML binding's dom_implementation_create_document() implementation to cope with changed API relating to doctype insertion.
Fix up XML parser wrapper to cater for new doctype insertion mechanism. Also sprinkle some NULL about for paranoia purposes.
Added:
trunk/dom/src/core/document_type.h
Modified:
trunk/dom/bindings/xml/xmlbinding.c
trunk/dom/bindings/xml/xmlparser.c
trunk/dom/include/dom/bootstrap/implpriv.h
trunk/dom/src/core/document.c
trunk/dom/src/core/document_type.c
trunk/dom/src/core/node.c
Modified: trunk/dom/bindings/xml/xmlbinding.c
URL: http://source.netsurf-browser.org/trunk/dom/bindings/xml/xmlbinding.c?rev...
==============================================================================
--- trunk/dom/bindings/xml/xmlbinding.c (original)
+++ trunk/dom/bindings/xml/xmlbinding.c Wed Sep 19 23:06:26 2007
@@ -193,11 +193,7 @@
* \param pw Pointer to client-specific private data
* \return DOM_NO_ERR on success,
* DOM_INVALID_CHARACTER_ERR if ::qname is invalid,
- * DOM_NAMESPACE_ERR if ::qname is malformed,
- * DOM_NOT_SUPPORTED_ERR if ::impl does not support the
- * feature "XML" and the language
- * exposed through Document does
- * not support XML namespaces.
+ * DOM_NAMESPACE_ERR if ::qname is malformed.
*
* Any memory allocated by this call should be allocated using
* the provided memory (de)allocation function.
@@ -214,15 +210,23 @@
struct dom_document_type **doctype,
dom_alloc alloc, void *pw)
{
+ struct dom_document_type *d;
+ dom_exception err;
+
+ /* We have no use for the impl -- we only have one */
UNUSED(impl);
- UNUSED(qname);
- UNUSED(public_id);
- UNUSED(system_id);
- UNUSED(doctype);
- UNUSED(alloc);
- UNUSED(pw);
-
- return DOM_NOT_SUPPORTED_ERR;
+
+ /** \todo validate qname */
+
+ /* Create the doctype */
+ err = dom_document_type_create(qname, public_id, system_id,
+ alloc, pw, &d);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ *doctype = d;
+
+ return DOM_NO_ERR;
}
/**
@@ -281,11 +285,18 @@
/* Set its doctype, if necessary */
if (doctype != NULL) {
- err = dom_document_set_doctype(d, doctype);
+ struct dom_node *ins_doctype = NULL;
+
+ err = dom_node_append_child((struct dom_node *) d,
+ (struct dom_node *) doctype, &ins_doctype);
if (err != DOM_NO_ERR) {
dom_node_unref((struct dom_node *) d);
return err;
}
+
+ /* Not interested in inserted doctype */
+ if (ins_doctype != NULL)
+ dom_node_unref(ins_doctype);
}
/* Create root element and attach it to document */
Modified: trunk/dom/bindings/xml/xmlparser.c
URL: http://source.netsurf-browser.org/trunk/dom/bindings/xml/xmlparser.c?rev=...
==============================================================================
--- trunk/dom/bindings/xml/xmlparser.c (original)
+++ trunk/dom/bindings/xml/xmlparser.c Wed Sep 19 23:06:26 2007
@@ -637,7 +637,7 @@
void xml_parser_add_element_node(xml_parser *parser, struct dom_node *parent,
xmlNodePtr child)
{
- struct dom_element *el, *ins_el;
+ struct dom_element *el, *ins_el = NULL;
xmlAttrPtr a;
dom_exception err;
@@ -896,7 +896,7 @@
void xml_parser_add_text_node(xml_parser *parser, struct dom_node *parent,
xmlNodePtr child)
{
- struct dom_text *text, *ins_text;
+ struct dom_text *text, *ins_text = NULL;
struct dom_string *data;
dom_exception err;
@@ -957,7 +957,7 @@
void xml_parser_add_cdata_section(xml_parser *parser,
struct dom_node *parent, xmlNodePtr child)
{
- struct dom_cdata_section *cdata, *ins_cdata;
+ struct dom_cdata_section *cdata, *ins_cdata = NULL;
struct dom_string *data;
dom_exception err;
@@ -1018,7 +1018,7 @@
void xml_parser_add_entity_reference(xml_parser *parser,
struct dom_node *parent, xmlNodePtr child)
{
- struct dom_entity_reference *entity, *ins_entity;
+ struct dom_entity_reference *entity, *ins_entity = NULL;
struct dom_string *name;
xmlNodePtr c;
dom_exception err;
@@ -1086,7 +1086,7 @@
void xml_parser_add_comment(xml_parser *parser, struct dom_node *parent,
xmlNodePtr child)
{
- struct dom_comment *comment, *ins_comment;
+ struct dom_comment *comment, *ins_comment = NULL;
struct dom_string *data;
dom_exception err;
@@ -1148,7 +1148,7 @@
struct dom_node *parent, xmlNodePtr child)
{
xmlDtdPtr dtd = (xmlDtdPtr) child;
- struct dom_document_type *doctype;
+ struct dom_document_type *doctype, *ins_doctype = NULL;
struct dom_string *qname, *public_id, *system_id;
dom_exception err;
@@ -1207,14 +1207,18 @@
dom_string_unref(qname);
/* Add doctype to document */
- err = dom_document_set_doctype((struct dom_document *) parent,
- doctype);
+ err = dom_node_append_child(parent, (struct dom_node *) doctype,
+ (struct dom_node **) &ins_doctype);
if (err != DOM_NO_ERR) {
dom_node_unref((struct dom_node *) doctype);
parser->msg(XML_MSG_CRITICAL, parser->mctx,
"Failed attaching doctype");
return;
}
+
+ /* Not interested in inserted node */
+ if (ins_doctype != NULL)
+ dom_node_unref((struct dom_node *) ins_doctype);
/* Link nodes together */
err = xml_parser_link_nodes(parser, (struct dom_node *) doctype,
Modified: trunk/dom/include/dom/bootstrap/implpriv.h
URL: http://source.netsurf-browser.org/trunk/dom/include/dom/bootstrap/implpri...
==============================================================================
--- trunk/dom/include/dom/bootstrap/implpriv.h (original)
+++ trunk/dom/include/dom/bootstrap/implpriv.h Wed Sep 19 23:06:26 2007
@@ -14,6 +14,9 @@
*
* The Document implementation includes this as it needs the declaration of
* dom_document_create and dom_document_set_doctype.
+ *
+ * The DocumentType implementation includes this as it needs the declaration
+ * of dom_document_type_create.
*
* No other client should be including this.
*/
@@ -248,8 +251,11 @@
dom_exception dom_document_create(struct dom_implementation *impl,
dom_alloc alloc, void *pw, struct dom_document **doc);
-/* Set a Document's DocumentType */
-dom_exception dom_document_set_doctype(struct dom_document *doc,
- struct dom_document_type *doctype);
+/* Create a DOM document type */
+dom_exception dom_document_type_create(struct dom_string *qname,
+ struct dom_string *public_id,
+ struct dom_string *system_id,
+ dom_alloc alloc, void *pw,
+ struct dom_document_type **doctype);
#endif
Modified: trunk/dom/src/core/document.c
URL: http://source.netsurf-browser.org/trunk/dom/src/core/document.c?rev=3551&...
==============================================================================
--- trunk/dom/src/core/document.c (original)
+++ trunk/dom/src/core/document.c Wed Sep 19 23:06:26 2007
@@ -54,8 +54,6 @@
*/
struct dom_document {
struct dom_node base; /**< Base node */
-
- struct dom_document_type *type; /**< Associated doctype */
struct dom_implementation *impl; /**< Owning implementation */
@@ -157,8 +155,6 @@
}
/* Initialise remaining type-specific data */
- d->type = NULL;
-
if (impl != NULL)
dom_implementation_ref(impl);
d->impl = impl;
@@ -210,15 +206,6 @@
/* Ok, the document tree is empty, as is the list of nodes pending
* deletion. Therefore, it is safe to destroy the document. */
-
- /* Destroy the doctype (if there is one) */
- if (doc->type != NULL) {
- ((struct dom_node *) doc->type)->parent = NULL;
-
- dom_node_destroy((struct dom_node *) doc->type);
- }
-
- doc->type = NULL;
if (doc->impl != NULL)
dom_implementation_unref(doc->impl);
@@ -258,10 +245,17 @@
dom_exception dom_document_get_doctype(struct dom_document *doc,
struct dom_document_type **result)
{
- if (doc->type != NULL)
- dom_node_ref((struct dom_node *) doc->type);
-
- *result = doc->type;
+ struct dom_node *c;
+
+ for (c = doc->base.first_child; c != NULL; c = c->next) {
+ if (c->type == DOM_DOCUMENT_TYPE_NODE)
+ break;
+ }
+
+ if (c != NULL)
+ dom_node_ref(c);
+
+ *result = (struct dom_document_type *) c;
return DOM_NO_ERR;
}
@@ -941,31 +935,6 @@
/* */
/**
- * Set a Document's Document Type
- *
- * \param doc Document to set type of
- * \param doctype The doctype to apply
- * \return DOM_NO_ERR on success,
- * DOM_INVALID_MODIFICATION_ERR if ::doc already has a doctype.
- *
- * The doctype will have its reference count increased. It is the
- * responsibility of the caller to unref the doctype once it has finished
- * with it.
- */
-dom_exception dom_document_set_doctype(struct dom_document *doc,
- struct dom_document_type *doctype)
-{
- UNUSED(doc);
- UNUSED(doctype);
-
- return DOM_NOT_SUPPORTED_ERR;
-}
-
-/* */
-/* ----------------------------------------------------------------------- */
-/* */
-
-/**
* Acquire a pointer to the base of the document buffer
*
* \param doc Document to retrieve pointer from
Modified: trunk/dom/src/core/document_type.c
URL: http://source.netsurf-browser.org/trunk/dom/src/core/document_type.c?rev=...
==============================================================================
--- trunk/dom/src/core/document_type.c (original)
+++ trunk/dom/src/core/document_type.c Wed Sep 19 23:06:26 2007
@@ -7,7 +7,10 @@
*/
#include <dom/core/document_type.h>
-
+#include <dom/core/string.h>
+#include <dom/bootstrap/implpriv.h>
+
+#include "core/document_type.h"
#include "core/node.h"
#include "utils/utils.h"
@@ -18,7 +21,83 @@
struct dom_node base; /**< Base node */
/** \todo other members */
+ struct dom_string *public_id; /**< Doctype public ID */
+ struct dom_string *system_id; /**< Doctype system ID */
+
+ dom_alloc alloc; /**< Memory (de)allocation function */
+ void *pw; /**< Pointer to private data */
};
+
+/**
+ * Create a document type node
+ *
+ * \param qname The qualified name of the document type
+ * \param public_id The external subset public identifier
+ * \param system_id The external subset system identifier
+ * \param alloc Memory (de)allocation function
+ * \param pw Pointer to client-specific private data
+ * \param doctype Pointer to location to receive result
+ * \return DOM_NO_ERR on success, DOM_NO_MEM_ERR on memory exhaustion.
+ *
+ * The doctype will be referenced, so the client need not do so
+ * explicitly. The client must unref the doctype once it has
+ * finished with it.
+ */
+dom_exception dom_document_type_create(struct dom_string *qname,
+ struct dom_string *public_id, struct dom_string *system_id,
+ dom_alloc alloc, void *pw, struct dom_document_type **doctype)
+{
+ struct dom_document_type *result;
+ dom_exception err;
+
+ /* Create node */
+ result = alloc(NULL, sizeof(struct dom_document_type), pw);
+ if (result == NULL)
+ return DOM_NO_MEM_ERR;
+
+ /* Initialise base node */
+ err = dom_node_initialise(&result->base, NULL, DOM_DOCUMENT_TYPE_NODE,
+ qname, NULL);
+ if (err != DOM_NO_ERR) {
+ alloc(result, 0, pw);
+ return err;
+ }
+
+ /* Get public and system IDs */
+ dom_string_ref(public_id);
+ result->public_id = public_id;
+
+ dom_string_ref(system_id);
+ result->system_id = system_id;
+
+ /* Fill in allocation information */
+ result->alloc = alloc;
+ result->pw = pw;
+
+ *doctype = result;
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Destroy a DocumentType node
+ *
+ * \param doctype The DocumentType node to destroy
+ *
+ * The contents of ::doctype will be destroyed and ::doctype will be freed.
+ */
+void dom_document_type_destroy(struct dom_document_type *doctype)
+{
+ /* Finish with public and system IDs */
+ dom_string_unref(doctype->system_id);
+ dom_string_unref(doctype->public_id);
+
+ /* Finalise base class */
+ dom_node_finalise(doctype->base.owner, &doctype->base);
+
+ /* Free doctype */
+ doctype->alloc(doctype, 0, doctype->pw);
+}
/**
* Retrieve a document type's name
Added: trunk/dom/src/core/document_type.h
URL: http://source.netsurf-browser.org/trunk/dom/src/core/document_type.h?rev=...
==============================================================================
--- trunk/dom/src/core/document_type.h (added)
+++ trunk/dom/src/core/document_type.h Wed Sep 19 23:06:26 2007
@@ -1,0 +1,17 @@
+/*
+ * 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_core_document_type_h_
+#define dom_internal_core_document_type_h_
+
+struct dom_document_type;
+
+/* Destroy a document type */
+void dom_document_type_destroy(struct dom_document_type *doctype);
+
+#endif
+
Modified: trunk/dom/src/core/node.c
URL: http://source.netsurf-browser.org/trunk/dom/src/core/node.c?rev=3551&r1=3...
==============================================================================
--- trunk/dom/src/core/node.c (original)
+++ trunk/dom/src/core/node.c Wed Sep 19 23:06:26 2007
@@ -14,6 +14,7 @@
#include "core/cdatasection.h"
#include "core/comment.h"
#include "core/document.h"
+#include "core/document_type.h"
#include "core/doc_fragment.h"
#include "core/element.h"
#include "core/entity_ref.h"
@@ -39,14 +40,15 @@
void dom_node_destroy(struct dom_node *node)
{
struct dom_document *owner = node->owner;
- bool document_node = (node->type == DOM_DOCUMENT_NODE);
+ bool null_owner_permitted = (node->type == DOM_DOCUMENT_NODE ||
+ node->type == DOM_DOCUMENT_TYPE_NODE);
/* This function simply acts as a central despatcher
* for type-specific destructors. */
- assert(owner != NULL);
-
- if (!document_node) {
+ assert(null_owner_permitted || owner != NULL);
+
+ if (!null_owner_permitted) {
/* Claim a reference upon the owning document during
* destruction to ensure that the document doesn't get
* destroyed before its contents. */
@@ -85,7 +87,7 @@
dom_document_destroy((struct dom_document *) node);
break;
case DOM_DOCUMENT_TYPE_NODE:
- /** \todo document type node */
+ dom_document_type_destroy((struct dom_document_type *) node);
break;
case DOM_DOCUMENT_FRAGMENT_NODE:
dom_document_fragment_destroy(owner,
@@ -96,7 +98,7 @@
break;
}
- if (!document_node) {
+ if (!null_owner_permitted) {
/* Release the reference we claimed on the document. If this
* is the last reference held on the document and the list
* of nodes pending deletion is empty, then the document will
@@ -173,7 +175,7 @@
/**
* Finalise a DOM node
*
- * \param doc The owning document
+ * \param doc The owning document (or NULL if it's a standalone DocumentType)
* \param node The node to finalise
*
* The contents of ::node will be cleaned up. ::node will not be freed.
@@ -182,6 +184,10 @@
void dom_node_finalise(struct dom_document *doc, struct dom_node *node)
{
struct dom_user_data *u, *v;
+
+ /* Standalone DocumentType nodes may not have user data attached */
+ assert(node->type != DOM_DOCUMENT_TYPE_NODE ||
+ node->user_data == NULL);
/* Destroy user data */
for (u = node->user_data; u != NULL; u = v) {
@@ -493,6 +499,15 @@
dom_exception dom_node_get_owner_document(struct dom_node *node,
struct dom_document **result)
{
+ /* Document nodes have no owner, as far as clients are concerned
+ * In reality, they own themselves as this simplifies code elsewhere
+ */
+ if (node->type == DOM_DOCUMENT_NODE) {
+ *result = NULL;
+
+ return DOM_NO_ERR;
+ }
+
/* If there is an owner, increase its reference count */
if (node->owner != NULL)
dom_node_ref((struct dom_node *) node->owner);
@@ -522,14 +537,12 @@
* DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly, or
* ::new_child's parent is readonly,
* DOM_NOT_FOUND_ERR if ::ref_child is not a child of
- * ::node,
- * DOM_NOT_SUPPORTED_ERR if ::node is of type Document and
- * ::new_child is of type DocumentType.
+ * ::node.
*
* If ::new_child is a DocumentFragment, all of its children are inserted.
* If ::new_child is already in the tree, it is first removed.
*
- * Attempting to insert a node before itself is a NOP
+ * Attempting to insert a node before itself is a NOP.
*
* ::new_child's reference count will be increased. The caller should unref
* it (as they should already have held a reference on the node)
@@ -539,7 +552,11 @@
struct dom_node **result)
{
/* Ensure that new_child and node are owned by the same document */
- if (new_child->owner != node->owner)
+ if ((new_child->type == DOM_DOCUMENT_TYPE_NODE &&
+ new_child->owner != NULL &&
+ new_child->owner != node->owner) ||
+ (new_child->type != DOM_DOCUMENT_TYPE_NODE &&
+ new_child->owner != node->owner))
return DOM_WRONG_DOCUMENT_ERR;
/** \todo ensure ::node may be written to */
@@ -547,12 +564,6 @@
/* Ensure that ref_child (if any) is a child of node */
if (ref_child != NULL && ref_child->parent != node)
return DOM_NOT_FOUND_ERR;
-
- /* We don't support addition of DocumentType nodes using this API */
- /** \todo if we did, then we could purge dom_document_set_doctype() */
- if (node->type == DOM_DOCUMENT_NODE &&
- new_child->type == DOM_DOCUMENT_TYPE_NODE)
- return DOM_NOT_SUPPORTED_ERR;
/* Ensure that new_child is not an ancestor of node, nor node itself */
for (struct dom_node *n = node; n != NULL; n = n->parent) {
@@ -561,7 +572,8 @@
}
/* Ensure that the document doesn't already have a root element */
- if (node->type == DOM_DOCUMENT_NODE && node->type == DOM_ELEMENT_NODE) {
+ if (node->type == DOM_DOCUMENT_NODE &&
+ new_child->type == DOM_ELEMENT_NODE) {
for (struct dom_node *n = node->first_child;
n != NULL; n = n->next) {
if (n->type == DOM_ELEMENT_NODE)
@@ -569,7 +581,27 @@
}
}
+ /* Ensure that the document doesn't already have a document type */
+ if (node->type == DOM_DOCUMENT_NODE &&
+ new_child->type == DOM_DOCUMENT_TYPE_NODE) {
+ for (struct dom_node *n = node->first_child;
+ n != NULL; n = n->next) {
+ if (n->type == DOM_DOCUMENT_TYPE_NODE)
+ return DOM_HIERARCHY_REQUEST_ERR;
+ }
+ }
+
/** \todo ensure ::new_child is permitted as a child of ::node */
+
+ /* DocumentType nodes are created outside the Document so,
+ * if we're trying to attach a DocumentType node, then we
+ * also need to set its owner. */
+ if (node->type == DOM_DOCUMENT_NODE &&
+ new_child->type == DOM_DOCUMENT_TYPE_NODE) {
+ /* See long comment in dom_node_initialise as to why
+ * we don't ref the document here */
+ new_child->owner = (struct dom_document *) node;
+ }
/* Attempting to insert a node before itself is a NOP */
if (new_child == ref_child) {
@@ -761,10 +793,7 @@
* DOM_WRONG_DOCUMENT_ERR if ::new_child was created from a
* different document than ::node,
* DOM_NO_MODIFICATION_ALLOWED_ERR if ::node is readonly, or
- * ::new_child's parent is readonly,
- * DOM_NOT_SUPPORTED_ERR if ::node is of type Document and
- * ::new_child is of type
- * DocumentType or Element.
+ * ::new_child's parent is readonly.
*
* If ::new_child is a DocumentFragment, all of its children are inserted.
* If ::new_child is already in the tree, it is first removed.
15 years, 8 months
r3550 jmb - /trunk/dom/bindings/xml/xmlparser.c
by netsurf@semichrome.net
Author: jmb
Date: Wed Sep 19 00:50:01 2007
New Revision: 3550
URL: http://source.netsurf-browser.org?rev=3550&view=rev
Log:
More informational messaging
Modified:
trunk/dom/bindings/xml/xmlparser.c
Modified: trunk/dom/bindings/xml/xmlparser.c
URL: http://source.netsurf-browser.org/trunk/dom/bindings/xml/xmlparser.c?rev=...
==============================================================================
--- trunk/dom/bindings/xml/xmlparser.c (original)
+++ trunk/dom/bindings/xml/xmlparser.c Wed Sep 19 00:50:01 2007
@@ -903,13 +903,18 @@
/* Create DOM string data for text node */
err = dom_string_create_from_const_ptr(parser->doc, child->content,
strlen((const char *) child->content), &data);
- if (err != DOM_NO_ERR)
- return;
+ if (err != DOM_NO_ERR) {
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for text node contents ");
+ return;
+ }
/* Create text node */
err = dom_document_create_text_node(parser->doc, data, &text);
if (err != DOM_NO_ERR) {
dom_string_unref(data);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for text node");
return;
}
@@ -921,6 +926,8 @@
(struct dom_node **) &ins_text);
if (err != DOM_NO_ERR) {
dom_node_unref((struct dom_node *) text);
+ parser->msg(XML_MSG_ERROR, parser->mctx,
+ "Failed attaching text node");
return;
}
@@ -957,13 +964,18 @@
/* Create DOM string data for cdata section */
err = dom_string_create_from_const_ptr(parser->doc, child->content,
strlen((const char *) child->content), &data);
- if (err != DOM_NO_ERR)
- return;
-
- /* Create text node */
+ if (err != DOM_NO_ERR) {
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for cdata section contents");
+ return;
+ }
+
+ /* Create cdata section */
err = dom_document_create_cdata_section(parser->doc, data, &cdata);
if (err != DOM_NO_ERR) {
dom_string_unref(data);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for cdata section");
return;
}
@@ -975,6 +987,8 @@
(struct dom_node **) &ins_cdata);
if (err != DOM_NO_ERR) {
dom_node_unref((struct dom_node *) cdata);
+ parser->msg(XML_MSG_ERROR, parser->mctx,
+ "Failed attaching cdata section");
return;
}
@@ -1012,14 +1026,19 @@
/* Create name of entity reference */
err = dom_string_create_from_const_ptr(parser->doc, child->name,
strlen((const char *) child->name), &name);
- if (err != DOM_NO_ERR)
- return;
+ if (err != DOM_NO_ERR) {
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for entity reference name");
+ return;
+ }
/* Create text node */
err = dom_document_create_entity_reference(parser->doc, name,
&entity);
if (err != DOM_NO_ERR) {
dom_string_unref(name);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for entity reference");
return;
}
@@ -1036,6 +1055,8 @@
(struct dom_node **) &ins_entity);
if (err != DOM_NO_ERR) {
dom_node_unref((struct dom_node *) entity);
+ parser->msg(XML_MSG_ERROR, parser->mctx,
+ "Failed attaching entity reference");
return;
}
@@ -1072,13 +1093,18 @@
/* Create DOM string data for comment */
err = dom_string_create_from_const_ptr(parser->doc, child->content,
strlen((const char *) child->content), &data);
- if (err != DOM_NO_ERR)
- return;
+ if (err != DOM_NO_ERR) {
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for comment data");
+ return;
+ }
/* Create comment */
err = dom_document_create_comment(parser->doc, data, &comment);
if (err != DOM_NO_ERR) {
dom_string_unref(data);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for comment node");
return;
}
@@ -1090,6 +1116,8 @@
(struct dom_node **) &ins_comment);
if (err != DOM_NO_ERR) {
dom_node_unref((struct dom_node *) comment);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "Failed attaching comment node");
return;
}
@@ -1127,8 +1155,11 @@
/* Create qname for doctype */
err = dom_string_create_from_const_ptr(parser->doc, dtd->name,
strlen((const char *) dtd->name), &qname);
- if (err != DOM_NO_ERR)
- return;
+ if (err != DOM_NO_ERR) {
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for doctype name");
+ return;
+ }
/* Create public ID for doctype */
err = dom_string_create_from_const_ptr(parser->doc,
@@ -1138,6 +1169,8 @@
&public_id);
if (err != DOM_NO_ERR) {
dom_string_unref(qname);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for doctype public id");
return;
}
@@ -1150,6 +1183,8 @@
if (err != DOM_NO_ERR) {
dom_string_unref(public_id);
dom_string_unref(qname);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for doctype system id");
return;
}
@@ -1161,6 +1196,8 @@
dom_string_unref(system_id);
dom_string_unref(public_id);
dom_string_unref(qname);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "Failed to create document type");
return;
}
@@ -1174,6 +1211,8 @@
doctype);
if (err != DOM_NO_ERR) {
dom_node_unref((struct dom_node *) doctype);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "Failed attaching doctype");
return;
}
15 years, 8 months
r3549 jmb - /trunk/dom/src/core/element.c
by netsurf@semichrome.net
Author: jmb
Date: Wed Sep 19 00:34:13 2007
New Revision: 3549
URL: http://source.netsurf-browser.org?rev=3549&view=rev
Log:
Implement dom_element_get_tag_name()
Implement dom_element_set_attribute_node() [still has some outstanding sanity checking]
Modified:
trunk/dom/src/core/element.c
Modified: trunk/dom/src/core/element.c
URL: http://source.netsurf-browser.org/trunk/dom/src/core/element.c?rev=3549&r...
==============================================================================
--- trunk/dom/src/core/element.c (original)
+++ trunk/dom/src/core/element.c Wed Sep 19 00:34:13 2007
@@ -5,7 +5,10 @@
* Copyright 2007 John-Mark Bell <jmb(a)netsurf-browser.org>
*/
+#include <stdio.h>
+
#include <dom/core/element.h>
+#include <dom/core/string.h>
#include "core/document.h"
#include "core/element.h"
@@ -138,7 +141,8 @@
*
* \param element The element to retrieve the name from
* \param name Pointer to location to receive name
- * \return DOM_NO_ERR.
+ * \return DOM_NO_ERR on success,
+ * DOM_NO_MEM_ERR on memory exhaustion.
*
* The returned string will have its reference count increased. It is
* the responsibility of the caller to unref the string once it has
@@ -147,10 +151,41 @@
dom_exception dom_element_get_tag_name(struct dom_element *element,
struct dom_string **name)
{
- UNUSED(element);
- UNUSED(name);
-
- return DOM_NOT_SUPPORTED_ERR;
+ struct dom_node *e = (struct dom_node *) element;
+ struct dom_string *tag_name;
+
+ if (e->localname != NULL) {
+ /* Has a localname, so build a qname string */
+ size_t local_len = 0, prefix_len = 0;
+ const uint8_t *local = NULL, *prefix = NULL;
+ dom_exception err;
+
+ if (e->prefix != NULL)
+ dom_string_get_data(e->prefix, &prefix, &prefix_len);
+
+ dom_string_get_data(e->localname, &local, &local_len);
+
+ uint8_t qname[prefix_len + 1 /* : */ + local_len + 1 /* \0 */];
+
+ sprintf((char *) qname, "%s:%s",
+ prefix ? (const char *) prefix : "",
+ (const char *) local);
+
+ err = dom_string_create_from_ptr(e->owner, qname,
+ prefix_len + 1 + local_len, &tag_name);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ /* tag_name is referenced for us */
+ } else {
+ tag_name = e->name;
+
+ dom_string_ref(tag_name);
+ }
+
+ *name = tag_name;
+
+ return DOM_NO_ERR;
}
/**
@@ -254,11 +289,73 @@
dom_exception dom_element_set_attribute_node(struct dom_element *element,
struct dom_attr *attr, struct dom_attr **result)
{
- UNUSED(element);
- UNUSED(attr);
- UNUSED(result);
-
- return DOM_NOT_SUPPORTED_ERR;
+ struct dom_node *e = (struct dom_node *) element;
+ struct dom_node *a = (struct dom_node *) attr;
+ struct dom_attr *prev = NULL;
+
+ /* Ensure element and attribute belong to the same document */
+ if (e->owner != a->owner)
+ return DOM_WRONG_DOCUMENT_ERR;
+
+ /** \todo ensure ::element can be written to */
+
+ /* Ensure attribute isn't attached to another element */
+ if (a->parent != NULL && a->parent != e)
+ return DOM_INUSE_ATTRIBUTE_ERR;
+
+ /* Attach attr to element, if not already attached */
+ if (a->parent == NULL) {
+
+ /* Search for existing attribute with same name */
+ prev = e->attributes;
+ while (prev != NULL) {
+ struct dom_node *p = (struct dom_node *) prev;
+
+ if (dom_string_cmp(a->name, p->name) == 0)
+ break;
+
+ prev = (struct dom_attr *) p->next;
+ }
+
+ a->parent = e;
+
+ if (prev != NULL) {
+ /* Found an existing attribute, so replace it */
+ struct dom_node *p = (struct dom_node *) prev;
+
+ a->previous = p->previous;
+ a->next = p->next;
+
+ if (a->previous != NULL)
+ a->previous->next = a;
+ else
+ e->attributes = attr;
+
+ if (a->next != NULL)
+ a->next->previous = a;
+
+ /* Invalidate existing attribute's location info */
+ p->next = NULL;
+ p->previous = NULL;
+ p->parent = NULL;
+ } else {
+ /* No existing attribute, so insert at front of list */
+ a->previous = NULL;
+ a->next = (struct dom_node *) e->attributes;
+
+ if (a->next != NULL)
+ a->next->previous = a;
+
+ e->attributes = attr;
+ }
+ }
+
+ if (prev != NULL)
+ dom_node_ref((struct dom_node *) prev);
+
+ *result = prev;
+
+ return DOM_NO_ERR;
}
/**
15 years, 8 months
r3548 jmb - /trunk/dom/src/core/node.c
by netsurf@semichrome.net
Author: jmb
Date: Tue Sep 18 23:50:55 2007
New Revision: 3548
URL: http://source.netsurf-browser.org?rev=3548&view=rev
Log:
Implement sanity checking in dom_node_insert_before()
There's still a couple of outstanding issues here, marked as todos.
Modified:
trunk/dom/src/core/node.c
Modified: trunk/dom/src/core/node.c
URL: http://source.netsurf-browser.org/trunk/dom/src/core/node.c?rev=3548&r1=3...
==============================================================================
--- trunk/dom/src/core/node.c (original)
+++ trunk/dom/src/core/node.c Tue Sep 18 23:50:55 2007
@@ -524,11 +524,12 @@
* DOM_NOT_FOUND_ERR if ::ref_child is not a child of
* ::node,
* DOM_NOT_SUPPORTED_ERR if ::node is of type Document and
- * ::new_child is of type
- * DocumentType or Element.
+ * ::new_child is of type DocumentType.
*
* If ::new_child is a DocumentFragment, all of its children are inserted.
* If ::new_child is already in the tree, it is first removed.
+ *
+ * Attempting to insert a node before itself is a NOP
*
* ::new_child's reference count will be increased. The caller should unref
* it (as they should already have held a reference on the node)
@@ -537,31 +538,128 @@
struct dom_node *new_child, struct dom_node *ref_child,
struct dom_node **result)
{
- /** \todo sanity checking etc. */
-
- new_child->parent = node;
-
- if (ref_child == NULL) {
- new_child->previous = node->last_child;
- new_child->next = NULL;
-
- if (node->last_child != NULL)
- node->last_child->next = new_child;
+ /* Ensure that new_child and node are owned by the same document */
+ if (new_child->owner != node->owner)
+ return DOM_WRONG_DOCUMENT_ERR;
+
+ /** \todo ensure ::node may be written to */
+
+ /* Ensure that ref_child (if any) is a child of node */
+ if (ref_child != NULL && ref_child->parent != node)
+ return DOM_NOT_FOUND_ERR;
+
+ /* We don't support addition of DocumentType nodes using this API */
+ /** \todo if we did, then we could purge dom_document_set_doctype() */
+ if (node->type == DOM_DOCUMENT_NODE &&
+ new_child->type == DOM_DOCUMENT_TYPE_NODE)
+ return DOM_NOT_SUPPORTED_ERR;
+
+ /* Ensure that new_child is not an ancestor of node, nor node itself */
+ for (struct dom_node *n = node; n != NULL; n = n->parent) {
+ if (n == new_child)
+ return DOM_HIERARCHY_REQUEST_ERR;
+ }
+
+ /* Ensure that the document doesn't already have a root element */
+ if (node->type == DOM_DOCUMENT_NODE && node->type == DOM_ELEMENT_NODE) {
+ for (struct dom_node *n = node->first_child;
+ n != NULL; n = n->next) {
+ if (n->type == DOM_ELEMENT_NODE)
+ return DOM_HIERARCHY_REQUEST_ERR;
+ }
+ }
+
+ /** \todo ensure ::new_child is permitted as a child of ::node */
+
+ /* Attempting to insert a node before itself is a NOP */
+ if (new_child == ref_child) {
+ dom_node_ref(new_child);
+ *result = new_child;
+
+ return DOM_NO_ERR;
+ }
+
+ /* If new_child is already in the tree, remove it */
+ if (new_child->parent != NULL) {
+ if (new_child->previous != NULL)
+ new_child->previous->next = new_child->next;
else
- node->first_child = new_child;
-
- node->last_child = new_child;
+ new_child->parent->first_child = new_child->next;
+
+ if (new_child->next != NULL)
+ new_child->next->previous = new_child->previous;
+ else
+ new_child->parent->last_child = new_child->previous;
+ }
+
+ /* If new_child is a DocumentFragment, insert its children
+ * Otherwise, insert new_child */
+ if (new_child->type == DOM_DOCUMENT_FRAGMENT_NODE) {
+ if (new_child->first_child != NULL) {
+ /* Reparent children */
+ for (struct dom_node *c = new_child->first_child;
+ c != NULL; c = c->next)
+ c->parent = node;
+
+ if (ref_child == NULL) {
+ new_child->first_child->previous =
+ node->last_child;
+
+ if (node->last_child != NULL) {
+ node->last_child->next =
+ new_child->first_child;
+ } else {
+ node->first_child =
+ new_child->first_child;
+ }
+
+ node->last_child = new_child->last_child;
+ } else {
+ new_child->first_child->previous =
+ ref_child->previous;
+
+ if (ref_child->previous != NULL) {
+ ref_child->previous->next =
+ new_child->first_child;
+ } else {
+ node->first_child =
+ new_child->first_child;
+ }
+
+ new_child->last_child->next = ref_child;
+ ref_child->previous = new_child->last_child;
+ }
+
+ new_child->first_child = NULL;
+ new_child->last_child = NULL;
+ }
} else {
- new_child->previous = ref_child->previous;
- new_child->next = ref_child;
-
- if (ref_child->previous != NULL)
- ref_child->previous->next = new_child;
- else
- node->first_child = new_child;
-
- ref_child->previous = new_child;
+ new_child->parent = node;
+
+ if (ref_child == NULL) {
+ new_child->previous = node->last_child;
+ new_child->next = NULL;
+
+ if (node->last_child != NULL)
+ node->last_child->next = new_child;
+ else
+ node->first_child = new_child;
+
+ node->last_child = new_child;
+ } else {
+ new_child->previous = ref_child->previous;
+ new_child->next = ref_child;
+
+ if (ref_child->previous != NULL)
+ ref_child->previous->next = new_child;
+ else
+ node->first_child = new_child;
+
+ ref_child->previous = new_child;
+ }
}
+
+ /** \todo Is it correct to return DocumentFragments? */
dom_node_ref(new_child);
*result = new_child;
15 years, 8 months
r3547 jmb - /trunk/dom/bindings/xml/xmlparser.c
by netsurf@semichrome.net
Author: jmb
Date: Mon Sep 17 18:34:12 2007
New Revision: 3547
URL: http://source.netsurf-browser.org?rev=3547&view=rev
Log:
More logging of failed DOM calls.
Fix segfault caused by failure to add attribute to element
Modified:
trunk/dom/bindings/xml/xmlparser.c
Modified: trunk/dom/bindings/xml/xmlparser.c
URL: http://source.netsurf-browser.org/trunk/dom/bindings/xml/xmlparser.c?rev=...
==============================================================================
--- trunk/dom/bindings/xml/xmlparser.c (original)
+++ trunk/dom/bindings/xml/xmlparser.c Mon Sep 17 18:34:12 2007
@@ -506,6 +506,13 @@
return;
}
+ /* If node wasn't linked, we can't do anything */
+ if (node->_private == NULL) {
+ parser->msg(XML_MSG_WARNING, parser->mctx,
+ "Node '%s' not linked", node->name);
+ return;
+ }
+
/* We need to mirror any child nodes at the end of the list of
* children which occur after the last Element node in the list */
@@ -644,14 +651,20 @@
child->name,
strlen((const char *) child->name),
&tag_name);
- if (err != DOM_NO_ERR)
+ if (err != DOM_NO_ERR) {
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for tag name");
return;
+ }
/* Create element node */
err = dom_document_create_element(parser->doc,
tag_name, &el);
if (err != DOM_NO_ERR) {
dom_string_unref(tag_name);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "Failed creating element '%s'",
+ child->name);
return;
}
@@ -672,8 +685,11 @@
child->ns->href,
strlen((const char *) child->ns->href),
&namespace);
- if (err != DOM_NO_ERR)
+ if (err != DOM_NO_ERR) {
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for namespace");
return;
+ }
/* QName is "prefix:localname",
* or "localname" if there is no prefix */
@@ -690,6 +706,8 @@
&qname);
if (err != DOM_NO_ERR) {
dom_string_unref(namespace);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for qname");
return;
}
@@ -699,6 +717,9 @@
if (err != DOM_NO_ERR) {
dom_string_unref(namespace);
dom_string_unref(qname);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "Failed creating element '%s'",
+ qnamebuf);
return;
}
@@ -722,14 +743,20 @@
a->name,
strlen((const char *) a->name),
&name);
- if (err != DOM_NO_ERR)
+ if (err != DOM_NO_ERR) {
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for attribute name");
goto cleanup;
+ }
/* Create attribute */
err = dom_document_create_attribute(parser->doc,
name, &attr);
if (err != DOM_NO_ERR) {
dom_string_unref(name);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "Failed creating attribute '%s'",
+ a->name);
goto cleanup;
}
@@ -750,8 +777,11 @@
a->ns->href,
strlen((const char *) a->ns->href),
&namespace);
- if (err != DOM_NO_ERR)
+ if (err != DOM_NO_ERR) {
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for namespace");
return;
+ }
/* QName is "prefix:localname",
* or "localname" if there is no prefix */
@@ -768,6 +798,8 @@
&qname);
if (err != DOM_NO_ERR) {
dom_string_unref(namespace);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "No memory for qname");
return;
}
@@ -777,6 +809,9 @@
if (err != DOM_NO_ERR) {
dom_string_unref(namespace);
dom_string_unref(qname);
+ parser->msg(XML_MSG_CRITICAL, parser->mctx,
+ "Failed creating attribute '%s'",
+ qnamebuf);
return;
}
@@ -803,6 +838,9 @@
err = dom_element_set_attribute_node(el, attr, &prev_attr);
if (err != DOM_NO_ERR) {
dom_node_unref((struct dom_node *) attr);
+ parser->msg(XML_MSG_ERROR, parser->mctx,
+ "Failed attaching attribute '%s'",
+ a->name);
goto cleanup;
}
@@ -818,6 +856,9 @@
err = dom_node_append_child(parent, (struct dom_node *) el,
(struct dom_node **) &ins_el);
if (err != DOM_NO_ERR) {
+ parser->msg(XML_MSG_ERROR, parser->mctx,
+ "Failed attaching element '%s'",
+ child->name);
goto cleanup;
}
15 years, 8 months
r3546 jmb - /trunk/dom/src/core/node.c
by netsurf@semichrome.net
Author: jmb
Date: Mon Sep 17 18:33:03 2007
New Revision: 3546
URL: http://source.netsurf-browser.org?rev=3546&view=rev
Log:
Partial implementation of dom_node_insert_before. This has utterly no sanity checking at present so will probably break, badly.
Modified:
trunk/dom/src/core/node.c
Modified: trunk/dom/src/core/node.c
URL: http://source.netsurf-browser.org/trunk/dom/src/core/node.c?rev=3546&r1=3...
==============================================================================
--- trunk/dom/src/core/node.c (original)
+++ trunk/dom/src/core/node.c Mon Sep 17 18:33:03 2007
@@ -537,12 +537,36 @@
struct dom_node *new_child, struct dom_node *ref_child,
struct dom_node **result)
{
- UNUSED(node);
- UNUSED(new_child);
- UNUSED(ref_child);
- UNUSED(result);
-
- return DOM_NOT_SUPPORTED_ERR;
+ /** \todo sanity checking etc. */
+
+ new_child->parent = node;
+
+ if (ref_child == NULL) {
+ new_child->previous = node->last_child;
+ new_child->next = NULL;
+
+ if (node->last_child != NULL)
+ node->last_child->next = new_child;
+ else
+ node->first_child = new_child;
+
+ node->last_child = new_child;
+ } else {
+ new_child->previous = ref_child->previous;
+ new_child->next = ref_child;
+
+ if (ref_child->previous != NULL)
+ ref_child->previous->next = new_child;
+ else
+ node->first_child = new_child;
+
+ ref_child->previous = new_child;
+ }
+
+ dom_node_ref(new_child);
+ *result = new_child;
+
+ return DOM_NO_ERR;
}
/**
15 years, 8 months
r3545 jmb - /trunk/netsurf/render/html_redraw.c
by netsurf@semichrome.net
Author: jmb
Date: Mon Sep 17 15:53:02 2007
New Revision: 3545
URL: http://source.netsurf-browser.org?rev=3545&view=rev
Log:
Fix handling of backgrounds on <body> and <html>
Modified:
trunk/netsurf/render/html_redraw.c
Modified: trunk/netsurf/render/html_redraw.c
URL: http://source.netsurf-browser.org/trunk/netsurf/render/html_redraw.c?rev=...
==============================================================================
--- trunk/netsurf/render/html_redraw.c (original)
+++ trunk/netsurf/render/html_redraw.c Mon Sep 17 15:53:02 2007
@@ -69,7 +69,7 @@
struct box *box, float scale, colour background_colour);
static bool html_redraw_background(int x, int y, struct box *box, float scale,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
- colour *background_colour);
+ colour *background_colour, struct box *background);
static bool html_redraw_text_decoration(struct box *box,
int x_parent, int y_parent, float scale,
colour background_colour);
@@ -159,6 +159,7 @@
int padding_left, padding_top, padding_width, padding_height;
int x0, y0, x1, y1;
int x_scrolled, y_scrolled;
+ struct box *bg_box = NULL;
/* avoid trivial FP maths */
if (scale == 1.0) {
@@ -273,10 +274,64 @@
}
/* background colour and image */
- if ((box->style && box->type != BOX_BR && (box->type != BOX_INLINE ||
- box->style != box->parent->parent->style)) &&
- ((box->style->background_color != TRANSPARENT) ||
- (box->background))) {
+
+ /* Thanks to backwards compatibility, CSS defines the following:
+ *
+ * + If the box is for the root element and it has a background,
+ * use that (and then process the body box with no special case)
+ * + If the box is for the root element and it has no background,
+ * then use the background (if any) from the body element as if
+ * it were specified on the root. Then, when the box for the body
+ * element is processed, ignore the background.
+ * + For any other box, just use its own styling.
+ */
+ if (!box->parent) {
+ /* Root box */
+ if (box->style &&
+ (box->style->background_color != TRANSPARENT ||
+ box->background)) {
+ /* With its own background */
+ bg_box = box;
+ } else if (!box->style ||
+ (box->style->background_color == TRANSPARENT &&
+ !box->background)) {
+ /* Without its own background */
+ if (box->children && box->children->style &&
+ (box->children->style->background_color !=
+ TRANSPARENT ||
+ box->children->background)) {
+ /* But body has one, so use that */
+ bg_box = box->children;
+ }
+ }
+ } else if (box->parent && !box->parent->parent) {
+ /* Body box */
+ if (box->style &&
+ (box->style->background_color != TRANSPARENT ||
+ box->background)) {
+ /* With a background */
+ if (box->parent->style &&
+ (box->parent->style->background_color !=
+ TRANSPARENT ||
+ box->parent->background)) {
+ /* Root has own background; process normally */
+ bg_box = box;
+ }
+ }
+ } else {
+ /* Any other box */
+ bg_box = box;
+ }
+
+ /* bg_box == NULL implies that this box should not have
+ * its background rendered. Otherwise filter out linebreaks,
+ * optimize away non-differing inlines and ensure the bg_box
+ * has something worth rendering */
+ if (bg_box && (bg_box->style && bg_box->type != BOX_BR &&
+ (bg_box->type != BOX_INLINE ||
+ bg_box->style != bg_box->parent->parent->style)) &&
+ ((bg_box->style->background_color != TRANSPARENT) ||
+ (bg_box->background))) {
/* find intersection of clip box and padding box */
int px0 = x < x0 ? x0 : x;
int py0 = y < y0 ? y0 : y;
@@ -288,7 +343,7 @@
/* plot background */
if (!html_redraw_background(x, y, box, scale,
px0, py0, px1, py1,
- ¤t_background_color))
+ ¤t_background_color, bg_box))
return false;
/* restore previous graphics window */
if (!plot.clip(x0, y0, x1, y1))
@@ -1095,12 +1150,17 @@
* \param box box to draw background image of
* \param scale scale for redraw
* \param background_colour current background colour
+ * \param background box containing background details (usually ::box)
* \return true if successful, false otherwise
+ *
+ * The reason for the presence of ::background is the backwards compatibility
+ * mess that is backgrounds on <body>. The background will be drawn relative
+ * to ::box, using the background information contained within ::background.
*/
bool html_redraw_background(int x, int y, struct box *box, float scale,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
- colour *background_colour)
+ colour *background_colour, struct box *background)
{
bool repeat_x = false;
bool repeat_y = false;
@@ -1112,16 +1172,18 @@
int ox = x, oy = y;
struct box *parent;
- plot_content = (box->background != NULL);
+ plot_content = (background->background != NULL);
+
if (plot_content) {
/* handle background-repeat */
- switch (box->style->background_repeat) {
+ switch (background->style->background_repeat) {
case CSS_BACKGROUND_REPEAT_REPEAT:
repeat_x = repeat_y = true;
- /* optimisation: only plot the colour if bitmap is not opaque */
- if (box->background->bitmap)
+ /* optimisation: only plot the colour if
+ * bitmap is not opaque */
+ if (background->background->bitmap)
plot_colour = !bitmap_get_opaque(
- box->background->bitmap);
+ background->background->bitmap);
break;
case CSS_BACKGROUND_REPEAT_REPEAT_X:
repeat_x = true;
@@ -1136,47 +1198,53 @@
}
/* handle background-position */
- switch (box->style->background_position.horz.pos) {
+ switch (background->style->background_position.horz.pos) {
case CSS_BACKGROUND_POSITION_PERCENT:
x += (box->padding[LEFT] + box->width +
- box->padding[RIGHT] -
- box->background->width) * scale *
- box->style->background_position.horz.
- value.percent / 100;
+ box->padding[RIGHT] -
+ background->background->width) * scale *
+ background->style->background_position.
+ horz.value.percent / 100;
break;
case CSS_BACKGROUND_POSITION_LENGTH:
- x += (int) (css_len2px(&box->style->background_position.
- horz.value.length, box->style) * scale);
+ x += (int) (css_len2px(&background->style->
+ background_position.horz.value.length,
+ background->style) * scale);
break;
default:
break;
}
- switch (box->style->background_position.vert.pos) {
+ switch (background->style->background_position.vert.pos) {
case CSS_BACKGROUND_POSITION_PERCENT:
y += (box->padding[TOP] + box->height +
- box->padding[BOTTOM] -
- box->background->height) * scale *
- box->style->background_position.vert.
- value.percent / 100;
+ box->padding[BOTTOM] -
+ background->background->height) * scale *
+ background->style->background_position.
+ vert.value.percent / 100;
break;
case CSS_BACKGROUND_POSITION_LENGTH:
- y += (int) (css_len2px(&box->style->background_position.
- vert.value.length, box->style) * scale);
+ y += (int) (css_len2px(&background->style->
+ background_position.vert.value.length,
+ background->style) * scale);
break;
default:
break;
}
}
- /* special case for table rows as their background needs to be clipped to
- * all the cells */
+ /* special case for table rows as their background needs
+ * to be clipped to all the cells */
if (box->type == BOX_TABLE_ROW) {
- for (parent = box->parent; ((parent) && (parent->type != BOX_TABLE));
+ for (parent = box->parent;
+ ((parent) && (parent->type != BOX_TABLE));
parent = parent->parent);
assert(parent && (parent->style));
- clip_to_children = (parent->style->border_spacing.horz.value > 0) ||
- (parent->style->border_spacing.vert.value > 0);
+
+ clip_to_children =
+ (parent->style->border_spacing.horz.value > 0) ||
+ (parent->style->border_spacing.vert.value > 0);
+
if (clip_to_children)
clip_box = box->children;
}
@@ -1190,9 +1258,12 @@
clip_x0 = ox + (clip_box->x * scale);
clip_y0 = oy + (clip_box->y * scale);
clip_x1 = clip_x0 + (clip_box->padding[LEFT] +
- clip_box->width + clip_box->padding[RIGHT]) * scale;
+ clip_box->width +
+ clip_box->padding[RIGHT]) * scale;
clip_y1 = clip_y0 + (clip_box->padding[TOP] +
- clip_box->height + clip_box->padding[BOTTOM]) * scale;
+ clip_box->height +
+ clip_box->padding[BOTTOM]) * scale;
+
if (clip_x0 < px0) clip_x0 = px0;
if (clip_y0 < py0) clip_y0 = py0;
if (clip_x1 > px1) clip_x1 = px1;
@@ -1200,31 +1271,34 @@
/* <td> attributes override <tr> */
if ((clip_x0 >= clip_x1) || (clip_y0 >= clip_y1) ||
- (clip_box->style->background_color != TRANSPARENT) ||
+ (clip_box->style->background_color !=
+ TRANSPARENT) ||
(clip_box->background &&
clip_box->background->bitmap &&
- bitmap_get_opaque(clip_box->background->bitmap)))
+ bitmap_get_opaque(
+ clip_box->background->bitmap)))
continue;
}
/* plot the background colour */
- if (box->style->background_color != TRANSPARENT) {
- *background_colour = box->style->background_color;
+ if (background->style->background_color != TRANSPARENT) {
+ *background_colour =
+ background->style->background_color;
if (plot_colour)
- if (!plot.fill(clip_x0, clip_y0, clip_x1, clip_y1,
- *background_colour))
+ if (!plot.fill(clip_x0, clip_y0,
+ clip_x1, clip_y1, *background_colour))
return false;
}
/* and plot the image */
if (plot_content) {
if (!plot.clip(clip_x0, clip_y0, clip_x1, clip_y1))
return false;
- if (!content_redraw_tiled(box->background, x, y,
- ceilf(box->background->width * scale),
- ceilf(box->background->height * scale),
- clip_x0, clip_y0, clip_x1, clip_y1, scale,
- *background_colour,
- repeat_x, repeat_y))
+ if (!content_redraw_tiled(background->background, x, y,
+ ceilf(background->background->width * scale),
+ ceilf(background->background->height * scale),
+ clip_x0, clip_y0, clip_x1, clip_y1, scale,
+ *background_colour,
+ repeat_x, repeat_y))
return false;
}
15 years, 8 months