diff options
Diffstat (limited to 'render')
-rw-r--r-- | render/box.c | 45 | ||||
-rw-r--r-- | render/box.h | 11 | ||||
-rw-r--r-- | render/box_construct.c | 52 | ||||
-rw-r--r-- | render/box_normalise.c | 124 | ||||
-rw-r--r-- | render/box_textarea.c | 15 | ||||
-rw-r--r-- | render/font.c | 8 | ||||
-rw-r--r-- | render/font.h | 11 | ||||
-rw-r--r-- | render/form.c | 145 | ||||
-rw-r--r-- | render/html.c | 97 | ||||
-rw-r--r-- | render/html_css.c | 43 | ||||
-rw-r--r-- | render/html_css_fetcher.c | 11 | ||||
-rw-r--r-- | render/html_interaction.c | 48 | ||||
-rw-r--r-- | render/html_internal.h | 4 | ||||
-rw-r--r-- | render/html_object.c | 51 | ||||
-rw-r--r-- | render/html_redraw.c | 41 | ||||
-rw-r--r-- | render/html_script.c | 98 | ||||
-rw-r--r-- | render/imagemap.c | 24 | ||||
-rw-r--r-- | render/layout.c | 3484 | ||||
-rw-r--r-- | render/layout.h | 31 | ||||
-rw-r--r-- | render/search.c | 9 | ||||
-rw-r--r-- | render/table.c | 378 | ||||
-rw-r--r-- | render/table.h | 8 | ||||
-rw-r--r-- | render/textplain.c | 18 |
23 files changed, 2596 insertions, 2160 deletions
diff --git a/render/box.c b/render/box.c index 77cc15bc3..c97e8982b 100644 --- a/render/box.c +++ b/render/box.c @@ -342,20 +342,27 @@ void box_bounds(struct box *box, struct rect *r) /** * Determine if a point lies within a box. * - * \param box box to consider - * \param x coordinate relative to box - * \param y coordinate relative to box - * \param physically if function returning true, physically is set true if - * point is within the box's physical dimensions and false - * if the point is not within the box's physical dimensions - * but is in the area defined by the box's descendants. - * if function returning false, physically is undefined. + * \param[in] len_ctx CSS length conversion context to use. + * \param[in] box Box to consider + * \param[in] x Coordinate relative to box + * \param[in] y Coordinate relative to box + * \param[out] physically If function returning true, physically is set true + * iff point is within the box's physical dimensions and + * false if the point is not within the box's physical + * dimensions but is in the area defined by the box's + * descendants. If function returns false, physically + * is undefined. * \return true if the point is within the box or a descendant box * * This is a helper function for box_at_point(). */ -static bool box_contains_point(struct box *box, int x, int y, bool *physically) +static bool box_contains_point( + const nscss_len_ctx *len_ctx, + const struct box *box, + int x, + int y, + bool *physically) { css_computed_clip_rect css_rect; @@ -382,25 +389,25 @@ static bool box_contains_point(struct box *box, int x, int y, bool *physically) /* Adjust rect to css clip region */ if (css_rect.left_auto == false) { - r.x0 += FIXTOINT(nscss_len2px( + r.x0 += FIXTOINT(nscss_len2px(len_ctx, css_rect.left, css_rect.lunit, box->style)); } if (css_rect.top_auto == false) { - r.y0 += FIXTOINT(nscss_len2px( + r.y0 += FIXTOINT(nscss_len2px(len_ctx, css_rect.top, css_rect.tunit, box->style)); } if (css_rect.right_auto == false) { r.x1 = box->border[LEFT].width + - FIXTOINT(nscss_len2px( + FIXTOINT(nscss_len2px(len_ctx, css_rect.right, css_rect.runit, box->style)); } if (css_rect.bottom_auto == false) { r.y1 = box->border[TOP].width + - FIXTOINT(nscss_len2px( + FIXTOINT(nscss_len2px(len_ctx, css_rect.bottom, css_rect.bunit, box->style)); @@ -659,6 +666,7 @@ skip_children: /** * Find the boxes at a point. * + * \param len_ctx CSS length conversion context for document. * \param box box to search children of * \param x point to find, in global document coordinates * \param y point to find, in global document coordinates @@ -674,13 +682,14 @@ skip_children: * struct box *box = top_of_document_to_search; * int box_x = 0, box_y = 0; * - * while ((box = box_at_point(box, x, y, &box_x, &box_y))) { + * while ((box = box_at_point(len_ctx, box, x, y, &box_x, &box_y))) { * // process box * } * \endcode */ -struct box *box_at_point(struct box *box, const int x, const int y, +struct box *box_at_point(const nscss_len_ctx *len_ctx, + struct box *box, const int x, const int y, int *box_x, int *box_y) { bool skip_children; @@ -690,7 +699,7 @@ struct box *box_at_point(struct box *box, const int x, const int y, skip_children = false; while ((box = box_next_xy(box, box_x, box_y, skip_children))) { - if (box_contains_point(box, x - *box_x, y - *box_y, + if (box_contains_point(len_ctx, box, x - *box_x, y - *box_y, &physically)) { *box_x -= scrollbar_get_offset(box->scroll_x); *box_y -= scrollbar_get_offset(box->scroll_y); @@ -1155,7 +1164,7 @@ bool box_handle_scrollbars(struct content *c, struct box *box, if (box->scroll_y == NULL) { data = malloc(sizeof(struct html_scrollbar_data)); if (data == NULL) { - LOG("malloc failed"); + NSLOG(netsurf, INFO, "malloc failed"); guit->misc->warning("NoMemory", 0); return false; } @@ -1176,7 +1185,7 @@ bool box_handle_scrollbars(struct content *c, struct box *box, if (box->scroll_x == NULL) { data = malloc(sizeof(struct html_scrollbar_data)); if (data == NULL) { - LOG("malloc failed"); + NSLOG(netsurf, INFO, "malloc failed"); guit->misc->warning("NoMemory", 0); return false; } diff --git a/render/box.h b/render/box.h index 2800d4026..1af0a8b73 100644 --- a/render/box.h +++ b/render/box.h @@ -91,6 +91,8 @@ #include <stdio.h> #include <libcss/libcss.h> +#include "content/handlers/css/utils.h" + struct content; struct box; struct browser_window; @@ -328,7 +330,9 @@ void box_free(struct box *box); void box_free_box(struct box *box); void box_bounds(struct box *box, struct rect *r); void box_coords(struct box *box, int *x, int *y); -struct box *box_at_point(struct box *box, const int x, const int y, +struct box *box_at_point( + const nscss_len_ctx *len_ctx, + struct box *box, const int x, const int y, int *box_x, int *box_y); struct box *box_pick_text_box(struct html_content *html, int x, int y, int dir, int *dx, int *dy); @@ -356,6 +360,9 @@ bool box_hscrollbar_present(const struct box *box); nserror dom_to_box(struct dom_node *n, struct html_content *c, box_construct_complete_cb cb); -bool box_normalise_block(struct box *block, struct html_content *c); +bool box_normalise_block( + struct box *block, + const struct box *root, + struct html_content *c); #endif diff --git a/render/box_construct.c b/render/box_construct.c index d0ffd9d83..1aa99e2d1 100644 --- a/render/box_construct.c +++ b/render/box_construct.c @@ -46,6 +46,7 @@ #include "content/content_protected.h" #include "css/hints.h" #include "css/select.h" +#include "css/utils.h" #include "desktop/gui_internal.h" #include "render/box.h" @@ -103,7 +104,8 @@ static bool box_construct_element(struct box_construct_ctx *ctx, static void box_construct_element_after(dom_node *n, html_content *content); static bool box_construct_text(struct box_construct_ctx *ctx); static css_select_results * box_get_style(html_content *c, - const css_computed_style *parent_style, dom_node *n); + const css_computed_style *parent_style, + const css_computed_style *root_style, dom_node *n); static void box_text_transform(char *s, unsigned int len, enum css_text_transform_e tt); #define BOX_SPECIAL_PARAMS dom_node *n, html_content *content, \ @@ -428,7 +430,8 @@ void convert_xml_to_box(struct box_construct_ctx *ctx) root.children->parent = &root; /** \todo Remove box_normalise_block */ - if (box_normalise_block(&root, ctx->content) == false) { + if (box_normalise_block(&root, ctx->root_box, + ctx->content) == false) { ctx->cb(ctx->content, false); } else { ctx->content->layout = root.children; @@ -612,7 +615,7 @@ static void box_construct_generate(dom_node *n, html_content *content, } /* create box for this element */ - computed_display = css_computed_display(style, box_is_root(n)); + computed_display = ns_computed_display(style, box_is_root(n)); if (computed_display == CSS_DISPLAY_BLOCK || computed_display == CSS_DISPLAY_TABLE) { /* currently only support block level boxes */ @@ -625,7 +628,7 @@ static void box_construct_generate(dom_node *n, html_content *content, } /* set box type from computed display */ - gen->type = box_map[css_computed_display( + gen->type = box_map[ns_computed_display( style, box_is_root(n))]; box_add_child(box, gen); @@ -740,6 +743,7 @@ bool box_construct_element(struct box_construct_ctx *ctx, lwc_string *bgimage_uri; dom_exception err; struct box_construct_props props; + const css_computed_style *root_style = NULL; assert(ctx->n != NULL); @@ -752,7 +756,12 @@ bool box_construct_element(struct box_construct_ctx *ctx, props.containing_block->flags &= ~PRE_STRIP; } - styles = box_get_style(ctx->content, props.parent_style, ctx->n); + if (props.node_is_root == false) { + root_style = ctx->root_box->style; + } + + styles = box_get_style(ctx->content, props.parent_style, root_style, + ctx->n); if (styles == NULL) return false; @@ -831,11 +840,11 @@ bool box_construct_element(struct box_construct_ctx *ctx, if ((css_computed_position(box->style) == CSS_POSITION_ABSOLUTE || css_computed_position(box->style) == CSS_POSITION_FIXED) && - (css_computed_display_static(box->style) == + (ns_computed_display_static(box->style) == CSS_DISPLAY_INLINE || - css_computed_display_static(box->style) == + ns_computed_display_static(box->style) == CSS_DISPLAY_INLINE_BLOCK || - css_computed_display_static(box->style) == + ns_computed_display_static(box->style) == CSS_DISPLAY_INLINE_TABLE)) { /* Special case for absolute positioning: make absolute inlines * into inline block so that the boxes are constructed in an @@ -848,7 +857,7 @@ bool box_construct_element(struct box_construct_ctx *ctx, box->type = BOX_BLOCK; } else { /* Normal mapping */ - box->type = box_map[css_computed_display(box->style, + box->type = box_map[ns_computed_display(box->style, props.node_is_root)]; } @@ -876,7 +885,7 @@ bool box_construct_element(struct box_construct_ctx *ctx, box->styles->styles[CSS_PSEUDO_ELEMENT_BEFORE]); } - if (box->type == BOX_NONE || (css_computed_display(box->style, + if (box->type == BOX_NONE || (ns_computed_display(box->style, props.node_is_root) == CSS_DISPLAY_NONE && props.node_is_root == false)) { css_select_results_destroy(styles); @@ -968,7 +977,7 @@ bool box_construct_element(struct box_construct_ctx *ctx, box_add_child(props.inline_container, box); } else { - if (css_computed_display(box->style, props.node_is_root) == + if (ns_computed_display(box->style, props.node_is_root) == CSS_DISPLAY_LIST_ITEM) { /* List item: compute marker */ if (box_construct_marker(box, props.title, ctx, @@ -1320,13 +1329,15 @@ bool box_construct_text(struct box_construct_ctx *ctx) /** * Get the style for an element. * - * \param c content of type CONTENT_HTML that is being processed + * \param c content of type CONTENT_HTML that is being processed * \param parent_style style at this point in xml tree, or NULL for root - * \param n node in xml tree + * \param root_style root node's style, or NULL for root + * \param n node in xml tree * \return the new style, or NULL on memory exhaustion */ css_select_results *box_get_style(html_content *c, - const css_computed_style *parent_style, dom_node *n) + const css_computed_style *parent_style, + const css_computed_style *root_style, dom_node *n) { dom_string *s; dom_exception err; @@ -1358,6 +1369,7 @@ css_select_results *box_get_style(html_content *c, ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL); ctx.base_url = c->base_url; ctx.universal = c->universal; + ctx.root_style = root_style; ctx.parent_style = parent_style; /* Select style for element */ @@ -1559,7 +1571,7 @@ bool box_image(BOX_SPECIAL_PARAMS) css_unit wunit = CSS_UNIT_PX; css_unit hunit = CSS_UNIT_PX; - if (box->style && css_computed_display(box->style, + if (box->style && ns_computed_display(box->style, box_is_root(n)) == CSS_DISPLAY_NONE) return true; @@ -1666,7 +1678,7 @@ bool box_object(BOX_SPECIAL_PARAMS) dom_node *c; dom_exception err; - if (box->style && css_computed_display(box->style, + if (box->style && ns_computed_display(box->style, box_is_root(n)) == CSS_DISPLAY_NONE) return true; @@ -1900,7 +1912,7 @@ bool box_frameset(BOX_SPECIAL_PARAMS) bool ok; if (content->frameset) { - LOG("Error: multiple framesets in document."); + NSLOG(netsurf, INFO, "Error: multiple framesets in document."); /* Don't convert children */ if (convert_children) *convert_children = false; @@ -2316,7 +2328,7 @@ bool box_iframe(BOX_SPECIAL_PARAMS) struct content_html_iframe *iframe; int i; - if (box->style && css_computed_display(box->style, + if (box->style && ns_computed_display(box->style, box_is_root(n)) == CSS_DISPLAY_NONE) return true; @@ -2551,7 +2563,7 @@ bool box_input(BOX_SPECIAL_PARAMS) corestring_lwc_image)) { gadget->type = GADGET_IMAGE; - if (box->style && css_computed_display(box->style, + if (box->style && ns_computed_display(box->style, box_is_root(n)) != CSS_DISPLAY_NONE && nsoption_bool(foreground_images) == true) { dom_string *s; @@ -2887,7 +2899,7 @@ bool box_embed(BOX_SPECIAL_PARAMS) dom_string *src; dom_exception err; - if (box->style && css_computed_display(box->style, + if (box->style && ns_computed_display(box->style, box_is_root(n)) == CSS_DISPLAY_NONE) return true; diff --git a/render/box_normalise.c b/render/box_normalise.c index 5d36b99d7..8da245754 100644 --- a/render/box_normalise.c +++ b/render/box_normalise.c @@ -65,24 +65,38 @@ struct columns { }; -static bool box_normalise_table(struct box *table, html_content *c); -static bool box_normalise_table_spans(struct box *table, - struct span_info *spans, html_content *c); -static bool box_normalise_table_row_group(struct box *row_group, +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, +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, html_content *c); +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 * @@ -100,7 +114,10 @@ static bool box_normalise_inline_container(struct box *cont, html_content *c); * \endcode */ -bool box_normalise_block(struct box *block, html_content *c) +bool box_normalise_block( + struct box *block, + const struct box *root, + html_content *c) { struct box *child; struct box *next_child; @@ -109,9 +126,12 @@ bool box_normalise_block(struct box *block, html_content *c) nscss_select_ctx ctx; assert(block != NULL); + assert(root != NULL); + + ctx.root_style = root->style; #ifdef BOX_NORMALISE_DEBUG - LOG("block %p, block->type %u", block, block->type); + NSLOG(netsurf, INFO, "block %p, block->type %u", block, block->type); #endif assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK || @@ -119,7 +139,8 @@ bool box_normalise_block(struct box *block, html_content *c) for (child = block->children; child != NULL; child = next_child) { #ifdef BOX_NORMALISE_DEBUG - LOG("child %p, child->type = %d", child, child->type); + NSLOG(netsurf, INFO, "child %p, child->type = %d", child, + child->type); #endif next_child = child->next; /* child may be destroyed */ @@ -127,15 +148,15 @@ bool box_normalise_block(struct box *block, html_content *c) switch (child->type) { case BOX_BLOCK: /* ok */ - if (box_normalise_block(child, c) == false) + if (box_normalise_block(child, root, c) == false) return false; break; case BOX_INLINE_CONTAINER: - if (box_normalise_inline_container(child, c) == false) + if (box_normalise_inline_container(child, root, c) == false) return false; break; case BOX_TABLE: - if (box_normalise_table(child, c) == false) + if (box_normalise_table(child, root, c) == false) return false; break; case BOX_INLINE: @@ -198,7 +219,7 @@ bool box_normalise_block(struct box *block, html_content *c) block->last = table; table->parent = block; - if (box_normalise_table(table, c) == false) + if (box_normalise_table(table, root, c) == false) return false; break; default: @@ -210,7 +231,10 @@ bool box_normalise_block(struct box *block, html_content *c) } -bool box_normalise_table(struct box *table, html_content * c) +bool box_normalise_table( + struct box *table, + const struct box *root, + html_content * c) { struct box *child; struct box *next_child; @@ -222,8 +246,10 @@ bool box_normalise_table(struct box *table, html_content * c) assert(table != NULL); assert(table->type == BOX_TABLE); + ctx.root_style = root->style; + #ifdef BOX_NORMALISE_DEBUG - LOG("table %p", table); + NSLOG(netsurf, INFO, "table %p", table); #endif col_info.num_columns = 1; @@ -242,7 +268,7 @@ bool box_normalise_table(struct box *table, html_content * c) switch (child->type) { case BOX_TABLE_ROW_GROUP: /* ok */ - if (box_normalise_table_row_group(child, + if (box_normalise_table_row_group(child, root, &col_info, c) == false) { free(col_info.spans); return false; @@ -307,7 +333,7 @@ bool box_normalise_table(struct box *table, html_content * c) table->last = row_group; row_group->parent = table; - if (box_normalise_table_row_group(row_group, + if (box_normalise_table_row_group(row_group, root, &col_info, c) == false) { free(col_info.spans); return false; @@ -337,7 +363,8 @@ bool box_normalise_table(struct box *table, html_content * c) struct box *row; #ifdef BOX_NORMALISE_DEBUG - LOG("table->children == 0, creating implied row"); + NSLOG(netsurf, INFO, + "table->children == 0, creating implied row"); #endif assert(table->style != NULL); @@ -388,18 +415,15 @@ bool box_normalise_table(struct box *table, html_content * c) table->rows = 1; } - if (box_normalise_table_spans(table, col_info.spans, c) == false) { + if (box_normalise_table_spans(table, root, col_info.spans, c) == false) { free(col_info.spans); return false; } free(col_info.spans); - if (table_calculate_column_types(table) == false) - return false; - #ifdef BOX_NORMALISE_DEBUG - LOG("table %p done", table); + NSLOG(netsurf, INFO, "table %p done", table); #endif return true; @@ -411,12 +435,16 @@ bool box_normalise_table(struct box *table, html_content * c) * 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, struct span_info *spans, +bool box_normalise_table_spans( + struct box *table, + const struct box *root, + struct span_info *spans, html_content *c) { struct box *table_row_group; @@ -427,6 +455,8 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans, unsigned int col; nscss_select_ctx ctx; + ctx.root_style = root->style; + /* Clear span data */ memset(spans, 0, table->columns * sizeof(struct span_info)); @@ -570,7 +600,9 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans, } -bool box_normalise_table_row_group(struct box *row_group, +bool box_normalise_table_row_group( + struct box *row_group, + const struct box *root, struct columns *col_info, html_content * c) { @@ -584,8 +616,10 @@ bool box_normalise_table_row_group(struct box *row_group, assert(row_group != 0); assert(row_group->type == BOX_TABLE_ROW_GROUP); + ctx.root_style = root->style; + #ifdef BOX_NORMALISE_DEBUG - LOG("row_group %p", row_group); + NSLOG(netsurf, INFO, "row_group %p", row_group); #endif for (child = row_group->children; child != NULL; child = next_child) { @@ -595,7 +629,7 @@ bool box_normalise_table_row_group(struct box *row_group, case BOX_TABLE_ROW: /* ok */ group_row_count++; - if (box_normalise_table_row(child, col_info, + if (box_normalise_table_row(child, root, col_info, c) == false) return false; break; @@ -655,7 +689,7 @@ bool box_normalise_table_row_group(struct box *row_group, row->parent = row_group; group_row_count++; - if (box_normalise_table_row(row, col_info, + if (box_normalise_table_row(row, root, col_info, c) == false) return false; break; @@ -677,7 +711,8 @@ bool box_normalise_table_row_group(struct box *row_group, if (row_group->children == NULL) { #ifdef BOX_NORMALISE_DEBUG - LOG("row_group->children == 0, inserting implied row"); + NSLOG(netsurf, INFO, + "row_group->children == 0, inserting implied row"); #endif assert(row_group->style != NULL); @@ -712,14 +747,16 @@ bool box_normalise_table_row_group(struct box *row_group, row_group->rows = group_row_count; #ifdef BOX_NORMALISE_DEBUG - LOG("row_group %p done", row_group); + NSLOG(netsurf, INFO, "row_group %p done", row_group); #endif return true; } -bool box_normalise_table_row(struct box *row, +bool box_normalise_table_row( + struct box *row, + const struct box *root, struct columns *col_info, html_content * c) { @@ -733,8 +770,10 @@ bool box_normalise_table_row(struct box *row, assert(row != NULL); assert(row->type == BOX_TABLE_ROW); + ctx.root_style = root->style; + #ifdef BOX_NORMALISE_DEBUG - LOG("row %p", row); + NSLOG(netsurf, INFO, "row %p", row); #endif for (child = row->children; child != NULL; child = next_child) { @@ -743,7 +782,7 @@ bool box_normalise_table_row(struct box *row, switch (child->type) { case BOX_TABLE_CELL: /* ok */ - if (box_normalise_block(child, c) == false) + if (box_normalise_block(child, root, c) == false) return false; cell = child; break; @@ -802,7 +841,7 @@ bool box_normalise_table_row(struct box *row, row->last = cell; cell->parent = row; - if (box_normalise_block(cell, c) == false) + if (box_normalise_block(cell, root, c) == false) return false; break; case BOX_INLINE: @@ -843,7 +882,7 @@ bool box_normalise_table_row(struct box *row, col_info->num_rows++; #ifdef BOX_NORMALISE_DEBUG - LOG("row %p done", row); + NSLOG(netsurf, INFO, "row %p done", row); #endif return true; @@ -925,7 +964,10 @@ bool calculate_table_row(struct columns *col_info, } -bool box_normalise_inline_container(struct box *cont, html_content * c) +bool box_normalise_inline_container( + struct box *cont, + const struct box *root, + html_content * c) { struct box *child; struct box *next_child; @@ -934,7 +976,7 @@ bool box_normalise_inline_container(struct box *cont, html_content * c) assert(cont->type == BOX_INLINE_CONTAINER); #ifdef BOX_NORMALISE_DEBUG - LOG("cont %p", cont); + NSLOG(netsurf, INFO, "cont %p", cont); #endif for (child = cont->children; child != NULL; child = next_child) { @@ -948,7 +990,7 @@ bool box_normalise_inline_container(struct box *cont, html_content * c) break; case BOX_INLINE_BLOCK: /* ok */ - if (box_normalise_block(child, c) == false) + if (box_normalise_block(child, root, c) == false) return false; break; case BOX_FLOAT_LEFT: @@ -958,12 +1000,12 @@ bool box_normalise_inline_container(struct box *cont, html_content * c) switch (child->children->type) { case BOX_BLOCK: - if (box_normalise_block(child->children, + if (box_normalise_block(child->children, root, c) == false) return false; break; case BOX_TABLE: - if (box_normalise_table(child->children, + if (box_normalise_table(child->children, root, c) == false) return false; break; @@ -997,7 +1039,7 @@ bool box_normalise_inline_container(struct box *cont, html_content * c) } #ifdef BOX_NORMALISE_DEBUG - LOG("cont %p done", cont); + NSLOG(netsurf, INFO, "cont %p done", cont); #endif return true; diff --git a/render/box_textarea.c b/render/box_textarea.c index 1586d71c4..a60984235 100644 --- a/render/box_textarea.c +++ b/render/box_textarea.c @@ -149,7 +149,9 @@ static void box_textarea_callback(void *data, struct textarea_msg *msg) break; default: - LOG("Drag type %d not handled.", msg->data.drag); + NSLOG(netsurf, INFO, + "Drag type %d not handled.", + msg->data.drag); /* This is a logic faliure in the * front end code so abort. */ @@ -237,7 +239,14 @@ bool box_textarea_create_textarea(html_content *html, dom_exception err; textarea_setup ta_setup; textarea_flags ta_flags; - plot_font_style_t fstyle; + plot_font_style_t fstyle = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 10 * FONT_SIZE_SCALE, + .weight = 400, + .flags = FONTF_NONE, + .background = 0, + .foreground = 0, + }; bool read_only = false; bool disabled = false; struct form_control *gadget = box->gadget; @@ -305,8 +314,6 @@ bool box_textarea_create_textarea(html_content *html, gadget->data.text.data.gadget = gadget; - font_plot_style_from_css(gadget->box->style, &fstyle); - /* Reset to correct values by layout */ ta_setup.width = 200; ta_setup.height = 20; diff --git a/render/font.c b/render/font.c index 94ef877c7..a769b476f 100644 --- a/render/font.c +++ b/render/font.c @@ -131,8 +131,10 @@ static plot_font_flags_t plot_font_flags(enum css_font_style_e style, } -/* exported function documented in render/font_internal.h */ -void font_plot_style_from_css(const css_computed_style *css, +/* exported function documented in render/font.h */ +void font_plot_style_from_css( + const nscss_len_ctx *len_ctx, + const css_computed_style *css, plot_font_style_t *fstyle) { lwc_string **families; @@ -144,7 +146,7 @@ void font_plot_style_from_css(const css_computed_style *css, css_computed_font_family(css, &families)); css_computed_font_size(css, &length, &unit); - fstyle->size = FIXTOINT(FMUL(nscss_len2pt(length, unit), + fstyle->size = FIXTOINT(FMUL(nscss_len2pt(len_ctx, length, unit), INTTOFIX(FONT_SIZE_SCALE))); /* Clamp font size to configured minimum */ diff --git a/render/font.h b/render/font.h index fba368a97..52f5a62c2 100644 --- a/render/font.h +++ b/render/font.h @@ -32,10 +32,13 @@ struct plot_font_style; /** * Populate a font style using data from a computed CSS style * - * \param css Computed style to consider - * \param fstyle Font style to populate + * \param len_ctx Length conversion context + * \param css Computed style to consider + * \param fstyle Font style to populate */ -void font_plot_style_from_css(const css_computed_style *css, - struct plot_font_style *fstyle); +void font_plot_style_from_css( + const nscss_len_ctx *len_ctx, + const css_computed_style *css, + struct plot_font_style *fstyle); #endif diff --git a/render/form.c b/render/form.c index a8b96fefb..432002564 100644 --- a/render/form.c +++ b/render/form.c @@ -218,7 +218,8 @@ void form_free_control(struct form_control *control) struct form_control *c; assert(control != NULL); - LOG("Control:%p name:%p value:%p initial:%p", control, control->name, control->value, control->initial_value); + NSLOG(netsurf, INFO, "Control:%p name:%p value:%p initial:%p", + control, control->name, control->value, control->initial_value); free(control->name); free(control->value); free(control->initial_value); @@ -229,7 +230,9 @@ void form_free_control(struct form_control *control) for (option = control->data.select.items; option; option = next) { next = option->next; - LOG("select option:%p text:%p value:%p", option, option->text, option->value); + NSLOG(netsurf, INFO, + "select option:%p text:%p value:%p", option, + option->text, option->value); free(option->text); free(option->value); free(option); @@ -348,7 +351,7 @@ bool form_successful_controls_dom(struct form *_form, /** \todo Replace this call with something DOMish */ charset = form_acceptable_charset(_form); if (charset == NULL) { - LOG("failed to find charset"); + NSLOG(netsurf, INFO, "failed to find charset"); return false; } @@ -362,7 +365,7 @@ bool form_successful_controls_dom(struct form *_form, err = dom_html_form_element_get_elements(form, &form_elements); if (err != DOM_NO_ERR) { - LOG("Could not get form elements"); + NSLOG(netsurf, INFO, "Could not get form elements"); goto dom_no_memory; } @@ -370,7 +373,7 @@ bool form_successful_controls_dom(struct form *_form, err = dom_html_collection_get_length(form_elements, &element_count); if (err != DOM_NO_ERR) { - LOG("Could not get form element count"); + NSLOG(netsurf, INFO, "Could not get form element count"); goto dom_no_memory; } @@ -402,7 +405,8 @@ bool form_successful_controls_dom(struct form *_form, err = dom_html_collection_item(form_elements, index, &form_element); if (err != DOM_NO_ERR) { - LOG("Could not retrieve form element %d", index); + NSLOG(netsurf, INFO, + "Could not retrieve form element %d", index); goto dom_no_memory; } @@ -414,7 +418,7 @@ bool form_successful_controls_dom(struct form *_form, */ err = dom_node_get_node_name(form_element, &nodename); if (err != DOM_NO_ERR) { - LOG("Could not get node name"); + NSLOG(netsurf, INFO, "Could not get node name"); goto dom_no_memory; } @@ -423,14 +427,16 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_text_area_element *)form_element, &element_disabled); if (err != DOM_NO_ERR) { - LOG("Could not get text area disabled property"); + NSLOG(netsurf, INFO, + "Could not get text area disabled property"); goto dom_no_memory; } err = dom_html_text_area_element_get_name( (dom_html_text_area_element *)form_element, &inputname); if (err != DOM_NO_ERR) { - LOG("Could not get text area name property"); + NSLOG(netsurf, INFO, + "Could not get text area name property"); goto dom_no_memory; } } else if (dom_string_isequal(nodename, corestring_dom_SELECT)) { @@ -438,14 +444,16 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_select_element *)form_element, &element_disabled); if (err != DOM_NO_ERR) { - LOG("Could not get select disabled property"); + NSLOG(netsurf, INFO, + "Could not get select disabled property"); goto dom_no_memory; } err = dom_html_select_element_get_name( (dom_html_select_element *)form_element, &inputname); if (err != DOM_NO_ERR) { - LOG("Could not get select name property"); + NSLOG(netsurf, INFO, + "Could not get select name property"); goto dom_no_memory; } } else if (dom_string_isequal(nodename, corestring_dom_INPUT)) { @@ -453,14 +461,16 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_input_element *)form_element, &element_disabled); if (err != DOM_NO_ERR) { - LOG("Could not get input disabled property"); + NSLOG(netsurf, INFO, + "Could not get input disabled property"); goto dom_no_memory; } err = dom_html_input_element_get_name( (dom_html_input_element *)form_element, &inputname); if (err != DOM_NO_ERR) { - LOG("Could not get input name property"); + NSLOG(netsurf, INFO, + "Could not get input name property"); goto dom_no_memory; } } else if (dom_string_isequal(nodename, corestring_dom_BUTTON)) { @@ -468,21 +478,23 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_button_element *)form_element, &element_disabled); if (err != DOM_NO_ERR) { - LOG("Could not get button disabled property"); + NSLOG(netsurf, INFO, + "Could not get button disabled property"); goto dom_no_memory; } err = dom_html_button_element_get_name( (dom_html_button_element *)form_element, &inputname); if (err != DOM_NO_ERR) { - LOG("Could not get button name property"); + NSLOG(netsurf, INFO, + "Could not get button name property"); goto dom_no_memory; } } else { /* Unknown element type came through! */ - LOG("Unknown element type: %*s", - (int)dom_string_byte_length(nodename), - dom_string_data(nodename)); + NSLOG(netsurf, INFO, "Unknown element type: %*s", + (int)dom_string_byte_length(nodename), + dom_string_data(nodename)); goto dom_no_memory; } if (element_disabled) @@ -495,7 +507,8 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_text_area_element *)form_element, &inputvalue); if (err != DOM_NO_ERR) { - LOG("Could not get text area content"); + NSLOG(netsurf, INFO, + "Could not get text area content"); goto dom_no_memory; } } else if (dom_string_isequal(nodename, corestring_dom_SELECT)) { @@ -504,13 +517,15 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_select_element *)form_element, &options); if (err != DOM_NO_ERR) { - LOG("Could not get select options collection"); + NSLOG(netsurf, INFO, + "Could not get select options collection"); goto dom_no_memory; } err = dom_html_options_collection_get_length( options, &options_count); if (err != DOM_NO_ERR) { - LOG("Could not get select options collection length"); + NSLOG(netsurf, INFO, + "Could not get select options collection length"); goto dom_no_memory; } for(option_index = 0; option_index < options_count; @@ -527,14 +542,17 @@ bool form_successful_controls_dom(struct form *_form, err = dom_html_options_collection_item( options, option_index, &option_element); if (err != DOM_NO_ERR) { - LOG("Could not get options item %d", option_index); + NSLOG(netsurf, INFO, + "Could not get options item %d", + option_index); goto dom_no_memory; } err = dom_html_option_element_get_selected( (dom_html_option_element *)option_element, &selected); if (err != DOM_NO_ERR) { - LOG("Could not get option selected property"); + NSLOG(netsurf, INFO, + "Could not get option selected property"); goto dom_no_memory; } if (!selected) @@ -543,13 +561,15 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_option_element *)option_element, &inputvalue); if (err != DOM_NO_ERR) { - LOG("Could not get option value"); + NSLOG(netsurf, INFO, + "Could not get option value"); goto dom_no_memory; } success_new = calloc(1, sizeof(*success_new)); if (success_new == NULL) { - LOG("Could not allocate data for option"); + NSLOG(netsurf, INFO, + "Could not allocate data for option"); goto dom_no_memory; } @@ -558,12 +578,14 @@ bool form_successful_controls_dom(struct form *_form, success_new->name = ENCODE_ITEM(inputname); if (success_new->name == NULL) { - LOG("Could not encode name for option"); + NSLOG(netsurf, INFO, + "Could not encode name for option"); goto dom_no_memory; } success_new->value = ENCODE_ITEM(inputvalue); if (success_new->value == NULL) { - LOG("Could not encode value for option"); + NSLOG(netsurf, INFO, + "Could not encode value for option"); goto dom_no_memory; } } @@ -573,7 +595,8 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_button_element *) form_element, &inputtype); if (err != DOM_NO_ERR) { - LOG("Could not get button element type"); + NSLOG(netsurf, INFO, + "Could not get button element type"); goto dom_no_memory; } if (dom_string_caseless_isequal( @@ -593,7 +616,8 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_button_element *)form_element, &inputvalue); if (err != DOM_NO_ERR) { - LOG("Could not get submit button value"); + NSLOG(netsurf, INFO, + "Could not get submit button value"); goto dom_no_memory; } /* Drop through to report successful button */ @@ -610,7 +634,8 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_input_element *) form_element, &inputtype); if (err != DOM_NO_ERR) { - LOG("Could not get input element type"); + NSLOG(netsurf, INFO, + "Could not get input element type"); goto dom_no_memory; } if (dom_string_caseless_isequal( @@ -630,7 +655,8 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_input_element *)form_element, &inputvalue); if (err != DOM_NO_ERR) { - LOG("Could not get submit button value"); + NSLOG(netsurf, INFO, + "Could not get submit button value"); goto dom_no_memory; } /* Drop through to report the successful button */ @@ -648,11 +674,13 @@ bool form_successful_controls_dom(struct form *_form, corestring_dom___ns_key_image_coords_node_data, &coords); if (err != DOM_NO_ERR) { - LOG("Could not get image XY data"); + NSLOG(netsurf, INFO, + "Could not get image XY data"); goto dom_no_memory; } if (coords == NULL) { - LOG("No XY data on the image input"); + NSLOG(netsurf, INFO, + "No XY data on the image input"); goto dom_no_memory; } @@ -661,7 +689,8 @@ bool form_successful_controls_dom(struct form *_form, success_new = calloc(1, sizeof(*success_new)); if (success_new == NULL) { free(basename); - LOG("Could not allocate data for image.x"); + NSLOG(netsurf, INFO, + "Could not allocate data for image.x"); goto dom_no_memory; } @@ -671,13 +700,15 @@ bool form_successful_controls_dom(struct form *_form, success_new->name = malloc(strlen(basename) + 3); if (success_new->name == NULL) { free(basename); - LOG("Could not allocate name for image.x"); + NSLOG(netsurf, INFO, + "Could not allocate name for image.x"); goto dom_no_memory; } success_new->value = malloc(20); if (success_new->value == NULL) { free(basename); - LOG("Could not allocate value for image.x"); + NSLOG(netsurf, INFO, + "Could not allocate value for image.x"); goto dom_no_memory; } sprintf(success_new->name, "%s.x", basename); @@ -686,7 +717,8 @@ bool form_successful_controls_dom(struct form *_form, success_new = calloc(1, sizeof(*success_new)); if (success_new == NULL) { free(basename); - LOG("Could not allocate data for image.y"); + NSLOG(netsurf, INFO, + "Could not allocate data for image.y"); goto dom_no_memory; } @@ -696,13 +728,15 @@ bool form_successful_controls_dom(struct form *_form, success_new->name = malloc(strlen(basename) + 3); if (success_new->name == NULL) { free(basename); - LOG("Could not allocate name for image.y"); + NSLOG(netsurf, INFO, + "Could not allocate name for image.y"); goto dom_no_memory; } success_new->value = malloc(20); if (success_new->value == NULL) { free(basename); - LOG("Could not allocate value for image.y"); + NSLOG(netsurf, INFO, + "Could not allocate value for image.y"); goto dom_no_memory; } sprintf(success_new->name, "%s.y", basename); @@ -717,7 +751,8 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_input_element *)form_element, &checked); if (err != DOM_NO_ERR) { - LOG("Could not get input element checked"); + NSLOG(netsurf, INFO, + "Could not get input element checked"); goto dom_no_memory; } if (!checked) @@ -726,7 +761,8 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_input_element *)form_element, &inputvalue); if (err != DOM_NO_ERR) { - LOG("Could not get input element value"); + NSLOG(netsurf, INFO, + "Could not get input element value"); goto dom_no_memory; } if (inputvalue == NULL) { @@ -741,7 +777,8 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_input_element *)form_element, &inputvalue); if (err != DOM_NO_ERR) { - LOG("Could not get file value"); + NSLOG(netsurf, INFO, + "Could not get file value"); goto dom_no_memory; } err = dom_node_get_user_data( @@ -749,14 +786,16 @@ bool form_successful_controls_dom(struct form *_form, corestring_dom___ns_key_file_name_node_data, &rawfile_temp); if (err != DOM_NO_ERR) { - LOG("Could not get file rawname"); + NSLOG(netsurf, INFO, + "Could not get file rawname"); goto dom_no_memory; } rawfile_temp = strdup(rawfile_temp != NULL ? rawfile_temp : ""); if (rawfile_temp == NULL) { - LOG("Could not copy file rawname"); + NSLOG(netsurf, INFO, + "Could not copy file rawname"); goto dom_no_memory; } /* Fall out to the allocation */ @@ -765,7 +804,8 @@ bool form_successful_controls_dom(struct form *_form, dom_string_caseless_isequal( inputtype, corestring_dom_button)) { /* Skip these */ - LOG("Skipping RESET and BUTTON"); + NSLOG(netsurf, INFO, + "Skipping RESET and BUTTON"); continue; } else { /* Everything else is treated as text values */ @@ -773,7 +813,8 @@ bool form_successful_controls_dom(struct form *_form, (dom_html_input_element *)form_element, &inputvalue); if (err != DOM_NO_ERR) { - LOG("Could not get input value"); + NSLOG(netsurf, INFO, + "Could not get input value"); goto dom_no_memory; } /* Fall out to the allocation */ @@ -782,7 +823,8 @@ bool form_successful_controls_dom(struct form *_form, success_new = calloc(1, sizeof(*success_new)); if (success_new == NULL) { - LOG("Could not allocate data for generic"); + NSLOG(netsurf, INFO, + "Could not allocate data for generic"); goto dom_no_memory; } @@ -791,12 +833,14 @@ bool form_successful_controls_dom(struct form *_form, success_new->name = ENCODE_ITEM(inputname); if (success_new->name == NULL) { - LOG("Could not encode name for generic"); + NSLOG(netsurf, INFO, + "Could not encode name for generic"); goto dom_no_memory; } success_new->value = ENCODE_ITEM(inputvalue); if (success_new->value == NULL) { - LOG("Could not encode value for generic"); + NSLOG(netsurf, INFO, + "Could not encode value for generic"); goto dom_no_memory; } if (rawfile_temp != NULL) { @@ -1089,6 +1133,7 @@ bool form_open_select_menu(void *client_data, plot_font_style_t fstyle; int total_height; struct form_select_menu *menu; + html_content *html = (html_content *)c; /* if the menu is opened for the first time */ @@ -1109,7 +1154,7 @@ bool form_open_select_menu(void *client_data, box->border[LEFT].width + box->padding[RIGHT] + box->padding[LEFT]; - font_plot_style_from_css(control->box->style, + font_plot_style_from_css(&html->len_ctx, control->box->style, &fstyle); menu->f_size = fstyle.size; diff --git a/render/html.c b/render/html.c index a573ef5f5..b7d7aa313 100644 --- a/render/html.c +++ b/render/html.c @@ -89,8 +89,8 @@ bool fire_dom_event(dom_string *type, dom_node *target, dom_event_unref(evt); return false; } - LOG("Dispatching '%*s' against %p", - dom_string_length(type), dom_string_data(type), target); + NSLOG(netsurf, INFO, "Dispatching '%*s' against %p", + dom_string_length(type), dom_string_data(type), target); exc = dom_event_target_dispatch_event(target, evt, &result); if (exc != DOM_NO_ERR) { result = false; @@ -111,7 +111,7 @@ static void html_box_convert_done(html_content *c, bool success) dom_exception exc; /* returned by libdom functions */ dom_node *html; - LOG("Done XML to box (%p)", c); + NSLOG(netsurf, INFO, "Done XML to box (%p)", c); /* Clean up and report error if unsuccessful or aborted */ if ((success == false) || (c->aborted)) { @@ -141,7 +141,7 @@ static void html_box_convert_done(html_content *c, bool success) /** @todo should this call html_object_free_objects(c); * like the other error paths */ - LOG("error retrieving html element from dom"); + NSLOG(netsurf, INFO, "error retrieving html element from dom"); content_broadcast_errorcode(&c->base, NSERROR_DOM); content_set_error(&c->base); return; @@ -150,7 +150,7 @@ static void html_box_convert_done(html_content *c, bool success) /* extract image maps - can't do this sensibly in dom_to_box */ err = imagemap_extract(c); if (err != NSERROR_OK) { - LOG("imagemap extraction failed"); + NSLOG(netsurf, INFO, "imagemap extraction failed"); html_object_free_objects(c); content_broadcast_errorcode(&c->base, err); content_set_error(&c->base); @@ -443,7 +443,7 @@ static nserror html_meta_refresh_process_element(html_content *c, dom_node *n) c->base.refresh = nsurl_ref( content_get_url(&c->base)); - content_broadcast(&c->base, CONTENT_MSG_REFRESH, msg_data); + content_broadcast(&c->base, CONTENT_MSG_REFRESH, &msg_data); return NSERROR_OK; } @@ -522,7 +522,8 @@ static nserror html_meta_refresh_process_element(html_content *c, dom_node *n) c->base.refresh = nsurl; - content_broadcast(&c->base, CONTENT_MSG_REFRESH, msg_data); + content_broadcast(&c->base, CONTENT_MSG_REFRESH, + &msg_data); c->refresh = true; } @@ -600,14 +601,14 @@ void html_finish_conversion(html_content *htmlc) } /* convert dom tree to box tree */ - LOG("DOM to box (%p)", htmlc); + NSLOG(netsurf, INFO, "DOM to box (%p)", htmlc); content_set_status(&htmlc->base, messages_get("Processing")); msg_data.explicit_status_text = NULL; - content_broadcast(&htmlc->base, CONTENT_MSG_STATUS, msg_data); + content_broadcast(&htmlc->base, CONTENT_MSG_STATUS, &msg_data); exc = dom_document_get_document_element(htmlc->document, (void *) &html); if ((exc != DOM_NO_ERR) || (html == NULL)) { - LOG("error retrieving html element from dom"); + NSLOG(netsurf, INFO, "error retrieving html element from dom"); content_broadcast_errorcode(&htmlc->base, NSERROR_DOM); content_set_error(&htmlc->base); return; @@ -615,7 +616,7 @@ void html_finish_conversion(html_content *htmlc) error = dom_to_box(html, htmlc, html_box_convert_done); if (error != NSERROR_OK) { - LOG("box conversion failed"); + NSLOG(netsurf, INFO, "box conversion failed"); dom_node_unref(html); html_object_free_objects(htmlc); content_broadcast_errorcode(&htmlc->base, error); @@ -685,10 +686,11 @@ dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw) msg_data.jscontext = &htmlc->jscontext; content_broadcast(&htmlc->base, CONTENT_MSG_GETCTX, - msg_data); - LOG("javascript context: %p (htmlc: %p)", - htmlc->jscontext, - htmlc); + &msg_data); + NSLOG(netsurf, INFO, + "javascript context: %p (htmlc: %p)", + htmlc->jscontext, + htmlc); } if (htmlc->jscontext != NULL) { js_handle_new_element(htmlc->jscontext, @@ -767,7 +769,7 @@ dom_event_fetcher(dom_string *type, dom_default_action_phase phase, void **pw) { - //LOG("type:%s", dom_string_data(type)); + NSLOG(netsurf, DEEPDEBUG, "type:%s", dom_string_data(type)); if (phase == DOM_DEFAULT_ACTION_END) { if (dom_string_isequal(type, corestring_dom_DOMNodeInserted)) { @@ -794,22 +796,22 @@ html_document_user_data_handler(dom_node_operation operation, switch (operation) { case DOM_NODE_CLONED: - LOG("Cloned"); + NSLOG(netsurf, INFO, "Cloned"); break; case DOM_NODE_RENAMED: - LOG("Renamed"); + NSLOG(netsurf, INFO, "Renamed"); break; case DOM_NODE_IMPORTED: - LOG("imported"); + NSLOG(netsurf, INFO, "imported"); break; case DOM_NODE_ADOPTED: - LOG("Adopted"); + NSLOG(netsurf, INFO, "Adopted"); break; case DOM_NODE_DELETED: /* This is the only path I expect */ break; default: - LOG("User data operation not handled."); + NSLOG(netsurf, INFO, "User data operation not handled."); assert(0); } } @@ -934,7 +936,7 @@ html_create_html_data(html_content *c, const http_parameter *params) lwc_string_unref(c->universal); c->universal = NULL; - LOG("Unable to set user data."); + NSLOG(netsurf, INFO, "Unable to set user data."); return NSERROR_DOM; } @@ -1141,11 +1143,11 @@ static bool html_convert(struct content *c) exc = dom_document_get_quirks_mode(htmlc->document, &htmlc->quirks); if (exc == DOM_NO_ERR) { html_css_quirks_stylesheets(htmlc); - LOG("quirks set to %d", htmlc->quirks); + NSLOG(netsurf, INFO, "quirks set to %d", htmlc->quirks); } htmlc->base.active--; /* the html fetch is no longer active */ - LOG("%d fetches active (%p)", htmlc->base.active, c); + NSLOG(netsurf, INFO, "%d fetches active (%p)", htmlc->base.active, c); /* The parse cannot be completed here because it may be paused * untill all the resources being fetched have completed. @@ -1198,11 +1200,11 @@ html_begin_conversion(html_content *htmlc) * complete to avoid repeating the completion pointlessly. */ if (htmlc->parse_completed == false) { - LOG("Completing parse (%p)", htmlc); + NSLOG(netsurf, INFO, "Completing parse (%p)", htmlc); /* complete parsing */ error = dom_hubbub_parser_completed(htmlc->parser); if (error != DOM_HUBBUB_OK) { - LOG("Parsing failed"); + NSLOG(netsurf, INFO, "Parsing failed"); content_broadcast_errorcode(&htmlc->base, libdom_hubbub_error_to_nserror(error)); @@ -1213,15 +1215,15 @@ html_begin_conversion(html_content *htmlc) } if (html_can_begin_conversion(htmlc) == false) { - LOG("Can't begin conversion (%p)", htmlc); + NSLOG(netsurf, INFO, "Can't begin conversion (%p)", htmlc); /* We can't proceed (see commentary above) */ return true; } /* Give up processing if we've been aborted */ if (htmlc->aborted) { - LOG("Conversion aborted (%p) (active: %u)", htmlc, - htmlc->base.active); + NSLOG(netsurf, INFO, "Conversion aborted (%p) (active: %u)", + htmlc, htmlc->base.active); content_set_error(&htmlc->base); content_broadcast_errorcode(&htmlc->base, NSERROR_STOPPED); return false; @@ -1257,7 +1259,7 @@ html_begin_conversion(html_content *htmlc) /* locate root element and ensure it is html */ exc = dom_document_get_document_element(htmlc->document, (void *) &html); if ((exc != DOM_NO_ERR) || (html == NULL)) { - LOG("error retrieving html element from dom"); + NSLOG(netsurf, INFO, "error retrieving html element from dom"); content_broadcast_errorcode(&htmlc->base, NSERROR_DOM); return false; } @@ -1267,7 +1269,7 @@ html_begin_conversion(html_content *htmlc) (node_name == NULL) || (!dom_string_caseless_lwc_isequal(node_name, corestring_lwc_html))) { - LOG("root element not html"); + NSLOG(netsurf, INFO, "root element not html"); content_broadcast_errorcode(&htmlc->base, NSERROR_DOM); dom_node_unref(html); return false; @@ -1373,7 +1375,8 @@ static void html_stop(struct content *c) break; default: - LOG("Unexpected status %d (%p)", c->status, c); + NSLOG(netsurf, INFO, "Unexpected status %d (%p)", c->status, + c); assert(0); } } @@ -1395,6 +1398,10 @@ static void html_reformat(struct content *c, int width, int height) htmlc->reflowing = true; + htmlc->len_ctx.vw = width; + htmlc->len_ctx.vh = height; + htmlc->len_ctx.root_style = htmlc->layout->style; + layout_document(htmlc, width, height); layout = htmlc->layout; @@ -1530,7 +1537,7 @@ static void html_destroy(struct content *c) html_content *html = (html_content *) c; struct form *f, *g; - LOG("content %p", c); + NSLOG(netsurf, INFO, "content %p", c); /* Destroy forms */ for (f = html->forms; f != NULL; f = g) { @@ -1644,7 +1651,7 @@ html_open(struct content *c, html->drag_owner.no_owner = true; /* text selection */ - selection_init(&html->sel, html->layout); + selection_init(&html->sel, html->layout, &html->len_ctx); html->selection_type = HTML_SELECTION_NONE; html->selection_owner.none = true; @@ -1765,7 +1772,8 @@ html_get_contextual_content(struct content *c, int x, int y, struct box *next; int box_x = 0, box_y = 0; - while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) { + while ((next = box_at_point(&html->len_ctx, box, x, y, + &box_x, &box_y)) != NULL) { box = next; /* hidden boxes are ignored */ @@ -1842,7 +1850,8 @@ html_scroll_at_point(struct content *c, int x, int y, int scrx, int scry) /* TODO: invert order; visit deepest box first */ - while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) { + while ((next = box_at_point(&html->len_ctx, box, x, y, + &box_x, &box_y)) != NULL) { box = next; if (box->style && css_computed_visibility(box->style) == @@ -1919,7 +1928,7 @@ static void html__dom_user_data_handler(dom_node_operation operation, free(data); break; default: - LOG("User data operation not handled."); + NSLOG(netsurf, INFO, "User data operation not handled."); assert(0); } } @@ -1935,7 +1944,8 @@ static void html__set_file_gadget_filename(struct content *c, ret = guit->utf8->local_to_utf8(fn, 0, &utf8_fn); if (ret != NSERROR_OK) { assert(ret != NSERROR_BAD_ENCODING); - LOG("utf8 to local encoding conversion failed"); + NSLOG(netsurf, INFO, + "utf8 to local encoding conversion failed"); /* Load was for us - just no memory */ return; } @@ -1983,7 +1993,8 @@ static bool html_drop_file_at_point(struct content *c, int x, int y, char *file) int box_x = 0, box_y = 0; /* Scan box tree for boxes that can handle drop */ - while ((next = box_at_point(box, x, y, &box_x, &box_y)) != NULL) { + while ((next = box_at_point(&html->len_ctx, box, x, y, + &box_x, &box_y)) != NULL) { box = next; if (box->style && css_computed_visibility(box->style) == @@ -2087,7 +2098,7 @@ static bool html_drop_file_at_point(struct content *c, int x, int y, char *file) if (ret != NSERROR_OK) { /* bad encoding shouldn't happen */ assert(ret != NSERROR_BAD_ENCODING); - LOG("local to utf8 encoding failed"); + NSLOG(netsurf, INFO, "local to utf8 encoding failed"); free(buffer); guit->misc->warning("NoMemory", NULL); return true; @@ -2153,19 +2164,19 @@ html_debug_dump(struct content *c, FILE *f, enum content_debug op) ret = NSERROR_OK; } else { if (htmlc->document == NULL) { - LOG("No document to dump"); + NSLOG(netsurf, INFO, "No document to dump"); return NSERROR_DOM; } exc = dom_document_get_document_element(htmlc->document, (void *) &html); if ((exc != DOM_NO_ERR) || (html == NULL)) { - LOG("Unable to obtain root node"); + NSLOG(netsurf, INFO, "Unable to obtain root node"); return NSERROR_DOM; } ret = libdom_dump_structure(html, f, 0); - LOG("DOM structure dump returning %d", ret); + NSLOG(netsurf, INFO, "DOM structure dump returning %d", ret); dom_node_unref(html); } diff --git a/render/html_css.c b/render/html_css.c index 4d5469361..45bc16f56 100644 --- a/render/html_css.c +++ b/render/html_css.c @@ -103,17 +103,23 @@ html_convert_css_callback(hlcache_handle *css, switch (event->type) { case CONTENT_MSG_DONE: - LOG("done stylesheet slot %d '%s'", i, nsurl_access(hlcache_handle_get_url(css))); + NSLOG(netsurf, INFO, "done stylesheet slot %d '%s'", i, + nsurl_access(hlcache_handle_get_url(css))); parent->base.active--; - LOG("%d fetches active", parent->base.active); + NSLOG(netsurf, INFO, "%d fetches active", parent->base.active); break; case CONTENT_MSG_ERROR: - LOG("stylesheet %s failed: %s", nsurl_access(hlcache_handle_get_url(css)), event->data.error); + NSLOG(netsurf, INFO, "stylesheet %s failed: %s", + nsurl_access(hlcache_handle_get_url(css)), + event->data.error); + /* fall through */ + + case CONTENT_MSG_ERRORCODE: hlcache_handle_release(css); s->sheet = NULL; parent->base.active--; - LOG("%d fetches active", parent->base.active); + NSLOG(netsurf, INFO, "%d fetches active", parent->base.active); content_add_error(&parent->base, "?", 0); break; @@ -150,7 +156,7 @@ html_stylesheet_from_domnode(html_content *c, exc = dom_node_get_text_content(node, &style); if ((exc != DOM_NO_ERR) || (style == NULL)) { - LOG("No text content"); + NSLOG(netsurf, INFO, "No text content"); return NSERROR_OK; } @@ -181,7 +187,7 @@ html_stylesheet_from_domnode(html_content *c, nsurl_unref(url); c->base.active++; - LOG("%d fetches active", c->base.active); + NSLOG(netsurf, INFO, "%d fetches active", c->base.active); return NSERROR_OK; } @@ -253,13 +259,14 @@ static bool html_css_process_modified_style(html_content *c, error = html_stylesheet_from_domnode(c, s->node, &sheet); if (error != NSERROR_OK) { - LOG("Failed to update sheet"); + NSLOG(netsurf, INFO, "Failed to update sheet"); content_broadcast_errorcode(&c->base, error); return false; } if (sheet != NULL) { - LOG("Updating sheet %p with %p", s->sheet, sheet); + NSLOG(netsurf, INFO, "Updating sheet %p with %p", s->sheet, + sheet); if (s->sheet != NULL) { switch (content_get_status(s->sheet)) { @@ -268,7 +275,8 @@ static bool html_css_process_modified_style(html_content *c, default: hlcache_handle_abort(s->sheet); c->base.active--; - LOG("%d fetches active", c->base.active); + NSLOG(netsurf, INFO, "%d fetches active", + c->base.active); } hlcache_handle_release(s->sheet); } @@ -313,7 +321,9 @@ bool html_css_update_style(html_content *c, dom_node *style) s = html_create_style_element(c, style); } if (s == NULL) { - LOG("Could not find or create inline stylesheet for %p", style); + NSLOG(netsurf, INFO, + "Could not find or create inline stylesheet for %p", + style); return false; } @@ -417,7 +427,8 @@ bool html_css_process_link(html_content *htmlc, dom_node *node) } dom_string_unref(href); - LOG("linked stylesheet %i '%s'", htmlc->stylesheet_count, nsurl_access(joined)); + NSLOG(netsurf, INFO, "linked stylesheet %i '%s'", + htmlc->stylesheet_count, nsurl_access(joined)); /* extend stylesheets array to allow for new sheet */ stylesheets = realloc(htmlc->stylesheets, @@ -452,7 +463,7 @@ bool html_css_process_link(html_content *htmlc, dom_node *node) htmlc->stylesheet_count++; htmlc->base.active++; - LOG("%d fetches active", htmlc->base.active); + NSLOG(netsurf, INFO, "%d fetches active", htmlc->base.active); return true; @@ -517,7 +528,7 @@ nserror html_css_quirks_stylesheets(html_content *c) } c->base.active++; - LOG("%d fetches active", c->base.active); + NSLOG(netsurf, INFO, "%d fetches active", c->base.active); } return ns_error; @@ -561,7 +572,7 @@ nserror html_css_new_stylesheets(html_content *c) } c->base.active++; - LOG("%d fetches active", c->base.active); + NSLOG(netsurf, INFO, "%d fetches active", c->base.active); if (nsoption_bool(block_advertisements)) { @@ -575,7 +586,7 @@ nserror html_css_new_stylesheets(html_content *c) } c->base.active++; - LOG("%d fetches active", c->base.active); + NSLOG(netsurf, INFO, "%d fetches active", c->base.active); } @@ -588,7 +599,7 @@ nserror html_css_new_stylesheets(html_content *c) } c->base.active++; - LOG("%d fetches active", c->base.active); + NSLOG(netsurf, INFO, "%d fetches active", c->base.active); return ns_error; } diff --git a/render/html_css_fetcher.c b/render/html_css_fetcher.c index 9eda6aeb7..0f8809a42 100644 --- a/render/html_css_fetcher.c +++ b/render/html_css_fetcher.c @@ -61,13 +61,15 @@ static html_css_fetcher_context *ring = NULL; static bool html_css_fetcher_initialise(lwc_string *scheme) { - LOG("html_css_fetcher_initialise called for %s", lwc_string_data(scheme)); + NSLOG(netsurf, INFO, "html_css_fetcher_initialise called for %s", + lwc_string_data(scheme)); return true; } static void html_css_fetcher_finalise(lwc_string *scheme) { - LOG("html_css_fetcher_finalise called for %s", lwc_string_data(scheme)); + NSLOG(netsurf, INFO, "html_css_fetcher_finalise called for %s", + lwc_string_data(scheme)); } static bool html_css_fetcher_can_fetch(const nsurl *url) @@ -251,7 +253,8 @@ static void html_css_fetcher_poll(lwc_string *scheme) html_css_fetcher_send_callback(&msg, c); } } else { - LOG("Processing of %s failed!", nsurl_access(c->url)); + NSLOG(netsurf, INFO, "Processing of %s failed!", + nsurl_access(c->url)); /* Ensure that we're unlocked here. If we aren't, * then html_css_fetcher_process() is broken. @@ -290,7 +293,7 @@ nserror html_css_fetcher_register(void) if (lwc_intern_string("x-ns-css", SLEN("x-ns-css"), &scheme) != lwc_error_ok) { - LOG("could not intern \"x-ns-css\"."); + NSLOG(netsurf, INFO, "could not intern \"x-ns-css\"."); return NSERROR_INIT_FAILED; } diff --git a/render/html_interaction.c b/render/html_interaction.c index e727a9ffc..2d14ed2ae 100644 --- a/render/html_interaction.c +++ b/render/html_interaction.c @@ -208,7 +208,7 @@ static size_t html_selection_drag_end(struct html_content *html, if (box) { plot_font_style_t fstyle; - font_plot_style_from_css(box->style, &fstyle); + font_plot_style_from_css(&html->len_ctx, box->style, &fstyle); guit->layout->position(&fstyle, box->text, box->length, dx, &idx, &pixel_offset); @@ -289,7 +289,7 @@ html__image_coords_dom_user_data_handler(dom_node_operation operation, break; default: - LOG("User data operation not handled."); + NSLOG(netsurf, INFO, "User data operation not handled."); assert(0); } } @@ -368,7 +368,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, mouse, x - box_x, y - box_y); if (status != NULL) { msg_data.explicit_status_text = status; - content_broadcast(c, CONTENT_MSG_STATUS, msg_data); + content_broadcast(c, CONTENT_MSG_STATUS, &msg_data); } else { int width, height; form_select_get_dimensions(html->visible_select_menu, @@ -415,7 +415,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw, size_t idx; plot_font_style_t fstyle; - font_plot_style_from_css(box->style, &fstyle); + font_plot_style_from_css(&html->len_ctx, + box->style, &fstyle); guit->layout->position(&fstyle, box->text, box->length, @@ -459,7 +460,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, } msg_data.explicit_status_text = status; - content_broadcast(c, CONTENT_MSG_STATUS, msg_data); + content_broadcast(c, CONTENT_MSG_STATUS, &msg_data); return; } @@ -649,7 +650,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw, text_box = box; text_box_x = box_x; } - } while ((box = box_at_point(box, x, y, &box_x, &box_y)) != NULL); + } while ((box = box_at_point(&html->len_ctx, box, x, y, + &box_x, &box_y)) != NULL); /* use of box_x, box_y, or content below this point is probably a * mistake; they will refer to the last box returned by box_at_point */ @@ -678,7 +680,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, } else if (mouse & BROWSER_MOUSE_CLICK_1) { msg_data.select_menu.gadget = gadget; content_broadcast(c, CONTENT_MSG_SELECTMENU, - msg_data); + &msg_data); } break; case GADGET_CHECKBOX: @@ -697,6 +699,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, form_radio_set(gadget); break; case GADGET_IMAGE: + /* This falls through to SUBMIT */ if (mouse & BROWSER_MOUSE_CLICK_1) { struct image_input_coords *coords, *oldcoords; /** \todo Find a way to not ignore errors */ @@ -714,7 +717,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, return; free(oldcoords); } - /* drop through */ + /* Fall through */ case GADGET_SUBMIT: if (gadget->form) { snprintf(status_buffer, sizeof status_buffer, @@ -768,7 +771,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw, status = messages_get("FormFile"); if (mouse & BROWSER_MOUSE_CLICK_1) { msg_data.gadget_click.gadget = gadget; - content_broadcast(c, CONTENT_MSG_GADGETCLICK, msg_data); + content_broadcast(c, CONTENT_MSG_GADGETCLICK, + &msg_data); } break; case GADGET_BUTTON: @@ -782,12 +786,12 @@ void html_mouse_action(struct content *c, struct browser_window *bw, if (mouse & BROWSER_MOUSE_DRAG_2) { msg_data.dragsave.type = CONTENT_SAVE_NATIVE; msg_data.dragsave.content = object; - content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data); + content_broadcast(c, CONTENT_MSG_DRAGSAVE, &msg_data); } else if (mouse & BROWSER_MOUSE_DRAG_1) { msg_data.dragsave.type = CONTENT_SAVE_ORIG; msg_data.dragsave.content = object; - content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data); + content_broadcast(c, CONTENT_MSG_DRAGSAVE, &msg_data); } /* \todo should have a drag-saving object msg */ @@ -869,7 +873,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, mouse & BROWSER_MOUSE_MOD_1) { msg_data.savelink.url = url; msg_data.savelink.title = title; - content_broadcast(c, CONTENT_MSG_SAVELINK, msg_data); + content_broadcast(c, CONTENT_MSG_SAVELINK, &msg_data); } else if (mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2)) @@ -908,8 +912,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw, int pixel_offset; size_t idx; - font_plot_style_from_css(text_box->style, - &fstyle); + font_plot_style_from_css(&html->len_ctx, + text_box->style, &fstyle); guit->layout->position(&fstyle, text_box->text, @@ -968,7 +972,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, msg_data.dragsave.content = NULL; content_broadcast(c, CONTENT_MSG_DRAGSAVE, - msg_data); + &msg_data); } else { if (drag_candidate == NULL) { browser_window_page_drag_start( @@ -988,7 +992,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, msg_data.dragsave.content = NULL; content_broadcast(c, CONTENT_MSG_DRAGSAVE, - msg_data); + &msg_data); } else { if (drag_candidate == NULL) { browser_window_page_drag_start( @@ -1013,10 +1017,10 @@ void html_mouse_action(struct content *c, struct browser_window *bw, if (!iframe && !html_object_box) { msg_data.explicit_status_text = status; - content_broadcast(c, CONTENT_MSG_STATUS, msg_data); + content_broadcast(c, CONTENT_MSG_STATUS, &msg_data); msg_data.pointer = pointer; - content_broadcast(c, CONTENT_MSG_POINTER, msg_data); + content_broadcast(c, CONTENT_MSG_POINTER, &msg_data); } /* fire dom click event */ @@ -1217,7 +1221,7 @@ void html_overflow_scroll_callback(void *client_data, html_set_drag_type(html, drag_type, drag_owner, NULL); msg_data.pointer = BROWSER_POINTER_AUTO; - content_broadcast(data->c, CONTENT_MSG_POINTER, msg_data); + content_broadcast(data->c, CONTENT_MSG_POINTER, &msg_data); break; } } @@ -1292,7 +1296,7 @@ void html_set_drag_type(html_content *html, html_drag_type drag_type, msg_data.drag.rect = rect; /* Inform of the content's drag status change */ - content_broadcast((struct content *)html, CONTENT_MSG_DRAG, msg_data); + content_broadcast((struct content *)html, CONTENT_MSG_DRAG, &msg_data); } /* Documented in html_internal.h */ @@ -1350,7 +1354,7 @@ void html_set_focus(html_content *html, html_focus_type focus_type, } /* Inform of the content's drag status change */ - content_broadcast((struct content *)html, CONTENT_MSG_CARET, msg_data); + content_broadcast((struct content *)html, CONTENT_MSG_CARET, &msg_data); } /* Documented in html_internal.h */ @@ -1426,5 +1430,5 @@ void html_set_selection(html_content *html, html_selection_type selection_type, /* Inform of the content's selection status change */ content_broadcast((struct content *)html, CONTENT_MSG_SELECTION, - msg_data); + &msg_data); } diff --git a/render/html_internal.h b/render/html_internal.h index 2f84cf869..66ecb2b36 100644 --- a/render/html_internal.h +++ b/render/html_internal.h @@ -26,6 +26,7 @@ #include <libcss/libcss.h> +#include "content/handlers/css/utils.h" #include "content/content_protected.h" #include "desktop/selection.h" #include "render/html.h" @@ -94,6 +95,9 @@ typedef struct html_content { /** Base target */ char *base_target; + /** CSS length conversion context for document. */ + nscss_len_ctx len_ctx; + /** Content has been aborted in the LOADING state */ bool aborted; diff --git a/render/html_object.c b/render/html_object.c index e20cd6d63..74e4bf0f3 100644 --- a/render/html_object.c +++ b/render/html_object.c @@ -97,6 +97,16 @@ html_object_done(struct box *box, box->object = object; + /* Normalise the box type, now it has been replaced. */ + switch (box->type) { + case BOX_TABLE: + box->type = BOX_BLOCK; + break; + default: + /* TODO: Any other box types need mapping? */ + break; + } + if (!(box->flags & REPLACE_DIM)) { /* invalidate parent min, max widths */ for (b = box; b; b = b->parent) @@ -125,7 +135,9 @@ html_object_callback(hlcache_handle *object, struct box *box; box = o->box; - if (box == NULL && event->type != CONTENT_MSG_ERROR) { + if (box == NULL && + event->type != CONTENT_MSG_ERROR && + event->type != CONTENT_MSG_ERRORCODE) { return NSERROR_OK; } @@ -158,7 +170,7 @@ html_object_callback(hlcache_handle *object, case CONTENT_MSG_DONE: c->base.active--; - LOG("%d fetches active", c->base.active); + NSLOG(netsurf, INFO, "%d fetches active", c->base.active); html_object_done(box, object, o->background); @@ -177,10 +189,11 @@ html_object_callback(hlcache_handle *object, data.redraw.height = box->height; data.redraw.full_redraw = true; - content_broadcast(&c->base, CONTENT_MSG_REDRAW, data); + content_broadcast(&c->base, CONTENT_MSG_REDRAW, &data); } break; + case CONTENT_MSG_ERRORCODE: case CONTENT_MSG_ERROR: hlcache_handle_release(object); @@ -188,7 +201,8 @@ html_object_callback(hlcache_handle *object, if (box != NULL) { c->base.active--; - LOG("%d fetches active", c->base.active); + NSLOG(netsurf, INFO, "%d fetches active", + c->base.active); content_add_error(&c->base, "?", 0); html_object_failed(box, c, o->background); @@ -223,7 +237,8 @@ html_object_callback(hlcache_handle *object, if (hunit == CSS_UNIT_PCT) { l = (width - w) * hpos / INTTOFIX(100); } else { - l = FIXTOINT(nscss_len2px(hpos, hunit, + l = FIXTOINT(nscss_len2px(&c->len_ctx, + hpos, hunit, box->style)); } @@ -231,7 +246,8 @@ html_object_callback(hlcache_handle *object, if (vunit == CSS_UNIT_PCT) { t = (height - h) * vpos / INTTOFIX(100); } else { - t = FIXTOINT(nscss_len2px(vpos, vunit, + t = FIXTOINT(nscss_len2px(&c->len_ctx, + vpos, vunit, box->style)); } @@ -276,7 +292,7 @@ html_object_callback(hlcache_handle *object, data.redraw.object_y += y; content_broadcast(&c->base, - CONTENT_MSG_REDRAW, data); + CONTENT_MSG_REDRAW, &data); break; } else { @@ -315,7 +331,7 @@ html_object_callback(hlcache_handle *object, data.redraw.object_y += y + box->padding[TOP]; } - content_broadcast(&c->base, CONTENT_MSG_REDRAW, data); + content_broadcast(&c->base, CONTENT_MSG_REDRAW, &data); } break; @@ -354,7 +370,7 @@ html_object_callback(hlcache_handle *object, msg_data.dragsave.content = event->data.dragsave.content; - content_broadcast(&c->base, CONTENT_MSG_DRAGSAVE, msg_data); + content_broadcast(&c->base, CONTENT_MSG_DRAGSAVE, &msg_data); } break; @@ -364,7 +380,7 @@ html_object_callback(hlcache_handle *object, case CONTENT_MSG_GADGETCLICK: /* These messages are for browser window layer. * we're not interested, so pass them on. */ - content_broadcast(&c->base, event->type, event->data); + content_broadcast(&c->base, event->type, &event->data); break; case CONTENT_MSG_CARET: @@ -437,7 +453,8 @@ html_object_callback(hlcache_handle *object, c->base.active == 0 && (event->type == CONTENT_MSG_LOADING || event->type == CONTENT_MSG_DONE || - event->type == CONTENT_MSG_ERROR)) { + event->type == CONTENT_MSG_ERROR || + event->type == CONTENT_MSG_ERRORCODE)) { /* all objects have arrived */ content__reformat(&c->base, false, c->base.available_width, c->base.height); @@ -499,7 +516,8 @@ static bool html_replace_object(struct content_html_object *object, nsurl *url) /* remove existing object */ if (content_get_status(object->content) != CONTENT_STATUS_DONE) { c->base.active--; - LOG("%d fetches active", c->base.active); + NSLOG(netsurf, INFO, "%d fetches active", + c->base.active); } hlcache_handle_release(object->content); @@ -520,7 +538,7 @@ static bool html_replace_object(struct content_html_object *object, nsurl *url) for (page = c; page != NULL; page = page->page) { page->base.active++; - LOG("%d fetches active", c->base.active); + NSLOG(netsurf, INFO, "%d fetches active", c->base.active); page->base.status = CONTENT_STATUS_READY; } @@ -603,7 +621,8 @@ nserror html_object_abort_objects(html_content *htmlc) object->content = NULL; if (object->box != NULL) { htmlc->base.active--; - LOG("%d fetches active", htmlc->base.active); + NSLOG(netsurf, INFO, "%d fetches active", + htmlc->base.active); } break; @@ -641,7 +660,7 @@ nserror html_object_free_objects(html_content *html) struct content_html_object *victim = html->object_list; if (victim->content != NULL) { - LOG("object %p", victim->content); + NSLOG(netsurf, INFO, "object %p", victim->content); if (content_get_type(victim->content) == CONTENT_HTML) { guit->misc->schedule(-1, html_object_refresh, victim); @@ -703,7 +722,7 @@ bool html_fetch_object(html_content *c, nsurl *url, struct box *box, c->num_objects++; if (box != NULL) { c->base.active++; - LOG("%d fetches active", c->base.active); + NSLOG(netsurf, INFO, "%d fetches active", c->base.active); } return true; diff --git a/render/html_redraw.c b/render/html_redraw.c index 2f8730634..9a97e5ec5 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -521,12 +521,14 @@ static bool html_redraw_radio(int x, int y, int width, int height, * \param box box of input * \param scale scale for redraw * \param background_colour current background colour + * \param len_ctx Length conversion context * \param ctx current redraw context * \return true if successful, false otherwise */ static bool html_redraw_file(int x, int y, int width, int height, struct box *box, float scale, colour background_colour, + const nscss_len_ctx *len_ctx, const struct redraw_context *ctx) { int text_width; @@ -535,7 +537,7 @@ static bool html_redraw_file(int x, int y, int width, int height, plot_font_style_t fstyle; nserror res; - font_plot_style_from_css(box->style, &fstyle); + font_plot_style_from_css(len_ctx, box->style, &fstyle); fstyle.background = background_colour; if (box->gadget->value) { @@ -578,13 +580,16 @@ static bool html_redraw_file(int x, int y, int width, int height, * \param clip current clip rectangle * \param background_colour current background colour * \param background box containing background details (usually \a box) - * \param ctx current redraw context + * \param len_ctx Length conversion context + * \param ctx current redraw context * \return true if successful, false otherwise */ static bool html_redraw_background(int x, int y, struct box *box, float scale, const struct rect *clip, colour *background_colour, - struct box *background, const struct redraw_context *ctx) + struct box *background, + const nscss_len_ctx *len_ctx, + const struct redraw_context *ctx) { bool repeat_x = false; bool repeat_y = false; @@ -660,7 +665,7 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale, content_get_width(background->background)) * scale * FIXTOFLT(hpos) / 100.; } else { - x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit, + x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit, background->style)) * scale); } @@ -669,7 +674,7 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale, content_get_height(background->background)) * scale * FIXTOFLT(vpos) / 100.; } else { - y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit, + y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit, background->style)) * scale); } } @@ -802,13 +807,15 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale, * \param first true if this is the first rectangle associated with the inline * \param last true if this is the last rectangle associated with the inline * \param background_colour updated to current background colour if plotted - * \param ctx current redraw context + * \param len_ctx Length conversion context + * \param ctx current redraw context * \return true if successful, false otherwise */ static bool html_redraw_inline_background(int x, int y, struct box *box, float scale, const struct rect *clip, struct rect b, bool first, bool last, colour *background_colour, + const nscss_len_ctx *len_ctx, const struct redraw_context *ctx) { struct rect r = *clip; @@ -869,7 +876,7 @@ static bool html_redraw_inline_background(int x, int y, struct box *box, plot_content = false; } } else { - x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit, + x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit, box->style)) * scale); } @@ -878,7 +885,7 @@ static bool html_redraw_inline_background(int x, int y, struct box *box, content_get_height(box->background) * scale) * FIXTOFLT(vpos) / 100.; } else { - y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit, + y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit, box->style)) * scale); } } @@ -1120,7 +1127,7 @@ static bool html_redraw_text_box(const html_content *html, struct box *box, bool excluded = (box->object != NULL); plot_font_style_t fstyle; - font_plot_style_from_css(box->style, &fstyle); + font_plot_style_from_css(&html->len_ctx, box->style, &fstyle); fstyle.background = current_background_color; if (!text_redraw(box->text, box->length, box->byte_offset, @@ -1382,21 +1389,25 @@ bool html_redraw_box(const html_content *html, struct box *box, /* We have an absolutly positioned box with a clip rect */ if (css_rect.left_auto == false) r.x0 = x - border_left + FIXTOINT(nscss_len2px( + &html->len_ctx, css_rect.left, css_rect.lunit, box->style)); if (css_rect.top_auto == false) r.y0 = y - border_top + FIXTOINT(nscss_len2px( + &html->len_ctx, css_rect.top, css_rect.tunit, box->style)); if (css_rect.right_auto == false) r.x1 = x - border_left + FIXTOINT(nscss_len2px( + &html->len_ctx, css_rect.right, css_rect.runit, box->style)); if (css_rect.bottom_auto == false) r.y1 = y - border_top + FIXTOINT(nscss_len2px( + &html->len_ctx, css_rect.bottom, css_rect.bunit, box->style)); @@ -1486,7 +1497,8 @@ bool html_redraw_box(const html_content *html, struct box *box, if ((p.x0 < p.x1) && (p.y0 < p.y1)) { /* plot background */ if (!html_redraw_background(x, y, box, scale, &p, - ¤t_background_color, bg_box, ctx)) + ¤t_background_color, bg_box, + &html->len_ctx, ctx)) return false; /* restore previous graphics window */ if (ctx->plot->clip(ctx, &r) != NSERROR_OK) @@ -1565,7 +1577,8 @@ bool html_redraw_box(const html_content *html, struct box *box, if (!html_redraw_inline_background( x, y, box, scale, &p, b, first, false, - ¤t_background_color, ctx)) + ¤t_background_color, + &html->len_ctx, ctx)) return false; /* restore previous graphics window */ if (ctx->plot->clip(ctx, &r) != NSERROR_OK) @@ -1597,7 +1610,8 @@ bool html_redraw_box(const html_content *html, struct box *box, /* plot background and borders for last rectangle of * the inline */ if (!html_redraw_inline_background(x, ib_y, box, scale, &p, b, - first, true, ¤t_background_color, ctx)) + first, true, ¤t_background_color, + &html->len_ctx, ctx)) return false; /* restore previous graphics window */ if (ctx->plot->clip(ctx, &r) != NSERROR_OK) @@ -1768,7 +1782,6 @@ bool html_redraw_box(const html_content *html, struct box *box, obj, sizeof(obj) - 1) != NSERROR_OK) return false; } - } else if (box->iframe) { /* Offset is passed to browser window redraw unscaled */ @@ -1789,7 +1802,7 @@ bool html_redraw_box(const html_content *html, struct box *box, } else if (box->gadget && box->gadget->type == GADGET_FILE) { if (!html_redraw_file(x + padding_left, y + padding_top, width, height, box, scale, - current_background_color, ctx)) + current_background_color, &html->len_ctx, ctx)) return false; } else if (box->gadget && diff --git a/render/html_script.c b/render/html_script.c index 37b0564d7..c73a4806d 100644 --- a/render/html_script.c +++ b/render/html_script.c @@ -96,7 +96,7 @@ nserror html_script_exec(html_content *c) s->already_started = true; - } + } } } @@ -105,8 +105,8 @@ nserror html_script_exec(html_content *c) /* create new html script entry */ static struct html_script * -html_process_new_script(html_content *c, - dom_string *mimetype, +html_process_new_script(html_content *c, + dom_string *mimetype, enum html_script_type type) { struct html_script *nscript; @@ -165,18 +165,24 @@ convert_script_async_cb(hlcache_handle *script, break; case CONTENT_MSG_DONE: - LOG("script %d done '%s'", i, nsurl_access(hlcache_handle_get_url(script))); + NSLOG(netsurf, INFO, "script %d done '%s'", i, + nsurl_access(hlcache_handle_get_url(script))); parent->base.active--; - LOG("%d fetches active", parent->base.active); + NSLOG(netsurf, INFO, "%d fetches active", parent->base.active); break; case CONTENT_MSG_ERROR: - LOG("script %s failed: %s", nsurl_access(hlcache_handle_get_url(script)), event->data.error); + NSLOG(netsurf, INFO, "script %s failed: %s", + nsurl_access(hlcache_handle_get_url(script)), + event->data.error); + /* fall through */ + + case CONTENT_MSG_ERRORCODE: hlcache_handle_release(script); s->data.handle = NULL; parent->base.active--; - LOG("%d fetches active", parent->base.active); + NSLOG(netsurf, INFO, "%d fetches active", parent->base.active); content_add_error(&parent->base, "?", 0); break; @@ -218,18 +224,24 @@ convert_script_defer_cb(hlcache_handle *script, switch (event->type) { case CONTENT_MSG_DONE: - LOG("script %d done '%s'", i, nsurl_access(hlcache_handle_get_url(script))); + NSLOG(netsurf, INFO, "script %d done '%s'", i, + nsurl_access(hlcache_handle_get_url(script))); parent->base.active--; - LOG("%d fetches active", parent->base.active); + NSLOG(netsurf, INFO, "%d fetches active", parent->base.active); break; case CONTENT_MSG_ERROR: - LOG("script %s failed: %s", nsurl_access(hlcache_handle_get_url(script)), event->data.error); + NSLOG(netsurf, INFO, "script %s failed: %s", + nsurl_access(hlcache_handle_get_url(script)), + event->data.error); + /* fall through */ + + case CONTENT_MSG_ERRORCODE: hlcache_handle_release(script); s->data.handle = NULL; parent->base.active--; - LOG("%d fetches active", parent->base.active); + NSLOG(netsurf, INFO, "%d fetches active", parent->base.active); content_add_error(&parent->base, "?", 0); break; @@ -272,9 +284,10 @@ convert_script_sync_cb(hlcache_handle *script, switch (event->type) { case CONTENT_MSG_DONE: - LOG("script %d done '%s'", i, nsurl_access(hlcache_handle_get_url(script))); + NSLOG(netsurf, INFO, "script %d done '%s'", i, + nsurl_access(hlcache_handle_get_url(script))); parent->base.active--; - LOG("%d fetches active", parent->base.active); + NSLOG(netsurf, INFO, "%d fetches active", parent->base.active); s->already_started = true; @@ -291,19 +304,23 @@ convert_script_sync_cb(hlcache_handle *script, /* continue parse */ err = dom_hubbub_parser_pause(parent->parser, false); if (err != DOM_HUBBUB_OK) { - LOG("unpause returned 0x%x", err); - } + NSLOG(netsurf, INFO, "unpause returned 0x%x", err); + } break; case CONTENT_MSG_ERROR: - LOG("script %s failed: %s", nsurl_access(hlcache_handle_get_url(script)), event->data.error); + NSLOG(netsurf, INFO, "script %s failed: %s", + nsurl_access(hlcache_handle_get_url(script)), + event->data.error); + /* fall through */ + case CONTENT_MSG_ERRORCODE: hlcache_handle_release(script); s->data.handle = NULL; parent->base.active--; - LOG("%d fetches active", parent->base.active); + NSLOG(netsurf, INFO, "%d fetches active", parent->base.active); content_add_error(&parent->base, "?", 0); s->already_started = true; @@ -311,8 +328,8 @@ convert_script_sync_cb(hlcache_handle *script, /* continue parse */ err = dom_hubbub_parser_pause(parent->parser, false); if (err != DOM_HUBBUB_OK) { - LOG("unpause returned 0x%x", err); - } + NSLOG(netsurf, INFO, "unpause returned 0x%x", err); + } break; @@ -343,7 +360,6 @@ exec_src_script(html_content *c, nsurl *joined; hlcache_child_context child; struct html_script *nscript; - union content_msg_data msg_data; bool async; bool defer; enum html_script_type script_type; @@ -354,21 +370,21 @@ exec_src_script(html_content *c, /* src url */ ns_error = nsurl_join(c->base_url, dom_string_data(src), &joined); if (ns_error != NSERROR_OK) { - msg_data.error = messages_get("NoMemory"); - content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + content_broadcast_errorcode(&c->base, NSERROR_NOMEM); return DOM_HUBBUB_NOMEM; } - LOG("script %i '%s'", c->scripts_count, nsurl_access(joined)); + NSLOG(netsurf, INFO, "script %i '%s'", c->scripts_count, + nsurl_access(joined)); /* there are three ways to process the script tag at this point: * * Syncronously pause the parent parse and continue after * the script has downloaded and executed. (default) - * Async Start the script downloading and execute it when it - * becomes available. - * Defered Start the script downloading and execute it when - * the page has completed parsing, may be set along + * Async Start the script downloading and execute it when it + * becomes available. + * Defered Start the script downloading and execute it when + * the page has completed parsing, may be set along * with async where it is ignored. */ @@ -377,7 +393,7 @@ exec_src_script(html_content *c, * value or the attribute name itself are valid. However * various browsers interpret this in various ways the most * compatible approach is to be liberal and accept any - * value. Note setting the values to "false" still makes them true! + * value. Note setting the values to "false" still makes them true! */ exc = dom_element_has_attribute(node, corestring_dom_async, &async); if (exc != DOM_NO_ERR) { @@ -390,7 +406,7 @@ exec_src_script(html_content *c, script_cb = convert_script_async_cb; } else { - exc = dom_element_has_attribute(node, + exc = dom_element_has_attribute(node, corestring_dom_defer, &defer); if (exc != DOM_NO_ERR) { return DOM_HUBBUB_OK; /* dom error */ @@ -410,8 +426,7 @@ exec_src_script(html_content *c, nscript = html_process_new_script(c, mimetype, script_type); if (nscript == NULL) { nsurl_unref(joined); - msg_data.error = messages_get("NoMemory"); - content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + content_broadcast_errorcode(&c->base, NSERROR_NOMEM); return DOM_HUBBUB_NOMEM; } @@ -434,15 +449,15 @@ exec_src_script(html_content *c, if (ns_error != NSERROR_OK) { /* @todo Deal with fetch error better. currently assume - * fetch never became active + * fetch never became active */ /* mark duff script fetch as already started */ - nscript->already_started = true; - LOG("Fetch failed with error %d", ns_error); + nscript->already_started = true; + NSLOG(netsurf, INFO, "Fetch failed with error %d", ns_error); } else { /* update base content active fetch count */ - c->base.active++; - LOG("%d fetches active", c->base.active); + c->base.active++; + NSLOG(netsurf, INFO, "%d fetches active", c->base.active); switch (script_type) { case HTML_SCRIPT_SYNC: @@ -465,7 +480,6 @@ exec_src_script(html_content *c, static dom_hubbub_error exec_inline_script(html_content *c, dom_node *node, dom_string *mimetype) { - union content_msg_data msg_data; dom_string *script; dom_exception exc; /* returned by libdom functions */ struct lwc_string_s *lwcmimetype; @@ -482,8 +496,7 @@ exec_inline_script(html_content *c, dom_node *node, dom_string *mimetype) if (nscript == NULL) { dom_string_unref(script); - msg_data.error = messages_get("NoMemory"); - content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + content_broadcast_errorcode(&c->base, NSERROR_NOMEM); return DOM_HUBBUB_NOMEM; } @@ -526,15 +539,16 @@ html_process_script(void *ctx, dom_node *node) union content_msg_data msg_data; msg_data.jscontext = &c->jscontext; - content_broadcast(&c->base, CONTENT_MSG_GETCTX, msg_data); - LOG("javascript context %p ", c->jscontext); + content_broadcast(&c->base, CONTENT_MSG_GETCTX, &msg_data); + NSLOG(netsurf, INFO, "javascript context %p ", c->jscontext); if (c->jscontext == NULL) { /* no context and it could not be created, abort */ return DOM_HUBBUB_OK; } } - LOG("content %p parser %p node %p", c, c->parser, node); + NSLOG(netsurf, INFO, "content %p parser %p node %p", c, c->parser, + node); exc = dom_element_get_attribute(node, corestring_dom_type, &mimetype); if (exc != DOM_NO_ERR || mimetype == NULL) { diff --git a/render/imagemap.c b/render/imagemap.c index 6e2504bdc..0d3b42a1b 100644 --- a/render/imagemap.c +++ b/render/imagemap.c @@ -241,21 +241,35 @@ void imagemap_dump(html_content *c) map = c->imagemaps[i]; while (map != NULL) { - LOG("Imagemap: %s", map->key); + NSLOG(netsurf, INFO, "Imagemap: %s", map->key); for (entry = map->list; entry; entry = entry->next) { switch (entry->type) { case IMAGEMAP_DEFAULT: - LOG("\tDefault: %s", nsurl_access(entry->url)); + NSLOG(netsurf, INFO, "\tDefault: %s", + nsurl_access(entry->url)); break; case IMAGEMAP_RECT: - LOG("\tRectangle: %s: [(%d,%d),(%d,%d)]", nsurl_access(entry->url), entry->bounds.rect.x0, entry->bounds.rect.y0, entry->bounds.rect.x1, entry->bounds.rect.y1); + NSLOG(netsurf, INFO, + "\tRectangle: %s: [(%d,%d),(%d,%d)]", + nsurl_access(entry->url), + entry->bounds.rect.x0, + entry->bounds.rect.y0, + entry->bounds.rect.x1, + entry->bounds.rect.y1); break; case IMAGEMAP_CIRCLE: - LOG("\tCircle: %s: [(%d,%d),%d]", nsurl_access(entry->url), entry->bounds.circle.x, entry->bounds.circle.y, entry->bounds.circle.r); + NSLOG(netsurf, INFO, + "\tCircle: %s: [(%d,%d),%d]", + nsurl_access(entry->url), + entry->bounds.circle.x, + entry->bounds.circle.y, + entry->bounds.circle.r); break; case IMAGEMAP_POLY: - LOG("\tPolygon: %s:", nsurl_access(entry->url)); + NSLOG(netsurf, INFO, + "\tPolygon: %s:", + nsurl_access(entry->url)); for (j = 0; j != entry->bounds.poly.num; j++) { fprintf(stderr, "(%d,%d) ", diff --git a/render/layout.c b/render/layout.c index 6782fdfc6..f6b774a6e 100644 --- a/render/layout.c +++ b/render/layout.c @@ -47,6 +47,7 @@ #include "utils/talloc.h" #include "utils/utils.h" #include "utils/nsoption.h" +#include "netsurf/inttypes.h" #include "netsurf/content.h" #include "netsurf/browser_window.h" #include "netsurf/layout.h" @@ -62,18 +63,69 @@ #include "render/layout.h" #include "render/table.h" - -/* Define to enable layout debugging */ -#undef LAYOUT_DEBUG - #define AUTO INT_MIN /* Fixed point percentage (a) of an integer (b), to an integer */ #define FPCT_OF_INT_TOINT(a, b) (FIXTOINT(FDIV((a * b), F_100))) +typedef uint8_t (*css_len_func)( + const css_computed_style *style, + css_fixed *length, css_unit *unit); +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. */ +static const css_len_func margin_funcs[4] = { + [TOP] = css_computed_margin_top, + [RIGHT] = css_computed_margin_right, + [BOTTOM] = css_computed_margin_bottom, + [LEFT] = css_computed_margin_left, +}; + +/** Array of per-side access functions for computed style paddings. */ +static const css_len_func padding_funcs[4] = { + [TOP] = css_computed_padding_top, + [RIGHT] = css_computed_padding_right, + [BOTTOM] = css_computed_padding_bottom, + [LEFT] = css_computed_padding_left, +}; + +/** Array of per-side access functions for computed style border_widths. */ +static const css_len_func border_width_funcs[4] = { + [TOP] = css_computed_border_top_width, + [RIGHT] = css_computed_border_right_width, + [BOTTOM] = css_computed_border_bottom_width, + [LEFT] = css_computed_border_left_width, +}; + +/** Array of per-side access functions for computed style border styles. */ +static const css_border_style_func border_style_funcs[4] = { + [TOP] = css_computed_border_top_style, + [RIGHT] = css_computed_border_right_style, + [BOTTOM] = css_computed_border_bottom_style, + [LEFT] = css_computed_border_left_style, +}; + +/** Array of per-side access functions for computed style border colors. */ +static const css_border_color_func border_color_funcs[4] = { + [TOP] = css_computed_border_top_color, + [RIGHT] = css_computed_border_right_color, + [BOTTOM] = css_computed_border_bottom_color, + [LEFT] = css_computed_border_left_color, +}; + /* forward declaration to break cycles */ -static bool layout_block_context(struct box *block, int viewport_height, html_content *content); -static void layout_minmax_block(struct box *block, const struct gui_layout_table *font_func); +static bool layout_block_context( + struct box *block, + int viewport_height, + html_content *content); +static void layout_minmax_block( + struct box *block, + const struct gui_layout_table *font_func, + const html_content *content); /** @@ -182,7 +234,9 @@ layout_get_object_dimensions(struct box *box, * \param width width of containing block * \return length of indent */ -static int layout_text_indent(const css_computed_style *style, int width) +static int layout_text_indent( + const nscss_len_ctx *len_ctx, + const css_computed_style *style, int width) { css_fixed value = 0; css_unit unit = CSS_UNIT_PX; @@ -192,7 +246,7 @@ static int layout_text_indent(const css_computed_style *style, int width) if (unit == CSS_UNIT_PCT) { return FPCT_OF_INT_TOINT(value, width); } else { - return FIXTOINT(nscss_len2px(value, unit, style)); + return FIXTOINT(nscss_len2px(len_ctx, value, unit, style)); } } @@ -200,6 +254,7 @@ static int layout_text_indent(const css_computed_style *style, int width) /** * Determine width of margin, borders, and padding on one side of a box. * + * \param 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 @@ -209,7 +264,8 @@ static int layout_text_indent(const css_computed_style *style, int width) * \param frac increased by sum of fractional margin and padding */ static void -calculate_mbp_width(const css_computed_style *style, +calculate_mbp_width(const nscss_len_ctx *len_ctx, + const css_computed_style *style, unsigned int side, bool margin, bool border, @@ -217,35 +273,6 @@ calculate_mbp_width(const css_computed_style *style, int *fixed, float *frac) { - typedef uint8_t (*len_func)(const css_computed_style *style, - css_fixed *length, css_unit *unit); - - static len_func margin_funcs[4] = { - css_computed_margin_top, - css_computed_margin_right, - css_computed_margin_bottom, - css_computed_margin_left - }; - static len_func padding_funcs[4] = { - css_computed_padding_top, - css_computed_padding_right, - css_computed_padding_bottom, - css_computed_padding_left - }; - static struct { - len_func width; - uint8_t (*style)(const css_computed_style *style); - } border_funcs[4] = { - { css_computed_border_top_width, - css_computed_border_top_style }, - { css_computed_border_right_width, - css_computed_border_right_style }, - { css_computed_border_bottom_width, - css_computed_border_bottom_style }, - { css_computed_border_left_width, - css_computed_border_left_style } - }; - css_fixed value = 0; css_unit unit = CSS_UNIT_PX; @@ -260,19 +287,20 @@ calculate_mbp_width(const css_computed_style *style, if (unit == CSS_UNIT_PCT) { *frac += FIXTOINT(FDIV(value, F_100)); } else { - *fixed += FIXTOINT(nscss_len2px(value, unit, - style)); + *fixed += FIXTOINT(nscss_len2px(len_ctx, + value, unit, style)); } } } /* border */ if (border) { - if (border_funcs[side].style(style) != + if (border_style_funcs[side](style) != CSS_BORDER_STYLE_NONE) { - border_funcs[side].width(style, &value, &unit); + border_width_funcs[side](style, &value, &unit); - *fixed += FIXTOINT(nscss_len2px(value, unit, style)); + *fixed += FIXTOINT(nscss_len2px(len_ctx, + value, unit, style)); } } @@ -282,9 +310,197 @@ calculate_mbp_width(const css_computed_style *style, if (unit == CSS_UNIT_PCT) { *frac += FIXTOINT(FDIV(value, F_100)); } else { - *fixed += FIXTOINT(nscss_len2px(value, unit, style)); + *fixed += FIXTOINT(nscss_len2px(len_ctx, + value, unit, style)); + } + } +} + + +/** + * Calculate minimum and maximum width of a table. + * + * \param table box of type TABLE + * \param font_func Font functions + * \param content The HTML content we are laying out. + * \post table->min_width and table->max_width filled in, + * 0 <= table->min_width <= table->max_width + */ +static void layout_minmax_table(struct box *table, + const struct gui_layout_table *font_func, + const html_content *content) +{ + unsigned int i, j; + int border_spacing_h = 0; + int table_min = 0, table_max = 0; + int extra_fixed = 0; + float extra_frac = 0; + struct column *col; + struct box *row_group, *row, *cell; + enum css_width_e wtype; + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + + /* check if the widths have already been calculated */ + if (table->max_width != UNKNOWN_MAX_WIDTH) + return; + + if (table_calculate_column_types(&content->len_ctx, table) == false) { + NSLOG(netsurf, WARNING, + "Could not establish table column types."); + return; + } + col = table->col; + + /* start with 0 except for fixed-width columns */ + for (i = 0; i != table->columns; i++) { + if (col[i].type == COLUMN_WIDTH_FIXED) + col[i].min = col[i].max = col[i].width; + else + col[i].min = col[i].max = 0; + } + + /* border-spacing is used in the separated borders model */ + if (css_computed_border_collapse(table->style) == + CSS_BORDER_COLLAPSE_SEPARATE) { + css_fixed h = 0, v = 0; + css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX; + + css_computed_border_spacing(table->style, &h, &hu, &v, &vu); + + border_spacing_h = FIXTOINT(nscss_len2px(&content->len_ctx, + h, hu, table->style)); + } + + /* 1st pass: consider 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) { + assert(cell->type == BOX_TABLE_CELL); + assert(cell->style); + /** TODO: Handle colspan="0" correctly. + * It's currently converted to 1 in box normaisation */ + assert(cell->columns != 0); + + if (cell->columns != 1) + continue; + + layout_minmax_block(cell, font_func, content); + i = cell->start_column; + + if (col[i].positioned) + continue; + + /* update column min, max widths using cell widths */ + if (col[i].min < cell->min_width) + col[i].min = cell->min_width; + if (col[i].max < cell->max_width) + col[i].max = cell->max_width; + } + + /* 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 flexible_columns = 0; + int min = 0, max = 0, fixed_width = 0, extra; + + if (cell->columns == 1) + continue; + + layout_minmax_block(cell, font_func, content); + i = cell->start_column; + + /* find min width so far of spanned columns, and count + * number of non-fixed spanned columns and total fixed width */ + for (j = 0; j != cell->columns; j++) { + min += col[i + j].min; + if (col[i + j].type == COLUMN_WIDTH_FIXED) + fixed_width += col[i + j].width; + else + flexible_columns++; } + min += (cell->columns - 1) * border_spacing_h; + + /* distribute extra min to spanned columns */ + if (min < cell->min_width) { + if (flexible_columns == 0) { + extra = 1 + (cell->min_width - min) / + cell->columns; + for (j = 0; j != cell->columns; j++) { + col[i + j].min += extra; + if (col[i + j].max < col[i + j].min) + col[i + j].max = col[i + j].min; + } + } else { + extra = 1 + (cell->min_width - min) / + flexible_columns; + for (j = 0; j != cell->columns; j++) { + if (col[i + j].type != + COLUMN_WIDTH_FIXED) { + col[i + j].min += extra; + if (col[i + j].max < + col[i + j].min) + col[i + j].max = + col[i + j].min; + } + } + } + } + + /* find max width so far of spanned columns */ + for (j = 0; j != cell->columns; j++) + max += col[i + j].max; + max += (cell->columns - 1) * border_spacing_h; + + /* distribute extra max to spanned columns */ + if (max < cell->max_width && flexible_columns) { + extra = 1 + (cell->max_width - max) / flexible_columns; + for (j = 0; j != cell->columns; j++) + if (col[i + j].type != COLUMN_WIDTH_FIXED) + col[i + j].max += extra; + } + } + + for (i = 0; i != table->columns; i++) { + if (col[i].max < col[i].min) { + box_dump(stderr, table, 0, true); + assert(0); + } + table_min += col[i].min; + table_max += col[i].max; + } + + /* fixed width takes priority, unless it is too narrow */ + wtype = css_computed_width(table->style, &value, &unit); + if (wtype == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) { + int width = FIXTOINT(nscss_len2px(&content->len_ctx, + value, unit, table->style)); + if (table_min < width) + table_min = width; + if (table_max < width) + table_max = width; } + + /* add margins, border, padding to min, max widths */ + calculate_mbp_width(&content->len_ctx, + table->style, LEFT, true, true, true, + &extra_fixed, &extra_frac); + calculate_mbp_width(&content->len_ctx, + table->style, RIGHT, true, true, true, + &extra_fixed, &extra_frac); + if (extra_fixed < 0) + extra_fixed = 0; + if (extra_frac < 0) + extra_frac = 0; + if (1.0 <= extra_frac) + extra_frac = 0.9; + table->min_width = (table_min + extra_fixed) / (1.0 - extra_frac); + table->max_width = (table_max + extra_fixed) / (1.0 - extra_frac); + table->min_width += (table->columns + 1) * border_spacing_h; + table->max_width += (table->columns + 1) * border_spacing_h; + + assert(0 <= table->min_width && table->min_width <= table->max_width); } @@ -306,7 +522,8 @@ layout_minmax_line(struct box *first, int *line_max, bool first_line, bool *line_has_height, - const struct gui_layout_table *font_func) + const struct gui_layout_table *font_func, + const html_content *content) { int min = 0, max = 0, width, height, fixed; float frac; @@ -342,9 +559,7 @@ layout_minmax_line(struct box *first, b->type == BOX_BR || b->type == BOX_TEXT || b->type == BOX_INLINE_END); -#ifdef LAYOUT_DEBUG - LOG("%p: min %i, max %i", b, min, max); -#endif + NSLOG(layout, DEBUG, "%p: min %i, max %i", b, min, max); if (b->type == BOX_BR) { b = b->next; @@ -354,9 +569,11 @@ layout_minmax_line(struct box *first, if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT) { assert(b->children); if (b->children->type == BOX_BLOCK) - layout_minmax_block(b->children, font_func); + layout_minmax_block(b->children, font_func, + content); else - layout_minmax_table(b->children, font_func); + layout_minmax_table(b->children, font_func, + content); b->min_width = b->children->min_width; b->max_width = b->children->max_width; if (min < b->min_width) @@ -366,7 +583,7 @@ layout_minmax_line(struct box *first, } if (b->type == BOX_INLINE_BLOCK) { - layout_minmax_block(b, font_func); + layout_minmax_block(b, font_func, content); if (min < b->min_width) min = b->min_width; max += b->max_width; @@ -377,16 +594,18 @@ layout_minmax_line(struct box *first, } assert(b->style); - font_plot_style_from_css(b->style, &fstyle); + font_plot_style_from_css(&content->len_ctx, b->style, &fstyle); if (b->type == BOX_INLINE && !b->object && !(b->flags & REPLACE_DIM) && !(b->flags & IFRAME)) { fixed = frac = 0; - calculate_mbp_width(b->style, LEFT, true, true, true, + calculate_mbp_width(&content->len_ctx, + b->style, LEFT, true, true, true, &fixed, &frac); if (!b->inline_end) - calculate_mbp_width(b->style, RIGHT, + calculate_mbp_width(&content->len_ctx, + b->style, RIGHT, true, true, true, &fixed, &frac); if (0 < fixed) @@ -395,7 +614,8 @@ layout_minmax_line(struct box *first, /* \todo update min width, consider fractional extra */ } else if (b->type == BOX_INLINE_END) { fixed = frac = 0; - calculate_mbp_width(b->inline_end->style, RIGHT, + calculate_mbp_width(&content->len_ctx, + b->inline_end->style, RIGHT, true, true, true, &fixed, &frac); if (0 < fixed) @@ -516,15 +736,17 @@ layout_minmax_line(struct box *first, width = AUTO; } else { - width = FIXTOINT(nscss_len2px(value, unit, - b->style)); + width = FIXTOINT(nscss_len2px(&content->len_ctx, + value, unit, b->style)); if (bs == CSS_BOX_SIZING_BORDER_BOX) { fixed = frac = 0; - calculate_mbp_width(block->style, LEFT, + calculate_mbp_width(&content->len_ctx, + block->style, LEFT, false, true, true, &fixed, &frac); - calculate_mbp_width(block->style, RIGHT, + calculate_mbp_width(&content->len_ctx, + block->style, RIGHT, false, true, true, &fixed, &frac); if (width < fixed) { @@ -541,7 +763,8 @@ layout_minmax_line(struct box *first, /* height */ htype = css_computed_height(b->style, &value, &unit); if (htype == CSS_HEIGHT_SET) { - height = FIXTOINT(nscss_len2px(value, unit, b->style)); + height = FIXTOINT(nscss_len2px(&content->len_ctx, + value, unit, b->style)); } else { height = AUTO; } @@ -557,17 +780,21 @@ layout_minmax_line(struct box *first, fixed = frac = 0; if (bs == CSS_BOX_SIZING_BORDER_BOX) { - calculate_mbp_width(b->style, LEFT, + calculate_mbp_width(&content->len_ctx, + b->style, LEFT, true, false, false, &fixed, &frac); - calculate_mbp_width(b->style, RIGHT, + calculate_mbp_width(&content->len_ctx, + b->style, RIGHT, true, false, false, &fixed, &frac); } else { - calculate_mbp_width(b->style, LEFT, + calculate_mbp_width(&content->len_ctx, + b->style, LEFT, true, true, true, &fixed, &frac); - calculate_mbp_width(b->style, RIGHT, + calculate_mbp_width(&content->len_ctx, + b->style, RIGHT, true, true, true, &fixed, &frac); } @@ -580,17 +807,21 @@ layout_minmax_line(struct box *first, fixed = frac = 0; if (bs == CSS_BOX_SIZING_BORDER_BOX) { - calculate_mbp_width(b->style, LEFT, + calculate_mbp_width(&content->len_ctx, + b->style, LEFT, true, false, false, &fixed, &frac); - calculate_mbp_width(b->style, RIGHT, + calculate_mbp_width(&content->len_ctx, + b->style, RIGHT, true, false, false, &fixed, &frac); } else { - calculate_mbp_width(b->style, LEFT, + calculate_mbp_width(&content->len_ctx, + b->style, LEFT, true, true, true, &fixed, &frac); - calculate_mbp_width(b->style, RIGHT, + calculate_mbp_width(&content->len_ctx, + b->style, RIGHT, true, true, true, &fixed, &frac); } @@ -601,8 +832,10 @@ layout_minmax_line(struct box *first, } else { /* form control with no object */ if (width == AUTO) - width = FIXTOINT(nscss_len2px(INTTOFIX(1), - CSS_UNIT_EM, b->style)); + width = FIXTOINT(nscss_len2px( + &content->len_ctx, + INTTOFIX(1), CSS_UNIT_EM, + b->style)); } if (min < width) @@ -615,7 +848,7 @@ layout_minmax_line(struct box *first, if (first_line) { /* todo: handle percentage values properly */ /* todo: handle text-indent interaction with floats */ - int text_indent = layout_text_indent( + int text_indent = layout_text_indent(&content->len_ctx, first->parent->parent->style, 100); min = (min + text_indent < 0) ? 0 : min + text_indent; max = (max + text_indent < 0) ? 0 : max + text_indent; @@ -624,9 +857,7 @@ layout_minmax_line(struct box *first, *line_min = min; *line_max = max; -#ifdef LAYOUT_DEBUG - LOG("line_min %i, line_max %i", min, max); -#endif + NSLOG(layout, DEBUG, "line_min %i, line_max %i", min, max); assert(b != first); assert(0 <= *line_min); @@ -647,7 +878,8 @@ layout_minmax_line(struct box *first, static void layout_minmax_inline_container(struct box *inline_container, bool *has_height, - const struct gui_layout_table *font_func) + const struct gui_layout_table *font_func, + const html_content *content) { struct box *child; int line_min = 0, line_max = 0; @@ -665,7 +897,8 @@ layout_minmax_inline_container(struct box *inline_container, for (child = inline_container->children; child; ) { child = layout_minmax_line(child, &line_min, &line_max, - first_line, &line_has_height, font_func); + first_line, &line_has_height, font_func, + content); if (min < line_min) min = line_min; if (max < line_max) @@ -688,11 +921,14 @@ layout_minmax_inline_container(struct box *inline_container, * * \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL * \param font_func font functions + * \param content The HTML content being layed out. * \post block->min_width and block->max_width filled in, * 0 <= block->min_width <= block->max_width */ -static void -layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) +static void layout_minmax_block( + struct box *block, + const struct gui_layout_table *font_func, + const html_content *content) { struct box *child; int min = 0, max = 0; @@ -745,7 +981,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) css_fixed size = INTTOFIX(10); css_unit unit = CSS_UNIT_EM; - min = max = FIXTOINT(nscss_len2px(size, unit, block->style)); + min = max = FIXTOINT(nscss_len2px(&content->len_ctx, + size, unit, block->style)); block->flags |= HAS_HEIGHT; } @@ -758,7 +995,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) /* form checkbox or radio button * if width is AUTO, set it to 1em */ - min = max = FIXTOINT(nscss_len2px(size, unit, block->style)); + min = max = FIXTOINT(nscss_len2px(&content->len_ctx, + size, unit, block->style)); block->flags |= HAS_HEIGHT; } @@ -766,7 +1004,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) if (block->object) { if (content_get_type(block->object) == CONTENT_HTML) { layout_minmax_block(html_get_box_tree(block->object), - font_func); + font_func, content); min = html_get_box_tree(block->object)->min_width; max = html_get_box_tree(block->object)->max_width; } else { @@ -783,7 +1021,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) for (child = block->children; child; child = child->next) { switch (child->type) { case BOX_BLOCK: - layout_minmax_block(child, font_func); + layout_minmax_block(child, font_func, + content); if (child->flags & HAS_HEIGHT) child_has_height = true; break; @@ -792,7 +1031,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) child->flags |= NEED_MIN; layout_minmax_inline_container(child, - &child_has_height, font_func); + &child_has_height, font_func, + content); if (child_has_height && child == child->parent->children) { @@ -800,7 +1040,8 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) } break; case BOX_TABLE: - layout_minmax_table(child, font_func); + layout_minmax_table(child, font_func, + content); /* todo: fix for zero height tables */ child_has_height = true; child->flags |= MAKE_HEIGHT; @@ -838,14 +1079,17 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) /* fixed width takes priority */ if (block->type != BOX_TABLE_CELL && wtype == CSS_WIDTH_SET && wunit != CSS_UNIT_PCT) { - min = max = FIXTOINT(nscss_len2px(width, wunit, block->style)); + min = max = FIXTOINT(nscss_len2px(&content->len_ctx, + width, wunit, block->style)); if (bs == CSS_BOX_SIZING_BORDER_BOX) { int border_box_fixed = 0; float border_box_frac = 0; - calculate_mbp_width(block->style, LEFT, + calculate_mbp_width(&content->len_ctx, + block->style, LEFT, false, true, true, &border_box_fixed, &border_box_frac); - calculate_mbp_width(block->style, RIGHT, + calculate_mbp_width(&content->len_ctx, + block->style, RIGHT, false, true, true, &border_box_fixed, &border_box_frac); if (min < border_box_fixed) { @@ -865,14 +1109,18 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) * and paddings are wrong. */ if (bs == CSS_BOX_SIZING_BORDER_BOX && wtype == CSS_WIDTH_SET) { /* Border and padding included in width, so just get margin */ - calculate_mbp_width(block->style, LEFT, true, false, false, + calculate_mbp_width(&content->len_ctx, + block->style, LEFT, true, false, false, &extra_fixed, &extra_frac); - calculate_mbp_width(block->style, RIGHT, true, false, false, + calculate_mbp_width(&content->len_ctx, + block->style, RIGHT, true, false, false, &extra_fixed, &extra_frac); } else { - calculate_mbp_width(block->style, LEFT, true, true, true, + calculate_mbp_width(&content->len_ctx, + block->style, LEFT, true, true, true, &extra_fixed, &extra_frac); - calculate_mbp_width(block->style, RIGHT, true, true, true, + calculate_mbp_width(&content->len_ctx, + block->style, RIGHT, true, true, true, &extra_fixed, &extra_frac); } if (extra_fixed < 0) @@ -902,6 +1150,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) * * This turns the specified dimension into a content-box dimension. * + * \param 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, @@ -911,6 +1160,7 @@ layout_minmax_block(struct box *block, const struct gui_layout_table *font_func) * gadget properties. */ static void layout_handle_box_sizing( + const nscss_len_ctx *len_ctx, struct box *box, int available_width, bool setwidth, @@ -927,9 +1177,11 @@ static void layout_handle_box_sizing( int fixed = 0; float frac = 0; - calculate_mbp_width(box->style, setwidth ? LEFT : TOP, + calculate_mbp_width(len_ctx, box->style, + setwidth ? LEFT : TOP, false, true, true, &fixed, &frac); - calculate_mbp_width(box->style, setwidth ? RIGHT : BOTTOM, + calculate_mbp_width(len_ctx, box->style, + setwidth ? RIGHT : BOTTOM, false, true, true, &fixed, &frac); orig -= frac * available_width + fixed; *dimension = orig > 0 ? orig : 0; @@ -940,6 +1192,7 @@ static void layout_handle_box_sizing( /** * Calculate width, height, and thickness of margins, paddings, and borders. * + * \param 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 @@ -956,7 +1209,8 @@ static void layout_handle_box_sizing( * \param border filled with border widths, may be NULL */ static void -layout_find_dimensions(int available_width, +layout_find_dimensions(const nscss_len_ctx *len_ctx, + int available_width, int viewport_height, struct box *box, const css_computed_style *style, @@ -985,15 +1239,15 @@ layout_find_dimensions(int available_width, *width = FPCT_OF_INT_TOINT( value, available_width); } else { - *width = FIXTOINT(nscss_len2px(value, unit, - style)); + *width = FIXTOINT(nscss_len2px(len_ctx, + value, unit, style)); } } else { *width = AUTO; } if (*width != AUTO) { - layout_handle_box_sizing(box, available_width, + layout_handle_box_sizing(len_ctx, box, available_width, true, width); } } @@ -1073,15 +1327,15 @@ layout_find_dimensions(int available_width, *height = AUTO; } } else { - *height = FIXTOINT(nscss_len2px(value, unit, - style)); + *height = FIXTOINT(nscss_len2px(len_ctx, + value, unit, style)); } } else { *height = AUTO; } if (*height != AUTO) { - layout_handle_box_sizing(box, available_width, + layout_handle_box_sizing(len_ctx, box, available_width, false, height); } } @@ -1098,8 +1352,8 @@ layout_find_dimensions(int available_width, *max_width = FPCT_OF_INT_TOINT(value, available_width); } else { - *max_width = FIXTOINT(nscss_len2px(value, unit, - style)); + *max_width = FIXTOINT(nscss_len2px(len_ctx, + value, unit, style)); } } else { /* Inadmissible */ @@ -1107,7 +1361,7 @@ layout_find_dimensions(int available_width, } if (*max_width != -1) { - layout_handle_box_sizing(box, available_width, + layout_handle_box_sizing(len_ctx, box, available_width, true, max_width); } } @@ -1117,15 +1371,15 @@ layout_find_dimensions(int available_width, css_fixed value = 0; css_unit unit = CSS_UNIT_PX; - type = css_computed_min_width(style, &value, &unit); + 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(nscss_len2px(value, unit, - style)); + *min_width = FIXTOINT(nscss_len2px(len_ctx, + value, unit, style)); } } else { /* Inadmissible */ @@ -1133,7 +1387,7 @@ layout_find_dimensions(int available_width, } if (*min_width != 0) { - layout_handle_box_sizing(box, available_width, + layout_handle_box_sizing(len_ctx, box, available_width, true, min_width); } } @@ -1150,8 +1404,8 @@ layout_find_dimensions(int available_width, /* TODO: handle percentage */ *max_height = -1; } else { - *max_height = FIXTOINT(nscss_len2px(value, unit, - style)); + *max_height = FIXTOINT(nscss_len2px(len_ctx, + value, unit, style)); } } else { /* Inadmissible */ @@ -1164,15 +1418,15 @@ layout_find_dimensions(int available_width, css_fixed value = 0; css_unit unit = CSS_UNIT_PX; - type = css_computed_min_height(style, &value, &unit); + 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(nscss_len2px(value, unit, - style)); + *min_height = FIXTOINT(nscss_len2px(len_ctx, + value, unit, style)); } } else { /* Inadmissible */ @@ -1186,32 +1440,16 @@ layout_find_dimensions(int available_width, css_fixed value = 0; css_unit unit = CSS_UNIT_PX; - switch (i) { - case TOP: - type = css_computed_margin_top(style, - &value, &unit); - break; - case RIGHT: - type = css_computed_margin_right(style, - &value, &unit); - break; - case BOTTOM: - type = css_computed_margin_bottom(style, - &value, &unit); - break; - case LEFT: - type = css_computed_margin_left(style, - &value, &unit); - break; - } + 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(nscss_len2px(value, - unit, style)); + margin[i] = FIXTOINT(nscss_len2px( + len_ctx, + value, unit, style)); } } else { margin[i] = AUTO; @@ -1222,29 +1460,14 @@ layout_find_dimensions(int available_width, css_fixed value = 0; css_unit unit = CSS_UNIT_PX; - switch (i) { - case TOP: - css_computed_padding_top(style, &value, &unit); - break; - case RIGHT: - css_computed_padding_right(style, &value, - &unit); - break; - case BOTTOM: - css_computed_padding_bottom(style, &value, - &unit); - break; - case LEFT: - css_computed_padding_left(style, &value, &unit); - break; - } + padding_funcs[i](style, &value, &unit); if (unit == CSS_UNIT_PCT) { padding[i] = FPCT_OF_INT_TOINT(value, available_width); } else { - padding[i] = FIXTOINT(nscss_len2px(value, unit, - style)); + padding[i] = FIXTOINT(nscss_len2px(len_ctx, + value, unit, style)); } } @@ -1255,33 +1478,9 @@ layout_find_dimensions(int available_width, css_fixed value = 0; css_unit unit = CSS_UNIT_PX; - switch (i) { - case TOP: - css_computed_border_top_width(style, &value, - &unit); - bstyle = css_computed_border_top_style(style); - css_computed_border_top_color(style, &color); - break; - case RIGHT: - css_computed_border_right_width(style, &value, - &unit); - bstyle = css_computed_border_right_style(style); - css_computed_border_right_color(style, &color); - break; - case BOTTOM: - css_computed_border_bottom_width(style, &value, - &unit); - bstyle = css_computed_border_bottom_style( - style); - css_computed_border_bottom_color(style, &color); - break; - case LEFT: - css_computed_border_left_width(style, &value, - &unit); - bstyle = css_computed_border_left_style(style); - css_computed_border_left_color(style, &color); - break; - } + 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; @@ -1291,8 +1490,8 @@ layout_find_dimensions(int available_width, /* spec unclear: following Mozilla */ border[i].width = 0; else - border[i].width = FIXTOINT(nscss_len2px(value, - unit, style)); + border[i].width = FIXTOINT(nscss_len2px(len_ctx, + value, unit, style)); /* Special case for border-collapse: make all borders * on table/table-row-group/table-row zero width. */ @@ -1310,6 +1509,7 @@ layout_find_dimensions(int available_width, /** * Find next block that current margin collapses to. * + * \param len_ctx Length conversion context * \param box box to start tree-order search from (top margin is included) * \param block box responsible for current block fromatting context * \param viewport_height height of viewport in px @@ -1318,7 +1518,8 @@ layout_find_dimensions(int available_width, * \return next box that current margin collapses to, or NULL if none. */ static struct box* -layout_next_margin_block(struct box *box, +layout_next_margin_block(const nscss_len_ctx *len_ctx, + struct box *box, struct box *block, int viewport_height, int *max_pos_margin, @@ -1337,7 +1538,8 @@ layout_next_margin_block(struct box *box, /* Get margins */ if (box->style) { - layout_find_dimensions(box->parent->width, + layout_find_dimensions(len_ctx, + box->parent->width, viewport_height, box, box->style, NULL, NULL, NULL, NULL, @@ -1411,7 +1613,8 @@ layout_next_margin_block(struct box *box, /* Get margins */ if (box->style) { - layout_find_dimensions(box->parent->width, + layout_find_dimensions(len_ctx, + box->parent->width, viewport_height, box, box->style, NULL, NULL, NULL, NULL, @@ -1469,9 +1672,7 @@ find_sides(struct box *fl, { int fy0, fy1, fx0, fx1; -#ifdef LAYOUT_DEBUG - LOG("y0 %i, y1 %i, x0 %i, x1 %i", y0, y1, *x0, *x1); -#endif + NSLOG(layout, DEBUG, "y0 %i, y1 %i, x0 %i, x1 %i", y0, y1, *x0, *x1); *left = *right = 0; for (; fl; fl = fl->next_float) { @@ -1500,9 +1701,8 @@ find_sides(struct box *fl, } } -#ifdef LAYOUT_DEBUG - LOG("x0 %i, x1 %i, left %p, right %p", *x0, *x1, *left, *right); -#endif + NSLOG(layout, DEBUG, "x0 %i, x1 %i, left %p, right %p", *x0, *x1, + *left, *right); } @@ -1650,6 +1850,7 @@ layout_solve_width(struct box *box, * Compute dimensions of box, margins, paddings, and borders for a block-level * element. * + * \param len_ctx Length conversion context * \param available_width Max width available in pixels * \param viewport_height Height of viewport in pixels or -ve if unknown * \param lm min left margin required to avoid floats in px. @@ -1662,7 +1863,8 @@ layout_solve_width(struct box *box, * See CSS 2.1 10.3.3, 10.3.4, 10.6.2, and 10.6.3. */ static void -layout_block_find_dimensions(int available_width, +layout_block_find_dimensions(const nscss_len_ctx *len_ctx, + int available_width, int viewport_height, int lm, int rm, @@ -1675,8 +1877,8 @@ layout_block_find_dimensions(int available_width, struct box_border *border = box->border; const css_computed_style *style = box->style; - layout_find_dimensions(available_width, viewport_height, box, style, - &width, &height, &max_width, &min_width, + layout_find_dimensions(len_ctx, available_width, viewport_height, box, + style, &width, &height, &max_width, &min_width, &max_height, &min_height, margin, padding, border); if (box->object && !(box->flags & REPLACE_DIM) && @@ -1829,8 +2031,9 @@ static bool layout_table(struct box *table, int available_width, memcpy(col, table->col, sizeof(col[0]) * columns); /* find margins, paddings, and borders for table and cells */ - layout_find_dimensions(available_width, -1, table, style, 0, 0, 0, 0, - 0, 0, table->margin, table->padding, table->border); + layout_find_dimensions(&content->len_ctx, available_width, -1, table, + style, 0, 0, 0, 0, 0, 0, table->margin, table->padding, + table->border); for (row_group = table->children; row_group; row_group = row_group->next) { for (row = row_group->children; row; row = row->next) { @@ -1839,9 +2042,11 @@ static bool layout_table(struct box *table, int available_width, enum css_overflow_e overflow_y; assert(c->style); - table_used_border_for_cell(c); - layout_find_dimensions(available_width, -1, - c, c->style, 0, 0, 0, 0, 0, 0, + table_used_border_for_cell( + &content->len_ctx, c); + layout_find_dimensions(&content->len_ctx, + available_width, -1, c, + c->style, 0, 0, 0, 0, 0, 0, 0, c->padding, c->border); overflow_x = css_computed_overflow_x(c->style); @@ -1869,8 +2074,10 @@ static bool layout_table(struct box *table, int available_width, css_computed_border_spacing(style, &h, &hu, &v, &vu); - border_spacing_h = FIXTOINT(nscss_len2px(h, hu, style)); - border_spacing_v = FIXTOINT(nscss_len2px(v, vu, style)); + border_spacing_h = FIXTOINT(nscss_len2px(&content->len_ctx, + h, hu, style)); + border_spacing_v = FIXTOINT(nscss_len2px(&content->len_ctx, + v, vu, style)); } /* find specified table width, or available width if auto-width */ @@ -1880,7 +2087,8 @@ static bool layout_table(struct box *table, int available_width, table_width = FPCT_OF_INT_TOINT(value, available_width); } else { table_width = - FIXTOINT(nscss_len2px(value, unit, style)); + FIXTOINT(nscss_len2px(&content->len_ctx, + value, unit, style)); } /* specified width includes border */ @@ -1958,21 +2166,29 @@ static bool layout_table(struct box *table, int available_width, } else { /* This is the minimum height for the table * (see 17.5.3) */ - min_height = FIXTOINT(nscss_len2px(value, unit, style)); + min_height = FIXTOINT(nscss_len2px(&content->len_ctx, + value, unit, style)); } } /* calculate width required by cells */ for (i = 0; i != columns; i++) { -#ifdef LAYOUT_DEBUG - LOG("table %p, column %u: type %s, width %i, min %i, max %i", table, i, ((const char *[]){ - "UNKNOWN", - "FIXED", - "AUTO", - "PERCENT", - "RELATIVE" - })[col[i].type], col[i].width, col[i].min, col[i].max); -#endif + + NSLOG(layout, DEBUG, + "table %p, column %u: type %s, width %i, min %i, max %i", + table, + i, + ((const char *[]){ + "UNKNOWN", + "FIXED", + "AUTO", + "PERCENT", + "RELATIVE", + })[col[i].type], + col[i].width, + col[i].min, + col[i].max); + if (col[i].positioned) { positioned_columns++; @@ -1990,16 +2206,14 @@ static bool layout_table(struct box *table, int available_width, } else required_width += col[i].min; -#ifdef LAYOUT_DEBUG - LOG("required_width %i", required_width); -#endif + NSLOG(layout, DEBUG, "required_width %i", required_width); } required_width += (columns + 1 - positioned_columns) * border_spacing_h; -#ifdef LAYOUT_DEBUG - LOG("width %i, min %i, max %i, auto %i, required %i", table_width, table->min_width, table->max_width, auto_width, required_width); -#endif + NSLOG(layout, DEBUG, + "width %i, min %i, max %i, auto %i, required %i", table_width, + table->min_width, table->max_width, auto_width, required_width); if (auto_width < required_width) { /* table narrower than required width for columns: @@ -2143,8 +2357,9 @@ static bool layout_table(struct box *table, int available_width, htype = css_computed_height(row->style, &value, &unit); if (htype == CSS_HEIGHT_SET && unit != CSS_UNIT_PCT) { - row_height = FIXTOINT(nscss_len2px(value, unit, - row->style)); + row_height = FIXTOINT(nscss_len2px( + &content->len_ctx, + value, unit, row->style)); } for (c = row->children; c; c = c->next) { assert(c->style); @@ -2181,8 +2396,9 @@ static bool layout_table(struct box *table, int available_width, /* some sites use height="1" or similar * to attempt to make cells as small as * possible, so treat it as a minimum */ - int h = FIXTOINT(nscss_len2px(value, - unit, c->style)); + int h = FIXTOINT(nscss_len2px( + &content->len_ctx, + value, unit, c->style)); if (c->height < h) c->height = h; } @@ -2326,12 +2542,16 @@ static bool layout_table(struct box *table, int available_width, /** * Manimpulate box height according to CSS min-height and max-height properties * + * \param len_ctx CSS length conversion context for document. * \param box block to modify with any min-height or max-height * \param container containing block for absolutely positioned elements, or * NULL for non absolutely positioned elements. * \return whether the height has been changed */ -static bool layout_apply_minmax_height(struct box *box, struct box *container) +static bool layout_apply_minmax_height( + const nscss_len_ctx *len_ctx, + struct box *box, + struct box *container) { int h; struct box *containing_block = NULL; @@ -2390,8 +2610,8 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container) } } } else { - h = FIXTOINT(nscss_len2px(value, unit, - box->style)); + h = FIXTOINT(nscss_len2px(len_ctx, + value, unit, box->style)); if (h < box->height) { box->height = h; updated = true; @@ -2400,7 +2620,7 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container) } /* min-height */ - if (css_computed_min_height(box->style, &value, &unit) == + if (ns_computed_min_height(box->style, &value, &unit) == CSS_MIN_HEIGHT_SET) { if (unit == CSS_UNIT_PCT) { if (containing_block && @@ -2420,8 +2640,8 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container) } } } else { - h = FIXTOINT(nscss_len2px(value, unit, - box->style)); + h = FIXTOINT(nscss_len2px(len_ctx, + value, unit, box->style)); if (h > box->height) { box->height = h; updated = true; @@ -2448,9 +2668,8 @@ static bool layout_block_object(struct box *block) block->type == BOX_TABLE_CELL); assert(block->object); -#ifdef LAYOUT_DEBUG - LOG("block %p, object %s, width %i", block, hlcache_handle_get_url(block->object), block->width); -#endif + NSLOG(layout, DEBUG, "block %p, object %p, width %i", block, + hlcache_handle_get_url(block->object), block->width); if (content_get_type(block->object) == CONTENT_HTML) { content_reformat(block->object, false, block->width, 1); @@ -2465,6 +2684,1211 @@ static bool layout_block_object(struct box *block) /** + * Insert a float into a container. + * + * \param cont block formatting context block, used to contain float + * \param b box to add to float + * + * This sorts floats in order of descending bottom edges. + */ +static void add_float_to_container(struct box *cont, struct box *b) +{ + struct box *box = cont->float_children; + int b_bottom = b->y + b->height; + + assert(b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT); + + if (box == NULL) { + /* No other float children */ + b->next_float = NULL; + cont->float_children = b; + return; + } else if (b_bottom >= box->y + box->height) { + /* Goes at start of list */ + b->next_float = cont->float_children; + cont->float_children = b; + } else { + struct box *prev = NULL; + while (box != NULL && b_bottom < box->y + box->height) { + prev = box; + box = box->next_float; + } + if (prev != NULL) { + b->next_float = prev->next_float; + prev->next_float = b; + } + } +} + + +/** + * Split a text box. + * + * \param content memory pool for any new boxes + * \param fstyle style for text in text box + * \param split_box box with text to split + * \param new_length new length for text in split_box, after splitting + * \param new_width new width for text in split_box, after splitting + * \return true on success, false on memory exhaustion + * + * A new box is created and inserted into the box tree after split_box, + * containing the text after new_length excluding the initial space character. + */ +static bool +layout_text_box_split(html_content *content, + plot_font_style_t *fstyle, + struct box *split_box, + size_t new_length, + int new_width) +{ + int space_width = split_box->space; + struct box *c2; + const struct gui_layout_table *font_func = content->font_func; + bool space = (split_box->text[new_length] == ' '); + int used_length = new_length + (space ? 1 : 0); + + if ((space && space_width == 0) || space_width == UNKNOWN_WIDTH) { + /* We're need to add a space, and we don't know how big + * it's to be, OR we have a space of unknown width anyway; + * Calculate space width */ + font_func->width(fstyle, " ", 1, &space_width); + } + + if (split_box->space == UNKNOWN_WIDTH) + split_box->space = space_width; + if (!space) + space_width = 0; + + /* Create clone of split_box, c2 */ + c2 = talloc_memdup(content->bctx, split_box, sizeof *c2); + if (!c2) + return false; + c2->flags |= CLONE; + + /* Set remaining text in c2 */ + c2->text += used_length; + + /* Set c2 according to the remaining text */ + c2->width -= new_width + space_width; + c2->flags &= ~MEASURED; /* width has been estimated */ + c2->length = split_box->length - used_length; + + /* Update split_box for its reduced text */ + split_box->width = new_width; + split_box->flags |= MEASURED; + split_box->length = new_length; + split_box->space = space_width; + + /* Insert c2 into box list */ + c2->next = split_box->next; + split_box->next = c2; + c2->prev = split_box; + if (c2->next) + c2->next->prev = c2; + else + c2->parent->last = c2; + + NSLOG(layout, DEBUG, + "split_box %p len: %" PRIsizet " \"%.*s\"", + split_box, + split_box->length, + (int)split_box->length, + split_box->text); + NSLOG(layout, DEBUG, + " new_box %p len: %" PRIsizet " \"%.*s\"", + c2, + c2->length, + (int)c2->length, + c2->text); + + return true; +} + + +/** + * Compute dimensions of box, margins, paddings, and borders for a floating + * element using shrink-to-fit. Also used for inline-blocks. + * + * \param len_ctx CSS length conversion context for document. + * \param available_width Max width available in pixels + * \param style Box's style + * \param box Box for which to find dimensions + * Box margins, borders, paddings, width and + * height are updated. + */ +static void +layout_float_find_dimensions( + const nscss_len_ctx *len_ctx, + int available_width, + const css_computed_style *style, + struct box *box) +{ + int width, height, max_width, min_width, max_height, min_height; + int *margin = box->margin; + int *padding = box->padding; + struct box_border *border = box->border; + enum css_overflow_e overflow_x = css_computed_overflow_x(style); + enum css_overflow_e overflow_y = css_computed_overflow_y(style); + int scrollbar_width_x = + (overflow_x == CSS_OVERFLOW_SCROLL || + overflow_x == CSS_OVERFLOW_AUTO) ? + SCROLLBAR_WIDTH : 0; + int scrollbar_width_y = + (overflow_y == CSS_OVERFLOW_SCROLL || + overflow_y == CSS_OVERFLOW_AUTO) ? + SCROLLBAR_WIDTH : 0; + + layout_find_dimensions(len_ctx, available_width, -1, box, style, + &width, &height, &max_width, &min_width, + &max_height, &min_height, margin, padding, border); + + if (margin[LEFT] == AUTO) + margin[LEFT] = 0; + if (margin[RIGHT] == AUTO) + margin[RIGHT] = 0; + + if (box->gadget == NULL) { + padding[RIGHT] += scrollbar_width_y; + padding[BOTTOM] += scrollbar_width_x; + } + + if (box->object && !(box->flags & REPLACE_DIM) && + content_get_type(box->object) != CONTENT_HTML) { + /* Floating replaced element, with intrinsic width or height. + * See 10.3.6 and 10.6.2 */ + layout_get_object_dimensions(box, &width, &height, + min_width, max_width, min_height, max_height); + } else if (box->gadget && (box->gadget->type == GADGET_TEXTBOX || + box->gadget->type == GADGET_PASSWORD || + box->gadget->type == GADGET_FILE || + box->gadget->type == GADGET_TEXTAREA)) { + css_fixed size = 0; + css_unit unit = CSS_UNIT_EM; + + /* Give sensible dimensions to gadgets, with auto width/height, + * that don't shrink to fit contained text. */ + assert(box->style); + + if (box->gadget->type == GADGET_TEXTBOX || + box->gadget->type == GADGET_PASSWORD || + box->gadget->type == GADGET_FILE) { + if (width == AUTO) { + size = INTTOFIX(10); + width = FIXTOINT(nscss_len2px(len_ctx, + size, unit, box->style)); + } + if (box->gadget->type == GADGET_FILE && + height == AUTO) { + size = FLTTOFIX(1.5); + height = FIXTOINT(nscss_len2px(len_ctx, + size, unit, box->style)); + } + } + if (box->gadget->type == GADGET_TEXTAREA) { + if (width == AUTO) { + size = INTTOFIX(10); + width = FIXTOINT(nscss_len2px(len_ctx, + size, unit, box->style)); + } + if (height == AUTO) { + size = INTTOFIX(4); + height = FIXTOINT(nscss_len2px(len_ctx, + size, unit, box->style)); + } + } + } else if (width == AUTO) { + /* CSS 2.1 section 10.3.5 */ + width = min(max(box->min_width, available_width), + box->max_width); + + /* width includes margin, borders and padding */ + if (width == available_width) { + width -= box->margin[LEFT] + box->border[LEFT].width + + box->padding[LEFT] + + box->padding[RIGHT] + + box->border[RIGHT].width + + box->margin[RIGHT]; + } else { + /* width was obtained from a min_width or max_width + * value, so need to use the same method for calculating + * mbp as was used in layout_minmax_block() */ + int fixed = 0; + float frac = 0; + calculate_mbp_width(len_ctx, box->style, LEFT, + true, true, true, &fixed, &frac); + calculate_mbp_width(len_ctx, box->style, RIGHT, + true, true, true, &fixed, &frac); + if (fixed < 0) + fixed = 0; + + width -= fixed; + } + + if (max_width >= 0 && width > max_width) width = max_width; + if (min_width > 0 && width < min_width) width = min_width; + + } else { + if (max_width >= 0 && width > max_width) width = max_width; + if (min_width > 0 && width < min_width) width = min_width; + width -= scrollbar_width_y; + } + + box->width = width; + box->height = height; + + if (margin[TOP] == AUTO) + margin[TOP] = 0; + if (margin[BOTTOM] == AUTO) + margin[BOTTOM] = 0; +} + + +/** + * Layout the contents of a float or inline block. + * + * \param b float or inline block box + * \param width available width + * \param content memory pool for any new boxes + * \return true on success, false on memory exhaustion + */ +static bool layout_float(struct box *b, int width, html_content *content) +{ + assert(b->type == BOX_TABLE || b->type == BOX_BLOCK || + b->type == BOX_INLINE_BLOCK); + layout_float_find_dimensions(&content->len_ctx, width, b->style, b); + if (b->type == BOX_TABLE) { + if (!layout_table(b, width, content)) + return false; + if (b->margin[LEFT] == AUTO) + b->margin[LEFT] = 0; + if (b->margin[RIGHT] == AUTO) + b->margin[RIGHT] = 0; + if (b->margin[TOP] == AUTO) + b->margin[TOP] = 0; + if (b->margin[BOTTOM] == AUTO) + b->margin[BOTTOM] = 0; + } else + return layout_block_context(b, -1, content); + return true; +} + + +/** + * Position a float in the first available space. + * + * \param c float box to position + * \param width available width + * \param cx x coordinate relative to cont to place float right of + * \param y y coordinate relative to cont to place float below + * \param cont ancestor box which defines horizontal space, for floats + */ +static void +place_float_below(struct box *c, int width, int cx, int y, struct box *cont) +{ + int x0, x1, yy; + struct box *left; + struct box *right; + + yy = y > cont->cached_place_below_level ? + y : cont->cached_place_below_level; + + NSLOG(layout, DEBUG, + "c %p, width %i, cx %i, y %i, cont %p", c, + width, cx, y, cont); + + do { + y = yy; + x0 = cx; + x1 = cx + width; + find_sides(cont->float_children, y, y + c->height, &x0, &x1, + &left, &right); + if (left != 0 && right != 0) { + yy = (left->y + left->height < + right->y + right->height ? + left->y + left->height : + right->y + right->height); + } else if (left == 0 && right != 0) { + yy = right->y + right->height; + } else if (left != 0 && right == 0) { + yy = left->y + left->height; + } + } while ((left != 0 || right != 0) && (c->width > x1 - x0)); + + if (c->type == BOX_FLOAT_LEFT) { + c->x = x0; + } else { + c->x = x1 - c->width; + } + c->y = y; + cont->cached_place_below_level = y; +} + + +/** + * Calculate line height from a style. + */ +static int line_height( + const nscss_len_ctx *len_ctx, + const css_computed_style *style) +{ + enum css_line_height_e lhtype; + css_fixed lhvalue = 0; + css_unit lhunit = CSS_UNIT_PX; + css_fixed line_height; + + assert(style); + + lhtype = css_computed_line_height(style, &lhvalue, &lhunit); + if (lhtype == CSS_LINE_HEIGHT_NORMAL) { + /* Normal => use a constant of 1.3 * font-size */ + lhvalue = FLTTOFIX(1.3); + lhtype = CSS_LINE_HEIGHT_NUMBER; + } + + if (lhtype == CSS_LINE_HEIGHT_NUMBER || + lhunit == CSS_UNIT_PCT) { + line_height = nscss_len2px(len_ctx, + lhvalue, CSS_UNIT_EM, style); + + if (lhtype != CSS_LINE_HEIGHT_NUMBER) + line_height = FDIV(line_height, F_100); + } else { + assert(lhunit != CSS_UNIT_PCT); + + line_height = nscss_len2px(len_ctx, + lhvalue, lhunit, style); + } + + return FIXTOINT(line_height); +} + + +/** + * Position a line of boxes in inline formatting context. + * + * \param first box at start of line + * \param width available width on input, updated with actual width on output + * (may be incorrect if the line gets split?) + * \param y coordinate of top of line, updated on exit to bottom + * \param cx coordinate of left of line relative to cont + * \param cy coordinate of top of line relative to cont + * \param cont ancestor box which defines horizontal space, for floats + * \param indent apply any first-line indent + * \param has_text_children at least one TEXT in the inline_container + * \param next_box updated to first box for next line, or 0 at end + * \param content memory pool for any new boxes + * \return true on success, false on memory exhaustion + */ +static bool +layout_line(struct box *first, + int *width, + int *y, + int cx, + int cy, + struct box *cont, + bool indent, + bool has_text_children, + html_content *content, + struct box **next_box) +{ + int height, used_height; + int x0 = 0; + int x1 = *width; + int x, h, x_previous; + int fy = cy; + struct box *left; + struct box *right; + struct box *b; + struct box *split_box = 0; + struct box *d; + struct box *br_box = 0; + bool move_y = false; + bool place_below = false; + int space_before = 0, space_after = 0; + unsigned int inline_count = 0; + unsigned int i; + const struct gui_layout_table *font_func = content->font_func; + plot_font_style_t fstyle; + + NSLOG(layout, DEBUG, + "first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i", + first, + (int)first->length, + first->text, + *width, + *y, + cx, + cy); + + /* find sides at top of line */ + x0 += cx; + x1 += cx; + find_sides(cont->float_children, cy, cy, &x0, &x1, &left, &right); + x0 -= cx; + x1 -= cx; + + if (indent) + x0 += layout_text_indent(&content->len_ctx, + first->parent->parent->style, *width); + + if (x1 < x0) + x1 = x0; + + /* get minimum line height from containing block. + * this is the line-height if there are text children and also in the + * case of an initially empty text input */ + if (has_text_children || first->parent->parent->gadget) + used_height = height = line_height(&content->len_ctx, + first->parent->parent->style); + else + /* inline containers with no text are usually for layout and + * look better with no minimum line-height */ + used_height = height = 0; + + /* pass 1: find height of line assuming sides at top of line: loop + * body executed at least once + * keep in sync with the loop in layout_minmax_line() */ + + NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0); + + + for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) { + int min_width, max_width, min_height, max_height; + + assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK || + b->type == BOX_FLOAT_LEFT || + b->type == BOX_FLOAT_RIGHT || + b->type == BOX_BR || b->type == BOX_TEXT || + b->type == BOX_INLINE_END); + + + NSLOG(layout, DEBUG, "pass 1: b %p, x %i", b, x); + + + if (b->type == BOX_BR) + break; + + if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT) + continue; + if (b->type == BOX_INLINE_BLOCK && + (css_computed_position(b->style) == + CSS_POSITION_ABSOLUTE || + css_computed_position(b->style) == + CSS_POSITION_FIXED)) + continue; + + assert(b->style != NULL); + font_plot_style_from_css(&content->len_ctx, b->style, &fstyle); + + x += space_after; + + if (b->type == BOX_INLINE_BLOCK) { + if (b->max_width != UNKNOWN_WIDTH) + if (!layout_float(b, *width, content)) + return false; + h = b->border[TOP].width + b->padding[TOP] + b->height + + b->padding[BOTTOM] + + b->border[BOTTOM].width; + if (height < h) + height = h; + x += b->margin[LEFT] + b->border[LEFT].width + + b->padding[LEFT] + b->width + + b->padding[RIGHT] + + b->border[RIGHT].width + + b->margin[RIGHT]; + space_after = 0; + continue; + } + + if (b->type == BOX_INLINE) { + /* calculate borders, margins, and padding */ + layout_find_dimensions(&content->len_ctx, + *width, -1, b, b->style, 0, 0, 0, 0, + 0, 0, b->margin, b->padding, b->border); + for (i = 0; i != 4; i++) + if (b->margin[i] == AUTO) + b->margin[i] = 0; + x += b->margin[LEFT] + b->border[LEFT].width + + b->padding[LEFT]; + if (b->inline_end) { + b->inline_end->margin[RIGHT] = b->margin[RIGHT]; + b->inline_end->padding[RIGHT] = + b->padding[RIGHT]; + b->inline_end->border[RIGHT] = + b->border[RIGHT]; + } else { + x += b->padding[RIGHT] + + b->border[RIGHT].width + + b->margin[RIGHT]; + } + } else if (b->type == BOX_INLINE_END) { + b->width = 0; + if (b->space == UNKNOWN_WIDTH) { + font_func->width(&fstyle, " ", 1, &b->space); + /** \todo handle errors */ + } + space_after = b->space; + + x += b->padding[RIGHT] + b->border[RIGHT].width + + b->margin[RIGHT]; + continue; + } + + if (!b->object && !(b->flags & IFRAME) && !b->gadget && + !(b->flags & REPLACE_DIM)) { + /* inline non-replaced, 10.3.1 and 10.6.1 */ + b->height = line_height(&content->len_ctx, + b->style ? b->style : + b->parent->parent->style); + if (height < b->height) + height = b->height; + + if (!b->text) { + b->width = 0; + space_after = 0; + continue; + } + + if (b->width == UNKNOWN_WIDTH) { + /** \todo handle errors */ + + /* If it's a select element, we must use the + * width of the widest option text */ + if (b->parent->parent->gadget && + b->parent->parent->gadget->type + == GADGET_SELECT) { + int opt_maxwidth = 0; + struct form_option *o; + + for (o = b->parent->parent->gadget-> + data.select.items; o; + o = o->next) { + int opt_width; + font_func->width(&fstyle, + o->text, + strlen(o->text), + &opt_width); + + if (opt_maxwidth < opt_width) + opt_maxwidth =opt_width; + } + b->width = opt_maxwidth; + if (nsoption_bool(core_select_menu)) + b->width += SCROLLBAR_WIDTH; + } else { + font_func->width(&fstyle, b->text, + b->length, &b->width); + b->flags |= MEASURED; + } + } + + /* If the current text has not been measured (i.e. its + * width was estimated after splitting), and it fits on + * the line, measure it properly, so next box is placed + * correctly. */ + if (b->text && (x + b->width < x1 - x0) && + !(b->flags & MEASURED) && + b->next) { + font_func->width(&fstyle, b->text, + b->length, &b->width); + b->flags |= MEASURED; + } + + x += b->width; + if (b->space == UNKNOWN_WIDTH) { + font_func->width(&fstyle, " ", 1, &b->space); + /** \todo handle errors */ + } + space_after = b->space; + continue; + } + + space_after = 0; + + /* inline replaced, 10.3.2 and 10.6.2 */ + assert(b->style); + + layout_find_dimensions(&content->len_ctx, + *width, -1, b, b->style, + &b->width, &b->height, + &max_width, &min_width, + &max_height, &min_height, + NULL, NULL, NULL); + + if (b->object && !(b->flags & REPLACE_DIM)) { + layout_get_object_dimensions(b, &b->width, &b->height, + min_width, max_width, + min_height, max_height); + } else if (b->flags & IFRAME) { + /* TODO: should we look at the content dimensions? */ + if (b->width == AUTO) + b->width = 400; + if (b->height == AUTO) + b->height = 300; + + /* We reformat the iframe browser window to new + * dimensions in pass 2 */ + } else { + /* form control with no object */ + if (b->width == AUTO) + b->width = FIXTOINT(nscss_len2px( + &content->len_ctx, INTTOFIX(1), + CSS_UNIT_EM, b->style)); + if (b->height == AUTO) + b->height = FIXTOINT(nscss_len2px( + &content->len_ctx, INTTOFIX(1), + CSS_UNIT_EM, b->style)); + } + + /* Reformat object to new box size */ + if (b->object && content_get_type(b->object) == CONTENT_HTML && + b->width != + content_get_available_width(b->object)) { + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + enum css_height_e htype = css_computed_height(b->style, + &value, &unit); + + content_reformat(b->object, false, b->width, b->height); + + if (htype == CSS_HEIGHT_AUTO) + b->height = content_get_height(b->object); + } + + if (height < b->height) + height = b->height; + + x += b->width; + } + + /* find new sides using this height */ + x0 = cx; + x1 = cx + *width; + find_sides(cont->float_children, cy, cy + height, &x0, &x1, + &left, &right); + x0 -= cx; + x1 -= cx; + + if (indent) + x0 += layout_text_indent(&content->len_ctx, + first->parent->parent->style, *width); + + if (x1 < x0) + x1 = x0; + + space_after = space_before = 0; + + /* pass 2: place boxes in line: loop body executed at least once */ + + NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0); + + for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) { + + NSLOG(layout, DEBUG, "pass 2: b %p, x %i", b, x); + + if (b->type == BOX_INLINE_BLOCK && + (css_computed_position(b->style) == + CSS_POSITION_ABSOLUTE || + css_computed_position(b->style) == + CSS_POSITION_FIXED)) { + b->x = x + space_after; + + } else if (b->type == BOX_INLINE || + b->type == BOX_INLINE_BLOCK || + b->type == BOX_TEXT || + b->type == BOX_INLINE_END) { + assert(b->width != UNKNOWN_WIDTH); + + x_previous = x; + x += space_after; + b->x = x; + + if ((b->type == BOX_INLINE && !b->inline_end) || + b->type == BOX_INLINE_BLOCK) { + b->x += b->margin[LEFT] + b->border[LEFT].width; + x = b->x + b->padding[LEFT] + b->width + + b->padding[RIGHT] + + b->border[RIGHT].width + + b->margin[RIGHT]; + } else if (b->type == BOX_INLINE) { + b->x += b->margin[LEFT] + b->border[LEFT].width; + x = b->x + b->padding[LEFT] + b->width; + } else if (b->type == BOX_INLINE_END) { + b->height = b->inline_end->height; + x += b->padding[RIGHT] + + b->border[RIGHT].width + + b->margin[RIGHT]; + } else { + x += b->width; + } + + space_before = space_after; + if (b->object || b->flags & REPLACE_DIM || + b->flags & IFRAME) + space_after = 0; + else if (b->text || b->type == BOX_INLINE_END) { + if (b->space == UNKNOWN_WIDTH) { + font_plot_style_from_css( + &content->len_ctx, + b->style, &fstyle); + /** \todo handle errors */ + font_func->width(&fstyle, " ", 1, + &b->space); + } + space_after = b->space; + } else { + space_after = 0; + } + split_box = b; + move_y = true; + inline_count++; + } else if (b->type == BOX_BR) { + b->x = x; + b->width = 0; + br_box = b; + b = b->next; + split_box = 0; + move_y = true; + break; + + } else { + /* float */ + NSLOG(layout, DEBUG, "float %p", b); + + d = b->children; + d->float_children = 0; + d->cached_place_below_level = 0; + b->float_container = d->float_container = cont; + + if (!layout_float(d, *width, content)) + return false; + + NSLOG(layout, DEBUG, + "%p : %d %d", + d, + d->margin[TOP], + d->border[TOP].width); + + d->x = d->margin[LEFT] + d->border[LEFT].width; + d->y = d->margin[TOP] + d->border[TOP].width; + b->width = d->margin[LEFT] + d->border[LEFT].width + + d->padding[LEFT] + d->width + + d->padding[RIGHT] + + d->border[RIGHT].width + + d->margin[RIGHT]; + b->height = d->margin[TOP] + d->border[TOP].width + + d->padding[TOP] + d->height + + d->padding[BOTTOM] + + d->border[BOTTOM].width + + d->margin[BOTTOM]; + + if (b->width > (x1 - x0) - x) + place_below = true; + if (d->style && (css_computed_clear(d->style) == + CSS_CLEAR_NONE || + (css_computed_clear(d->style) == + CSS_CLEAR_LEFT && left == 0) || + (css_computed_clear(d->style) == + CSS_CLEAR_RIGHT && + right == 0) || + (css_computed_clear(d->style) == + CSS_CLEAR_BOTH && + left == 0 && right == 0)) && + (!place_below || + (left == 0 && right == 0 && x == 0)) && + cy >= cont->clear_level && + cy >= cont->cached_place_below_level) { + /* + not cleared or, + * cleared and there are no floats to clear + * + fits without needing to be placed below or, + * this line is empty with no floats + * + current y, cy, is below the clear level + * + * Float affects current line */ + if (b->type == BOX_FLOAT_LEFT) { + b->x = cx + x0; + if (b->width > 0) + x0 += b->width; + left = b; + } else { + b->x = cx + x1 - b->width; + if (b->width > 0) + x1 -= b->width; + right = b; + } + b->y = cy; + } else { + /* cleared or doesn't fit on line */ + /* place below into next available space */ + int fcy = (cy > cont->clear_level) ? cy : + cont->clear_level; + fcy = (fcy > cont->cached_place_below_level) ? + fcy : + cont->cached_place_below_level; + fy = (fy > fcy) ? fy : fcy; + fy = (fy == cy) ? fy + height : fy; + + place_float_below(b, *width, cx, fy, cont); + fy = b->y; + if (d->style && ( + (css_computed_clear(d->style) == + CSS_CLEAR_LEFT && left != 0) || + (css_computed_clear(d->style) == + CSS_CLEAR_RIGHT && + right != 0) || + (css_computed_clear(d->style) == + CSS_CLEAR_BOTH && + (left != 0 || right != 0)))) { + /* to be cleared below existing + * floats */ + if (b->type == BOX_FLOAT_LEFT) + b->x = cx; + else + b->x = cx + *width - b->width; + + fcy = layout_clear(cont->float_children, + css_computed_clear(d->style)); + if (fcy > cont->clear_level) + cont->clear_level = fcy; + if (b->y < fcy) + b->y = fcy; + } + if (b->type == BOX_FLOAT_LEFT) + left = b; + else + right = b; + } + add_float_to_container(cont, b); + + split_box = 0; + } + } + + if (x1 - x0 < x && split_box) { + /* the last box went over the end */ + size_t split = 0; + int w; + bool no_wrap = css_computed_white_space( + split_box->style) == CSS_WHITE_SPACE_NOWRAP || + css_computed_white_space( + split_box->style) == CSS_WHITE_SPACE_PRE; + + x = x_previous; + + if (!no_wrap && + (split_box->type == BOX_INLINE || + split_box->type == BOX_TEXT) && + !split_box->object && + !(split_box->flags & REPLACE_DIM) && + !(split_box->flags & IFRAME) && + !split_box->gadget && split_box->text) { + + font_plot_style_from_css(&content->len_ctx, + split_box->style, &fstyle); + /** \todo handle errors */ + font_func->split(&fstyle, + split_box->text, + split_box->length, + x1 - x0 - x - space_before, + &split, + &w); + } + + /* split == 0 implies that text can't be split */ + + if (split == 0) + w = split_box->width; + + + NSLOG(layout, DEBUG, + "splitting: split_box %p \"%.*s\", spilt %zu, w %i, " + "left %p, right %p, inline_count %u", + split_box, + (int)split_box->length, + split_box->text, + split, + w, + left, + right, + inline_count); + + if ((split == 0 || x1 - x0 <= x + space_before + w) && + !left && !right && inline_count == 1) { + /* first word of box doesn't fit, but no floats and + * first box on line so force in */ + if (split == 0 || split == split_box->length) { + /* only one word in this box, or not text + * or white-space:nowrap */ + b = split_box->next; + } else { + /* cut off first word for this line */ + if (!layout_text_box_split(content, &fstyle, + split_box, split, w)) + return false; + b = split_box->next; + } + x += space_before + w; + + NSLOG(layout, DEBUG, "forcing"); + + } else if ((split == 0 || x1 - x0 <= x + space_before + w) && + inline_count == 1) { + /* first word of first box doesn't fit, but a float is + * taking some of the width so move below it */ + assert(left || right); + used_height = 0; + if (left) { + + NSLOG(layout, DEBUG, + "cy %i, left->y %i, left->height %i", + cy, + left->y, + left->height); + + used_height = left->y + left->height - cy + 1; + + NSLOG(layout, DEBUG, "used_height %i", + used_height); + + } + if (right && used_height < + right->y + right->height - cy + 1) + used_height = right->y + right->height - cy + 1; + + if (used_height < 0) + used_height = 0; + + b = split_box; + + NSLOG(layout, DEBUG, "moving below float"); + + } else if (split == 0 || x1 - x0 <= x + space_before + w) { + /* first word of box doesn't fit so leave box for next + * line */ + b = split_box; + + NSLOG(layout, DEBUG, "leaving for next line"); + + } else { + /* fit as many words as possible */ + assert(split != 0); + + NSLOG(layout, DEBUG, "'%.*s' %i %zu %i", + (int)split_box->length, split_box->text, + x1 - x0, split, w); + + if (split != split_box->length) { + if (!layout_text_box_split(content, &fstyle, + split_box, split, w)) + return false; + b = split_box->next; + } + x += space_before + w; + + NSLOG(layout, DEBUG, "fitting words"); + + } + move_y = true; + } + + /* set positions */ + switch (css_computed_text_align(first->parent->parent->style)) { + case CSS_TEXT_ALIGN_RIGHT: + case CSS_TEXT_ALIGN_LIBCSS_RIGHT: + x0 = x1 - x; + break; + case CSS_TEXT_ALIGN_CENTER: + case CSS_TEXT_ALIGN_LIBCSS_CENTER: + x0 = (x0 + (x1 - x)) / 2; + break; + case CSS_TEXT_ALIGN_LEFT: + case CSS_TEXT_ALIGN_LIBCSS_LEFT: + case CSS_TEXT_ALIGN_JUSTIFY: + /* leave on left */ + break; + case CSS_TEXT_ALIGN_DEFAULT: + /* None; consider text direction */ + switch (css_computed_direction(first->parent->parent->style)) { + case CSS_DIRECTION_LTR: + /* leave on left */ + break; + case CSS_DIRECTION_RTL: + x0 = x1 - x; + break; + } + break; + } + + for (d = first; d != b; d = d->next) { + d->flags &= ~NEW_LINE; + + if (d->type == BOX_INLINE_BLOCK && + (css_computed_position(d->style) == + CSS_POSITION_ABSOLUTE || + css_computed_position(d->style) == + CSS_POSITION_FIXED)) { + /* positioned inline-blocks: + * set static position (x,y) only, rest of positioning + * is handled later */ + d->x += x0; + d->y = *y; + continue; + } else if ((d->type == BOX_INLINE && + ((d->object || d->gadget) == false) && + !(d->flags & IFRAME) && + !(d->flags & REPLACE_DIM)) || + d->type == BOX_BR || + d->type == BOX_TEXT || + d->type == BOX_INLINE_END) { + /* regular (non-replaced) inlines */ + d->x += x0; + d->y = *y - d->padding[TOP]; + + if (d->type == BOX_TEXT && d->height > used_height) { + /* text */ + used_height = d->height; + } + } else if ((d->type == BOX_INLINE) || + d->type == BOX_INLINE_BLOCK) { + /* replaced inlines and inline-blocks */ + d->x += x0; + d->y = *y + d->border[TOP].width + d->margin[TOP]; + h = d->margin[TOP] + d->border[TOP].width + + d->padding[TOP] + d->height + + d->padding[BOTTOM] + + d->border[BOTTOM].width + + d->margin[BOTTOM]; + if (used_height < h) + used_height = h; + } + } + + first->flags |= NEW_LINE; + + assert(b != first || (move_y && 0 < used_height && (left || right))); + + /* handle vertical-align by adjusting box y values */ + /** \todo proper vertical alignment handling */ + for (d = first; d != b; d = d->next) { + if ((d->type == BOX_INLINE && d->inline_end) || + d->type == BOX_BR || + d->type == BOX_TEXT || + d->type == BOX_INLINE_END) { + css_fixed value = 0; + css_unit unit = CSS_UNIT_PX; + switch (css_computed_vertical_align(d->style, &value, + &unit)) { + case CSS_VERTICAL_ALIGN_SUPER: + case CSS_VERTICAL_ALIGN_TOP: + case CSS_VERTICAL_ALIGN_TEXT_TOP: + /* already at top */ + break; + case CSS_VERTICAL_ALIGN_SUB: + case CSS_VERTICAL_ALIGN_BOTTOM: + case CSS_VERTICAL_ALIGN_TEXT_BOTTOM: + d->y += used_height - d->height; + break; + default: + case CSS_VERTICAL_ALIGN_BASELINE: + d->y += 0.75 * (used_height - d->height); + break; + } + } + } + + /* handle clearance for br */ + if (br_box && css_computed_clear(br_box->style) != CSS_CLEAR_NONE) { + int clear_y = layout_clear(cont->float_children, + css_computed_clear(br_box->style)); + if (used_height < clear_y - cy) + used_height = clear_y - cy; + } + + if (move_y) + *y += used_height; + *next_box = b; + *width = x; /* return actual width */ + return true; +} + + +/** + * Layout lines of text or inline boxes with floats. + * + * \param box inline container box + * \param width horizontal space available + * \param cont ancestor box which defines horizontal space, for floats + * \param cx box position relative to cont + * \param cy box position relative to cont + * \param content memory pool for any new boxes + * \return true on success, false on memory exhaustion + */ +static bool layout_inline_container(struct box *inline_container, int width, + struct box *cont, int cx, int cy, html_content *content) +{ + bool first_line = true; + bool has_text_children; + struct box *c, *next; + int y = 0; + int curwidth,maxwidth = width; + + assert(inline_container->type == BOX_INLINE_CONTAINER); + + NSLOG(layout, DEBUG, + "inline_container %p, width %i, cont %p, cx %i, cy %i", + inline_container, + width, + cont, + cx, + cy); + + + has_text_children = false; + for (c = inline_container->children; c; c = c->next) { + bool is_pre = false; + + if (c->style) { + enum css_white_space_e whitespace; + + whitespace = css_computed_white_space(c->style); + + is_pre = (whitespace == CSS_WHITE_SPACE_PRE || + whitespace == CSS_WHITE_SPACE_PRE_LINE || + whitespace == CSS_WHITE_SPACE_PRE_WRAP); + } + + if ((!c->object && !(c->flags & REPLACE_DIM) && + !(c->flags & IFRAME) && + c->text && (c->length || is_pre)) || + c->type == BOX_BR) + has_text_children = true; + } + + /** \todo fix wrapping so that a box with horizontal scrollbar will + * shrink back to 'width' if no word is wider than 'width' (Or just set + * curwidth = width and have the multiword lines wrap to the min width) + */ + for (c = inline_container->children; c; ) { + + NSLOG(layout, DEBUG, "c %p", c); + + curwidth = inline_container->width; + if (!layout_line(c, &curwidth, &y, cx, cy + y, cont, first_line, + has_text_children, content, &next)) + return false; + maxwidth = max(maxwidth,curwidth); + c = next; + first_line = false; + } + + inline_container->width = maxwidth; + inline_container->height = y; + + return true; +} + + +/** * Layout a block formatting context. * * \param block BLOCK, INLINE_BLOCK, or TABLE_CELL to layout @@ -2522,7 +3946,8 @@ layout_block_context(struct box *block, gadget_unit = CSS_UNIT_EM; gadget_size = INTTOFIX(1); if (block->height == AUTO) - block->height = FIXTOINT(nscss_len2px(gadget_size, + block->height = FIXTOINT(nscss_len2px( + &content->len_ctx, gadget_size, gadget_unit, block->style)); } @@ -2586,7 +4011,8 @@ layout_block_context(struct box *block, /* If we don't know which box the current margin collapses * through to, find out. Update the pos/neg margin values. */ if (margin_collapse == NULL) { - margin_collapse = layout_next_margin_block(box, block, + margin_collapse = layout_next_margin_block( + &content->len_ctx, box, block, viewport_height, &max_pos_margin, &max_neg_margin); /* We have a margin that has not yet been applied. */ @@ -2637,7 +4063,8 @@ layout_block_context(struct box *block, box->parent->padding[RIGHT] - x1; } - layout_block_find_dimensions(box->parent->width, + layout_block_find_dimensions(&content->len_ctx, + box->parent->width, viewport_height, lm, rm, box); if (box->type == BOX_BLOCK && !(box->flags & IFRAME)) { layout_block_add_scrollbar(box, RIGHT); @@ -2746,9 +4173,7 @@ layout_block_context(struct box *block, goto advance_to_next_box; } -#ifdef LAYOUT_DEBUG - LOG("box %p, cx %i, cy %i", box, cx, cy); -#endif + NSLOG(layout, DEBUG, "box %p, cx %i, cy %i", box, cx, cy); /* Layout (except tables). */ if (box->object) { @@ -2879,8 +4304,9 @@ layout_block_context(struct box *block, if (box->style && css_computed_position(box->style) != CSS_POSITION_ABSOLUTE && - layout_apply_minmax_height(box, - NULL)) { + layout_apply_minmax_height( + &content->len_ctx, + box, NULL)) { /* Height altered */ /* Set current cy */ cy += box->height - @@ -2936,19 +4362,23 @@ layout_block_context(struct box *block, if (block->style && css_computed_position(block->style) != CSS_POSITION_ABSOLUTE) { /* Block is in normal flow */ - layout_apply_minmax_height(block, NULL); + layout_apply_minmax_height(&content->len_ctx, block, NULL); } if (block->gadget && (block->gadget->type == GADGET_TEXTAREA || block->gadget->type == GADGET_PASSWORD || block->gadget->type == GADGET_TEXTBOX)) { + plot_font_style_t fstyle; int ta_width = block->padding[LEFT] + block->width + block->padding[RIGHT]; int ta_height = block->padding[TOP] + block->height + block->padding[BOTTOM]; + font_plot_style_from_css(&content->len_ctx, + block->style, &fstyle); + fstyle.background = NS_TRANSPARENT; textarea_set_layout(block->gadget->data.text.ta, - ta_width, ta_height, + &fstyle, ta_width, ta_height, block->padding[TOP], block->padding[RIGHT], block->padding[BOTTOM], block->padding[LEFT]); } @@ -2958,46 +4388,12 @@ layout_block_context(struct box *block, /** - * Calculate line height from a style. - */ -static int line_height(const css_computed_style *style) -{ - enum css_line_height_e lhtype; - css_fixed lhvalue = 0; - css_unit lhunit = CSS_UNIT_PX; - css_fixed line_height; - - assert(style); - - lhtype = css_computed_line_height(style, &lhvalue, &lhunit); - if (lhtype == CSS_LINE_HEIGHT_NORMAL) { - /* Normal => use a constant of 1.3 * font-size */ - lhvalue = FLTTOFIX(1.3); - lhtype = CSS_LINE_HEIGHT_NUMBER; - } - - if (lhtype == CSS_LINE_HEIGHT_NUMBER || - lhunit == CSS_UNIT_PCT) { - line_height = nscss_len2px(lhvalue, CSS_UNIT_EM, style); - - if (lhtype != CSS_LINE_HEIGHT_NUMBER) - line_height = FDIV(line_height, F_100); - } else { - assert(lhunit != CSS_UNIT_PCT); - - line_height = nscss_len2px(lhvalue, lhunit, style); - } - - return FIXTOINT(line_height); -} - - -/** * Layout list markers. */ static void layout_lists(struct box *box, - const struct gui_layout_table *font_func) + const struct gui_layout_table *font_func, + const nscss_len_ctx *len_ctx) { struct box *child; struct box *marker; @@ -3012,12 +4408,13 @@ layout_lists(struct box *box, marker->x = -marker->width; marker->height = content_get_height(marker->object); - marker->y = (line_height(marker->style) - + marker->y = (line_height(len_ctx, + marker->style) - marker->height) / 2; } else if (marker->text) { if (marker->width == UNKNOWN_WIDTH) { - font_plot_style_from_css(marker->style, - &fstyle); + font_plot_style_from_css(len_ctx, + marker->style, &fstyle); font_func->width(&fstyle, marker->text, marker->length, @@ -3026,7 +4423,8 @@ layout_lists(struct box *box, } marker->x = -marker->width; marker->y = 0; - marker->height = line_height(marker->style); + marker->height = line_height(len_ctx, + marker->style); } else { marker->x = 0; marker->y = 0; @@ -3036,7 +4434,7 @@ layout_lists(struct box *box, /* Gap between marker and content */ marker->x -= 4; } - layout_lists(child, font_func); + layout_lists(child, font_func, len_ctx); } } @@ -3045,6 +4443,7 @@ layout_lists(struct box *box, * Compute box offsets for a relatively or absolutely positioned box with * respect to a box. * + * \param len_ctx Length conversion context * \param box box to compute offsets for * \param containing_block box to compute percentages with respect to * \param top updated to top offset, or AUTO @@ -3055,7 +4454,8 @@ layout_lists(struct box *box, * See CSS 2.1 9.3.2. containing_block must have width and height. */ static void -layout_compute_offsets(struct box *box, +layout_compute_offsets(const nscss_len_ctx *len_ctx, + struct box *box, struct box *containing_block, int *top, int *right, @@ -3077,7 +4477,8 @@ layout_compute_offsets(struct box *box, *left = FPCT_OF_INT_TOINT(value, containing_block->width); } else { - *left = FIXTOINT(nscss_len2px(value, unit, box->style)); + *left = FIXTOINT(nscss_len2px(len_ctx, + value, unit, box->style)); } } else { *left = AUTO; @@ -3090,8 +4491,8 @@ layout_compute_offsets(struct box *box, *right = FPCT_OF_INT_TOINT(value, containing_block->width); } else { - *right = FIXTOINT(nscss_len2px(value, unit, - box->style)); + *right = FIXTOINT(nscss_len2px(len_ctx, + value, unit, box->style)); } } else { *right = AUTO; @@ -3104,7 +4505,8 @@ layout_compute_offsets(struct box *box, *top = FPCT_OF_INT_TOINT(value, containing_block->height); } else { - *top = FIXTOINT(nscss_len2px(value, unit, box->style)); + *top = FIXTOINT(nscss_len2px(len_ctx, + value, unit, box->style)); } } else { *top = AUTO; @@ -3117,8 +4519,8 @@ layout_compute_offsets(struct box *box, *bottom = FPCT_OF_INT_TOINT(value, containing_block->height); } else { - *bottom = FIXTOINT(nscss_len2px(value, unit, - box->style)); + *bottom = FIXTOINT(nscss_len2px(len_ctx, + value, unit, box->style)); } } else { *bottom = AUTO; @@ -3174,22 +4576,26 @@ layout_absolute(struct box *box, /** \todo inline containers */ } - layout_compute_offsets(box, containing_block, + layout_compute_offsets(&content->len_ctx, box, containing_block, &top, &right, &bottom, &left); /* Pass containing block into layout_find_dimensions via the float * containing block box member. This is unused for absolutely positioned * boxes because a box can't be floated and absolutely positioned. */ box->float_container = containing_block; - layout_find_dimensions(available_width, -1, box, box->style, - &width, &height, &max_width, &min_width, - 0, 0, margin, padding, border); + layout_find_dimensions(&content->len_ctx, available_width, -1, + box, box->style, &width, &height, + &max_width, &min_width, 0, 0, + margin, padding, border); box->float_container = NULL; /* 10.3.7 */ -#ifdef LAYOUT_DEBUG - LOG("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", left, margin[LEFT], border[LEFT].width, padding[LEFT], width, padding[RIGHT], border[RIGHT].width, margin[RIGHT], right, containing_block->width); -#endif + NSLOG(layout, DEBUG, + "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", + left, margin[LEFT], border[LEFT].width, padding[LEFT], width, + padding[RIGHT], border[RIGHT].width, margin[RIGHT], right, + containing_block->width); + if (left == AUTO && width == AUTO && right == AUTO) { if (margin[LEFT] == AUTO) @@ -3352,9 +4758,11 @@ layout_absolute(struct box *box, } } -#ifdef LAYOUT_DEBUG - LOG("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", left, margin[LEFT], border[LEFT].width, padding[LEFT], width, padding[RIGHT], border[RIGHT].width, margin[RIGHT], right, containing_block->width); -#endif + NSLOG(layout, DEBUG, + "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", + left, margin[LEFT], border[LEFT].width, padding[LEFT], width, + padding[RIGHT], border[RIGHT].width, margin[RIGHT], right, + containing_block->width); box->x = left + margin[LEFT] + border[LEFT].width - cx; if (containing_block->type == BOX_BLOCK || @@ -3386,9 +4794,11 @@ layout_absolute(struct box *box, } /* 10.6.4 */ -#ifdef LAYOUT_DEBUG - LOG("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", top, margin[TOP], border[TOP].width, padding[TOP], height, padding[BOTTOM], border[BOTTOM].width, margin[BOTTOM], bottom, containing_block->height); -#endif + NSLOG(layout, DEBUG, + "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", + top, margin[TOP], border[TOP].width, padding[TOP], height, + padding[BOTTOM], border[BOTTOM].width, margin[BOTTOM], bottom, + containing_block->height); if (top == AUTO && height == AUTO && bottom == AUTO) { top = static_top; @@ -3474,9 +4884,11 @@ layout_absolute(struct box *box, } } -#ifdef LAYOUT_DEBUG - LOG("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", top, margin[TOP], border[TOP].width, padding[TOP], height, padding[BOTTOM], border[BOTTOM].width, margin[BOTTOM], bottom, containing_block->height); -#endif + NSLOG(layout, DEBUG, + "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i", + top, margin[TOP], border[TOP].width, padding[TOP], height, + padding[BOTTOM], border[BOTTOM].width, margin[BOTTOM], bottom, + containing_block->height); box->y = top + margin[TOP] + border[TOP].width - cy; if (containing_block->type == BOX_BLOCK || @@ -3489,7 +4901,7 @@ layout_absolute(struct box *box, /** \todo Inline ancestors */ } box->height = height; - layout_apply_minmax_height(box, containing_block); + layout_apply_minmax_height(&content->len_ctx, box, containing_block); return true; } @@ -3566,11 +4978,16 @@ layout_position_absolute(struct box *box, /** * Compute a box's relative offset as per CSS 2.1 9.4.3 * + * \param len_ctx Length conversion context * \param box Box to compute relative offsets for. * \param x Receives relative offset in x. * \param y Receives relative offset in y. */ -static void layout_compute_relative_offset(struct box *box, int *x, int *y) +static void layout_compute_relative_offset( + const nscss_len_ctx *len_ctx, + struct box *box, + int *x, + int *y) { int left, right, top, bottom; struct box *containing_block; @@ -3587,7 +5004,7 @@ static void layout_compute_relative_offset(struct box *box, int *x, int *y) containing_block = box->parent; } - layout_compute_offsets(box, containing_block, + layout_compute_offsets(len_ctx, box, containing_block, &top, &right, &bottom, &left); if (left == AUTO && right == AUTO) @@ -3624,9 +5041,8 @@ static void layout_compute_relative_offset(struct box *box, int *x, int *y) bottom = -top; } -#ifdef LAYOUT_DEBUG - LOG("left %i, right %i, top %i, bottom %i", left, right, top, bottom); -#endif + NSLOG(layout, DEBUG, "left %i, right %i, top %i, bottom %i", left, + right, top, bottom); *x = left; *y = top; @@ -3636,6 +5052,7 @@ static void layout_compute_relative_offset(struct box *box, int *x, int *y) /** * Adjust positions of relatively positioned boxes. * + * \param len_ctx Length conversion context * \param root box to adjust the position of * \param fp box which forms the block formatting context for children of * "root" which are floats @@ -3647,7 +5064,12 @@ static void layout_compute_relative_offset(struct box *box, int *x, int *y) * box, "fp", for float children of "root" */ static void -layout_position_relative(struct box *root, struct box *fp, int fx, int fy) +layout_position_relative( + const nscss_len_ctx *len_ctx, + struct box *root, + struct box *fp, + int fx, + int fy) { struct box *box; /* for children of "root" */ struct box *fn; /* for block formatting context box for children of @@ -3671,7 +5093,8 @@ layout_position_relative(struct box *root, struct box *fp, int fx, int fy) /* If relatively positioned, get offsets */ if (box->style && css_computed_position(box->style) == CSS_POSITION_RELATIVE) - layout_compute_relative_offset(box, &x, &y); + layout_compute_relative_offset( + len_ctx, box, &x, &y); else x = y = 0; @@ -3707,7 +5130,7 @@ layout_position_relative(struct box *root, struct box *fp, int fx, int fy) } /* recurse first */ - layout_position_relative(box, fn, fnx, fny); + layout_position_relative(len_ctx, box, fn, fnx, fny); /* Ignore things we're not interested in. */ if (!box->style || (box->style && @@ -3733,1334 +5156,10 @@ layout_position_relative(struct box *root, struct box *fp, int fx, int fy) } -/* exported function documented in render/layout.h */ -bool layout_document(html_content *content, int width, int height) -{ - bool ret; - struct box *doc = content->layout; - const struct gui_layout_table *font_func = content->font_func; - - layout_minmax_block(doc, font_func); - - layout_block_find_dimensions(width, height, 0, 0, doc); - doc->x = doc->margin[LEFT] + doc->border[LEFT].width; - doc->y = doc->margin[TOP] + doc->border[TOP].width; - width -= doc->margin[LEFT] + doc->border[LEFT].width + - doc->padding[LEFT] + doc->padding[RIGHT] + - doc->border[RIGHT].width + doc->margin[RIGHT]; - if (width < 0) { - width = 0; - } - doc->width = width; - - ret = layout_block_context(doc, height, content); - - /* make <html> and <body> fill available height */ - if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] + - doc->border[BOTTOM].width + doc->margin[BOTTOM] < - height) { - doc->height = height - (doc->y + doc->padding[TOP] + - doc->padding[BOTTOM] + - doc->border[BOTTOM].width + - doc->margin[BOTTOM]); - if (doc->children) - doc->children->height = doc->height - - (doc->children->margin[TOP] + - doc->children->border[TOP].width + - doc->children->padding[TOP] + - doc->children->padding[BOTTOM] + - doc->children->border[BOTTOM].width + - doc->children->margin[BOTTOM]); - } - - layout_lists(doc, font_func); - layout_position_absolute(doc, doc, 0, 0, content); - layout_position_relative(doc, doc, 0, 0); - - layout_calculate_descendant_bboxes(doc); - - return ret; -} - - -/** - * Insert a float into a container. - * - * \param cont block formatting context block, used to contain float - * \param b box to add to float - * - * This sorts floats in order of descending bottom edges. - */ -static void add_float_to_container(struct box *cont, struct box *b) -{ - struct box *box = cont->float_children; - int b_bottom = b->y + b->height; - - assert(b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT); - - if (box == NULL) { - /* No other float children */ - b->next_float = NULL; - cont->float_children = b; - return; - } else if (b_bottom >= box->y + box->height) { - /* Goes at start of list */ - b->next_float = cont->float_children; - cont->float_children = b; - } else { - struct box *prev = NULL; - while (box != NULL && b_bottom < box->y + box->height) { - prev = box; - box = box->next_float; - } - if (prev != NULL) { - b->next_float = prev->next_float; - prev->next_float = b; - } - } -} - - -/** - * Split a text box. - * - * \param content memory pool for any new boxes - * \param fstyle style for text in text box - * \param split_box box with text to split - * \param new_length new length for text in split_box, after splitting - * \param new_width new width for text in split_box, after splitting - * \return true on success, false on memory exhaustion - * - * A new box is created and inserted into the box tree after split_box, - * containing the text after new_length excluding the initial space character. - */ -static bool -layout_text_box_split(html_content *content, - plot_font_style_t *fstyle, - struct box *split_box, - size_t new_length, - int new_width) -{ - int space_width = split_box->space; - struct box *c2; - const struct gui_layout_table *font_func = content->font_func; - bool space = (split_box->text[new_length] == ' '); - int used_length = new_length + (space ? 1 : 0); - - if ((space && space_width == 0) || space_width == UNKNOWN_WIDTH) { - /* We're need to add a space, and we don't know how big - * it's to be, OR we have a space of unknown width anyway; - * Calculate space width */ - font_func->width(fstyle, " ", 1, &space_width); - } - - if (split_box->space == UNKNOWN_WIDTH) - split_box->space = space_width; - if (!space) - space_width = 0; - - /* Create clone of split_box, c2 */ - c2 = talloc_memdup(content->bctx, split_box, sizeof *c2); - if (!c2) - return false; - c2->flags |= CLONE; - - /* Set remaining text in c2 */ - c2->text += used_length; - - /* Set c2 according to the remaining text */ - c2->width -= new_width + space_width; - c2->flags &= ~MEASURED; /* width has been estimated */ - c2->length = split_box->length - used_length; - - /* Update split_box for its reduced text */ - split_box->width = new_width; - split_box->flags |= MEASURED; - split_box->length = new_length; - split_box->space = space_width; - - /* Insert c2 into box list */ - c2->next = split_box->next; - split_box->next = c2; - c2->prev = split_box; - if (c2->next) - c2->next->prev = c2; - else - c2->parent->last = c2; -#ifdef LAYOUT_DEBUG - LOG("split_box %p len: %u \"%.*s\"", split_box, split_box->length, split_box->length, split_box->text); - LOG(" new_box %p len: %u \"%.*s\"", c2, c2->length, c2->length, c2->text); -#endif - return true; -} - - -/** - * Compute dimensions of box, margins, paddings, and borders for a floating - * element using shrink-to-fit. Also used for inline-blocks. - * - * \param available_width Max width available in pixels - * \param style Box's style - * \param box Box for which to find dimensions - * Box margins, borders, paddings, width and - * height are updated. - */ -static void -layout_float_find_dimensions(int available_width, - const css_computed_style *style, - struct box *box) -{ - int width, height, max_width, min_width, max_height, min_height; - int *margin = box->margin; - int *padding = box->padding; - struct box_border *border = box->border; - enum css_overflow_e overflow_x = css_computed_overflow_x(style); - enum css_overflow_e overflow_y = css_computed_overflow_y(style); - int scrollbar_width_x = - (overflow_x == CSS_OVERFLOW_SCROLL || - overflow_x == CSS_OVERFLOW_AUTO) ? - SCROLLBAR_WIDTH : 0; - int scrollbar_width_y = - (overflow_y == CSS_OVERFLOW_SCROLL || - overflow_y == CSS_OVERFLOW_AUTO) ? - SCROLLBAR_WIDTH : 0; - - layout_find_dimensions(available_width, -1, box, style, &width, &height, - &max_width, &min_width, &max_height, &min_height, - margin, padding, border); - - if (margin[LEFT] == AUTO) - margin[LEFT] = 0; - if (margin[RIGHT] == AUTO) - margin[RIGHT] = 0; - - if (box->gadget == NULL) { - padding[RIGHT] += scrollbar_width_y; - padding[BOTTOM] += scrollbar_width_x; - } - - if (box->object && !(box->flags & REPLACE_DIM) && - content_get_type(box->object) != CONTENT_HTML) { - /* Floating replaced element, with intrinsic width or height. - * See 10.3.6 and 10.6.2 */ - layout_get_object_dimensions(box, &width, &height, - min_width, max_width, min_height, max_height); - } else if (box->gadget && (box->gadget->type == GADGET_TEXTBOX || - box->gadget->type == GADGET_PASSWORD || - box->gadget->type == GADGET_FILE || - box->gadget->type == GADGET_TEXTAREA)) { - css_fixed size = 0; - css_unit unit = CSS_UNIT_EM; - - /* Give sensible dimensions to gadgets, with auto width/height, - * that don't shrink to fit contained text. */ - assert(box->style); - - if (box->gadget->type == GADGET_TEXTBOX || - box->gadget->type == GADGET_PASSWORD || - box->gadget->type == GADGET_FILE) { - if (width == AUTO) { - size = INTTOFIX(10); - width = FIXTOINT(nscss_len2px(size, unit, - box->style)); - } - if (box->gadget->type == GADGET_FILE && - height == AUTO) { - size = FLTTOFIX(1.5); - height = FIXTOINT(nscss_len2px(size, unit, - box->style)); - } - } - if (box->gadget->type == GADGET_TEXTAREA) { - if (width == AUTO) { - size = INTTOFIX(10); - width = FIXTOINT(nscss_len2px(size, unit, - box->style)); - } - if (height == AUTO) { - size = INTTOFIX(4); - height = FIXTOINT(nscss_len2px(size, unit, - box->style)); - } - } - } else if (width == AUTO) { - /* CSS 2.1 section 10.3.5 */ - width = min(max(box->min_width, available_width), - box->max_width); - - /* width includes margin, borders and padding */ - if (width == available_width) { - width -= box->margin[LEFT] + box->border[LEFT].width + - box->padding[LEFT] + - box->padding[RIGHT] + - box->border[RIGHT].width + - box->margin[RIGHT]; - } else { - /* width was obtained from a min_width or max_width - * value, so need to use the same method for calculating - * mbp as was used in layout_minmax_block() */ - int fixed = 0; - float frac = 0; - calculate_mbp_width(box->style, LEFT, true, true, true, - &fixed, &frac); - calculate_mbp_width(box->style, RIGHT, true, true, true, - &fixed, &frac); - if (fixed < 0) - fixed = 0; - - width -= fixed; - } - - if (max_width >= 0 && width > max_width) width = max_width; - if (min_width > 0 && width < min_width) width = min_width; - - } else { - if (max_width >= 0 && width > max_width) width = max_width; - if (min_width > 0 && width < min_width) width = min_width; - width -= scrollbar_width_y; - } - - box->width = width; - box->height = height; - - if (margin[TOP] == AUTO) - margin[TOP] = 0; - if (margin[BOTTOM] == AUTO) - margin[BOTTOM] = 0; -} - - -/** - * Layout the contents of a float or inline block. - * - * \param b float or inline block box - * \param width available width - * \param content memory pool for any new boxes - * \return true on success, false on memory exhaustion - */ -static bool layout_float(struct box *b, int width, html_content *content) -{ - assert(b->type == BOX_TABLE || b->type == BOX_BLOCK || - b->type == BOX_INLINE_BLOCK); - layout_float_find_dimensions(width, b->style, b); - if (b->type == BOX_TABLE) { - if (!layout_table(b, width, content)) - return false; - if (b->margin[LEFT] == AUTO) - b->margin[LEFT] = 0; - if (b->margin[RIGHT] == AUTO) - b->margin[RIGHT] = 0; - if (b->margin[TOP] == AUTO) - b->margin[TOP] = 0; - if (b->margin[BOTTOM] == AUTO) - b->margin[BOTTOM] = 0; - } else - return layout_block_context(b, -1, content); - return true; -} - - -/** - * Position a float in the first available space. - * - * \param c float box to position - * \param width available width - * \param cx x coordinate relative to cont to place float right of - * \param y y coordinate relative to cont to place float below - * \param cont ancestor box which defines horizontal space, for floats - */ -static void -place_float_below(struct box *c, int width, int cx, int y, struct box *cont) -{ - int x0, x1, yy; - struct box *left; - struct box *right; - - yy = y > cont->cached_place_below_level ? - y : cont->cached_place_below_level; - -#ifdef LAYOUT_DEBUG - LOG("c %p, width %i, cx %i, y %i, cont %p", c, width, cx, y, cont); -#endif - - do { - y = yy; - x0 = cx; - x1 = cx + width; - find_sides(cont->float_children, y, y + c->height, &x0, &x1, - &left, &right); - if (left != 0 && right != 0) { - yy = (left->y + left->height < - right->y + right->height ? - left->y + left->height : - right->y + right->height); - } else if (left == 0 && right != 0) { - yy = right->y + right->height; - } else if (left != 0 && right == 0) { - yy = left->y + left->height; - } - } while ((left != 0 || right != 0) && (c->width > x1 - x0)); - - if (c->type == BOX_FLOAT_LEFT) { - c->x = x0; - } else { - c->x = x1 - c->width; - } - c->y = y; - cont->cached_place_below_level = y; -} - - -/** - * Position a line of boxes in inline formatting context. - * - * \param first box at start of line - * \param width available width on input, updated with actual width on output - * (may be incorrect if the line gets split?) - * \param y coordinate of top of line, updated on exit to bottom - * \param cx coordinate of left of line relative to cont - * \param cy coordinate of top of line relative to cont - * \param cont ancestor box which defines horizontal space, for floats - * \param indent apply any first-line indent - * \param has_text_children at least one TEXT in the inline_container - * \param next_box updated to first box for next line, or 0 at end - * \param content memory pool for any new boxes - * \return true on success, false on memory exhaustion - */ -static bool -layout_line(struct box *first, - int *width, - int *y, - int cx, - int cy, - struct box *cont, - bool indent, - bool has_text_children, - html_content *content, - struct box **next_box) -{ - int height, used_height; - int x0 = 0; - int x1 = *width; - int x, h, x_previous; - int fy = cy; - struct box *left; - struct box *right; - struct box *b; - struct box *split_box = 0; - struct box *d; - struct box *br_box = 0; - bool move_y = false; - bool place_below = false; - int space_before = 0, space_after = 0; - unsigned int inline_count = 0; - unsigned int i; - const struct gui_layout_table *font_func = content->font_func; - plot_font_style_t fstyle; - -#ifdef LAYOUT_DEBUG - LOG("first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i", first, (int)first->length, first->text, *width, *y, cx, cy); -#endif - - /* find sides at top of line */ - x0 += cx; - x1 += cx; - find_sides(cont->float_children, cy, cy, &x0, &x1, &left, &right); - x0 -= cx; - x1 -= cx; - - if (indent) - x0 += layout_text_indent(first->parent->parent->style, *width); - - if (x1 < x0) - x1 = x0; - - /* get minimum line height from containing block. - * this is the line-height if there are text children and also in the - * case of an initially empty text input */ - if (has_text_children || first->parent->parent->gadget) - used_height = height = - line_height(first->parent->parent->style); - else - /* inline containers with no text are usually for layout and - * look better with no minimum line-height */ - used_height = height = 0; - - /* pass 1: find height of line assuming sides at top of line: loop - * body executed at least once - * keep in sync with the loop in layout_minmax_line() */ -#ifdef LAYOUT_DEBUG - LOG("x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0); -#endif - - for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) { - int min_width, max_width, min_height, max_height; - - assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK || - b->type == BOX_FLOAT_LEFT || - b->type == BOX_FLOAT_RIGHT || - b->type == BOX_BR || b->type == BOX_TEXT || - b->type == BOX_INLINE_END); - -#ifdef LAYOUT_DEBUG - LOG("pass 1: b %p, x %i", b, x); -#endif - - if (b->type == BOX_BR) - break; - - if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT) - continue; - if (b->type == BOX_INLINE_BLOCK && - (css_computed_position(b->style) == - CSS_POSITION_ABSOLUTE || - css_computed_position(b->style) == - CSS_POSITION_FIXED)) - continue; - - assert(b->style != NULL); - font_plot_style_from_css(b->style, &fstyle); - - x += space_after; - - if (b->type == BOX_INLINE_BLOCK) { - if (b->max_width != UNKNOWN_WIDTH) - if (!layout_float(b, *width, content)) - return false; - h = b->border[TOP].width + b->padding[TOP] + b->height + - b->padding[BOTTOM] + - b->border[BOTTOM].width; - if (height < h) - height = h; - x += b->margin[LEFT] + b->border[LEFT].width + - b->padding[LEFT] + b->width + - b->padding[RIGHT] + - b->border[RIGHT].width + - b->margin[RIGHT]; - space_after = 0; - continue; - } - - if (b->type == BOX_INLINE) { - /* calculate borders, margins, and padding */ - layout_find_dimensions(*width, -1, b, b->style, 0, 0, - 0, 0, 0, 0, b->margin, b->padding, - b->border); - for (i = 0; i != 4; i++) - if (b->margin[i] == AUTO) - b->margin[i] = 0; - x += b->margin[LEFT] + b->border[LEFT].width + - b->padding[LEFT]; - if (b->inline_end) { - b->inline_end->margin[RIGHT] = b->margin[RIGHT]; - b->inline_end->padding[RIGHT] = - b->padding[RIGHT]; - b->inline_end->border[RIGHT] = - b->border[RIGHT]; - } else { - x += b->padding[RIGHT] + - b->border[RIGHT].width + - b->margin[RIGHT]; - } - } else if (b->type == BOX_INLINE_END) { - b->width = 0; - if (b->space == UNKNOWN_WIDTH) { - font_func->width(&fstyle, " ", 1, &b->space); - /** \todo handle errors */ - } - space_after = b->space; - - x += b->padding[RIGHT] + b->border[RIGHT].width + - b->margin[RIGHT]; - continue; - } - - if (!b->object && !(b->flags & IFRAME) && !b->gadget && - !(b->flags & REPLACE_DIM)) { - /* inline non-replaced, 10.3.1 and 10.6.1 */ - b->height = line_height(b->style ? b->style : - b->parent->parent->style); - if (height < b->height) - height = b->height; - - if (!b->text) { - b->width = 0; - space_after = 0; - continue; - } - - if (b->width == UNKNOWN_WIDTH) { - /** \todo handle errors */ - - /* If it's a select element, we must use the - * width of the widest option text */ - if (b->parent->parent->gadget && - b->parent->parent->gadget->type - == GADGET_SELECT) { - int opt_maxwidth = 0; - struct form_option *o; - - for (o = b->parent->parent->gadget-> - data.select.items; o; - o = o->next) { - int opt_width; - font_func->width(&fstyle, - o->text, - strlen(o->text), - &opt_width); - - if (opt_maxwidth < opt_width) - opt_maxwidth =opt_width; - } - b->width = opt_maxwidth; - if (nsoption_bool(core_select_menu)) - b->width += SCROLLBAR_WIDTH; - } else { - font_func->width(&fstyle, b->text, - b->length, &b->width); - b->flags |= MEASURED; - } - } - - /* If the current text has not been measured (i.e. its - * width was estimated after splitting), and it fits on - * the line, measure it properly, so next box is placed - * correctly. */ - if (b->text && (x + b->width < x1 - x0) && - !(b->flags & MEASURED) && - b->next) { - font_func->width(&fstyle, b->text, - b->length, &b->width); - b->flags |= MEASURED; - } - - x += b->width; - if (b->space == UNKNOWN_WIDTH) { - font_func->width(&fstyle, " ", 1, &b->space); - /** \todo handle errors */ - } - space_after = b->space; - continue; - } - - space_after = 0; - - /* inline replaced, 10.3.2 and 10.6.2 */ - assert(b->style); - - layout_find_dimensions(*width, -1, b, b->style, - &b->width, &b->height, &max_width, &min_width, - &max_height, &min_height, NULL, NULL, NULL); - - if (b->object && !(b->flags & REPLACE_DIM)) { - layout_get_object_dimensions(b, &b->width, &b->height, - min_width, max_width, - min_height, max_height); - } else if (b->flags & IFRAME) { - /* TODO: should we look at the content dimensions? */ - if (b->width == AUTO) - b->width = 400; - if (b->height == AUTO) - b->height = 300; - - /* We reformat the iframe browser window to new - * dimensions in pass 2 */ - } else { - /* form control with no object */ - if (b->width == AUTO) - b->width = FIXTOINT(nscss_len2px(INTTOFIX(1), - CSS_UNIT_EM, b->style)); - if (b->height == AUTO) - b->height = FIXTOINT(nscss_len2px(INTTOFIX(1), - CSS_UNIT_EM, b->style)); - } - - /* Reformat object to new box size */ - if (b->object && content_get_type(b->object) == CONTENT_HTML && - b->width != - content_get_available_width(b->object)) { - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - enum css_height_e htype = css_computed_height(b->style, - &value, &unit); - - content_reformat(b->object, false, b->width, b->height); - - if (htype == CSS_HEIGHT_AUTO) - b->height = content_get_height(b->object); - } - - if (height < b->height) - height = b->height; - - x += b->width; - } - - /* find new sides using this height */ - x0 = cx; - x1 = cx + *width; - find_sides(cont->float_children, cy, cy + height, &x0, &x1, - &left, &right); - x0 -= cx; - x1 -= cx; - - if (indent) - x0 += layout_text_indent(first->parent->parent->style, *width); - - if (x1 < x0) - x1 = x0; - - space_after = space_before = 0; - - /* pass 2: place boxes in line: loop body executed at least once */ -#ifdef LAYOUT_DEBUG - LOG("x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0); -#endif - - for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) { -#ifdef LAYOUT_DEBUG - LOG("pass 2: b %p, x %i", b, x); -#endif - - if (b->type == BOX_INLINE_BLOCK && - (css_computed_position(b->style) == - CSS_POSITION_ABSOLUTE || - css_computed_position(b->style) == - CSS_POSITION_FIXED)) { - b->x = x + space_after; - - } else if (b->type == BOX_INLINE || - b->type == BOX_INLINE_BLOCK || - b->type == BOX_TEXT || - b->type == BOX_INLINE_END) { - assert(b->width != UNKNOWN_WIDTH); - - x_previous = x; - x += space_after; - b->x = x; - - if ((b->type == BOX_INLINE && !b->inline_end) || - b->type == BOX_INLINE_BLOCK) { - b->x += b->margin[LEFT] + b->border[LEFT].width; - x = b->x + b->padding[LEFT] + b->width + - b->padding[RIGHT] + - b->border[RIGHT].width + - b->margin[RIGHT]; - } else if (b->type == BOX_INLINE) { - b->x += b->margin[LEFT] + b->border[LEFT].width; - x = b->x + b->padding[LEFT] + b->width; - } else if (b->type == BOX_INLINE_END) { - b->height = b->inline_end->height; - x += b->padding[RIGHT] + - b->border[RIGHT].width + - b->margin[RIGHT]; - } else { - x += b->width; - } - - space_before = space_after; - if (b->object || b->flags & REPLACE_DIM || - b->flags & IFRAME) - space_after = 0; - else if (b->text || b->type == BOX_INLINE_END) { - if (b->space == UNKNOWN_WIDTH) { - font_plot_style_from_css(b->style, - &fstyle); - /** \todo handle errors */ - font_func->width(&fstyle, " ", 1, - &b->space); - } - space_after = b->space; - } else { - space_after = 0; - } - split_box = b; - move_y = true; - inline_count++; - } else if (b->type == BOX_BR) { - b->x = x; - b->width = 0; - br_box = b; - b = b->next; - split_box = 0; - move_y = true; - break; - - } else { - /* float */ -#ifdef LAYOUT_DEBUG - LOG("float %p", b); -#endif - - d = b->children; - d->float_children = 0; - d->cached_place_below_level = 0; - b->float_container = d->float_container = cont; - - if (!layout_float(d, *width, content)) - return false; - -#ifdef LAYOUT_DEBUG - LOG("%p : %d %d", d, d->margin[TOP], d->border[TOP].width); -#endif - - d->x = d->margin[LEFT] + d->border[LEFT].width; - d->y = d->margin[TOP] + d->border[TOP].width; - b->width = d->margin[LEFT] + d->border[LEFT].width + - d->padding[LEFT] + d->width + - d->padding[RIGHT] + - d->border[RIGHT].width + - d->margin[RIGHT]; - b->height = d->margin[TOP] + d->border[TOP].width + - d->padding[TOP] + d->height + - d->padding[BOTTOM] + - d->border[BOTTOM].width + - d->margin[BOTTOM]; - - if (b->width > (x1 - x0) - x) - place_below = true; - if (d->style && (css_computed_clear(d->style) == - CSS_CLEAR_NONE || - (css_computed_clear(d->style) == - CSS_CLEAR_LEFT && left == 0) || - (css_computed_clear(d->style) == - CSS_CLEAR_RIGHT && - right == 0) || - (css_computed_clear(d->style) == - CSS_CLEAR_BOTH && - left == 0 && right == 0)) && - (!place_below || - (left == 0 && right == 0 && x == 0)) && - cy >= cont->clear_level && - cy >= cont->cached_place_below_level) { - /* + not cleared or, - * cleared and there are no floats to clear - * + fits without needing to be placed below or, - * this line is empty with no floats - * + current y, cy, is below the clear level - * - * Float affects current line */ - if (b->type == BOX_FLOAT_LEFT) { - b->x = cx + x0; - if (b->width > 0) - x0 += b->width; - left = b; - } else { - b->x = cx + x1 - b->width; - if (b->width > 0) - x1 -= b->width; - right = b; - } - b->y = cy; - } else { - /* cleared or doesn't fit on line */ - /* place below into next available space */ - int fcy = (cy > cont->clear_level) ? cy : - cont->clear_level; - fcy = (fcy > cont->cached_place_below_level) ? - fcy : - cont->cached_place_below_level; - fy = (fy > fcy) ? fy : fcy; - fy = (fy == cy) ? fy + height : fy; - - place_float_below(b, *width, cx, fy, cont); - fy = b->y; - if (d->style && ( - (css_computed_clear(d->style) == - CSS_CLEAR_LEFT && left != 0) || - (css_computed_clear(d->style) == - CSS_CLEAR_RIGHT && - right != 0) || - (css_computed_clear(d->style) == - CSS_CLEAR_BOTH && - (left != 0 || right != 0)))) { - /* to be cleared below existing - * floats */ - if (b->type == BOX_FLOAT_LEFT) - b->x = cx; - else - b->x = cx + *width - b->width; - - fcy = layout_clear(cont->float_children, - css_computed_clear(d->style)); - if (fcy > cont->clear_level) - cont->clear_level = fcy; - if (b->y < fcy) - b->y = fcy; - } - if (b->type == BOX_FLOAT_LEFT) - left = b; - else - right = b; - } - add_float_to_container(cont, b); - - split_box = 0; - } - } - - if (x1 - x0 < x && split_box) { - /* the last box went over the end */ - size_t split = 0; - int w; - bool no_wrap = css_computed_white_space( - split_box->style) == CSS_WHITE_SPACE_NOWRAP || - css_computed_white_space( - split_box->style) == CSS_WHITE_SPACE_PRE; - - x = x_previous; - - if (!no_wrap && - (split_box->type == BOX_INLINE || - split_box->type == BOX_TEXT) && - !split_box->object && - !(split_box->flags & REPLACE_DIM) && - !(split_box->flags & IFRAME) && - !split_box->gadget && split_box->text) { - - font_plot_style_from_css(split_box->style, &fstyle); - /** \todo handle errors */ - font_func->split(&fstyle, - split_box->text, - split_box->length, - x1 - x0 - x - space_before, - &split, - &w); - } - - /* split == 0 implies that text can't be split */ - - if (split == 0) - w = split_box->width; - -#ifdef LAYOUT_DEBUG - LOG("splitting: split_box %p \"%.*s\", spilt %zu, w %i, ""left %p, right %p, inline_count %u", split_box, (int)split_box->length, split_box->text, split, w, left, right, inline_count); -#endif - - if ((split == 0 || x1 - x0 <= x + space_before + w) && - !left && !right && inline_count == 1) { - /* first word of box doesn't fit, but no floats and - * first box on line so force in */ - if (split == 0 || split == split_box->length) { - /* only one word in this box, or not text - * or white-space:nowrap */ - b = split_box->next; - } else { - /* cut off first word for this line */ - if (!layout_text_box_split(content, &fstyle, - split_box, split, w)) - return false; - b = split_box->next; - } - x += space_before + w; -#ifdef LAYOUT_DEBUG - LOG("forcing"); -#endif - } else if ((split == 0 || x1 - x0 <= x + space_before + w) && - inline_count == 1) { - /* first word of first box doesn't fit, but a float is - * taking some of the width so move below it */ - assert(left || right); - used_height = 0; - if (left) { -#ifdef LAYOUT_DEBUG - LOG("cy %i, left->y %i, left->height %i", cy, left->y, left->height); -#endif - used_height = left->y + left->height - cy + 1; -#ifdef LAYOUT_DEBUG - LOG("used_height %i", used_height); -#endif - } - if (right && used_height < - right->y + right->height - cy + 1) - used_height = right->y + right->height - cy + 1; - - if (used_height < 0) - used_height = 0; - - b = split_box; -#ifdef LAYOUT_DEBUG - LOG("moving below float"); -#endif - } else if (split == 0 || x1 - x0 <= x + space_before + w) { - /* first word of box doesn't fit so leave box for next - * line */ - b = split_box; -#ifdef LAYOUT_DEBUG - LOG("leaving for next line"); -#endif - } else { - /* fit as many words as possible */ - assert(split != 0); -#ifdef LAYOUT_DEBUG - LOG("'%.*s' %i %zu %i", (int)split_box->length, split_box->text, x1 - x0, split, w); -#endif - if (split != split_box->length) { - if (!layout_text_box_split(content, &fstyle, - split_box, split, w)) - return false; - b = split_box->next; - } - x += space_before + w; -#ifdef LAYOUT_DEBUG - LOG("fitting words"); -#endif - } - move_y = true; - } - - /* set positions */ - switch (css_computed_text_align(first->parent->parent->style)) { - case CSS_TEXT_ALIGN_RIGHT: - case CSS_TEXT_ALIGN_LIBCSS_RIGHT: - x0 = x1 - x; - break; - case CSS_TEXT_ALIGN_CENTER: - case CSS_TEXT_ALIGN_LIBCSS_CENTER: - x0 = (x0 + (x1 - x)) / 2; - break; - case CSS_TEXT_ALIGN_LEFT: - case CSS_TEXT_ALIGN_LIBCSS_LEFT: - case CSS_TEXT_ALIGN_JUSTIFY: - /* leave on left */ - break; - case CSS_TEXT_ALIGN_DEFAULT: - /* None; consider text direction */ - switch (css_computed_direction(first->parent->parent->style)) { - case CSS_DIRECTION_LTR: - /* leave on left */ - break; - case CSS_DIRECTION_RTL: - x0 = x1 - x; - break; - } - break; - } - - for (d = first; d != b; d = d->next) { - d->flags &= ~NEW_LINE; - - if (d->type == BOX_INLINE_BLOCK && - (css_computed_position(d->style) == - CSS_POSITION_ABSOLUTE || - css_computed_position(d->style) == - CSS_POSITION_FIXED)) { - /* positioned inline-blocks: - * set static position (x,y) only, rest of positioning - * is handled later */ - d->x += x0; - d->y = *y; - continue; - } else if ((d->type == BOX_INLINE && - ((d->object || d->gadget) == false) && - !(d->flags & IFRAME) && - !(d->flags & REPLACE_DIM)) || - d->type == BOX_BR || - d->type == BOX_TEXT || - d->type == BOX_INLINE_END) { - /* regular (non-replaced) inlines */ - d->x += x0; - d->y = *y - d->padding[TOP]; - - if (d->type == BOX_TEXT && d->height > used_height) { - /* text */ - used_height = d->height; - } - } else if ((d->type == BOX_INLINE) || - d->type == BOX_INLINE_BLOCK) { - /* replaced inlines and inline-blocks */ - d->x += x0; - d->y = *y + d->border[TOP].width + d->margin[TOP]; - h = d->margin[TOP] + d->border[TOP].width + - d->padding[TOP] + d->height + - d->padding[BOTTOM] + - d->border[BOTTOM].width + - d->margin[BOTTOM]; - if (used_height < h) - used_height = h; - } - } - - first->flags |= NEW_LINE; - - assert(b != first || (move_y && 0 < used_height && (left || right))); - - /* handle vertical-align by adjusting box y values */ - /** \todo proper vertical alignment handling */ - for (d = first; d != b; d = d->next) { - if ((d->type == BOX_INLINE && d->inline_end) || - d->type == BOX_BR || - d->type == BOX_TEXT || - d->type == BOX_INLINE_END) { - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - switch (css_computed_vertical_align(d->style, &value, - &unit)) { - case CSS_VERTICAL_ALIGN_SUPER: - case CSS_VERTICAL_ALIGN_TOP: - case CSS_VERTICAL_ALIGN_TEXT_TOP: - /* already at top */ - break; - case CSS_VERTICAL_ALIGN_SUB: - case CSS_VERTICAL_ALIGN_BOTTOM: - case CSS_VERTICAL_ALIGN_TEXT_BOTTOM: - d->y += used_height - d->height; - break; - default: - case CSS_VERTICAL_ALIGN_BASELINE: - d->y += 0.75 * (used_height - d->height); - break; - } - } - } - - /* handle clearance for br */ - if (br_box && css_computed_clear(br_box->style) != CSS_CLEAR_NONE) { - int clear_y = layout_clear(cont->float_children, - css_computed_clear(br_box->style)); - if (used_height < clear_y - cy) - used_height = clear_y - cy; - } - - if (move_y) - *y += used_height; - *next_box = b; - *width = x; /* return actual width */ - return true; -} - - -/* exported function documented in render/layout.h */ -bool layout_inline_container(struct box *inline_container, int width, - struct box *cont, int cx, int cy, html_content *content) -{ - bool first_line = true; - bool has_text_children; - struct box *c, *next; - int y = 0; - int curwidth,maxwidth = width; - - assert(inline_container->type == BOX_INLINE_CONTAINER); - -#ifdef LAYOUT_DEBUG - LOG("inline_container %p, width %i, cont %p, cx %i, cy %i", inline_container, width, cont, cx, cy); -#endif - - has_text_children = false; - for (c = inline_container->children; c; c = c->next) { - bool is_pre = false; - - if (c->style) { - enum css_white_space_e whitespace; - - whitespace = css_computed_white_space(c->style); - - is_pre = (whitespace == CSS_WHITE_SPACE_PRE || - whitespace == CSS_WHITE_SPACE_PRE_LINE || - whitespace == CSS_WHITE_SPACE_PRE_WRAP); - } - - if ((!c->object && !(c->flags & REPLACE_DIM) && - !(c->flags & IFRAME) && - c->text && (c->length || is_pre)) || - c->type == BOX_BR) - has_text_children = true; - } - - /** \todo fix wrapping so that a box with horizontal scrollbar will - * shrink back to 'width' if no word is wider than 'width' (Or just set - * curwidth = width and have the multiword lines wrap to the min width) - */ - for (c = inline_container->children; c; ) { -#ifdef LAYOUT_DEBUG - LOG("c %p", c); -#endif - curwidth = inline_container->width; - if (!layout_line(c, &curwidth, &y, cx, cy + y, cont, first_line, - has_text_children, content, &next)) - return false; - maxwidth = max(maxwidth,curwidth); - c = next; - first_line = false; - } - - inline_container->width = maxwidth; - inline_container->height = y; - - return true; -} - - -/* exported function documented in render/layout.h */ -void -layout_minmax_table(struct box *table, const struct gui_layout_table *font_func) -{ - unsigned int i, j; - int border_spacing_h = 0; - int table_min = 0, table_max = 0; - int extra_fixed = 0; - float extra_frac = 0; - struct column *col = table->col; - struct box *row_group, *row, *cell; - enum css_width_e wtype; - css_fixed value = 0; - css_unit unit = CSS_UNIT_PX; - - /* check if the widths have already been calculated */ - if (table->max_width != UNKNOWN_MAX_WIDTH) - return; - - /* start with 0 except for fixed-width columns */ - for (i = 0; i != table->columns; i++) { - if (col[i].type == COLUMN_WIDTH_FIXED) - col[i].min = col[i].max = col[i].width; - else - col[i].min = col[i].max = 0; - } - - /* border-spacing is used in the separated borders model */ - if (css_computed_border_collapse(table->style) == - CSS_BORDER_COLLAPSE_SEPARATE) { - css_fixed h = 0, v = 0; - css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX; - - css_computed_border_spacing(table->style, &h, &hu, &v, &vu); - - border_spacing_h = FIXTOINT(nscss_len2px(h, hu, table->style)); - } - - /* 1st pass: consider 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) { - assert(cell->type == BOX_TABLE_CELL); - assert(cell->style); - /** TODO: Handle colspan="0" correctly. - * It's currently converted to 1 in box normaisation */ - assert(cell->columns != 0); - - if (cell->columns != 1) - continue; - - layout_minmax_block(cell, font_func); - i = cell->start_column; - - if (col[i].positioned) - continue; - - /* update column min, max widths using cell widths */ - if (col[i].min < cell->min_width) - col[i].min = cell->min_width; - if (col[i].max < cell->max_width) - col[i].max = cell->max_width; - } - - /* 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 flexible_columns = 0; - int min = 0, max = 0, fixed_width = 0, extra; - - if (cell->columns == 1) - continue; - - layout_minmax_block(cell, font_func); - i = cell->start_column; - - /* find min width so far of spanned columns, and count - * number of non-fixed spanned columns and total fixed width */ - for (j = 0; j != cell->columns; j++) { - min += col[i + j].min; - if (col[i + j].type == COLUMN_WIDTH_FIXED) - fixed_width += col[i + j].width; - else - flexible_columns++; - } - min += (cell->columns - 1) * border_spacing_h; - - /* distribute extra min to spanned columns */ - if (min < cell->min_width) { - if (flexible_columns == 0) { - extra = 1 + (cell->min_width - min) / - cell->columns; - for (j = 0; j != cell->columns; j++) { - col[i + j].min += extra; - if (col[i + j].max < col[i + j].min) - col[i + j].max = col[i + j].min; - } - } else { - extra = 1 + (cell->min_width - min) / - flexible_columns; - for (j = 0; j != cell->columns; j++) { - if (col[i + j].type != - COLUMN_WIDTH_FIXED) { - col[i + j].min += extra; - if (col[i + j].max < - col[i + j].min) - col[i + j].max = - col[i + j].min; - } - } - } - } - - /* find max width so far of spanned columns */ - for (j = 0; j != cell->columns; j++) - max += col[i + j].max; - max += (cell->columns - 1) * border_spacing_h; - - /* distribute extra max to spanned columns */ - if (max < cell->max_width && flexible_columns) { - extra = 1 + (cell->max_width - max) / flexible_columns; - for (j = 0; j != cell->columns; j++) - if (col[i + j].type != COLUMN_WIDTH_FIXED) - col[i + j].max += extra; - } - } - - for (i = 0; i != table->columns; i++) { - if (col[i].max < col[i].min) { - box_dump(stderr, table, 0, true); - assert(0); - } - table_min += col[i].min; - table_max += col[i].max; - } - - /* fixed width takes priority, unless it is too narrow */ - wtype = css_computed_width(table->style, &value, &unit); - if (wtype == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) { - int width = FIXTOINT(nscss_len2px(value, unit, table->style)); - if (table_min < width) - table_min = width; - if (table_max < width) - table_max = width; - } - - /* add margins, border, padding to min, max widths */ - calculate_mbp_width(table->style, LEFT, true, true, true, - &extra_fixed, &extra_frac); - calculate_mbp_width(table->style, RIGHT, true, true, true, - &extra_fixed, &extra_frac); - if (extra_fixed < 0) - extra_fixed = 0; - if (extra_frac < 0) - extra_frac = 0; - if (1.0 <= extra_frac) - extra_frac = 0.9; - table->min_width = (table_min + extra_fixed) / (1.0 - extra_frac); - table->max_width = (table_max + extra_fixed) / (1.0 - extra_frac); - table->min_width += (table->columns + 1) * border_spacing_h; - table->max_width += (table->columns + 1) * border_spacing_h; - - assert(0 <= table->min_width && table->min_width <= table->max_width); -} - - /** * Find a box's bounding box relative to itself, i.e. the box's border edge box * + * \param len_ctx Length conversion context * \param box box find bounding box of * \param desc_x0 updated to left of box's bbox * \param desc_y0 updated to top of box's bbox @@ -5068,9 +5167,11 @@ layout_minmax_table(struct box *table, const struct gui_layout_table *font_func) * \param desc_y1 updated to bottom of box's bbox */ static void -layout_get_box_bbox(struct box *box, - int *desc_x0, int *desc_y0, - int *desc_x1, int *desc_y1) +layout_get_box_bbox( + const nscss_len_ctx *len_ctx, + struct box *box, + int *desc_x0, int *desc_y0, + int *desc_x1, int *desc_y1) { *desc_x0 = -box->border[LEFT].width; *desc_y0 = -box->border[TOP].width; @@ -5090,7 +5191,8 @@ layout_get_box_bbox(struct box *box, int text_height; css_computed_font_size(box->style, &font_size, &font_unit); - text_height = nscss_len2px(font_size, font_unit, box->style); + text_height = nscss_len2px(len_ctx, font_size, font_unit, + box->style); text_height = FIXTOINT(text_height * 3 / 4); *desc_y0 = (*desc_y0 < -text_height) ? *desc_y0 : -text_height; } @@ -5100,16 +5202,19 @@ layout_get_box_bbox(struct box *box, /** * Apply changes to box descendant_[xy][01] values due to given child. * - * \param box box to update - * \param child a box, which may affect box's descendant bbox - * \param off_x offset to apply to child->x coord to treat as child of box - * \param off_y offset to apply to child->y coord to treat as child of box + * \param len_ctx Length conversion context + * \param box box to update + * \param child a box, which may affect box's descendant bbox + * \param off_x offset to apply to child->x coord to treat as child of box + * \param off_y offset to apply to child->y coord to treat as child of box */ static void -layout_update_descendant_bbox(struct box *box, - struct box *child, - int off_x, - int off_y) +layout_update_descendant_bbox( + const nscss_len_ctx *len_ctx, + struct box *box, + struct box *child, + int off_x, + int off_y) { int child_desc_x0, child_desc_y0, child_desc_x1, child_desc_y1; @@ -5129,7 +5234,8 @@ layout_update_descendant_bbox(struct box *box, } /* Get child's border edge */ - layout_get_box_bbox(child, &child_desc_x0, &child_desc_y0, + layout_get_box_bbox(len_ctx, child, + &child_desc_x0, &child_desc_y0, &child_desc_x1, &child_desc_y1); if (overflow_x == CSS_OVERFLOW_VISIBLE && @@ -5162,8 +5268,16 @@ layout_update_descendant_bbox(struct box *box, } -/* exported function documented in render/layout.h */ -void layout_calculate_descendant_bboxes(struct box *box) +/** + * Recursively calculate the descendant_[xy][01] values for a laid-out box tree + * and inform iframe browser windows of their size and position. + * + * \param len_ctx Length conversion context + * \param box tree of boxes to update + */ +static void layout_calculate_descendant_bboxes( + const nscss_len_ctx *len_ctx, + struct box *box) { struct box *child; @@ -5172,7 +5286,8 @@ void layout_calculate_descendant_bboxes(struct box *box) /* assert((box->width >= 0) && (box->height >= 0)); */ /* Initialise box's descendant box to border edge box */ - layout_get_box_bbox(box, &box->descendant_x0, &box->descendant_y0, + layout_get_box_bbox(len_ctx, box, + &box->descendant_x0, &box->descendant_y0, &box->descendant_x1, &box->descendant_y1); /* Extend it to contain HTML contents if box is replaced */ @@ -5205,7 +5320,7 @@ void layout_calculate_descendant_bboxes(struct box *box) child->type == BOX_FLOAT_RIGHT) continue; - layout_update_descendant_bbox(box, child, + layout_update_descendant_bbox(len_ctx, box, child, box->x, box->y); if (child == box->inline_end) @@ -5223,7 +5338,7 @@ void layout_calculate_descendant_bboxes(struct box *box) child->type == BOX_FLOAT_RIGHT) continue; - layout_calculate_descendant_bboxes(child); + layout_calculate_descendant_bboxes(len_ctx, child); if (box->style && css_computed_overflow_x(box->style) == CSS_OVERFLOW_HIDDEN && @@ -5231,22 +5346,73 @@ void layout_calculate_descendant_bboxes(struct box *box) CSS_OVERFLOW_HIDDEN) continue; - layout_update_descendant_bbox(box, child, 0, 0); + layout_update_descendant_bbox(len_ctx, box, child, 0, 0); } for (child = box->float_children; child; child = child->next_float) { assert(child->type == BOX_FLOAT_LEFT || child->type == BOX_FLOAT_RIGHT); - layout_calculate_descendant_bboxes(child); + layout_calculate_descendant_bboxes(len_ctx, child); - layout_update_descendant_bbox(box, child, 0, 0); + layout_update_descendant_bbox(len_ctx, box, child, 0, 0); } if (box->list_marker) { child = box->list_marker; - layout_calculate_descendant_bboxes(child); + layout_calculate_descendant_bboxes(len_ctx, child); + + layout_update_descendant_bbox(len_ctx, box, child, 0, 0); + } +} + + +/* exported function documented in render/layout.h */ +bool layout_document(html_content *content, int width, int height) +{ + bool ret; + struct box *doc = content->layout; + const struct gui_layout_table *font_func = content->font_func; + + layout_minmax_block(doc, font_func, content); + + layout_block_find_dimensions(&content->len_ctx, + width, height, 0, 0, doc); + doc->x = doc->margin[LEFT] + doc->border[LEFT].width; + doc->y = doc->margin[TOP] + doc->border[TOP].width; + width -= doc->margin[LEFT] + doc->border[LEFT].width + + doc->padding[LEFT] + doc->padding[RIGHT] + + doc->border[RIGHT].width + doc->margin[RIGHT]; + if (width < 0) { + width = 0; + } + doc->width = width; - layout_update_descendant_bbox(box, child, 0, 0); + ret = layout_block_context(doc, height, content); + + /* make <html> and <body> fill available height */ + if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] + + doc->border[BOTTOM].width + doc->margin[BOTTOM] < + height) { + doc->height = height - (doc->y + doc->padding[TOP] + + doc->padding[BOTTOM] + + doc->border[BOTTOM].width + + doc->margin[BOTTOM]); + if (doc->children) + doc->children->height = doc->height - + (doc->children->margin[TOP] + + doc->children->border[TOP].width + + doc->children->padding[TOP] + + doc->children->padding[BOTTOM] + + doc->children->border[BOTTOM].width + + doc->children->margin[BOTTOM]); } + + layout_lists(doc, font_func, &content->len_ctx); + layout_position_absolute(doc, doc, 0, 0, content); + layout_position_relative(&content->len_ctx, doc, doc, 0, 0); + + layout_calculate_descendant_bboxes(&content->len_ctx, doc); + + return ret; } diff --git a/render/layout.h b/render/layout.h index 78a30028e..cd5ddd77f 100644 --- a/render/layout.h +++ b/render/layout.h @@ -42,35 +42,4 @@ struct gui_layout_table; */ bool layout_document(struct html_content *content, int width, int height); -/** - * Layout lines of text or inline boxes with floats. - * - * \param box inline container box - * \param width horizontal space available - * \param cont ancestor box which defines horizontal space, for floats - * \param cx box position relative to cont - * \param cy box position relative to cont - * \param content memory pool for any new boxes - * \return true on success, false on memory exhaustion - */ -bool layout_inline_container(struct box *box, int width, struct box *cont, int cx, int cy, struct html_content *content); - -/** - * Recursively calculate the descendant_[xy][01] values for a laid-out box tree - * and inform iframe browser windows of their size and position. - * - * \param box tree of boxes to update - */ -void layout_calculate_descendant_bboxes(struct box *box); - -/** - * Calculate minimum and maximum width of a table. - * - * \param table box of type TABLE - * \param font_func Font functions - * \post table->min_width and table->max_width filled in, - * 0 <= table->min_width <= table->max_width - */ -void layout_minmax_table(struct box *table, const struct gui_layout_table *font_func); - #endif diff --git a/render/search.c b/render/search.c index 4af6706a0..ca9520165 100644 --- a/render/search.c +++ b/render/search.c @@ -538,7 +538,7 @@ static void search_text(const char *string, int string_len, msg_data.scroll.y0 = bounds.y0; msg_data.scroll.x1 = bounds.x1; msg_data.scroll.y1 = bounds.y1; - content_broadcast(context->c, CONTENT_MSG_SCROLL, msg_data); + content_broadcast(context->c, CONTENT_MSG_SCROLL, &msg_data); } @@ -571,7 +571,7 @@ void search_step(struct search_context *context, search_flags_t flags, msg_data.scroll.area = false; msg_data.scroll.x0 = 0; msg_data.scroll.y0 = 0; - content_broadcast(context->c, CONTENT_MSG_SCROLL, msg_data); + content_broadcast(context->c, CONTENT_MSG_SCROLL, &msg_data); return; } search_text(string, string_len, context, flags); @@ -621,13 +621,14 @@ void search_show_all(bool all, struct search_context *context) if (!a->sel) continue; - selection_init(a->sel, html->layout); + selection_init(a->sel, html->layout, + &html->len_ctx); } else { a->sel = selection_create(context->c, false); if (!a->sel) continue; - selection_init(a->sel, NULL); + selection_init(a->sel, NULL, NULL); } selection_set_start(a->sel, a->start_idx); diff --git a/render/table.c b/render/table.c index acf00c70e..08a2e805c 100644 --- a/render/table.c +++ b/render/table.c @@ -45,31 +45,57 @@ struct border { css_unit unit; /**< border-width units */ }; -static void table_used_left_border_for_cell(struct box *cell); -static void table_used_top_border_for_cell(struct box *cell); -static void table_used_right_border_for_cell(struct box *cell); -static void table_used_bottom_border_for_cell(struct box *cell); -static bool table_border_is_more_eyecatching(const struct border *a, - box_type a_src, const struct border *b, box_type b_src); -static void table_cell_top_process_table(struct box *table, struct border *a, +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); -static bool table_cell_top_process_group(struct box *cell, struct box *group, - struct border *a, box_type *a_src); -static bool table_cell_top_process_row(struct box *cell, struct box *row, - struct border *a, box_type *a_src); /** * Determine the column width types for a table. * - * \param table box of type BOX_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(struct box *table) +bool table_calculate_column_types( + const nscss_len_ctx *len_ctx, + struct box *table) { unsigned int i, j; struct column *col; @@ -109,7 +135,7 @@ bool table_calculate_column_types(struct box *table) css_computed_position(cell->style) != CSS_POSITION_FIXED) { col[i].positioned = false; - } + } type = css_computed_width(cell->style, &value, &unit); @@ -117,8 +143,8 @@ bool table_calculate_column_types(struct box *table) 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(value, unit, - cell->style)); + col[i].width = FIXTOINT(nscss_len2px(len_ctx, + value, unit, cell->style)); if (col[i].width < 0) col[i].width = 0; continue; @@ -181,7 +207,7 @@ bool table_calculate_column_types(struct box *table) if (type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT && fixed_columns + unknown_columns == cell->columns) { - int width = (FIXTOFLT(nscss_len2px(value, unit, + int width = (FIXTOFLT(nscss_len2px(len_ctx, value, unit, cell->style)) - fixed_width) / unknown_columns; if (width < 0) @@ -219,13 +245,14 @@ bool table_calculate_column_types(struct box *table) #ifdef TABLE_DEBUG for (i = 0; i != table->columns; i++) - LOG("table %p, column %u: type %s, width %i", table, i, ((const char *[]){ + 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); + "RELATIVE", + })[col[i].type], col[i].width); #endif return true; @@ -234,11 +261,14 @@ bool table_calculate_column_types(struct box *table) /** * Calculate used values of border-{trbl}-{style,color,width} for table cells. * - * \param cell Table cell to consider + * \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(struct box *cell) +void table_used_border_for_cell( + const nscss_len_ctx *len_ctx, + struct box *cell) { int side; @@ -256,7 +286,8 @@ void table_used_border_for_cell(struct box *cell) &cell->border[LEFT].c); css_computed_border_left_width(cell->style, &width, &unit); cell->border[LEFT].width = - FIXTOINT(nscss_len2px(width, unit, cell->style)); + FIXTOINT(nscss_len2px(len_ctx, + width, unit, cell->style)); /* Top border */ cell->border[TOP].style = @@ -265,7 +296,8 @@ void table_used_border_for_cell(struct box *cell) &cell->border[TOP].c); css_computed_border_top_width(cell->style, &width, &unit); cell->border[TOP].width = - FIXTOINT(nscss_len2px(width, unit, cell->style)); + FIXTOINT(nscss_len2px(len_ctx, + width, unit, cell->style)); /* Right border */ cell->border[RIGHT].style = @@ -274,7 +306,8 @@ void table_used_border_for_cell(struct box *cell) &cell->border[RIGHT].c); css_computed_border_right_width(cell->style, &width, &unit); cell->border[RIGHT].width = - FIXTOINT(nscss_len2px(width, unit, cell->style)); + FIXTOINT(nscss_len2px(len_ctx, + width, unit, cell->style)); /* Bottom border */ cell->border[BOTTOM].style = @@ -283,19 +316,20 @@ void table_used_border_for_cell(struct box *cell) &cell->border[BOTTOM].c); css_computed_border_bottom_width(cell->style, &width, &unit); cell->border[BOTTOM].width = - FIXTOINT(nscss_len2px(width, unit, cell->style)); + FIXTOINT(nscss_len2px(len_ctx, + width, unit, cell->style)); } else { /* Left border */ - table_used_left_border_for_cell(cell); + table_used_left_border_for_cell(len_ctx, cell); /* Top border */ - table_used_top_border_for_cell(cell); + table_used_top_border_for_cell(len_ctx, cell); /* Right border */ - table_used_right_border_for_cell(cell); + table_used_right_border_for_cell(len_ctx, cell); /* Bottom border */ - table_used_bottom_border_for_cell(cell); + table_used_bottom_border_for_cell(len_ctx, cell); } /* Finally, ensure that any borders configured as @@ -315,9 +349,12 @@ void table_used_border_for_cell(struct box *cell) /** * Calculate used values of border-left-{style,color,width} * - * \param cell Table cell to consider + * \param len_ctx Length conversion context + * \param cell Table cell to consider */ -void table_used_left_border_for_cell(struct box *cell) +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; @@ -328,7 +365,7 @@ void table_used_left_border_for_cell(struct box *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(a.width, a.unit, cell->style); + a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style); a.unit = CSS_UNIT_PX; a_src = BOX_TABLE_CELL; @@ -361,11 +398,12 @@ void table_used_left_border_for_cell(struct box *cell) 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(b.width, b.unit, prev->style); + 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(&a, a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, + &a, a_src, &b, b_src)) { a = b; a_src = b_src; } @@ -383,12 +421,13 @@ void table_used_left_border_for_cell(struct box *cell) row->style, &b.c); css_computed_border_left_width( row->style, &b.width, &b.unit); - b.width = nscss_len2px(b.width, b.unit, row->style); + 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(&a, a_src, - &b, b_src)) { + + if (table_border_is_more_eyecatching(len_ctx, + &a, a_src, &b, b_src)) { a = b; a_src = b_src; } @@ -402,11 +441,12 @@ void table_used_left_border_for_cell(struct box *cell) 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(b.width, b.unit, group->style); + 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(&a, a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, + &a, a_src, &b, b_src)) { a = b; a_src = b_src; } @@ -415,11 +455,12 @@ void table_used_left_border_for_cell(struct box *cell) 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(b.width, b.unit, table->style); + 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(&a, a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, + &a, a_src, &b, b_src)) { a = b; a_src = b_src; } @@ -428,16 +469,19 @@ void table_used_left_border_for_cell(struct box *cell) /* 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(a.width, a.unit, cell->style)); + 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 cell Table cell to consider + * \param len_ctx Length conversion context + * \param cell Table cell to consider */ -void table_used_top_border_for_cell(struct box *cell) +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; @@ -448,7 +492,7 @@ void table_used_top_border_for_cell(struct box *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(a.width, a.unit, cell->style); + a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style); a.unit = CSS_UNIT_PX; a_src = BOX_TABLE_CELL; @@ -456,18 +500,18 @@ void table_used_top_border_for_cell(struct box *cell) 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(b.width, b.unit, row->style); + 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(&a, a_src, &b, b_src)) { + 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(cell, row->prev, + while (table_cell_top_process_row(len_ctx, cell, row->prev, &a, &a_src) == false) { if (row->prev->prev == NULL) { /* Consider row group */ @@ -488,26 +532,29 @@ void table_used_top_border_for_cell(struct box *cell) 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(b.width, b.unit, group->style); + 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(&a, a_src, &b, b_src)) { + 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(group->parent, &a, &a_src); + table_cell_top_process_table(len_ctx, + group->parent, &a, &a_src); } else { /* Process previous group(s) */ - while (table_cell_top_process_group(cell, group->prev, + 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( - group->parent, + table_cell_top_process_table(len_ctx, + group->parent, &a, &a_src); break; } else { @@ -520,16 +567,19 @@ void table_used_top_border_for_cell(struct box *cell) /* 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(a.width, a.unit, cell->style)); + 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 cell Table cell to consider + * \param len_ctx Length conversion context + * \param cell Table cell to consider */ -void table_used_right_border_for_cell(struct box *cell) +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; @@ -540,7 +590,7 @@ void table_used_right_border_for_cell(struct box *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(a.width, a.unit, cell->style); + a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style); a.unit = CSS_UNIT_PX; a_src = BOX_TABLE_CELL; @@ -564,12 +614,13 @@ void table_used_right_border_for_cell(struct box *cell) row->style, &b.c); css_computed_border_right_width( row->style, &b.width, &b.unit); - b.width = nscss_len2px(b.width, b.unit, row->style); + 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(&a, a_src, - &b, b_src)) { + + if (table_border_is_more_eyecatching(len_ctx, + &a, a_src, &b, b_src)) { a = b; a_src = b_src; } @@ -582,13 +633,14 @@ void table_used_right_border_for_cell(struct box *cell) /* 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, + css_computed_border_right_width(group->style, &b.width, &b.unit); - b.width = nscss_len2px(b.width, b.unit, group->style); + 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(&a, a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, + &a, a_src, &b, b_src)) { a = b; a_src = b_src; } @@ -598,11 +650,12 @@ void table_used_right_border_for_cell(struct box *cell) 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(b.width, b.unit, table->style); + 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(&a, a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, + &a, a_src, &b, b_src)) { a = b; a_src = b_src; } @@ -611,16 +664,19 @@ void table_used_right_border_for_cell(struct box *cell) /* 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(a.width, a.unit, cell->style)); + 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 cell Table cell to consider + * \param len_ctx Length conversion context + * \param cell Table cell to consider */ -void table_used_bottom_border_for_cell(struct box *cell) +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; @@ -631,7 +687,7 @@ void table_used_bottom_border_for_cell(struct box *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(a.width, a.unit, cell->style); + a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style); a.unit = CSS_UNIT_PX; a_src = BOX_TABLE_CELL; @@ -655,11 +711,12 @@ void table_used_bottom_border_for_cell(struct box *cell) 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(b.width, b.unit, row->style); + 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(&a, a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, + &a, a_src, &b, b_src)) { a = b; a_src = b_src; } @@ -669,11 +726,12 @@ void table_used_bottom_border_for_cell(struct box *cell) 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(b.width, b.unit, group->style); + 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(&a, a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, + &a, a_src, &b, b_src)) { a = b; a_src = b_src; } @@ -683,11 +741,12 @@ void table_used_bottom_border_for_cell(struct box *cell) 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(b.width, b.unit, table->style); + 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(&a, a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, + &a, a_src, &b, b_src)) { a = b; } } @@ -695,21 +754,26 @@ void table_used_bottom_border_for_cell(struct box *cell) /* 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(a.width, a.unit, cell->style)); + 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 a Reference border style - * \param a_src Source of \a a - * \param b Candidate border style - * \param b_src Source of \a b + * \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 struct border *a, - box_type a_src, const struct border *b, box_type b_src) +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; @@ -730,8 +794,8 @@ bool table_border_is_more_eyecatching(const struct border *a, * 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(a->width, a->unit, NULL); - bwidth = nscss_len2px(b->width, b->unit, NULL); + 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; @@ -740,27 +804,27 @@ bool table_border_is_more_eyecatching(const struct border *a, /* 3b -- sort by style */ switch (a->style) { - case CSS_BORDER_STYLE_DOUBLE: impact++; - case CSS_BORDER_STYLE_SOLID: impact++; - case CSS_BORDER_STYLE_DASHED: impact++; - case CSS_BORDER_STYLE_DOTTED: impact++; - case CSS_BORDER_STYLE_RIDGE: impact++; - case CSS_BORDER_STYLE_OUTSET: impact++; - case CSS_BORDER_STYLE_GROOVE: impact++; - case CSS_BORDER_STYLE_INSET: impact++; + 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--; - case CSS_BORDER_STYLE_SOLID: impact--; - case CSS_BORDER_STYLE_DASHED: impact--; - case CSS_BORDER_STYLE_DOTTED: impact--; - case CSS_BORDER_STYLE_RIDGE: impact--; - case CSS_BORDER_STYLE_OUTSET: impact--; - case CSS_BORDER_STYLE_GROOVE: impact--; - case CSS_BORDER_STYLE_INSET: impact--; + 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; } @@ -773,22 +837,22 @@ bool table_border_is_more_eyecatching(const struct border *a, /* 4a -- sort by origin */ impact = 0; - switch (a_src) { - case BOX_TABLE_CELL: impact++; - case BOX_TABLE_ROW: impact++; - case BOX_TABLE_ROW_GROUP: impact++; /** \todo COL/COL_GROUP */ - case BOX_TABLE: impact++; + 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; } - switch (b_src) { - case BOX_TABLE_CELL: impact--; - case BOX_TABLE_ROW: impact--; - case BOX_TABLE_ROW_GROUP: impact--; /** \todo COL/COL_GROUP */ - case BOX_TABLE: impact--; + 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; } @@ -810,14 +874,18 @@ bool table_border_is_more_eyecatching(const struct border *a, /** * Process a table * - * \param table Table to process - * \param a Current border style for cell - * \param a_src Source of \a a + * \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(struct box *table, struct border *a, +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; @@ -827,11 +895,11 @@ void table_cell_top_process_table(struct box *table, struct border *a, 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(b.width, b.unit, table->style); + 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(a, *a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) { *a = b; *a_src = b_src; } @@ -840,17 +908,22 @@ void table_cell_top_process_table(struct box *table, struct border *a, /** * Process a group * - * \param cell Cell being considered - * \param group Group to process - * \param a Current border style for cell - * \param a_src Source of \a a + * \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(struct box *cell, struct box *group, - struct border *a, box_type *a_src) +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; @@ -859,11 +932,11 @@ bool table_cell_top_process_group(struct box *cell, struct box *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(b.width, b.unit, group->style); + 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(a, *a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) { *a = b; *a_src = b_src; } @@ -872,7 +945,7 @@ bool table_cell_top_process_group(struct box *cell, struct box *group, /* Process rows in group, starting with last */ struct box *row = group->last; - while (table_cell_top_process_row(cell, row, + while (table_cell_top_process_row(len_ctx, cell, row, a, a_src) == false) { if (row->prev == NULL) { return false; @@ -885,11 +958,12 @@ bool table_cell_top_process_group(struct box *cell, struct box *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(b.width, b.unit, group->style); + 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(a, *a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, + a, *a_src, &b, b_src)) { *a = b; *a_src = b_src; } @@ -903,17 +977,22 @@ bool table_cell_top_process_group(struct box *cell, struct box *group, /** * Process a row * - * \param cell Cell being considered - * \param row Row to process - * \param a Current border style for cell - * \param a_src Source of \a a + * \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(struct box *cell, struct box *row, - struct border *a, box_type *a_src) +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; @@ -922,11 +1001,11 @@ bool table_cell_top_process_row(struct box *cell, struct box *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(b.width, b.unit, row->style); + 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(a, *a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) { *a = b; *a_src = b_src; } @@ -936,11 +1015,12 @@ bool table_cell_top_process_row(struct box *cell, struct box *row, 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(b.width, b.unit, row->style); + 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(a, *a_src, &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, + a, *a_src, &b, b_src)) { *a = b; *a_src = b_src; } @@ -974,13 +1054,13 @@ bool table_cell_top_process_row(struct box *cell, struct box *row, c->style, &b.c); css_computed_border_bottom_width(c->style, &b.width, &b.unit); - b.width = nscss_len2px(b.width, b.unit, - c->style); + 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(a, *a_src, - &b, b_src)) { + if (table_border_is_more_eyecatching(len_ctx, + a, *a_src, &b, b_src)) { *a = b; *a_src = b_src; } diff --git a/render/table.h b/render/table.h index ecd3043b5..2eeffe699 100644 --- a/render/table.h +++ b/render/table.h @@ -28,7 +28,11 @@ struct box; -bool table_calculate_column_types(struct box *table); -void table_used_border_for_cell(struct box *cell); +bool table_calculate_column_types( + const nscss_len_ctx *len_ctx, + struct box *table); +void table_used_border_for_cell( + const nscss_len_ctx *len_ctx, + struct box *cell); #endif diff --git a/render/textplain.c b/render/textplain.c index 5d28d9c54..0036eb5c0 100644 --- a/render/textplain.c +++ b/render/textplain.c @@ -150,7 +150,6 @@ textplain_create_internal(textplain_content *c, lwc_string *encoding) char *utf8_data; parserutils_inputstream *stream; parserutils_error error; - union content_msg_data msg_data; textplain_style.size = (nsoption_int(font_size) * FONT_SIZE_SCALE) / 10; @@ -185,8 +184,7 @@ textplain_create_internal(textplain_content *c, lwc_string *encoding) return NSERROR_OK; no_memory: - msg_data.error = messages_get("NoMemory"); - content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + content_broadcast_errorcode(&c->base, NSERROR_NOMEM); return NSERROR_NOMEM; } @@ -347,7 +345,6 @@ textplain_process_data(struct content *c, const char *data, unsigned int size) { textplain_content *text = (textplain_content *) c; parserutils_inputstream *stream = text->inputstream; - union content_msg_data msg_data; parserutils_error error; error = parserutils_inputstream_append(stream, @@ -362,8 +359,7 @@ textplain_process_data(struct content *c, const char *data, unsigned int size) return true; no_memory: - msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); + content_broadcast_errorcode(c, NSERROR_NOMEM); return false; } @@ -427,7 +423,7 @@ static void textplain_reformat(struct content *c, int width, int height) size_t line_start; nserror res; - LOG("content %p w:%d h:%d", c, width, height); + NSLOG(netsurf, INFO, "content %p w:%d h:%d", c, width, height); /* compute available columns (assuming monospaced font) - use 8 * characters for better accuracy @@ -526,7 +522,7 @@ static void textplain_reformat(struct content *c, int width, int height) return; no_memory: - LOG("out of memory (line_count %lu)", line_count); + NSLOG(netsurf, INFO, "out of memory (line_count %lu)", line_count); return; } @@ -647,10 +643,10 @@ textplain_mouse_action(struct content *c, } msg_data.explicit_status_text = status; - content_broadcast(c, CONTENT_MSG_STATUS, msg_data); + content_broadcast(c, CONTENT_MSG_STATUS, &msg_data); msg_data.pointer = pointer; - content_broadcast(c, CONTENT_MSG_POINTER, msg_data); + content_broadcast(c, CONTENT_MSG_POINTER, &msg_data); } @@ -992,7 +988,7 @@ textplain_open(struct content *c, text->bw = bw; /* text selection */ - selection_init(&text->sel, NULL); + selection_init(&text->sel, NULL, NULL); } |