Implement percentage heights for block level elements in normal flow, floats and positioned boxes. Percentage min/max-height not yet handled.

svn path=/trunk/netsurf/; revision=5550
This commit is contained in:
Michael Drake 2008-10-12 21:22:28 +00:00
parent c1db0e90cc
commit b7a1b3999e
7 changed files with 142 additions and 79 deletions

View File

@ -180,7 +180,7 @@ const struct css_style css_base_style = {
CSS_FONT_STYLE_NORMAL,
CSS_FONT_VARIANT_NORMAL,
CSS_FONT_WEIGHT_NORMAL,
{ CSS_HEIGHT_AUTO, { 1, CSS_UNIT_EM } },
{ CSS_HEIGHT_AUTO, { { 1, CSS_UNIT_EM } } },
{ CSS_LETTER_SPACING_NORMAL, { 0, CSS_UNIT_PX } },
{ CSS_LINE_HEIGHT_ABSOLUTE, { 1.33 } },
{ CSS_LIST_STYLE_IMAGE_NONE, 0 },
@ -265,7 +265,7 @@ const struct css_style css_empty_style = {
CSS_FONT_STYLE_NOT_SET,
CSS_FONT_VARIANT_NOT_SET,
CSS_FONT_WEIGHT_NOT_SET,
{ CSS_HEIGHT_NOT_SET, { 1, CSS_UNIT_EM } },
{ CSS_HEIGHT_NOT_SET, { { 1, CSS_UNIT_EM } } },
{ CSS_LETTER_SPACING_NOT_SET, { 0, CSS_UNIT_PX } },
{ CSS_LINE_HEIGHT_NOT_SET, { 1.33 } },
{ CSS_LIST_STYLE_IMAGE_NOT_SET, 0 },
@ -351,7 +351,7 @@ const struct css_style css_blank_style = {
CSS_FONT_STYLE_INHERIT,
CSS_FONT_VARIANT_INHERIT,
CSS_FONT_WEIGHT_INHERIT,
{ CSS_HEIGHT_AUTO, { 1, CSS_UNIT_EM } },
{ CSS_HEIGHT_AUTO, { { 1, CSS_UNIT_EM } } },
{ CSS_LETTER_SPACING_INHERIT, { 0, CSS_UNIT_PX } },
{ CSS_LINE_HEIGHT_INHERIT, { 1.33 } },
{ CSS_LIST_STYLE_IMAGE_INHERIT, 0 },
@ -1903,7 +1903,11 @@ void css_dump_style(FILE *stream, const struct css_style * const style)
fprintf(stream, "auto");
break;
case CSS_HEIGHT_LENGTH:
css_dump_length(stream, &style->height.length);
css_dump_length(stream, &style->height.value.length);
break;
case CSS_HEIGHT_PERCENT:
fprintf(stream, "%g%%",
style->height.value.percent);
break;
default:
fprintf(stream, "UNKNOWN");

View File

@ -279,8 +279,12 @@ struct css_style {
enum { CSS_HEIGHT_INHERIT,
CSS_HEIGHT_AUTO,
CSS_HEIGHT_LENGTH,
CSS_HEIGHT_PERCENT,
CSS_HEIGHT_NOT_SET } height;
struct css_length length;
union {
struct css_length length;
float percent;
} value;
} height;
struct {

View File

@ -2228,8 +2228,11 @@ void parse_height(struct css_style * const s, const struct css_node * const v)
if (v->type == CSS_NODE_IDENT && v->data_length == 4 &&
strncasecmp(v->data, "auto", 4) == 0)
s->height.height = CSS_HEIGHT_AUTO;
else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) &&
parse_length(&s->height.length, v, true) == 0)
else if (v->type == CSS_NODE_PERCENTAGE) {
s->height.height = CSS_HEIGHT_PERCENT;
s->height.value.percent = atof(v->data);
} else if ((v->type == CSS_NODE_DIMENSION || v->type == CSS_NODE_NUMBER) &&
parse_length(&s->height.value.length, v, true) == 0)
s->height.height = CSS_HEIGHT_LENGTH;
}

View File

@ -102,6 +102,7 @@ struct box * box_create(struct css_style *style,
box->fallback = NULL;
box->inline_end = NULL;
box->float_children = NULL;
box->float_container = NULL;
box->next_float = NULL;
box->list_marker = NULL;
box->col = NULL;
@ -551,7 +552,7 @@ void box_dump(FILE *stream, struct box *box, unsigned int depth)
fprintf(stream, "(%i %i %i %i) ",
box->descendant_x0, box->descendant_y0,
box->descendant_x1, box->descendant_y1);
fprintf(stream, "m(%i %i %i %i) ",
box->margin[TOP], box->margin[LEFT],
box->margin[BOTTOM], box->margin[RIGHT]);
@ -685,9 +686,9 @@ struct box* box_duplicate_tree(struct box *root, struct content *c)
struct box *new_root;/**< Root of the new box tree*/
int box_number = 0;
struct box_dict_element *box_dict, *box_dict_end;
box_duplicate_last = NULL;
/* 1. Duplicate parent - children structure, list_markers*/
new_root = talloc_memdup(c, root, sizeof (struct box));
if (!box_duplicate_main_tree(new_root, c, &box_number))
@ -695,32 +696,32 @@ struct box* box_duplicate_tree(struct box *root, struct content *c)
/* 2. Create address translation dictionary*/
/*TODO: dont save unnecessary addresses*/
box_dict_end = box_dict = malloc(box_number *
sizeof(struct box_dict_element));
if (box_dict == NULL)
return NULL;
box_duplicate_create_dict(root, new_root, &box_dict_end);
assert((box_dict_end - box_dict) == box_number);
/*3. Sort it*/
qsort(box_dict, (box_dict_end - box_dict), sizeof(struct box_dict_element),
(int (*)(const void *, const void *))box_compare_dict_elements);
/* 4. Update inline_end and float_children pointers */
box_duplicate_update(new_root, box_dict, (box_dict_end - box_dict));
free(box_dict);
return new_root;
}
/**
* Recursively duplicates children of an element, and also if present - its
* Recursively duplicates children of an element, and also if present - its
* list_marker, style and text.
* \param box Current box to duplicate its children
* \param c talloc memory pool
@ -730,9 +731,9 @@ struct box* box_duplicate_tree(struct box *root, struct content *c)
bool box_duplicate_main_tree(struct box *box, struct content *c, int *count)
{
struct box *b, *prev;
prev = NULL;
for (b = box->children; b; b = b->next) {
struct box *copy;
@ -740,14 +741,14 @@ bool box_duplicate_main_tree(struct box *box, struct content *c, int *count)
copy = talloc_memdup(c, b, sizeof (struct box));
if (copy == NULL)
return false;
copy->parent = box;
if (prev != NULL)
prev->next = copy;
else
box->children = copy;
if (copy->type == BOX_INLINE) {
struct box_duplicate_llist *temp;
@ -763,21 +764,21 @@ bool box_duplicate_main_tree(struct box *box, struct content *c, int *count)
box_duplicate_last->box->inline_end = copy;
copy->inline_end = box_duplicate_last->box;
temp = box_duplicate_last;
box_duplicate_last = temp->prev;
free(temp);
}
/* Recursively visit child */
if (!box_duplicate_main_tree(copy, c, count))
return false;
prev = copy;
}
box->last = prev;
if (box->object && option_suppress_images && (
#ifdef WITH_JPEG
box->object->type == CONTENT_JPEG ||
@ -817,27 +818,27 @@ bool box_duplicate_main_tree(struct box *box, struct content *c, int *count)
#endif
false))
box->object = NULL;
if (box->list_marker) {
box->list_marker = talloc_memdup(c, box->list_marker,
sizeof *box->list_marker);
if (box->list_marker == NULL)
if (box->list_marker == NULL)
return false;
box->list_marker->parent = box;
}
if (box->text) {
box->text = talloc_memdup(c, box->text, box->length);
if (box->text == NULL)
if (box->text == NULL)
return false;
}
if (box->style) {
box->style = talloc_memdup(c, box->style, sizeof *box->style);
if (box->style == NULL)
if (box->style == NULL)
return false;
}
/*Make layout calculate the size of this element later
(might change because of font change etc.) */
box->width = UNKNOWN_WIDTH;
@ -845,7 +846,7 @@ bool box_duplicate_main_tree(struct box *box, struct content *c, int *count)
box->max_width = UNKNOWN_MAX_WIDTH;
(*count)++;
return true;
}
@ -861,15 +862,15 @@ void box_duplicate_create_dict(struct box *old_box, struct box *new_box,
{
/**Children of the old and new boxes*/
struct box *b_old, *b_new;
for (b_old = old_box->children, b_new = new_box->children;
b_old != NULL && b_new != NULL;
b_old = b_old->next, b_new = b_new->next)
box_duplicate_create_dict(b_old, b_new, dict);
/*The new tree should be a exact copy*/
assert(b_old == NULL && b_new == NULL);
(*dict)->old = old_box;
(*dict)->new = new_box;
(*dict)++;
@ -888,10 +889,10 @@ void box_duplicate_update(struct box *box,
struct box_dict_element *box_dict_element;
struct box *b;
struct box_dict_element element;
for (b = box->children; b; b = b->next)
box_duplicate_update(b, box_dict, n);
if (box->float_children) {
element.old = box->float_children;
box_dict_element = bsearch(&element,
@ -900,7 +901,7 @@ void box_duplicate_update(struct box *box,
(int (*)(const void *, const void *))box_compare_dict_elements);
box->float_children = box_dict_element->new;
}
if (box->next_float) {
element.old = box->next_float;
box_dict_element = bsearch(&element,

View File

@ -190,7 +190,7 @@ struct box {
unsigned int start_column; /**< Start column for TABLE_CELL only. */
bool printed; /** Whether this box has already been printed*/
struct box *next; /**< Next sibling box, or 0. */
struct box *prev; /**< Previous sibling box, or 0. */
struct box *children; /**< First child box, or 0. */
@ -207,6 +207,8 @@ struct box {
struct box *float_children;
/** Next sibling float box. */
struct box *next_float;
/** If box is a float, points to box's containing block */
struct box *float_container;
/** Level below which subsequent floats must be cleared.
* This is used only for boxes with float_children */
int clear_level;

View File

@ -583,9 +583,14 @@ bool box_construct_element(xmlNode *n, struct content *content,
float current;
for (child = box->children; child;
child = child->next) {
current = css_len2px(
if (child->style->height.height ==
CSS_HEIGHT_LENGTH)
current = css_len2px(
&child->style->height.
length, child->style);
value.length,
child->style);
else
current = 0;
if (child->type == BOX_TABLE_CELL &&
value > current) {
/* Row height exceeds cell
@ -593,10 +598,11 @@ bool box_construct_element(xmlNode *n, struct content *content,
* to row height */
child->style->height.height =
CSS_HEIGHT_LENGTH;
child->style->height.length.
unit = CSS_UNIT_PX;
child->style->height.length.
value = value;
child->style->height.value.
length.unit =
CSS_UNIT_PX;
child->style->height.value.
length.value = value;
}
}
}
@ -932,8 +938,8 @@ struct css_style * box_get_style(struct content *c,
* percentage heights mean, so ignore them */
} else {
style->height.height = CSS_HEIGHT_LENGTH;
style->height.length.unit = CSS_UNIT_PX;
style->height.length.value = value;
style->height.value.length.unit = CSS_UNIT_PX;
style->height.value.length.value = value;
}
xmlFree(s);
}
@ -1027,8 +1033,8 @@ struct css_style * box_get_style(struct content *c,
int value = isdigit(s[0]) ? atoi(s): -1;
if (0 < value) {
style->height.height = CSS_HEIGHT_LENGTH;
style->height.length.unit = CSS_UNIT_EM;
style->height.length.value = value;
style->height.value.length.unit = CSS_UNIT_EM;
style->height.value.length.value = value;
}
xmlFree(s);
}

View File

@ -308,6 +308,9 @@ bool layout_block_context(struct box *block, struct content *content)
(box->style->position == CSS_POSITION_ABSOLUTE||
box->style->position == CSS_POSITION_FIXED)) {
box->x = box->parent->padding[LEFT];
layout_find_dimensions(box->parent->width, box,
box->style, NULL, &(box->height), NULL,
NULL, NULL, NULL, NULL);
/* absolute positioned; this element will establish
* its own block context when it gets laid out later,
* so no need to look at its children now. */
@ -974,8 +977,8 @@ void layout_float_find_dimensions(int available_width,
* \param max_width updated to max-width, may be NULL
* \param min_width updated to min-width, may be NULL
* \param margin[4] filled with margins, may be NULL
* \param padding[4] filled with paddings
* \param border[4] filled with border widths
* \param padding[4] filled with paddings, may be NULL
* \param border[4] filled with border widths, may be NULL
*/
void layout_find_dimensions(int available_width,
@ -983,6 +986,7 @@ void layout_find_dimensions(int available_width,
int *width, int *height, int *max_width, int *min_width,
int margin[4], int padding[4], int border[4])
{
struct box *containing_block = NULL;
unsigned int i;
int fixed = 0;
float frac = 0;
@ -1015,7 +1019,33 @@ void layout_find_dimensions(int available_width,
if (height) {
switch (style->height.height) {
case CSS_HEIGHT_LENGTH:
*height = css_len2px(&style->height.length, style);
*height = css_len2px(&style->height.value.length,
style);
break;
case CSS_HEIGHT_PERCENT:
if (box->float_container) {
containing_block = box->float_container;
} else if (box->parent && box->parent->type !=
BOX_INLINE_CONTAINER) {
containing_block = box->parent;
} else if (box->parent && box->parent->type ==
BOX_INLINE_CONTAINER) {
assert(box->parent->parent);
containing_block = box->parent->parent;
}
if (box->style->position == CSS_POSITION_ABSOLUTE ||
(containing_block &&
(containing_block->style->height.
height == CSS_HEIGHT_LENGTH ||
containing_block->style->height.
height == CSS_HEIGHT_PERCENT) &&
containing_block->height != AUTO)) {
*height = style->height.value.percent *
containing_block->height / 100;
} else {
/* else treated as auto; fall though */
*height = AUTO;
}
break;
case CSS_HEIGHT_AUTO:
default:
@ -1094,25 +1124,31 @@ void layout_find_dimensions(int available_width,
}
}
switch (style->padding[i].padding) {
case CSS_PADDING_PERCENT:
padding[i] = available_width *
style->padding[i].value.percent / 100;
break;
case CSS_PADDING_LENGTH:
default:
padding[i] = css_len2px(&style->padding[i].
value.length, style);
break;
if (padding) {
switch (style->padding[i].padding) {
case CSS_PADDING_PERCENT:
padding[i] = available_width *
style->padding[i].value.
percent / 100;
break;
case CSS_PADDING_LENGTH:
default:
padding[i] = css_len2px(&style->padding[i].
value.length, style);
break;
}
}
if (style->border[i].style == CSS_BORDER_STYLE_HIDDEN ||
style->border[i].style == CSS_BORDER_STYLE_NONE)
/* spec unclear: following Mozilla */
border[i] = 0;
else
border[i] = css_len2px(&style->border[i].
width.value, style);
if (border) {
if (style->border[i].style == CSS_BORDER_STYLE_HIDDEN ||
style->border[i].style ==
CSS_BORDER_STYLE_NONE)
/* spec unclear: following Mozilla */
border[i] = 0;
else
border[i] = css_len2px(&style->border[i].
width.value, style);
}
}
}
@ -1536,7 +1572,7 @@ bool layout_line(struct box *first, int *width, int *y,
/* height */
switch (b->style->height.height) {
case CSS_HEIGHT_LENGTH:
b->height = css_len2px(&b->style->height.length,
b->height = css_len2px(&b->style->height.value.length,
b->style);
break;
case CSS_HEIGHT_AUTO:
@ -1735,6 +1771,7 @@ bool layout_line(struct box *first, int *width, int *y,
box_dump(stderr, cont, 0);
assert(0);
}
b->float_container = d->float_container = cont;
b->next_float = cont->float_children;
cont->float_children = b;
split_box = 0;
@ -2104,7 +2141,8 @@ struct box *layout_minmax_line(struct box *first,
/* height */
switch (b->style->height.height) {
case CSS_HEIGHT_LENGTH:
height = css_len2px(&b->style->height.length, b->style);
height = css_len2px(&b->style->height.value.length,
b->style);
break;
case CSS_HEIGHT_AUTO:
default:
@ -2553,7 +2591,7 @@ bool layout_table(struct box *table, int available_width,
* to attempt to make cells as small as
* possible, so treat it as a minimum */
int h = (int) css_len2px(&c->style->
height.length, c->style);
height.value.length, c->style);
if (c->height < h)
c->height = h;
}
@ -2673,7 +2711,7 @@ bool layout_table(struct box *table, int available_width,
/* Take account of any table height specified within CSS/HTML */
if (style->height.height == CSS_HEIGHT_LENGTH) {
/* This is the minimum height for the table (see 17.5.3) */
int min_height = css_len2px(&style->height.length, style);
int min_height = css_len2px(&style->height.value.length, style);
table->height = max(table_height, min_height);
} else {
@ -3205,9 +3243,14 @@ bool layout_absolute(struct box *box, struct box *containing_block,
layout_compute_offsets(box, containing_block,
&top, &right, &bottom, &left);
/* Pass containing block into layout_find_dimensions via the float
* containing block box member. This is unused for absolutly positioned
* boxes because a box can't be floated and absolutly positioned. */
box->float_container = containing_block;
layout_find_dimensions(available_width, box, box->style,
&width, &height, &max_width, &min_width,
margin, padding, border);
box->float_container = NULL;
/* 10.3.7 */
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",