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