diff --git a/css/css.c b/css/css.c index 76c7e6ca5..aeeec4084 100644 --- a/css/css.c +++ b/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"); diff --git a/css/css.h b/css/css.h index a48d97ef8..b3ff34ea0 100644 --- a/css/css.h +++ b/css/css.h @@ -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 { diff --git a/css/ruleset.c b/css/ruleset.c index 4529fba8d..d04f62359 100644 --- a/css/ruleset.c +++ b/css/ruleset.c @@ -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; } diff --git a/render/box.c b/render/box.c index 1d72da607..023c444cc 100644 --- a/render/box.c +++ b/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, diff --git a/render/box.h b/render/box.h index c1cce449f..c66767225 100644 --- a/render/box.h +++ b/render/box.h @@ -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; diff --git a/render/box_construct.c b/render/box_construct.c index fb605209b..94ca2ef57 100644 --- a/render/box_construct.c +++ b/render/box_construct.c @@ -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); } diff --git a/render/layout.c b/render/layout.c index 1bf77fbcf..faffd750b 100644 --- a/render/layout.c +++ b/render/layout.c @@ -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",