diff options
Diffstat (limited to 'render/table.c')
-rw-r--r-- | render/table.c | 1080 |
1 files changed, 0 insertions, 1080 deletions
diff --git a/render/table.c b/render/table.c deleted file mode 100644 index 08a2e805c..000000000 --- a/render/table.c +++ /dev/null @@ -1,1080 +0,0 @@ -/* - * Copyright 2005 James Bursa <bursa@users.sourceforge.net> - * Copyright 2005 Richard Wilson <info@tinct.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 - * Table processing and layout (implementation). - */ - -#include <assert.h> -#include <dom/dom.h> - -#include "utils/log.h" -#include "utils/talloc.h" -#include "css/utils.h" - -#include "render/box.h" -#include "render/table.h" - -/* Define to enable verbose table debug */ -#undef TABLE_DEBUG - -/** - * Container for border values during table border calculations - */ -struct border { - enum css_border_style_e style; /**< border-style */ - enum css_border_color_e color; /**< border-color type */ - css_color c; /**< border-color value */ - css_fixed width; /**< border-width length */ - css_unit unit; /**< border-width units */ -}; - -static void table_used_left_border_for_cell( - const nscss_len_ctx *len_ctx, - struct box *cell); -static void table_used_top_border_for_cell( - const nscss_len_ctx *len_ctx, - struct box *cell); -static void table_used_right_border_for_cell( - const nscss_len_ctx *len_ctx, - struct box *cell); -static void table_used_bottom_border_for_cell( - const nscss_len_ctx *len_ctx, - struct box *cell); -static bool table_border_is_more_eyecatching( - const nscss_len_ctx *len_ctx, - const struct border *a, - box_type a_src, - const struct border *b, - box_type b_src); -static void table_cell_top_process_table( - const nscss_len_ctx *len_ctx, - struct box *table, - struct border *a, - box_type *a_src); -static bool table_cell_top_process_group( - const nscss_len_ctx *len_ctx, - struct box *cell, - struct box *group, - struct border *a, - box_type *a_src); -static bool table_cell_top_process_row( - const nscss_len_ctx *len_ctx, - struct box *cell, - struct box *row, - struct border *a, - box_type *a_src); - - -/** - * Determine the column width types for a table. - * - * \param len_ctx Length conversion context - * \param table box of type BOX_TABLE - * \return true on success, false on memory exhaustion - * - * The table->col array is allocated and type and width are filled in for each - * column. - */ - -bool table_calculate_column_types( - const nscss_len_ctx *len_ctx, - struct box *table) -{ - unsigned int i, j; - struct column *col; - struct box *row_group, *row, *cell; - - if (table->col) - /* table->col already constructed, for example frameset table */ - return true; - - table->col = col = talloc_array(table, struct column, table->columns); - if (!col) - return false; - - for (i = 0; i != table->columns; i++) { - col[i].type = COLUMN_WIDTH_UNKNOWN; - col[i].width = 0; - col[i].positioned = true; - } - - /* 1st pass: cells with colspan 1 only */ - for (row_group = table->children; row_group; row_group =row_group->next) - for (row = row_group->children; row; row = row->next) - for (cell = row->children; cell; cell = cell->next) { - enum css_width_e type; - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - - assert(cell->type == BOX_TABLE_CELL); - assert(cell->style); - - if (cell->columns != 1) - continue; - i = cell->start_column; - - if (css_computed_position(cell->style) != - CSS_POSITION_ABSOLUTE && - css_computed_position(cell->style) != - CSS_POSITION_FIXED) { - col[i].positioned = false; - } - - type = css_computed_width(cell->style, &value, &unit); - - /* fixed width takes priority over any other width type */ - if (col[i].type != COLUMN_WIDTH_FIXED && - type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) { - col[i].type = COLUMN_WIDTH_FIXED; - col[i].width = FIXTOINT(nscss_len2px(len_ctx, - value, unit, cell->style)); - if (col[i].width < 0) - col[i].width = 0; - continue; - } - - if (col[i].type != COLUMN_WIDTH_UNKNOWN) - continue; - - if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT) { - col[i].type = COLUMN_WIDTH_PERCENT; - col[i].width = FIXTOINT(value); - if (col[i].width < 0) - col[i].width = 0; - } else if (type == CSS_WIDTH_AUTO) { - col[i].type = COLUMN_WIDTH_AUTO; - } - } - - /* 2nd pass: cells which span multiple columns */ - for (row_group = table->children; row_group; row_group =row_group->next) - for (row = row_group->children; row; row = row->next) - for (cell = row->children; cell; cell = cell->next) { - unsigned int fixed_columns = 0, percent_columns = 0, - auto_columns = 0, unknown_columns = 0; - int fixed_width = 0, percent_width = 0; - enum css_width_e type; - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - - if (cell->columns == 1) - continue; - i = cell->start_column; - - for (j = i; j < i + cell->columns; j++) { - col[j].positioned = false; - } - - /* count column types in spanned cells */ - for (j = 0; j != cell->columns; j++) { - if (col[i + j].type == COLUMN_WIDTH_FIXED) { - fixed_width += col[i + j].width; - fixed_columns++; - } else if (col[i + j].type == COLUMN_WIDTH_PERCENT) { - percent_width += col[i + j].width; - percent_columns++; - } else if (col[i + j].type == COLUMN_WIDTH_AUTO) { - auto_columns++; - } else { - unknown_columns++; - } - } - - if (!unknown_columns) - continue; - - type = css_computed_width(cell->style, &value, &unit); - - /* if cell is fixed width, and all spanned columns are fixed - * or unknown width, split extra width among unknown columns */ - if (type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT && - fixed_columns + unknown_columns == - cell->columns) { - int width = (FIXTOFLT(nscss_len2px(len_ctx, value, unit, - cell->style)) - fixed_width) / - unknown_columns; - if (width < 0) - width = 0; - for (j = 0; j != cell->columns; j++) { - if (col[i + j].type == COLUMN_WIDTH_UNKNOWN) { - col[i + j].type = COLUMN_WIDTH_FIXED; - col[i + j].width = width; - } - } - } - - /* as above for percentage width */ - if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT && - percent_columns + unknown_columns == - cell->columns) { - int width = (FIXTOFLT(value) - - percent_width) / unknown_columns; - if (width < 0) - width = 0; - for (j = 0; j != cell->columns; j++) { - if (col[i + j].type == COLUMN_WIDTH_UNKNOWN) { - col[i + j].type = COLUMN_WIDTH_PERCENT; - col[i + j].width = width; - } - } - } - } - - /* use AUTO if no width type was specified */ - for (i = 0; i != table->columns; i++) { - if (col[i].type == COLUMN_WIDTH_UNKNOWN) - col[i].type = COLUMN_WIDTH_AUTO; - } - -#ifdef TABLE_DEBUG - for (i = 0; i != table->columns; i++) - NSLOG(netsurf, INFO, - "table %p, column %u: type %s, width %i", table, i, ((const char *[]){ - "UNKNOWN", - "FIXED", - "AUTO", - "PERCENT", - "RELATIVE", - })[col[i].type], col[i].width); -#endif - - return true; -} - -/** - * Calculate used values of border-{trbl}-{style,color,width} for table cells. - * - * \param len_ctx Length conversion context - * \param cell Table cell to consider - * - * \post \a cell's border array is populated - */ -void table_used_border_for_cell( - const nscss_len_ctx *len_ctx, - struct box *cell) -{ - int side; - - assert(cell->type == BOX_TABLE_CELL); - - if (css_computed_border_collapse(cell->style) == - CSS_BORDER_COLLAPSE_SEPARATE) { - css_fixed width = 0; - css_unit unit = CSS_UNIT_PX; - - /* Left border */ - cell->border[LEFT].style = - css_computed_border_left_style(cell->style); - css_computed_border_left_color(cell->style, - &cell->border[LEFT].c); - css_computed_border_left_width(cell->style, &width, &unit); - cell->border[LEFT].width = - FIXTOINT(nscss_len2px(len_ctx, - width, unit, cell->style)); - - /* Top border */ - cell->border[TOP].style = - css_computed_border_top_style(cell->style); - css_computed_border_top_color(cell->style, - &cell->border[TOP].c); - css_computed_border_top_width(cell->style, &width, &unit); - cell->border[TOP].width = - FIXTOINT(nscss_len2px(len_ctx, - width, unit, cell->style)); - - /* Right border */ - cell->border[RIGHT].style = - css_computed_border_right_style(cell->style); - css_computed_border_right_color(cell->style, - &cell->border[RIGHT].c); - css_computed_border_right_width(cell->style, &width, &unit); - cell->border[RIGHT].width = - FIXTOINT(nscss_len2px(len_ctx, - width, unit, cell->style)); - - /* Bottom border */ - cell->border[BOTTOM].style = - css_computed_border_bottom_style(cell->style); - css_computed_border_bottom_color(cell->style, - &cell->border[BOTTOM].c); - css_computed_border_bottom_width(cell->style, &width, &unit); - cell->border[BOTTOM].width = - FIXTOINT(nscss_len2px(len_ctx, - width, unit, cell->style)); - } else { - /* Left border */ - table_used_left_border_for_cell(len_ctx, cell); - - /* Top border */ - table_used_top_border_for_cell(len_ctx, cell); - - /* Right border */ - table_used_right_border_for_cell(len_ctx, cell); - - /* Bottom border */ - table_used_bottom_border_for_cell(len_ctx, cell); - } - - /* Finally, ensure that any borders configured as - * hidden or none have zero width. (c.f. layout_find_dimensions) */ - for (side = 0; side != 4; side++) { - if (cell->border[side].style == CSS_BORDER_STYLE_HIDDEN || - cell->border[side].style == - CSS_BORDER_STYLE_NONE) - cell->border[side].width = 0; - } -} - -/****************************************************************************** - * Helpers for used border calculations * - ******************************************************************************/ - -/** - * Calculate used values of border-left-{style,color,width} - * - * \param len_ctx Length conversion context - * \param cell Table cell to consider - */ -void table_used_left_border_for_cell( - const nscss_len_ctx *len_ctx, - struct box *cell) -{ - struct border a, b; - box_type a_src, b_src; - - /** \todo Need column and column_group, too */ - - /* Initialise to computed left border for cell */ - a.style = css_computed_border_left_style(cell->style); - a.color = css_computed_border_left_color(cell->style, &a.c); - css_computed_border_left_width(cell->style, &a.width, &a.unit); - a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style); - a.unit = CSS_UNIT_PX; - a_src = BOX_TABLE_CELL; - - if (cell->prev != NULL || cell->start_column != 0) { - /* Cell to the left -- consider its right border */ - struct box *prev = NULL; - - if (cell->prev == NULL) { - struct box *row; - - /* Spanned from a previous row in current row group */ - for (row = cell->parent; row != NULL; row = row->prev) { - for (prev = row->children; prev != NULL; - prev = prev->next) { - if (prev->start_column + - prev->columns == - cell->start_column) - break; - } - - if (prev != NULL) - break; - } - - assert(prev != NULL); - } else { - prev = cell->prev; - } - - b.style = css_computed_border_right_style(prev->style); - b.color = css_computed_border_right_color(prev->style, &b.c); - css_computed_border_right_width(prev->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, prev->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_CELL; - - if (table_border_is_more_eyecatching(len_ctx, - &a, a_src, &b, b_src)) { - a = b; - a_src = b_src; - } - } else { - /* First cell in row, so consider rows and row group */ - struct box *row = cell->parent; - struct box *group = row->parent; - struct box *table = group->parent; - unsigned int rows = cell->rows; - - while (rows-- > 0 && row != NULL) { - /* Spanned rows -- consider their left border */ - b.style = css_computed_border_left_style(row->style); - b.color = css_computed_border_left_color( - row->style, &b.c); - css_computed_border_left_width( - row->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, - b.width, b.unit, row->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW; - - if (table_border_is_more_eyecatching(len_ctx, - &a, a_src, &b, b_src)) { - a = b; - a_src = b_src; - } - - row = row->next; - } - - /** \todo can cells span row groups? */ - - /* Row group -- consider its left border */ - b.style = css_computed_border_left_style(group->style); - b.color = css_computed_border_left_color(group->style, &b.c); - css_computed_border_left_width(group->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW_GROUP; - - if (table_border_is_more_eyecatching(len_ctx, - &a, a_src, &b, b_src)) { - a = b; - a_src = b_src; - } - - /* The table itself -- consider its left border */ - b.style = css_computed_border_left_style(table->style); - b.color = css_computed_border_left_color(table->style, &b.c); - css_computed_border_left_width(table->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE; - - if (table_border_is_more_eyecatching(len_ctx, - &a, a_src, &b, b_src)) { - a = b; - a_src = b_src; - } - } - - /* a now contains the used left border for the cell */ - cell->border[LEFT].style = a.style; - cell->border[LEFT].c = a.c; - cell->border[LEFT].width = FIXTOINT(nscss_len2px(len_ctx, - a.width, a.unit, cell->style)); -} - -/** - * Calculate used values of border-top-{style,color,width} - * - * \param len_ctx Length conversion context - * \param cell Table cell to consider - */ -void table_used_top_border_for_cell( - const nscss_len_ctx *len_ctx, - struct box *cell) -{ - struct border a, b; - box_type a_src, b_src; - struct box *row = cell->parent; - bool process_group = false; - - /* Initialise to computed top border for cell */ - a.style = css_computed_border_top_style(cell->style); - css_computed_border_top_color(cell->style, &a.c); - css_computed_border_top_width(cell->style, &a.width, &a.unit); - a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style); - a.unit = CSS_UNIT_PX; - a_src = BOX_TABLE_CELL; - - /* Top border of row */ - b.style = css_computed_border_top_style(row->style); - css_computed_border_top_color(row->style, &b.c); - css_computed_border_top_width(row->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW; - - if (table_border_is_more_eyecatching(len_ctx, &a, a_src, &b, b_src)) { - a = b; - a_src = b_src; - } - - if (row->prev != NULL) { - /* Consider row(s) above */ - while (table_cell_top_process_row(len_ctx, cell, row->prev, - &a, &a_src) == false) { - if (row->prev->prev == NULL) { - /* Consider row group */ - process_group = true; - break; - } else { - row = row->prev; - } - } - } else { - process_group = true; - } - - if (process_group) { - struct box *group = row->parent; - - /* Top border of row group */ - b.style = css_computed_border_top_style(group->style); - b.color = css_computed_border_top_color(group->style, &b.c); - css_computed_border_top_width(group->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW_GROUP; - - if (table_border_is_more_eyecatching(len_ctx, - &a, a_src, &b, b_src)) { - a = b; - a_src = b_src; - } - - if (group->prev == NULL) { - /* Top border of table */ - table_cell_top_process_table(len_ctx, - group->parent, &a, &a_src); - } else { - /* Process previous group(s) */ - while (table_cell_top_process_group(len_ctx, - cell, group->prev, - &a, &a_src) == false) { - if (group->prev->prev == NULL) { - /* Top border of table */ - table_cell_top_process_table(len_ctx, - group->parent, - &a, &a_src); - break; - } else { - group = group->prev; - } - } - } - } - - /* a now contains the used top border for the cell */ - cell->border[TOP].style = a.style; - cell->border[TOP].c = a.c; - cell->border[TOP].width = FIXTOINT(nscss_len2px(len_ctx, - a.width, a.unit, cell->style)); -} - -/** - * Calculate used values of border-right-{style,color,width} - * - * \param len_ctx Length conversion context - * \param cell Table cell to consider - */ -void table_used_right_border_for_cell( - const nscss_len_ctx *len_ctx, - struct box *cell) -{ - struct border a, b; - box_type a_src, b_src; - - /** \todo Need column and column_group, too */ - - /* Initialise to computed right border for cell */ - a.style = css_computed_border_right_style(cell->style); - css_computed_border_right_color(cell->style, &a.c); - css_computed_border_right_width(cell->style, &a.width, &a.unit); - a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style); - a.unit = CSS_UNIT_PX; - a_src = BOX_TABLE_CELL; - - if (cell->next != NULL || cell->start_column + cell->columns != - cell->parent->parent->parent->columns) { - /* Cell is not at right edge of table -- no right border */ - a.style = CSS_BORDER_STYLE_NONE; - a.width = 0; - a.unit = CSS_UNIT_PX; - } else { - /* Last cell in row, so consider rows and row group */ - struct box *row = cell->parent; - struct box *group = row->parent; - struct box *table = group->parent; - unsigned int rows = cell->rows; - - while (rows-- > 0 && row != NULL) { - /* Spanned rows -- consider their right border */ - b.style = css_computed_border_right_style(row->style); - b.color = css_computed_border_right_color( - row->style, &b.c); - css_computed_border_right_width( - row->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, - b.width, b.unit, row->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW; - - if (table_border_is_more_eyecatching(len_ctx, - &a, a_src, &b, b_src)) { - a = b; - a_src = b_src; - } - - row = row->next; - } - - /** \todo can cells span row groups? */ - - /* Row group -- consider its right border */ - b.style = css_computed_border_right_style(group->style); - b.color = css_computed_border_right_color(group->style, &b.c); - css_computed_border_right_width(group->style, - &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW_GROUP; - - if (table_border_is_more_eyecatching(len_ctx, - &a, a_src, &b, b_src)) { - a = b; - a_src = b_src; - } - - /* The table itself -- consider its right border */ - b.style = css_computed_border_right_style(table->style); - b.color = css_computed_border_right_color(table->style, &b.c); - css_computed_border_right_width(table->style, - &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE; - - if (table_border_is_more_eyecatching(len_ctx, - &a, a_src, &b, b_src)) { - a = b; - a_src = b_src; - } - } - - /* a now contains the used right border for the cell */ - cell->border[RIGHT].style = a.style; - cell->border[RIGHT].c = a.c; - cell->border[RIGHT].width = FIXTOINT(nscss_len2px(len_ctx, - a.width, a.unit, cell->style)); -} - -/** - * Calculate used values of border-bottom-{style,color,width} - * - * \param len_ctx Length conversion context - * \param cell Table cell to consider - */ -void table_used_bottom_border_for_cell( - const nscss_len_ctx *len_ctx, - struct box *cell) -{ - struct border a, b; - box_type a_src, b_src; - struct box *row = cell->parent; - unsigned int rows = cell->rows; - - /* Initialise to computed bottom border for cell */ - a.style = css_computed_border_bottom_style(cell->style); - css_computed_border_bottom_color(cell->style, &a.c); - css_computed_border_bottom_width(cell->style, &a.width, &a.unit); - a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style); - a.unit = CSS_UNIT_PX; - a_src = BOX_TABLE_CELL; - - while (rows-- > 0 && row != NULL) - row = row->next; - - /** \todo Can cells span row groups? */ - - if (row != NULL) { - /* Cell is not at bottom edge of table -- no bottom border */ - a.style = CSS_BORDER_STYLE_NONE; - a.width = 0; - a.unit = CSS_UNIT_PX; - } else { - /* Cell at bottom of table, so consider row and row group */ - struct box *row = cell->parent; - struct box *group = row->parent; - struct box *table = group->parent; - - /* Bottom border of row */ - b.style = css_computed_border_bottom_style(row->style); - b.color = css_computed_border_bottom_color(row->style, &b.c); - css_computed_border_bottom_width(row->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW; - - if (table_border_is_more_eyecatching(len_ctx, - &a, a_src, &b, b_src)) { - a = b; - a_src = b_src; - } - - /* Row group -- consider its bottom border */ - b.style = css_computed_border_bottom_style(group->style); - b.color = css_computed_border_bottom_color(group->style, &b.c); - css_computed_border_bottom_width(group->style, - &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW_GROUP; - - if (table_border_is_more_eyecatching(len_ctx, - &a, a_src, &b, b_src)) { - a = b; - a_src = b_src; - } - - /* The table itself -- consider its bottom border */ - b.style = css_computed_border_bottom_style(table->style); - b.color = css_computed_border_bottom_color(table->style, &b.c); - css_computed_border_bottom_width(table->style, - &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE; - - if (table_border_is_more_eyecatching(len_ctx, - &a, a_src, &b, b_src)) { - a = b; - } - } - - /* a now contains the used bottom border for the cell */ - cell->border[BOTTOM].style = a.style; - cell->border[BOTTOM].c = a.c; - cell->border[BOTTOM].width = FIXTOINT(nscss_len2px(len_ctx, - a.width, a.unit, cell->style)); -} - -/** - * Determine if a border style is more eyecatching than another - * - * \param len_ctx Length conversion context - * \param a Reference border style - * \param a_src Source of \a a - * \param b Candidate border style - * \param b_src Source of \a b - * \return True if \a b is more eyecatching than \a a - */ -bool table_border_is_more_eyecatching( - const nscss_len_ctx *len_ctx, - const struct border *a, - box_type a_src, - const struct border *b, - box_type b_src) -{ - css_fixed awidth, bwidth; - int impact = 0; - - /* See CSS 2.1 $17.6.2.1 */ - - /* 1 + 2 -- hidden beats everything, none beats nothing */ - if (a->style == CSS_BORDER_STYLE_HIDDEN || - b->style == CSS_BORDER_STYLE_NONE) - return false; - - if (b->style == CSS_BORDER_STYLE_HIDDEN || - a->style == CSS_BORDER_STYLE_NONE) - return true; - - /* 3a -- wider borders beat narrow ones */ - /* The widths must be absolute, which will be the case - * if they've come from a computed style. */ - assert(a->unit != CSS_UNIT_EM && a->unit != CSS_UNIT_EX); - assert(b->unit != CSS_UNIT_EM && b->unit != CSS_UNIT_EX); - awidth = nscss_len2px(len_ctx, a->width, a->unit, NULL); - bwidth = nscss_len2px(len_ctx, b->width, b->unit, NULL); - - if (awidth < bwidth) - return true; - else if (bwidth < awidth) - return false; - - /* 3b -- sort by style */ - switch (a->style) { - case CSS_BORDER_STYLE_DOUBLE: impact++; /* Fall through */ - case CSS_BORDER_STYLE_SOLID: impact++; /* Fall through */ - case CSS_BORDER_STYLE_DASHED: impact++; /* Fall through */ - case CSS_BORDER_STYLE_DOTTED: impact++; /* Fall through */ - case CSS_BORDER_STYLE_RIDGE: impact++; /* Fall through */ - case CSS_BORDER_STYLE_OUTSET: impact++; /* Fall through */ - case CSS_BORDER_STYLE_GROOVE: impact++; /* Fall through */ - case CSS_BORDER_STYLE_INSET: impact++; /* Fall through */ - default: - break; - } - - switch (b->style) { - case CSS_BORDER_STYLE_DOUBLE: impact--; /* Fall through */ - case CSS_BORDER_STYLE_SOLID: impact--; /* Fall through */ - case CSS_BORDER_STYLE_DASHED: impact--; /* Fall through */ - case CSS_BORDER_STYLE_DOTTED: impact--; /* Fall through */ - case CSS_BORDER_STYLE_RIDGE: impact--; /* Fall through */ - case CSS_BORDER_STYLE_OUTSET: impact--; /* Fall through */ - case CSS_BORDER_STYLE_GROOVE: impact--; /* Fall through */ - case CSS_BORDER_STYLE_INSET: impact--; /* Fall through */ - default: - break; - } - - if (impact < 0) - return true; - else if (impact > 0) - return false; - - /* 4a -- sort by origin */ - impact = 0; - - /** \todo COL/COL_GROUP */ - switch (a_src) { - case BOX_TABLE_CELL: impact++; /* Fall through */ - case BOX_TABLE_ROW: impact++; /* Fall through */ - case BOX_TABLE_ROW_GROUP: impact++; /* Fall through */ - case BOX_TABLE: impact++; /* Fall through */ - default: - break; - } - - /** \todo COL/COL_GROUP */ - switch (b_src) { - case BOX_TABLE_CELL: impact--; /* Fall through */ - case BOX_TABLE_ROW: impact--; /* Fall through */ - case BOX_TABLE_ROW_GROUP: impact--; /* Fall through */ - case BOX_TABLE: impact--; /* Fall through */ - default: - break; - } - - if (impact < 0) - return true; - else if (impact > 0) - return false; - - /* 4b -- furthest left (if direction: ltr) and towards top wins */ - /** \todo Currently assumes b satisifies this */ - return true; -} - -/****************************************************************************** - * Helpers for top border collapsing * - ******************************************************************************/ - -/** - * Process a table - * - * \param len_ctx Length conversion context - * \param table Table to process - * \param a Current border style for cell - * \param a_src Source of \a a - * - * \post \a a will be updated with most eyecatching style - * \post \a a_src will be updated also - */ -void table_cell_top_process_table( - const nscss_len_ctx *len_ctx, - struct box *table, - struct border *a, - box_type *a_src) -{ - struct border b; - box_type b_src; - - /* Top border of table */ - b.style = css_computed_border_top_style(table->style); - b.color = css_computed_border_top_color(table->style, &b.c); - css_computed_border_top_width(table->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE; - - if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) { - *a = b; - *a_src = b_src; - } -} - -/** - * Process a group - * - * \param len_ctx Length conversion context - * \param cell Cell being considered - * \param group Group to process - * \param a Current border style for cell - * \param a_src Source of \a a - * \return true if group has non-empty rows, false otherwise - * - * \post \a a will be updated with most eyecatching style - * \post \a a_src will be updated also - */ -bool table_cell_top_process_group( - const nscss_len_ctx *len_ctx, - struct box *cell, - struct box *group, - struct border *a, - box_type *a_src) -{ - struct border b; - box_type b_src; - - /* Bottom border of group */ - b.style = css_computed_border_bottom_style(group->style); - b.color = css_computed_border_bottom_color(group->style, &b.c); - css_computed_border_bottom_width(group->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW_GROUP; - - if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) { - *a = b; - *a_src = b_src; - } - - if (group->last != NULL) { - /* Process rows in group, starting with last */ - struct box *row = group->last; - - while (table_cell_top_process_row(len_ctx, cell, row, - a, a_src) == false) { - if (row->prev == NULL) { - return false; - } else { - row = row->prev; - } - } - } else { - /* Group is empty, so consider its top border */ - b.style = css_computed_border_top_style(group->style); - b.color = css_computed_border_top_color(group->style, &b.c); - css_computed_border_top_width(group->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW_GROUP; - - if (table_border_is_more_eyecatching(len_ctx, - a, *a_src, &b, b_src)) { - *a = b; - *a_src = b_src; - } - - return false; - } - - return true; -} - -/** - * Process a row - * - * \param len_ctx Length conversion context - * \param cell Cell being considered - * \param row Row to process - * \param a Current border style for cell - * \param a_src Source of \a a - * \return true if row has cells, false otherwise - * - * \post \a a will be updated with most eyecatching style - * \post \a a_src will be updated also - */ -bool table_cell_top_process_row( - const nscss_len_ctx *len_ctx, - struct box *cell, - struct box *row, - struct border *a, - box_type *a_src) -{ - struct border b; - box_type b_src; - - /* Bottom border of row */ - b.style = css_computed_border_bottom_style(row->style); - b.color = css_computed_border_bottom_color(row->style, &b.c); - css_computed_border_bottom_width(row->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW; - - if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) { - *a = b; - *a_src = b_src; - } - - if (row->children == NULL) { - /* Row is empty, so consider its top border */ - b.style = css_computed_border_top_style(row->style); - b.color = css_computed_border_top_color(row->style, &b.c); - css_computed_border_top_width(row->style, &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_ROW; - - if (table_border_is_more_eyecatching(len_ctx, - a, *a_src, &b, b_src)) { - *a = b; - *a_src = b_src; - } - - return false; - } else { - /* Process cells that are directly above the cell being - * considered. They may not be in this row, but in one of the - * rows above it in the case where rowspan > 1. */ - struct box *c; - bool processed = false; - - while (processed == false) { - for (c = row->children; c != NULL; c = c->next) { - /* Ignore cells to the left */ - if (c->start_column + c->columns - 1 < - cell->start_column) - continue; - /* Ignore cells to the right */ - if (c->start_column > cell->start_column + - cell->columns - 1) - continue; - - /* Flag that we've processed a cell */ - processed = true; - - /* Consider bottom border */ - b.style = css_computed_border_bottom_style( - c->style); - b.color = css_computed_border_bottom_color( - c->style, &b.c); - css_computed_border_bottom_width(c->style, - &b.width, &b.unit); - b.width = nscss_len2px(len_ctx, - b.width, b.unit, c->style); - b.unit = CSS_UNIT_PX; - b_src = BOX_TABLE_CELL; - - if (table_border_is_more_eyecatching(len_ctx, - a, *a_src, &b, b_src)) { - *a = b; - *a_src = b_src; - } - } - - if (processed == false) { - /* There must be a preceding row */ - assert(row->prev != NULL); - - row = row->prev; - } - } - } - - return true; -} - |