summaryrefslogtreecommitdiff
path: root/render/box_construct.c
diff options
context:
space:
mode:
Diffstat (limited to 'render/box_construct.c')
-rw-r--r--render/box_construct.c439
1 files 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,
@@ -246,6 +255,38 @@ bool convert_xml_to_box(xmlNode *n, struct content *content,
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;
struct css_style *style = 0;
@@ -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,11 +866,46 @@ 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.
*
* \param s string to transform