From ddeadd1c02880367ad786b113d352a519f45ec73 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Thu, 23 Jul 2009 23:05:34 +0000 Subject: Merge LibCSS port to trunk. svn path=/trunk/netsurf/; revision=8752 --- render/layout.c | 1558 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 941 insertions(+), 617 deletions(-) (limited to 'render/layout.c') diff --git a/render/layout.c b/render/layout.c index 4d9adc468..411d6755e 100644 --- a/render/layout.c +++ b/render/layout.c @@ -40,6 +40,7 @@ #include #include #include "css/css.h" +#include "css/utils.h" #include "content/content.h" #include "desktop/gui.h" #include "desktop/options.h" @@ -47,6 +48,7 @@ #include "render/font.h" #include "render/form.h" #include "render/layout.h" +#include "render/table.h" #define NDEBUG #include "utils/log.h" #undef NDEBUG @@ -69,36 +71,36 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container); static void layout_block_add_scrollbar(struct box *box, int which); static int layout_solve_width(int available_width, int width, int lm, int rm, int max_width, int min_width, - int margin[4], int padding[4], int border[4]); + int margin[4], int padding[4], struct box_border border[4]); static void layout_float_find_dimensions(int available_width, - struct css_style *style, struct box *box); + const css_computed_style *style, struct box *box); static void layout_find_dimensions(int available_width, int viewport_height, - struct box *box, struct css_style *style, + struct box *box, const css_computed_style *style, int *width, int *height, int *max_width, int *min_width, - int margin[4], int padding[4], int border[4]); + int margin[4], int padding[4], struct box_border border[4]); static void layout_tweak_form_dimensions(struct box *box, bool percentage, int available_width, bool setwidth, int *dimension); -static int layout_clear(struct box *fl, css_clear clear); +static int layout_clear(struct box *fl, enum css_clear clear); static void find_sides(struct box *fl, int y0, int y1, int *x0, int *x1, struct box **left, struct box **right); static void layout_minmax_inline_container(struct box *inline_container, const struct font_functions *font_func); -static int line_height(struct css_style *style); +static int line_height(const css_computed_style *style); static bool layout_line(struct box *first, int *width, int *y, int cx, int cy, struct box *cont, bool indent, bool has_text_children, struct content *content, struct box **next_box); static struct box *layout_minmax_line(struct box *first, int *min, int *max, const struct font_functions *font_func); -static int layout_text_indent(struct css_style *style, int width); +static int layout_text_indent(const css_computed_style *style, int width); static bool layout_float(struct box *b, int width, struct content *content); static void place_float_below(struct box *c, int width, int cx, int y, struct box *cont); static bool layout_table(struct box *box, int available_width, struct content *content); static void layout_move_children(struct box *box, int x, int y); -static void calculate_mbp_width(struct css_style *style, unsigned int side, - bool margin, bool border, bool padding, +static void calculate_mbp_width(const css_computed_style *style, + unsigned int side, bool margin, bool border, bool padding, int *fixed, float *frac); static void layout_lists(struct box *box, const struct font_functions *font_func); @@ -137,11 +139,11 @@ bool layout_document(struct content *content, int width, int height) layout_minmax_block(doc, font_func); layout_block_find_dimensions(width, height, 0, 0, doc); - doc->x = doc->margin[LEFT] + doc->border[LEFT]; - doc->y = doc->margin[TOP] + doc->border[TOP]; - width -= doc->margin[LEFT] + doc->border[LEFT] + doc->padding[LEFT] + - doc->padding[RIGHT] + doc->border[RIGHT] + - doc->margin[RIGHT]; + doc->x = doc->margin[LEFT] + doc->border[LEFT].width; + doc->y = doc->margin[TOP] + doc->border[TOP].width; + width -= doc->margin[LEFT] + doc->border[LEFT].width + + doc->padding[LEFT] + doc->padding[RIGHT] + + doc->border[RIGHT].width + doc->margin[RIGHT]; if (width < 0) width = 0; doc->width = width; @@ -150,18 +152,19 @@ bool layout_document(struct content *content, int width, int height) /* make and fill available height */ if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] + - doc->border[BOTTOM] + doc->margin[BOTTOM] < + doc->border[BOTTOM].width + doc->margin[BOTTOM] < height) { doc->height = height - (doc->y + doc->padding[TOP] + - doc->padding[BOTTOM] + doc->border[BOTTOM] + + doc->padding[BOTTOM] + + doc->border[BOTTOM].width + doc->margin[BOTTOM]); if (doc->children) doc->children->height = doc->height - (doc->children->margin[TOP] + - doc->children->border[TOP] + + doc->children->border[TOP].width + doc->children->padding[TOP] + doc->children->padding[BOTTOM] + - doc->children->border[BOTTOM] + + doc->children->border[BOTTOM].width + doc->children->margin[BOTTOM]); } @@ -197,7 +200,8 @@ bool layout_block_context(struct box *block, int viewport_height, int y = 0; int lm, rm; struct box *margin_box; - struct css_length gadget_size; /* Checkbox / radio buttons */ + css_fixed gadget_size; + css_unit gadget_unit; /* Checkbox / radio buttons */ assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK || @@ -267,10 +271,11 @@ bool layout_block_context(struct box *block, int viewport_height, block->gadget->type == GADGET_CHECKBOX)) { /* form checkbox or radio button * if width or height is AUTO, set it to 1em */ - gadget_size.unit = CSS_UNIT_EM; - gadget_size.value = 1; + gadget_unit = CSS_UNIT_EM; + gadget_size = INTTOFIX(1); if (block->height == AUTO) - block->height = css_len2px(&gadget_size, block->style); + block->height = FIXTOINT(nscss_len2px(gadget_size, + gadget_unit, block->style)); } box = margin_box = block->children; @@ -317,8 +322,10 @@ bool layout_block_context(struct box *block, int viewport_height, */ if (box->style && - (box->style->position == CSS_POSITION_ABSOLUTE|| - box->style->position == CSS_POSITION_FIXED)) { + (css_computed_position(box->style) == + CSS_POSITION_ABSOLUTE || + css_computed_position(box->style) == + CSS_POSITION_FIXED)) { box->x = box->parent->padding[LEFT]; /* absolute positioned; this element will establish * its own block context when it gets laid out later, @@ -328,9 +335,10 @@ bool layout_block_context(struct box *block, int viewport_height, /* Clearance. */ y = 0; - if (box->style && box->style->clear != CSS_CLEAR_NONE) + if (box->style && css_computed_clear(box->style) != + CSS_CLEAR_NONE) y = layout_clear(block->float_children, - box->style->clear); + css_computed_clear(box->style)); /* Get top margin */ if (box->style) { @@ -351,7 +359,7 @@ bool layout_block_context(struct box *block, int viewport_height, if (box->type == BOX_BLOCK || box->object) { if (!box->object && box->style && - box->style->overflow != + css_computed_overflow(box->style) != CSS_OVERFLOW_VISIBLE) { /* box establishes new block formatting context * so available width may be diminished due to @@ -381,7 +389,13 @@ bool layout_block_context(struct box *block, int viewport_height, layout_block_add_scrollbar(box, BOTTOM); } } else if (box->type == BOX_TABLE) { - if (box->style->width.width == CSS_WIDTH_AUTO) { + enum css_width wtype; + css_fixed width = 0; + css_unit unit = CSS_UNIT_PX; + + wtype = css_computed_width(box->style, &width, &unit); + + if (wtype == CSS_WIDTH_AUTO) { /* max available width may be diminished due to * floats. */ int x0, x1, top; @@ -412,18 +426,18 @@ bool layout_block_context(struct box *block, int viewport_height, /* Position box: horizontal. */ box->x = box->parent->padding[LEFT] + box->margin[LEFT] + - box->border[LEFT]; + box->border[LEFT].width; cx += box->x; /* Position box: vertical. */ if (box->type != BOX_BLOCK || y || - box->border[TOP] || box->padding[TOP]) { + box->border[TOP].width || box->padding[TOP]) { margin_box->y += max_pos_margin - max_neg_margin; cy += max_pos_margin - max_neg_margin; max_pos_margin = max_neg_margin = 0; margin_box = 0; - box->y += box->border[TOP]; - cy += box->border[TOP]; + box->y += box->border[TOP].width; + cy += box->border[TOP].width; if (cy < y) { box->y += y - cy; cy = y; @@ -433,7 +447,8 @@ bool layout_block_context(struct box *block, int viewport_height, /* Unless the box has an overflow style of visible, the box * establishes a new block context. */ if (box->type == BOX_BLOCK && box->style && - box->style->overflow != CSS_OVERFLOW_VISIBLE) { + css_computed_overflow(box->style) != + CSS_OVERFLOW_VISIBLE) { cy += max_pos_margin - max_neg_margin; box->y += max_pos_margin - max_neg_margin; @@ -449,7 +464,7 @@ bool layout_block_context(struct box *block, int viewport_height, cx -= box->x; cy += box->height + box->padding[BOTTOM] + - box->border[BOTTOM]; + box->border[BOTTOM].width; max_pos_margin = max_neg_margin = 0; if (max_pos_margin < box->margin[BOTTOM]) max_pos_margin = box->margin[BOTTOM]; @@ -457,7 +472,7 @@ bool layout_block_context(struct box *block, int viewport_height, max_neg_margin = -box->margin[BOTTOM]; y = box->y + box->padding[TOP] + box->height + box->padding[BOTTOM] + - box->border[BOTTOM]; + box->border[BOTTOM].width; /* Skip children, because they are done in the new * block context */ goto advance_to_next_box; @@ -480,12 +495,19 @@ bool layout_block_context(struct box *block, int viewport_height, struct box *left, *right; y = cy; while (1) { + enum css_width wtype; + css_fixed width = 0; + css_unit unit = CSS_UNIT_PX; + + wtype = css_computed_width(box->style, + &width, &unit); + x0 = cx; x1 = cx + box->parent->width; find_sides(block->float_children, y, y + box->height, &x0, &x1, &left, &right); - if (box->style->width.width == CSS_WIDTH_AUTO) + if (wtype == CSS_WIDTH_AUTO) break; if (box->width <= x1 - x0) break; @@ -527,7 +549,8 @@ bool layout_block_context(struct box *block, int viewport_height, layout_block_add_scrollbar(box, BOTTOM); } - cy += box->height + box->padding[BOTTOM] + box->border[BOTTOM]; + cy += box->height + box->padding[BOTTOM] + + box->border[BOTTOM].width; max_pos_margin = max_neg_margin = 0; if (max_pos_margin < box->margin[BOTTOM]) max_pos_margin = box->margin[BOTTOM]; @@ -535,7 +558,8 @@ bool layout_block_context(struct box *block, int viewport_height, max_neg_margin = -box->margin[BOTTOM]; cx -= box->x; y = box->y + box->padding[TOP] + box->height + - box->padding[BOTTOM] + box->border[BOTTOM]; + box->padding[BOTTOM] + + box->border[BOTTOM].width; advance_to_next_box: if (!box->next) { /* No more siblings: @@ -556,7 +580,8 @@ bool layout_block_context(struct box *block, int viewport_height, /* Apply any min-height and max-height to * boxes in normal flow */ - if (box->style && box->style->position != + if (box->style && + css_computed_position(box->style) != CSS_POSITION_ABSOLUTE && layout_apply_minmax_height(box, NULL)) { @@ -567,7 +592,7 @@ bool layout_block_context(struct box *block, int viewport_height, } cy += box->padding[BOTTOM] + - box->border[BOTTOM]; + box->border[BOTTOM].width; if (max_pos_margin < box->margin[BOTTOM]) max_pos_margin = box->margin[BOTTOM]; else if (max_neg_margin < -box->margin[BOTTOM]) @@ -575,7 +600,7 @@ bool layout_block_context(struct box *block, int viewport_height, cx -= box->x; y = box->y + box->padding[TOP] + box->height + box->padding[BOTTOM] + - box->border[BOTTOM]; + box->border[BOTTOM].width; } while (box != block && !box->next); if (box == block) break; @@ -589,7 +614,7 @@ bool layout_block_context(struct box *block, int viewport_height, /* Increase height to contain any floats inside (CSS 2.1 10.6.7). */ for (box = block->float_children; box; box = box->next_float) { y = box->y + box->height + box->padding[BOTTOM] + - box->border[BOTTOM] + box->margin[BOTTOM]; + box->border[BOTTOM].width + box->margin[BOTTOM]; if (cy < y) cy = y; } @@ -600,7 +625,8 @@ bool layout_block_context(struct box *block, int viewport_height, layout_block_add_scrollbar(block, BOTTOM); } - if (block->style && block->style->position != CSS_POSITION_ABSOLUTE) { + if (block->style && css_computed_position(block->style) != + CSS_POSITION_ABSOLUTE) { /* Block is in normal flow */ layout_apply_minmax_height(block, NULL); } @@ -624,12 +650,9 @@ void layout_minmax_block(struct box *block, int min = 0, max = 0; int extra_fixed = 0; float extra_frac = 0; - struct css_length size; - struct css_length gadget_size; /* Checkbox / radio buttons */ - size.unit = CSS_UNIT_EM; - size.value = 10; - gadget_size.unit = CSS_UNIT_EM; - gadget_size.value = 1; + enum css_width wtype; + css_fixed width = 0; + css_unit wunit = CSS_UNIT_PX; assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK || @@ -639,22 +662,28 @@ void layout_minmax_block(struct box *block, if (block->max_width != UNKNOWN_MAX_WIDTH) return; + wtype = css_computed_width(block->style, &width, &wunit); + if (block->gadget && (block->gadget->type == GADGET_TEXTBOX || block->gadget->type == GADGET_PASSWORD || block->gadget->type == GADGET_FILE || block->gadget->type == GADGET_TEXTAREA) && - block->style && - block->style->width.width == CSS_WIDTH_AUTO) { - min = max = css_len2px(&size, block->style); + block->style && wtype == CSS_WIDTH_AUTO) { + css_fixed size = INTTOFIX(10); + css_unit unit = CSS_UNIT_EM; + + min = max = FIXTOINT(nscss_len2px(size, unit, block->style)); } if (block->gadget && (block->gadget->type == GADGET_RADIO || block->gadget->type == GADGET_CHECKBOX) && - block->style && - block->style->width.width == CSS_WIDTH_AUTO) { + block->style && wtype == CSS_WIDTH_AUTO) { + css_fixed size = INTTOFIX(1); + css_unit unit = CSS_UNIT_EM; + /* form checkbox or radio button * if width is AUTO, set it to 1em */ - min = max = css_len2px(&gadget_size, block->style); + min = max = FIXTOINT(nscss_len2px(size, unit, block->style)); } if (block->object) { @@ -686,9 +715,9 @@ void layout_minmax_block(struct box *block, assert(child->max_width != UNKNOWN_MAX_WIDTH); if (child->style && - (child->style->position == + (css_computed_position(child->style) == CSS_POSITION_ABSOLUTE || - child->style->position == + css_computed_position(child->style) == CSS_POSITION_FIXED)) { /* This child is positioned out of normal flow, * so it will have no affect on width */ @@ -708,18 +737,16 @@ void layout_minmax_block(struct box *block, } /* fixed width takes priority */ - if (block->type != BOX_TABLE_CELL && - block->style->width.width == CSS_WIDTH_LENGTH) { - min = max = css_len2px(&block->style->width.value.length, - block->style); + if (block->type != BOX_TABLE_CELL && wtype == CSS_WIDTH_SET && + wunit != CSS_UNIT_PCT) { + min = max = FIXTOINT(nscss_len2px(width, wunit, block->style)); } /* add margins, border, padding to min, max widths */ - if (block->gadget && (block->style->width.width == CSS_WIDTH_PERCENT || - (block->style->width.width == CSS_WIDTH_LENGTH && + if (block->gadget && wtype == CSS_WIDTH_SET && (block->gadget->type == GADGET_SUBMIT || block->gadget->type == GADGET_RESET || - block->gadget->type == GADGET_BUTTON)))) { + block->gadget->type == GADGET_BUTTON)) { /* some gadgets with specified width already include border and * padding, so just get margin */ calculate_mbp_width(block->style, LEFT, true, false, false, @@ -799,8 +826,8 @@ void layout_block_find_dimensions(int available_width, int viewport_height, int height; int *margin = box->margin; int *padding = box->padding; - int *border = box->border; - struct css_style *style = box->style; + struct box_border *border = box->border; + const css_computed_style *style = box->style; layout_find_dimensions(available_width, viewport_height, box, style, &width, &height, &max_width, &min_width, @@ -854,13 +881,13 @@ bool layout_apply_minmax_height(struct box *box, struct box *container) bool updated = false; /* Find containing block for percentage heights */ - if (box->style->position == CSS_POSITION_ABSOLUTE) { + if (css_computed_position(box->style) == CSS_POSITION_ABSOLUTE) { /* Box is absolutely positioned */ assert(container); containing_block = container; } else if (box->float_container && - (box->style->float_ == CSS_FLOAT_LEFT || - box->style->float_ == CSS_FLOAT_RIGHT)) { + (css_computed_float(box->style) == CSS_FLOAT_LEFT || + css_computed_float(box->style) == CSS_FLOAT_RIGHT)) { /* Box is a float */ assert(box->parent && box->parent->parent && box->parent->parent->parent); @@ -875,72 +902,73 @@ bool layout_apply_minmax_height(struct box *box, struct box *container) } if (box->style) { + enum css_height htype = CSS_HEIGHT_AUTO; + css_fixed length = 0; + css_unit unit = CSS_UNIT_PX; + + if (containing_block) { + htype = css_computed_height(containing_block->style, + &length, &unit); + } + /* max-height */ - switch (box->style->max_height.max_height) { - case CSS_MAX_HEIGHT_LENGTH: - h = css_len2px(&box->style->max_height.value.length, - box->style); - if (h < box->height) { - box->height = h; - updated = true; - } - break; - case CSS_MAX_HEIGHT_PERCENT: - if (containing_block && + if (css_computed_max_height(box->style, &length, &unit) == + CSS_MAX_HEIGHT_SET) { + if (unit == CSS_UNIT_PCT) { + if (containing_block && containing_block->height != AUTO && - (box->style->position == + (css_computed_position(box->style) == CSS_POSITION_ABSOLUTE || - (containing_block->style->height. - height == CSS_HEIGHT_LENGTH || - containing_block->style->height. - height == CSS_HEIGHT_PERCENT))) { - /* Box is absolutely positioned or its - * containing block has a valid specified - * height. (CSS 2.1 Section 10.5) */ - h = box->style->max_height.value.percent * + htype == CSS_HEIGHT_SET)) { + /* Box is absolutely positioned or its + * containing block has a valid + * specified height. (CSS 2.1 + * Section 10.5) */ + h = FIXTOFLT(length) * containing_block->height / 100; + if (h < box->height) { + box->height = h; + updated = true; + } + } + } else { + h = FIXTOINT(nscss_len2px(length, unit, + box->style)); if (h < box->height) { box->height = h; updated = true; } } - break; - default: - break; } /* min-height */ - switch (box->style->min_height.min_height) { - case CSS_MIN_HEIGHT_LENGTH: - h = css_len2px(&box->style->min_height.value.length, - box->style); - if (h > box->height) { - box->height = h; - updated = true; - } - break; - case CSS_MIN_HEIGHT_PERCENT: - if (containing_block && + if (css_computed_min_height(box->style, &length, &unit) == + CSS_MIN_HEIGHT_SET) { + if (unit == CSS_UNIT_PCT) { + if (containing_block && containing_block->height != AUTO && - (box->style->position == + (css_computed_position(box->style) == CSS_POSITION_ABSOLUTE || - (containing_block->style->height. - height == CSS_HEIGHT_LENGTH || - containing_block->style->height. - height == CSS_HEIGHT_PERCENT))) { - /* Box is absolutely positioned or its - * containing block has a valid specified - * height. (CSS 2.1 Section 10.5) */ - h = box->style->min_height.value.percent * + htype == CSS_HEIGHT_SET)) { + /* Box is absolutely positioned or its + * containing block has a valid + * specified height. (CSS 2.1 + * Section 10.5) */ + h = FIXTOFLT(length) * containing_block->height / 100; + if (h > box->height) { + box->height = h; + updated = true; + } + } + } else { + h = FIXTOINT(nscss_len2px(length, unit, + box->style)); if (h > box->height) { box->height = h; updated = true; } } - break; - default: - break; } } return updated; @@ -955,18 +983,24 @@ bool layout_apply_minmax_height(struct box *box, struct box *container) void layout_block_add_scrollbar(struct box *box, int which) { + enum css_overflow overflow; + assert(box->type == BOX_BLOCK && (which == RIGHT || which == BOTTOM)); - if (box->style && (box->style->overflow == CSS_OVERFLOW_SCROLL || - box->style->overflow == CSS_OVERFLOW_AUTO)) { + if (box->style == NULL) + return; + + overflow = css_computed_overflow(box->style); + + if (overflow == CSS_OVERFLOW_SCROLL || overflow == CSS_OVERFLOW_AUTO) { /* make space for scrollbars, unless height/width are AUTO */ if (which == BOTTOM && box->height != AUTO && - (box->style->overflow == CSS_OVERFLOW_SCROLL || + (overflow == CSS_OVERFLOW_SCROLL || box_hscrollbar_present(box))) { box->padding[BOTTOM] += SCROLLBAR_WIDTH; } if (which == RIGHT && box->width != AUTO && - (box->style->overflow == CSS_OVERFLOW_SCROLL || + (overflow == CSS_OVERFLOW_SCROLL || box_vscrollbar_present(box))) { box->width -= SCROLLBAR_WIDTH; box->padding[RIGHT] += SCROLLBAR_WIDTH; @@ -987,16 +1021,14 @@ void layout_block_add_scrollbar(struct box *box, int which) * \param min_width Box min-width ( <=0 means no min-width to apply) * \param margin[4] Current box margins. Updated with new box * left / right margins - * \param padding[4] Current box paddings. Updated with new box - * left / right paddings - * \param border[4] Current box border widths. Updated with new - * box left / right border widths + * \param padding[4] Current box paddings. + * \param border[4] Current box border widths. * \return New box width */ int layout_solve_width(int available_width, int width, int lm, int rm, int max_width, int min_width, - int margin[4], int padding[4], int border[4]) + int margin[4], int padding[4], struct box_border border[4]) { bool auto_width = false; @@ -1013,8 +1045,9 @@ int layout_solve_width(int available_width, int width, int lm, int rm, if (margin[RIGHT] == AUTO) margin[RIGHT] = rm; width = available_width - - (margin[LEFT] + border[LEFT] + padding[LEFT] + - padding[RIGHT] + border[RIGHT] + margin[RIGHT]); + (margin[LEFT] + border[LEFT].width + + padding[LEFT] + padding[RIGHT] + + border[RIGHT].width + margin[RIGHT]); width = width < 0 ? 0 : width; auto_width = true; } @@ -1032,8 +1065,8 @@ int layout_solve_width(int available_width, int width, int lm, int rm, if (!auto_width && margin[LEFT] == AUTO && margin[RIGHT] == AUTO) { /* make the margins equal, centering the element */ margin[LEFT] = margin[RIGHT] = (available_width - lm - rm - - (border[LEFT] + padding[LEFT] + width + - padding[RIGHT] + border[RIGHT])) / 2; + (border[LEFT].width + padding[LEFT] + width + + padding[RIGHT] + border[RIGHT].width)) / 2; if (margin[LEFT] < 0) { margin[RIGHT] += margin[LEFT]; @@ -1044,14 +1077,16 @@ int layout_solve_width(int available_width, int width, int lm, int rm, } else if (!auto_width && margin[LEFT] == AUTO) { margin[LEFT] = available_width - lm - - (border[LEFT] + padding[LEFT] + width + - padding[RIGHT] + border[RIGHT] + margin[RIGHT]); + (border[LEFT].width + padding[LEFT] + width + + padding[RIGHT] + border[RIGHT].width + + margin[RIGHT]); margin[LEFT] = margin[LEFT] < lm ? lm : margin[LEFT]; } else if (!auto_width) { /* margin-right auto or "over-constrained" */ margin[RIGHT] = available_width - rm - - (margin[LEFT] + border[LEFT] + padding[LEFT] + - width + padding[RIGHT] + border[RIGHT]); + (margin[LEFT] + border[LEFT].width + + padding[LEFT] + width + padding[RIGHT] + + border[RIGHT].width); } return width; @@ -1070,14 +1105,15 @@ int layout_solve_width(int available_width, int width, int lm, int rm, */ void layout_float_find_dimensions(int available_width, - struct css_style *style, struct box *box) + const css_computed_style *style, struct box *box) { int width, height, max_width, min_width; int *margin = box->margin; int *padding = box->padding; - int *border = box->border; - int scrollbar_width = (style->overflow == CSS_OVERFLOW_SCROLL || - style->overflow == CSS_OVERFLOW_AUTO) ? + struct box_border *border = box->border; + int scrollbar_width = + (css_computed_overflow(style) == CSS_OVERFLOW_SCROLL || + css_computed_overflow(style) == CSS_OVERFLOW_AUTO) ? SCROLLBAR_WIDTH : 0; layout_find_dimensions(available_width, -1, box, style, &width, &height, @@ -1107,44 +1143,49 @@ void layout_float_find_dimensions(int available_width, box->gadget->type == GADGET_PASSWORD || box->gadget->type == GADGET_FILE || box->gadget->type == GADGET_TEXTAREA)) { - struct css_length size; + css_fixed size = 0; + css_unit unit = CSS_UNIT_EM; + /* Give sensible dimensions to gadgets, with auto width/height, * that don't shrink to fit contained text. */ assert(box->style); - size.unit = CSS_UNIT_EM; if (box->gadget->type == GADGET_TEXTBOX || box->gadget->type == GADGET_PASSWORD || box->gadget->type == GADGET_FILE) { if (width == AUTO) { - size.value = 10; - width = css_len2px(&size, box->style); + size = INTTOFIX(10); + width = FIXTOINT(nscss_len2px(size, unit, + box->style)); } if (box->gadget->type == GADGET_FILE && height == AUTO) { - size.value = 1.5; - height = css_len2px(&size, box->style); + size = FLTTOFIX(1.5); + height = FIXTOINT(nscss_len2px(size, unit, + box->style)); } } if (box->gadget->type == GADGET_TEXTAREA) { if (width == AUTO) { - size.value = 10; - width = css_len2px(&size, box->style); + size = INTTOFIX(10); + width = FIXTOINT(nscss_len2px(size, unit, + box->style)); } else { width -= scrollbar_width; } if (height == AUTO) { - size.value = 4; - height = css_len2px(&size, box->style); + size = INTTOFIX(4); + height = FIXTOINT(nscss_len2px(size, unit, + box->style)); } } } else if (width == AUTO) { /* CSS 2.1 section 10.3.5 */ width = min(max(box->min_width, available_width), box->max_width); - width -= box->margin[LEFT] + box->border[LEFT] + + width -= box->margin[LEFT] + box->border[LEFT].width + box->padding[LEFT] + box->padding[RIGHT] + - box->border[RIGHT] + box->margin[RIGHT]; + box->border[RIGHT].width + box->margin[RIGHT]; if (max_width >= 0 && width > max_width) width = max_width; if (min_width > 0 && width < min_width) width = min_width; @@ -1183,33 +1224,37 @@ void layout_float_find_dimensions(int available_width, */ void layout_find_dimensions(int available_width, int viewport_height, - struct box *box, struct css_style *style, + struct box *box, const css_computed_style *style, int *width, int *height, int *max_width, int *min_width, - int margin[4], int padding[4], int border[4]) + int margin[4], int padding[4], struct box_border border[4]) { struct box *containing_block = NULL; unsigned int i; bool percentage; if (width) { - switch (style->width.width) { - case CSS_WIDTH_LENGTH: - *width = css_len2px(&style->width.value.length, style); - break; - case CSS_WIDTH_PERCENT: - *width = (style->width.value.percent * - available_width) / 100; - break; - case CSS_WIDTH_AUTO: - default: + enum css_width wtype; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + wtype = css_computed_width(style, &value, &unit); + + if (wtype == CSS_WIDTH_SET) { + if (unit == CSS_UNIT_PCT) { + *width = (FIXTOFLT(value) * available_width) + / 100; + } else { + *width = FIXTOINT(nscss_len2px(value, unit, + style)); + } + } else { *width = AUTO; - break; } /* specified gadget widths include borders and padding in some * cases */ if (box->gadget && *width != AUTO) { - percentage = style->width.width == CSS_WIDTH_PERCENT; + percentage = unit == CSS_UNIT_PCT; layout_tweak_form_dimensions(box, percentage, available_width, true, width); @@ -1217,72 +1262,91 @@ void layout_find_dimensions(int available_width, int viewport_height, } if (height) { - switch (style->height.height) { - case CSS_HEIGHT_LENGTH: - *height = css_len2px(&style->height.value.length, - style); - break; - case CSS_HEIGHT_PERCENT: - if (box->style->position == CSS_POSITION_ABSOLUTE) { - /* Box is absolutely positioned */ - assert(box->float_container); - containing_block = box->float_container; - } else if (box->float_container && - box->style->position != - CSS_POSITION_ABSOLUTE && - (box->style->float_ == - CSS_FLOAT_LEFT || - box->style->float_ == - CSS_FLOAT_RIGHT)) { - /* Box is a float */ - assert(box->parent && box->parent->parent && + enum css_height htype; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + htype = css_computed_height(style, &value, &unit); + + if (htype == CSS_HEIGHT_SET) { + if (unit == CSS_UNIT_PCT) { + enum css_height cbhtype; + + if (css_computed_position(box->style) == + CSS_POSITION_ABSOLUTE) { + /* Box is absolutely positioned */ + assert(box->float_container); + containing_block = box->float_container; + } else if (box->float_container && + css_computed_position(box->style) != + CSS_POSITION_ABSOLUTE && + (css_computed_float(box->style) == + CSS_FLOAT_LEFT || + css_computed_float(box->style) == + CSS_FLOAT_RIGHT)) { + /* Box is a float */ + assert(box->parent && + box->parent->parent && box->parent->parent->parent); - containing_block = box->parent->parent->parent; - } else if (box->parent && box->parent->type != - BOX_INLINE_CONTAINER) { - /* Box is a block level element */ - containing_block = box->parent; - } else if (box->parent && box->parent->type == - BOX_INLINE_CONTAINER) { - /* Box is an inline block */ - assert(box->parent->parent); - containing_block = box->parent->parent; - } - if (containing_block && + + containing_block = + box->parent->parent->parent; + } else if (box->parent && box->parent->type != + BOX_INLINE_CONTAINER) { + /* Box is a block level element */ + containing_block = box->parent; + } else if (box->parent && box->parent->type == + BOX_INLINE_CONTAINER) { + /* Box is an inline block */ + assert(box->parent->parent); + containing_block = box->parent->parent; + } + + if (containing_block) { + css_fixed f = 0; + css_unit u = CSS_UNIT_PX; + + cbhtype = css_computed_height( + containing_block->style, + &f, &u); + } + + if (containing_block && containing_block->height != AUTO && - (box->style->position == + (css_computed_position(box->style) == CSS_POSITION_ABSOLUTE || - (containing_block->style->height. - height == CSS_HEIGHT_LENGTH || - containing_block->style->height. - height == CSS_HEIGHT_PERCENT))) { - /* Box is absolutely positioned or its - * containing block has a valid specified - * height. (CSS 2.1 Section 10.5) */ - *height = style->height.value.percent * - containing_block->height / 100; - } else if ((!box->parent || !box->parent->parent) && - viewport_height >= 0) { - /* If root element or it's child - * (HTML or BODY) */ - *height = style->height.value.percent * - viewport_height / 100; + cbhtype == CSS_HEIGHT_SET)) { + /* Box is absolutely positioned or its + * containing block has a valid + * specified height. + * (CSS 2.1 Section 10.5) */ + *height = FIXTOFLT(value) * + containing_block->height / + 100; + } else if ((!box->parent || + !box->parent->parent) && + viewport_height >= 0) { + /* If root element or it's child + * (HTML or BODY) */ + *height = FIXTOFLT(value) * + viewport_height / 100; + } else { + /* precentage height not permissible + * treat height as auto */ + *height = AUTO; + } } else { - /* precentage height not permissible - * treat height as auto */ - *height = AUTO; + *height = FIXTOINT(nscss_len2px(value, unit, + style)); } - break; - case CSS_HEIGHT_AUTO: - default: + } else { *height = AUTO; - break; } /* specified gadget heights include borders and padding in * some cases */ if (box->gadget && *height != AUTO) { - percentage = style->height.height == CSS_HEIGHT_PERCENT; + percentage = unit == CSS_UNIT_PCT; layout_tweak_form_dimensions(box, percentage, available_width, false, height); @@ -1290,53 +1354,60 @@ void layout_find_dimensions(int available_width, int viewport_height, } if (max_width) { - switch (style->max_width.max_width) { - case CSS_MAX_WIDTH_LENGTH: - *max_width = css_len2px(&style->max_width.value.length, - style); - break; - case CSS_MAX_WIDTH_PERCENT: - *max_width = (style->max_width.value.percent * - available_width) / 100; - break; - case CSS_MAX_WIDTH_NONE: - default: + enum css_max_width type; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + type = css_computed_max_width(style, &value, &unit); + + if (type == CSS_MAX_WIDTH_SET) { + if (unit == CSS_UNIT_PCT) { + *max_width = (FIXTOFLT(value) * + available_width) / 100; + } else { + *max_width = FIXTOINT(nscss_len2px(value, unit, + style)); + } + } else { /* Inadmissible */ *max_width = -1; - break; } /* specified gadget widths include borders and padding in some * cases */ if (box->gadget && *max_width != -1) { - percentage = style->max_width.max_width == - CSS_WIDTH_PERCENT; + percentage = unit == CSS_UNIT_PCT; + layout_tweak_form_dimensions(box, percentage, available_width, true, max_width); } } if (min_width) { - switch (style->min_width.min_width) { - case CSS_MIN_WIDTH_LENGTH: - *min_width = css_len2px(&style->min_width.value. - length, style); - break; - case CSS_MIN_WIDTH_PERCENT: - *min_width = (style->min_width.value.percent * + enum css_min_width type; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + type = css_computed_min_width(style, &value, &unit); + + if (type == CSS_MIN_WIDTH_SET) { + if (unit == CSS_UNIT_PCT) { + *min_width = (FIXTOFLT(value) * available_width) / 100; - break; - default: + } else { + *min_width = FIXTOINT(nscss_len2px(value, unit, + style)); + } + } else { /* Inadmissible */ *min_width = 0; - break; } /* specified gadget widths include borders and padding in some * cases */ if (box->gadget && *min_width != 0) { - percentage = style->min_width.min_width == - CSS_WIDTH_PERCENT; + percentage = unit == CSS_UNIT_PCT; + layout_tweak_form_dimensions(box, percentage, available_width, true, min_width); } @@ -1344,46 +1415,137 @@ void layout_find_dimensions(int available_width, int viewport_height, for (i = 0; i != 4; i++) { if (margin) { - switch (style->margin[i].margin) { - case CSS_MARGIN_LENGTH: - margin[i] = css_len2px(&style->margin[i]. - value.length, style); + enum css_margin type = CSS_MARGIN_AUTO;; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + switch (i) { + case TOP: + type = css_computed_margin_top(style, + &value, &unit); break; - case CSS_MARGIN_PERCENT: - margin[i] = available_width * - style->margin[i].value.percent / 100; + case RIGHT: + type = css_computed_margin_right(style, + &value, &unit); break; - case CSS_MARGIN_AUTO: - default: - margin[i] = AUTO; + case BOTTOM: + type = css_computed_margin_bottom(style, + &value, &unit); + break; + case LEFT: + type = css_computed_margin_left(style, + &value, &unit); break; } + + if (type == CSS_MARGIN_SET) { + if (unit == CSS_UNIT_PCT) { + margin[i] = available_width * + FIXTOFLT(value) / 100; + } else { + margin[i] = FIXTOINT(nscss_len2px(value, + unit, style)); + } + } else { + margin[i] = AUTO; + } } if (padding) { - switch (style->padding[i].padding) { - case CSS_PADDING_PERCENT: - padding[i] = available_width * - style->padding[i].value. - percent / 100; + enum css_padding type; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + switch (i) { + case TOP: + type = css_computed_padding_top(style, + &value, &unit); break; - case CSS_PADDING_LENGTH: - default: - padding[i] = css_len2px(&style->padding[i]. - value.length, style); + case RIGHT: + type = css_computed_padding_right(style, + &value, &unit); + break; + case BOTTOM: + type = css_computed_padding_bottom(style, + &value, &unit); break; + case LEFT: + type = css_computed_padding_left(style, + &value, &unit); + break; + } + + if (unit == CSS_UNIT_PCT) { + padding[i] = available_width * + FIXTOFLT(value) / 100; + } else { + padding[i] = FIXTOINT(nscss_len2px(value, unit, + style)); } } - if (border) { - if (style->border[i].style == CSS_BORDER_STYLE_HIDDEN || - style->border[i].style == - CSS_BORDER_STYLE_NONE) + /* Table cell borders are populated in table.c */ + if (border && box->type != BOX_TABLE_CELL) { + enum css_border_width wtype; + enum css_border_style bstyle = CSS_BORDER_STYLE_NONE; + enum css_border_color bcolor = + CSS_BORDER_COLOR_TRANSPARENT; + css_color color = 0; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + switch (i) { + case TOP: + wtype = css_computed_border_top_width(style, + &value, &unit); + bstyle = css_computed_border_top_style(style); + bcolor = css_computed_border_top_color(style, + &color); + break; + case RIGHT: + wtype = css_computed_border_right_width(style, + &value, &unit); + bstyle = css_computed_border_right_style(style); + bcolor = css_computed_border_right_color(style, + &color); + break; + case BOTTOM: + wtype = css_computed_border_bottom_width(style, + &value, &unit); + bstyle = css_computed_border_bottom_style( + style); + bcolor = css_computed_border_bottom_color(style, + &color); + break; + case LEFT: + wtype = css_computed_border_left_width(style, + &value, &unit); + bstyle = css_computed_border_left_style(style); + bcolor = css_computed_border_left_color(style, + &color); + break; + } + + border[i].style = bstyle; + border[i].color = bcolor; + border[i].c = color; + + if (bstyle == CSS_BORDER_STYLE_HIDDEN || + bstyle == CSS_BORDER_STYLE_NONE) /* spec unclear: following Mozilla */ - border[i] = 0; + border[i].width = 0; else - border[i] = css_len2px(&style->border[i]. - width.value, style); + border[i].width = FIXTOINT(nscss_len2px(value, + unit, style)); + + /* Special case for border-collapse: make all borders + * on table/table-row-group/table-row zero width. */ + if (css_computed_border_collapse(style) == + CSS_BORDER_COLLAPSE_COLLAPSE && + (box->type == BOX_TABLE || + box->type == BOX_TABLE_ROW_GROUP || + box->type == BOX_TABLE_ROW)) + border[i].width = 0; } } } @@ -1435,7 +1597,7 @@ void layout_tweak_form_dimensions(struct box *box, bool percentage, * \return y coordinate relative to ancestor box for floats */ -int layout_clear(struct box *fl, css_clear clear) +int layout_clear(struct box *fl, enum css_clear clear) { int y = 0; for (; fl; fl = fl->next_float) { @@ -1522,13 +1684,17 @@ bool layout_inline_container(struct box *inline_container, int width, has_text_children = false; for (c = inline_container->children; c; c = c->next) { bool is_pre = false; - if (c->style) - is_pre = (c->style->white_space == - CSS_WHITE_SPACE_PRE || - c->style->white_space == - CSS_WHITE_SPACE_PRE_LINE || - c->style->white_space == - CSS_WHITE_SPACE_PRE_WRAP); + + if (c->style) { + enum css_white_space whitespace; + + whitespace = css_computed_white_space(c->style); + + is_pre = (whitespace == CSS_WHITE_SPACE_PRE || + whitespace == CSS_WHITE_SPACE_PRE_LINE || + whitespace == CSS_WHITE_SPACE_PRE_WRAP); + } + if ((!c->object && c->text && (c->length || is_pre)) || c->type == BOX_BR) has_text_children = true; @@ -1600,31 +1766,50 @@ void layout_minmax_inline_container(struct box *inline_container, * Calculate line height from a style. */ -int line_height(struct css_style *style) +int line_height(const css_computed_style *style) { - float font_len; + enum css_line_height lhtype; + css_fixed lhvalue = 0; + css_unit lhunit = CSS_UNIT_PX; + css_fixed line_height; assert(style); - assert(style->line_height.size == CSS_LINE_HEIGHT_LENGTH || - style->line_height.size == CSS_LINE_HEIGHT_ABSOLUTE || - style->line_height.size == CSS_LINE_HEIGHT_PERCENT); - /* take account of minimum font size option */ - if ((font_len = css_len2px(&style->font_size.value.length, 0)) < - option_font_min_size * css_screen_dpi / 720.0) - font_len = option_font_min_size * css_screen_dpi / 720.0; + lhtype = css_computed_line_height(style, &lhvalue, &lhunit); + if (lhtype == CSS_LINE_HEIGHT_NORMAL) { + /* Normal => use a constant of 1.3 * font-size */ + lhvalue = FLTTOFIX(1.3); + lhtype = CSS_LINE_HEIGHT_NUMBER; + } - switch (style->line_height.size) { - case CSS_LINE_HEIGHT_LENGTH: - return css_len2px(&style->line_height.value.length, style); + if (lhtype == CSS_LINE_HEIGHT_NUMBER || + lhunit == CSS_UNIT_PCT) { + css_fixed fs = 0, px_fs; + css_unit fs_unit = CSS_UNIT_PX; - case CSS_LINE_HEIGHT_ABSOLUTE: - return style->line_height.value.absolute * font_len; + css_computed_font_size(style, &fs, &fs_unit); - case CSS_LINE_HEIGHT_PERCENT: - default: - return style->line_height.value.percent * font_len / 100.0; + /* Convert to points */ + fs = nscss_len2pt(fs, fs_unit); + fs_unit = CSS_UNIT_PT; + + /* Clamp to configured minimum */ + if (fs < FDIVI(INTTOFIX(option_font_min_size), 10)) + fs = FDIVI(INTTOFIX(option_font_min_size), 10); + + px_fs = nscss_len2px(fs, fs_unit, style); + + if (lhtype == CSS_LINE_HEIGHT_NUMBER) + line_height = FMUL(lhvalue, px_fs); + else + line_height = FDIVI(FMUL(lhvalue, px_fs), 100); + } else { + assert(lhunit != CSS_UNIT_PCT); + + line_height = nscss_len2px(lhvalue, lhunit, style); } + + return FIXTOINT(line_height); } @@ -1666,13 +1851,9 @@ bool layout_line(struct box *first, int *width, int *y, int space_before = 0, space_after = 0; unsigned int inline_count = 0; unsigned int i; - struct css_length gadget_size; /* Checkbox / radio buttons */ const struct font_functions *font_func = content->data.html.font_func; plot_font_style_t fstyle; - gadget_size.unit = CSS_UNIT_EM; - gadget_size.value = 1; - LOG(("first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i", first, (int) first->length, first->text, *width, *y, cx, cy)); @@ -1706,6 +1887,11 @@ bool layout_line(struct box *first, int *width, int *y, * keep in sync with the loop in layout_minmax_line() */ LOG(("x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0)); for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) { + enum css_width wtype; + enum css_height htype; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK || b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT || @@ -1719,8 +1905,10 @@ bool layout_line(struct box *first, int *width, int *y, if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT) continue; if (b->type == BOX_INLINE_BLOCK && - (b->style->position == CSS_POSITION_ABSOLUTE || - b->style->position == CSS_POSITION_FIXED)) + (css_computed_position(b->style) == + CSS_POSITION_ABSOLUTE || + css_computed_position(b->style) == + CSS_POSITION_FIXED)) continue; assert(b->style != NULL); @@ -1732,13 +1920,15 @@ bool layout_line(struct box *first, int *width, int *y, if (b->max_width != UNKNOWN_WIDTH) if (!layout_float(b, *width, content)) return false; - h = b->border[TOP] + b->padding[TOP] + b->height + - b->padding[BOTTOM] + b->border[BOTTOM]; + h = b->border[TOP].width + b->padding[TOP] + b->height + + b->padding[BOTTOM] + + b->border[BOTTOM].width; if (height < h) height = h; - x += b->margin[LEFT] + b->border[LEFT] + + x += b->margin[LEFT] + b->border[LEFT].width + b->padding[LEFT] + b->width + - b->padding[RIGHT] + b->border[RIGHT] + + b->padding[RIGHT] + + b->border[RIGHT].width + b->margin[RIGHT]; space_after = 0; continue; @@ -1751,7 +1941,7 @@ bool layout_line(struct box *first, int *width, int *y, for (i = 0; i != 4; i++) if (b->margin[i] == AUTO) b->margin[i] = 0; - x += b->margin[LEFT] + b->border[LEFT] + + x += b->margin[LEFT] + b->border[LEFT].width + b->padding[LEFT]; if (b->inline_end) { b->inline_end->margin[RIGHT] = b->margin[RIGHT]; @@ -1760,7 +1950,8 @@ bool layout_line(struct box *first, int *width, int *y, b->inline_end->border[RIGHT] = b->border[RIGHT]; } else { - x += b->padding[RIGHT] + b->border[RIGHT] + + x += b->padding[RIGHT] + + b->border[RIGHT].width + b->margin[RIGHT]; } } else if (b->type == BOX_INLINE_END) { @@ -1772,7 +1963,7 @@ bool layout_line(struct box *first, int *width, int *y, } else { space_after = 0; } - x += b->padding[RIGHT] + b->border[RIGHT] + + x += b->padding[RIGHT] + b->border[RIGHT].width + b->margin[RIGHT]; continue; } @@ -1838,32 +2029,27 @@ bool layout_line(struct box *first, int *width, int *y, assert(b->style); /* calculate box width */ - switch (b->style->width.width) { - case CSS_WIDTH_LENGTH: - b->width = css_len2px(&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: + wtype = css_computed_width(b->style, &value, &unit); + if (wtype == CSS_WIDTH_SET) { + if (unit == CSS_UNIT_PCT) { + b->width = *width * FIXTOFLT(value) / 100; + } else { + b->width = FIXTOINT(nscss_len2px(value, unit, + b->style)); + } + } else { b->width = AUTO; - break; } /* height */ - switch (b->style->height.height) { - case CSS_HEIGHT_LENGTH: - b->height = css_len2px(&b->style->height.value.length, - b->style); - break; - case CSS_HEIGHT_AUTO: - default: + htype = css_computed_height(b->style, &value, &unit); + if (htype == CSS_HEIGHT_SET) { + b->height = FIXTOINT(nscss_len2px(value, unit, + b->style)); + } else { b->height = AUTO; - break; } - + if (b->object) { if (b->width == AUTO && b->height == AUTO) { b->width = b->object->width; @@ -1886,15 +2072,20 @@ bool layout_line(struct box *first, int *width, int *y, } else { /* form control with no object */ if (b->width == AUTO) - b->width = css_len2px(&gadget_size, b->style); + b->width = FIXTOINT(nscss_len2px(INTTOFIX(1), + CSS_UNIT_EM, b->style)); if (b->height == AUTO) - b->height = css_len2px(&gadget_size, b->style); + b->height = FIXTOINT(nscss_len2px(INTTOFIX(1), + CSS_UNIT_EM, b->style)); } if (b->object && b->object->type == CONTENT_HTML && b->width != b->object->available_width) { + htype = css_computed_height(b->style, &value, &unit); + content_reformat(b->object, b->width, b->height); - if (b->style->height.height == CSS_HEIGHT_AUTO) + + if (htype == CSS_HEIGHT_AUTO) b->height = b->object->height; } @@ -1925,8 +2116,10 @@ bool layout_line(struct box *first, int *width, int *y, for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) { LOG(("pass 2: b %p, x %i", b, x)); if (b->type == BOX_INLINE_BLOCK && - (b->style->position == CSS_POSITION_ABSOLUTE || - b->style->position == CSS_POSITION_FIXED)) { + (css_computed_position(b->style) == + CSS_POSITION_ABSOLUTE || + css_computed_position(b->style) == + CSS_POSITION_FIXED)) { b->x = x + space_after; } else if (b->type == BOX_INLINE || @@ -1941,16 +2134,17 @@ bool layout_line(struct box *first, int *width, int *y, if ((b->type == BOX_INLINE && !b->inline_end) || b->type == BOX_INLINE_BLOCK) { - b->x += b->margin[LEFT] + b->border[LEFT]; + b->x += b->margin[LEFT] + b->border[LEFT].width; x = b->x + b->padding[LEFT] + b->width + b->padding[RIGHT] + - b->border[RIGHT] + + b->border[RIGHT].width + b->margin[RIGHT]; } else if (b->type == BOX_INLINE) { - b->x += b->margin[LEFT] + b->border[LEFT]; + b->x += b->margin[LEFT] + b->border[LEFT].width; x = b->x + b->padding[LEFT] + b->width; } else if (b->type == BOX_INLINE_END) { - x += b->padding[RIGHT] + b->border[RIGHT] + + x += b->padding[RIGHT] + + b->border[RIGHT].width + b->margin[RIGHT]; } else { x += b->width; @@ -1991,27 +2185,33 @@ bool layout_line(struct box *first, int *width, int *y, if (!layout_float(d, *width, content)) return false; - LOG(("%p : %d %d", d, d->margin[TOP], d->border[TOP])); - d->x = d->margin[LEFT] + d->border[LEFT]; - d->y = d->margin[TOP] + d->border[TOP]; - b->width = d->margin[LEFT] + d->border[LEFT] + + LOG(("%p : %d %d", d, d->margin[TOP], + d->border[TOP].width)); + d->x = d->margin[LEFT] + d->border[LEFT].width; + d->y = d->margin[TOP] + d->border[TOP].width; + b->width = d->margin[LEFT] + d->border[LEFT].width + d->padding[LEFT] + d->width + - d->padding[RIGHT] + d->border[RIGHT] + + d->padding[RIGHT] + + d->border[RIGHT].width + d->margin[RIGHT]; - b->height = d->margin[TOP] + d->border[TOP] + + b->height = d->margin[TOP] + d->border[TOP].width + d->padding[TOP] + d->height + - d->padding[BOTTOM] + d->border[BOTTOM] + + d->padding[BOTTOM] + + d->border[BOTTOM].width + d->margin[BOTTOM]; if (b->width > (x1 - x0) - x) place_below = true; - if (d->style && (d->style->clear == CSS_CLEAR_NONE || - (d->style->clear == CSS_CLEAR_LEFT && - left == 0) || - (d->style->clear == CSS_CLEAR_RIGHT && - right == 0) || - (d->style->clear == CSS_CLEAR_BOTH && - left == 0 && right == 0)) && + if (d->style && (css_computed_clear(d->style) == + CSS_CLEAR_NONE || + (css_computed_clear(d->style) == + CSS_CLEAR_LEFT && left == 0) || + (css_computed_clear(d->style) == + CSS_CLEAR_RIGHT && + right == 0) || + (css_computed_clear(d->style) == + CSS_CLEAR_BOTH && + left == 0 && right == 0)) && (!place_below || (left == 0 && right == 0 && x == 0)) && cy >= cont->clear_level) { @@ -2044,7 +2244,7 @@ bool layout_line(struct box *first, int *width, int *y, place_float_below(b, *width, cx, fy + height, cont); - if (d->style && d->style->clear != + if (d->style && css_computed_clear(d->style) != CSS_CLEAR_NONE) { /* to be cleared below existing * floats */ @@ -2054,7 +2254,7 @@ bool layout_line(struct box *first, int *width, int *y, b->x = cx + *width - b->width; fy = layout_clear(cont->float_children, - d->style->clear); + css_computed_clear(d->style)); if (fy > cont->clear_level) cont->clear_level = fy; if (b->y < fy) @@ -2221,7 +2421,7 @@ bool layout_line(struct box *first, int *width, int *y, } /* set positions */ - switch (first->parent->parent->style->text_align) { + switch (css_computed_text_align(first->parent->parent->style)) { case CSS_TEXT_ALIGN_RIGHT: x0 = x1 - x; break; @@ -2243,20 +2443,24 @@ bool layout_line(struct box *first, int *width, int *y, } if ((d->type == BOX_INLINE && (d->object || d->gadget)) || d->type == BOX_INLINE_BLOCK) { - d->y = *y + d->border[TOP] + d->margin[TOP]; + d->y = *y + d->border[TOP].width + d->margin[TOP]; } if (d->type == BOX_INLINE_BLOCK) { d->x += x0; } if (d->type == BOX_INLINE_BLOCK && - (d->style->position == CSS_POSITION_ABSOLUTE || - d->style->position == CSS_POSITION_FIXED)) + (css_computed_position(d->style) == + CSS_POSITION_ABSOLUTE || + css_computed_position(d->style) == + CSS_POSITION_FIXED)) continue; if ((d->type == BOX_INLINE && (d->object || d->gadget)) || d->type == BOX_INLINE_BLOCK) { - h = d->margin[TOP] + d->border[TOP] + d->padding[TOP] + - d->height + d->padding[BOTTOM] + - d->border[BOTTOM] + d->margin[BOTTOM]; + h = d->margin[TOP] + d->border[TOP].width + + d->padding[TOP] + d->height + + d->padding[BOTTOM] + + d->border[BOTTOM].width + + d->margin[BOTTOM]; if (used_height < h) used_height = h; } @@ -2279,9 +2483,9 @@ bool layout_line(struct box *first, int *width, int *y, } /* handle clearance for br */ - if (br_box && br_box->style->clear != CSS_CLEAR_NONE) { + if (br_box && css_computed_clear(br_box->style) != CSS_CLEAR_NONE) { int clear_y = layout_clear(cont->float_children, - br_box->style->clear); + css_computed_clear(br_box->style)); if (used_height < clear_y - cy) used_height = clear_y - cy; } @@ -2312,14 +2516,15 @@ struct box *layout_minmax_line(struct box *first, float frac; size_t i, j; struct box *b; - struct css_length gadget_size; /* Checkbox / radio buttons */ plot_font_style_t fstyle; - gadget_size.unit = CSS_UNIT_EM; - gadget_size.value = 1; - /* corresponds to the pass 1 loop in layout_line() */ for (b = first; b; b = b->next) { + enum css_width wtype; + enum css_height htype; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK || b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT || @@ -2444,34 +2649,28 @@ struct box *layout_minmax_line(struct box *first, assert(b->style); /* calculate box width */ - switch (b->style->width.width) { - case CSS_WIDTH_LENGTH: - width = css_len2px(&b->style->width.value.length, - b->style); - if (width < 0) - width = 0; - break; - case CSS_WIDTH_PERCENT: - /* - b->width = width * b->style->width.value.percent / 100; - break; - */ - case CSS_WIDTH_AUTO: - default: + wtype = css_computed_width(b->style, &value, &unit); + if (wtype == CSS_WIDTH_SET) { + if (unit == CSS_UNIT_PCT) { + /* + b->width = width * FIXTOFLT(value) / 100 + */ + } else { + width = FIXTOINT(nscss_len2px(value, unit, + b->style)); + if (width < 0) + width = 0; + } + } else { width = AUTO; - break; } /* height */ - switch (b->style->height.height) { - case CSS_HEIGHT_LENGTH: - height = css_len2px(&b->style->height.value.length, - b->style); - break; - case CSS_HEIGHT_AUTO: - default: + htype = css_computed_height(b->style, &value, &unit); + if (htype == CSS_HEIGHT_SET) { + height = FIXTOINT(nscss_len2px(value, unit, b->style)); + } else { height = AUTO; - break; } if (b->object) { @@ -2494,7 +2693,8 @@ struct box *layout_minmax_line(struct box *first, } else { /* form control with no object */ if (width == AUTO) - width = css_len2px(&gadget_size, b->style); + width = FIXTOINT(nscss_len2px(INTTOFIX(1), + CSS_UNIT_EM, b->style)); } if (min < width) @@ -2522,15 +2722,17 @@ struct box *layout_minmax_line(struct box *first, * \return length of indent */ -int layout_text_indent(struct css_style *style, int width) +int layout_text_indent(const css_computed_style *style, int width) { - switch (style->text_indent.size) { - case CSS_TEXT_INDENT_LENGTH: - return css_len2px(&style->text_indent.value.length, style); - case CSS_TEXT_INDENT_PERCENT: - return width * style->text_indent.value.percent / 100; - default: - return 0; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + css_computed_text_indent(style, &value, &unit); + + if (unit == CSS_UNIT_PCT) { + return width * FIXTOFLT(value) / 100; + } else { + return FIXTOINT(nscss_len2px(value, unit, style)); } } @@ -2644,7 +2846,11 @@ bool layout_table(struct box *table, int available_width, struct box *row_group; struct box **row_span_cell; struct column *col; - struct css_style *style = table->style; + const css_computed_style *style = table->style; + enum css_width wtype; + enum css_height htype; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; assert(table->type == BOX_TABLE); assert(style); @@ -2676,12 +2882,13 @@ bool layout_table(struct box *table, int available_width, for (row = row_group->children; row; row = row->next) { for (c = row->children; c; c = c->next) { assert(c->style); + table_used_border_for_cell(c); layout_find_dimensions(available_width, -1, c, c->style, 0, 0, 0, 0, 0, c->padding, c->border); - if (c->style->overflow == + if (css_computed_overflow(c->style) == CSS_OVERFLOW_SCROLL || - c->style->overflow == + css_computed_overflow(c->style) == CSS_OVERFLOW_AUTO) { c->padding[RIGHT] += SCROLLBAR_WIDTH; c->padding[BOTTOM] += SCROLLBAR_WIDTH; @@ -2691,92 +2898,104 @@ bool layout_table(struct box *table, int available_width, } /* border-spacing is used in the separated borders model */ - if (style->border_collapse == CSS_BORDER_COLLAPSE_SEPARATE) { - border_spacing_h = css_len2px(&style->border_spacing.horz, - style); - border_spacing_v = css_len2px(&style->border_spacing.vert, - style); - } + if (css_computed_border_collapse(style) == + CSS_BORDER_COLLAPSE_SEPARATE) { + css_fixed h = 0, v = 0; + css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX; - /* find specified table width, or available width if auto-width */ - switch (style->width.width) { - case CSS_WIDTH_LENGTH: - table_width = css_len2px(&style->width.value.length, style); + css_computed_border_spacing(style, &h, &hu, &v, &vu); - /* specified width includes border */ - table_width -= table->border[LEFT] + table->border[RIGHT]; - table_width = table_width < 0 ? 0 : table_width; + border_spacing_h = FIXTOINT(nscss_len2px(h, hu, style)); + border_spacing_v = FIXTOINT(nscss_len2px(v, vu, style)); + } - auto_width = table_width; - break; - case CSS_WIDTH_PERCENT: - table_width = ceil(available_width * - style->width.value.percent / 100); + /* find specified table width, or available width if auto-width */ + wtype = css_computed_width(style, &value, &unit); + if (wtype == CSS_WIDTH_SET) { + if (unit == CSS_UNIT_PCT) { + table_width = ceil(available_width * + FIXTOFLT(value) / 100); + } else { + table_width = + FIXTOINT(nscss_len2px(value, unit, style)); + } /* specified width includes border */ - table_width -= table->border[LEFT] + table->border[RIGHT]; + table_width -= table->border[LEFT].width + + table->border[RIGHT].width; table_width = table_width < 0 ? 0 : table_width; auto_width = table_width; - break; - case CSS_WIDTH_AUTO: - default: + } else { table_width = AUTO; auto_width = available_width - ((table->margin[LEFT] == AUTO ? 0 : table->margin[LEFT]) + - table->border[LEFT] + + table->border[LEFT].width + table->padding[LEFT] + table->padding[RIGHT] + - table->border[RIGHT] + + table->border[RIGHT].width + (table->margin[RIGHT] == AUTO ? 0 : table->margin[RIGHT])); - break; } /* Find 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) */ - min_height = css_len2px(&style->height.value.length, style); - } else if (style->height.height == CSS_HEIGHT_PERCENT) { - /* This is the minimum height for the table (see 17.5.3) */ - if (table->style->position == CSS_POSITION_ABSOLUTE) { - /* Table is absolutely positioned */ - assert(table->float_container); - containing_block = table->float_container; - } else if (table->float_container && - table->style->position != - CSS_POSITION_ABSOLUTE && - (table->style->float_ == - CSS_FLOAT_LEFT || - table->style->float_ == - CSS_FLOAT_RIGHT)) { - /* Table is a float */ - assert(table->parent && table->parent->parent && - table->parent->parent->parent); - containing_block = table->parent->parent->parent; - } else if (table->parent && table->parent->type != - BOX_INLINE_CONTAINER) { - /* Table is a block level element */ - containing_block = table->parent; - } else if (table->parent && table->parent->type == - BOX_INLINE_CONTAINER) { - /* Table is an inline block */ - assert(table->parent->parent); - containing_block = table->parent->parent; - } - if (containing_block && containing_block->height != AUTO && - (table->style->position == - CSS_POSITION_ABSOLUTE || - (containing_block->style->height.height == - CSS_HEIGHT_LENGTH || - containing_block->style->height.height == - CSS_HEIGHT_PERCENT))) { - /* Table is absolutely positioned or its - * containing block has a valid specified - * height. (CSS 2.1 Section 10.5) */ - min_height = style->height.value.percent * + htype = css_computed_height(style, &value, &unit); + if (htype == CSS_HEIGHT_SET) { + if (unit == CSS_UNIT_PCT) { + /* This is the minimum height for the table + * (see 17.5.3) */ + if (css_computed_position(table->style) == + CSS_POSITION_ABSOLUTE) { + /* Table is absolutely positioned */ + assert(table->float_container); + containing_block = table->float_container; + } else if (table->float_container && + css_computed_position(table->style) != + CSS_POSITION_ABSOLUTE && + (css_computed_float(table->style) == + CSS_FLOAT_LEFT || + css_computed_float(table->style) == + CSS_FLOAT_RIGHT)) { + /* Table is a float */ + assert(table->parent && table->parent->parent && + table->parent->parent->parent); + containing_block = + table->parent->parent->parent; + } else if (table->parent && table->parent->type != + BOX_INLINE_CONTAINER) { + /* Table is a block level element */ + containing_block = table->parent; + } else if (table->parent && table->parent->type == + BOX_INLINE_CONTAINER) { + /* Table is an inline block */ + assert(table->parent->parent); + containing_block = table->parent->parent; + } + + if (containing_block) { + css_fixed ignored = 0; + + htype = css_computed_height( + containing_block->style, + &ignored, &unit); + } + + if (containing_block && + containing_block->height != AUTO && + (css_computed_position(table->style) == + CSS_POSITION_ABSOLUTE || + htype == CSS_HEIGHT_SET)) { + /* Table is absolutely positioned or its + * containing block has a valid specified + * height. (CSS 2.1 Section 10.5) */ + min_height = FIXTOFLT(value) * containing_block->height / 100; + } + } else { + /* This is the minimum height for the table + * (see 17.5.3) */ + min_height = FIXTOINT(nscss_len2px(value, unit, style)); } } @@ -2950,20 +3169,21 @@ bool layout_table(struct box *table, int available_width, int row_group_height = 0; for (row = row_group->children; row; row = row->next) { int row_height = 0; - if (row->style->height.height == CSS_HEIGHT_LENGTH) { - row_height = (int) css_len2px(&row->style-> - height.value.length, - row->style); + + htype = css_computed_height(row->style, &value, &unit); + if (htype == CSS_HEIGHT_SET && unit != CSS_UNIT_PCT) { + row_height = FIXTOINT(nscss_len2px(value, unit, + row->style)); } for (c = row->children; c; c = c->next) { assert(c->style); c->width = xs[c->start_column + c->columns] - xs[c->start_column] - border_spacing_h - - c->border[LEFT] - + c->border[LEFT].width - c->padding[LEFT] - c->padding[RIGHT] - - c->border[RIGHT]; + c->border[RIGHT].width; c->float_children = 0; c->height = AUTO; @@ -2980,13 +3200,17 @@ bool layout_table(struct box *table, int available_width, * until after vertical alignment is complete */ c->descendant_y0 = c->height; c->descendant_y1 = c->padding[BOTTOM]; - if (c->style->height.height == - CSS_HEIGHT_LENGTH) { + + htype = css_computed_height(c->style, + &value, &unit); + + if (htype == CSS_HEIGHT_SET && + unit != CSS_UNIT_PCT) { /* some sites use height="1" or similar * to attempt to make cells as small as * possible, so treat it as a minimum */ - int h = (int) css_len2px(&c->style-> - height.value.length, c->style); + int h = FIXTOINT(nscss_len2px(value, + unit, c->style)); if (c->height < h) c->height = h; } @@ -2994,24 +3218,25 @@ bool layout_table(struct box *table, int available_width, */ if (c->height < row_height) c->height = row_height; - c->x = xs[c->start_column] + c->border[LEFT]; - c->y = c->border[TOP]; + c->x = xs[c->start_column] + + c->border[LEFT].width; + c->y = c->border[TOP].width; for (i = 0; i != c->columns; i++) { row_span[c->start_column + i] = c->rows; excess_y[c->start_column + i] = - c->border[TOP] + + c->border[TOP].width + c->padding[TOP] + c->height + c->padding[BOTTOM] + - c->border[BOTTOM]; + c->border[BOTTOM].width; row_span_cell[c->start_column + i] = 0; } row_span_cell[c->start_column] = c; c->padding[BOTTOM] = -border_spacing_v - - c->border[TOP] - + c->border[TOP].width - c->padding[TOP] - c->height - - c->border[BOTTOM]; + c->border[BOTTOM].width; } for (i = 0; i != columns; i++) if (row_span[i] != 0) @@ -3064,19 +3289,24 @@ bool layout_table(struct box *table, int available_width, row_group = row_group->next) { for (row = row_group->children; row; row = row->next) { for (c = row->children; c; c = c->next) { + enum css_vertical_align vertical_align; + /* unextended bottom padding is in * c->descendant_y1, and unextended * cell height is in c->descendant_y0 */ spare_height = (c->padding[BOTTOM] - c->descendant_y1) + (c->height - c->descendant_y0); - switch (c->style->vertical_align.type) { + + vertical_align = css_computed_vertical_align( + c->style, &value, &unit); + + switch (vertical_align) { case CSS_VERTICAL_ALIGN_SUB: case CSS_VERTICAL_ALIGN_SUPER: case CSS_VERTICAL_ALIGN_TEXT_TOP: case CSS_VERTICAL_ALIGN_TEXT_BOTTOM: - case CSS_VERTICAL_ALIGN_LENGTH: - case CSS_VERTICAL_ALIGN_PERCENT: + case CSS_VERTICAL_ALIGN_SET: case CSS_VERTICAL_ALIGN_BASELINE: /* todo: baseline alignment, for now * just use ALIGN_TOP */ @@ -3094,7 +3324,6 @@ bool layout_table(struct box *table, int available_width, layout_move_children(c, 0, spare_height); break; - case CSS_VERTICAL_ALIGN_NOT_SET: case CSS_VERTICAL_ALIGN_INHERIT: assert(0); break; @@ -3134,6 +3363,9 @@ void layout_minmax_table(struct box *table, float extra_frac = 0; struct column *col = table->col; struct box *row_group, *row, *cell; + enum css_width wtype; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; /* check if the widths have already been calculated */ if (table->max_width != UNKNOWN_MAX_WIDTH) @@ -3148,9 +3380,15 @@ void layout_minmax_table(struct box *table, } /* border-spacing is used in the separated borders model */ - if (table->style->border_collapse == CSS_BORDER_COLLAPSE_SEPARATE) - border_spacing_h = css_len2px(&table->style-> - border_spacing.horz, table->style); + if (css_computed_border_collapse(table->style) == + CSS_BORDER_COLLAPSE_SEPARATE) { + css_fixed h = 0, v = 0; + css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX; + + css_computed_border_spacing(table->style, &h, &hu, &v, &vu); + + border_spacing_h = FIXTOINT(nscss_len2px(h, hu, table->style)); + } /* 1st pass: consider cells with colspan 1 only */ for (row_group = table->children; row_group; row_group =row_group->next) @@ -3249,9 +3487,9 @@ void layout_minmax_table(struct box *table, } /* fixed width takes priority, unless it is too narrow */ - if (table->style->width.width == CSS_WIDTH_LENGTH) { - int width = css_len2px(&table->style->width.value.length, - table->style); + wtype = css_computed_width(table->style, &value, &unit); + if (wtype == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) { + int width = FIXTOINT(nscss_len2px(value, unit, table->style)); if (table_min < width) table_min = width; if (table_max < width) @@ -3309,35 +3547,77 @@ void layout_move_children(struct box *box, int x, int y) * \param frac increased by sum of fractional margin and padding */ -void calculate_mbp_width(struct css_style *style, unsigned int side, +void calculate_mbp_width(const css_computed_style *style, unsigned int side, bool margin, bool border, bool padding, int *fixed, float *frac) { + typedef uint8_t (*len_func)(const css_computed_style *style, + css_fixed *length, css_unit *unit); + + static len_func margin_funcs[4] = { + css_computed_margin_top, + css_computed_margin_right, + css_computed_margin_bottom, + css_computed_margin_left + }; + static len_func padding_funcs[4] = { + css_computed_padding_top, + css_computed_padding_right, + css_computed_padding_bottom, + css_computed_padding_left + }; + static struct { + len_func width; + uint8_t (*style)(const css_computed_style *style); + } border_funcs[4] = { + { css_computed_border_top_width, + css_computed_border_top_style }, + { css_computed_border_right_width, + css_computed_border_right_style }, + { css_computed_border_bottom_width, + css_computed_border_bottom_style }, + { css_computed_border_left_width, + css_computed_border_left_style } + }; + + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + assert(style); /* margin */ if (margin) { - if (style->margin[side].margin == CSS_MARGIN_LENGTH) - *fixed += css_len2px(&style->margin[side].value.length, - style); - else if (style->margin[side].margin == CSS_MARGIN_PERCENT) - *frac += style->margin[side].value.percent * 0.01; + enum css_margin type; + + type = margin_funcs[side](style, &value, &unit); + if (type == CSS_MARGIN_SET) { + if (unit == CSS_UNIT_PCT) { + *frac += FIXTOFLT(value) * 0.01; + } else { + *fixed += FIXTOINT(nscss_len2px(value, unit, + style)); + } + } } /* border */ if (border) { - if (style->border[side].style != CSS_BORDER_STYLE_NONE) - *fixed += css_len2px(&style->border[side].width.value, - style); + if (border_funcs[side].style(style) != + CSS_BORDER_STYLE_NONE) { + border_funcs[side].width(style, &value, &unit); + + *fixed += FIXTOINT(nscss_len2px(value, unit, style)); + } } /* padding */ if (padding) { - if (style->padding[side].padding == CSS_PADDING_LENGTH) - *fixed += css_len2px(&style->padding[side].value.length, - style); - else if (style->padding[side].padding == CSS_PADDING_PERCENT) - *frac += style->padding[side].value.percent * 0.01; + padding_funcs[side](style, &value, &unit); + if (unit == CSS_UNIT_PCT) { + *frac += FIXTOFLT(value) * 0.01; + } else { + *fixed += FIXTOINT(nscss_len2px(value, unit, style)); + } } } @@ -3424,7 +3704,8 @@ void layout_position_relative(struct box *root, struct box *fp, int fx, int fy) continue; /* If relatively positioned, get offsets */ - if (box->style && box->style->position == CSS_POSITION_RELATIVE) + if (box->style && css_computed_position(box->style) == + CSS_POSITION_RELATIVE) layout_compute_relative_offset(box, &x, &y); else x = y = 0; @@ -3432,8 +3713,10 @@ void layout_position_relative(struct box *root, struct box *fp, int fx, int fy) /* Adjust float coordinates. * (note float x and y are relative to their block formatting * context box and not their parent) */ - if (box->style && (box->style->float_ == CSS_FLOAT_LEFT || - box->style->float_ == CSS_FLOAT_RIGHT) && + if (box->style && (css_computed_float(box->style) == + CSS_FLOAT_LEFT || + css_computed_float(box->style) == + CSS_FLOAT_RIGHT) && (fx != 0 || fy != 0)) { /* box is a float and there is a float offset to * apply */ @@ -3463,7 +3746,8 @@ void layout_position_relative(struct box *root, struct box *fp, int fx, int fy) /* Ignore things we're not interested in. */ if (!box->style || (box->style && - box->style->position != CSS_POSITION_RELATIVE)) + css_computed_position(box->style) != + CSS_POSITION_RELATIVE)) continue; box->x += x; @@ -3498,10 +3782,12 @@ void layout_compute_relative_offset(struct box *box, int *x, int *y) struct box *containing_block; assert(box && box->parent && box->style && - box->style->position == CSS_POSITION_RELATIVE); + css_computed_position(box->style) == + CSS_POSITION_RELATIVE); - if (box->float_container && (box->style->float_ == CSS_FLOAT_LEFT || - box->style->float_ == CSS_FLOAT_RIGHT)) { + if (box->float_container && (css_computed_float(box->style) == + CSS_FLOAT_LEFT || + css_computed_float(box->style) == CSS_FLOAT_RIGHT)) { containing_block = box->float_container; } else { containing_block = box->parent; @@ -3522,11 +3808,12 @@ void layout_compute_relative_offset(struct box *box, int *x, int *y) /* over constrained => examine direction property * of containing block */ if (containing_block->style) { - if (box->parent->style->direction == + if (css_computed_direction(containing_block->style) == CSS_DIRECTION_LTR) /* left wins */ right = -left; - else if (box->parent->style->direction == + else if (css_computed_direction( + containing_block->style) == CSS_DIRECTION_RTL) /* right wins */ left = -right; @@ -3576,21 +3863,25 @@ bool layout_position_absolute(struct box *box, for (c = box->children; c; c = c->next) { if ((c->type == BOX_BLOCK || c->type == BOX_TABLE || c->type == BOX_INLINE_BLOCK) && - (c->style->position == CSS_POSITION_ABSOLUTE || - c->style->position == CSS_POSITION_FIXED)) { + (css_computed_position(c->style) == + CSS_POSITION_ABSOLUTE || + css_computed_position(c->style) == + CSS_POSITION_FIXED)) { if (!layout_absolute(c, containing_block, cx, cy, content)) return false; if (!layout_position_absolute(c, c, 0, 0, content)) return false; - } else if (c->style && - c->style->position == CSS_POSITION_RELATIVE) { + } else if (c->style && css_computed_position(c->style) == + CSS_POSITION_RELATIVE) { if (!layout_position_absolute(c, c, 0, 0, content)) return false; } else { int px, py; - if (c->style && (c->style->float_ == CSS_FLOAT_LEFT || - c->style->float_ == CSS_FLOAT_RIGHT)) { + if (c->style && (css_computed_float(c->style) == + CSS_FLOAT_LEFT || + css_computed_float(c->style) == + CSS_FLOAT_RIGHT)) { /* Float x/y coords are relative to nearest * ansestor with float_children, rather than * relative to parent. Need to get x/y relative @@ -3639,7 +3930,7 @@ bool layout_absolute(struct box *box, struct box *containing_block, int width, height, max_width, min_width; int *margin = box->margin; int *padding = box->padding; - int *border = box->border; + struct box_border *border = box->border; int available_width = containing_block->width; int space; @@ -3680,8 +3971,9 @@ bool layout_absolute(struct box *box, struct box *containing_block, /* 10.3.7 */ LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", - left, margin[LEFT], border[LEFT], padding[LEFT], width, - padding[RIGHT], border[RIGHT], margin[RIGHT], right, + left, margin[LEFT], border[LEFT].width, + padding[LEFT], width, padding[RIGHT], + border[RIGHT].width, margin[RIGHT], right, containing_block->width)); if (left == AUTO && width == AUTO && right == AUTO) { if (margin[LEFT] == AUTO) @@ -3692,19 +3984,19 @@ bool layout_absolute(struct box *box, struct box *containing_block, width = min(max(box->min_width, available_width), box->max_width); - width -= box->margin[LEFT] + box->border[LEFT] + + width -= box->margin[LEFT] + box->border[LEFT].width + box->padding[LEFT] + box->padding[RIGHT] + - box->border[RIGHT] + box->margin[RIGHT]; + box->border[RIGHT].width + box->margin[RIGHT]; /* Adjust for {min|max}-width */ if (max_width >= 0 && width > max_width) width = max_width; if (min_width > 0 && width < min_width) width = min_width; right = containing_block->width - - left - - margin[LEFT] - border[LEFT] - padding[LEFT] - - width - - padding[RIGHT] - border[RIGHT] - margin[RIGHT]; + left - + margin[LEFT] - border[LEFT].width - padding[LEFT] - + width - + padding[RIGHT] - border[RIGHT].width - margin[RIGHT]; } else if (left != AUTO && width != AUTO && right != AUTO) { /* Adjust for {min|max}-width */ @@ -3713,9 +4005,9 @@ bool layout_absolute(struct box *box, struct box *containing_block, if (margin[LEFT] == AUTO && margin[RIGHT] == AUTO) { space = containing_block->width - - left - border[LEFT] - + left - border[LEFT].width - padding[LEFT] - width - padding[RIGHT] - - border[RIGHT] - right; + border[RIGHT].width - right; if (space < 0) { margin[LEFT] = 0; margin[RIGHT] = space; @@ -3724,19 +4016,22 @@ bool layout_absolute(struct box *box, struct box *containing_block, } } else if (margin[LEFT] == AUTO) { margin[LEFT] = containing_block->width - - left - border[LEFT] - + left - border[LEFT].width - padding[LEFT] - width - padding[RIGHT] - - border[RIGHT] - margin[RIGHT] - right; + border[RIGHT].width - margin[RIGHT] - + right; } else if (margin[RIGHT] == AUTO) { margin[RIGHT] = containing_block->width - - left - margin[LEFT] - border[LEFT] - + left - margin[LEFT] - + border[LEFT].width - padding[LEFT] - width - padding[RIGHT] - - border[RIGHT] - right; + border[RIGHT].width - right; } else { right = containing_block->width - - left - margin[LEFT] - border[LEFT] - + left - margin[LEFT] - + border[LEFT].width - padding[LEFT] - width - padding[RIGHT] - - border[RIGHT] - margin[RIGHT]; + border[RIGHT].width - margin[RIGHT]; } } else { if (margin[LEFT] == AUTO) @@ -3749,9 +4044,9 @@ bool layout_absolute(struct box *box, struct box *containing_block, width = min(max(box->min_width, available_width), box->max_width); - width -= box->margin[LEFT] + box->border[LEFT] + + width -= box->margin[LEFT] + box->border[LEFT].width + box->padding[LEFT] + box->padding[RIGHT] + - box->border[RIGHT] + box->margin[RIGHT]; + box->border[RIGHT].width + box->margin[RIGHT]; /* Adjust for {min|max}-width */ if (max_width >= 0 && width > max_width) @@ -3760,9 +4055,10 @@ bool layout_absolute(struct box *box, struct box *containing_block, width = min_width; left = containing_block->width - - margin[LEFT] - border[LEFT] - + margin[LEFT] - border[LEFT].width - padding[LEFT] - width - padding[RIGHT] - - border[RIGHT] - margin[RIGHT] - right; + border[RIGHT].width - margin[RIGHT] - + right; } else if (left == AUTO && width != AUTO && right == AUTO) { /* Adjust for {min|max}-width */ @@ -3773,17 +4069,18 @@ bool layout_absolute(struct box *box, struct box *containing_block, left = static_left; right = containing_block->width - - left - margin[LEFT] - border[LEFT] - + left - margin[LEFT] - + border[LEFT].width - padding[LEFT] - width - padding[RIGHT] - - border[RIGHT] - margin[RIGHT]; + border[RIGHT].width - margin[RIGHT]; } else if (left != AUTO && width == AUTO && right == AUTO) { available_width -= left; width = min(max(box->min_width, available_width), box->max_width); - width -= box->margin[LEFT] + box->border[LEFT] + + width -= box->margin[LEFT] + box->border[LEFT].width + box->padding[LEFT] + box->padding[RIGHT] + - box->border[RIGHT] + box->margin[RIGHT]; + box->border[RIGHT].width + box->margin[RIGHT]; /* Adjust for {min|max}-width */ if (max_width >= 0 && width > max_width) @@ -3792,9 +4089,10 @@ bool layout_absolute(struct box *box, struct box *containing_block, width = min_width; right = containing_block->width - - left - margin[LEFT] - border[LEFT] - + left - margin[LEFT] - + border[LEFT].width - padding[LEFT] - width - padding[RIGHT] - - border[RIGHT] - margin[RIGHT]; + border[RIGHT].width - margin[RIGHT]; } else if (left == AUTO && width != AUTO && right != AUTO) { /* Adjust for {min|max}-width */ @@ -3804,14 +4102,17 @@ bool layout_absolute(struct box *box, struct box *containing_block, width = min_width; left = containing_block->width - - margin[LEFT] - border[LEFT] - + margin[LEFT] - border[LEFT].width - padding[LEFT] - width - padding[RIGHT] - - border[RIGHT] - margin[RIGHT] - right; + border[RIGHT].width - margin[RIGHT] - + right; } else if (left != AUTO && width == AUTO && right != AUTO) { width = containing_block->width - - left - margin[LEFT] - border[LEFT] - + left - margin[LEFT] - + border[LEFT].width - padding[LEFT] - padding[RIGHT] - - border[RIGHT] - margin[RIGHT] - right; + border[RIGHT].width - margin[RIGHT] - + right; /* Adjust for {min|max}-width */ if (max_width >= 0 && width > max_width) @@ -3828,17 +4129,19 @@ bool layout_absolute(struct box *box, struct box *containing_block, width = min_width; right = containing_block->width - - left - margin[LEFT] - border[LEFT] - + left - margin[LEFT] - + border[LEFT].width - padding[LEFT] - width - padding[RIGHT] - - border[RIGHT] - margin[RIGHT]; + border[RIGHT].width - margin[RIGHT]; } } LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", - left, margin[LEFT], border[LEFT], padding[LEFT], width, - padding[RIGHT], border[RIGHT], margin[RIGHT], right, + left, margin[LEFT], border[LEFT].width, padding[LEFT], + width, padding[RIGHT], border[RIGHT].width, + margin[RIGHT], right, containing_block->width)); - box->x = left + margin[LEFT] + border[LEFT] - cx; + box->x = left + margin[LEFT] + border[LEFT].width - cx; if (containing_block->type == BOX_BLOCK || containing_block->type == BOX_INLINE_BLOCK || containing_block->type == BOX_TABLE_CELL) { @@ -3865,8 +4168,9 @@ bool layout_absolute(struct box *box, struct box *containing_block, /* 10.6.4 */ LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", - top, margin[TOP], border[TOP], padding[TOP], height, - padding[BOTTOM], border[BOTTOM], margin[BOTTOM], bottom, + top, margin[TOP], border[TOP].width, padding[TOP], + height, padding[BOTTOM], border[BOTTOM].width, + margin[BOTTOM], bottom, containing_block->height)); if (top == AUTO && height == AUTO && bottom == AUTO) { top = static_top; @@ -3876,33 +4180,33 @@ bool layout_absolute(struct box *box, struct box *containing_block, if (margin[BOTTOM] == AUTO) margin[BOTTOM] = 0; bottom = containing_block->height - - top - margin[TOP] - border[TOP] - + top - margin[TOP] - border[TOP].width - padding[TOP] - height - padding[BOTTOM] - - border[BOTTOM] - margin[BOTTOM]; + border[BOTTOM].width - margin[BOTTOM]; } else if (top != AUTO && height != AUTO && bottom != AUTO) { if (margin[TOP] == AUTO && margin[BOTTOM] == AUTO) { space = containing_block->height - - top - border[TOP] - padding[TOP] - + top - border[TOP].width - padding[TOP] - height - padding[BOTTOM] - - border[BOTTOM] - bottom; + border[BOTTOM].width - bottom; margin[TOP] = margin[BOTTOM] = space / 2; } else if (margin[TOP] == AUTO) { margin[TOP] = containing_block->height - - top - border[TOP] - padding[TOP] - + top - border[TOP].width - padding[TOP] - height - padding[BOTTOM] - - border[BOTTOM] - margin[BOTTOM] - + border[BOTTOM].width - margin[BOTTOM] - bottom; } else if (margin[BOTTOM] == AUTO) { margin[BOTTOM] = containing_block->height - - top - margin[TOP] - border[TOP] - + top - margin[TOP] - border[TOP].width - padding[TOP] - height - - padding[BOTTOM] - border[BOTTOM] - + padding[BOTTOM] - border[BOTTOM].width - bottom; } else { bottom = containing_block->height - - top - margin[TOP] - border[TOP] - + top - margin[TOP] - border[TOP].width - padding[TOP] - height - - padding[BOTTOM] - border[BOTTOM] - + padding[BOTTOM] - border[BOTTOM].width - margin[BOTTOM]; } } else { @@ -3913,50 +4217,51 @@ bool layout_absolute(struct box *box, struct box *containing_block, if (top == AUTO && height == AUTO && bottom != AUTO) { height = box->height; top = containing_block->height - - margin[TOP] - border[TOP] - + margin[TOP] - border[TOP].width - padding[TOP] - height - - padding[BOTTOM] - border[BOTTOM] - + padding[BOTTOM] - border[BOTTOM].width - margin[BOTTOM] - bottom; } else if (top == AUTO && height != AUTO && bottom == AUTO) { top = static_top; bottom = containing_block->height - - top - margin[TOP] - border[TOP] - + top - margin[TOP] - border[TOP].width - padding[TOP] - height - - padding[BOTTOM] - border[BOTTOM] - + padding[BOTTOM] - border[BOTTOM].width - margin[BOTTOM]; } else if (top != AUTO && height == AUTO && bottom == AUTO) { height = box->height; bottom = containing_block->height - - top - margin[TOP] - border[TOP] - + top - margin[TOP] - border[TOP].width - padding[TOP] - height - - padding[BOTTOM] - border[BOTTOM] - + padding[BOTTOM] - border[BOTTOM].width - margin[BOTTOM]; } else if (top == AUTO && height != AUTO && bottom != AUTO) { top = containing_block->height - - margin[TOP] - border[TOP] - + margin[TOP] - border[TOP].width - padding[TOP] - height - - padding[BOTTOM] - border[BOTTOM] - + padding[BOTTOM] - border[BOTTOM].width - margin[BOTTOM] - bottom; } else if (top != AUTO && height == AUTO && bottom != AUTO) { height = containing_block->height - - top - margin[TOP] - border[TOP] - + top - margin[TOP] - border[TOP].width - padding[TOP] - padding[BOTTOM] - - border[BOTTOM] - margin[BOTTOM] - + border[BOTTOM].width - margin[BOTTOM] - bottom; } else if (top != AUTO && height != AUTO && bottom == AUTO) { bottom = containing_block->height - - top - margin[TOP] - border[TOP] - + top - margin[TOP] - border[TOP].width - padding[TOP] - height - - padding[BOTTOM] - border[BOTTOM] - + padding[BOTTOM] - border[BOTTOM].width - margin[BOTTOM]; } } LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", - top, margin[TOP], border[TOP], padding[TOP], height, - padding[BOTTOM], border[BOTTOM], margin[BOTTOM], bottom, + top, margin[TOP], border[TOP].width, padding[TOP], + height, padding[BOTTOM], border[BOTTOM].width, + margin[BOTTOM], bottom, containing_block->height)); - box->y = top + margin[TOP] + border[TOP] - cy; + box->y = top + margin[TOP] + border[TOP].width - cy; if (containing_block->type == BOX_BLOCK || containing_block->type == BOX_INLINE_BLOCK || containing_block->type == BOX_TABLE_CELL) { @@ -3991,49 +4296,67 @@ void layout_compute_offsets(struct box *box, struct box *containing_block, int *top, int *right, int *bottom, int *left) { + uint32_t type; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + assert(containing_block->width != UNKNOWN_WIDTH && containing_block->width != AUTO && containing_block->height != AUTO); /* left */ - if (box->style->pos[LEFT].pos == CSS_POS_PERCENT) - *left = ((box->style->pos[LEFT].value.percent * - containing_block->width) / 100); - else if (box->style->pos[LEFT].pos == CSS_POS_LENGTH) - *left = css_len2px(&box->style->pos[LEFT].value.length, - box->style); - else + type = css_computed_left(box->style, &value, &unit); + if (type == CSS_LEFT_SET) { + if (unit == CSS_UNIT_PCT) { + *left = (FIXTOFLT(value) * + containing_block->width) / 100; + } else { + *left = FIXTOINT(nscss_len2px(value, unit, box->style)); + } + } else { *left = AUTO; + } /* right */ - if (box->style->pos[RIGHT].pos == CSS_POS_PERCENT) - *right = ((box->style->pos[RIGHT].value.percent * - containing_block->width) / 100); - else if (box->style->pos[RIGHT].pos == CSS_POS_LENGTH) - *right = css_len2px(&box->style->pos[RIGHT].value.length, - box->style); - else + type = css_computed_right(box->style, &value, &unit); + if (type == CSS_RIGHT_SET) { + if (unit == CSS_UNIT_PCT) { + *right = (FIXTOFLT(value) * + containing_block->width) / 100; + } else { + *right = FIXTOINT(nscss_len2px(value, unit, + box->style)); + } + } else { *right = AUTO; + } /* top */ - if (box->style->pos[TOP].pos == CSS_POS_PERCENT) - *top = ((box->style->pos[TOP].value.percent * - containing_block->height) / 100); - else if (box->style->pos[TOP].pos == CSS_POS_LENGTH) - *top = css_len2px(&box->style->pos[TOP].value.length, - box->style); - else + type = css_computed_top(box->style, &value, &unit); + if (type == CSS_TOP_SET) { + if (unit == CSS_UNIT_PCT) { + *top = (FIXTOFLT(value) * + containing_block->height) / 100; + } else { + *top = FIXTOINT(nscss_len2px(value, unit, box->style)); + } + } else { *top = AUTO; + } /* bottom */ - if (box->style->pos[BOTTOM].pos == CSS_POS_PERCENT) - *bottom = ((box->style->pos[BOTTOM].value.percent * - containing_block->height) / 100); - else if (box->style->pos[BOTTOM].pos == CSS_POS_LENGTH) - *bottom = css_len2px(&box->style->pos[BOTTOM].value.length, - box->style); - else + type = css_computed_bottom(box->style, &value, &unit); + if (type == CSS_BOTTOM_SET) { + if (unit == CSS_UNIT_PCT) { + *bottom = (FIXTOFLT(value) * + containing_block->height) / 100; + } else { + *bottom = FIXTOINT(nscss_len2px(value, unit, + box->style)); + } + } else { *bottom = AUTO; + } } @@ -4056,12 +4379,12 @@ void layout_calculate_descendant_bboxes(struct box *box) assert(0); } - box->descendant_x0 = -box->border[LEFT]; - box->descendant_y0 = -box->border[TOP]; + box->descendant_x0 = -box->border[LEFT].width; + box->descendant_y0 = -box->border[TOP].width; box->descendant_x1 = box->padding[LEFT] + box->width + - box->padding[RIGHT] + box->border[RIGHT]; + box->padding[RIGHT] + box->border[RIGHT].width; box->descendant_y1 = box->padding[TOP] + box->height + - box->padding[BOTTOM] + box->border[BOTTOM]; + box->padding[BOTTOM] + box->border[BOTTOM].width; if (box->type == BOX_INLINE || box->type == BOX_TEXT) return; @@ -4103,7 +4426,8 @@ void layout_calculate_descendant_bboxes(struct box *box) layout_calculate_descendant_bboxes(child); - if (box->style && box->style->overflow == CSS_OVERFLOW_HIDDEN) + if (box->style && css_computed_overflow(box->style) == + CSS_OVERFLOW_HIDDEN) continue; if (child->x + child->descendant_x0 < box->descendant_x0) -- cgit v1.2.3