summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2007-09-18 22:50:55 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2007-09-18 22:50:55 +0000
commit1545d762fc48469fcb67fc34c27a70b8f0917803 (patch)
treef72a0f06c12ca05d267934a8e9022b2e10eb6286
parentb9c7501629b1b7a8d8616e83daf0644659199c88 (diff)
downloadlibdom-1545d762fc48469fcb67fc34c27a70b8f0917803.tar.gz
Implement sanity checking in dom_node_insert_before()
There's still a couple of outstanding issues here, marked as todos. svn path=/trunk/dom/; revision=3548
-rw-r--r--src/core/node.c134
1 files changed, 116 insertions, 18 deletions
diff --git a/src/core/node.c b/src/core/node.c
index c33e24d5..7dd084fd 100644
--- a/src/core/node.c
+++ b/src/core/node.c
@@ -524,12 +524,13 @@ dom_exception dom_node_get_owner_document(struct dom_node *node,
* 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,32 +538,129 @@ dom_exception dom_node_insert_before(struct dom_node *node,
struct dom_node *new_child, struct dom_node *ref_child,
struct dom_node **result)
{
- /** \todo sanity checking etc. */
+ /* 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;
+ }
- new_child->parent = node;
+ /* 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;
+ }
+ }
- if (ref_child == NULL) {
- new_child->previous = node->last_child;
- new_child->next = NULL;
+ /** \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 (node->last_child != NULL)
- node->last_child->next = new_child;
+ /* 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;
+ new_child->parent->first_child = new_child->next;
- node->last_child = new_child;
+ 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;
+ new_child->parent = node;
- if (ref_child->previous != NULL)
- ref_child->previous->next = new_child;
- else
- node->first_child = new_child;
+ if (ref_child == NULL) {
+ new_child->previous = node->last_child;
+ new_child->next = NULL;
- ref_child->previous = new_child;
+ 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;