mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-11-22 22:41:30 +03:00
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:
parent
c1db0e90cc
commit
b7a1b3999e
12
css/css.c
12
css/css.c
@ -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");
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
75
render/box.c
75
render/box.c
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user