diff options
author | James Bursa <james@netsurf-browser.org> | 2005-04-09 09:47:37 +0000 |
---|---|---|
committer | James Bursa <james@netsurf-browser.org> | 2005-04-09 09:47:37 +0000 |
commit | 2920bca14adbf145d64754b1ef8e6b888c7995ee (patch) | |
tree | db57b9169d89bf0bc79e06c1cde68db60adf2462 | |
parent | 8728712699ff8ff80bfce53308e073898c958c11 (diff) | |
download | netsurf-2920bca14adbf145d64754b1ef8e6b888c7995ee.tar.gz netsurf-2920bca14adbf145d64754b1ef8e6b888c7995ee.tar.bz2 |
[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
-rw-r--r-- | css/css.c | 34 | ||||
-rw-r--r-- | css/css.h | 11 | ||||
-rw-r--r-- | css/ruleset.c | 27 | ||||
-rw-r--r-- | desktop/browser.c | 40 | ||||
-rw-r--r-- | render/box.c | 59 | ||||
-rw-r--r-- | render/box.h | 9 | ||||
-rw-r--r-- | render/box_construct.c | 2288 | ||||
-rw-r--r-- | render/box_normalise.c | 53 | ||||
-rw-r--r-- | render/form.c | 1 | ||||
-rw-r--r-- | render/form.h | 1 | ||||
-rw-r--r-- | render/html.c | 86 | ||||
-rw-r--r-- | render/html.h | 10 | ||||
-rw-r--r-- | render/layout.c | 113 | ||||
-rw-r--r-- | render/layout.h | 8 | ||||
-rw-r--r-- | riscos/print.c | 10 | ||||
-rw-r--r-- | riscos/save_draw.c | 6 |
16 files changed, 1285 insertions, 1471 deletions
@@ -110,7 +110,6 @@ static void css_dump_selector(const struct css_selector *r); /** Default style for a document. These are the 'Initial values' from the * spec. */ const struct css_style css_base_style = { - { {CSS_CELLPADDING_VALUE, 1} }, CSS_BACKGROUND_ATTACHMENT_SCROLL, 0xffffff, { CSS_BACKGROUND_IMAGE_NONE, 0 }, @@ -167,10 +166,10 @@ const struct css_style css_base_style = { { CSS_BORDER_WIDTH_LENGTH, { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE }, CSS_OVERFLOW_VISIBLE, - { { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } }, false }, - { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } }, false }, - { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } }, false }, - { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } }, false }, }, + { { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } } }, CSS_PAGE_BREAK_AFTER_AUTO, CSS_PAGE_BREAK_BEFORE_AUTO, CSS_PAGE_BREAK_INSIDE_AUTO, @@ -196,7 +195,6 @@ const struct css_style css_base_style = { /** Style with no values set. */ const struct css_style css_empty_style = { - { { CSS_CELLPADDING_NOT_SET, 0 } }, CSS_BACKGROUND_ATTACHMENT_NOT_SET, CSS_COLOR_NOT_SET, { CSS_BACKGROUND_IMAGE_NOT_SET, 0 }, @@ -253,10 +251,10 @@ const struct css_style css_empty_style = { { CSS_BORDER_WIDTH_NOT_SET, { 0, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NOT_SET }, CSS_OVERFLOW_NOT_SET, - { { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } }, false }, - { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } }, false }, - { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } }, false }, - { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } }, false }, }, + { { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_NOT_SET, { { 0, CSS_UNIT_PX } } } }, CSS_PAGE_BREAK_AFTER_NOT_SET, CSS_PAGE_BREAK_BEFORE_NOT_SET, CSS_PAGE_BREAK_INSIDE_NOT_SET, @@ -283,7 +281,6 @@ const struct css_style css_empty_style = { /** Default style for an element. These should be INHERIT if 'Inherited' is yes, * and the 'Initial value' otherwise. */ const struct css_style css_blank_style = { - { { CSS_CELLPADDING_INHERIT, 0 } }, CSS_BACKGROUND_ATTACHMENT_SCROLL, TRANSPARENT, { CSS_BACKGROUND_IMAGE_NONE, 0 }, @@ -340,10 +337,10 @@ const struct css_style css_blank_style = { { CSS_BORDER_WIDTH_LENGTH, { 2, CSS_UNIT_PX } }, CSS_BORDER_STYLE_NONE }, CSS_OVERFLOW_VISIBLE, - { { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } }, false }, - { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } }, false }, - { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } }, false }, - { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } }, false }, }, + { { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } }, + { CSS_PADDING_LENGTH, { { 0, CSS_UNIT_PX } } } }, CSS_PAGE_BREAK_AFTER_AUTO, CSS_PAGE_BREAK_BEFORE_AUTO, CSS_PAGE_BREAK_INSIDE_INHERIT, @@ -2383,11 +2380,6 @@ void css_cascade(struct css_style * const style, unsigned int i; float f; - if (apply->html_style.cellpadding.type != - CSS_CELLPADDING_INHERIT && - apply->html_style.cellpadding.type != - CSS_CELLPADDING_NOT_SET) - style->html_style.cellpadding = apply->html_style.cellpadding; if (apply->background_attachment != CSS_BACKGROUND_ATTACHMENT_INHERIT && apply->background_attachment != @@ -2678,8 +2670,6 @@ void css_merge(struct css_style * const style, { unsigned int i; - if (apply->html_style.cellpadding.type != CSS_CELLPADDING_NOT_SET) - style->html_style.cellpadding = apply->html_style.cellpadding; if (apply->background_attachment != CSS_BACKGROUND_ATTACHMENT_NOT_SET) style->background_attachment = apply->background_attachment; if (apply->background_color != CSS_COLOR_NOT_SET) @@ -149,16 +149,6 @@ struct css_content { /** Representation of a complete CSS 2 style. */ struct css_style { - /* html styles that don't translate directly to CSS */ - struct { - struct { - enum { CSS_CELLPADDING_INHERIT, - CSS_CELLPADDING_VALUE, - CSS_CELLPADDING_NOT_SET } type; - int value; - } cellpadding; - } html_style; - /* background properties */ css_background_attachment background_attachment; colour background_color; @@ -378,7 +368,6 @@ struct css_style { struct css_length length; float percent; } value; - bool override_cellpadding; /* override HTML setting */ } padding[4]; /**< top, right, bottom, left */ css_page_break_after page_break_after; diff --git a/css/ruleset.c b/css/ruleset.c index 54d7ff87d..a5bb20f12 100644 --- a/css/ruleset.c +++ b/css/ruleset.c @@ -1153,7 +1153,7 @@ bool css_background_position_parse(const struct css_node **node, *node = w->next; return true; } - + /* reverse specifiers such that idents are places in h, v order */ if ((v->type == CSS_NODE_IDENT && bg && bg->vertical) || (w->type == CSS_NODE_IDENT && bg2 && bg2->horizontal)) { @@ -1651,7 +1651,7 @@ void parse_content(struct css_style * const s, const struct css_node * v) struct css_content *content; struct css_node *t; bool first = true; - + for (; v; v = v->next) { switch (v->type) { case CSS_NODE_STRING: @@ -1746,18 +1746,18 @@ void parse_content(struct css_style * const s, const struct css_node * v) } first = false; } - + if (new_content) { css_deep_free_content(s->content.content); s->content.type = CSS_CONTENT_INTERPRET; - s->content.content = new_content; + s->content.content = new_content; } } struct css_content *parse_content_new(struct css_content **current, css_content_type_generated generated) { struct css_content *content; struct css_content *link; - + content = (struct css_content *)calloc(1, sizeof(struct css_content)); if (!content) { css_deep_free_content(*current); @@ -1777,15 +1777,15 @@ struct css_content *parse_content_new(struct css_content **current, css_content_ bool parse_content_counter(struct css_content **current, struct css_node *t, bool counters) { struct css_content *content; css_list_style_type z; - + content = parse_content_new(current, CSS_CONTENT_COUNTER); if ((!content) || (t->type != CSS_NODE_IDENT)) return false; - + content->data.counter.name = strndup(t->data, t->data_length); content->data.counter.style = CSS_LIST_STYLE_TYPE_DECIMAL; t = t->next; - + if (counters) { if ((!t) || (t->type != CSS_NODE_STRING)) { css_deep_free_content(*current); @@ -1794,7 +1794,7 @@ bool parse_content_counter(struct css_content **current, struct css_node *t, boo content->data.counter.separator = strndup(t->data, t->data_length); t = t->next; } - + if (!t) return true; @@ -1818,7 +1818,7 @@ void parse_counter_reset(struct css_style * const s, const struct css_node * v) css_deep_free_counter_control(s->counter_reset.data); s->counter_reset.type = CSS_COUNTER_RESET_INTERPRET; s->counter_reset.data = counter; - } + } } void parse_counter_increment(struct css_style * const s, const struct css_node * v) { @@ -1836,7 +1836,7 @@ void parse_counter_increment(struct css_style * const s, const struct css_node * bool parse_counter_control_data(struct css_counter_control **current, const struct css_node * v, int empty) { struct css_counter_control *open = NULL; - + for (; v; v = v->next) { switch (v->type) { case CSS_NODE_IDENT: @@ -1869,7 +1869,7 @@ bool parse_counter_control_data(struct css_counter_control **current, const stru struct css_counter_control *parse_counter_control_new(struct css_counter_control **current) { struct css_counter_control *counter; struct css_counter_control *link; - + counter = (struct css_counter_control *)calloc(1, sizeof(struct css_counter_control)); if (!counter) { css_deep_free_counter_control(*current); @@ -2683,15 +2683,12 @@ void parse_padding_side(struct css_style * const s, const struct css_node * cons if (v->type == CSS_NODE_IDENT && v->data_length == 7 && strncasecmp(v->data, "inherit", 7) == 0) { s->padding[i].padding = CSS_PADDING_INHERIT; - s->padding[i].override_cellpadding = true; } else if (v->type == CSS_NODE_PERCENTAGE) { s->padding[i].padding = CSS_PADDING_PERCENT; s->padding[i].value.percent = atof(v->data); - s->padding[i].override_cellpadding = true; } else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) && parse_length(&s->padding[i].value.length, v, true) == 0) { s->padding[i].padding = CSS_PADDING_LENGTH; - s->padding[i].override_cellpadding = true; } } diff --git a/desktop/browser.c b/desktop/browser.c index b1c63ebf4..b04bb3558 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -37,6 +37,7 @@ #include "netsurf/render/layout.h" #include "netsurf/utils/log.h" #include "netsurf/utils/messages.h" +#include "netsurf/utils/talloc.h" #include "netsurf/utils/url.h" #include "netsurf/utils/utils.h" @@ -330,7 +331,7 @@ void browser_window_callback(content_msg msg, struct content *c, browser_window_stop_throbber(bw); history_update(bw->history, c); hotlist_visited(c); - free (bw->referer); + free(bw->referer); bw->referer = 0; break; @@ -388,7 +389,7 @@ void browser_window_callback(content_msg msg, struct content *c, bw->scrolling_box = NULL; } browser_window_stop_throbber(bw); - free (bw->referer); + free(bw->referer); bw->referer = 0; break; #endif @@ -1279,7 +1280,8 @@ void browser_window_textarea_callback(struct browser_window *bw, utf8[0] = key; utf8_len = 1; - text = realloc(text_box->text, text_box->length + 8); + text = talloc_realloc(bw->current_content, text_box->text, + char, text_box->length + 8); if (!text) { warn_user("NoMemory", 0); return; @@ -1299,16 +1301,16 @@ void browser_window_textarea_callback(struct browser_window *bw, } else if (key == 10 || key == 13) { /* paragraph break */ - text = malloc(text_box->length + 1); + text = talloc_array(bw->current_content, char, + text_box->length + 1); if (!text) { warn_user("NoMemory", 0); return; } - new_br = box_create(text_box->style, 0, 0, 0, - bw->current_content->data.html.box_pool); - new_text = pool_alloc(bw->current_content->data.html.box_pool, - sizeof (struct box)); + new_br = box_create(text_box->style, 0, text_box->title, 0, + bw->current_content); + new_text = talloc(bw->current_content, struct box); if (!new_text) { warn_user("NoMemory", 0); return; @@ -1353,7 +1355,8 @@ void browser_window_textarea_callback(struct browser_window *bw, /* delete space by merging with previous text box */ prev = text_box->prev; assert(prev->text); - text = realloc(prev->text, + text = talloc_realloc(bw->current_content, prev->text, + char, prev->length + text_box->length + 1); if (!text) { warn_user("NoMemory", 0); @@ -1469,7 +1472,7 @@ void browser_window_textarea_callback(struct browser_window *bw, height = textarea->height; if (!layout_inline_container(inline_container, width, textarea, 0, 0, - bw->current_content->data.html.box_pool)) + bw->current_content)) warn_user("NoMemory", 0); textarea->width = width; textarea->height = height; @@ -1627,7 +1630,8 @@ void browser_window_input_callback(struct browser_window *bw, return; utf8keySize = strlen(utf8key); - value = realloc(input->gadget->value, input->gadget->length + utf8keySize + 1); + value = realloc(input->gadget->value, + input->gadget->length + utf8keySize + 1); if (!value) { free(utf8key); warn_user("NoMemory", 0); @@ -1651,7 +1655,8 @@ void browser_window_input_callback(struct browser_window *bw, return; utf8keySize = strlen(utf8key); - value = realloc(text_box->text, text_box->length + utf8keySize + 1); + value = talloc_realloc(bw->current_content, text_box->text, + char, text_box->length + utf8keySize + 1); if (!value) { free(utf8key); warn_user("NoMemory", 0); @@ -1910,14 +1915,17 @@ void browser_window_form_select(struct browser_window *bw, control->data.select.current = o; } - free(inline_box->text); + talloc_free(inline_box->text); inline_box->text = 0; if (control->data.select.num_selected == 0) - inline_box->text = strdup(messages_get("Form_None")); + inline_box->text = talloc_strdup(bw->current_content, + messages_get("Form_None")); else if (control->data.select.num_selected == 1) - inline_box->text = strdup(control->data.select.current->text); + inline_box->text = talloc_strdup(bw->current_content, + control->data.select.current->text); else - inline_box->text = strdup(messages_get("Form_Many")); + inline_box->text = talloc_strdup(bw->current_content, + messages_get("Form_Many")); if (!inline_box->text) { warn_user("NoMemory", 0); inline_box->length = 0; 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 <limits.h> #include <stdbool.h> #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 <object> 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 <td> and <th> 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) { @@ -906,6 +825,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. * * \param s string to transform @@ -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; + } + + /* object codebase */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "codebase"))) { + po->codebase = talloc_strdup(content, s); + xmlFree(s); + if (!po->codebase) + return false; + } + + /* object classid */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "classid"))) { + po->classid = talloc_strdup(content, s); + xmlFree(s); + if (!po->classid) + return false; + } + + /* 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; + + 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; + + 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; + } + + pp->next = po->params; + po->params = pp; + } + + box->object_params = po; + + /* start fetch */ + if (plugin_decode(content, box)) + return false; + + return true; } -struct box_result box_textarea(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) { - /* 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; + struct box *box; + struct object_params *po; + struct plugin_params *pp = NULL; char *s; - size_t len; + xmlNode *c; - box = box_create(style, NULL, 0, status->id, - status->content->data.html.box_pool); - if (!box) + po = calloc(1, sizeof(struct object_params)); + if (!po) return (struct box_result) {0, false, true}; - box->type = BOX_INLINE_BLOCK; - box->gadget = form_new_control(GADGET_TEXTAREA); - if (!box->gadget) + + 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}; - box->gadget->box = box; + } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "name")) != NULL) { - box->gadget->name = strdup(s); + /* 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 (!box->gadget->name) - return (struct box_result) {0, false, true}; + if (!po->data) + goto no_memory; + } + /* 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; } - 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); + /* object codebase */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "codebase")) != NULL) { + po->codebase = strdup(s); + LOG(("codebase: %s", s)); + xmlFree(s); + if (!po->codebase) + goto no_memory; + } - 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}; + /* 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; + + if (strcmp((const char *) c->name, "param") == 0) { + pp = calloc(1, sizeof(struct plugin_params)); + if (!pp) + goto no_memory; + + 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; + } + + 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 = 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); + box->object_params = po; - current += len; - if (current[0] == 0) - /* finished */ - break; + /* start fetch */ + if (plugin_decode(status->content, box)) + return (struct box_result) {box, false, false}; - /* 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); + return (struct box_result) {box, true, false}; - if (current[0] == '\r' && current[1] == '\n') - current += 2; - else - current++; +no_memory: + if (pp && pp != po->params) { + /* ran out of memory creating parameter struct */ + free(pp->name); + free(pp->value); + free(pp->type); + free(pp->valuetype); + free(pp); } - xmlFree(content); - if (status->current_form) - form_add_control(status->current_form, box->gadget); + box_free_object_params(po); + box_free_box(box); - return (struct box_result) {box, false, false}; + return (struct box_result) {0, false, true}; } +#endif -struct box_result box_select(xmlNode *n, struct box_status *status, - struct css_style *style) + +/** + * Window subdivision [16.2.1]. + */ + +bool box_frameset(BOX_SPECIAL_PARAMS) { - struct box *box; - struct box *inline_container; - struct box *inline_box; - struct form_control *gadget; - char* s; - xmlNode *c, *c2; + unsigned int row, col; + unsigned int rows = 1, cols = 1; + int object_width, object_height; + char *s, *s1, *url; + struct box *row_box; + struct box *cell_box; + struct box *frameset_box; + struct box *object_box; + struct css_style *style = box->style; + struct css_style *row_style; + struct css_style *cell_style; + struct css_style *object_style; + struct box_multi_length *row_height = 0, *col_width = 0; + xmlNode *c; + url_func_result res; - gadget = form_new_control(GADGET_SELECT); - if (!gadget) - return (struct box_result) {0, false, true}; + box->type = BOX_TABLE; - gadget->data.select.multiple = false; - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "multiple")) != NULL) { - gadget->data.select.multiple = true; + /* parse rows and columns */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "rows"))) { + row_height = box_parse_multi_lengths(s, &rows, content); xmlFree(s); + if (!row_height) + return false; } - gadget->data.select.items = NULL; - gadget->data.select.last_item = NULL; - gadget->data.select.num_items = 0; - gadget->data.select.num_selected = 0; + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "cols"))) { + col_width = box_parse_multi_lengths(s, &cols, content); + xmlFree(s); + if (!col_width) + return false; + } - 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; - } + LOG(("rows %u, cols %u", rows, cols)); + + box->min_width = 1; + box->max_width = 10000; + box->col = talloc_array(content, struct column, cols); + if (!box->col) + return false; + + if (col_width) { + for (col = 0; col != cols; col++) { + if (col_width[col].type == LENGTH_PX) { + box->col[col].type = COLUMN_WIDTH_FIXED; + box->col[col].width = col_width[col].value; + } else if (col_width[col].type == LENGTH_PERCENT) { + box->col[col].type = COLUMN_WIDTH_PERCENT; + box->col[col].width = col_width[col].value; + } else { + box->col[col].type = COLUMN_WIDTH_RELATIVE; + box->col[col].width = col_width[col].value; } + box->col[col].min = 1; + box->col[col].max = 10000; } + } else { + box->col[0].type = COLUMN_WIDTH_RELATIVE; + box->col[0].width = 1; + box->col[0].min = 1; + box->col[0].max = 10000; } - if (gadget->data.select.num_items == 0) { - /* no options: ignore entire select */ - form_free_control(gadget); - return (struct box_result) {0, false, false}; - } + /* create the frameset table */ + c = n->children; + for (row = 0; c && row != rows; row++) { + row_style = talloc_memdup(content, style, sizeof *style); + if (!row_style) + return false; + object_height = 1000; /** \todo get available height */ + /* if (row_height) { + row_style->height.height = CSS_HEIGHT_LENGTH; + row_style->height.length.unit = CSS_UNIT_PX; + if (row_height[row].type == LENGTH_PERCENT) + row_style->height.length.value = 1000 * + row_height[row].value / 100; + else if (row_height[row].type == LENGTH_RELATIVE) + row_style->height.length.value = 100 * + row_height[row].value; + else + row_style->height.length.value = + row_height[row].value; + object_height = row_style->height.length.value; + }*/ + row_box = box_create(row_style, 0, 0, 0, content); + if (!row_box) + return false; - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "name")) != NULL) { - gadget->name = strdup(s); - xmlFree(s); - if (!gadget->name) - goto no_memory; - } + row_box->type = BOX_TABLE_ROW; + box_add_child(box, row_box); - 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; + for (col = 0; c && col != cols; col++) { + while (c && !(c->type == XML_ELEMENT_NODE && ( + strcmp((const char *) c->name, "frame") == 0 || + strcmp((const char *) c->name, "frameset") == 0 + ))) + c = c->next; + if (!c) + break; - 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); + /* estimate frame width */ + object_width = content->available_width; + if (col_width && col_width[col].type == LENGTH_PX) + object_width = col_width[col].value; - 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; - } + cell_style = talloc_memdup(content, style, + sizeof *style); + if (!cell_style) + return false; + css_cascade(cell_style, &css_blank_style); + cell_style->overflow = CSS_OVERFLOW_AUTO; - 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; + cell_box = box_create(cell_style, 0, 0, 0, content); + if (!cell_box) + return false; + cell_box->type = BOX_TABLE_CELL; + box_add_child(row_box, cell_box); - inline_box->length = strlen(inline_box->text); + if (strcmp((const char *) c->name, "frameset") == 0) { + LOG(("frameset")); + frameset_box = box_create(cell_style, 0, 0, 0, + content); + if (!frameset_box) + return false; + if (!box_frameset(n, content, frameset_box, 0)) + return false; + box_add_child(cell_box, frameset_box); - if (status->current_form) - form_add_control(status->current_form, gadget); + c = c->next; + continue; + } + + object_style = talloc_memdup(content, style, + sizeof *style); + if (!object_style) + return false; + if (col_width && col_width[col].type == LENGTH_PX) { + object_style->width.width = CSS_WIDTH_LENGTH; + object_style->width.value.length.unit = + CSS_UNIT_PX; + object_style->width.value.length.value = + object_width; + } - return (struct box_result) {box, false, false}; + object_box = box_create(object_style, 0, 0, 0, content); + if (!object_box) + return false; + object_box->type = BOX_BLOCK; + box_add_child(cell_box, object_box); -no_memory: - form_free_control(gadget); - return (struct box_result) {0, false, true}; + if (!(s = (char *) xmlGetProp(c, + (const xmlChar *) "src"))) { + c = c->next; + continue; + } + + s1 = strip(s); + res = url_join(s1, content->data.html.base_url, &url); + xmlFree(s); + /* if url is equivalent to the parent's url, + * we've got infinite inclusion. stop it here. + * also bail if url_join failed. + */ + if (res != URL_FUNC_OK || strcasecmp(url, + content->data.html.base_url) == 0) { + LOG(("url_join failed")); + c = c->next; + continue; + } + + LOG(("frame, url '%s'", url)); + + if (!html_fetch_object(content, url, + object_box, 0, + object_width, object_height, false)) + return false; + free(url); + + c = c->next; + } + } + + talloc_free(row_height); + talloc_free(col_width); + + style->width.width = CSS_WIDTH_PERCENT; + style->width.value.percent = 100; + + if (convert_children) + *convert_children = false; + return true; } /** - * Add an option to a form select control. - * - * \param control select containing the option - * \param n xml element node for <option> - * \return true on success, false on memory exhaustion + * Inline subwindow [16.5]. */ -bool box_select_add_option(struct form_control *control, xmlNode *n) +bool box_iframe(BOX_SPECIAL_PARAMS) { - char *value = 0; - char *text = 0; - bool selected; - xmlChar *content; - xmlChar *s; + struct object_params *po; + char *s; - content = xmlNodeGetContent(n); - if (!content) - goto no_memory; - text = squash_whitespace(content); - xmlFree(content); - if (!text) - goto no_memory; + po = talloc(content, struct object_params); + if (!po) + return false; - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) { - value = strdup(s); + /* iframe src */ + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "src"))) { + po->data = talloc_strdup(content, s); xmlFree(s); - } else - value = strdup(text); - if (!value) - goto no_memory; + if (!po->data) + return false; + } - selected = xmlHasProp(n, (const xmlChar *) "selected"); + box->object_params = po; - if (!form_add_option(control, value, text, selected)) - goto no_memory; + /* start fetch */ + plugin_decode(content, box); return true; +} -no_memory: - free(value); - free(text); - return false; + +/** + * Interactive form [17.3]. + */ + +bool box_form(BOX_SPECIAL_PARAMS) +{ + char *action, *method, *enctype; + form_method fmethod; + struct form *form; + + if (!(action = (char *) xmlGetProp(n, (const xmlChar *) "action"))) + /* the action attribute is required */ + return true; + + 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); + } + + form = form_new(action, fmethod); + if (!form) { + xmlFree(action); + return false; + } + form->prev = content->data.html.forms; + content->data.html.forms = form; + + return true; } -struct box_result box_input(xmlNode *n, struct box_status *status, - struct css_style *style) +/** + * Form control [17.4]. + */ + +bool box_input(BOX_SPECIAL_PARAMS) { - struct box* box = NULL; struct form_control *gadget = NULL; char *s, *type, *url; url_func_result res; @@ -1377,17 +1591,12 @@ struct box_result box_input(xmlNode *n, struct box_status *status, type = (char *) xmlGetProp(n, (const xmlChar *) "type"); if (type && strcasecmp(type, "password") == 0) { - box = box_input_text(n, status, style, true); - if (!box) + if (!box_input_text(n, content, box, 0, true)) goto no_memory; gadget = box->gadget; gadget->box = box; } else if (type && strcasecmp(type, "file") == 0) { - 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 = form_new_control(GADGET_FILE); if (!gadget) @@ -1410,10 +1619,6 @@ struct box_result box_input(xmlNode *n, struct box_status *status, } else if (type && (strcasecmp(type, "checkbox") == 0 || strcasecmp(type, "radio") == 0)) { - box = box_create(style, NULL, 0, status->id, - status->content->data.html.box_pool); - if (!box) - goto no_memory; box->gadget = gadget = form_new_control(type[0] == 'c' || type[0] == 'C' ? GADGET_CHECKBOX : GADGET_RADIO); @@ -1423,7 +1628,7 @@ struct box_result box_input(xmlNode *n, struct box_status *status, gadget->selected = xmlHasProp(n, (const xmlChar *) "checked"); - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) { gadget->value = strdup(s); xmlFree(s); if (!gadget->value) @@ -1433,28 +1638,27 @@ struct box_result box_input(xmlNode *n, struct box_status *status, } else if (type && (strcasecmp(type, "submit") == 0 || strcasecmp(type, "reset") == 0)) { - struct box_result result = box_button(n, status, style); struct box *inline_container, *inline_box; - if (result.memory_error) + if (!box_button(n, content, box, 0)) goto no_memory; - box = result.box; - inline_container = box_create(0, 0, 0, 0, - status->content->data.html.box_pool); + inline_container = box_create(0, 0, 0, 0, content); 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); + inline_box = box_create(box->style, 0, box->title, 0, content); if (!inline_box) goto no_memory; inline_box->type = BOX_INLINE; inline_box->style_clone = 1; if (box->gadget->value != NULL) - inline_box->text = strdup(box->gadget->value); + inline_box->text = talloc_strdup(content, + box->gadget->value); else if (box->gadget->type == GADGET_SUBMIT) - inline_box->text = strdup(messages_get("Form_Submit")); + inline_box->text = talloc_strdup(content, + messages_get("Form_Submit")); else - inline_box->text = strdup(messages_get("Form_Reset")); + inline_box->text = talloc_strdup(content, + messages_get("Form_Reset")); if (!inline_box->text) goto no_memory; inline_box->length = strlen(inline_box->text); @@ -1462,26 +1666,22 @@ struct box_result box_input(xmlNode *n, struct box_status *status, box_add_child(box, inline_container); } else if (type && strcasecmp(type, "button") == 0) { - struct box_result result = box_button(n, status, style); struct box *inline_container, *inline_box; - if (result.memory_error) + if (!box_button(n, content, box, 0)) goto no_memory; - box = result.box; - inline_container = box_create(0, 0, 0, 0, - status->content->data.html.box_pool); + inline_container = box_create(0, 0, 0, 0, content); 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); + inline_box = box_create(box->style, 0, box->title, 0, content); if (!inline_box) goto no_memory; inline_box->type = BOX_INLINE; inline_box->style_clone = 1; if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) - inline_box->text = strdup(s); + inline_box->text = talloc_strdup(content, s); else - inline_box->text = strdup("Button"); + inline_box->text = talloc_strdup(content, "Button"); if (!inline_box->text) goto no_memory; inline_box->length = strlen(inline_box->text); @@ -1489,48 +1689,46 @@ struct box_result box_input(xmlNode *n, struct box_status *status, box_add_child(box, inline_container); } else if (type && strcasecmp(type, "image") == 0) { - box = box_create(style, NULL, 0, status->id, - status->content->data.html.box_pool); - if (!box) - goto no_memory; box->gadget = gadget = form_new_control(GADGET_IMAGE); if (!gadget) goto no_memory; gadget->box = box; gadget->type = GADGET_IMAGE; - if ((s = (char *) xmlGetProp(n, (const xmlChar*) "src")) != NULL) { - res = url_join(s, status->content->data.html.base_url, &url); + if ((s = (char *) xmlGetProp(n, (const xmlChar*) "src"))) { + res = url_join(s, content->data.html.base_url, &url); + xmlFree(s); /* if url is equivalent to the parent's url, * we've got infinite inclusion. stop it here. * also bail if url_join failed. */ if (res == URL_FUNC_OK && - strcasecmp(url, status->content->data.html.base_url) != 0) - if (!html_fetch_object(status->content, url, box, - image_types, - status->content->available_width, - 1000, false)) + strcasecmp(url, content->data. + html.base_url) != 0) { + if (!html_fetch_object(content, url, + box, image_types, + content->available_width, + 1000, false)) { + free(url); goto no_memory; - xmlFree(s); + } + } + free(url); } } else { /* the default type is "text" */ - box = box_input_text(n, status, style, false); - if (!box) + if (!box_input_text(n, content, box, 0, false)) goto no_memory; gadget = box->gadget; gadget->box = box; } - if (type != 0) + if (type) xmlFree(type); - if (gadget != 0) { - if (status->current_form) - form_add_control(status->current_form, gadget); - else - gadget->form = 0; + if (gadget) { + if (content->data.html.forms) + form_add_control(content->data.html.forms, gadget); s = (char *) xmlGetProp(n, (const xmlChar *) "name"); if (s) { gadget->name = strdup(s); @@ -1540,7 +1738,8 @@ struct box_result box_input(xmlNode *n, struct box_status *status, } } - return (struct box_result) {box, false, false}; + *convert_children = false; + return true; no_memory: if (type) @@ -1548,36 +1747,36 @@ no_memory: if (gadget) form_free_control(gadget); - return (struct box_result) {0, false, true}; + return false; } -struct box *box_input_text(xmlNode *n, struct box_status *status, - struct css_style *style, bool password) + +/** + * Helper function for box_input(). + */ + +bool box_input_text(BOX_SPECIAL_PARAMS, bool password) { char *s; - struct box *box = box_create(style, 0, 0, status->id, - status->content->data.html.box_pool); struct box *inline_container, *inline_box; - if (!box) - return 0; - box->type = BOX_INLINE_BLOCK; - - box->gadget = form_new_control((password) ? GADGET_PASSWORD : GADGET_TEXTBOX); + box->gadget = form_new_control((password) ? GADGET_PASSWORD : + GADGET_TEXTBOX); if (!box->gadget) return 0; box->gadget->box = box; box->gadget->maxlength = 100; - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "maxlength")) != NULL) { + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "maxlength"))) { box->gadget->maxlength = atoi(s); xmlFree(s); } s = (char *) xmlGetProp(n, (const xmlChar *) "value"); box->gadget->value = strdup((s != NULL) ? s : ""); - box->gadget->initial_value = strdup((box->gadget->value != NULL) ? box->gadget->value : ""); + box->gadget->initial_value = strdup((box->gadget->value != NULL) ? + box->gadget->value : ""); if (s) xmlFree(s); if (box->gadget->value == NULL || box->gadget->initial_value == NULL) { @@ -1586,27 +1785,31 @@ struct box *box_input_text(xmlNode *n, struct box_status *status, } box->gadget->length = strlen(box->gadget->value); - inline_container = box_create(0, 0, 0, 0, - status->content->data.html.box_pool); + inline_container = box_create(0, 0, 0, 0, content); if (!inline_container) return 0; inline_container->type = BOX_INLINE_CONTAINER; - inline_box = box_create(style, 0, 0, 0, - status->content->data.html.box_pool); + inline_box = box_create(box->style, 0, box->title, 0, content); if (!inline_box) return 0; inline_box->type = BOX_INLINE; inline_box->style_clone = 1; if (password) { inline_box->length = strlen(box->gadget->value); - inline_box->text = malloc(inline_box->length + 1); + inline_box->text = talloc_array(content, char, + inline_box->length + 1); if (!inline_box->text) return 0; memset(inline_box->text, '*', inline_box->length); inline_box->text[inline_box->length] = '\0'; } else { - /* replace spaces/TABs with hard spaces to prevent line wrapping */ - inline_box->text = cnv_space2nbsp(box->gadget->value); + /* replace spaces/TABs with hard spaces to prevent line + * wrapping */ + char *text = cnv_space2nbsp(box->gadget->value); + if (!text) + return 0; + inline_box->text = talloc_strdup(content, text); + free(text); if (!inline_box->text) return 0; inline_box->length = strlen(inline_box->text); @@ -1617,15 +1820,16 @@ struct box *box_input_text(xmlNode *n, struct box_status *status, return box; } -struct box_result box_button(xmlNode *n, struct box_status *status, - struct css_style *style) + +/** + * Push button [17.5]. + */ + +bool box_button(BOX_SPECIAL_PARAMS) { xmlChar *s; char *type = (char *) xmlGetProp(n, (const xmlChar *) "type"); - struct box *box = box_create(style, 0, 0, status->id, - status->content->data.html.box_pool); - if (!box) - return (struct box_result) {0, false, true}; + box->type = BOX_INLINE_BLOCK; if (!type || strcasecmp(type, "submit") == 0) { @@ -1635,450 +1839,340 @@ struct box_result box_button(xmlNode *n, struct box_status *status, } else { /* type="button" or unknown: just render the contents */ xmlFree(type); - return (struct box_result) {box, true, false}; + return true; } if (type) xmlFree(type); - if (!box->gadget) { - box_free_box(box); - return (struct box_result) {0, false, true}; - } + if (!box->gadget) + return false; - if (status->current_form) - form_add_control(status->current_form, box->gadget); - else - box->gadget->form = 0; + if (content->data.html.forms) + form_add_control(content->data.html.forms, box->gadget); box->gadget->box = box; if ((s = xmlGetProp(n, (const xmlChar *) "name")) != NULL) { box->gadget->name = strdup((char *) s); xmlFree(s); - if (!box->gadget->name) { - box_free_box(box); - return (struct box_result) {0, false, true}; - } + if (!box->gadget->name) + return false; } if ((s = xmlGetProp(n, (const xmlChar *) "value")) != NULL) { box->gadget->value = strdup((char *) s); xmlFree(s); - if (!box->gadget->value) { - box_free_box(box); - return (struct box_result) {0, false, true}; - } + if (!box->gadget->value) + return false; } - return (struct box_result) {box, true, false}; + return true; } /** - * add an object to the box tree + * Option selector [17.6]. */ -struct box_result box_object(xmlNode *n, struct box_status *status, - struct css_style *style) -{ - struct box *box; - struct object_params *po; - struct plugin_params *pp = NULL; - char *s, *map; - xmlNode *c; - po = calloc(1, sizeof(struct object_params)); - if (!po) - return (struct box_result) {0, false, true}; +bool box_select(BOX_SPECIAL_PARAMS) +{ + struct box *inline_container; + struct box *inline_box; + struct form_control *gadget; + char* s; + xmlNode *c, *c2; - 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 = form_new_control(GADGET_SELECT); + if (!gadget) + return false; - /* object data */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "data")) != NULL) { - po->data = strdup(s); + gadget->data.select.multiple = false; + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "multiple"))) { + gadget->data.select.multiple = true; xmlFree(s); - if (!po->data) - goto no_memory; - LOG(("object '%s'", po->data)); } - /* imagemap associated with this object */ - if ((map = xmlGetProp(n, (const xmlChar *) "usemap")) != NULL) { - box->usemap = (map[0] == '#') ? strdup(map+1) : strdup(map); - xmlFree(map); - if (!box->usemap) - goto no_memory; - } - - /* object type */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "type")) != NULL) { - po->type = strdup(s); - xmlFree(s); - if (!po->type) - goto no_memory; - LOG(("type: %s", po->type)); - } + gadget->data.select.items = NULL; + gadget->data.select.last_item = NULL; + gadget->data.select.num_items = 0; + gadget->data.select.num_selected = 0; - /* object codetype */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "codetype")) != NULL) { - po->codetype = strdup(s); - xmlFree(s); - if (!po->codetype) - goto no_memory; - LOG(("codetype: %s", po->codetype)); + 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; + } + } + } } - /* object codebase */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "codebase")) != NULL) { - po->codebase = strdup(s); - xmlFree(s); - if (!po->codebase) - goto no_memory; - LOG(("codebase: %s", po->codebase)); + if (gadget->data.select.num_items == 0) { + /* no options: ignore entire select */ + form_free_control(gadget); + return true; } - /* object classid */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "classid")) != NULL) { - po->classid = strdup(s); + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "name"))) { + gadget->name = strdup(s); xmlFree(s); - if (!po->classid) + if (!gadget->name) goto no_memory; - LOG(("classid: %s", po->classid)); } - /* 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 != NULL; c = c->next) { - if (c->type != XML_ELEMENT_NODE) - continue; - - if (strcmp((const char *) c->name, "param") == 0) { - pp = calloc(1, sizeof(struct plugin_params)); - if (!pp) - goto no_memory; + box->type = BOX_INLINE_BLOCK; + box->gadget = gadget; + gadget->box = box; - 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; - } + inline_container = box_create(0, 0, 0, 0, content); + if (!inline_container) + goto no_memory; + inline_container->type = BOX_INLINE_CONTAINER; + inline_box = box_create(box->style, 0, box->title, 0, content); + 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); - 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; - } + 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; } - box->object_params = po; - - /* start fetch */ - if (plugin_decode(status->content, box)) - return (struct box_result) {box, false, false}; + if (gadget->data.select.num_selected == 0) + inline_box->text = messages_get("Form_None"); + else if (gadget->data.select.num_selected == 1) + inline_box->text = talloc_strdup(content, + gadget->data.select.current->text); + else + inline_box->text = messages_get("Form_Many"); + if (!inline_box->text) + goto no_memory; - return (struct box_result) {box, true, false}; + inline_box->length = strlen(inline_box->text); -no_memory: - if (pp && pp != po->params) { - /* ran out of memory creating parameter struct */ - free(pp->name); - free(pp->value); - free(pp->type); - free(pp->valuetype); - free(pp); - } + if (content->data.html.forms) + form_add_control(content->data.html.forms, box->gadget); - box_free_object_params(po); - box_free_box(box); + *convert_children = false; + return true; - return (struct box_result) {0, false, true}; +no_memory: + form_free_control(gadget); + return false; } + /** - * add an embed to the box tree + * Add an option to a form select control (helper function for box_select()). + * + * \param control select containing the option + * \param n xml element node for <option> + * \return true on success, false on memory exhaustion */ -struct box_result box_embed(xmlNode *n, struct box_status *status, - struct css_style *style) -{ - struct box *box; - struct object_params *po; - struct plugin_params *pp = NULL; - char *s; - xmlAttr *a; - po = calloc(1, sizeof(struct object_params)); - if (!po) - return (struct box_result) {0, false, true}; +bool box_select_add_option(struct form_control *control, xmlNode *n) +{ + char *value = 0; + char *text = 0; + bool selected; + xmlChar *content; + xmlChar *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}; - } + content = xmlNodeGetContent(n); + if (!content) + goto no_memory; + text = squash_whitespace(content); + xmlFree(content); + if (!text) + goto no_memory; - /* embed src */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "src")) != NULL) { - LOG(("embed '%s'", s)); - po->data = strdup(s); + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) { + value = strdup(s); xmlFree(s); - if (!po->data) - goto no_memory; - } - - /** - * we munge all other attributes into a plugin_parameter structure - */ - for (a=n->properties; a != NULL; a=a->next) { - pp = calloc(1, sizeof(struct plugin_params)); - if (!pp) - goto no_memory; - - if (strcasecmp((const char*)a->name, "src") != 0 && - a->children && a->children->content) { - pp->name = strdup((const char*)a->name); - pp->value = strdup((char*)a->children->content); - pp->valuetype = strdup("data"); - if (!pp->name || !pp->value || !pp->valuetype) - goto no_memory; - - pp->next = po->params; - po->params = pp; - } - } + } else + value = strdup(text); + if (!value) + goto no_memory; - box->object_params = po; + selected = xmlHasProp(n, (const xmlChar *) "selected"); - /* start fetch */ - /* embeds have no content, so we don't care if this returns false */ - plugin_decode(status->content, box); + if (!form_add_option(control, value, text, selected)) + goto no_memory; - return (struct box_result) {box, false, false}; + return true; no_memory: - if (pp && pp != po->params) { - /* ran out of memory creating parameter struct */ - free(pp->name); - free(pp->value); - free(pp->type); - free(pp->valuetype); - free(pp); - } - - box_free_object_params(po); - box_free_box(box); - - return (struct box_result) {0, false, true}; + free(value); + free(text); + return false; } + /** - * add an applet to the box tree - * - * \todo This needs reworking to be compliant to the spec - * For now, we simply ignore all applet tags. + * Multi-line text field [17.7]. */ -struct box_result box_applet(xmlNode *n, struct box_status *status, - struct css_style *style) -{ - struct box *box; - struct object_params *po; - struct plugin_params *pp = NULL; - char *s; - xmlNode *c; - po = calloc(1, sizeof(struct object_params)); - if (!po) - return (struct box_result) {0, false, true}; +bool box_textarea(BOX_SPECIAL_PARAMS) +{ + /* 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. */ - 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}; - } + xmlChar *text, *current; + struct box *inline_container, *inline_box, *br_box; + char *s; + size_t len; - /* 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; - } - /* 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; - } + box->type = BOX_INLINE_BLOCK; + box->gadget = form_new_control(GADGET_TEXTAREA); + if (!box->gadget) + return false; + box->gadget->box = box; - /* object codebase */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "codebase")) != NULL) { - po->codebase = strdup(s); - LOG(("codebase: %s", s)); + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "name"))) { + box->gadget->name = strdup(s); xmlFree(s); - if (!po->codebase) - goto no_memory; + if (!box->gadget->name) + return false; } - /* 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; - - if (strcmp((const char *) c->name, "param") == 0) { - pp = calloc(1, sizeof(struct plugin_params)); - if (!pp) - goto no_memory; - - 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; - } + inline_container = box_create(0, 0, box->title, 0, content); + if (!inline_container) + return false; + inline_container->type = BOX_INLINE_CONTAINER; + box_add_child(box, inline_container); - 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; + current = text = xmlNodeGetContent(n); + while (1) { + /* BOX_INLINE */ + len = strcspn(current, "\r\n"); + s = talloc_strndup(content, current, len); + if (!s) { + xmlFree(content); + return false; } - } - box->object_params = po; + inline_box = box_create(box->style, 0, box->title, 0, content); + if (!inline_box) + return false; + 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); - /* start fetch */ - if (plugin_decode(status->content, box)) - return (struct box_result) {box, false, false}; + current += len; + if (current[0] == 0) + /* finished */ + break; - return (struct box_result) {box, true, false}; + /* BOX_BR */ + br_box = box_create(box->style, 0, box->title, 0, content); + if (!br_box) + return false; + br_box->type = BOX_BR; + br_box->style_clone = 1; + box_add_child(inline_container, br_box); -no_memory: - if (pp && pp != po->params) { - /* ran out of memory creating parameter struct */ - free(pp->name); - free(pp->value); - free(pp->type); - free(pp->valuetype); - free(pp); + if (current[0] == '\r' && current[1] == '\n') + current += 2; + else + current++; } + xmlFree(text); - box_free_object_params(po); - box_free_box(box); + if (content->data.html.forms) + form_add_control(content->data.html.forms, box->gadget); - return (struct box_result) {0, false, true}; + *convert_children = false; + return true; } + /** - * box_iframe - * add an iframe to the box tree - * TODO - implement GUI nested wimp stuff 'cos this looks naff atm. (16_5) + * Embedded object (not in any HTML specification: + * see http://wp.netscape.com/assist/net_sites/new_html3_prop.html ) */ -struct box_result box_iframe(xmlNode *n, struct box_status *status, - struct css_style *style) + +bool box_embed(BOX_SPECIAL_PARAMS) { - struct box *box; struct object_params *po; + struct plugin_params *pp = NULL; char *s; + xmlAttr *a; - po = calloc(1, sizeof(struct object_params)); + po = talloc(content, struct object_params); if (!po) - return (struct box_result) {0, false, true}; - - 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}; - } + return false; + po->data = 0; + po->type = 0; + po->codetype = 0; + po->codebase = 0; + po->classid = 0; + po->params = 0; + po->basehref = 0; - /* iframe src */ + /* embed src */ if ((s = (char *) xmlGetProp(n, (const xmlChar *) "src")) != NULL) { - LOG(("iframe '%s'", s)); - po->data = strdup(s); + LOG(("embed '%s'", s)); + po->data = talloc_strdup(content, s); xmlFree(s); if (!po->data) - goto no_memory; + return false; } + /** + * we munge all other attributes into a plugin_parameter structure + */ + for (a = n->properties; a; a = a->next) { + 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 (strcasecmp((const char *) a->name, "src") != 0 && + a->children && a->children->content) { + pp->name = talloc_strdup(content, + (const char *) a->name); + pp->value = talloc_strdup(content, + (char *) a->children->content); + pp->valuetype = talloc_strdup(content, "data"); + if (!pp->name || !pp->value || !pp->valuetype) + return false; + + pp->next = po->params; + po->params = pp; + } + } + box->object_params = po; /* start fetch */ - plugin_decode(status->content, box); + /* embeds have no content, so we don't care if this returns false */ + plugin_decode(content, box); - return (struct box_result) {box, false, false}; + return true; +} -no_memory: - box_free_object_params(po); - box_free_box(box); +/** + * \} + */ - return (struct box_result) {0, false, true}; -} /** * plugin_decode @@ -2202,8 +2296,7 @@ bool plugin_decode(struct content *content, struct box *box) */ if (!html_fetch_object(content, url, box, 0, 1000, 1000, false)) goto no_handler; - - /* do _not_ free url here - html_fetch_object doesn't copy it */ + free(url); return true; @@ -2213,237 +2306,17 @@ no_handler: } -struct box_result box_frameset(xmlNode *n, struct box_status *status, - struct css_style *style) -{ - unsigned int row, col; - unsigned int rows = 1, cols = 1; - int object_width, object_height; - char *s, *s1, *url; - struct box *box; - struct box *row_box; - struct box *cell_box; - struct box *object_box; - struct css_style *row_style; - struct css_style *cell_style; - struct css_style *object_style; - struct box_result r; - struct box_multi_length *row_height = 0, *col_width = 0; - xmlNode *c; - url_func_result res; - - box = box_create(style, 0, status->title, status->id, - status->content->data.html.box_pool); - if (!box) - return (struct box_result) {0, false, true}; - box->type = BOX_TABLE; - - /* parse rows and columns */ - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "rows")) != NULL) { - row_height = box_parse_multi_lengths(s, &rows); - xmlFree(s); - if (!row_height) { - box_free_box(box); - return (struct box_result) {0, false, true}; - } - } - - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "cols")) != NULL) { - col_width = box_parse_multi_lengths(s, &cols); - xmlFree(s); - if (!col_width) { - free(row_height); - box_free_box(box); - return (struct box_result) {0, false, true}; - } - } - - LOG(("rows %u, cols %u", rows, cols)); - - box->min_width = 1; - box->max_width = 10000; - box->col = malloc(sizeof box->col[0] * cols); - if (!box->col) { - free(row_height); - free(col_width); - box_free_box(box); - return (struct box_result) {0, false, true}; - } - - if (col_width) { - for (col = 0; col != cols; col++) { - if (col_width[col].type == LENGTH_PX) { - box->col[col].type = COLUMN_WIDTH_FIXED; - box->col[col].width = col_width[col].value; - } else if (col_width[col].type == LENGTH_PERCENT) { - box->col[col].type = COLUMN_WIDTH_PERCENT; - box->col[col].width = col_width[col].value; - } else { - box->col[col].type = COLUMN_WIDTH_RELATIVE; - box->col[col].width = col_width[col].value; - } - box->col[col].min = 1; - box->col[col].max = 10000; - } - } else { - box->col[0].type = COLUMN_WIDTH_RELATIVE; - box->col[0].width = 1; - box->col[0].min = 1; - box->col[0].max = 10000; - } - - /* create the frameset table */ - c = n->children; - for (row = 0; c && row != rows; row++) { - row_style = css_duplicate_style(style); - if (!row_style) { - box_free(box); - free(row_height); - free(col_width); - return (struct box_result) {0, false, true}; - } - object_height = 1000; /** \todo get available height */ - /* if (row_height) { - row_style->height.height = CSS_HEIGHT_LENGTH; - row_style->height.length.unit = CSS_UNIT_PX; - if (row_height[row].type == LENGTH_PERCENT) - row_style->height.length.value = 1000 * - row_height[row].value / 100; - else if (row_height[row].type == LENGTH_RELATIVE) - row_style->height.length.value = 100 * - row_height[row].value; - else - row_style->height.length.value = - row_height[row].value; - object_height = row_style->height.length.value; - }*/ - row_box = box_create(row_style, 0, 0, 0, - status->content->data.html.box_pool); - if (!row_box) - return (struct box_result) {0, false, true}; - - row_box->type = BOX_TABLE_ROW; - box_add_child(box, row_box); - - for (col = 0; c && col != cols; col++) { - while (c && !(c->type == XML_ELEMENT_NODE && ( - strcmp((const char *) c->name, "frame") == 0 || - strcmp((const char *) c->name, "frameset") == 0 - ))) - c = c->next; - if (!c) - break; - - /* estimate frame width */ - object_width = status->content->available_width; - if (col_width && col_width[col].type == LENGTH_PX) - object_width = col_width[col].value; - - cell_style = css_duplicate_style(style); - if (!cell_style) { - box_free(box); - free(row_height); - free(col_width); - return (struct box_result) {0, false, true}; - } - css_cascade(cell_style, &css_blank_style); - cell_style->overflow = CSS_OVERFLOW_AUTO; - - cell_box = box_create(cell_style, 0, 0, 0, - status->content->data.html.box_pool); - if (!cell_box) - return (struct box_result) {0, false, true}; - cell_box->type = BOX_TABLE_CELL; - box_add_child(row_box, cell_box); - - if (strcmp((const char *) c->name, "frameset") == 0) { - LOG(("frameset")); - r = box_frameset(c, status, style); - if (r.memory_error) { - box_free(box); - free(row_height); - free(col_width); - return (struct box_result) {0, false, - true}; - } - r.box->style_clone = 1; - box_add_child(cell_box, r.box); - - c = c->next; - continue; - } - - object_style = css_duplicate_style(style); - if (!object_style) { - box_free(box); - free(row_height); - free(col_width); - return (struct box_result) {0, false, true}; - } - if (col_width && col_width[col].type == LENGTH_PX) { - object_style->width.width = CSS_WIDTH_LENGTH; - object_style->width.value.length.unit = - CSS_UNIT_PX; - object_style->width.value.length.value = - object_width; - } - - object_box = box_create(object_style, 0, 0, 0, - status->content->data.html.box_pool); - if (!object_box) - return (struct box_result) {0, false, true}; - object_box->type = BOX_BLOCK; - box_add_child(cell_box, object_box); - - if ((s = (char *) xmlGetProp(c, (const xmlChar *) "src")) == NULL) { - c = c->next; - continue; - } - - s1 = strip(s); - res = url_join(s1, status->content->data.html.base_url, &url); - /* if url is equivalent to the parent's url, - * we've got infinite inclusion. stop it here. - * also bail if url_join failed. - */ - if (res != URL_FUNC_OK || strcasecmp(url, status->content->data.html.base_url) == 0) { - xmlFree(s); - c = c->next; - continue; - } - - LOG(("frame, url '%s'", url)); - - if (!html_fetch_object(status->content, url, - object_box, 0, - object_width, object_height, false)) - return (struct box_result) {0, false, true}; - xmlFree(s); - - c = c->next; - } - } - - free(row_height); - free(col_width); - - style->width.width = CSS_WIDTH_PERCENT; - style->width.value.percent = 100; - - return (struct box_result) {box, false, false}; -} - - /** * Parse a multi-length-list, as defined by HTML 4.01. * - * \param s string to parse - * \param count updated to number of entries + * \param s string to parse + * \param count updated to number of entries + * \param context talloc context block * \return array of struct box_multi_length, or 0 on memory exhaustion */ struct box_multi_length *box_parse_multi_lengths(const char *s, - unsigned int *count) + unsigned int *count, void *context) { char *end; unsigned int i, n; @@ -2453,7 +2326,8 @@ struct box_multi_length *box_parse_multi_lengths(const char *s, if (s[i] == ',') n++; - if ((length = malloc(sizeof *length * n)) == NULL) + length = talloc_array(context, struct box_multi_length, n); + if (!length) return NULL; for (i = 0; i != n; i++) { diff --git a/render/box_normalise.c b/render/box_normalise.c index 6be2d92c3..e05aa077a 100644 --- a/render/box_normalise.c +++ b/render/box_normalise.c @@ -21,7 +21,6 @@ #endif #define NDEBUG #include "netsurf/utils/log.h" -#include "netsurf/utils/pool.h" struct span_info { @@ -45,18 +44,18 @@ struct columns { }; -static bool box_normalise_table(struct box *table, pool box_pool); +static bool box_normalise_table(struct box *table, struct content *c); static void box_normalise_table_spans(struct box *table); static bool box_normalise_table_row_group(struct box *row_group, struct columns *col_info, - pool box_pool); + struct content *c); static bool box_normalise_table_row(struct box *row, struct columns *col_info, - pool box_pool); + struct content *c); static bool calculate_table_row(struct columns *col_info, unsigned int col_span, unsigned int row_span, unsigned int *start_column); -static bool box_normalise_inline_container(struct box *cont, pool box_pool); +static bool box_normalise_inline_container(struct box *cont, struct content *c); /** @@ -79,7 +78,7 @@ static bool box_normalise_inline_container(struct box *cont, pool box_pool); * FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE \endcode */ -bool box_normalise_block(struct box *block, pool box_pool) +bool box_normalise_block(struct box *block, struct content *c) { struct box *child; struct box *next_child; @@ -98,16 +97,16 @@ bool box_normalise_block(struct box *block, pool box_pool) switch (child->type) { case BOX_BLOCK: /* ok */ - if (!box_normalise_block(child, box_pool)) + if (!box_normalise_block(child, c)) return false; break; case BOX_INLINE_CONTAINER: if (!box_normalise_inline_container(child, - box_pool)) + c)) return false; break; case BOX_TABLE: - if (!box_normalise_table(child, box_pool)) + if (!box_normalise_table(child, c)) return false; break; case BOX_INLINE: @@ -127,7 +126,7 @@ bool box_normalise_block(struct box *block, pool box_pool) if (!style) return false; css_cascade(style, &css_blank_style); - table = box_create(style, block->href, 0, 0, box_pool); + table = box_create(style, block->href, 0, 0, c); if (!table) { css_free_style(style); return false; @@ -152,7 +151,7 @@ bool box_normalise_block(struct box *block, pool box_pool) if (table->next) table->next->prev = table; table->parent = block; - if (!box_normalise_table(table, box_pool)) + if (!box_normalise_table(table, c)) return false; break; default: @@ -164,7 +163,7 @@ bool box_normalise_block(struct box *block, pool box_pool) } -bool box_normalise_table(struct box *table, pool box_pool) +bool box_normalise_table(struct box *table, struct content * c) { struct box *child; struct box *next_child; @@ -192,7 +191,7 @@ bool box_normalise_table(struct box *table, pool box_pool) case BOX_TABLE_ROW_GROUP: /* ok */ if (!box_normalise_table_row_group(child, - &col_info, box_pool)) { + &col_info, c)) { free(col_info.spans); return false; } @@ -211,7 +210,7 @@ bool box_normalise_table(struct box *table, pool box_pool) } css_cascade(style, &css_blank_style); row_group = box_create(style, table->href, 0, - 0, box_pool); + 0, c); if (!row_group) { free(col_info.spans); css_free_style(style); @@ -240,7 +239,7 @@ bool box_normalise_table(struct box *table, pool box_pool) row_group->next->prev = row_group; row_group->parent = table; if (!box_normalise_table_row_group(row_group, - &col_info, box_pool)) { + &col_info, c)) { free(col_info.spans); return false; } @@ -344,7 +343,7 @@ void box_normalise_table_spans(struct box *table) bool box_normalise_table_row_group(struct box *row_group, struct columns *col_info, - pool box_pool) + struct content * c) { struct box *child; struct box *next_child; @@ -361,7 +360,7 @@ bool box_normalise_table_row_group(struct box *row_group, case BOX_TABLE_ROW: /* ok */ if (!box_normalise_table_row(child, col_info, - box_pool)) + c)) return false; break; case BOX_BLOCK: @@ -376,7 +375,7 @@ bool box_normalise_table_row_group(struct box *row_group, return false; css_cascade(style, &css_blank_style); row = box_create(style, row_group->href, 0, - 0, box_pool); + 0, c); if (!row) { css_free_style(style); return false; @@ -404,7 +403,7 @@ bool box_normalise_table_row_group(struct box *row_group, row->next->prev = row; row->parent = row_group; if (!box_normalise_table_row(row, col_info, - box_pool)) + c)) return false; break; case BOX_INLINE: @@ -440,7 +439,7 @@ bool box_normalise_table_row_group(struct box *row_group, bool box_normalise_table_row(struct box *row, struct columns *col_info, - pool box_pool) + struct content * c) { struct box *child; struct box *next_child; @@ -457,7 +456,7 @@ bool box_normalise_table_row(struct box *row, switch (child->type) { case BOX_TABLE_CELL: /* ok */ - if (!box_normalise_block(child, box_pool)) + if (!box_normalise_block(child, c)) return false; cell = child; break; @@ -473,7 +472,7 @@ bool box_normalise_table_row(struct box *row, return false; css_cascade(style, &css_blank_style); cell = box_create(style, row->href, 0, 0, - box_pool); + c); if (!cell) { css_free_style(style); return false; @@ -500,7 +499,7 @@ bool box_normalise_table_row(struct box *row, if (cell->next) cell->next->prev = cell; cell->parent = row; - if (!box_normalise_block(cell, box_pool)) + if (!box_normalise_block(cell, c)) return false; break; case BOX_INLINE: @@ -627,7 +626,7 @@ bool calculate_table_row(struct columns *col_info, } -bool box_normalise_inline_container(struct box *cont, pool box_pool) +bool box_normalise_inline_container(struct box *cont, struct content * c) { struct box *child; struct box *next_child; @@ -645,7 +644,7 @@ bool box_normalise_inline_container(struct box *cont, pool box_pool) break; case BOX_INLINE_BLOCK: /* ok */ - if (!box_normalise_block(child, box_pool)) + if (!box_normalise_block(child, c)) return false; break; case BOX_FLOAT_LEFT: @@ -656,13 +655,13 @@ bool box_normalise_inline_container(struct box *cont, pool box_pool) case BOX_BLOCK: if (!box_normalise_block( child->children, - box_pool)) + c)) return false; break; case BOX_TABLE: if (!box_normalise_table( child->children, - box_pool)) + c)) return false; break; default: diff --git a/render/form.c b/render/form.c index 119fa968b..559f7e3e2 100644 --- a/render/form.c +++ b/render/form.c @@ -42,6 +42,7 @@ struct form *form_new(char *action, form_method method) form->method = method; form->controls = 0; form->last_control = 0; + form->prev = 0; return form; } diff --git a/render/form.h b/render/form.h index 00d8eb565..ceddd96f8 100644 --- a/render/form.h +++ b/render/form.h @@ -33,6 +33,7 @@ struct form { form_method method; /**< Method and enctype. */ struct form_control *controls; /**< Linked list of controls. */ struct form_control *last_control; /**< Last control in list. */ + struct form *prev; /**< Previous form in doc. */ }; /** Type of a struct form_control. */ diff --git a/render/html.c b/render/html.c index 60e29f694..506904f6f 100644 --- a/render/html.c +++ b/render/html.c @@ -28,6 +28,7 @@ #include "netsurf/render/layout.h" #include "netsurf/utils/log.h" #include "netsurf/utils/messages.h" +#include "netsurf/utils/talloc.h" #include "netsurf/utils/url.h" #include "netsurf/utils/utils.h" @@ -65,7 +66,7 @@ bool html_create(struct content *c, const char *params[]) html->encoding_handler = 0; html->encoding = 0; html->getenc = true; - html->base_url = strdup(c->url); + html->base_url = c->url; html->layout = 0; html->background_colour = TRANSPARENT; html->stylesheet_count = 0; @@ -73,17 +74,13 @@ bool html_create(struct content *c, const char *params[]) html->style = 0; html->object_count = 0; html->object = 0; + html->forms = 0; html->imagemaps = 0; - html->box_pool = pool_create(sizeof (struct box) * 100); - html->string_pool = pool_create(8000); html->bw = 0; - if (!html->base_url || !html->string_pool || !html->box_pool) - goto no_memory; - for (i = 0; params[i]; i += 2) { if (strcasecmp(params[i], "charset") == 0) { - html->encoding = strdup(params[i + 1]); + html->encoding = talloc_strdup(c, params[i + 1]); if (!html->encoding) goto no_memory; html->encoding_source = ENCODING_SOURCE_HEADER; @@ -135,7 +132,7 @@ bool html_process_data(struct content *c, char *data, unsigned int size) if (encoding) { if (!html_set_parser_encoding(c, encoding)) return false; - c->data.html.encoding = strdup(encoding); + c->data.html.encoding = talloc_strdup(c, encoding); if (!c->data.html.encoding) return false; c->data.html.encoding_source = @@ -266,7 +263,7 @@ bool html_convert(struct content *c, int width, int height) /* The encoding was not in headers or detected, and the parser * found a <meta http-equiv="content-type" * content="text/html; charset=...">. */ - c->data.html.encoding = strdup(document->encoding); + c->data.html.encoding = talloc_strdup(c, document->encoding); if (!c->data.html.encoding) { msg_data.error = messages_get("NoMemory"); content_broadcast(c, CONTENT_MSG_ERROR, msg_data); @@ -338,12 +335,13 @@ bool html_convert(struct content *c, int width, int height) content_set_status(c, messages_get("Formatting")); content_broadcast(c, CONTENT_MSG_STATUS, msg_data); LOG(("Layout document")); - layout_document(c->data.html.layout, width, - c->data.html.box_pool); + layout_document(c, width); /*box_dump(c->data.html.layout->children, 0);*/ c->width = c->data.html.layout->descendant_x1; c->height = c->data.html.layout->descendant_y1; + c->size = talloc_total_size(c); + if (c->active == 0) { c->status = CONTENT_STATUS_DONE; content_set_status(c, messages_get("Done")); @@ -380,20 +378,26 @@ bool html_head(struct content *c, xmlNode *head) xmlChar *title = xmlNodeGetContent(node); if (!title) return false; - c->title = squash_whitespace(title); + char *title2 = squash_whitespace(title); + xmlFree(title); + if (!title2) + return false; + c->title = talloc_strdup(c, title2); + free(title2); if (!c->title) return false; - xmlFree(title); } else if (strcmp(node->name, "base") == 0) { - char *href = (char *) xmlGetProp(node, (const xmlChar *) "href"); + char *href = (char *) xmlGetProp(node, + (const xmlChar *) "href"); if (href) { char *url; url_func_result res; res = url_normalize(href, &url); if (res == URL_FUNC_OK) { - free(c->data.html.base_url); - c->data.html.base_url = url; + c->data.html.base_url = + talloc_strdup(c, url); + free(url); } xmlFree(href); } @@ -424,8 +428,8 @@ bool html_find_stylesheets(struct content *c, xmlNode *head) /* stylesheet 0 is the base style sheet, * stylesheet 1 is the adblocking stylesheet, * stylesheet 2 is any <style> elements */ - c->data.html.stylesheet_content = malloc(STYLESHEET_START * - sizeof *c->data.html.stylesheet_content); + c->data.html.stylesheet_content = talloc_array(c, struct content *, + STYLESHEET_START); if (!c->data.html.stylesheet_content) return false; c->data.html.stylesheet_content[STYLESHEET_ADBLOCK] = 0; @@ -511,10 +515,9 @@ bool html_find_stylesheets(struct content *c, xmlNode *head) LOG(("linked stylesheet %i '%s'", i, url)); /* start fetch */ - stylesheet_content = realloc( + stylesheet_content = talloc_realloc(c, c->data.html.stylesheet_content, - (i + 1) * sizeof - *c->data.html.stylesheet_content); + struct content *, i + 1); if (!stylesheet_content) return false; c->data.html.stylesheet_content = stylesheet_content; @@ -709,7 +712,7 @@ void html_convert_css_callback(content_msg msg, struct content *css, * Start a fetch for an object required by a page. * * \param c content structure - * \param url URL of object to fetch (not copied, must be on heap) + * \param url URL of object to fetch (copied) * \param box box that will contain the object * \param permitted_types array of types, terminated by CONTENT_UNKNOWN, * or 0 if all types except OTHER and UNKNOWN acceptable @@ -727,7 +730,7 @@ bool html_fetch_object(struct content *c, char *url, struct box *box, unsigned int i = c->data.html.object_count; struct content_html_object *object; struct content *c_fetch; - + /* initialise fetch */ c_fetch = fetchcache(url, html_object_callback, c, (void *) i, available_width, available_height, @@ -736,14 +739,18 @@ bool html_fetch_object(struct content *c, char *url, struct box *box, return false; /* add to object list */ - object = realloc(c->data.html.object, - (i + 1) * sizeof *c->data.html.object); + object = talloc_realloc(c, c->data.html.object, + struct content_html_object, i + 1); if (!object) { content_remove_user(c_fetch, html_object_callback, c, (void*)i); return false; } c->data.html.object = object; - c->data.html.object[i].url = url; + c->data.html.object[i].url = talloc_strdup(c, url); + if (!c->data.html.object[i].url) { + content_remove_user(c_fetch, html_object_callback, c, (void*)i); + return false; + } c->data.html.object[i].box = box; c->data.html.object[i].permitted_types = permitted_types; c->data.html.object[i].background = background; @@ -829,8 +836,9 @@ void html_object_callback(content_msg msg, struct content *object, case CONTENT_MSG_REDIRECT: c->active--; - free(c->data.html.object[i].url); - c->data.html.object[i].url = strdup(data.redirect); + talloc_free(c->data.html.object[i].url); + c->data.html.object[i].url = talloc_strdup(c, + data.redirect); if (!c->data.html.object[i].url) { /** \todo report oom */ } else { @@ -1003,8 +1011,7 @@ void html_stop(struct content *c) void html_reformat(struct content *c, int width, int height) { - layout_document(c->data.html.layout, width, - c->data.html.box_pool); + layout_document(c, width); c->width = c->data.html.layout->descendant_x1; c->height = c->data.html.layout->descendant_y1; } @@ -1019,20 +1026,11 @@ void html_destroy(struct content *c) unsigned int i; LOG(("content %p", c)); - free(c->title); - imagemap_destroy(c); if (c->data.html.parser) htmlFreeParserCtxt(c->data.html.parser); - free(c->data.html.encoding); - - free(c->data.html.base_url); - - if (c->data.html.layout) - box_free(c->data.html.layout); - /* Free stylesheets */ if (c->data.html.stylesheet_count) { for (i = 0; i != c->data.html.stylesheet_count; i++) { @@ -1043,10 +1041,9 @@ void html_destroy(struct content *c) c, (void *) i); } } - free(c->data.html.stylesheet_content); - if (c->data.html.style) - css_free_style(c->data.html.style); + /*if (c->data.html.style) + css_free_style(c->data.html.style);*/ /* Free objects */ for (i = 0; i != c->data.html.object_count; i++) { @@ -1054,12 +1051,7 @@ void html_destroy(struct content *c) if (c->data.html.object[i].content) content_remove_user(c->data.html.object[i].content, html_object_callback, c, (void*)i); - free(c->data.html.object[i].url); } - free(c->data.html.object); - - pool_destroy(c->data.html.string_pool); - pool_destroy(c->data.html.box_pool); } diff --git a/render/html.h b/render/html.h index e57f08b07..38b65b950 100644 --- a/render/html.h +++ b/render/html.h @@ -18,7 +18,6 @@ #include "libxml/HTMLparser.h" #include "netsurf/content/content_type.h" #include "netsurf/css/css.h" -#include "netsurf/utils/pool.h" struct box; struct browser_window; @@ -75,11 +74,10 @@ struct content_html_data { unsigned int object_count; /** Objects. Each may be 0. */ struct content_html_object *object; - - struct imagemap **imagemaps; /**< Hashtable of imagemaps */ - - pool box_pool; /**< Memory pool for box tree. */ - pool string_pool; /**< Memory pool for strings. */ + /** Forms, in reverse order to document. */ + struct form *forms; + /** Hash table of imagemaps */ + struct imagemap **imagemaps; /**< Browser window containing this document, or 0 if not open. */ struct browser_window *bw; diff --git a/render/layout.c b/render/layout.c index fbe54bda7..af7ca565f 100644 --- a/render/layout.c +++ b/render/layout.c @@ -15,7 +15,6 @@ */ #define _GNU_SOURCE /* for strndup */ -#include <alloca.h> #include <assert.h> #include <ctype.h> #include <limits.h> @@ -34,7 +33,7 @@ #include "netsurf/render/layout.h" #define NDEBUG #include "netsurf/utils/log.h" -#include "netsurf/utils/pool.h" +#include "netsurf/utils/talloc.h" #include "netsurf/utils/utils.h" @@ -55,12 +54,13 @@ static void find_sides(struct box *fl, int y0, int y1, static int line_height(struct css_style *style); static bool layout_line(struct box *first, int width, int *y, int cx, int cy, struct box *cont, bool indent, - pool box_pool, struct box **next_box); + struct content *content, struct box **next_box); static int layout_text_indent(struct css_style *style, int width); -static bool layout_float(struct box *b, int width, pool box_pool); +static bool layout_float(struct box *b, int width, struct content *content); static void place_float_below(struct box *c, int width, int cx, int y, struct box *cont); -static bool layout_table(struct box *box, int available_width, pool box_pool); +static bool layout_table(struct box *box, int available_width, + struct content *content); static void layout_move_children(struct box *box, int x, int y); static bool calculate_widths(struct box *box); static bool calculate_block_widths(struct box *box, int *min, int *max, @@ -75,15 +75,17 @@ static bool calculate_table_widths(struct box *table); /** * Calculate positions of boxes in a document. * - * \param doc root of document box tree + * \param doc content of type CONTENT_HTML * \param width available page width - * \param box_pool memory pool for any new boxes * \return true on success, false on memory exhaustion */ -bool layout_document(struct box *doc, int width, pool box_pool) +bool layout_document(struct content *content, int width) { bool ret; + struct box *doc = content->data.html.layout; + + assert(content->type == CONTENT_HTML); doc->float_children = 0; @@ -97,7 +99,7 @@ bool layout_document(struct box *doc, int width, pool box_pool) doc->border[RIGHT] + doc->margin[RIGHT]; doc->width = width; - ret = layout_block_context(doc, box_pool); + ret = layout_block_context(doc, content); layout_calculate_descendant_bboxes(doc); @@ -109,14 +111,14 @@ bool layout_document(struct box *doc, int width, pool box_pool) * Layout a block formatting context. * * \param block BLOCK, INLINE_BLOCK, or TABLE_CELL to layout. - * \param box_pool memory pool for any new boxes + * \param content memory pool for any new boxes * \return true on success, false on memory exhaustion * * This function carries out layout of a block and its children, as described * in CSS 2.1 9.4.1. */ -bool layout_block_context(struct box *block, pool box_pool) +bool layout_block_context(struct box *block, struct content *content) { struct box *box; int cx; @@ -154,7 +156,7 @@ bool layout_block_context(struct box *block, pool box_pool) if (box->type == BOX_BLOCK) layout_block_find_dimensions(box->parent->width, box); else if (box->type == BOX_TABLE) { - if (!layout_table(box, box->parent->width, box_pool)) + if (!layout_table(box, box->parent->width, content)) return false; layout_solve_width(box->parent->width, box->width, box->margin, box->padding, box->border); @@ -195,7 +197,7 @@ bool layout_block_context(struct box *block, pool box_pool) if (box->type == BOX_INLINE_CONTAINER) { box->width = box->parent->width; if (!layout_inline_container(box, box->width, block, - cx, cy, box_pool)) + cx, cy, content)) return false; } else if (box->type == BOX_TABLE) { /* Move down to avoid floats if necessary. */ @@ -634,12 +636,12 @@ void find_sides(struct box *fl, int y0, int y1, * \param cont ancestor box which defines horizontal space, for floats * \param cx box position relative to cont * \param cy box position relative to cont - * \param box_pool memory pool for any new boxes + * \param content memory pool for any new boxes * \return true on success, false on memory exhaustion */ bool layout_inline_container(struct box *box, int width, - struct box *cont, int cx, int cy, pool box_pool) + struct box *cont, int cx, int cy, struct content *content) { bool first_line = true; struct box *c, *next; @@ -653,7 +655,7 @@ bool layout_inline_container(struct box *box, int width, for (c = box->children; c; ) { LOG(("c %p", c)); if (!layout_line(c, width, &y, cx, cy + y, cont, first_line, - box_pool, &next)) + content, &next)) return false; c = next; first_line = false; @@ -710,13 +712,13 @@ int line_height(struct css_style *style) * \param cont ancestor box which defines horizontal space, for floats * \param indent apply any first-line indent * \param next_box updated to first box for next line, or 0 at end - * \param box_pool memory pool for any new boxes + * \param content memory pool for any new boxes * \return true on success, false on memory exhaustion */ bool layout_line(struct box *first, int width, int *y, int cx, int cy, struct box *cont, bool indent, - pool box_pool, struct box **next_box) + struct content *content, struct box **next_box) { int height, used_height; int x0 = 0; @@ -759,7 +761,7 @@ bool layout_line(struct box *first, int width, int *y, if (b->type == BOX_INLINE_BLOCK) { if (b->width == UNKNOWN_WIDTH) - if (!layout_float(b, width, box_pool)) + if (!layout_float(b, width, content)) return false; /** \todo should margin be included? spec unclear */ h = b->border[TOP] + b->padding[TOP] + b->height + @@ -943,7 +945,7 @@ bool layout_line(struct box *first, int width, int *y, d->float_children = 0; /* css_dump_style(b->style); */ - if (!layout_float(d, width, box_pool)) + if (!layout_float(d, width, content)) return false; d->x = d->margin[LEFT] + d->border[LEFT]; d->y = d->margin[TOP] + d->border[TOP]; @@ -1022,13 +1024,14 @@ bool layout_line(struct box *first, int width, int *y, b = split_box->next; } else { /* cut off first word for this line */ - /* \todo allocate from box_pool */ - c2 = pool_alloc(box_pool, sizeof *c2); + /* \todo allocate from content */ + c2 = talloc_memdup(content, split_box, + sizeof *c2); if (!c2) return false; - memcpy(c2, split_box, sizeof *c2); - c2->text = strndup(split_box->text + space + 1, - split_box->length - (space + 1)); + c2->text = talloc_strndup(content, + split_box->text + space + 1, + split_box->length -(space + 1)); if (!c2->text) return false; c2->length = split_box->length - (space + 1); @@ -1066,12 +1069,13 @@ bool layout_line(struct box *first, int width, int *y, if (space == 0) space = 1; if (space != split_box->length) { - c2 = pool_alloc(box_pool, sizeof *c2); + c2 = talloc_memdup(content, split_box, + sizeof *c2); if (!c2) return false; - memcpy(c2, split_box, sizeof *c2); - c2->text = strndup(split_box->text + space + 1, - split_box->length - (space + 1)); + c2->text = talloc_strndup(content, + split_box->text + space + 1, + split_box->length -(space + 1)); if (!c2->text) return false; c2->length = split_box->length - (space + 1); @@ -1147,22 +1151,22 @@ int layout_text_indent(struct css_style *style, int width) * * \param b float or inline block box * \param width available width - * \param box_pool memory pool for any new boxes + * \param content memory pool for any new boxes * \return true on success, false on memory exhaustion */ -bool layout_float(struct box *b, int width, pool box_pool) +bool layout_float(struct box *b, int width, struct content *content) { layout_float_find_dimensions(width, b->style, b); if (b->type == BOX_TABLE) { - if (!layout_table(b, width, box_pool)) + if (!layout_table(b, width, content)) return false; if (b->margin[LEFT] == AUTO) b->margin[LEFT] = 0; if (b->margin[RIGHT] == AUTO) b->margin[RIGHT] = 0; } else - return layout_block_context(b, box_pool); + return layout_block_context(b, content); return true; } @@ -1212,12 +1216,12 @@ void place_float_below(struct box *c, int width, int cx, int y, * * \param table table to layout * \param available_width width of containing block - * \param box_pool memory pool for any new boxes + * \param content memory pool for any new boxes * \return true on success, false on memory exhaustion */ bool layout_table(struct box *table, int available_width, - pool box_pool) + struct content *content) { unsigned int columns = table->columns; /* total columns */ unsigned int i; @@ -1225,7 +1229,7 @@ bool layout_table(struct box *table, int available_width, int *excess_y; int table_width, min_width = 0, max_width = 0; int required_width = 0; - int x, cp, remainder = 0, count = 0; + int x, remainder = 0, count = 0; int table_height = 0; int *xs; /* array of column x positions */ int auto_width; @@ -1273,11 +1277,6 @@ bool layout_table(struct box *table, int available_width, layout_find_dimensions(available_width, c->style, 0, c->padding, c->border); - if (c->style->html_style.cellpadding.type == CSS_CELLPADDING_VALUE) - for (cp = 0; cp < 4; cp++) - if (!c->style->padding[cp].override_cellpadding) - c->padding[cp] = - c->style->html_style.cellpadding.value; if (c->style->overflow == CSS_OVERFLOW_SCROLL || c->style->overflow == @@ -1489,7 +1488,7 @@ bool layout_table(struct box *table, int available_width, c->float_children = 0; c->height = AUTO; - if (!layout_block_context(c, box_pool)) { + if (!layout_block_context(c, content)) { free(col); free(excess_y); free(row_span); @@ -1692,25 +1691,25 @@ bool calculate_widths(struct box *box) /* add margins, border, padding to min, max widths */ if (style) { for (side = 1; side != 5; side += 2) { /* RIGHT, LEFT */ - if ((box->type == BOX_TABLE_CELL) && - (style->html_style.cellpadding.type == CSS_CELLPADDING_VALUE) && - (!style->padding[side].override_cellpadding)) - extra_fixed += style->html_style.cellpadding.value; - else if (style->padding[side].padding == CSS_PADDING_LENGTH) - extra_fixed += (int)css_len2px(&style->padding[side].value.length, - style); - else if (style->padding[side].padding == CSS_PADDING_PERCENT) - extra_frac += style->padding[side].value.percent * 0.01; + if (style->padding[side].padding == CSS_PADDING_LENGTH) + extra_fixed += css_len2px(&style->padding[side]. + value.length, style); + else if (style->padding[side].padding == + CSS_PADDING_PERCENT) + extra_frac += style->padding[side].value. + percent * 0.01; if (style->border[side].style != CSS_BORDER_STYLE_NONE) - extra_fixed += (int)css_len2px(&style->border[side].width.value, - style); + extra_fixed += css_len2px(&style->border[side]. + width.value, style); if (style->margin[side].margin == CSS_MARGIN_LENGTH) - extra_fixed += (int)css_len2px(&style->margin[side].value.length, - style); - else if (style->margin[side].margin == CSS_MARGIN_PERCENT) - extra_frac += style->margin[side].value.percent * 0.01; + extra_fixed += css_len2px(&style->margin[side]. + value.length, style); + else if (style->margin[side].margin == + CSS_MARGIN_PERCENT) + extra_frac += style->margin[side].value. + percent * 0.01; } } diff --git a/render/layout.h b/render/layout.h index 1a926d904..c56b42d9c 100644 --- a/render/layout.h +++ b/render/layout.h @@ -16,16 +16,14 @@ #ifndef _NETSURF_RENDER_LAYOUT_H_ #define _NETSURF_RENDER_LAYOUT_H_ -#include "netsurf/utils/pool.h" - #define SCROLLBAR_WIDTH 16 struct box; -bool layout_document(struct box *box, int width, pool box_pool); -bool layout_block_context(struct box *block, pool box_pool); +bool layout_document(struct content *content, int width); +bool layout_block_context(struct box *block, struct content *content); bool layout_inline_container(struct box *box, int width, - struct box *cont, int cx, int cy, pool box_pool); + struct box *cont, int cx, int cy, struct content *content); void layout_calculate_descendant_bboxes(struct box *box); #endif diff --git a/riscos/print.c b/riscos/print.c index 0e4eef004..f136fe100 100644 --- a/riscos/print.c +++ b/riscos/print.c @@ -471,7 +471,6 @@ bool print_document(struct gui_window *g, const char *filename) int left, right, top, bottom, width, height; int saved_width; int yscroll = 0, sheets = print_max_sheets; - struct box *box = 0; struct content *c = g->bw->current_content; const char *error_message; pdriver_features features; @@ -484,9 +483,6 @@ bool print_document(struct gui_window *g, const char *filename) return false; } - if (c->type == CONTENT_HTML) - box = c->data.html.layout; - /* read printer driver features */ error = xpdriver_info(0, 0, 0, &features, 0, 0, 0, 0); if (error) { @@ -511,7 +507,7 @@ bool print_document(struct gui_window *g, const char *filename) /* layout the document to the correct width */ saved_width = c->width; if (c->type == CONTENT_HTML) - layout_document(box, width, c->data.html.box_pool); + layout_document(c, width); /* open printer file */ error = xosfind_openoutw(osfind_NO_PATH | osfind_ERROR_IF_DIR | @@ -648,7 +644,7 @@ bool print_document(struct gui_window *g, const char *filename) /* restore document layout */ if (c->type == CONTENT_HTML) - layout_document(box, saved_width, c->data.html.box_pool); + layout_document(c, saved_width); return true; @@ -666,7 +662,7 @@ error: /* restore document layout */ if (c->type == CONTENT_HTML) - layout_document(box, saved_width, c->data.html.box_pool); + layout_document(c, saved_width); return false; } diff --git a/riscos/save_draw.c b/riscos/save_draw.c index 896f5cacd..05ef8defb 100644 --- a/riscos/save_draw.c +++ b/riscos/save_draw.c @@ -146,7 +146,7 @@ bool save_as_draw(struct content *c, const char *path) memcpy(diagram->source, "NetSurf ", 12); /* recalculate box widths for an A4 page */ - if (!layout_document(box, A4PAGEWIDTH, c->data.html.box_pool)) { + if (!layout_document(c, A4PAGEWIDTH)) { warn_user("NoMemory", 0); goto draw_save_error; } @@ -183,7 +183,7 @@ bool save_as_draw(struct content *c, const char *path) drawbuf_free(); /* reset layout to current window width */ - if (!layout_document(box, current_width, c->data.html.box_pool)) { + if (!layout_document(c, current_width)) { warn_user("NoMemory", 0); return false; } @@ -193,7 +193,7 @@ bool save_as_draw(struct content *c, const char *path) draw_save_error: drawbuf_free(); /* attempt to reflow back on failure */ - (void)layout_document(box, current_width, c->data.html.box_pool); + (void)layout_document(c, current_width); return false; } |