From 6c726473eff8a352d51e3931356347384bd8686a Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Thu, 27 Apr 2017 16:47:38 +0100 Subject: Layout: Implement CSS3 box-sizing property. Updates user agent CSS to set form element box-sizing properties, and removes some legacy pre-CSS3 hacks for handling gadget dimensions. --- !NetSurf/Resources/CSS,f79 | 4 +- render/layout.c | 154 +++++++++++++++++++++++++++------------------ 2 files changed, 96 insertions(+), 62 deletions(-) diff --git a/!NetSurf/Resources/CSS,f79 b/!NetSurf/Resources/CSS,f79 index 2aee83b7c..276bc1554 100644 --- a/!NetSurf/Resources/CSS,f79 +++ b/!NetSurf/Resources/CSS,f79 @@ -114,13 +114,13 @@ form { display: block; } input, button { background-color: #fff; color: #000; text-align: left; font-family: sans-serif; width: auto; height: auto; overflow: hidden; border: 1px solid #444; padding: 2px 3px; line-height: 1.33; - margin: 1px; } + margin: 1px; box-sizing: border-box; } input[disabled] { background-color: #ddd; color: #333; } input[type=button], input[type=reset], input[type=submit], button { background-color: #d9d9d9; color: #000; text-align: center; border: 2px outset #d9d9d9; padding: 1px 0.5em; } input[type=image] { background-color: transparent; color: #000; - border: none; padding: 0 2px; } + border: none; padding: 0 2px; box-sizing: content-box; } input[type=checkbox], input[type=radio] { background-color: transparent; border: none; padding: 0 0.1em; } input[type=file] { background-color: #d9d9d9; color: #000; font-style: italic; diff --git a/render/layout.c b/render/layout.c index c92089f63..4086c04f9 100644 --- a/render/layout.c +++ b/render/layout.c @@ -332,6 +332,7 @@ layout_minmax_line(struct box *first, for (b = first; b; b = b->next) { enum css_width_e wtype; enum css_height_e htype; + enum css_box_sizing_e bs; css_fixed value = 0; css_unit unit = CSS_UNIT_PX; @@ -506,6 +507,7 @@ layout_minmax_line(struct box *first, /* calculate box width */ wtype = css_computed_width(b->style, &value, &unit); + bs = css_computed_box_sizing(block->style); if (wtype == CSS_WIDTH_SET) { if (unit == CSS_UNIT_PCT) { /* @@ -516,6 +518,19 @@ layout_minmax_line(struct box *first, } else { width = FIXTOINT(nscss_len2px(value, unit, b->style)); + + if (bs == CSS_BOX_SIZING_BORDER_BOX) { + fixed = frac = 0; + calculate_mbp_width(block->style, LEFT, + false, true, true, + &fixed, &frac); + calculate_mbp_width(block->style, RIGHT, + false, true, true, + &fixed, &frac); + if (width < fixed) { + width = fixed; + } + } if (width < 0) width = 0; } @@ -541,11 +556,21 @@ layout_minmax_line(struct box *first, } fixed = frac = 0; - calculate_mbp_width(b->style, LEFT, true, true, true, - &fixed, &frac); - calculate_mbp_width(b->style, RIGHT, true, true, true, - &fixed, &frac); - + if (bs == CSS_BOX_SIZING_BORDER_BOX) { + calculate_mbp_width(b->style, LEFT, + true, false, false, + &fixed, &frac); + calculate_mbp_width(b->style, RIGHT, + true, false, false, + &fixed, &frac); + } else { + calculate_mbp_width(b->style, LEFT, + true, true, true, + &fixed, &frac); + calculate_mbp_width(b->style, RIGHT, + true, true, true, + &fixed, &frac); + } if (0 < width + fixed) width += fixed; } else if (b->flags & IFRAME) { @@ -554,13 +579,25 @@ layout_minmax_line(struct box *first, width = 400; fixed = frac = 0; - calculate_mbp_width(b->style, LEFT, true, true, true, - &fixed, &frac); - calculate_mbp_width(b->style, RIGHT, true, true, true, - &fixed, &frac); + if (bs == CSS_BOX_SIZING_BORDER_BOX) { + calculate_mbp_width(b->style, LEFT, + true, false, false, + &fixed, &frac); + calculate_mbp_width(b->style, RIGHT, + true, false, false, + &fixed, &frac); + } else { + calculate_mbp_width(b->style, LEFT, + true, true, true, + &fixed, &frac); + calculate_mbp_width(b->style, RIGHT, + true, true, true, + &fixed, &frac); + } if (0 < width + fixed) width += fixed; + } else { /* form control with no object */ if (width == AUTO) @@ -667,6 +704,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) enum css_height_e htype = CSS_HEIGHT_AUTO; css_fixed height = 0; css_unit hunit = CSS_UNIT_PX; + enum css_box_sizing_e bs = CSS_BOX_SIZING_CONTENT_BOX; bool child_has_height = false; assert(block->type == BOX_BLOCK || @@ -680,6 +718,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) if (block->style != NULL) { wtype = css_computed_width(block->style, &width, &wunit); htype = css_computed_height(block->style, &height, &hunit); + bs = css_computed_box_sizing(block->style); } /* set whether the minimum width is of any interest for this box */ @@ -800,6 +839,19 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) if (block->type != BOX_TABLE_CELL && wtype == CSS_WIDTH_SET && wunit != CSS_UNIT_PCT) { min = max = FIXTOINT(nscss_len2px(width, wunit, block->style)); + if (bs == CSS_BOX_SIZING_BORDER_BOX) { + int border_box_fixed = 0; + float border_box_frac = 0; + calculate_mbp_width(block->style, LEFT, + false, true, true, + &border_box_fixed, &border_box_frac); + calculate_mbp_width(block->style, RIGHT, + false, true, true, + &border_box_fixed, &border_box_frac); + if (min < border_box_fixed) { + min = max = border_box_fixed; + } + } } if (htype == CSS_HEIGHT_SET && hunit != CSS_UNIT_PCT && @@ -811,12 +863,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) /* add margins, border, padding to min, max widths */ /* Note: we don't know available width here so percentage margin * and paddings are wrong. */ - if (block->gadget && wtype == CSS_WIDTH_SET && - (block->gadget->type == GADGET_SUBMIT || - block->gadget->type == GADGET_RESET || - block->gadget->type == GADGET_BUTTON)) { - /* some gadgets with specified width already include border and - * padding, so just get margin */ + if (bs == CSS_BOX_SIZING_BORDER_BOX && wtype == CSS_WIDTH_SET) { + /* Border and padding included in width, so just get margin */ calculate_mbp_width(block->style, LEFT, true, false, false, &extra_fixed, &extra_frac); calculate_mbp_width(block->style, RIGHT, true, false, false, @@ -850,12 +898,11 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) /** - * Under some circumstances, specified dimensions for form elements include - * borders and padding. + * Adjust a specified width or height for the box-sizing property. + * + * This turns the specified dimension into a content-box dimension. * * \param box gadget to adjust dimensions of - * \param percentage whether the gadget has its dimension specified as a - * percentage * \param available_width width of containing block * \param setwidth set true if the dimension to be tweaked is a width, * else set false for a height @@ -863,25 +910,29 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) * updated to new value after consideration of * gadget properties. */ -static void layout_tweak_form_dimensions(struct box *box, bool percentage, - int available_width, bool setwidth, int *dimension) +static void layout_handle_box_sizing( + struct box *box, + int available_width, + bool setwidth, + int *dimension) { - int fixed = 0; - float frac = 0; + enum css_box_sizing_e bs; + + assert(box && box->style); - assert(box && box->gadget); + bs = css_computed_box_sizing(box->style); + + if (bs == CSS_BOX_SIZING_BORDER_BOX) { + int orig = *dimension; + int fixed = 0; + float frac = 0; - /* specified gadget widths include borders and padding in some - * cases */ - if (percentage || box->gadget->type == GADGET_SUBMIT || - box->gadget->type == GADGET_RESET || - box->gadget->type == GADGET_BUTTON) { calculate_mbp_width(box->style, setwidth ? LEFT : TOP, false, true, true, &fixed, &frac); calculate_mbp_width(box->style, setwidth ? RIGHT : BOTTOM, false, true, true, &fixed, &frac); - *dimension -= frac * available_width + fixed; - *dimension = *dimension > 0 ? *dimension : 0; + orig -= frac * available_width + fixed; + *dimension = orig > 0 ? orig : 0; } } @@ -921,7 +972,6 @@ layout_find_dimensions(int available_width, { struct box *containing_block = NULL; unsigned int i; - bool percentage; if (width) { enum css_width_e wtype; @@ -942,13 +992,9 @@ layout_find_dimensions(int available_width, *width = AUTO; } - /* specified gadget widths include borders and padding in some - * cases */ - if (box->gadget && *width != AUTO) { - percentage = unit == CSS_UNIT_PCT; - - layout_tweak_form_dimensions(box, percentage, - available_width, true, width); + if (*width != AUTO) { + layout_handle_box_sizing(box, available_width, + true, width); } } @@ -1034,13 +1080,9 @@ layout_find_dimensions(int available_width, *height = AUTO; } - /* specified gadget heights include borders and padding in - * some cases */ - if (box->gadget && *height != AUTO) { - percentage = unit == CSS_UNIT_PCT; - - layout_tweak_form_dimensions(box, percentage, - available_width, false, height); + if (*height != AUTO) { + layout_handle_box_sizing(box, available_width, + false, height); } } @@ -1064,13 +1106,9 @@ layout_find_dimensions(int available_width, *max_width = -1; } - /* specified gadget widths include borders and padding in some - * cases */ - if (box->gadget && *max_width != -1) { - percentage = unit == CSS_UNIT_PCT; - - layout_tweak_form_dimensions(box, percentage, - available_width, true, max_width); + if (*max_width != -1) { + layout_handle_box_sizing(box, available_width, + true, max_width); } } @@ -1094,13 +1132,9 @@ layout_find_dimensions(int available_width, *min_width = 0; } - /* specified gadget widths include borders and padding in some - * cases */ - if (box->gadget && *min_width != 0) { - percentage = unit == CSS_UNIT_PCT; - - layout_tweak_form_dimensions(box, percentage, - available_width, true, min_width); + if (*min_width != 0) { + layout_handle_box_sizing(box, available_width, + true, min_width); } } -- cgit v1.2.3