From 29d44c739e9f90dbaeb2257f914ebd44949622b6 Mon Sep 17 00:00:00 2001 From: James Bursa Date: Mon, 28 Mar 2005 19:17:06 +0000 Subject: [project @ 2005-03-28 19:17:06 by bursa] Split convert_xml_to_box() into box_construct_element() and box_construct_text(). Add box_solve_display(). svn path=/import/netsurf/; revision=1585 --- render/box_construct.c | 439 ++++++++++++++++++++++++++++++------------------- 1 file changed, 267 insertions(+), 172 deletions(-) diff --git a/render/box_construct.c b/render/box_construct.c index 61f20cb83..5e74497a4 100644 --- a/render/box_construct.c +++ b/render/box_construct.c @@ -92,9 +92,18 @@ 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); -struct css_style * box_get_style(struct content *c, +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); +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); +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, @@ -245,6 +254,38 @@ 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) +{ + switch (n->type) { + case XML_ELEMENT_NODE: + return box_construct_element(n, content, parent_style, parent, + inline_container, status); + case XML_TEXT_NODE: + return box_construct_text(n, content, parent_style, parent, + inline_container, status); + default: + /* not an element or text node: ignore it (eg. comment) */ + return true; + } +} + + +/** + * Construct the box tree for an XML element. + * + * \param n XML node of type XML_ELEMENT_NODE + * \param content content of type CONTENT_HTML that is being processed + * \param parent_style style at this point in xml tree + * \param parent parent in box tree + * \param inline_container current inline container box, or 0, updated to + * new current inline container on exit + * \param status status for forms etc. + * \return true on success, false on memory exhaustion + */ + +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) { struct box *box = 0; struct box *inline_container_c; @@ -255,88 +296,219 @@ bool convert_xml_to_box(xmlNode *n, struct content *content, char *title = 0, *id = 0; bool convert_children = true; char *href_in = status.href; + struct element_entry *element; assert(n); + assert(n->type == XML_ELEMENT_NODE); assert(parent_style); assert(parent); assert(inline_container); - if (n->type == XML_ELEMENT_NODE) { - struct element_entry *element; + gui_multitask(); - gui_multitask(); + style = box_get_style(content, parent_style, n); + if (!style) + goto no_memory; + if (style->display == CSS_DISPLAY_NONE) { + css_free_style(style); + goto end; + } + + /* extract title attribute, if present */ + if ((title0 = xmlGetProp(n, (const xmlChar *) "title"))) { + status.title = title = squash_whitespace(title0); + xmlFree(title0); + if (!title) + goto no_memory; + } + + /* extract id attribute, if present */ + if ((id0 = xmlGetProp(n, (const xmlChar *) "id"))) { + status.id = id = squash_whitespace(id0); + xmlFree(id0); + if (!id) + goto no_memory; + } - style = box_get_style(content, parent_style, n); - if (!style) + /* 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 (style->display == CSS_DISPLAY_NONE) { + if (!box) { + /* no box for this element */ + assert(!convert_children); css_free_style(style); goto end; } - /* floats are treated as blocks */ - if (style->float_ == CSS_FLOAT_LEFT || - style->float_ == CSS_FLOAT_RIGHT) - if (style->display == CSS_DISPLAY_INLINE) - style->display = CSS_DISPLAY_BLOCK; - - /* extract title attribute, if present */ - if ((title0 = xmlGetProp(n, (const xmlChar *) "title"))) { - status.title = title = squash_whitespace(title0); - xmlFree(title0); - if (!title) - goto no_memory; - } + } else { + /* general element */ + box = box_create(style, status.href, title, id, + content->data.html.box_pool); + if (!box) + goto no_memory; + } + /* 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); - /* extract id attribute, if present */ - if ((id0 = xmlGetProp(n, (const xmlChar *) "id"))) { - status.id = id = squash_whitespace(id0); - xmlFree(id0); - if (!id) + if (box->type == BOX_INLINE || + 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); } - /* 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; + 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 { - /* general element */ - box = box_create(style, status.href, title, id, + /* 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); - if (!box) + if (!parent) goto no_memory; + if (style->float_ == CSS_FLOAT_LEFT) + parent->type = BOX_FLOAT_LEFT; + else + parent->type = BOX_FLOAT_RIGHT; + box_add_child(*inline_container, parent); + if (box->type == BOX_INLINE || + box->type == BOX_INLINE_BLOCK) + box->type = BOX_BLOCK; } - /* set box type from style if it has not been set already */ - if (box->type == BOX_INLINE) - box->type = box_map[style->display]; + } - } else if (n->type == XML_TEXT_NODE) { - /* text node: added to inline container below */ + /* non-inline box: add to tree and recurse */ + box_add_child(parent, 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; + } + if (style->float_ == CSS_FLOAT_NONE) + /* new inline container unless this is a float */ + *inline_container = 0; - } else { - /* not an element or text node: ignore it (eg. comment) */ - goto end; + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "colspan")) != NULL) { + 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) { + box->rows = strtol(s, NULL, 10); + if (MAX_SPAN < box->rows) + box->rows = 1; + 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)) + 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; +} + + +/** + * Construct the box tree for an XML text node. + * + * \param n XML node of type XML_TEXT_NODE + * \param content content of type CONTENT_HTML that is being processed + * \param parent_style style at this point in xml tree + * \param parent parent in box tree + * \param inline_container current inline container box, or 0, updated to + * new current inline container on exit + * \param status status for forms etc. + * \return true on success, false on memory exhaustion + */ + +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) +{ + struct box *box = 0; + + assert(n); + assert(n->type == XML_TEXT_NODE); + assert(parent_style); + assert(parent); + assert(inline_container); + content->size += sizeof(struct box) + sizeof(struct css_style); - if (n->type == XML_TEXT_NODE && - (parent_style->white_space == CSS_WHITE_SPACE_NORMAL || - parent_style->white_space == CSS_WHITE_SPACE_NOWRAP)) { + 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; @@ -364,7 +536,7 @@ bool convert_xml_to_box(xmlNode *n, struct content *content, box_add_child(parent, *inline_container); } - box = box_create(parent_style, status.href, title, id, + box = box_create(parent_style, status.href, 0, 0, content->data.html.box_pool); if (!box) { free(text); @@ -407,7 +579,7 @@ bool convert_xml_to_box(xmlNode *n, struct content *content, } goto end; - } else if (n->type == XML_TEXT_NODE) { + } else { /* white-space: pre */ char *text = cnv_space2nbsp(n->content); char *current; @@ -438,8 +610,8 @@ bool convert_xml_to_box(xmlNode *n, struct content *content, BOX_INLINE_CONTAINER; box_add_child(parent, *inline_container); } - box = box_create(parent_style, status.href, title, - id, content->data.html.box_pool); + box = box_create(parent_style, status.href, 0, + 0, content->data.html.box_pool); if (!box) { free(text); goto no_memory; @@ -465,124 +637,12 @@ bool convert_xml_to_box(xmlNode *n, struct content *content, } while (*current); free(text); goto end; - - } else if (box->type == BOX_INLINE || - 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); - } - - 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 { - /* 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); - if (!parent) - goto no_memory; - if (style->float_ == CSS_FLOAT_LEFT) - parent->type = BOX_FLOAT_LEFT; - else - parent->type = BOX_FLOAT_RIGHT; - box_add_child(*inline_container, parent); - if (box->type == BOX_INLINE || - box->type == BOX_INLINE_BLOCK) - box->type = BOX_BLOCK; - } - } - - assert(n->type == XML_ELEMENT_NODE); - - /* non-inline box: add to tree and recurse */ - box_add_child(parent, 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; - } - 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) { - 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) { - box->rows = strtol(s, NULL, 10); - if (MAX_SPAN < box->rows) - box->rows = 1; - 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)) - 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; } @@ -806,10 +866,45 @@ struct css_style * box_get_style(struct content *c, xmlFree(s); } + box_solve_display(style, !n->parent); + return style; } +/** + * Calculate 'display' based on 'display', 'position', and 'float', as given + * by CSS 2.1 9.7. + * + * \param style style to update + * \param root this is the root element + */ + +void box_solve_display(struct css_style *style, bool root) +{ + if (style->display == CSS_DISPLAY_NONE) /* 1. */ + return; + else if (style->position == CSS_POSITION_ABSOLUTE || + style->position == CSS_POSITION_FIXED) /* 2. */ + style->float_ = CSS_FLOAT_NONE; + else if (style->float_ != CSS_FLOAT_NONE) /* 3. */ + ; + else if (root) /* 4. */ + ; + else /* 5. */ + return; + + /* map specified value to computed value using table given in 9.7 */ + if (style->display == CSS_DISPLAY_INLINE_TABLE) + style->display = CSS_DISPLAY_TABLE; + else if (style->display == CSS_DISPLAY_LIST_ITEM || + style->display == CSS_DISPLAY_TABLE) + ; /* same as specified */ + else + style->display = CSS_DISPLAY_BLOCK; +} + + /** * Apply the CSS text-transform property to given text for its ASCII chars. * -- cgit v1.2.3