From c0ef8ce645d6077831877b5a8499b89c18df7bf9 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Tue, 28 Apr 2020 23:30:20 +0100 Subject: clean up html box, no functionality change just cosmetic split up the html box headers tidy up the documentation comments avoid forward declarations in normalisation implementation --- content/handlers/html/box_normalise.c | 904 ++++++++++++++++------------------ 1 file changed, 427 insertions(+), 477 deletions(-) (limited to 'content/handlers/html/box_normalise.c') diff --git a/content/handlers/html/box_normalise.c b/content/handlers/html/box_normalise.c index 7155cb722..03fe731b2 100644 --- a/content/handlers/html/box_normalise.c +++ b/content/handlers/html/box_normalise.c @@ -21,7 +21,7 @@ /** * \file - * Box tree normalisation (implementation). + * Box tree normalisation implementation. */ #include @@ -33,6 +33,7 @@ #include "css/select.h" #include "html/box.h" +#include "html/box_normalise.h" #include "html/html_internal.h" #include "html/table.h" @@ -66,279 +67,310 @@ struct columns { }; -static bool box_normalise_table( - struct box *table, - const struct box *root, - html_content *c); -static bool box_normalise_table_spans( - struct box *table, - const struct box *root, - struct span_info *spans, - html_content *c); -static bool box_normalise_table_row_group( - struct box *row_group, - const struct box *root, - struct columns *col_info, - html_content *c); -static bool box_normalise_table_row( - struct box *row, - const struct box *root, - struct columns *col_info, - html_content *c); -static bool calculate_table_row(struct columns *col_info, - unsigned int col_span, unsigned int row_span, - unsigned int *start_column, struct box *cell); -static bool box_normalise_inline_container( - struct box *cont, - const struct box *root, - html_content *c); - /** - * Ensure the box tree is correctly nested by adding and removing nodes. - * - * \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL - * \param root root box of document - * \param c content of boxes - * \return true on success, false on memory exhaustion + * Compute the column index at which the current cell begins. + * Additionally, update the column record to reflect row spanning. * - * The tree is modified to satisfy the following: - * \code - * parent permitted child nodes - * BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE - * INLINE_CONTAINER INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, TEXT - * INLINE, TEXT none - * TABLE at least 1 TABLE_ROW_GROUP - * TABLE_ROW_GROUP at least 1 TABLE_ROW - * TABLE_ROW at least 1 TABLE_CELL - * TABLE_CELL BLOCK, INLINE_CONTAINER, TABLE (same as BLOCK) - * FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE - * \endcode + * \param col_info Column record + * \param col_span Number of columns that current cell spans + * \param row_span Number of rows that current cell spans + * \param start_column Pointer to location to receive column index + * \param cell Box for current table cell + * \return true on success, false on memory exhaustion */ +static bool +calculate_table_row(struct columns *col_info, + unsigned int col_span, + unsigned int row_span, + unsigned int *start_column, + struct box *cell) +{ + unsigned int cell_start_col = col_info->current_column; + unsigned int cell_end_col; + unsigned int i; + struct span_info *spans; + struct box *rg = cell->parent->parent; /* Cell's row group */ + + /* Skip columns with cells spanning from above */ + /* TODO: Need to ignore cells spanning from above that belong to + * different row group. We don't have that info here. */ + while (col_info->spans[cell_start_col].row_span != 0 && + col_info->spans[cell_start_col].rg == rg) { + cell_start_col++; + } + + /* Update current column with calculated start */ + col_info->current_column = cell_start_col; + + /* If this cell has a colspan of 0, then assume 1. + * No other browser supports colspan=0, anyway. */ + if (col_span == 0) + col_span = 1; + + cell_end_col = cell_start_col + col_span; + + if (col_info->num_columns < cell_end_col) { + /* It appears that this row has more columns than + * the maximum recorded for the table so far. + * Allocate more span records. */ + spans = realloc(col_info->spans, + sizeof *spans * (cell_end_col + 1)); + if (spans == NULL) + return false; + + col_info->spans = spans; + col_info->num_columns = cell_end_col; + + /* Mark new final column as sentinel */ + col_info->spans[cell_end_col].row_span = 0; + col_info->spans[cell_end_col].auto_row = false; + } + + /* This cell may span multiple columns. If it also wants to span + * multiple rows, temporarily assume it spans 1 row only. This will + * be fixed up in box_normalise_table_spans() */ + for (i = cell_start_col; i < cell_end_col; i++) { + col_info->spans[i].row_span = (row_span == 0) ? 1 : row_span; + col_info->spans[i].auto_row = (row_span == 0); + col_info->spans[i].rg = rg; + } + + /* Update current column with calculated end. */ + col_info->current_column = cell_end_col; + + *start_column = cell_start_col; -bool box_normalise_block( - struct box *block, - const struct box *root, - html_content *c) + return true; +} + + +static bool +box_normalise_table_row(struct box *row, + const struct box *root, + struct columns *col_info, + html_content * c) { struct box *child; struct box *next_child; - struct box *table; + struct box *cell = NULL; css_computed_style *style; + unsigned int i; nscss_select_ctx ctx; - assert(block != NULL); - assert(root != NULL); + assert(row != NULL); + assert(row->type == BOX_TABLE_ROW); ctx.root_style = root->style; #ifdef BOX_NORMALISE_DEBUG - NSLOG(netsurf, INFO, "block %p, block->type %u", block, block->type); -#endif - - assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK || - block->type == BOX_TABLE_CELL); - - for (child = block->children; child != NULL; child = next_child) { -#ifdef BOX_NORMALISE_DEBUG - NSLOG(netsurf, INFO, "child %p, child->type = %d", child, - child->type); + NSLOG(netsurf, INFO, "row %p", row); #endif - next_child = child->next; /* child may be destroyed */ + for (child = row->children; child != NULL; child = next_child) { + next_child = child->next; switch (child->type) { - case BOX_BLOCK: + case BOX_TABLE_CELL: /* ok */ if (box_normalise_block(child, root, c) == false) return false; + cell = child; break; + case BOX_BLOCK: case BOX_INLINE_CONTAINER: - if (box_normalise_inline_container(child, root, c) == false) - return false; - break; case BOX_TABLE: - if (box_normalise_table(child, root, c) == false) - return false; - break; - case BOX_INLINE: - case BOX_INLINE_END: - case BOX_INLINE_BLOCK: - case BOX_FLOAT_LEFT: - case BOX_FLOAT_RIGHT: - case BOX_BR: - case BOX_TEXT: - /* should have been wrapped in inline - container by convert_xml_to_box() */ - assert(0); - break; case BOX_TABLE_ROW_GROUP: case BOX_TABLE_ROW: - case BOX_TABLE_CELL: - /* insert implied table */ - assert(block->style != NULL); + /* insert implied table cell */ + assert(row->style != NULL); ctx.ctx = c->select_ctx; ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL); ctx.base_url = c->base_url; ctx.universal = c->universal; - style = nscss_get_blank_style(&ctx, block->style); + style = nscss_get_blank_style(&ctx, row->style); if (style == NULL) return false; - table = box_create(NULL, style, true, block->href, - block->target, NULL, NULL, c->bctx); - if (table == NULL) { + cell = box_create(NULL, style, true, row->href, + row->target, NULL, NULL, c->bctx); + if (cell == NULL) { css_computed_style_destroy(style); return false; } - table->type = BOX_TABLE; + cell->type = BOX_TABLE_CELL; if (child->prev == NULL) - block->children = table; + row->children = cell; else - child->prev->next = table; + child->prev->next = cell; - table->prev = child->prev; + cell->prev = child->prev; while (child != NULL && ( + child->type == BOX_BLOCK || + child->type == BOX_INLINE_CONTAINER || + child->type == BOX_TABLE || child->type == BOX_TABLE_ROW_GROUP || - child->type == BOX_TABLE_ROW || - child->type == BOX_TABLE_CELL)) { - box_add_child(table, child); + child->type == BOX_TABLE_ROW)) { + box_add_child(cell, child); next_child = child->next; child->next = NULL; child = next_child; } - table->last->next = NULL; - table->next = next_child = child; - if (table->next != NULL) - table->next->prev = table; + assert(cell->last != NULL); + + cell->last->next = NULL; + cell->next = next_child = child; + if (cell->next != NULL) + cell->next->prev = cell; else - block->last = table; - table->parent = block; + row->last = cell; + cell->parent = row; - if (box_normalise_table(table, root, c) == false) + if (box_normalise_block(cell, root, c) == false) return false; break; + case BOX_INLINE: + case BOX_INLINE_END: + case BOX_INLINE_BLOCK: + case BOX_FLOAT_LEFT: + case BOX_FLOAT_RIGHT: + case BOX_BR: + case BOX_TEXT: + /* should have been wrapped in inline + container by convert_xml_to_box() */ + assert(0); + break; default: assert(0); } + + if (calculate_table_row(col_info, cell->columns, cell->rows, + &cell->start_column, cell) == false) + return false; + } + + + /* Update row spanning details for all columns */ + for (i = 0; i < col_info->num_columns; i++) { + if (col_info->spans[i].row_span != 0 && + col_info->spans[i].auto_row == false) { + /* This cell spans rows, and is not an auto row. + * Reduce number of rows left to span */ + col_info->spans[i].row_span--; + } } + /* Reset current column for next row */ + col_info->current_column = 0; + + /* Increment row counter */ + col_info->num_rows++; + +#ifdef BOX_NORMALISE_DEBUG + NSLOG(netsurf, INFO, "row %p done", row); +#endif + return true; } -bool box_normalise_table( - struct box *table, - const struct box *root, - html_content * c) +static bool +box_normalise_table_row_group(struct box *row_group, + const struct box *root, + struct columns *col_info, + html_content * c) { struct box *child; struct box *next_child; - struct box *row_group; + struct box *row; css_computed_style *style; - struct columns col_info; nscss_select_ctx ctx; + unsigned int group_row_count = 0; - assert(table != NULL); - assert(table->type == BOX_TABLE); + assert(row_group != 0); + assert(row_group->type == BOX_TABLE_ROW_GROUP); ctx.root_style = root->style; #ifdef BOX_NORMALISE_DEBUG - NSLOG(netsurf, INFO, "table %p", table); + NSLOG(netsurf, INFO, "row_group %p", row_group); #endif - col_info.num_columns = 1; - col_info.current_column = 0; - col_info.spans = malloc(2 * sizeof *col_info.spans); - if (col_info.spans == NULL) - return false; - - col_info.spans[0].row_span = col_info.spans[1].row_span = 0; - col_info.spans[0].auto_row = false; - col_info.spans[1].auto_row = false; - col_info.num_rows = 0; - - for (child = table->children; child != NULL; child = next_child) { + for (child = row_group->children; child != NULL; child = next_child) { next_child = child->next; + switch (child->type) { - case BOX_TABLE_ROW_GROUP: + case BOX_TABLE_ROW: /* ok */ - if (box_normalise_table_row_group(child, root, - &col_info, c) == false) { - free(col_info.spans); + group_row_count++; + if (box_normalise_table_row(child, root, col_info, + c) == false) return false; - } break; case BOX_BLOCK: case BOX_INLINE_CONTAINER: case BOX_TABLE: - case BOX_TABLE_ROW: + case BOX_TABLE_ROW_GROUP: case BOX_TABLE_CELL: - /* insert implied table row group */ - assert(table->style != NULL); + /* insert implied table row */ + assert(row_group->style != NULL); ctx.ctx = c->select_ctx; ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL); ctx.base_url = c->base_url; ctx.universal = c->universal; - style = nscss_get_blank_style(&ctx, table->style); - if (style == NULL) { - free(col_info.spans); + style = nscss_get_blank_style(&ctx, row_group->style); + if (style == NULL) return false; - } - row_group = box_create(NULL, style, true, table->href, - table->target, NULL, NULL, c->bctx); - if (row_group == NULL) { + row = box_create(NULL, style, true, row_group->href, + row_group->target, NULL, NULL, c->bctx); + if (row == NULL) { css_computed_style_destroy(style); - free(col_info.spans); return false; } - - row_group->type = BOX_TABLE_ROW_GROUP; + row->type = BOX_TABLE_ROW; if (child->prev == NULL) - table->children = row_group; + row_group->children = row; else - child->prev->next = row_group; + child->prev->next = row; - row_group->prev = child->prev; + row->prev = child->prev; while (child != NULL && ( child->type == BOX_BLOCK || child->type == BOX_INLINE_CONTAINER || child->type == BOX_TABLE || - child->type == BOX_TABLE_ROW || + child->type == BOX_TABLE_ROW_GROUP || child->type == BOX_TABLE_CELL)) { - box_add_child(row_group, child); + box_add_child(row, child); next_child = child->next; child->next = NULL; child = next_child; } - assert(row_group->last != NULL); + assert(row->last != NULL); - row_group->last->next = NULL; - row_group->next = next_child = child; - if (row_group->next != NULL) - row_group->next->prev = row_group; + row->last->next = NULL; + row->next = next_child = child; + if (row->next != NULL) + row->next->prev = row; else - table->last = row_group; - row_group->parent = table; + row_group->last = row; + row->parent = row_group; - if (box_normalise_table_row_group(row_group, root, - &col_info, c) == false) { - free(col_info.spans); + group_row_count++; + if (box_normalise_table_row(row, root, col_info, + c) == false) return false; - } break; case BOX_INLINE: case BOX_INLINE_END: @@ -352,48 +384,25 @@ bool box_normalise_table( assert(0); break; default: - fprintf(stderr, "%i\n", child->type); assert(0); } } - table->columns = col_info.num_columns; - table->rows = col_info.num_rows; - - if (table->children == NULL) { - struct box *row; - + if (row_group->children == NULL) { #ifdef BOX_NORMALISE_DEBUG NSLOG(netsurf, INFO, - "table->children == 0, creating implied row"); + "row_group->children == 0, inserting implied row"); #endif - assert(table->style != NULL); + assert(row_group->style != NULL); ctx.ctx = c->select_ctx; ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL); ctx.base_url = c->base_url; ctx.universal = c->universal; - style = nscss_get_blank_style(&ctx, table->style); - if (style == NULL) { - free(col_info.spans); - return false; - } - - row_group = box_create(NULL, style, true, table->href, - table->target, NULL, NULL, c->bctx); - if (row_group == NULL) { - css_computed_style_destroy(style); - free(col_info.spans); - return false; - } - row_group->type = BOX_TABLE_ROW_GROUP; - style = nscss_get_blank_style(&ctx, row_group->style); if (style == NULL) { - box_free(row_group); - free(col_info.spans); return false; } @@ -401,8 +410,6 @@ bool box_normalise_table( row_group->target, NULL, NULL, c->bctx); if (row == NULL) { css_computed_style_destroy(style); - box_free(row_group); - free(col_info.spans); return false; } row->type = BOX_TABLE_ROW; @@ -410,21 +417,16 @@ bool box_normalise_table( row->parent = row_group; row_group->children = row_group->last = row; - row_group->parent = table; - table->children = table->last = row_group; - - table->rows = 1; - } + group_row_count = 1; - if (box_normalise_table_spans(table, root, col_info.spans, c) == false) { - free(col_info.spans); - return false; + /* Keep table's row count in sync */ + col_info->num_rows++; } - free(col_info.spans); + row_group->rows = group_row_count; #ifdef BOX_NORMALISE_DEBUG - NSLOG(netsurf, INFO, "table %p done", table); + NSLOG(netsurf, INFO, "row_group %p done", row_group); #endif return true; @@ -441,12 +443,11 @@ bool box_normalise_table( * \param c Content containing table * \return True on success, false on memory exhaustion. */ - -bool box_normalise_table_spans( - struct box *table, - const struct box *root, - struct span_info *spans, - html_content *c) +static bool +box_normalise_table_spans(struct box *table, + const struct box *root, + struct span_info *spans, + html_content *c) { struct box *table_row_group; struct box *table_row; @@ -601,249 +602,111 @@ bool box_normalise_table_spans( } -bool box_normalise_table_row_group( - struct box *row_group, - const struct box *root, - struct columns *col_info, - html_content * c) +static bool +box_normalise_table(struct box *table, const struct box *root, html_content * c) { struct box *child; struct box *next_child; - struct box *row; + struct box *row_group; css_computed_style *style; + struct columns col_info; nscss_select_ctx ctx; - unsigned int group_row_count = 0; - assert(row_group != 0); - assert(row_group->type == BOX_TABLE_ROW_GROUP); + assert(table != NULL); + assert(table->type == BOX_TABLE); ctx.root_style = root->style; #ifdef BOX_NORMALISE_DEBUG - NSLOG(netsurf, INFO, "row_group %p", row_group); -#endif - - for (child = row_group->children; child != NULL; child = next_child) { - next_child = child->next; - - switch (child->type) { - case BOX_TABLE_ROW: - /* ok */ - group_row_count++; - if (box_normalise_table_row(child, root, col_info, - c) == false) - return false; - break; - case BOX_BLOCK: - case BOX_INLINE_CONTAINER: - case BOX_TABLE: - case BOX_TABLE_ROW_GROUP: - case BOX_TABLE_CELL: - /* insert implied table row */ - assert(row_group->style != NULL); - - ctx.ctx = c->select_ctx; - ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL); - ctx.base_url = c->base_url; - ctx.universal = c->universal; - - style = nscss_get_blank_style(&ctx, row_group->style); - if (style == NULL) - return false; - - row = box_create(NULL, style, true, row_group->href, - row_group->target, NULL, NULL, c->bctx); - if (row == NULL) { - css_computed_style_destroy(style); - return false; - } - row->type = BOX_TABLE_ROW; - - if (child->prev == NULL) - row_group->children = row; - else - child->prev->next = row; - - row->prev = child->prev; - - while (child != NULL && ( - child->type == BOX_BLOCK || - child->type == BOX_INLINE_CONTAINER || - child->type == BOX_TABLE || - child->type == BOX_TABLE_ROW_GROUP || - child->type == BOX_TABLE_CELL)) { - box_add_child(row, child); - - next_child = child->next; - child->next = NULL; - child = next_child; - } - - assert(row->last != NULL); - - row->last->next = NULL; - row->next = next_child = child; - if (row->next != NULL) - row->next->prev = row; - else - row_group->last = row; - row->parent = row_group; - - group_row_count++; - if (box_normalise_table_row(row, root, col_info, - c) == false) - return false; - break; - case BOX_INLINE: - case BOX_INLINE_END: - case BOX_INLINE_BLOCK: - case BOX_FLOAT_LEFT: - case BOX_FLOAT_RIGHT: - case BOX_BR: - case BOX_TEXT: - /* should have been wrapped in inline - container by convert_xml_to_box() */ - assert(0); - break; - default: - assert(0); - } - } - - if (row_group->children == NULL) { -#ifdef BOX_NORMALISE_DEBUG - NSLOG(netsurf, INFO, - "row_group->children == 0, inserting implied row"); -#endif - - assert(row_group->style != NULL); - - ctx.ctx = c->select_ctx; - ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL); - ctx.base_url = c->base_url; - ctx.universal = c->universal; - - style = nscss_get_blank_style(&ctx, row_group->style); - if (style == NULL) { - return false; - } - - row = box_create(NULL, style, true, row_group->href, - row_group->target, NULL, NULL, c->bctx); - if (row == NULL) { - css_computed_style_destroy(style); - return false; - } - row->type = BOX_TABLE_ROW; - - row->parent = row_group; - row_group->children = row_group->last = row; - - group_row_count = 1; - - /* Keep table's row count in sync */ - col_info->num_rows++; - } - - row_group->rows = group_row_count; - -#ifdef BOX_NORMALISE_DEBUG - NSLOG(netsurf, INFO, "row_group %p done", row_group); + NSLOG(netsurf, INFO, "table %p", table); #endif - return true; -} - - -bool box_normalise_table_row( - struct box *row, - const struct box *root, - struct columns *col_info, - html_content * c) -{ - struct box *child; - struct box *next_child; - struct box *cell = NULL; - css_computed_style *style; - unsigned int i; - nscss_select_ctx ctx; - - assert(row != NULL); - assert(row->type == BOX_TABLE_ROW); - - ctx.root_style = root->style; + col_info.num_columns = 1; + col_info.current_column = 0; + col_info.spans = malloc(2 * sizeof *col_info.spans); + if (col_info.spans == NULL) + return false; -#ifdef BOX_NORMALISE_DEBUG - NSLOG(netsurf, INFO, "row %p", row); -#endif + col_info.spans[0].row_span = col_info.spans[1].row_span = 0; + col_info.spans[0].auto_row = false; + col_info.spans[1].auto_row = false; + col_info.num_rows = 0; - for (child = row->children; child != NULL; child = next_child) { + for (child = table->children; child != NULL; child = next_child) { next_child = child->next; - switch (child->type) { - case BOX_TABLE_CELL: + case BOX_TABLE_ROW_GROUP: /* ok */ - if (box_normalise_block(child, root, c) == false) + if (box_normalise_table_row_group(child, root, + &col_info, c) == false) { + free(col_info.spans); return false; - cell = child; + } break; case BOX_BLOCK: case BOX_INLINE_CONTAINER: case BOX_TABLE: - case BOX_TABLE_ROW_GROUP: case BOX_TABLE_ROW: - /* insert implied table cell */ - assert(row->style != NULL); + case BOX_TABLE_CELL: + /* insert implied table row group */ + assert(table->style != NULL); ctx.ctx = c->select_ctx; ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL); ctx.base_url = c->base_url; ctx.universal = c->universal; - style = nscss_get_blank_style(&ctx, row->style); - if (style == NULL) + style = nscss_get_blank_style(&ctx, table->style); + if (style == NULL) { + free(col_info.spans); return false; + } - cell = box_create(NULL, style, true, row->href, - row->target, NULL, NULL, c->bctx); - if (cell == NULL) { + row_group = box_create(NULL, style, true, table->href, + table->target, NULL, NULL, c->bctx); + if (row_group == NULL) { css_computed_style_destroy(style); + free(col_info.spans); return false; } - cell->type = BOX_TABLE_CELL; + + row_group->type = BOX_TABLE_ROW_GROUP; if (child->prev == NULL) - row->children = cell; + table->children = row_group; else - child->prev->next = cell; + child->prev->next = row_group; - cell->prev = child->prev; + row_group->prev = child->prev; while (child != NULL && ( child->type == BOX_BLOCK || child->type == BOX_INLINE_CONTAINER || child->type == BOX_TABLE || - child->type == BOX_TABLE_ROW_GROUP || - child->type == BOX_TABLE_ROW)) { - box_add_child(cell, child); + child->type == BOX_TABLE_ROW || + child->type == BOX_TABLE_CELL)) { + box_add_child(row_group, child); next_child = child->next; child->next = NULL; child = next_child; } - assert(cell->last != NULL); + assert(row_group->last != NULL); - cell->last->next = NULL; - cell->next = next_child = child; - if (cell->next != NULL) - cell->next->prev = cell; + row_group->last->next = NULL; + row_group->next = next_child = child; + if (row_group->next != NULL) + row_group->next->prev = row_group; else - row->last = cell; - cell->parent = row; + table->last = row_group; + row_group->parent = table; - if (box_normalise_block(cell, root, c) == false) + if (box_normalise_table_row_group(row_group, root, + &col_info, c) == false) { + free(col_info.spans); return false; + } break; case BOX_INLINE: case BOX_INLINE_END: @@ -857,118 +720,89 @@ bool box_normalise_table_row( assert(0); break; default: + fprintf(stderr, "%i\n", child->type); assert(0); } - - if (calculate_table_row(col_info, cell->columns, cell->rows, - &cell->start_column, cell) == false) - return false; - } - - - /* Update row spanning details for all columns */ - for (i = 0; i < col_info->num_columns; i++) { - if (col_info->spans[i].row_span != 0 && - col_info->spans[i].auto_row == false) { - /* This cell spans rows, and is not an auto row. - * Reduce number of rows left to span */ - col_info->spans[i].row_span--; - } } - /* Reset current column for next row */ - col_info->current_column = 0; + table->columns = col_info.num_columns; + table->rows = col_info.num_rows; - /* Increment row counter */ - col_info->num_rows++; + if (table->children == NULL) { + struct box *row; #ifdef BOX_NORMALISE_DEBUG - NSLOG(netsurf, INFO, "row %p done", row); + NSLOG(netsurf, INFO, + "table->children == 0, creating implied row"); #endif - return true; -} - - -/** - * Compute the column index at which the current cell begins. - * Additionally, update the column record to reflect row spanning. - * - * \param col_info Column record - * \param col_span Number of columns that current cell spans - * \param row_span Number of rows that current cell spans - * \param start_column Pointer to location to receive column index - * \param cell Box for current table cell - * \return true on success, false on memory exhaustion - */ - -bool calculate_table_row(struct columns *col_info, - unsigned int col_span, unsigned int row_span, - unsigned int *start_column, struct box *cell) -{ - unsigned int cell_start_col = col_info->current_column; - unsigned int cell_end_col; - unsigned int i; - struct span_info *spans; - struct box *rg = cell->parent->parent; /* Cell's row group */ + assert(table->style != NULL); - /* Skip columns with cells spanning from above */ - /* TODO: Need to ignore cells spanning from above that belong to - * different row group. We don't have that info here. */ - while (col_info->spans[cell_start_col].row_span != 0 && - col_info->spans[cell_start_col].rg == rg) { - cell_start_col++; - } + ctx.ctx = c->select_ctx; + ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL); + ctx.base_url = c->base_url; + ctx.universal = c->universal; - /* Update current column with calculated start */ - col_info->current_column = cell_start_col; + style = nscss_get_blank_style(&ctx, table->style); + if (style == NULL) { + free(col_info.spans); + return false; + } - /* If this cell has a colspan of 0, then assume 1. - * No other browser supports colspan=0, anyway. */ - if (col_span == 0) - col_span = 1; + row_group = box_create(NULL, style, true, table->href, + table->target, NULL, NULL, c->bctx); + if (row_group == NULL) { + css_computed_style_destroy(style); + free(col_info.spans); + return false; + } + row_group->type = BOX_TABLE_ROW_GROUP; - cell_end_col = cell_start_col + col_span; + style = nscss_get_blank_style(&ctx, row_group->style); + if (style == NULL) { + box_free(row_group); + free(col_info.spans); + return false; + } - if (col_info->num_columns < cell_end_col) { - /* It appears that this row has more columns than - * the maximum recorded for the table so far. - * Allocate more span records. */ - spans = realloc(col_info->spans, - sizeof *spans * (cell_end_col + 1)); - if (spans == NULL) + row = box_create(NULL, style, true, row_group->href, + row_group->target, NULL, NULL, c->bctx); + if (row == NULL) { + css_computed_style_destroy(style); + box_free(row_group); + free(col_info.spans); return false; + } + row->type = BOX_TABLE_ROW; - col_info->spans = spans; - col_info->num_columns = cell_end_col; + row->parent = row_group; + row_group->children = row_group->last = row; - /* Mark new final column as sentinel */ - col_info->spans[cell_end_col].row_span = 0; - col_info->spans[cell_end_col].auto_row = false; + row_group->parent = table; + table->children = table->last = row_group; + + table->rows = 1; } - /* This cell may span multiple columns. If it also wants to span - * multiple rows, temporarily assume it spans 1 row only. This will - * be fixed up in box_normalise_table_spans() */ - for (i = cell_start_col; i < cell_end_col; i++) { - col_info->spans[i].row_span = (row_span == 0) ? 1 : row_span; - col_info->spans[i].auto_row = (row_span == 0); - col_info->spans[i].rg = rg; + if (box_normalise_table_spans(table, root, col_info.spans, c) == false) { + free(col_info.spans); + return false; } - /* Update current column with calculated end. */ - col_info->current_column = cell_end_col; + free(col_info.spans); - *start_column = cell_start_col; +#ifdef BOX_NORMALISE_DEBUG + NSLOG(netsurf, INFO, "table %p done", table); +#endif return true; } -bool box_normalise_inline_container( - struct box *cont, - const struct box *root, - html_content * c) +static bool +box_normalise_inline_container(struct box *cont, + const struct box *root, + html_content * c) { struct box *child; struct box *next_child; @@ -1045,3 +879,119 @@ bool box_normalise_inline_container( return true; } + + +/* Exported function documented in html/box_normalise.h */ +bool +box_normalise_block(struct box *block, const struct box *root, html_content *c) +{ + struct box *child; + struct box *next_child; + struct box *table; + css_computed_style *style; + nscss_select_ctx ctx; + + assert(block != NULL); + assert(root != NULL); + + ctx.root_style = root->style; + +#ifdef BOX_NORMALISE_DEBUG + NSLOG(netsurf, INFO, "block %p, block->type %u", block, block->type); +#endif + + assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK || + block->type == BOX_TABLE_CELL); + + for (child = block->children; child != NULL; child = next_child) { +#ifdef BOX_NORMALISE_DEBUG + NSLOG(netsurf, INFO, "child %p, child->type = %d", child, + child->type); +#endif + + next_child = child->next; /* child may be destroyed */ + + switch (child->type) { + case BOX_BLOCK: + /* ok */ + if (box_normalise_block(child, root, c) == false) + return false; + break; + case BOX_INLINE_CONTAINER: + if (box_normalise_inline_container(child, root, c) == false) + return false; + break; + case BOX_TABLE: + if (box_normalise_table(child, root, c) == false) + return false; + break; + case BOX_INLINE: + case BOX_INLINE_END: + case BOX_INLINE_BLOCK: + case BOX_FLOAT_LEFT: + case BOX_FLOAT_RIGHT: + case BOX_BR: + case BOX_TEXT: + /* should have been wrapped in inline + container by convert_xml_to_box() */ + assert(0); + break; + case BOX_TABLE_ROW_GROUP: + case BOX_TABLE_ROW: + case BOX_TABLE_CELL: + /* insert implied table */ + assert(block->style != NULL); + + ctx.ctx = c->select_ctx; + ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL); + ctx.base_url = c->base_url; + ctx.universal = c->universal; + + style = nscss_get_blank_style(&ctx, block->style); + if (style == NULL) + return false; + + table = box_create(NULL, style, true, block->href, + block->target, NULL, NULL, c->bctx); + if (table == NULL) { + css_computed_style_destroy(style); + return false; + } + table->type = BOX_TABLE; + + if (child->prev == NULL) + block->children = table; + else + child->prev->next = table; + + table->prev = child->prev; + + while (child != NULL && ( + child->type == BOX_TABLE_ROW_GROUP || + child->type == BOX_TABLE_ROW || + child->type == BOX_TABLE_CELL)) { + box_add_child(table, child); + + next_child = child->next; + child->next = NULL; + child = next_child; + } + + table->last->next = NULL; + table->next = next_child = child; + if (table->next != NULL) + table->next->prev = table; + else + block->last = table; + table->parent = block; + + if (box_normalise_table(table, root, c) == false) + return false; + break; + default: + assert(0); + } + } + + return true; +} -- cgit v1.2.3