diff options
author | Michael Drake <tlsa@netsurf-browser.org> | 2022-10-15 14:19:36 +0100 |
---|---|---|
committer | Michael Drake <tlsa@netsurf-browser.org> | 2022-10-23 17:25:51 +0100 |
commit | 1cf74a9d79ee49aeae237ceb53a3b4c31e02054e (patch) | |
tree | 182d87a8fac54f911ee410571b63f3af1b82a5fb | |
parent | e5790106c5600d378a4c25eac68e9c5a3ba4ff73 (diff) | |
download | netsurf-1cf74a9d79ee49aeae237ceb53a3b4c31e02054e.tar.gz netsurf-1cf74a9d79ee49aeae237ceb53a3b4c31e02054e.tar.bz2 |
html: layout: Split out common helpers
-rw-r--r-- | content/handlers/html/layout.c | 542 | ||||
-rw-r--r-- | content/handlers/html/layout_internal.h | 584 |
2 files changed, 599 insertions, 527 deletions
diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c index cb5be5dde..99e9bcf19 100644 --- a/content/handlers/html/layout.c +++ b/content/handlers/html/layout.c @@ -67,13 +67,9 @@ #include "html/font.h" #include "html/form_internal.h" #include "html/layout.h" +#include "html/layout_internal.h" #include "html/table.h" -#define AUTO INT_MIN - -/* Fixed point percentage (a) of an integer (b), to an integer */ -#define FPCT_OF_INT_TOINT(a, b) (FIXTOINT(FDIV((a * b), F_100))) - typedef uint8_t (*css_len_func)( const css_computed_style *style, css_fixed *length, css_unit *unit); @@ -84,7 +80,7 @@ typedef uint8_t (*css_border_color_func)( css_color *color); /** Array of per-side access functions for computed style margins. */ -static const css_len_func margin_funcs[4] = { +const css_len_func margin_funcs[4] = { [TOP] = css_computed_margin_top, [RIGHT] = css_computed_margin_right, [BOTTOM] = css_computed_margin_bottom, @@ -92,7 +88,7 @@ static const css_len_func margin_funcs[4] = { }; /** Array of per-side access functions for computed style paddings. */ -static const css_len_func padding_funcs[4] = { +const css_len_func padding_funcs[4] = { [TOP] = css_computed_padding_top, [RIGHT] = css_computed_padding_right, [BOTTOM] = css_computed_padding_bottom, @@ -100,7 +96,7 @@ static const css_len_func padding_funcs[4] = { }; /** Array of per-side access functions for computed style border_widths. */ -static const css_len_func border_width_funcs[4] = { +const css_len_func border_width_funcs[4] = { [TOP] = css_computed_border_top_width, [RIGHT] = css_computed_border_right_width, [BOTTOM] = css_computed_border_bottom_width, @@ -108,67 +104,15 @@ static const css_len_func border_width_funcs[4] = { }; /** Array of per-side access functions for computed style border styles. */ -static const css_border_style_func border_style_funcs[4] = { +const css_border_style_func border_style_funcs[4] = { [TOP] = css_computed_border_top_style, [RIGHT] = css_computed_border_right_style, [BOTTOM] = css_computed_border_bottom_style, [LEFT] = css_computed_border_left_style, }; -/** Layout helper: Check for CSS border on given side. */ -static inline bool lh__have_border( - enum box_side side, - const css_computed_style *style) -{ - return border_style_funcs[side](style) != CSS_BORDER_STYLE_NONE; -} - -/** Layout helper: Check whether box is a float. */ -static inline bool lh__box_is_float_box(const struct box *b) -{ - return b->type == BOX_FLOAT_LEFT || - b->type == BOX_FLOAT_RIGHT; -} - -/** Layout helper: Check whether box takes part in inline flow. */ -static inline bool lh__box_is_inline_flow(const struct box *b) -{ - return b->type == BOX_INLINE || - b->type == BOX_INLINE_BLOCK || - b->type == BOX_TEXT || - b->type == BOX_INLINE_END; -} - -/** Layout helper: Check whether box is inline level. (Includes BR.) */ -static inline bool lh__box_is_inline_level(const struct box *b) -{ - return lh__box_is_inline_flow(b) || - b->type == BOX_BR; -} - -/** Layout helper: Check whether box is inline level. (Includes BR, floats.) */ -static inline bool lh__box_is_inline_content(const struct box *b) -{ - return lh__box_is_float_box(b) || - lh__box_is_inline_level(b); -} - -/** Layout helper: Check whether box is an object. */ -static inline bool lh__box_is_object(const struct box *b) -{ - return b->object || - (b->flags & (IFRAME | REPLACE_DIM)); -} - -/** Layout helper: Check whether box is replaced. */ -static inline bool lh__box_is_replace(const struct box *b) -{ - return b->gadget || - lh__box_is_object(b); -} - /** Array of per-side access functions for computed style border colors. */ -static const css_border_color_func border_color_funcs[4] = { +const css_border_color_func border_color_funcs[4] = { [TOP] = css_computed_border_top_color, [RIGHT] = css_computed_border_right_color, [BOTTOM] = css_computed_border_bottom_color, @@ -176,10 +120,6 @@ static const css_border_color_func border_color_funcs[4] = { }; /* forward declaration to break cycles */ -static bool layout_block_context( - struct box *block, - int viewport_height, - html_content *content); static void layout_minmax_block( struct box *block, const struct gui_layout_table *font_func, @@ -315,74 +255,6 @@ static int layout_text_indent( /** - * Determine width of margin, borders, and padding on one side of a box. - * - * \param unit_len_ctx CSS length conversion context for document - * \param style style to measure - * \param side side of box to measure - * \param margin whether margin width is required - * \param border whether border width is required - * \param padding whether padding width is required - * \param fixed increased by sum of fixed margin, border, and padding - * \param frac increased by sum of fractional margin and padding - */ -static void -calculate_mbp_width(const css_unit_ctx *unit_len_ctx, - const css_computed_style *style, - unsigned int side, - bool margin, - bool border, - bool padding, - int *fixed, - float *frac) -{ - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - - assert(style); - - /* margin */ - if (margin) { - enum css_margin_e type; - - type = margin_funcs[side](style, &value, &unit); - if (type == CSS_MARGIN_SET) { - if (unit == CSS_UNIT_PCT) { - *frac += FIXTOINT(FDIV(value, F_100)); - } else { - *fixed += FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - } - } - } - - /* border */ - if (border) { - if (lh__have_border(side, style)) { - border_width_funcs[side](style, &value, &unit); - - *fixed += FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - } - } - - /* padding */ - if (padding) { - padding_funcs[side](style, &value, &unit); - if (unit == CSS_UNIT_PCT) { - *frac += FIXTOINT(FDIV(value, F_100)); - } else { - *fixed += FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - } - } -} - - -/** * Calculate minimum and maximum width of a table. * * \param table box of type TABLE @@ -1227,375 +1099,6 @@ static void layout_minmax_block( /** - * Adjust a specified width or height for the box-sizing property. - * - * This turns the specified dimension into a content-box dimension. - * - * \param unit_len_ctx Length conversion context - * \param box gadget to adjust dimensions of - * \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 - * \param dimension current value for given width/height dimension. - * updated to new value after consideration of - * gadget properties. - */ -static void layout_handle_box_sizing( - const css_unit_ctx *unit_len_ctx, - const struct box *box, - int available_width, - bool setwidth, - int *dimension) -{ - enum css_box_sizing_e bs; - - assert(box && box->style); - - bs = css_computed_box_sizing(box->style); - - if (bs == CSS_BOX_SIZING_BORDER_BOX) { - int orig = *dimension; - int fixed = 0; - float frac = 0; - - calculate_mbp_width(unit_len_ctx, box->style, - setwidth ? LEFT : TOP, - false, true, true, &fixed, &frac); - calculate_mbp_width(unit_len_ctx, box->style, - setwidth ? RIGHT : BOTTOM, - false, true, true, &fixed, &frac); - orig -= frac * available_width + fixed; - *dimension = orig > 0 ? orig : 0; - } -} - - -/** - * Calculate width, height, and thickness of margins, paddings, and borders. - * - * \param unit_len_ctx Length conversion context - * \param available_width width of containing block - * \param viewport_height height of viewport in pixels or -ve if unknown - * \param box current box - * \param style style giving width, height, margins, paddings, - * and borders - * \param width updated to width, may be NULL - * \param height updated to height, may be NULL - * \param max_width updated to max-width, may be NULL - * \param min_width updated to min-width, may be NULL - * \param max_height updated to max-height, may be NULL - * \param min_height updated to min-height, may be NULL - * \param margin filled with margins, may be NULL - * \param padding filled with paddings, may be NULL - * \param border filled with border widths, may be NULL - */ -static void -layout_find_dimensions(const css_unit_ctx *unit_len_ctx, - int available_width, - int viewport_height, - const struct box *box, - const css_computed_style *style, - int *width, - int *height, - int *max_width, - int *min_width, - int *max_height, - int *min_height, - int margin[4], - int padding[4], - struct box_border border[4]) -{ - struct box *containing_block = NULL; - unsigned int i; - - if (width) { - enum css_width_e 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 = FPCT_OF_INT_TOINT( - value, available_width); - } else { - *width = FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - } - } else { - *width = AUTO; - } - - if (*width != AUTO) { - layout_handle_box_sizing(unit_len_ctx, box, available_width, - true, width); - } - } - - if (height) { - enum css_height_e 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_e cbhtype; - - if (css_computed_position(box->style) == - CSS_POSITION_ABSOLUTE && - box->parent) { - /* 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) { - 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 && - (css_computed_position(box->style) == - CSS_POSITION_ABSOLUTE || - cbhtype == CSS_HEIGHT_SET)) { - /* Box is absolutely positioned or its - * containing block has a valid - * specified height. - * (CSS 2.1 Section 10.5) */ - *height = FPCT_OF_INT_TOINT(value, - containing_block->height); - } else if ((!box->parent || - !box->parent->parent) && - viewport_height >= 0) { - /* If root element or it's child - * (HTML or BODY) */ - *height = FPCT_OF_INT_TOINT(value, - viewport_height); - } else { - /* precentage height not permissible - * treat height as auto */ - *height = AUTO; - } - } else { - *height = FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - } - } else { - *height = AUTO; - } - - if (*height != AUTO) { - layout_handle_box_sizing(unit_len_ctx, box, available_width, - false, height); - } - } - - if (max_width) { - enum css_max_width_e 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 = FPCT_OF_INT_TOINT(value, - available_width); - } else { - *max_width = FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - } - } else { - /* Inadmissible */ - *max_width = -1; - } - - if (*max_width != -1) { - layout_handle_box_sizing(unit_len_ctx, box, available_width, - true, max_width); - } - } - - if (min_width) { - enum css_min_width_e type; - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - - type = ns_computed_min_width(style, &value, &unit); - - if (type == CSS_MIN_WIDTH_SET) { - if (unit == CSS_UNIT_PCT) { - *min_width = FPCT_OF_INT_TOINT(value, - available_width); - } else { - *min_width = FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - } - } else { - /* Inadmissible */ - *min_width = 0; - } - - if (*min_width != 0) { - layout_handle_box_sizing(unit_len_ctx, box, available_width, - true, min_width); - } - } - - if (max_height) { - enum css_max_height_e type; - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - - type = css_computed_max_height(style, &value, &unit); - - if (type == CSS_MAX_HEIGHT_SET) { - if (unit == CSS_UNIT_PCT) { - /* TODO: handle percentage */ - *max_height = -1; - } else { - *max_height = FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - } - } else { - /* Inadmissible */ - *max_height = -1; - } - } - - if (min_height) { - enum css_min_height_e type; - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - - type = ns_computed_min_height(style, &value, &unit); - - if (type == CSS_MIN_HEIGHT_SET) { - if (unit == CSS_UNIT_PCT) { - /* TODO: handle percentage */ - *min_height = 0; - } else { - *min_height = FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - } - } else { - /* Inadmissible */ - *min_height = 0; - } - } - - for (i = 0; i != 4; i++) { - if (margin) { - enum css_margin_e type = CSS_MARGIN_AUTO; - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - - type = margin_funcs[i](style, &value, &unit); - - if (type == CSS_MARGIN_SET) { - if (unit == CSS_UNIT_PCT) { - margin[i] = FPCT_OF_INT_TOINT(value, - available_width); - } else { - margin[i] = FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - } - } else { - margin[i] = AUTO; - } - } - - if (padding) { - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - - padding_funcs[i](style, &value, &unit); - - if (unit == CSS_UNIT_PCT) { - padding[i] = FPCT_OF_INT_TOINT(value, - available_width); - } else { - padding[i] = FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - } - } - - /* Table cell borders are populated in table.c */ - if (border && box->type != BOX_TABLE_CELL) { - enum css_border_style_e bstyle = CSS_BORDER_STYLE_NONE; - css_color color = 0; - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - - border_width_funcs[i](style, &value, &unit); - bstyle = border_style_funcs[i](style); - border_color_funcs[i](style, &color); - - border[i].style = bstyle; - border[i].c = color; - - if (bstyle == CSS_BORDER_STYLE_HIDDEN || - bstyle == CSS_BORDER_STYLE_NONE) - /* spec unclear: following Mozilla */ - border[i].width = 0; - else - border[i].width = FIXTOINT(css_unit_len2device_px( - style, unit_len_ctx, - value, unit)); - - /* 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; - } - } -} - - -/** * Find next block that current margin collapses to. * * \param unit_len_ctx Length conversion context @@ -2058,15 +1561,10 @@ static void layout_move_children(struct box *box, int x, int y) } -/** - * Layout a table. - * - * \param table table to layout - * \param available_width width of containing block - * \param content memory pool for any new boxes - * \return true on success, false on memory exhaustion - */ -static bool layout_table(struct box *table, int available_width, +/* Documented in layout_internal.h */ +bool layout_table( + struct box *table, + int available_width, html_content *content) { unsigned int columns = table->columns; /* total columns */ @@ -3977,21 +3475,11 @@ static bool layout_inline_container(struct box *inline_container, int width, } -/** - * Layout a block formatting context. - * - * \param block BLOCK, INLINE_BLOCK, or TABLE_CELL to layout - * \param viewport_height Height of viewport in pixels or -ve if unknown - * \param content Memory pool for any new boxes - * \return true on success, false on memory exhaustion - * - * This function carries out layout of a block and its children, as described - * in CSS 2.1 9.4.1. - */ -static bool -layout_block_context(struct box *block, - int viewport_height, - html_content *content) +/* Documented in layout_intertnal.h */ +bool layout_block_context( + struct box *block, + int viewport_height, + html_content *content) { struct box *box; int cx, cy; /**< current coordinates */ diff --git a/content/handlers/html/layout_internal.h b/content/handlers/html/layout_internal.h new file mode 100644 index 000000000..0c171ef44 --- /dev/null +++ b/content/handlers/html/layout_internal.h @@ -0,0 +1,584 @@ +/* + * Copyright 2003 James Bursa <bursa@users.sourceforge.net> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * HTML layout private interface. + */ + +#ifndef NETSURF_HTML_LAYOUT_INTERNAL_H +#define NETSURF_HTML_LAYOUT_INTERNAL_H + +#define AUTO INT_MIN + +/* Fixed point percentage (a) of an integer (b), to an integer */ +#define FPCT_OF_INT_TOINT(a, b) (FIXTOINT(FDIV((a * b), F_100))) + +/** + * Layout a block formatting context. + * + * \param block BLOCK, INLINE_BLOCK, or TABLE_CELL to layout + * \param viewport_height Height of viewport in pixels or -ve if unknown + * \param content Memory pool for any new boxes + * \return true on success, false on memory exhaustion + * + * This function carries out layout of a block and its children, as described + * in CSS 2.1 9.4.1. + */ +bool layout_block_context( + struct box *block, + int viewport_height, + html_content *content); + +/** + * Layout a table. + * + * \param table table to layout + * \param available_width width of containing block + * \param content memory pool for any new boxes + * \return true on success, false on memory exhaustion + */ +bool layout_table( + struct box *table, + int available_width, + html_content *content); + +/** + * Layout a flex container. + * + * \param[in] flex table to layout + * \param[in] available_width width of containing block + * \param[in] content memory pool for any new boxes + * \return true on success, false on memory exhaustion + */ +bool layout_flex( + struct box *flex, + int available_width, + html_content *content); + +typedef uint8_t (*css_len_func)( + const css_computed_style *style, + css_fixed *length, css_unit *unit); +typedef uint8_t (*css_border_style_func)( + const css_computed_style *style); +typedef uint8_t (*css_border_color_func)( + const css_computed_style *style, + css_color *color); + +/** Array of per-side access functions for computed style margins. */ +extern const css_len_func margin_funcs[4]; + +/** Array of per-side access functions for computed style paddings. */ +extern const css_len_func padding_funcs[4]; + +/** Array of per-side access functions for computed style border_widths. */ +extern const css_len_func border_width_funcs[4]; + +/** Array of per-side access functions for computed style border styles. */ +extern const css_border_style_func border_style_funcs[4]; + +/** Array of per-side access functions for computed style border colors. */ +extern const css_border_color_func border_color_funcs[4]; + +/** Layout helper: Check whether box is a float. */ +static inline bool lh__box_is_float_box(const struct box *b) +{ + return b->type == BOX_FLOAT_LEFT || + b->type == BOX_FLOAT_RIGHT; +} + +/** Layout helper: Check whether box takes part in inline flow. */ +static inline bool lh__box_is_inline_flow(const struct box *b) +{ + return b->type == BOX_INLINE || + b->type == BOX_INLINE_BLOCK || + b->type == BOX_TEXT || + b->type == BOX_INLINE_END; +} + +/** Layout helper: Check whether box is inline level. (Includes BR.) */ +static inline bool lh__box_is_inline_level(const struct box *b) +{ + return lh__box_is_inline_flow(b) || + b->type == BOX_BR; +} + +/** Layout helper: Check whether box is inline level. (Includes BR, floats.) */ +static inline bool lh__box_is_inline_content(const struct box *b) +{ + return lh__box_is_float_box(b) || + lh__box_is_inline_level(b); +} + +/** Layout helper: Check whether box is an object. */ +static inline bool lh__box_is_object(const struct box *b) +{ + return b->object || + (b->flags & (IFRAME | REPLACE_DIM)); +} + +/** Layout helper: Check whether box is replaced. */ +static inline bool lh__box_is_replace(const struct box *b) +{ + return b->gadget || + lh__box_is_object(b); +} + +/** Layout helper: Check for CSS border on given side. */ +static inline bool lh__have_border( + enum box_side side, + const css_computed_style *style) +{ + return border_style_funcs[side](style) != CSS_BORDER_STYLE_NONE; +} + +/** + * Determine width of margin, borders, and padding on one side of a box. + * + * \param unit_len_ctx CSS length conversion context for document + * \param style style to measure + * \param side side of box to measure + * \param margin whether margin width is required + * \param border whether border width is required + * \param padding whether padding width is required + * \param fixed increased by sum of fixed margin, border, and padding + * \param frac increased by sum of fractional margin and padding + */ +static inline void calculate_mbp_width( + const css_unit_ctx *unit_len_ctx, + const css_computed_style *style, + unsigned int side, + bool margin, + bool border, + bool padding, + int *fixed, + float *frac) +{ + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + assert(style); + + /* margin */ + if (margin) { + enum css_margin_e type; + + type = margin_funcs[side](style, &value, &unit); + if (type == CSS_MARGIN_SET) { + if (unit == CSS_UNIT_PCT) { + *frac += FIXTOINT(FDIV(value, F_100)); + } else { + *fixed += FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + } + } + } + + /* border */ + if (border) { + if (lh__have_border(side, style)) { + border_width_funcs[side](style, &value, &unit); + + *fixed += FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + } + } + + /* padding */ + if (padding) { + padding_funcs[side](style, &value, &unit); + if (unit == CSS_UNIT_PCT) { + *frac += FIXTOINT(FDIV(value, F_100)); + } else { + *fixed += FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + } + } +} + +/** + * Adjust a specified width or height for the box-sizing property. + * + * This turns the specified dimension into a content-box dimension. + * + * \param unit_len_ctx Length conversion context + * \param box gadget to adjust dimensions of + * \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 + * \param dimension current value for given width/height dimension. + * updated to new value after consideration of + * gadget properties. + */ +static inline void layout_handle_box_sizing( + const css_unit_ctx *unit_len_ctx, + const struct box *box, + int available_width, + bool setwidth, + int *dimension) +{ + enum css_box_sizing_e bs; + + assert(box && box->style); + + bs = css_computed_box_sizing(box->style); + + if (bs == CSS_BOX_SIZING_BORDER_BOX) { + int orig = *dimension; + int fixed = 0; + float frac = 0; + + calculate_mbp_width(unit_len_ctx, box->style, + setwidth ? LEFT : TOP, + false, true, true, &fixed, &frac); + calculate_mbp_width(unit_len_ctx, box->style, + setwidth ? RIGHT : BOTTOM, + false, true, true, &fixed, &frac); + orig -= frac * available_width + fixed; + *dimension = orig > 0 ? orig : 0; + } +} + +/** + * Calculate width, height, and thickness of margins, paddings, and borders. + * + * \param unit_len_ctx Length conversion context + * \param available_width width of containing block + * \param viewport_height height of viewport in pixels or -ve if unknown + * \param box current box + * \param style style giving width, height, margins, paddings, + * and borders + * \param width updated to width, may be NULL + * \param height updated to height, may be NULL + * \param max_width updated to max-width, may be NULL + * \param min_width updated to min-width, may be NULL + * \param max_height updated to max-height, may be NULL + * \param min_height updated to min-height, may be NULL + * \param margin filled with margins, may be NULL + * \param padding filled with paddings, may be NULL + * \param border filled with border widths, may be NULL + */ +static inline void layout_find_dimensions( + const css_unit_ctx *unit_len_ctx, + int available_width, + int viewport_height, + const struct box *box, + const css_computed_style *style, + int *width, + int *height, + int *max_width, + int *min_width, + int *max_height, + int *min_height, + int margin[4], + int padding[4], + struct box_border border[4]) +{ + struct box *containing_block = NULL; + unsigned int i; + + if (width) { + enum css_width_e 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 = FPCT_OF_INT_TOINT( + value, available_width); + } else { + *width = FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + } + } else { + *width = AUTO; + } + + if (*width != AUTO) { + layout_handle_box_sizing(unit_len_ctx, box, + available_width, true, width); + } + } + + if (height) { + enum css_height_e 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_e cbhtype; + + if (css_computed_position(box->style) == + CSS_POSITION_ABSOLUTE && + box->parent) { + /* 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) { + 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 && + (css_computed_position(box->style) == + CSS_POSITION_ABSOLUTE || + cbhtype == CSS_HEIGHT_SET)) { + /* Box is absolutely positioned or its + * containing block has a valid + * specified height. + * (CSS 2.1 Section 10.5) */ + *height = FPCT_OF_INT_TOINT(value, + containing_block->height); + } else if ((!box->parent || + !box->parent->parent) && + viewport_height >= 0) { + /* If root element or it's child + * (HTML or BODY) */ + *height = FPCT_OF_INT_TOINT(value, + viewport_height); + } else { + /* precentage height not permissible + * treat height as auto */ + *height = AUTO; + } + } else { + *height = FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + } + } else { + *height = AUTO; + } + + if (*height != AUTO) { + layout_handle_box_sizing(unit_len_ctx, box, + available_width, false, height); + } + } + + if (max_width) { + enum css_max_width_e 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 = FPCT_OF_INT_TOINT(value, + available_width); + } else { + *max_width = FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + } + } else { + /* Inadmissible */ + *max_width = -1; + } + + if (*max_width != -1) { + layout_handle_box_sizing(unit_len_ctx, box, + available_width, true, max_width); + } + } + + if (min_width) { + enum css_min_width_e type; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + type = ns_computed_min_width(style, &value, &unit); + + if (type == CSS_MIN_WIDTH_SET) { + if (unit == CSS_UNIT_PCT) { + *min_width = FPCT_OF_INT_TOINT(value, + available_width); + } else { + *min_width = FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + } + } else { + /* Inadmissible */ + *min_width = 0; + } + + if (*min_width != 0) { + layout_handle_box_sizing(unit_len_ctx, box, + available_width, true, min_width); + } + } + + if (max_height) { + enum css_max_height_e type; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + type = css_computed_max_height(style, &value, &unit); + + if (type == CSS_MAX_HEIGHT_SET) { + if (unit == CSS_UNIT_PCT) { + /* TODO: handle percentage */ + *max_height = -1; + } else { + *max_height = FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + } + } else { + /* Inadmissible */ + *max_height = -1; + } + } + + if (min_height) { + enum css_min_height_e type; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + type = ns_computed_min_height(style, &value, &unit); + + if (type == CSS_MIN_HEIGHT_SET) { + if (unit == CSS_UNIT_PCT) { + /* TODO: handle percentage */ + *min_height = 0; + } else { + *min_height = FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + } + } else { + /* Inadmissible */ + *min_height = 0; + } + } + + for (i = 0; i != 4; i++) { + if (margin) { + enum css_margin_e type = CSS_MARGIN_AUTO; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + type = margin_funcs[i](style, &value, &unit); + + if (type == CSS_MARGIN_SET) { + if (unit == CSS_UNIT_PCT) { + margin[i] = FPCT_OF_INT_TOINT(value, + available_width); + } else { + margin[i] = FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + } + } else { + margin[i] = AUTO; + } + } + + if (padding) { + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + padding_funcs[i](style, &value, &unit); + + if (unit == CSS_UNIT_PCT) { + padding[i] = FPCT_OF_INT_TOINT(value, + available_width); + } else { + padding[i] = FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + } + } + + /* Table cell borders are populated in table.c */ + if (border && box->type != BOX_TABLE_CELL) { + enum css_border_style_e bstyle = CSS_BORDER_STYLE_NONE; + css_color color = 0; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + border_width_funcs[i](style, &value, &unit); + bstyle = border_style_funcs[i](style); + border_color_funcs[i](style, &color); + + border[i].style = bstyle; + border[i].c = color; + + if (bstyle == CSS_BORDER_STYLE_HIDDEN || + bstyle == CSS_BORDER_STYLE_NONE) + /* spec unclear: following Mozilla */ + border[i].width = 0; + else + border[i].width = FIXTOINT(css_unit_len2device_px( + style, unit_len_ctx, + value, unit)); + + /* 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; + } + } +} + +#endif |