diff options
Diffstat (limited to 'content/handlers/html/box_normalise.c')
-rw-r--r-- | content/handlers/html/box_normalise.c | 1047 |
1 files changed, 1047 insertions, 0 deletions
diff --git a/content/handlers/html/box_normalise.c b/content/handlers/html/box_normalise.c new file mode 100644 index 000000000..7155cb722 --- /dev/null +++ b/content/handlers/html/box_normalise.c @@ -0,0 +1,1047 @@ +/* + * Copyright 2005 James Bursa <bursa@users.sourceforge.net> + * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net> + * Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk> + * Copyright 2004 Kevin Bagust <kevin.bagust@ntlworld.com> + * + * 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 + * Box tree normalisation (implementation). + */ + +#include <assert.h> +#include <stdbool.h> +#include <string.h> + +#include "utils/log.h" +#include "utils/errors.h" +#include "css/select.h" + +#include "html/box.h" +#include "html/html_internal.h" +#include "html/table.h" + +/* Define to enable box normalise debug */ +#undef BOX_NORMALISE_DEBUG + +/** + * Row spanning information for a cell + */ +struct span_info { + /** Number of rows this cell spans */ + unsigned int row_span; + /** Row group of cell */ + struct box *rg; + /** The cell in this column spans all rows until the end of the table */ + bool auto_row; +}; + +/** + * Column record for a table + */ +struct columns { + /** Current column index */ + unsigned int current_column; + /** Number of columns in main part of table 1..max columns */ + unsigned int num_columns; + /** Information about columns in main table, array [0, num_columns) */ + struct span_info *spans; + /** Number of rows in table */ + unsigned int num_rows; +}; + + +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 + * + * 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 + */ + +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; +} + + +bool box_normalise_table( + struct box *table, + const struct box *root, + html_content * c) +{ + struct box *child; + struct box *next_child; + struct box *row_group; + css_computed_style *style; + struct columns col_info; + nscss_select_ctx ctx; + + assert(table != NULL); + assert(table->type == BOX_TABLE); + + ctx.root_style = root->style; + +#ifdef BOX_NORMALISE_DEBUG + NSLOG(netsurf, INFO, "table %p", table); +#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) { + next_child = child->next; + switch (child->type) { + case BOX_TABLE_ROW_GROUP: + /* ok */ + if (box_normalise_table_row_group(child, root, + &col_info, c) == false) { + free(col_info.spans); + return false; + } + break; + case BOX_BLOCK: + case BOX_INLINE_CONTAINER: + case BOX_TABLE: + case BOX_TABLE_ROW: + 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, 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; + + if (child->prev == NULL) + table->children = row_group; + else + child->prev->next = row_group; + + 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 || + child->type == BOX_TABLE_CELL)) { + box_add_child(row_group, child); + + next_child = child->next; + child->next = NULL; + child = next_child; + } + + assert(row_group->last != NULL); + + row_group->last->next = NULL; + row_group->next = next_child = child; + if (row_group->next != NULL) + row_group->next->prev = row_group; + else + table->last = row_group; + row_group->parent = table; + + 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: + 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: + 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; + +#ifdef BOX_NORMALISE_DEBUG + NSLOG(netsurf, INFO, + "table->children == 0, creating implied row"); +#endif + + 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, 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; + } + + 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; + + row->parent = row_group; + row_group->children = row_group->last = row; + + row_group->parent = table; + table->children = table->last = row_group; + + table->rows = 1; + } + + if (box_normalise_table_spans(table, root, col_info.spans, c) == false) { + free(col_info.spans); + return false; + } + + free(col_info.spans); + +#ifdef BOX_NORMALISE_DEBUG + NSLOG(netsurf, INFO, "table %p done", table); +#endif + + return true; +} + + +/** + * Normalise table cell column/row counts for colspan/rowspan = 0. + * Additionally, generate empty cells. + * + * \param table Table to process + * \param root root box of document + * \param spans Array of length table->columns for use in empty cell detection + * \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) +{ + struct box *table_row_group; + struct box *table_row; + struct box *table_cell; + unsigned int rows_left = table->rows; + unsigned int group_rows_left; + unsigned int col; + nscss_select_ctx ctx; + + ctx.root_style = root->style; + + /* Clear span data */ + memset(spans, 0, table->columns * sizeof(struct span_info)); + + /* Scan table, filling in width and height of table cells with + * colspan = 0 and rowspan = 0. Also generate empty cells */ + for (table_row_group = table->children; + table_row_group != NULL; + table_row_group = table_row_group->next) { + + group_rows_left = table_row_group->rows; + + for (table_row = table_row_group->children; + table_row != NULL; + table_row = table_row->next) { + + for (table_cell = table_row->children; + table_cell != NULL; + table_cell = table_cell->next) { + + /* colspan = 0 -> colspan = 1 */ + if (table_cell->columns == 0) { + table_cell->columns = 1; + } + + /* if rowspan is 0 it is expanded to + * the number of rows left in the row + * group + */ + if (table_cell->rows == 0) { + table_cell->rows = group_rows_left; + } + + /* limit rowspans within group */ + if (table_cell->rows > group_rows_left) { + table_cell->rows = group_rows_left; + } + + /* Record span information */ + for (col = table_cell->start_column; + col < table_cell->start_column + + table_cell->columns; col++) { + spans[col].row_span = table_cell->rows; + } + } + + /* Reduce span count of each column */ + for (col = 0; col < table->columns; col++) { + if (spans[col].row_span == 0) { + unsigned int start = col; + css_computed_style *style; + struct box *cell, *prev; + + /* If it's already zero, then we need + * to generate an empty cell for the + * gap in the row that spans as many + * columns as remain blank. + */ + assert(table_row->style != NULL); + + /* Find width of gap */ + while (col < table->columns && + spans[col].row_span == + 0) { + 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; + + style = nscss_get_blank_style(&ctx, + table_row->style); + if (style == NULL) + return false; + + cell = box_create(NULL, style, true, + table_row->href, + table_row->target, + NULL, NULL, c->bctx); + if (cell == NULL) { + css_computed_style_destroy( + style); + return false; + } + cell->type = BOX_TABLE_CELL; + + cell->rows = 1; + cell->columns = col - start; + cell->start_column = start; + + /* Find place to insert cell */ + for (prev = table_row->children; + prev != NULL; + prev = prev->next) { + if (prev->start_column + + prev->columns == + start) + break; + if (prev->next == NULL) + break; + } + + /* Insert it */ + if (prev == NULL) { + if (table_row->children != NULL) + table_row->children-> + prev = cell; + else + table_row->last = cell; + + cell->next = + table_row->children; + table_row->children = cell; + } else { + if (prev->next != NULL) + prev->next->prev = cell; + else + table_row->last = cell; + + cell->next = prev->next; + prev->next = cell; + cell->prev = prev; + } + cell->parent = table_row; + } else { + spans[col].row_span--; + } + } + + assert(rows_left > 0); + + rows_left--; + } + + group_rows_left--; + } + + return true; +} + + +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; + css_computed_style *style; + nscss_select_ctx ctx; + unsigned int group_row_count = 0; + + assert(row_group != 0); + assert(row_group->type == BOX_TABLE_ROW_GROUP); + + 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); +#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; + +#ifdef BOX_NORMALISE_DEBUG + NSLOG(netsurf, INFO, "row %p", row); +#endif + + for (child = row->children; child != NULL; child = next_child) { + next_child = child->next; + + switch (child->type) { + 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: + case BOX_TABLE: + case BOX_TABLE_ROW_GROUP: + case BOX_TABLE_ROW: + /* 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, row->style); + if (style == NULL) + return false; + + cell = box_create(NULL, style, true, row->href, + row->target, NULL, NULL, c->bctx); + if (cell == NULL) { + css_computed_style_destroy(style); + return false; + } + cell->type = BOX_TABLE_CELL; + + if (child->prev == NULL) + row->children = cell; + else + child->prev->next = cell; + + 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)) { + box_add_child(cell, child); + + next_child = child->next; + child->next = NULL; + child = next_child; + } + + assert(cell->last != NULL); + + cell->last->next = NULL; + cell->next = next_child = child; + if (cell->next != NULL) + cell->next->prev = cell; + else + row->last = cell; + cell->parent = row; + + 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; +} + + +/** + * 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 */ + + /* 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; + + return true; +} + + +bool box_normalise_inline_container( + struct box *cont, + const struct box *root, + html_content * c) +{ + struct box *child; + struct box *next_child; + + assert(cont != NULL); + assert(cont->type == BOX_INLINE_CONTAINER); + +#ifdef BOX_NORMALISE_DEBUG + NSLOG(netsurf, INFO, "cont %p", cont); +#endif + + for (child = cont->children; child != NULL; child = next_child) { + next_child = child->next; + switch (child->type) { + case BOX_INLINE: + case BOX_INLINE_END: + case BOX_BR: + case BOX_TEXT: + /* ok */ + break; + case BOX_INLINE_BLOCK: + /* ok */ + if (box_normalise_block(child, root, c) == false) + return false; + break; + case BOX_FLOAT_LEFT: + case BOX_FLOAT_RIGHT: + /* ok */ + assert(child->children != NULL); + + switch (child->children->type) { + case BOX_BLOCK: + if (box_normalise_block(child->children, root, + c) == false) + return false; + break; + case BOX_TABLE: + if (box_normalise_table(child->children, root, + c) == false) + return false; + break; + default: + assert(0); + } + + if (child->children == NULL) { + /* the child has destroyed itself: remove float */ + if (child->prev == NULL) + child->parent->children = child->next; + else + child->prev->next = child->next; + if (child->next != NULL) + child->next->prev = child->prev; + else + child->parent->last = child->prev; + + box_free(child); + } + break; + case BOX_BLOCK: + case BOX_INLINE_CONTAINER: + case BOX_TABLE: + case BOX_TABLE_ROW_GROUP: + case BOX_TABLE_ROW: + case BOX_TABLE_CELL: + default: + assert(0); + } + } + +#ifdef BOX_NORMALISE_DEBUG + NSLOG(netsurf, INFO, "cont %p done", cont); +#endif + + return true; +} |