From 2920bca14adbf145d64754b1ef8e6b888c7995ee Mon Sep 17 00:00:00 2001 From: James Bursa Date: Sat, 9 Apr 2005 09:47:37 +0000 Subject: [project @ 2005-04-09 09:47:36 by bursa] Move HTML contents almost fully over to talloc(), simplifying code. Improvements to title attributes, broken forms, cellpadding. Reorder functions in box_construct.c. svn path=/import/netsurf/; revision=1608 --- render/box.c | 59 +- render/box.h | 9 +- render/box_construct.c | 2310 +++++++++++++++++++++++------------------------- render/box_normalise.c | 53 +- render/form.c | 1 + render/form.h | 1 + render/html.c | 86 +- render/html.h | 10 +- render/layout.c | 113 ++- render/layout.h | 8 +- 10 files changed, 1242 insertions(+), 1408 deletions(-) (limited to 'render') diff --git a/render/box.c b/render/box.c index 8d21d7a01..c6b8f51ed 100644 --- a/render/box.c +++ b/render/box.c @@ -18,7 +18,7 @@ #include "netsurf/css/css.h" #include "netsurf/render/box.h" #include "netsurf/render/form.h" -#include "netsurf/utils/pool.h" +#include "netsurf/utils/talloc.h" static bool box_contains_point(struct box *box, int x, int y); @@ -31,43 +31,23 @@ static bool box_contains_point(struct box *box, int x, int y); * Create a box tree node. * * \param style style for the box (not copied) - * \param href href for the box (copied), or 0 - * \param title title for the box (copied), or 0 - * \param id id for the box (copied), or 0 - * \param box_pool pool to allocate box from + * \param href href for the box (not copied), or 0 + * \param title title for the box (not copied), or 0 + * \param id id for the box (not copied), or 0 + * \param context context for allocations * \return allocated and initialised box, or 0 on memory exhaustion */ struct box * box_create(struct css_style *style, - const char *href, const char *title, const char *id, - pool box_pool) + char *href, char *title, char *id, + void *context) { unsigned int i; struct box *box; - char *href1 = 0; - char *title1 = 0; - char *id1 = 0; - - if (href) - href1 = strdup(href); - if (title) - title1 = strdup(title); - if (id) - id1 = strdup(id); - if ((href && !href1) || (title && !title1) || (id && !id1)) { - free(href1); - free(title1); - free(id1); - return 0; - } - box = pool_alloc(box_pool, sizeof (struct box)); - if (!box) { - free(href1); - free(title1); - free(id1); + box = talloc(context, struct box); + if (!box) return 0; - } box->type = BOX_INLINE; box->style = style; @@ -86,8 +66,8 @@ struct box * box_create(struct css_style *style, box->space = 0; box->clone = 0; box->style_clone = 0; - box->href = href1; - box->title = title1; + box->href = href; + box->title = title; box->columns = 1; box->rows = 1; box->start_column = 0; @@ -101,7 +81,7 @@ struct box * box_create(struct css_style *style, box->col = NULL; box->gadget = NULL; box->usemap = NULL; - box->id = id1; + box->id = id; box->background = NULL; box->object = NULL; box->object_params = NULL; @@ -153,12 +133,11 @@ void box_insert_sibling(struct box *box, struct box *new_box) /** - * Free the data in a box tree recursively. + * Free the a box tree recursively. * * \param box box to free recursively * - * The data in box and all its children is freed. The actual box structures are - * not freed, only the data (since they will be in a pool). + * The box and all its children is freed. */ void box_free(struct box *box) @@ -187,17 +166,11 @@ void box_free_box(struct box *box) if (!box->clone) { if (box->gadget) form_free_control(box->gadget); - free(box->href); - free(box->title); - free(box->col); - if (!box->style_clone && box->style) - css_free_style(box->style); } - free(box->usemap); - free(box->text); - free(box->id); box_free_object_params(box->object_params); + + talloc_free(box); } diff --git a/render/box.h b/render/box.h index 28a1f2b4e..3e1b24182 100644 --- a/render/box.h +++ b/render/box.h @@ -76,7 +76,6 @@ #include #include #include "libxml/HTMLparser.h" -#include "netsurf/utils/pool.h" struct box; @@ -90,7 +89,7 @@ typedef enum { BOX_TABLE, BOX_TABLE_ROW, BOX_TABLE_CELL, BOX_TABLE_ROW_GROUP, BOX_FLOAT_LEFT, BOX_FLOAT_RIGHT, - BOX_INLINE_BLOCK, BOX_BR + BOX_INLINE_BLOCK, BOX_BR, BOX_TEXT } box_type; /* parameters for and related elements */ @@ -232,8 +231,8 @@ struct column { struct box * box_create(struct css_style *style, - const char *href, const char *title, - const char *id, pool box_pool); + char *href, char *title, + char *id, void *context); void box_add_child(struct box *parent, struct box *child); void box_insert_sibling(struct box *box, struct box *new_box); void box_free(struct box *box); @@ -259,6 +258,6 @@ void box_scrollbar_dimensions(const struct box *box, bool xml_to_box(xmlNode *n, struct content *c); -bool box_normalise_block(struct box *block, pool box_pool); +bool box_normalise_block(struct box *block, struct content *c); #endif diff --git a/render/box_construct.c b/render/box_construct.c index 5e74497a4..8fc6881a3 100644 --- a/render/box_construct.c +++ b/render/box_construct.c @@ -29,33 +29,14 @@ #ifdef riscos #include "netsurf/desktop/gui.h" #endif -#define NDEBUG +/* #define NDEBUG */ #include "netsurf/utils/log.h" #include "netsurf/utils/messages.h" -#include "netsurf/utils/pool.h" +#include "netsurf/utils/talloc.h" #include "netsurf/utils/url.h" #include "netsurf/utils/utils.h" -/** Status of box tree construction. */ -struct box_status { - struct content *content; - char *href; - char *title; - struct form *current_form; - char *id; -}; - -/** Return type for special case element functions. */ -struct box_result { - /** Box for element, if any, 0 otherwise. */ - struct box *box; - /** Children of this element should be converted. */ - bool convert_children; - /** Memory was exhausted when handling the element. */ - bool memory_error; -}; - /** MultiLength, as defined by HTML 4.01. */ struct box_multi_length { enum { LENGTH_PX, LENGTH_PERCENT, LENGTH_RELATIVE } type; @@ -91,62 +72,49 @@ static const content_type image_types[] = { static bool convert_xml_to_box(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, - struct box_status status); + char *href, char *title); bool box_construct_element(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, - struct box_status status); + char *href, char *title); bool box_construct_text(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, - struct box_status status); + char *href, char *title); static struct css_style * box_get_style(struct content *c, struct css_style *parent_style, xmlNode *n); static void box_solve_display(struct css_style *style, bool root); static void box_text_transform(char *s, unsigned int len, css_text_transform tt); -static struct box_result box_a(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box_result box_body(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box_result box_br(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box_result box_image(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box_result box_form(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box_result box_textarea(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box_result box_select(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box_result box_input(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box *box_input_text(xmlNode *n, struct box_status *status, - struct css_style *style, bool password); -static struct box_result box_button(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box_result box_frameset(xmlNode *n, struct box_status *status, - struct css_style *style); +#define BOX_SPECIAL_PARAMS xmlNode *n, struct content *content, \ + struct box *box, bool *convert_children +static bool box_a(BOX_SPECIAL_PARAMS); +static bool box_body(BOX_SPECIAL_PARAMS); +static bool box_br(BOX_SPECIAL_PARAMS); +static bool box_image(BOX_SPECIAL_PARAMS); +static bool box_form(BOX_SPECIAL_PARAMS); +static bool box_textarea(BOX_SPECIAL_PARAMS); +static bool box_select(BOX_SPECIAL_PARAMS); +static bool box_input(BOX_SPECIAL_PARAMS); +static bool box_input_text(BOX_SPECIAL_PARAMS, bool password); +static bool box_button(BOX_SPECIAL_PARAMS); +static bool box_frameset(BOX_SPECIAL_PARAMS); static bool box_select_add_option(struct form_control *control, xmlNode *n); -static struct box_result box_object(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box_result box_embed(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box_result box_applet(xmlNode *n, struct box_status *status, - struct css_style *style); -static struct box_result box_iframe(xmlNode *n, struct box_status *status, - struct css_style *style); +static bool box_object(BOX_SPECIAL_PARAMS); +static bool box_embed(BOX_SPECIAL_PARAMS); +static bool box_applet(BOX_SPECIAL_PARAMS); +static bool box_iframe(BOX_SPECIAL_PARAMS); static bool plugin_decode(struct content* content, struct box* box); static struct box_multi_length *box_parse_multi_lengths(const char *s, - unsigned int *count); + unsigned int *count, void *context); +void box_set_cellpadding(struct box *box, int value); /* element_table must be sorted by name */ struct element_entry { char name[10]; /* element type */ - struct box_result (*convert)(xmlNode *n, struct box_status *status, - struct css_style *style); + bool (*convert)(BOX_SPECIAL_PARAMS); }; static const struct element_entry element_table[] = { {"a", box_a}, @@ -178,7 +146,6 @@ static const struct element_entry element_table[] = { bool xml_to_box(xmlNode *n, struct content *c) { struct box root; - struct box_status status = {c, 0, 0, 0, 0}; struct box *inline_container = 0; assert(c->type == CONTENT_HTML); @@ -193,7 +160,8 @@ bool xml_to_box(xmlNode *n, struct content *c) root.float_children = NULL; root.next_float = NULL; - c->data.html.style = css_duplicate_style(&css_base_style); + c->data.html.style = talloc_memdup(c, &css_base_style, + sizeof css_base_style); if (!c->data.html.style) return false; c->data.html.style->font_size.value.length.value = @@ -203,9 +171,9 @@ bool xml_to_box(xmlNode *n, struct content *c) c->data.html.object = 0; if (!convert_xml_to_box(n, c, c->data.html.style, &root, - &inline_container, status)) + &inline_container, 0, 0)) return false; - if (!box_normalise_block(&root, c->data.html.box_pool)) + if (!box_normalise_block(&root, c)) return false; c->data.html.layout = root.children; @@ -253,15 +221,15 @@ static const box_type box_map[] = { bool convert_xml_to_box(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, - struct box_status status) + char *href, char *title) { switch (n->type) { case XML_ELEMENT_NODE: return box_construct_element(n, content, parent_style, parent, - inline_container, status); + inline_container, href, title); case XML_TEXT_NODE: return box_construct_text(n, content, parent_style, parent, - inline_container, status); + inline_container, href, title); default: /* not an element or text node: ignore it (eg. comment) */ return true; @@ -285,18 +253,17 @@ bool convert_xml_to_box(xmlNode *n, struct content *content, bool box_construct_element(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, - struct box_status status) + char *href, char *title) { + bool convert_children = true; + char *id = 0; + char *s; struct box *box = 0; struct box *inline_container_c; struct css_style *style = 0; - xmlNode *c; - char *s; - xmlChar *title0, *id0; - char *title = 0, *id = 0; - bool convert_children = true; - char *href_in = status.href; struct element_entry *element; + xmlChar *title0, *id0; + xmlNode *c; assert(n); assert(n->type == XML_ELEMENT_NODE); @@ -308,108 +275,89 @@ bool box_construct_element(xmlNode *n, struct content *content, style = box_get_style(content, parent_style, n); if (!style) - goto no_memory; + return false; if (style->display == CSS_DISPLAY_NONE) { - css_free_style(style); - goto end; + talloc_free(style); + return true; } /* extract title attribute, if present */ if ((title0 = xmlGetProp(n, (const xmlChar *) "title"))) { - status.title = title = squash_whitespace(title0); + char *title1 = squash_whitespace(title0); xmlFree(title0); + if (!title1) + return false; + title = talloc_strdup(content, title1); + free(title1); if (!title) - goto no_memory; + return false; } /* extract id attribute, if present */ if ((id0 = xmlGetProp(n, (const xmlChar *) "id"))) { - status.id = id = squash_whitespace(id0); + id = talloc_strdup(content, id0); xmlFree(id0); if (!id) - goto no_memory; + return false; } + /* create box for this element */ + box = box_create(style, href, title, id, content); + if (!box) + return false; + /* set box type from style */ + box->type = box_map[style->display]; + /* special elements */ element = bsearch((const char *) n->name, element_table, ELEMENT_TABLE_COUNT, sizeof(element_table[0]), (int (*)(const void *, const void *)) strcmp); if (element) { /* a special convert function exists for this element */ - struct box_result res = element->convert(n, &status, style); - box = res.box; - convert_children = res.convert_children; - if (res.memory_error) - goto no_memory; - if (!box) { - /* no box for this element */ - assert(!convert_children); - css_free_style(style); - goto end; - } - } else { - /* general element */ - box = box_create(style, status.href, title, id, - content->data.html.box_pool); - if (!box) - goto no_memory; + if (!element->convert(n, content, box, &convert_children)) + return false; + href = box->href; } - /* set box type from style if it has not been set already */ - if (box->type == BOX_INLINE) - box->type = box_map[style->display]; - - content->size += sizeof(struct box) + sizeof(struct css_style); - if (box->type == BOX_INLINE || + if (!*inline_container && + (box->type == BOX_INLINE || + box->type == BOX_BR || box->type == BOX_INLINE_BLOCK || style->float_ == CSS_FLOAT_LEFT || - style->float_ == CSS_FLOAT_RIGHT || - box->type == BOX_BR) { - /* this is an inline box */ - if (!*inline_container) { - /* this is the first inline node: make a container */ - *inline_container = box_create(0, 0, 0, 0, - content->data.html.box_pool); - if (!*inline_container) - goto no_memory; - (*inline_container)->type = BOX_INLINE_CONTAINER; - box_add_child(parent, *inline_container); - } + style->float_ == CSS_FLOAT_RIGHT)) { + /* this is the first inline in a block: make a container */ + *inline_container = box_create(0, 0, 0, 0, content); + if (!*inline_container) + return false; + (*inline_container)->type = BOX_INLINE_CONTAINER; + box_add_child(parent, *inline_container); + } - if (box->type == BOX_INLINE || box->type == BOX_BR) { - /* inline box: add to tree and recurse */ - box_add_child(*inline_container, box); - if (convert_children) { - for (c = n->children; c != 0; c = c->next) - if (!convert_xml_to_box(c, content, - style, parent, - inline_container, - status)) - goto no_memory; - } - goto end; - } else if (box->type == BOX_INLINE_BLOCK) { - /* inline block box: add to tree and recurse */ - box_add_child(*inline_container, box); - if (convert_children) { - inline_container_c = 0; - for (c = n->children; c != 0; c = c->next) - if (!convert_xml_to_box(c, content, - style, box, - &inline_container_c, - status)) - goto no_memory; - } - goto end; - } else { + if (box->type == BOX_INLINE || box->type == BOX_BR) { + /* inline box: add to tree and recurse */ + box_add_child(*inline_container, box); + for (c = n->children; convert_children && c; c = c->next) + if (!convert_xml_to_box(c, content, style, parent, + inline_container, href, title)) + return false; + } else if (box->type == BOX_INLINE_BLOCK) { + /* inline block box: add to tree and recurse */ + box_add_child(*inline_container, box); + inline_container_c = 0; + for (c = n->children; convert_children && c; c = c->next) + if (!convert_xml_to_box(c, content, style, box, + &inline_container_c, href, title)) + return false; + } else { + if (style->float_ == CSS_FLOAT_LEFT || + style->float_ == CSS_FLOAT_RIGHT) { /* float: insert a float box between the parent and * current node */ assert(style->float_ == CSS_FLOAT_LEFT || style->float_ == CSS_FLOAT_RIGHT); - parent = box_create(0, status.href, title, id, - content->data.html.box_pool); + parent = box_create(0, href, title, 0, content); if (!parent) - goto no_memory; + return false; if (style->float_ == CSS_FLOAT_LEFT) parent->type = BOX_FLOAT_LEFT; else @@ -419,63 +367,50 @@ bool box_construct_element(xmlNode *n, struct content *content, box->type == BOX_INLINE_BLOCK) box->type = BOX_BLOCK; } - } - /* non-inline box: add to tree and recurse */ - box_add_child(parent, box); - if (convert_children) { + /* non-inline box: add to tree and recurse */ + box_add_child(parent, box); inline_container_c = 0; - for (c = n->children; c != 0; c = c->next) - if (!convert_xml_to_box(c, content, style, - box, &inline_container_c, status)) - goto no_memory; + for (c = n->children; convert_children && c; c = c->next) + if (!convert_xml_to_box(c, content, style, box, + &inline_container_c, href, title)) + return false; + if (style->float_ == CSS_FLOAT_NONE) + /* new inline container unless this is a float */ + *inline_container = 0; } - if (style->float_ == CSS_FLOAT_NONE) - /* new inline container unless this is a float */ - *inline_container = 0; - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "colspan")) != NULL) { + /* misc. attributes that can't be handled in box_get_style() */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "colspan"))) { box->columns = strtol(s, NULL, 10); if (MAX_SPAN < box->columns) box->columns = 1; xmlFree(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "rowspan")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "rowspan"))) { box->rows = strtol(s, NULL, 10); if (MAX_SPAN < box->rows) box->rows = 1; xmlFree(s); } + if (strcmp((const char *) n->name, "table") == 0 && + (s = (char *) xmlGetProp(n, + (const xmlChar *) "cellpadding"))) { + int value = atoi(s); + if (!strrchr(s, '%') && 0 < value) /* % not implemented */ + box_set_cellpadding(box, value); + xmlFree(s); + } -end: - free(title); - free(id); - if (!href_in) - xmlFree(status.href); - - /* Now fetch any background image for this box */ - if (box && box->style && box->style->background_image.type == - CSS_BACKGROUND_IMAGE_URI) { - char *url = strdup(box->style->background_image.uri); - if (!url) - return false; - /* start fetch */ - if (!html_fetch_object(content, url, box, image_types, - content->available_width, 1000, true)) + /* fetch any background image for this box */ + if (style->background_image.type == CSS_BACKGROUND_IMAGE_URI) { + if (!html_fetch_object(content, style->background_image.uri, + box, image_types, content->available_width, + 1000, true)) return false; } return true; - -no_memory: - free(title); - free(id); - if (!href_in) - xmlFree(status.href); - if (style && !box) - css_free_style(style); - - return false; } @@ -495,7 +430,7 @@ no_memory: bool box_construct_text(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, - struct box_status status) + char *href, char *title) { struct box *box = 0; @@ -505,13 +440,11 @@ bool box_construct_text(xmlNode *n, struct content *content, assert(parent); assert(inline_container); - content->size += sizeof(struct box) + sizeof(struct css_style); - if (parent_style->white_space == CSS_WHITE_SPACE_NORMAL || parent_style->white_space == CSS_WHITE_SPACE_NOWRAP) { char *text = squash_whitespace(n->content); if (!text) - goto no_memory; + return false; /* if the text is just a space, combine it with the preceding * text node, if any */ @@ -521,30 +454,31 @@ bool box_construct_text(xmlNode *n, struct content *content, (*inline_container)->last->space = 1; } free(text); - goto end; + return true; } if (!*inline_container) { /* this is the first inline node: make a container */ - *inline_container = box_create(0, 0, 0, 0, - content->data.html.box_pool); + *inline_container = box_create(0, 0, 0, 0, content); if (!*inline_container) { free(text); - goto no_memory; + return false; } (*inline_container)->type = BOX_INLINE_CONTAINER; box_add_child(parent, *inline_container); } - box = box_create(parent_style, status.href, 0, 0, - content->data.html.box_pool); + box = box_create(parent_style, href, title, 0, content); if (!box) { free(text); - goto no_memory; + return false; } - box->text = text; + box->text = talloc_strdup(content, text); + free(text); + if (!box->text) + return false; box->style_clone = 1; - box->length = strlen(text); + box->length = strlen(box->text); /* strip ending space char off */ if (box->length > 1 && text[box->length - 1] == ' ') { box->space = 1; @@ -561,12 +495,12 @@ bool box_construct_text(xmlNode *n, struct content *content, /* there is a space in text block and we * want all spaces to be converted to NBSP */ - box->text = cnv_space2nbsp(text); + /*box->text = cnv_space2nbsp(text); if (!box->text) { free(text); goto no_memory; } - box->length = strlen(box->text); + box->length = strlen(box->text);*/ } } @@ -577,7 +511,6 @@ bool box_construct_text(xmlNode *n, struct content *content, if (box->prev != NULL) box->prev->space = 1; } - goto end; } else { /* white-space: pre */ @@ -590,7 +523,7 @@ bool box_construct_text(xmlNode *n, struct content *content, parent_style->white_space == CSS_WHITE_SPACE_PRE_WRAP); if (!text) - goto no_memory; + return false; if (parent_style->text_transform != CSS_TEXT_TRANSFORM_NONE) box_text_transform(text, strlen(text), parent_style->text_transform); @@ -601,27 +534,26 @@ bool box_construct_text(xmlNode *n, struct content *content, current[len] = 0; if (!*inline_container) { *inline_container = box_create(0, 0, 0, 0, - content->data.html.box_pool); + content); if (!*inline_container) { free(text); - goto no_memory; + return false; } (*inline_container)->type = BOX_INLINE_CONTAINER; box_add_child(parent, *inline_container); } - box = box_create(parent_style, status.href, 0, - 0, content->data.html.box_pool); + box = box_create(parent_style, href, title, 0, content); if (!box) { free(text); - goto no_memory; + return false; } box->type = BOX_INLINE; box->style_clone = 1; - box->text = strdup(current); + box->text = talloc_strdup(content, current); if (!box->text) { free(text); - goto no_memory; + return false; } box->length = strlen(box->text); box_add_child(*inline_container, box); @@ -636,14 +568,9 @@ bool box_construct_text(xmlNode *n, struct content *content, } } while (*current); free(text); - goto end; } -end: return true; - -no_memory: - return false; } @@ -674,15 +601,13 @@ struct css_style * box_get_style(struct content *c, char *url; url_func_result res; - style = css_duplicate_style(parent_style); + style = talloc_memdup(c, parent_style, sizeof *style); if (!style) return 0; - style_new = css_duplicate_style(&css_blank_style); - if (!style_new) { - css_free_style(style); + style_new = talloc_memdup(c, &css_blank_style, sizeof *style_new); + if (!style_new) return 0; - } for (i = 0; i != stylesheet_count; i++) { if (stylesheet[i]) { @@ -693,15 +618,15 @@ struct css_style * box_get_style(struct content *c, css_cascade(style, style_new); /* style_new isn't needed past this point */ - css_free_style(style_new); + talloc_free(style_new); /* This property only applies to the body element, if you believe * the spec. Many browsers seem to allow it on other elements too, * so let's be generic ;) */ if ((s = (char *) xmlGetProp(n, (const xmlChar *) "background"))) { res = url_join(s, c->data.html.base_url, &url); + xmlFree(s); if (res == URL_FUNC_NOMEM) { - css_free_style(style); return 0; } else if (res == URL_FUNC_OK) { /* if url is equivalent to the parent's url, @@ -711,13 +636,16 @@ struct css_style * box_get_style(struct content *c, else { style->background_image.type = CSS_BACKGROUND_IMAGE_URI; - style->background_image.uri = url; + style->background_image.uri = talloc_strdup( + c, url); + free(url); + if (!style->background_image.uri) + return 0; } } - xmlFree(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "bgcolor")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "bgcolor"))) { unsigned int r, g, b; if (s[0] == '#' && sscanf(s + 1, "%2x%2x%2x", &r, &g, &b) == 3) style->background_color = (b << 16) | (g << 8) | r; @@ -726,7 +654,7 @@ struct css_style * box_get_style(struct content *c, xmlFree(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "color")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "color"))) { unsigned int r, g, b; if (s[0] == '#' && sscanf(s + 1, "%2x%2x%2x", &r, &g, &b) == 3) style->color = (b << 16) | (g << 8) | r; @@ -735,7 +663,7 @@ struct css_style * box_get_style(struct content *c, xmlFree(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "height")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "height"))) { float value = atof(s); if (value < 0 || strlen(s) == 0) { /* ignore negative values and height="" */ @@ -751,18 +679,23 @@ struct css_style * box_get_style(struct content *c, } if (strcmp((const char *) n->name, "input") == 0) { - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "size")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "size"))) { int size = atoi(s); if (0 < size) { - char *type = (char *) xmlGetProp(n, (const xmlChar *) "type"); + char *type = (char *) xmlGetProp(n, + (const xmlChar *) "type"); style->width.width = CSS_WIDTH_LENGTH; if (!type || strcasecmp(type, "text") == 0 || - strcasecmp(type, "password") == 0) - /* in characters for text, password, file */ - style->width.value.length.unit = CSS_UNIT_EX; + strcasecmp(type, "password") == 0) + /* in characters for text, password */ + style->width.value.length.unit = + CSS_UNIT_EX; else if (strcasecmp(type, "file") != 0) - /* in pixels otherwise */ - style->width.value.length.unit = CSS_UNIT_PX; + /* in pixels otherwise; ignore width + * on file, because we do them + * differently to most browsers */ + style->width.value.length.unit = + CSS_UNIT_PX; style->width.value.length.value = size; if (type) xmlFree(type); @@ -772,9 +705,10 @@ struct css_style * box_get_style(struct content *c, } if (strcmp((const char *) n->name, "body") == 0) { - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "text")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "text"))) { unsigned int r, g, b; - if (s[0] == '#' && sscanf(s + 1, "%2x%2x%2x", &r, &g, &b) == 3) + if (s[0] == '#' && sscanf(s + 1, "%2x%2x%2x", + &r, &g, &b) == 3) style->color = (b << 16) | (g << 8) | r; else if (s[0] != '#') style->color = named_colour(s); @@ -782,7 +716,7 @@ struct css_style * box_get_style(struct content *c, } } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "width")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "width"))) { float value = atof(s); if (value < 0 || strlen(s) == 0) { /* ignore negative values and width="" */ @@ -798,7 +732,7 @@ struct css_style * box_get_style(struct content *c, } if (strcmp((const char *) n->name, "textarea") == 0) { - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "rows")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "rows"))) { int value = atoi(s); if (0 < value) { style->height.height = CSS_HEIGHT_LENGTH; @@ -807,7 +741,7 @@ struct css_style * box_get_style(struct content *c, } xmlFree(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "cols")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "cols"))) { int value = atoi(s); if (0 < value) { style->width.width = CSS_WIDTH_LENGTH; @@ -835,24 +769,9 @@ struct css_style * box_get_style(struct content *c, } } } - style->html_style.cellpadding.type = CSS_CELLPADDING_VALUE; - if ((s = (char *) xmlGetProp(n, - (const xmlChar *) "cellpadding"))) { - if (!strrchr(s, '%')) { /* % not implemented */ - int value = atoi(s); - if (0 <= value) { - style->html_style.cellpadding.value = value; - /* todo: match and rules and don't set if they are */ - for (i = 0; i < 4; i++) - style->padding[i].override_cellpadding = false; - } - } - } else { - style->html_style.cellpadding.value = 1; - } } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "style")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "style"))) { struct css_style *astyle; astyle = css_duplicate_style(&css_empty_style); if (!astyle) { @@ -905,6 +824,44 @@ void box_solve_display(struct css_style *style, bool root) } +/** + * Set the cellpadding on a table. + * + * \param box box to set cellpadding on + * \param value padding in pixels + * + * The descendants of the box are searched for table cells, and the padding is + * set on each one. + */ + +void box_set_cellpadding(struct box *box, int value) +{ + /* The tree is not normalized yet, so accept cells not in rows and + * rows not in row groups. */ + struct box *child; + for (child = box->children; child; child = child->next) { + switch (child->type) { + case BOX_TABLE_ROW_GROUP: + case BOX_TABLE_ROW: + box_set_cellpadding(child, value); + break; + case BOX_TABLE_CELL: + for (unsigned int i = 0; i != 4; i++) { + child->style->padding[i].padding = + CSS_PADDING_LENGTH; + child->style->padding[i].value.length.value = + value; + child->style->padding[i].value.length.unit = + CSS_UNIT_PX; + } + break; + default: + break; + } + } +} + + /** * Apply the CSS text-transform property to given text for its ASCII chars. * @@ -943,433 +900,690 @@ void box_text_transform(char *s, unsigned int len, } -/* - * Special case elements +/** + * \name Special case element handlers * * These functions are called by convert_xml_to_box when an element is being - * converted, according to the entries in element_table (top of file). + * converted, according to the entries in element_table. + * + * The parameters are the xmlNode, the content for the document, and a partly + * filled in box structure for the element. * - * The parameters are the xmlNode, a status structure for the conversion, and - * the style found for the element. + * Return true on success, false on memory exhaustion. Set *convert_children + * to false if children of this element in the XML tree should be skipped (for + * example, if they have been processed in some special way already). * - * If a box is created, it is returned in the result structure. The - * convert_children field should be 1 if convert_xml_to_box should convert the - * node's children recursively, 0 if it should ignore them (presumably they - * have been processed in some way by the function). If box is 0, no box will - * be created for that element, and convert_children must be 0. + * Elements ordered as in the HTML 4.01 specification. Section numbers in + * brackets [] refer to the spec. + * + * \{ */ -struct box_result box_a(xmlNode *n, struct box_status *status, - struct css_style *style) -{ - struct box *box; - char *s, *s1; - char *id = status->id; - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "href")) != NULL) - status->href = s; +/** + * Document body [7.5.1]. + */ - /* name and id share the same namespace */ - if ((s1 = (char *) xmlGetProp(n, (const xmlChar *) "name")) != NULL) { - if (status->id && strcmp(status->id, s1) == 0) { - /* both specified and they match => ok */ - id = status->id; - } - else if (!status->id) { - /* only name specified */ - id = squash_whitespace(s1); - if (!id) { - xmlFree(s1); - return (struct box_result) {0, false, true}; - } - } else - /* both specified but no match */ - id = 0; +bool box_body(BOX_SPECIAL_PARAMS) +{ + content->data.html.background_colour = box->style->background_color; + return true; +} - xmlFree(s1); - } - box = box_create(style, status->href, status->title, id, - status->content->data.html.box_pool); +/** + * Forced line break [9.3.2]. + */ - if (id && id != status->id) - free(id); +bool box_br(BOX_SPECIAL_PARAMS) +{ + box->type = BOX_BR; + return true; +} - if (!box) - return (struct box_result) {0, false, true}; - return (struct box_result) {box, true, false}; -} +/** + * Anchor [12.2]. + */ -struct box_result box_body(xmlNode *n, struct box_status *status, - struct css_style *style) +bool box_a(BOX_SPECIAL_PARAMS) { - struct box *box; - status->content->data.html.background_colour = style->background_color; - box = box_create(style, status->href, status->title, status->id, - status->content->data.html.box_pool); - if (!box) - return (struct box_result) {0, false, true}; - return (struct box_result) {box, true, false}; -} + char *s; -struct box_result box_br(xmlNode *n, struct box_status *status, - struct css_style *style) -{ - struct box *box; - box = box_create(style, status->href, status->title, status->id, - status->content->data.html.box_pool); - if (!box) - return (struct box_result) {0, false, true}; - box->type = BOX_BR; - return (struct box_result) {box, false, false}; + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "href"))) { + box->href = talloc_strdup(content, s); + xmlFree(s); + if (!box->href) + return false; + } + + /* name and id share the same namespace */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "name"))) { + box->id = talloc_strdup(content, s); + xmlFree(s); + if (!box->id) + return false; + } + + return true; } -struct box_result box_image(xmlNode *n, struct box_status *status, - struct css_style *style) + +/** + * Embedded image [13.2]. + */ + +bool box_image(BOX_SPECIAL_PARAMS) { - struct box *box; char *s, *url, *s1, *map; xmlChar *s2; url_func_result res; - box = box_create(style, status->href, status->title, status->id, - status->content->data.html.box_pool); - if (!box) - return (struct box_result) {0, false, true}; - /* handle alt text */ - if ((s2 = xmlGetProp(n, (const xmlChar *) "alt")) != NULL) { - box->text = squash_whitespace(s2); + if ((s2 = xmlGetProp(n, (const xmlChar *) "alt"))) { + s = squash_whitespace(s2); xmlFree(s2); + if (!s) + return false; + box->text = talloc_strdup(content, s); + free(s); if (!box->text) - return (struct box_result) {0, false, true}; + return false; box->length = strlen(box->text); } /* imagemap associated with this image */ - if ((map = xmlGetProp(n, (const xmlChar *) "usemap")) != NULL) { + if ((map = xmlGetProp(n, (const xmlChar *) "usemap"))) { if (map[0] == '#') - box->usemap = strdup(map + 1); + box->usemap = talloc_strdup(content, map + 1); else - box->usemap = strdup(map); + box->usemap = talloc_strdup(content, map); xmlFree(map); - if (!box->usemap) { - free(box->text); - return (struct box_result) {0, false, true}; - } + if (!box->usemap) + return false; } /* img without src is an error */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "src")) == NULL) - return (struct box_result) {box, false, false}; + if (!(s = (char *) xmlGetProp(n, (const xmlChar *) "src"))) + return true; /* remove leading and trailing whitespace */ s1 = strip(s); - res = url_join(s1, status->content->data.html.base_url, &url); + res = url_join(s1, content->data.html.base_url, &url); xmlFree(s); - if (res == URL_FUNC_NOMEM) { - free(box->text); - return (struct box_result) {0, false, true}; - } else if (res == URL_FUNC_FAILED) { - return (struct box_result) {box, false, false}; - } + if (res == URL_FUNC_NOMEM) + return false; + else if (res == URL_FUNC_FAILED) + return true; - if (strcmp(url, status->content->data.html.base_url) == 0) + if (strcmp(url, content->data.html.base_url) == 0) /* if url is equivalent to the parent's url, * we've got infinite inclusion: ignore */ - return (struct box_result) {box, false, false}; + return true; /* start fetch */ - if (!html_fetch_object(status->content, url, box, image_types, - status->content->available_width, 1000, false)) - return (struct box_result) {0, false, true}; + if (!html_fetch_object(content, url, box, image_types, + content->available_width, 1000, false)) { + free(url); + return false; + } + free(url); - return (struct box_result) {box, false, false}; + return true; } -struct box_result box_form(xmlNode *n, struct box_status *status, - struct css_style *style) + +/** + * Generic embedded object [13.3]. + */ + +bool box_object(BOX_SPECIAL_PARAMS) { - char *action, *method, *enctype; - form_method fmethod; - struct box *box; - struct form *form; + struct object_params *po; + struct plugin_params *pp = NULL; + char *s, *map; + xmlNode *c; - box = box_create(style, status->href, status->title, status->id, - status->content->data.html.box_pool); - if (!box) - return (struct box_result) {0, false, true}; + po = talloc(content, struct object_params); + if (!po) + return false; + po->data = 0; + po->type = 0; + po->codetype = 0; + po->codebase = 0; + po->classid = 0; + po->params = 0; + po->basehref = 0; - if (!(action = (char *) xmlGetProp(n, (const xmlChar *) "action"))) { - /* the action attribute is required */ - return (struct box_result) {box, true, false}; + /* object data */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "data"))) { + po->data = strdup(s); + xmlFree(s); + if (!po->data) + return false; } - fmethod = method_GET; - if ((method = (char *) xmlGetProp(n, (const xmlChar *) "method"))) { - if (strcasecmp(method, "post") == 0) { - fmethod = method_POST_URLENC; - if ((enctype = (char *) xmlGetProp(n, - (const xmlChar *) "enctype"))) { - if (strcasecmp(enctype, - "multipart/form-data") == 0) - fmethod = method_POST_MULTIPART; - xmlFree(enctype); - } - } - xmlFree(method); + /* imagemap associated with this object */ + if ((map = xmlGetProp(n, (const xmlChar *) "usemap"))) { + box->usemap = (map[0] == '#') ? talloc_strdup(content, map + 1) + : talloc_strdup(content, map); + xmlFree(map); + if (!box->usemap) + return false; } - status->current_form = form = form_new(action, fmethod); - if (!form) { - xmlFree(action); - return (struct box_result) {0, false, true}; + /* object type */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "type"))) { + po->type = talloc_strdup(content, s); + xmlFree(s); + if (!po->type) + return false; } - return (struct box_result) {box, true, false}; -} + /* object codetype */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "codetype"))) { + po->codetype = talloc_strdup(content, s); + xmlFree(s); + if (!po->codetype) + return false; + } -struct box_result box_textarea(xmlNode *n, struct box_status *status, - struct css_style *style) -{ - /* A textarea is an INLINE_BLOCK containing a single INLINE_CONTAINER, - * which contains the text as runs of INLINE separated by BR. There is - * at least one INLINE. The first and last boxes are INLINE. - * Consecutive BR may not be present. These constraints are satisfied - * by using a 0-length INLINE for blank lines. */ - - xmlChar *content, *current; - struct box *box, *inline_container, *inline_box, *br_box; - char *s; - size_t len; - - box = box_create(style, NULL, 0, status->id, - status->content->data.html.box_pool); - if (!box) - return (struct box_result) {0, false, true}; - box->type = BOX_INLINE_BLOCK; - box->gadget = form_new_control(GADGET_TEXTAREA); - if (!box->gadget) - return (struct box_result) {0, false, true}; - box->gadget->box = box; - - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "name")) != NULL) { - box->gadget->name = strdup(s); + /* object codebase */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "codebase"))) { + po->codebase = talloc_strdup(content, s); xmlFree(s); - if (!box->gadget->name) - return (struct box_result) {0, false, true}; + if (!po->codebase) + return false; } - inline_container = box_create(0, 0, 0, 0, - status->content->data.html.box_pool); - if (!inline_container) - return (struct box_result) {0, false, true}; - inline_container->type = BOX_INLINE_CONTAINER; - box_add_child(box, inline_container); - - current = content = xmlNodeGetContent(n); - while (1) { - /* BOX_INLINE */ - len = strcspn(current, "\r\n"); - s = strndup(current, len); - if (!s) { - box_free(box); - xmlFree(content); - return (struct box_result) {NULL, false, false}; - } + /* object classid */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "classid"))) { + po->classid = talloc_strdup(content, s); + xmlFree(s); + if (!po->classid) + return false; + } - inline_box = box_create(style, 0, 0, 0, - status->content->data.html.box_pool); - if (!inline_box) - return (struct box_result) {0, false, true}; - inline_box->type = BOX_INLINE; - inline_box->style_clone = 1; - inline_box->text = s; - inline_box->length = len; - box_add_child(inline_container, inline_box); + /* parameters + * parameter data is stored in a singly linked list. + * po->params points to the head of the list. + * new parameters are added to the head of the list. + */ + for (c = n->children; c; c = c->next) { + if (c->type != XML_ELEMENT_NODE) + continue; - current += len; - if (current[0] == 0) - /* finished */ + if (strcmp((const char *) c->name, "param") != 0) + /* The first non-param child is the start + * of the alt html. Therefore, we should + * break out of this loop. + */ break; - /* BOX_BR */ - br_box = box_create(style, 0, 0, 0, - status->content->data.html.box_pool); - if (!br_box) - return (struct box_result) {0, false, true}; - br_box->type = BOX_BR; - br_box->style_clone = 1; - box_add_child(inline_container, br_box); + pp = talloc(content, struct plugin_params); + if (!pp) + return false; + pp->name = 0; + pp->value = 0; + pp->type = 0; + pp->valuetype = 0; + pp->next = 0; + + if ((s = (char *) xmlGetProp(c, (const xmlChar *) "name"))) { + pp->name = talloc_strdup(content, s); + xmlFree(s); + if (!pp->name) + return false; + } + if ((s = (char *) xmlGetProp(c, (const xmlChar *) "value"))) { + pp->value = talloc_strdup(content, s); + xmlFree(s); + if (!pp->value) + return false; + } + if ((s = (char *) xmlGetProp(c, (const xmlChar *) "type"))) { + pp->type = talloc_strdup(content, s); + xmlFree(s); + if (!pp->type) + return false; + } + if ((s = (char *) xmlGetProp(c, + (const xmlChar *) "valuetype"))) { + pp->valuetype = talloc_strdup(content, s); + xmlFree(s); + if (!pp->valuetype) + return false; + } else { + pp->valuetype = talloc_strdup(content, "data"); + if (!pp->valuetype) + return false; + } - if (current[0] == '\r' && current[1] == '\n') - current += 2; - else - current++; + pp->next = po->params; + po->params = pp; } - xmlFree(content); - if (status->current_form) - form_add_control(status->current_form, box->gadget); + box->object_params = po; + + /* start fetch */ + if (plugin_decode(content, box)) + return false; - return (struct box_result) {box, false, false}; + return true; } -struct box_result box_select(xmlNode *n, struct box_status *status, + +#if 0 +/** + * "Java applet" [13.4]. + * + * \todo This needs reworking to be compliant to the spec + * For now, we simply ignore all applet tags. + */ + +struct box_result box_applet(xmlNode *n, struct box_status *status, struct css_style *style) { struct box *box; - struct box *inline_container; - struct box *inline_box; - struct form_control *gadget; - char* s; - xmlNode *c, *c2; + struct object_params *po; + struct plugin_params *pp = NULL; + char *s; + xmlNode *c; - gadget = form_new_control(GADGET_SELECT); - if (!gadget) + po = calloc(1, sizeof(struct object_params)); + if (!po) return (struct box_result) {0, false, true}; - gadget->data.select.multiple = false; - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "multiple")) != NULL) { - gadget->data.select.multiple = true; - xmlFree(s); + box = box_create(style, status->href, 0, status->id, + status->content->data.html.box_pool); + if (!box) { + free(po); + return (struct box_result) {0, false, true}; } - gadget->data.select.items = NULL; - gadget->data.select.last_item = NULL; - gadget->data.select.num_items = 0; - gadget->data.select.num_selected = 0; - - for (c = n->children; c; c = c->next) { - if (strcmp((const char *) c->name, "option") == 0) { - if (!box_select_add_option(gadget, c)) - goto no_memory; - } else if (strcmp((const char *) c->name, "optgroup") == 0) { - for (c2 = c->children; c2; c2 = c2->next) { - if (strcmp((const char *) c2->name, - "option") == 0) { - if (!box_select_add_option(gadget, c2)) - goto no_memory; - } - } - } + /* archive */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "archive")) != NULL) { + /** \todo tokenise this comma separated list */ + LOG(("archive '%s'", s)); + po->data = strdup(s); + xmlFree(s); + if (!po->data) + goto no_memory; } - - if (gadget->data.select.num_items == 0) { - /* no options: ignore entire select */ - form_free_control(gadget); - return (struct box_result) {0, false, false}; + /* code */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "code")) != NULL) { + LOG(("applet '%s'", s)); + po->classid = strdup(s); + xmlFree(s); + if (!po->classid) + goto no_memory; } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "name")) != NULL) { - gadget->name = strdup(s); + /* object codebase */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "codebase")) != NULL) { + po->codebase = strdup(s); + LOG(("codebase: %s", s)); xmlFree(s); - if (!gadget->name) + if (!po->codebase) goto no_memory; } - box = box_create(style, NULL, 0, status->id, - status->content->data.html.box_pool); - if (!box) - goto no_memory; - box->type = BOX_INLINE_BLOCK; - box->gadget = gadget; - gadget->box = box; + /* parameters + * parameter data is stored in a singly linked list. + * po->params points to the head of the list. + * new parameters are added to the head of the list. + */ + for (c = n->children; c != 0; c = c->next) { + if (c->type != XML_ELEMENT_NODE) + continue; - inline_container = box_create(0, 0, 0, 0, - status->content->data.html.box_pool); - if (!inline_container) - goto no_memory; - inline_container->type = BOX_INLINE_CONTAINER; - inline_box = box_create(style, 0, 0, 0, - status->content->data.html.box_pool); - if (!inline_box) - goto no_memory; - inline_box->type = BOX_INLINE; - inline_box->style_clone = 1; - box_add_child(inline_container, inline_box); - box_add_child(box, inline_container); + if (strcmp((const char *) c->name, "param") == 0) { + pp = calloc(1, sizeof(struct plugin_params)); + if (!pp) + goto no_memory; - if (!gadget->data.select.multiple && - gadget->data.select.num_selected == 0) { - gadget->data.select.current = gadget->data.select.items; - gadget->data.select.current->initial_selected = - gadget->data.select.current->selected = true; - gadget->data.select.num_selected = 1; - } + if ((s = (char *) xmlGetProp(c, (const xmlChar *) "name")) != NULL) { + pp->name = strdup(s); + xmlFree(s); + if (!pp->name) + goto no_memory; + } + if ((s = (char *) xmlGetProp(c, (const xmlChar *) "value")) != NULL) { + pp->value = strdup(s); + xmlFree(s); + if (!pp->value) + goto no_memory; + } + if ((s = (char *) xmlGetProp(c, (const xmlChar *) "type")) != NULL) { + pp->type = strdup(s); + xmlFree(s); + if (!pp->type) + goto no_memory; + } + if ((s = (char *) xmlGetProp(c, (const xmlChar *) "valuetype")) != NULL) { + pp->valuetype = strdup(s); + xmlFree(s); + if (!pp->valuetype) + goto no_memory; + } else { + pp->valuetype = strdup("data"); + if (!pp->valuetype) + goto no_memory; + } - if (gadget->data.select.num_selected == 0) - inline_box->text = strdup(messages_get("Form_None")); - else if (gadget->data.select.num_selected == 1) - inline_box->text = strdup(gadget->data.select.current->text); - else - inline_box->text = strdup(messages_get("Form_Many")); - if (!inline_box->text) - goto no_memory; + pp->next = po->params; + po->params = pp; + } else { + /* The first non-param child is the start + * of the alt html. Therefore, we should + * break out of this loop. + */ + break; + } + } - inline_box->length = strlen(inline_box->text); + box->object_params = po; - if (status->current_form) - form_add_control(status->current_form, gadget); + /* start fetch */ + if (plugin_decode(status->content, box)) + return (struct box_result) {box, false, false}; - return (struct box_result) {box, false, false}; + return (struct box_result) {box, true, false}; no_memory: - form_free_control(gadget); - return (struct box_result) {0, false, true}; -} - - -/** - * Add an option to a form select control. - * - * \param control select containing the option - * \param n xml element node for