[project @ 2004-05-21 14:26:59 by bursa]

Improved handling of objects and frames; some work on malloc() failure in box conversion.

svn path=/import/netsurf/; revision=880
This commit is contained in:
James Bursa 2004-05-21 14:26:59 +00:00
parent c2ebb7e4de
commit 8b78a7803d
6 changed files with 699 additions and 332 deletions

View File

@ -116,8 +116,8 @@ struct content {
CONTENT_STATUS_DONE /**< All finished. */
} status; /**< Current status. */
unsigned long width, height; /**< Dimensions, if applicable. */
unsigned long available_width; /**< Available width (eg window width). */
int width, height; /**< Dimensions, if applicable. */
int available_width; /**< Available width (eg window width). */
/** Data dependent on type. */
union {

View File

@ -36,50 +36,61 @@
#include "netsurf/utils/utils.h"
/* status for box tree construction */
struct status {
/** Status of box tree construction. */
struct box_status {
struct content *content;
char *href;
char *title;
struct form* current_form;
};
/* result of converting a special case element */
struct result {
struct box *box; /* box for element, if any, 0 otherwise */
int convert_children; /* children should be converted */
/** 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;
float value;
};
static struct box * convert_xml_to_box(xmlNode * n, struct content *content,
struct css_style * parent_style,
struct box * parent, struct box *inline_container,
struct status status);
struct box_status status);
static struct css_style * box_get_style(struct content ** stylesheet,
unsigned int stylesheet_count, struct css_style * parent_style,
xmlNode * n);
static void box_text_transform(char *s, unsigned int len,
css_text_transform tt);
static struct result box_a(xmlNode *n, struct status *status,
static struct box_result box_a(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct result box_body(xmlNode *n, struct status *status,
static struct box_result box_body(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct result box_br(xmlNode *n, struct status *status,
static struct box_result box_br(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct result box_image(xmlNode *n, struct status *status,
static struct box_result box_image(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct result box_form(xmlNode *n, struct status *status,
static struct box_result box_form(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct result box_textarea(xmlNode *n, struct status *status,
static struct box_result box_textarea(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct result box_select(xmlNode *n, struct status *status,
static struct box_result box_select(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct result box_input(xmlNode *n, struct status *status,
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 status *status,
static struct box *box_input_text(xmlNode *n, struct box_status *status,
struct css_style *style, bool password);
static struct result box_button(xmlNode *n, struct status *status,
static struct box_result box_button(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct result box_frameset(xmlNode *n, struct status *status,
static struct box_result box_frameset(xmlNode *n, struct box_status *status,
struct css_style *style);
static void add_option(xmlNode* n, struct form_control* current_select, char *text);
static void box_normalise_block(struct box *block, pool box_pool);
@ -91,23 +102,24 @@ void box_normalise_table_row(struct box *row,
unsigned int **row_span, unsigned int *table_columns,
pool box_pool);
static void box_normalise_inline_container(struct box *cont, pool box_pool);
static void gadget_free(struct form_control* g);
static void box_free_box(struct box *box);
static struct result box_object(xmlNode *n, struct status *status,
static struct box_result box_object(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct result box_embed(xmlNode *n, struct status *status,
static struct box_result box_embed(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct result box_applet(xmlNode *n, struct status *status,
static struct box_result box_applet(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct result box_iframe(xmlNode *n, struct status *status,
static struct box_result box_iframe(xmlNode *n, struct box_status *status,
struct css_style *style);
static bool plugin_decode(struct content* content, char* url, struct box* box,
struct object_params* po);
static struct box_multi_length *box_parse_multi_lengths(const char *s,
unsigned int *count);
/* element_table must be sorted by name */
struct element_entry {
char name[10]; /* element type */
struct result (*convert)(xmlNode *n, struct status *status,
struct box_result (*convert)(xmlNode *n, struct box_status *status,
struct css_style *style);
};
static const struct element_entry element_table[] = {
@ -217,7 +229,7 @@ void box_insert_sibling(struct box *box, struct box *new_box)
void xml_to_box(xmlNode *n, struct content *c)
{
struct status status = {c, 0, 0, 0};
struct box_status status = {c, 0, 0, 0};
LOG(("node %p", n));
assert(c->type == CONTENT_HTML);
@ -280,7 +292,7 @@ static box_type box_map[] = {
struct box * convert_xml_to_box(xmlNode * n, struct content *content,
struct css_style * parent_style,
struct box * parent, struct box *inline_container,
struct status status)
struct box_status status)
{
struct box * box = 0;
struct box * inline_container_c;
@ -289,7 +301,7 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content,
char * s;
xmlChar * title0;
char * title = 0;
int convert_children = 1;
bool convert_children = true;
char *href_in = status.href;
assert(n != 0 && parent_style != 0 && parent != 0);
@ -325,9 +337,12 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content,
(int (*)(const void *, const void *)) strcmp);
if (element != 0) {
/* a special convert function exists for this element */
struct result res = element->convert(n, &status, style);
struct box_result res = element->convert(n, &status, style);
box = res.box;
convert_children = res.convert_children;
if (res.memory_error) {
/** \todo handle memory exhaustion */
}
if (box == 0) {
/* no box for this element */
assert(convert_children == 0);
@ -367,7 +382,7 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content,
assert(inline_container->last != 0);
inline_container->last->space = 1;
}
xfree(text);
free(text);
goto end;
}
@ -448,7 +463,7 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content,
inline_container = 0;
}
} while (*current);
xfree(text);
free(text);
goto end;
} else if (box->type == BOX_INLINE ||
@ -733,7 +748,7 @@ void box_text_transform(char *s, unsigned int len,
* be created for that element, and convert_children must be 0.
*/
struct result box_a(xmlNode *n, struct status *status,
struct box_result box_a(xmlNode *n, struct box_status *status,
struct css_style *style)
{
struct box *box;
@ -742,27 +757,27 @@ struct result box_a(xmlNode *n, struct status *status,
status->href = s;
box = box_create(style, status->href, status->title,
status->content->data.html.box_pool);
return (struct result) {box, 1};
return (struct box_result) {box, true, false};
}
struct result box_body(xmlNode *n, struct status *status,
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->content->data.html.box_pool);
return (struct result) {box, 1};
return (struct box_result) {box, true, false};
}
struct result box_br(xmlNode *n, struct status *status,
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->content->data.html.box_pool);
box->type = BOX_BR;
return (struct result) {box, 0};
return (struct box_result) {box, false, false};
}
static const content_type image_types[] = {
@ -772,7 +787,7 @@ static const content_type image_types[] = {
#endif
CONTENT_UNKNOWN };
struct result box_image(xmlNode *n, struct status *status,
struct box_result box_image(xmlNode *n, struct box_status *status,
struct css_style *style)
{
struct box *box;
@ -792,7 +807,7 @@ struct result box_image(xmlNode *n, struct status *status,
/* img without src is an error */
if (!(s = (char *) xmlGetProp(n, (const xmlChar *) "src")))
return (struct result) {box, 0};
return (struct box_result) {box, false, false};
/* imagemap associated with this image */
if ((map = xmlGetProp(n, (const xmlChar *) "usemap"))) {
@ -811,19 +826,20 @@ struct result box_image(xmlNode *n, struct status *status,
url = url_join(s1, status->content->data.html.base_url);
if (!url) {
xmlFree(s);
return (struct result) {box, 0};
return (struct box_result) {box, false, false};
}
LOG(("image '%s'", url));
xmlFree(s);
/* start fetch */
html_fetch_object(status->content, url, box, image_types);
html_fetch_object(status->content, url, box, image_types,
status->content->available_width, 1000);
return (struct result) {box, 0};
return (struct box_result) {box, false, false};
}
struct result box_form(xmlNode *n, struct status *status,
struct box_result box_form(xmlNode *n, struct box_status *status,
struct css_style *style)
{
char *s, *s2;
@ -836,7 +852,7 @@ struct result box_form(xmlNode *n, struct status *status,
s = (char *) xmlGetProp(n, (const xmlChar *) "action");
if (!s) {
/* the action attribute is required */
return (struct result) {box, 1};
return (struct box_result) {box, true, false};
}
status->current_form = form = xcalloc(1, sizeof(*form));
@ -857,10 +873,10 @@ struct result box_form(xmlNode *n, struct status *status,
form->controls = form->last_control = 0;
return (struct result) {box, 1};
return (struct box_result) {box, true, false};
}
struct result box_textarea(xmlNode *n, struct status *status,
struct box_result box_textarea(xmlNode *n, struct box_status *status,
struct css_style *style)
{
xmlChar *content, *current;
@ -870,14 +886,26 @@ struct result box_textarea(xmlNode *n, struct status *status,
box = box_create(style, NULL, 0,
status->content->data.html.box_pool);
box->type = BOX_INLINE_BLOCK;
box->gadget = xcalloc(1, sizeof(struct form_control));
box->gadget = form_new_control(GADGET_TEXTAREA);
if (!box->gadget) {
free(box);
return (struct box_result) {0, false, true};
}
box->gadget->box = box;
box->gadget->type = GADGET_TEXTAREA;
if (status->current_form)
form_add_control(status->current_form, box->gadget);
else
box->gadget->form = 0;
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "name"))) {
box->gadget->name = strdup(s);
xmlFree(s);
if (!box->gadget->name) {
box_free(box);
return (struct box_result) {0, false, true};
}
}
/* split the content at newlines and make an inline container with an
* inline box for each line */
current = content = xmlNodeGetContent(n);
@ -906,25 +934,23 @@ struct result box_textarea(xmlNode *n, struct status *status,
} while (*current);
xmlFree(content);
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "name")))
{
box->gadget->name = s;
}
return (struct result) {box, 0};
return (struct box_result) {box, false, false};
}
struct result box_select(xmlNode *n, struct status *status,
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 = xcalloc(1, sizeof(struct form_control));
struct form_control *gadget;
char* s;
xmlNode *c, *c2;
gadget->type = GADGET_SELECT;
gadget = form_new_control(GADGET_SELECT);
if (gadget)
return (struct box_result) {0, false, true};
if (status->current_form)
form_add_control(status->current_form, gadget);
else
@ -961,12 +987,17 @@ struct result box_select(xmlNode *n, struct status *status,
if (gadget->data.select.num_items == 0) {
/* no options: ignore entire select */
xfree(gadget);
return (struct result) {0, 0};
form_free_control(gadget);
return (struct box_result) {0, false, false};
}
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "name"))) {
gadget->name = s;
gadget->name = strdup(s);
xmlFree(s);
if (!gadget->name) {
form_free_control(gadget);
return (struct box_result) {0, false, true};
}
}
box = box_create(style, NULL, 0, status->content->data.html.box_pool);
@ -1002,7 +1033,7 @@ struct result box_select(xmlNode *n, struct status *status,
inline_box->length = strlen(inline_box->text);
inline_box->font = font_open(status->content->data.html.fonts, style);
return (struct result) {box, 0};
return (struct box_result) {box, false, false};
}
void add_option(xmlNode* n, struct form_control* current_select, char *text)
@ -1042,7 +1073,7 @@ void add_option(xmlNode* n, struct form_control* current_select, char *text)
}
}
struct result box_input(xmlNode *n, struct status *status,
struct box_result box_input(xmlNode *n, struct box_status *status,
struct css_style *style)
{
struct box* box = 0;
@ -1060,29 +1091,46 @@ struct result box_input(xmlNode *n, struct status *status,
box = box_create(style, NULL, 0,
status->content->data.html.box_pool);
box->type = BOX_INLINE_BLOCK;
box->gadget = gadget = xcalloc(1, sizeof(struct form_control));
box->gadget = gadget = form_new_control(GADGET_FILE);
if (!gadget) {
box_free_box(box);
xmlFree(type);
return (struct box_result) {0, false, true};
}
gadget->box = box;
gadget->type = GADGET_FILE;
box->font = font_open(status->content->data.html.fonts, style);
} else if (type && strcasecmp(type, "hidden") == 0) {
/* no box for hidden inputs */
gadget = xcalloc(1, sizeof(struct form_control));
gadget->type = GADGET_HIDDEN;
gadget = form_new_control(GADGET_HIDDEN);
if (!gadget) {
xmlFree(type);
return (struct box_result) {0, false, true};
}
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value")))
gadget->value = s;
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) {
gadget->value = strdup(s);
xmlFree(s);
if (!gadget->value) {
form_free_control(gadget);
xmlFree(type);
return (struct box_result) {0, false, true};
}
}
} else if (type && (strcasecmp(type, "checkbox") == 0 ||
strcasecmp(type, "radio") == 0)) {
box = box_create(style, NULL, 0,
status->content->data.html.box_pool);
box->gadget = gadget = xcalloc(1, sizeof(struct form_control));
box->gadget = gadget = form_new_control(GADGET_RADIO);
if (!gadget) {
box_free_box(box);
xmlFree(type);
return (struct box_result) {0, false, true};
}
gadget->box = box;
if (type[0] == 'c' || type[0] == 'C')
gadget->type = GADGET_CHECKBOX;
else
gadget->type = GADGET_RADIO;
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "checked"))) {
if (gadget->type == GADGET_CHECKBOX)
@ -1092,12 +1140,19 @@ struct result box_input(xmlNode *n, struct status *status,
xmlFree(s);
}
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value")))
gadget->value = s;
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) {
gadget->value = strdup(s);
xmlFree(s);
if (!gadget->value) {
box_free_box(box);
xmlFree(type);
return (struct box_result) {0, false, true};
}
}
} else if (type && (strcasecmp(type, "submit") == 0 ||
strcasecmp(type, "reset") == 0)) {
struct result result = box_button(n, status, style);
struct box_result result = box_button(n, status, style);
struct box *inline_container, *inline_box;
box = result.box;
inline_container = box_create(0, 0, 0,
@ -1119,7 +1174,7 @@ struct result box_input(xmlNode *n, struct status *status,
box_add_child(box, inline_container);
} else if (type && strcasecmp(type, "button") == 0) {
struct result result = box_button(n, status, style);
struct box_result result = box_button(n, status, style);
struct box *inline_container, *inline_box;
box = result.box;
inline_container = box_create(0, 0, 0,
@ -1143,14 +1198,21 @@ struct result box_input(xmlNode *n, struct status *status,
} else if (type && strcasecmp(type, "image") == 0) {
box = box_create(style, NULL, 0,
status->content->data.html.box_pool);
box->gadget = gadget = xcalloc(1, sizeof(struct form_control));
box->gadget = gadget = form_new_control(GADGET_IMAGE);
if (!gadget) {
box_free_box(box);
xmlFree(type);
return (struct box_result) {0, false, true};
}
gadget->box = box;
gadget->type = GADGET_IMAGE;
if ((s = (char *) xmlGetProp(n, (const xmlChar*) "src"))) {
url = url_join(s, status->content->data.html.base_url);
if (url)
html_fetch_object(status->content, url, box,
image_types);
image_types,
status->content->available_width,
1000);
xmlFree(s);
}
@ -1168,14 +1230,22 @@ struct result box_input(xmlNode *n, struct status *status,
if (status->current_form)
form_add_control(status->current_form, gadget);
else
gadget->form = 0;
gadget->name = (char *) xmlGetProp(n, (const xmlChar *) "name");
gadget->form = 0;
s = (char *) xmlGetProp(n, (const xmlChar *) "name");
if (s) {
gadget->name = strdup(s);
xmlFree(s);
if (!gadget->name) {
box_free_box(box);
return (struct box_result) {0, false, true};
}
}
}
return (struct result) {box, 0};
return (struct box_result) {box, false, false};
}
struct box *box_input_text(xmlNode *n, struct status *status,
struct box *box_input_text(xmlNode *n, struct box_status *status,
struct css_style *style, bool password)
{
char *s;
@ -1185,7 +1255,7 @@ struct box *box_input_text(xmlNode *n, struct status *status,
struct box *inline_container, *inline_box;
box->type = BOX_INLINE_BLOCK;
box->gadget = xcalloc(1, sizeof(struct form_control));
box->gadget = form_new_control(GADGET_TEXTBOX);
box->gadget->box = box;
box->gadget->maxlength = 100;
@ -1228,38 +1298,56 @@ struct box *box_input_text(xmlNode *n, struct status *status,
return box;
}
struct result box_button(xmlNode *n, struct status *status,
struct box_result box_button(xmlNode *n, struct box_status *status,
struct css_style *style)
{
xmlChar *s;
char *type = (char *) xmlGetProp(n, (const xmlChar *) "type");
struct box *box = box_create(style, 0, 0,
status->content->data.html.box_pool);
box->type = BOX_INLINE_BLOCK;
if (!type || strcasecmp(type, "submit") == 0) {
box->gadget = xcalloc(1, sizeof(struct form_control));
box->gadget->type = GADGET_SUBMIT;
box->gadget = form_new_control(GADGET_SUBMIT);
} else if (strcasecmp(type, "reset") == 0) {
box->gadget = xcalloc(1, sizeof(struct form_control));
box->gadget->type = GADGET_RESET;
box->gadget = form_new_control(GADGET_RESET);
} else {
/* type="button" or unknown: just render the contents */
xmlFree(type);
return (struct result) {box, 1};
return (struct box_result) {box, true, false};
}
if (type)
xmlFree(type);
if (!box->gadget) {
box_free_box(box);
return (struct box_result) {0, false, true};
}
if (status->current_form)
form_add_control(status->current_form, box->gadget);
else
box->gadget->form = 0;
box->gadget->box = box;
box->gadget->name = (char *) xmlGetProp(n, (const xmlChar *) "name");
box->gadget->value = (char *) xmlGetProp(n, (const xmlChar *) "value");
if ((s = xmlGetProp(n, (const xmlChar *) "name"))) {
box->gadget->name = strdup((char *) s);
xmlFree(s);
if (!box->gadget->name) {
box_free_box(box);
return (struct box_result) {0, false, true};
}
}
if ((s = xmlGetProp(n, (const xmlChar *) "value"))) {
box->gadget->value = strdup((char *) s);
xmlFree(s);
if (!box->gadget->value) {
box_free_box(box);
return (struct box_result) {0, false, true};
}
}
return (struct result) {box, 1};
return (struct box_result) {box, true, false};
}
@ -1476,7 +1564,7 @@ void box_normalise_table(struct box *table, pool box_pool)
}
table->columns = table_columns;
xfree(row_span);
free(row_span);
if (table->children == 0) {
LOG(("table->children == 0, removing"));
@ -1744,32 +1832,8 @@ void box_normalise_inline_container(struct box *cont, pool box_pool)
}
void gadget_free(struct form_control* g)
{
struct form_option *o, *o1;
if (g->name != 0)
xmlFree(g->name);
free(g->value);
free(g->initial_value);
if (g->type == GADGET_SELECT) {
o = g->data.select.items;
while (o != NULL)
{
if (o->text != 0)
xmlFree(o->text);
if (o->value != 0)
xmlFree(o->value);
o1 = o->next;
xfree(o);
o = o1;
}
}
}
/**
* free a box tree recursively
* Free a box tree recursively.
*/
void box_free(struct box *box)
@ -1786,13 +1850,16 @@ void box_free(struct box *box)
box_free_box(box);
}
/**
* Free a single box structure.
*/
void box_free_box(struct box *box)
{
if (!box->clone) {
if (box->gadget) {
gadget_free(box->gadget);
free(box->gadget);
}
if (box->gadget)
form_free_control(box->gadget);
free(box->href);
free(box->title);
free(box->col);
@ -1800,8 +1867,7 @@ void box_free_box(struct box *box)
free(box->style);
}
if (box->usemap)
free(box->usemap);
free(box->usemap);
free(box->text);
/* TODO: free object_params */
}
@ -1810,7 +1876,7 @@ void box_free_box(struct box *box)
/**
* add an object to the box tree
*/
struct result box_object(xmlNode *n, struct status *status,
struct box_result box_object(xmlNode *n, struct box_status *status,
struct css_style *style)
{
struct box *box;
@ -1838,7 +1904,7 @@ struct result box_object(xmlNode *n, struct status *status,
if (!url) {
free(po);
xmlFree(s);
return (struct result) {box, 1};
return (struct box_result) {box, true, true};
}
po->data = strdup(s);
LOG(("object '%s'", po->data));
@ -1941,16 +2007,16 @@ struct result box_object(xmlNode *n, struct status *status,
/* start fetch */
if (plugin_decode(status->content, url, box, po))
return (struct result) {box, 0};
return (struct box_result) {box, false, false};
return (struct result) {box, 1};
return (struct box_result) {box, true, false};
}
/**
* add an embed to the box tree
*/
struct result box_embed(xmlNode *n, struct status *status,
struct box_result box_embed(xmlNode *n, struct box_status *status,
struct css_style *style)
{
struct box *box;
@ -1978,7 +2044,7 @@ struct result box_embed(xmlNode *n, struct status *status,
if (!url) {
free(po);
xmlFree(s);
return (struct result) {box, 0};
return (struct box_result) {box, false, true};
}
LOG(("embed '%s'", url));
po->data = strdup(s);
@ -2014,14 +2080,14 @@ struct result box_embed(xmlNode *n, struct status *status,
/* start fetch */
plugin_decode(status->content, url, box, po);
return (struct result) {box,0};
return (struct box_result) {box, false, false};
}
/**
* add an applet to the box tree
*/
struct result box_applet(xmlNode *n, struct status *status,
struct box_result box_applet(xmlNode *n, struct box_status *status,
struct css_style *style)
{
struct box *box;
@ -2049,7 +2115,7 @@ struct result box_applet(xmlNode *n, struct status *status,
if (!url) {
free(po);
xmlFree(s);
return (struct result) {box, 1};
return (struct box_result) {box, true, false};
}
LOG(("applet '%s'", url));
po->classid = strdup(s);
@ -2117,9 +2183,9 @@ struct result box_applet(xmlNode *n, struct status *status,
/* start fetch */
if(plugin_decode(status->content, url, box, po))
return (struct result) {box,0};
return (struct box_result) {box, false, false};
return (struct result) {box,1};
return (struct box_result) {box, true, false};
}
/**
@ -2127,7 +2193,7 @@ struct result box_applet(xmlNode *n, struct status *status,
* add an iframe to the box tree
* TODO - implement GUI nested wimp stuff 'cos this looks naff atm. (16_5)
*/
struct result box_iframe(xmlNode *n, struct status *status,
struct box_result box_iframe(xmlNode *n, struct box_status *status,
struct css_style *style)
{
struct box *box;
@ -2153,7 +2219,7 @@ struct result box_iframe(xmlNode *n, struct status *status,
if (!url) {
free(po);
xmlFree(s);
return (struct result) {box, 0};
return (struct box_result) {box, false, true};
}
LOG(("embed '%s'", url));
po->data = strdup(s);
@ -2165,7 +2231,7 @@ struct result box_iframe(xmlNode *n, struct status *status,
/* start fetch */
plugin_decode(status->content, url, box, po);
return (struct result) {box,0};
return (struct box_result) {box, false, false};
}
/**
@ -2269,7 +2335,7 @@ bool plugin_decode(struct content* content, char* url, struct box* box,
* when we fetch it (if the type was not specified or is different to that
* given in the attributes).
*/
html_fetch_object(content, url, box, 0);
html_fetch_object(content, url, box, 0, 1000, 1000);
return true;
}
@ -2301,49 +2367,105 @@ void box_coords(struct box *box, int *x, int *y)
}
struct result box_frameset(xmlNode *n, struct status *status,
struct box_result box_frameset(xmlNode *n, struct box_status *status,
struct css_style *style)
{
unsigned int i;
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 result r;
struct box_result r;
struct box_multi_length *row_height = 0, *col_width = 0;
xmlNode *c;
box = box_create(style, 0, status->title,
status->content->data.html.box_pool);
box->type = BOX_TABLE;
/* count rows and columns */
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "rows"))) {
for (i = 0; s[i]; i++)
if (s[i] == ',')
rows++;
free(s);
}
/* parse rows and columns */
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "rows"))) {
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"))) {
for (i = 0; s[i]; i++)
if (s[i] == ',')
cols++;
free(s);
}
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "cols"))) {
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 = malloc(sizeof (struct css_style));
if (!row_style)
return (struct result) {box, 0};
if (!row_style) {
free(row_height);
free(col_width);
return (struct box_result) {box, false, true};
}
memcpy(row_style, style, sizeof (struct css_style));
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,
status->content->data.html.box_pool);
row_box->type = BOX_TABLE_ROW;
@ -2358,24 +2480,40 @@ struct result box_frameset(xmlNode *n, struct status *status,
if (!c)
break;
cell_style = malloc(sizeof (struct css_style));
if (!cell_style)
return (struct result) {box, 0};
memcpy(cell_style, style, sizeof (struct css_style));
cell_box = box_create(cell_style, 0, 0,
status->content->data.html.box_pool);
/* 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_box = box_create(style, 0, 0,
status->content->data.html.box_pool);
cell_box->type = BOX_TABLE_CELL;
cell_box->style_clone = 1;
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_box = box_create(style, 0, 0,
status->content->data.html.box_pool);
object_box->type = BOX_BLOCK;
object_box->style_clone = 1;
box_add_child(cell_box, object_box);
if (!(s = (char *) xmlGetProp(c,
(const xmlChar *) "src"))) {
c = c->next;
@ -2392,12 +2530,63 @@ struct result box_frameset(xmlNode *n, struct status *status,
LOG(("frame, url '%s'", url));
html_fetch_object(status->content, url, cell_box, 0);
html_fetch_object(status->content, url, object_box, 0,
object_width, object_height);
xmlFree(s);
c = c->next;
}
}
return (struct result) {box, 0};
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
* \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)
{
char *end;
unsigned int i, n = 1;
struct box_multi_length *length;
for (i = 0; s[i]; i++)
if (s[i] == ',')
n++;
length = malloc(sizeof *length * n);
if (!length)
return 0;
for (i = 0; i != n; i++) {
length[i].value = strtof(s, &end);
if (length[i].value <= 0)
length[i].value = 1;
s = end;
switch (*s) {
case '%': length[i].type = LENGTH_PERCENT; break;
case '*': length[i].type = LENGTH_RELATIVE; break;
default: length[i].type = LENGTH_PX; break;
}
while (*s && *s != ',')
s++;
if (*s == ',')
s++;
}
*count = n;
return length;
}

View File

@ -92,7 +92,8 @@ typedef enum {
struct column {
enum { COLUMN_WIDTH_UNKNOWN = 0, COLUMN_WIDTH_FIXED,
COLUMN_WIDTH_AUTO, COLUMN_WIDTH_PERCENT } type;
COLUMN_WIDTH_AUTO, COLUMN_WIDTH_PERCENT,
COLUMN_WIDTH_RELATIVE } type;
int min, max, width;
};

View File

@ -38,6 +38,7 @@ static void html_head(struct content *c, xmlNode *head);
static void html_find_stylesheets(struct content *c, xmlNode *head);
static void html_object_callback(content_msg msg, struct content *object,
void *p1, void *p2, union content_msg_data data);
static void html_object_done(struct box *box, struct content *object);
static bool html_object_type_permitted(const content_type type,
const content_type *permitted_types);
@ -524,7 +525,8 @@ void html_convert_css_callback(content_msg msg, struct content *css,
*/
void html_fetch_object(struct content *c, char *url, struct box *box,
const content_type *permitted_types)
const content_type *permitted_types,
int available_width, int available_height)
{
unsigned int i = c->data.html.object_count;
union content_msg_data data;
@ -539,7 +541,7 @@ void html_fetch_object(struct content *c, char *url, struct box *box,
/* start fetch */
c->data.html.object[i].content = fetchcache(url, c->url,
html_object_callback,
c, (void*)i, c->width, c->height,
c, (void*)i, available_width, available_height,
true
#ifdef WITH_POST
, 0, 0
@ -547,9 +549,8 @@ void html_fetch_object(struct content *c, char *url, struct box *box,
#ifdef WITH_COOKIES
, false
#endif
); /* we don't know the object's
dimensions yet; use
parent's as an estimate */
);
if (c->data.html.object[i].content) {
c->active++;
if (c->data.html.object[i].content->status == CONTENT_STATUS_DONE)
@ -571,7 +572,6 @@ void html_object_callback(content_msg msg, struct content *object,
unsigned int i = (unsigned int) p2;
int x, y;
struct box *box = c->data.html.object[i].box;
struct box *b;
switch (msg) {
case CONTENT_MSG_LOADING:
@ -590,53 +590,14 @@ void html_object_callback(content_msg msg, struct content *object,
break;
case CONTENT_MSG_READY:
if (object->type == CONTENT_HTML) {
html_object_done(box, object);
content_reformat(c, c->available_width, 0);
}
break;
case CONTENT_MSG_DONE:
LOG(("got object '%s'", object->url));
box->object = object;
/* retain aspect ratio of box content */
if ((box->style->width.width == CSS_WIDTH_LENGTH /*||
box->style->width.width == CSS_WIDTH_PERCENT*/) &&
box->style->height.height == CSS_HEIGHT_AUTO) {
box->style->height.height = CSS_HEIGHT_LENGTH;
box->style->height.length.unit = CSS_UNIT_PX;
if (box->style->width.width == CSS_WIDTH_LENGTH) {
box->style->height.length.value = object->height * (box->style->width.value.length.value / object->width);
}
/*else {
box->style->height.length.value = object->height * (box->style->width.value.percent / 100);
}*/
box->height = box->style->height.length.value;
}
if (box->style->height.height == CSS_HEIGHT_LENGTH &&
box->style->width.width == CSS_WIDTH_AUTO) {
box->style->width.width = CSS_WIDTH_LENGTH;
box->style->width.value.length.unit = CSS_UNIT_PX;
box->style->width.value.length.value = object->width * (box->style->height.length.value / object->height);
box->min_width = box->max_width = box->width = box->style->width.value.length.value;
}
/* set dimensions to object dimensions if auto */
if (box->style->width.width == CSS_WIDTH_AUTO) {
box->style->width.width = CSS_WIDTH_LENGTH;
box->style->width.value.length.unit = CSS_UNIT_PX;
box->style->width.value.length.value = object->width;
box->min_width = box->max_width = box->width = object->width;
}
if (box->style->height.height == CSS_HEIGHT_AUTO) {
box->style->height.height = CSS_HEIGHT_LENGTH;
box->style->height.length.unit = CSS_UNIT_PX;
box->style->height.length.value = object->height;
box->height = object->height;
}
/* invalidate parent min, max widths */
for (b = box->parent; b; b = b->parent)
b->max_width = UNKNOWN_MAX_WIDTH;
/* delete any clones of this box */
while (box->next && box->next->clone) {
/* box_free_box(box->next); */
box->next = box->next->next;
}
html_object_done(box, object);
c->active--;
break;
@ -714,7 +675,12 @@ void html_object_callback(content_msg msg, struct content *object,
assert(0);
}
if (c->status == CONTENT_STATUS_READY && c->active == 0) {
if (c->status == CONTENT_STATUS_READY && c->active == 0 &&
(msg == CONTENT_MSG_LOADING ||
msg == CONTENT_MSG_DONE ||
msg == CONTENT_MSG_ERROR ||
msg == CONTENT_MSG_REDIRECT ||
msg == CONTENT_MSG_AUTH)) {
/* all objects have arrived */
content_reformat(c, c->available_width, 0);
c->status = CONTENT_STATUS_DONE;
@ -727,6 +693,32 @@ void html_object_callback(content_msg msg, struct content *object,
}
/**
* Update a box whose content has completed rendering.
*/
void html_object_done(struct box *box, struct content *object)
{
struct box *b;
box->object = object;
if (box->width != UNKNOWN_WIDTH &&
object->available_width != box->width)
content_reformat(object, box->width, box->height);
/* invalidate parent min, max widths */
for (b = box->parent; b; b = b->parent)
b->max_width = UNKNOWN_MAX_WIDTH;
/* delete any clones of this box */
while (box->next && box->next->clone) {
/* box_free_box(box->next); */
box->next = box->next->next;
}
}
/**
* Check if a type is in a list.
*

View File

@ -88,7 +88,8 @@ void html_revive(struct content *c, unsigned int width, unsigned int height);
void html_reformat(struct content *c, unsigned int width, unsigned int height);
void html_destroy(struct content *c);
void html_fetch_object(struct content *c, char *url, struct box *box,
const content_type *permitted_types);
const content_type *permitted_types,
int available_width, int available_height);
/* in riscos/htmlinstance.c */
void html_add_instance(struct content *c, struct browser_window *bw,

View File

@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include "netsurf/css/css.h"
#include "netsurf/content/content.h"
#ifdef riscos
#include "netsurf/desktop/gui.h"
#endif
@ -59,7 +60,12 @@ static void place_float_below(struct box *c, int width, int cx, int y,
struct box *cont);
static void layout_table(struct box *box, int available_width);
static void calculate_widths(struct box *box);
static void calculate_block_widths(struct box *box, int *min, int *max,
int *max_sum);
static void calculate_inline_container_widths(struct box *box);
static void calculate_inline_replaced_widths(struct box *box, int *min,
int *max, int *line_max);
static void calculate_inline_widths(struct box *box, int *min, int *line_max);
static void calculate_table_widths(struct box *table);
@ -267,6 +273,8 @@ void layout_block_context(struct box *block)
/**
* Compute dimensions of box, margins, paddings, and borders for a block-level
* element.
*
* See CSS 2.1 10.3.3, 10.3.4, 10.6.2, and 10.6.3.
*/
void layout_block_find_dimensions(int available_width, struct box *box)
@ -291,11 +299,6 @@ void layout_block_find_dimensions(int available_width, struct box *box)
break;
}
layout_find_dimensions(available_width, style, margin, padding, border);
box->width = layout_solve_width(available_width, width, margin,
padding, border);
/* height */
switch (style->height.height) {
case CSS_HEIGHT_LENGTH:
@ -307,6 +310,40 @@ void layout_block_find_dimensions(int available_width, struct box *box)
break;
}
if (box->object) {
/* block-level replaced element, see 10.3.4 and 10.6.2 */
if (width == AUTO && box->height == AUTO) {
width = box->object->width;
box->height = box->object->height;
} else if (width == AUTO) {
if (box->object->height)
width = box->object->width *
(float) box->height /
box->object->height;
else
width = box->object->width;
} else if (box->height == AUTO) {
if (box->object->width)
box->height = box->object->height *
(float) width /
box->object->width;
else
box->height = box->object->height;
}
}
layout_find_dimensions(available_width, style, margin, padding, border);
box->width = layout_solve_width(available_width, width, margin,
padding, border);
if (box->object && box->object->type == CONTENT_HTML &&
box->width != box->object->available_width) {
content_reformat(box->object, box->width, box->height);
if (style->height.height == CSS_HEIGHT_AUTO)
box->height = box->object->height;
}
if (margin[TOP] == AUTO)
margin[TOP] = 0;
if (margin[BOTTOM] == AUTO)
@ -377,16 +414,7 @@ void layout_float_find_dimensions(int available_width,
break;
case CSS_WIDTH_AUTO:
default:
/* CSS 2.1 section 10.3.5 */
available_width -= box->margin[LEFT] + box->border[LEFT] +
box->padding[LEFT] + box->padding[RIGHT] +
box->border[RIGHT] + box->margin[RIGHT];
if (box->min_width < available_width)
box->width = available_width;
else
box->width = box->min_width;
if (box->max_width < box->width)
box->width = box->max_width;
box->width = AUTO;
break;
}
@ -401,6 +429,30 @@ void layout_float_find_dimensions(int available_width,
break;
}
if (box->object) {
/* floating replaced element, see 10.3.6 and 10.6.2 */
if (box->width == AUTO && box->height == AUTO) {
box->width = box->object->width;
box->height = box->object->height;
} else if (box->width == AUTO)
box->width = box->object->width * (float) box->height /
box->object->height;
else if (box->height == AUTO)
box->height = box->object->height * (float) box->width /
box->object->width;
} else if (box->width == AUTO) {
/* CSS 2.1 section 10.3.5 */
available_width -= box->margin[LEFT] + box->border[LEFT] +
box->padding[LEFT] + box->padding[RIGHT] +
box->border[RIGHT] + box->margin[RIGHT];
if (box->min_width < available_width)
box->width = available_width;
else
box->width = box->min_width;
if (box->max_width < box->width)
box->width = box->max_width;
}
if (box->margin[TOP] == AUTO)
box->margin[TOP] = 0;
if (box->margin[BOTTOM] == AUTO)
@ -653,34 +705,87 @@ struct box * layout_line(struct box *first, int width, int *y,
if (b->type != BOX_INLINE)
continue;
if ((b->object || b->gadget) && b->style &&
b->style->height.height == CSS_HEIGHT_LENGTH)
h = len(&b->style->height.length, b->style);
else
h = line_height(b->style ? b->style :
if (!b->object && !b->gadget) {
/* inline non-replaced, 10.3.1 and 10.6.1 */
b->height = line_height(b->style ? b->style :
b->parent->parent->style);
b->height = h;
if (height < b->height)
height = b->height;
if (height < h)
height = h;
if (b->text) {
if (b->width == UNKNOWN_WIDTH)
b->width = font_width(b->font, b->text,
b->length);
x += b->width + b->space ?
b->font->space_width : 0;
} else
b->width = 0;
if ((b->object || b->gadget) && b->style &&
b->style->width.width == CSS_WIDTH_LENGTH)
b->width = len(&b->style->width.value.length, b->style);
else if ((b->object || b->gadget) && b->style &&
b->style->width.width == CSS_WIDTH_PERCENT)
b->width = width * b->style->width.value.percent / 100;
else if (b->text) {
if (b->width == UNKNOWN_WIDTH)
b->width = font_width(b->font, b->text,
b->length);
} else
b->width = 0;
continue;
}
if (b->text)
x += b->width + b->space ? b->font->space_width : 0;
else
x += b->width;
/* inline replaced, 10.3.2 and 10.6.2 */
assert(b->style);
/* calculate box width */
switch (b->style->width.width) {
case CSS_WIDTH_LENGTH:
b->width = len(&b->style->width.value.length,
b->style);
break;
case CSS_WIDTH_PERCENT:
b->width = width *
b->style->width.value.percent /
100;
break;
case CSS_WIDTH_AUTO:
default:
b->width = AUTO;
break;
}
/* height */
switch (b->style->height.height) {
case CSS_HEIGHT_LENGTH:
b->height = len(&b->style->height.length,
b->style);
break;
case CSS_HEIGHT_AUTO:
default:
b->height = AUTO;
break;
}
if (b->width == AUTO && b->height == AUTO) {
b->width = b->object->width;
b->height = b->object->height;
} else if (b->width == AUTO) {
if (b->object->height)
b->width = b->object->width *
(float) b->height /
b->object->height;
else
b->width = b->object->width;
} else if (b->height == AUTO) {
if (b->object->width)
b->height = b->object->height *
(float) b->width /
b->object->width;
else
b->height = b->object->height;
}
if (b->object && b->object->type == CONTENT_HTML &&
b->width != b->object->available_width) {
content_reformat(b->object, b->width, b->height);
if (b->style->height.height == CSS_HEIGHT_AUTO)
b->height = b->object->height;
}
if (height < b->height)
height = b->height;
x += b->width;
}
/* find new sides using this height */
@ -691,11 +796,11 @@ struct box * layout_line(struct box *first, int width, int *y,
x0 -= cx;
x1 -= cx;
if (indent)
x0 += layout_text_indent(first->parent->parent->style, width);
if (indent)
x0 += layout_text_indent(first->parent->parent->style, width);
if (x1 < x0)
x1 = x0;
if (x1 < x0)
x1 = x0;
/* pass 2: place boxes in line: loop body executed at least once */
for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
@ -984,7 +1089,7 @@ void place_float_below(struct box *c, int width, int cx, int y,
/**
* layout a table
* Layout a table.
*/
void layout_table(struct box *table, int available_width)
@ -999,6 +1104,8 @@ void layout_table(struct box *table, int available_width)
int table_height = 0;
int *xs; /* array of column x positions */
int auto_width;
int spare_width;
int relative_sum = 0;
struct box *c;
struct box *row;
struct box *row_group;
@ -1059,6 +1166,8 @@ void layout_table(struct box *table, int available_width)
/* table narrower than required width for columns:
* treat percentage widths as maximums */
for (i = 0; i != columns; i++) {
if (col[i].type == COLUMN_WIDTH_RELATIVE)
continue;
if (col[i].type == COLUMN_WIDTH_PERCENT) {
col[i].max = auto_width * col[i].width / 100;
if (col[i].max < col[i].min)
@ -1070,6 +1179,8 @@ void layout_table(struct box *table, int available_width)
} else {
/* take percentages exactly */
for (i = 0; i != columns; i++) {
if (col[i].type == COLUMN_WIDTH_RELATIVE)
continue;
if (col[i].type == COLUMN_WIDTH_PERCENT) {
int width = auto_width * col[i].width / 100;
if (width < col[i].min)
@ -1082,6 +1193,25 @@ void layout_table(struct box *table, int available_width)
}
}
/* allocate relative widths */
spare_width = auto_width;
for (i = 0; i != columns; i++) {
if (col[i].type == COLUMN_WIDTH_RELATIVE)
relative_sum += col[i].width;
else
spare_width -= col[i].width;
}
if (spare_width < 0)
spare_width = 0;
for (i = 0; i != columns; i++) {
if (col[i].type == COLUMN_WIDTH_RELATIVE) {
col[i].min = col[i].max = (float) spare_width *
(float) col[i].width / relative_sum;
min_width += col[i].min;
max_width += col[i].max;
}
}
if (auto_width <= min_width) {
/* not enough space: minimise column widths */
for (i = 0; i < columns; i++) {
@ -1227,7 +1357,7 @@ void layout_table(struct box *table, int available_width)
void calculate_widths(struct box *box)
{
struct box *child;
int min = 0, max = 0, width, extra_fixed = 0;
int min = 0, max = 0, extra_fixed = 0;
float extra_frac = 0;
unsigned int side;
struct css_style *style = box->style;
@ -1244,25 +1374,15 @@ void calculate_widths(struct box *box)
switch (child->type) {
case BOX_BLOCK:
case BOX_TABLE:
if (child->type == BOX_TABLE)
calculate_table_widths(child);
else
calculate_widths(child);
if (child->style->width.width == CSS_WIDTH_LENGTH) {
width = len(&child->style->width.value.length,
child->style);
if (min < width) min = width;
if (max < width) max = width;
} else {
if (min < child->min_width) min = child->min_width;
if (max < child->max_width) max = child->max_width;
}
calculate_block_widths(child, &min, &max, 0);
break;
case BOX_INLINE_CONTAINER:
calculate_inline_container_widths(child);
if (min < child->min_width) min = child->min_width;
if (max < child->max_width) max = child->max_width;
if (min < child->min_width)
min = child->min_width;
if (max < child->max_width)
max = child->max_width;
break;
default:
@ -1299,72 +1419,78 @@ void calculate_widths(struct box *box)
}
/**
* Find min, max widths for a BOX_BLOCK, BOX_INLINE_BLOCK, BOX_FLOAT_*,
* or BOX_TABLE.
*
* \param box BLOCK, INLINE_BLOCK, FLOAT, or TABLE box
* \param min current min, updated to new min
* \param max current max, updated to new max
* \param max_sum sum of maximum widths, updated, or 0 if not required
*/
void calculate_block_widths(struct box *box, int *min, int *max,
int *max_sum)
{
int width;
if (box->type == BOX_TABLE)
calculate_table_widths(box);
else
calculate_widths(box);
if (box->style->width.width == CSS_WIDTH_LENGTH) {
width = len(&box->style->width.value.length, box->style);
if (*min < width) *min = width;
if (*max < width) *max = width;
if (max_sum) *max_sum += width;
} else if (box->style->width.width == CSS_WIDTH_AUTO && box->object) {
/* replaced element */
if (box->style->height.height == CSS_HEIGHT_AUTO)
width = box->object->width;
else
width = box->object->width *
(float) len(&box->style->height.length,
box->style) / box->object->height;
if (*min < width) *min = width;
if (*max < width) *max = width;
if (max_sum) *max_sum += width;
} else {
if (*min < box->min_width) *min = box->min_width;
if (*max < box->max_width) *max = box->max_width;
if (max_sum) *max_sum += box->max_width;
}
}
/**
* Find min, max width for an inline container.
*/
void calculate_inline_container_widths(struct box *box)
{
struct box *child;
int min = 0, max = 0, line_max = 0, width;
unsigned int i, j;
int min = 0, max = 0, line_max = 0;
for (child = box->children; child != 0; child = child->next) {
switch (child->type) {
case BOX_INLINE:
if (child->object || child->gadget) {
if (child->style->width.width == CSS_WIDTH_LENGTH) {
child->width = len(&child->style->width.value.length,
child->style);
line_max += child->width;
if (min < child->width)
min = child->width;
}
} else if (child->text) {
/* max = all one line */
child->width = font_width(child->font,
child->text, child->length);
line_max += child->width;
if (child->next && child->space)
line_max += child->font->space_width;
/* min = widest word */
i = 0;
do {
for (j = i; j != child->length && child->text[j] != ' '; j++)
;
width = font_width(child->font, child->text + i, (j - i));
if (min < width) min = width;
i = j + 1;
} while (j != child->length);
}
if (child->object || child->gadget)
calculate_inline_replaced_widths(child,
&min, &max, &line_max);
else if (child->text)
calculate_inline_widths(child,
&min, &line_max);
break;
case BOX_INLINE_BLOCK:
calculate_widths(child);
if (child->style != 0 &&
child->style->width.width == CSS_WIDTH_LENGTH) {
width = len(&child->style->width.value.length,
child->style);
if (min < width) min = width;
line_max += width;
} else {
if (min < child->min_width) min = child->min_width;
line_max += child->max_width;
}
calculate_block_widths(child, &min, &max,
&line_max);
break;
case BOX_FLOAT_LEFT:
case BOX_FLOAT_RIGHT:
calculate_widths(child);
if (child->style != 0 &&
child->style->width.width == CSS_WIDTH_LENGTH) {
width = len(&child->style->width.value.length,
child->style);
if (min < width) min = width;
if (max < width) max = width;
} else {
if (min < child->min_width) min = child->min_width;
if (max < child->max_width) max = child->max_width;
}
calculate_block_widths(child, &min, &max, 0);
break;
case BOX_BR:
@ -1392,6 +1518,63 @@ void calculate_inline_container_widths(struct box *box)
}
/**
* Find min, max width for an inline replaced box.
*/
void calculate_inline_replaced_widths(struct box *box, int *min,
int *max, int *line_max)
{
int width;
if (box->style->width.width == CSS_WIDTH_LENGTH) {
box->width = len(&box->style->width.value.length, box->style);
*line_max += box->width;
if (*min < box->width)
*min = box->width;
} else if (box->style->width.width == CSS_WIDTH_AUTO) {
if (box->style->height.height == CSS_HEIGHT_AUTO)
width = box->object->width;
else
width = box->object->width *
(float) len(&box->style->height.length,
box->style) / box->object->height;
if (*min < width) *min = width;
if (*max < width) *max = width;
}
}
/**
* Find min, max width for an inline text box.
*/
void calculate_inline_widths(struct box *box, int *min, int *line_max)
{
unsigned int i, j;
int width;
/* max = all one line */
box->width = font_width(box->font, box->text, box->length);
*line_max += box->width;
if (box->next && box->space)
*line_max += box->font->space_width;
/* min = widest word */
i = 0;
do {
for (j = i; j != box->length && box->text[j] != ' '; j++)
;
width = font_width(box->font, box->text + i, (j - i));
if (*min < width) *min = width;
i = j + 1;
} while (j != box->length);
}
/**
* Find min, max widths for a table and determine column width types.
*/
void calculate_table_widths(struct box *table)
{
@ -1406,8 +1589,9 @@ void calculate_table_widths(struct box *table)
if (table->max_width != UNKNOWN_MAX_WIDTH)
return;
free(table->col);
table->col = col = xcalloc(table->columns, sizeof(*col));
if (!table->col)
table->col = xcalloc(table->columns, sizeof(*col));
col = table->col;
assert(table->children != 0 && table->children->children != 0);