You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
720 lines
19 KiB
720 lines
19 KiB
/*
|
|
* 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
|
|
|
|
/**
|
|
* 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_FLEX ||
|
|
b->type == BOX_INLINE_BLOCK ||
|
|
b->type == BOX_TEXT ||
|
|
b->type == BOX_INLINE_END;
|
|
}
|
|
|
|
/** Layout helper: Check whether box takes part in inline flow. */
|
|
static inline bool lh__box_is_flex_container(const struct box *b)
|
|
{
|
|
return b->type == BOX_FLEX ||
|
|
b->type == BOX_INLINE_FLEX;
|
|
}
|
|
|
|
/** Layout helper: Check whether box takes part in inline flow. */
|
|
static inline bool lh__box_is_flex_item(const struct box *b)
|
|
{
|
|
return (b->parent != NULL) && lh__box_is_flex_container(b->parent);
|
|
}
|
|
|
|
/** 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;
|
|
}
|
|
|
|
static inline bool lh__box_is_absolute(const struct box *b)
|
|
{
|
|
return css_computed_position(b->style) == CSS_POSITION_ABSOLUTE ||
|
|
css_computed_position(b->style) == CSS_POSITION_FIXED;
|
|
}
|
|
|
|
static inline bool lh__flex_main_is_horizontal(const struct box *flex)
|
|
{
|
|
const css_computed_style *style = flex->style;
|
|
|
|
assert(style != NULL);
|
|
|
|
switch (css_computed_flex_direction(style)) {
|
|
default: /* Fallthrough. */
|
|
case CSS_FLEX_DIRECTION_ROW: /* Fallthrough. */
|
|
case CSS_FLEX_DIRECTION_ROW_REVERSE:
|
|
return true;
|
|
case CSS_FLEX_DIRECTION_COLUMN: /* Fallthrough. */
|
|
case CSS_FLEX_DIRECTION_COLUMN_REVERSE:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static inline bool lh__flex_direction_reversed(const struct box *flex)
|
|
{
|
|
switch (css_computed_flex_direction(flex->style)) {
|
|
default: /* Fallthrough. */
|
|
case CSS_FLEX_DIRECTION_ROW_REVERSE: /* Fallthrough. */
|
|
case CSS_FLEX_DIRECTION_COLUMN_REVERSE:
|
|
return true;
|
|
case CSS_FLEX_DIRECTION_ROW: /* Fallthrough. */
|
|
case CSS_FLEX_DIRECTION_COLUMN:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static inline int lh__non_auto_margin(const struct box *b, enum box_side side)
|
|
{
|
|
return (b->margin[side] == AUTO) ? 0 : b->margin[side];
|
|
}
|
|
|
|
static inline int lh__delta_outer_height(const struct box *b)
|
|
{
|
|
return b->padding[TOP] +
|
|
b->padding[BOTTOM] +
|
|
b->border[TOP].width +
|
|
b->border[BOTTOM].width +
|
|
lh__non_auto_margin(b, TOP) +
|
|
lh__non_auto_margin(b, BOTTOM);
|
|
}
|
|
|
|
static inline int lh__delta_outer_width(const struct box *b)
|
|
{
|
|
return b->padding[LEFT] +
|
|
b->padding[RIGHT] +
|
|
b->border[LEFT].width +
|
|
b->border[RIGHT].width +
|
|
lh__non_auto_margin(b, LEFT) +
|
|
lh__non_auto_margin(b, RIGHT);
|
|
}
|
|
|
|
static inline int lh__delta_outer_main(
|
|
const struct box *flex,
|
|
const struct box *b)
|
|
{
|
|
if (lh__flex_main_is_horizontal(flex)) {
|
|
return lh__delta_outer_width(b);
|
|
} else {
|
|
return lh__delta_outer_height(b);
|
|
}
|
|
}
|
|
|
|
static inline int lh__delta_outer_cross(
|
|
const struct box *flex,
|
|
const struct box *b)
|
|
{
|
|
if (lh__flex_main_is_horizontal(flex) == false) {
|
|
return lh__delta_outer_width(b);
|
|
} else {
|
|
return lh__delta_outer_height(b);
|
|
}
|
|
}
|
|
|
|
static inline int *lh__box_size_main_ptr(
|
|
bool horizontal,
|
|
struct box *b)
|
|
{
|
|
return horizontal ? &b->width : &b->height;
|
|
}
|
|
|
|
static inline int *lh__box_size_cross_ptr(
|
|
bool horizontal,
|
|
struct box *b)
|
|
{
|
|
return horizontal ? &b->height : &b->width;
|
|
}
|
|
|
|
static inline int lh__box_size_main(
|
|
bool horizontal,
|
|
const struct box *b)
|
|
{
|
|
return horizontal ? b->width : b->height;
|
|
}
|
|
|
|
static inline int lh__box_size_cross(
|
|
bool horizontal,
|
|
const struct box *b)
|
|
{
|
|
return horizontal ? b->height : b->width;
|
|
}
|
|
|
|
static inline bool lh__box_size_cross_is_auto(
|
|
bool horizontal,
|
|
struct box *b)
|
|
{
|
|
css_fixed length;
|
|
css_unit unit;
|
|
|
|
if (horizontal) {
|
|
return css_computed_height(b->style,
|
|
&length, &unit) == CSS_HEIGHT_AUTO;
|
|
} else {
|
|
return css_computed_width(b->style,
|
|
&length, &unit) == CSS_WIDTH_AUTO;
|
|
}
|
|
}
|
|
|
|
static inline enum css_align_self_e lh__box_align_self(
|
|
const struct box *flex,
|
|
const struct box *item)
|
|
{
|
|
enum css_align_self_e align_self = css_computed_align_self(item->style);
|
|
|
|
if (align_self == CSS_ALIGN_SELF_AUTO) {
|
|
align_self = css_computed_align_items(flex->style);
|
|
}
|
|
|
|
return align_self;
|
|
}
|
|
|
|
/**
|
|
* 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 += FIXTOFLT(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 += FIXTOFLT(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) {
|
|
if (css_computed_width_px(style, unit_len_ctx,
|
|
available_width, width) == CSS_WIDTH_SET) {
|
|
layout_handle_box_sizing(unit_len_ctx, box,
|
|
available_width, true, width);
|
|
} else {
|
|
*width = AUTO;
|
|
}
|
|
}
|
|
|
|
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
|