summaryrefslogtreecommitdiff
path: root/src/core/text.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/text.c')
-rw-r--r--src/core/text.c320
1 files changed, 285 insertions, 35 deletions
diff --git a/src/core/text.c b/src/core/text.c
index bad20bf..6cb9e1f 100644
--- a/src/core/text.c
+++ b/src/core/text.c
@@ -3,18 +3,23 @@
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
* Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
+ * Copyright 2009 Bo Yang <struggleyb.nku@gmail.com>
*/
+#include <assert.h>
+
#include <dom/core/string.h>
#include <dom/core/text.h>
+#include <libwapcaplet/libwapcaplet.h>
+
#include "core/characterdata.h"
#include "core/document.h"
#include "core/text.h"
#include "utils/utils.h"
/* The virtual table for dom_text */
-static struct dom_text_vtable text_vtable = {
+struct dom_text_vtable text_vtable = {
{
{
DOM_NODE_VTABLE
@@ -24,15 +29,30 @@ static struct dom_text_vtable text_vtable = {
DOM_TEXT_VTABLE
};
-/* The destroy virtual function */
-void _dom_text_destroy(struct dom_node_internal *node);
-void _dom_text_destroy(struct dom_node_internal *node)
-{
- struct dom_document *doc;
- dom_node_get_owner_document(node, &doc);
+static struct dom_node_protect_vtable text_protect_vtable = {
+ DOM_TEXT_PROTECT_VTABLE
+};
- dom_text_destroy(doc, (struct dom_text *) node);
-}
+/* Following comes helper functions */
+typedef enum walk_operation {
+ COLLECT,
+ DELETE
+} walk_operation;
+typedef enum walk_order {
+ LEFT,
+ RIGHT
+} walk_order;
+
+/* Walk the logic-adjacent text in document order */
+static dom_exception walk_logic_adjacent_text_in_order(
+ dom_node_internal *node, walk_operation opt,
+ walk_order order, dom_string **ret, bool *cont);
+/* Walk the logic-adjacent text */
+static dom_exception walk_logic_adjacent_text(dom_text *text,
+ walk_operation opt, dom_string **ret);
+
+/*----------------------------------------------------------------------*/
+/* Constructor and Destructor */
/**
* Create a text node
@@ -48,25 +68,29 @@ void _dom_text_destroy(struct dom_node_internal *node)
*
* The returned node will already be referenced.
*/
-dom_exception dom_text_create(struct dom_document *doc,
- struct dom_string *name, struct dom_string *value,
+dom_exception _dom_text_create(struct dom_document *doc,
+ struct lwc_string_s *name, struct dom_string *value,
struct dom_text **result)
{
struct dom_text *t;
dom_exception err;
/* Allocate the text node */
- t = dom_document_alloc(doc, NULL, sizeof(struct dom_text));
+ t = _dom_document_alloc(doc, NULL, sizeof(struct dom_text));
if (t == NULL)
return DOM_NO_MEM_ERR;
/* And initialise the node */
- err = dom_text_initialise(t, doc, DOM_TEXT_NODE, name, value);
+ err = _dom_text_initialise(t, doc, DOM_TEXT_NODE, name, value);
if (err != DOM_NO_ERR) {
- dom_document_alloc(doc, t, 0);
+ _dom_document_alloc(doc, t, 0);
return err;
}
+ /* Compose the vtable */
+ ((struct dom_node *) t)->vtable = &text_vtable;
+ ((struct dom_node_internal *) t)->vtable = &text_protect_vtable;
+
*result = t;
return DOM_NO_ERR;
@@ -80,13 +104,13 @@ dom_exception dom_text_create(struct dom_document *doc,
*
* The contents of ::text will be destroyed and ::text will be freed.
*/
-void dom_text_destroy(struct dom_document *doc, struct dom_text *text)
+void _dom_text_destroy(struct dom_document *doc, struct dom_text *text)
{
/* Finalise node */
- dom_text_finalise(doc, text);
+ _dom_text_finalise(doc, text);
/* Free node */
- dom_document_alloc(doc, text, 0);
+ _dom_document_alloc(doc, text, 0);
}
/**
@@ -101,22 +125,18 @@ void dom_text_destroy(struct dom_document *doc, struct dom_text *text)
*
* ::doc, ::name and ::value will have their reference counts increased.
*/
-dom_exception dom_text_initialise(struct dom_text *text,
+dom_exception _dom_text_initialise(struct dom_text *text,
struct dom_document *doc, dom_node_type type,
- struct dom_string *name, struct dom_string *value)
+ struct lwc_string_s *name, struct dom_string *value)
{
dom_exception err;
/* Initialise the base class */
- err = dom_characterdata_initialise(&text->base, doc, type,
+ err = _dom_characterdata_initialise(&text->base, doc, type,
name, value);
if (err != DOM_NO_ERR)
return err;
- /* Compose the vtable */
- ((struct dom_node *) text)->vtable = &text_vtable;
- text->base.base.destroy = &_dom_text_destroy;
-
/* Perform our type-specific initialisation */
text->element_content_whitespace = false;
@@ -131,11 +151,14 @@ dom_exception dom_text_initialise(struct dom_text *text,
*
* The contents of ::text will be cleaned up. ::text will not be freed.
*/
-void dom_text_finalise(struct dom_document *doc, struct dom_text *text)
+void _dom_text_finalise(struct dom_document *doc, struct dom_text *text)
{
- dom_characterdata_finalise(doc, &text->base);
+ _dom_characterdata_finalise(doc, &text->base);
}
+/*----------------------------------------------------------------------*/
+/* The public virtual functions */
+
/**
* Split a text node at a given character offset
*
@@ -181,7 +204,7 @@ dom_exception _dom_text_split_text(struct dom_text *text,
}
/* Create new node */
- err = dom_text_create(t->owner, t->name, value, &res);
+ err = _dom_text_create(t->owner, t->name, value, &res);
if (err != DOM_NO_ERR) {
dom_string_unref(value);
return err;
@@ -227,10 +250,7 @@ dom_exception _dom_text_get_is_element_content_whitespace(
dom_exception _dom_text_get_whole_text(struct dom_text *text,
struct dom_string **result)
{
- UNUSED(text);
- UNUSED(result);
-
- return DOM_NOT_SUPPORTED_ERR;
+ return walk_logic_adjacent_text(text, COLLECT, result);
}
/**
@@ -249,10 +269,240 @@ dom_exception _dom_text_get_whole_text(struct dom_text *text,
dom_exception _dom_text_replace_whole_text(struct dom_text *text,
struct dom_string *content, struct dom_text **result)
{
- UNUSED(text);
- UNUSED(content);
- UNUSED(result);
+ dom_exception err;
+ dom_string *ret;
+
+ err = walk_logic_adjacent_text(text, DELETE, &ret);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ err = dom_characterdata_set_data(text, content);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ *result = text;
+ dom_node_ref(text);
+
+ return DOM_NO_ERR;
+}
+
+/*-----------------------------------------------------------------------*/
+/* The protected virtual functions */
+
+/* The destroy function of this class */
+void __dom_text_destroy(struct dom_node_internal *node)
+{
+ struct dom_document *doc;
+ doc = dom_node_get_owner(node);
+
+ _dom_text_destroy(doc, (struct dom_text *) node);
+}
+
+/* The memory allocator for this class */
+dom_exception _dom_text_alloc(struct dom_document *doc,
+ struct dom_node_internal *n, struct dom_node_internal **ret)
+{
+ UNUSED(n);
+ dom_text *a;
+
+ a = _dom_document_alloc(doc, NULL, sizeof(struct dom_text));
+ if (a == NULL)
+ return DOM_NO_MEM_ERR;
+
+ *ret = (dom_node_internal *) a;
+ dom_node_set_owner(*ret, doc);
+
+ return DOM_NO_ERR;
+}
+
+/* The copy constructor of this class */
+dom_exception _dom_text_copy(struct dom_node_internal *new,
+ struct dom_node_internal *old)
+{
+ dom_text *ot = (dom_text *) old;
+ dom_text *nt = (dom_text *) new;
- return DOM_NOT_SUPPORTED_ERR;
+ nt->element_content_whitespace = ot->element_content_whitespace;
+
+ return _dom_characterdata_copy(new, old);
+}
+
+/*----------------------------------------------------------------------*/
+/* Helper functions */
+
+/**
+ * Walk the logic adjacent text in certain order
+ *
+ * \param node The start Text node
+ * \param opt The operation on each Text Node
+ * \param order The order
+ * \param ret The string of the logic adjacent text
+ * \param cont Whether the logic adjacent text is interrupt here
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception walk_logic_adjacent_text_in_order(
+ dom_node_internal *node, walk_operation opt,
+ walk_order order, dom_string **ret, bool *cont)
+{
+ dom_exception err;
+ dom_string *data, *tmp;
+ dom_node_internal *parent = dom_node_get_parent(node);
+
+ /* If we reach the leaf of the DOM tree, just return to continue
+ * to next sibling of our parent */
+ if (node == NULL) {
+ *cont = true;
+ return DOM_NO_ERR;
+ }
+
+ while (node != NULL) {
+ /* If we reach the boundary of logical-adjacent text, we stop */
+ if (node->type == DOM_ELEMENT_NODE ||
+ node->type == DOM_COMMENT_NODE ||
+ node->type ==
+ DOM_PROCESSING_INSTRUCTION_NODE) {
+ *cont = false;
+ return DOM_NO_ERR;
+ }
+
+ if (node->type == DOM_TEXT_NODE) {
+ /* According the DOM spec, text node never have child */
+ assert(node->first_child == NULL);
+ assert(node->last_child == NULL);
+ if (opt == COLLECT) {
+ err = dom_characterdata_get_data(node, &data);
+ if (err == DOM_NO_ERR)
+ return err;
+
+ tmp = *ret;
+ if (order == LEFT) {
+ err = dom_string_concat(data, tmp, ret);
+ if (err == DOM_NO_ERR)
+ return err;
+ } else if (order == RIGHT) {
+ err = dom_string_concat(tmp, data, ret);
+ if (err == DOM_NO_ERR)
+ return err;
+ }
+
+ dom_string_unref(tmp);
+ dom_string_unref(data);
+
+ *cont = true;
+ return DOM_NO_ERR;
+ }
+
+ if (opt == DELETE) {
+ dom_node_internal *tn;
+ err = dom_node_remove_child(node->parent,
+ node, (void *) &tn);
+ if (err != DOM_NO_ERR)
+ return err;
+
+ *cont = true;
+ dom_node_unref(tn);
+ return DOM_NO_ERR;
+ }
+ }
+
+ dom_node_internal *p = dom_node_get_parent(node);
+ if (order == LEFT) {
+ if (node->last_child != NULL) {
+ node = node->last_child;
+ } else if (node->previous != NULL) {
+ node = node->previous;
+ } else {
+ while (p != parent && node == p->last_child) {
+ node = p;
+ p = dom_node_get_parent(p);
+ }
+
+ node = node->previous;
+ }
+ } else {
+ if (node->first_child != NULL) {
+ node = node->first_child;
+ } else if (node->next != NULL) {
+ node = node->next;
+ } else {
+ while (p != parent && node == p->first_child) {
+ node = p;
+ p = dom_node_get_parent(p);
+ }
+
+ node = node->next;
+ }
+ }
+ }
+
+ return DOM_NO_ERR;
+}
+
+/**
+ * Traverse the logic adjacent text.
+ *
+ * \param text The Text Node from which we start traversal
+ * \param opt The operation code
+ * \param ret The returned string if the opt is COLLECT
+ * \return DOM_NO_ERR on success, appropriate dom_exception on failure.
+ */
+dom_exception walk_logic_adjacent_text(dom_text *text,
+ walk_operation opt, dom_string **ret)
+{
+ dom_node_internal *node = (dom_node_internal *) text;
+ dom_node_internal *parent = node->parent;
+ dom_node_internal *left = node->previous;
+ dom_node_internal *right = node->next;
+ dom_exception err;
+ bool cont;
+
+ if (parent->type == DOM_ENTITY_NODE) {
+ return DOM_NOT_SUPPORTED_ERR;
+ }
+
+ /* Firstly, we look our left */
+ err = walk_logic_adjacent_text_in_order(left, opt, LEFT, ret, &cont);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(*ret);
+ *ret = NULL;
+ return err;
+ }
+
+ /* Ourself */
+ if (opt == COLLECT) {
+ dom_string *data = NULL, *tmp = NULL;
+ err = dom_characterdata_get_data(text, &data);
+ if (err == DOM_NO_ERR) {
+ dom_string_unref(*ret);
+ return err;
+ }
+
+ err = dom_string_concat(*ret, data, &tmp);
+ if (err == DOM_NO_ERR) {
+ dom_string_unref(*ret);
+ return err;
+ }
+
+ dom_string_unref(*ret);
+ dom_string_unref(data);
+ *ret = tmp;
+ } else {
+ dom_node_internal *tn;
+ err = dom_node_remove_child(node->parent, node,
+ (void *) &tn);
+ if (err != DOM_NO_ERR)
+ return err;
+ dom_node_unref(tn);
+ }
+
+ /* Now, look right */
+ err = walk_logic_adjacent_text_in_order(right, opt, RIGHT, ret, &cont);
+ if (err != DOM_NO_ERR) {
+ dom_string_unref(*ret);
+ *ret = NULL;
+ return err;
+ }
+
+ return DOM_NO_ERR;
}