From 22640f85e0d245df817df96afa18d382e3a1b49a Mon Sep 17 00:00:00 2001 From: James Bursa Date: Sun, 22 May 2005 21:50:14 +0000 Subject: [project @ 2005-05-22 21:50:14 by bursa] Add BOX_TEXT type to distinguish boxes which came from an inline element to boxes which came from a text node. Add inline_parent pointer to box structure. Rewrite text-decoration support to take advantage of the new data (line colours are now correct). Note: there is a clipping issue in redraw. svn path=/import/netsurf/; revision=1732 --- render/box.c | 4 ++ render/box.h | 6 +- render/box_construct.c | 29 +++++---- render/box_normalise.c | 9 ++- render/html_redraw.c | 171 ++++++++++++++++++++++++++++++++++++++----------- render/layout.c | 14 ++-- 6 files changed, 176 insertions(+), 57 deletions(-) (limited to 'render') diff --git a/render/box.c b/render/box.c index f00b8aa1d..51db3c0cf 100644 --- a/render/box.c +++ b/render/box.c @@ -76,6 +76,7 @@ struct box * box_create(struct css_style *style, box->last = NULL; box->parent = NULL; box->fallback = NULL; + box->inline_parent = NULL; box->float_children = NULL; box->next_float = NULL; box->col = NULL; @@ -457,6 +458,7 @@ void box_dump(struct box *box, unsigned int depth) case BOX_FLOAT_LEFT: fprintf(stderr, "FLOAT_LEFT "); break; case BOX_FLOAT_RIGHT: fprintf(stderr, "FLOAT_RIGHT "); break; case BOX_BR: fprintf(stderr, "BR "); break; + case BOX_TEXT: fprintf(stderr, "TEXT "); break; default: fprintf(stderr, "Unknown box type "); } @@ -474,6 +476,8 @@ void box_dump(struct box *box, unsigned int depth) fprintf(stderr, " [%s]", box->title); if (box->id != 0) fprintf(stderr, " <%s>", box->id); + if (box->inline_parent) + fprintf(stderr, " inline_parent %p", box->inline_parent); if (box->float_children) fprintf(stderr, " float_children %p", box->float_children); if (box->next_float) diff --git a/render/box.h b/render/box.h index 60aba1ba5..9bef5edd3 100644 --- a/render/box.h +++ b/render/box.h @@ -141,7 +141,8 @@ struct box { int min_width; int max_width; /**< Width that would be taken with no line breaks. */ - unsigned byte_offset; /**< byte offset within a textual representation of this content */ + /**< Byte offset within a textual representation of this content. */ + size_t byte_offset; char *text; /**< Text, or 0 if none. Unterminated. */ size_t length; /**< Length of text. */ @@ -165,6 +166,9 @@ struct box { struct box *last; /**< Last child box, or 0. */ struct box *parent; /**< Parent box, or 0. */ struct box *fallback; /**< Fallback children for object, or 0. */ + /** Box of type INLINE which contains this box in the document tree + * (only valid for TEXT boxes). */ + struct box *inline_parent; /** First float child box, or 0. Float boxes are in the tree twice, in * this list for the block box which defines the area for floats, and diff --git a/render/box_construct.c b/render/box_construct.c index 57046120f..d6841bf7b 100644 --- a/render/box_construct.c +++ b/render/box_construct.c @@ -72,14 +72,17 @@ static const content_type image_types[] = { static bool convert_xml_to_box(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, + struct box *inline_parent, char *href, char *title); bool box_construct_element(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, + struct box *inline_parent, char *href, char *title); bool box_construct_text(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, + struct box *inline_parent, char *href, char *title); static struct css_style * box_get_style(struct content *c, struct css_style *parent_style, @@ -174,7 +177,7 @@ bool xml_to_box(xmlNode *n, struct content *c) c->data.html.object = 0; if (!convert_xml_to_box(n, c, c->data.html.style, &root, - &inline_container, 0, 0)) + &inline_container, 0, 0, 0)) return false; if (!box_normalise_block(&root, c)) return false; @@ -224,15 +227,16 @@ static const box_type box_map[] = { bool convert_xml_to_box(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, + struct box *inline_parent, char *href, char *title) { switch (n->type) { case XML_ELEMENT_NODE: return box_construct_element(n, content, parent_style, parent, - inline_container, href, title); + inline_container, inline_parent, href, title); case XML_TEXT_NODE: return box_construct_text(n, content, parent_style, parent, - inline_container, href, title); + inline_container, inline_parent, href, title); default: /* not an element or text node: ignore it (eg. comment) */ return true; @@ -256,6 +260,7 @@ bool convert_xml_to_box(xmlNode *n, struct content *content, bool box_construct_element(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, + struct box *inline_parent, char *href, char *title) { bool convert_children = true; @@ -335,10 +340,11 @@ bool box_construct_element(xmlNode *n, struct content *content, if (box->type == BOX_INLINE || box->type == BOX_BR) { /* inline box: add to tree and recurse */ + box->inline_parent = inline_parent; box_add_child(*inline_container, box); for (c = n->children; convert_children && c; c = c->next) if (!convert_xml_to_box(c, content, style, parent, - inline_container, href, title)) + inline_container, box, href, title)) return false; } else if (box->type == BOX_INLINE_BLOCK) { /* inline block box: add to tree and recurse */ @@ -346,7 +352,7 @@ bool box_construct_element(xmlNode *n, struct content *content, inline_container_c = 0; for (c = n->children; convert_children && c; c = c->next) if (!convert_xml_to_box(c, content, style, box, - &inline_container_c, href, title)) + &inline_container_c, 0, href, title)) return false; } else { if (style->float_ == CSS_FLOAT_LEFT || @@ -373,7 +379,7 @@ bool box_construct_element(xmlNode *n, struct content *content, inline_container_c = 0; for (c = n->children; convert_children && c; c = c->next) if (!convert_xml_to_box(c, content, style, box, - &inline_container_c, href, title)) + &inline_container_c, 0, href, title)) return false; if (style->float_ == CSS_FLOAT_NONE) /* new inline container unless this is a float */ @@ -486,6 +492,7 @@ bool box_construct_element(xmlNode *n, struct content *content, bool box_construct_text(xmlNode *n, struct content *content, struct css_style *parent_style, struct box *parent, struct box **inline_container, + struct box *inline_parent, char *href, char *title) { struct box *box = 0; @@ -529,6 +536,8 @@ bool box_construct_text(xmlNode *n, struct content *content, free(text); return false; } + box->type = BOX_TEXT; + box->inline_parent = inline_parent; box->text = talloc_strdup(content, text); free(text); if (!box->text) @@ -604,7 +613,8 @@ bool box_construct_text(xmlNode *n, struct content *content, free(text); return false; } - box->type = BOX_INLINE; + box->type = BOX_TEXT; + box->inline_parent = inline_parent; box->text = talloc_strdup(content, current); if (!box->text) { free(text); @@ -648,9 +658,6 @@ struct css_style * box_get_style(struct content *c, xmlNode *n) { char *s; - unsigned int i; - unsigned int stylesheet_count = c->data.html.stylesheet_count; - struct content **stylesheet = c->data.html.stylesheet_content; struct css_style *style; struct css_style *style_new; char *url; @@ -1284,7 +1291,7 @@ bool box_object(BOX_SPECIAL_PARAMS) /* convert children and place into fallback */ for (c = n->children; c; c = c->next) { if (!convert_xml_to_box(c, content, box->style, box, - &inline_container, 0, 0)) + &inline_container, 0, 0, 0)) return false; } box->fallback = box->children; diff --git a/render/box_normalise.c b/render/box_normalise.c index e05aa077a..05e2f2d76 100644 --- a/render/box_normalise.c +++ b/render/box_normalise.c @@ -69,8 +69,8 @@ static bool box_normalise_inline_container(struct box *cont, struct content *c); * \code * parent permitted child nodes * BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE - * INLINE_CONTAINER INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR - * INLINE none + * INLINE_CONTAINER INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, TEXT + * INLINE, TEXT none * TABLE at least 1 TABLE_ROW_GROUP * TABLE_ROW_GROUP at least 1 TABLE_ROW * TABLE_ROW at least 1 TABLE_CELL @@ -114,6 +114,7 @@ bool box_normalise_block(struct box *block, struct content *c) case BOX_FLOAT_LEFT: case BOX_FLOAT_RIGHT: case BOX_BR: + case BOX_TEXT: /* should have been wrapped in inline container by convert_xml_to_box() */ assert(0); @@ -249,6 +250,7 @@ bool box_normalise_table(struct box *table, struct content * c) case BOX_FLOAT_LEFT: case BOX_FLOAT_RIGHT: case BOX_BR: + case BOX_TEXT: /* should have been wrapped in inline container by convert_xml_to_box() */ assert(0); @@ -411,6 +413,7 @@ bool box_normalise_table_row_group(struct box *row_group, case BOX_FLOAT_LEFT: case BOX_FLOAT_RIGHT: case BOX_BR: + case BOX_TEXT: /* should have been wrapped in inline container by convert_xml_to_box() */ assert(0); @@ -507,6 +510,7 @@ bool box_normalise_table_row(struct box *row, case BOX_FLOAT_LEFT: case BOX_FLOAT_RIGHT: case BOX_BR: + case BOX_TEXT: /* should have been wrapped in inline container by convert_xml_to_box() */ assert(0); @@ -640,6 +644,7 @@ bool box_normalise_inline_container(struct box *cont, struct content * c) switch (child->type) { case BOX_INLINE: case BOX_BR: + case BOX_TEXT: /* ok */ break; case BOX_INLINE_BLOCK: diff --git a/render/html_redraw.c b/render/html_redraw.c index eb7a974a3..13f1315d3 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -45,6 +45,13 @@ static bool html_redraw_file(int x, int y, int width, int height, static bool html_redraw_background(int x, int y, struct box *box, float scale, int clip_x0, int clip_y0, int clip_x1, int clip_y1, colour *background_colour); +static bool html_redraw_text_decoration(struct box *box, + int x_parent, int y_parent, float scale, + colour background_colour); +static bool html_redraw_text_decoration_inline(struct box *box, int x, int y, + float scale, colour colour, float ratio); +static bool html_redraw_text_decoration_block(struct box *box, int x, int y, + float scale, colour colour, float ratio); static bool html_redraw_scrollbars(struct box *box, float scale, int x, int y, int padding_width, int padding_height, colour background_colour); @@ -119,7 +126,6 @@ bool html_redraw_box(struct box *box, int width, height; int padding_left, padding_top, padding_width, padding_height; int x0, y0, x1, y1; - int colour; int x_scrolled, y_scrolled; /* avoid trivial FP maths */ @@ -259,6 +265,14 @@ bool html_redraw_box(struct box *box, } } + /* text decoration */ + if (box->type != BOX_TEXT && box->style && + box->style->text_decoration != + CSS_TEXT_DECORATION_NONE) + if (!html_redraw_text_decoration(box, x_parent, y_parent, + scale, current_background_color)) + return false; + if (box->object) { x_scrolled = x - box->scroll_x * scale; y_scrolled = y - box->scroll_y * scale; @@ -290,40 +304,6 @@ bool html_redraw_box(struct box *box, } else if (box->text) { bool highlighted = false; - /* antialias colour for under/overline */ - colour = html_redraw_aa(current_background_color, - /*print_text_black ? 0 :*/ box->style->color); - - if (box->style->text_decoration & - CSS_TEXT_DECORATION_UNDERLINE) { - if (!plot.line(x, - y + (int) (box->height * 0.9 * scale), - x + box->width * scale, - y + (int) (box->height * 0.9 * scale), - 0, colour, false, false)) - return false; - } - - if (box->style->text_decoration & - CSS_TEXT_DECORATION_OVERLINE) { - if (!plot.line(x, - y + (int) (box->height * 0.1 * scale), - x + box->width * scale, - y + (int) (box->height * 0.1 * scale), - 0, colour, false, false)) - return false; - } - - if (box->style->text_decoration & - CSS_TEXT_DECORATION_LINE_THROUGH) { - if (!plot.line(x, - y + (int) (box->height * 0.5 * scale), - x + box->width * scale, - y + (int) (box->height * 0.5 * scale), - 0, colour, false, false)) - return false; - } - /* is this box part of a selection? */ if (box->text && !box->object && current_redraw_browser) { unsigned start_idx; @@ -863,7 +843,7 @@ bool html_redraw_background(int x, int y, struct box *box, float scale, do { if (clip_to_children) { assert(clip_box->type == BOX_TABLE_CELL); - + /* update clip_* to the child cell */ clip_x0 = ox + (clip_box->x * scale); clip_y0 = oy + (clip_box->y * scale); @@ -875,7 +855,7 @@ bool html_redraw_background(int x, int y, struct box *box, float scale, if (clip_y0 < py0) clip_y0 = py0; if (clip_x1 > px1) clip_x1 = px1; if (clip_y1 > py1) clip_y1 = py1; - + if ((clip_x0 >= clip_x1) || (clip_y0 >= clip_y1) || (clip_box->style->background_color != TRANSPARENT) || (clip_box->background && @@ -907,7 +887,7 @@ bool html_redraw_background(int x, int y, struct box *box, float scale, repeat_x, repeat_y)) return false; } - + /* advance and loop for child clipping */ clip_box = clip_box->next; } while (clip_box && clip_to_children); @@ -915,6 +895,121 @@ bool html_redraw_background(int x, int y, struct box *box, float scale, } +/** + * Plot text decoration for a box. + * + * \param box box to plot decorations for + * \param x_parent x coordinate of parent of box + * \param y_parent y coordinate of parent of box + * \param scale scale for redraw + * \param background_colour current background colour + * \return true if successful, false otherwise + */ + +bool html_redraw_text_decoration(struct box *box, + int x_parent, int y_parent, float scale, + colour background_colour) +{ + static const css_text_decoration decoration[] = { + CSS_TEXT_DECORATION_UNDERLINE, CSS_TEXT_DECORATION_OVERLINE, + CSS_TEXT_DECORATION_LINE_THROUGH }; + static const float line_ratio[] = { 0.9, 0.5, 0.1 }; + int colour; + unsigned int i; + + /* antialias colour for under/overline */ + colour = html_redraw_aa(background_colour, box->style->color); + + if (box->type == BOX_INLINE) { + for (i = 0; i != NOF_ELEMENTS(decoration); i++) + if (box->style->text_decoration & decoration[i]) + if (!html_redraw_text_decoration_inline(box, + x_parent, y_parent, scale, + colour, line_ratio[i])) + return false; + } else { + for (i = 0; i != NOF_ELEMENTS(decoration); i++) + if (box->style->text_decoration & decoration[i]) + if (!html_redraw_text_decoration_block(box, + x_parent + box->x, + y_parent + box->y, + scale, + colour, line_ratio[i])) + return false; + } + + return true; +} + + +/** + * Plot text decoration for an inline box. + * + * \param box box to plot decorations for, of type BOX_INLINE + * \param x x coordinate of parent of box + * \param y y coordinate of parent of box + * \param scale scale for redraw + * \param colour colour for decorations + * \param ratio position of line as a ratio of line height + * \return true if successful, false otherwise + */ + +bool html_redraw_text_decoration_inline(struct box *box, int x, int y, + float scale, colour colour, float ratio) +{ + /* draw from next sibling to the sibling which has the same inline + * parent as this box (which must mean it was the next sibling of this + * inline in the HTML tree) */ + for (struct box *c = box->next; + c && c->inline_parent != box->inline_parent; + c = c->next) { + if (!plot.line((x + c->x) * scale, + (y + c->y + c->height * ratio) * scale, + (x + c->x + c->width) * scale, + (y + c->y + c->height * ratio) * scale, + 0, colour, false, false)) + return false; + } + return true; +} + + +/** + * Plot text decoration for an non-inline box. + * + * \param box box to plot decorations for, of type other than BOX_INLINE + * \param x x coordinate of box + * \param y y coordinate of box + * \param scale scale for redraw + * \param colour colour for decorations + * \param ratio position of line as a ratio of line height + * \return true if successful, false otherwise + */ + +bool html_redraw_text_decoration_block(struct box *box, int x, int y, + float scale, colour colour, float ratio) +{ + /* draw through text descendants */ + for (struct box *c = box->children; c; c = c->next) { + if (c->type == BOX_TEXT) { + if (!plot.line((x + c->x) * scale, + (y + c->y + c->height * ratio) * scale, + (x + c->x + c->width) * scale, + (y + c->y + c->height * ratio) * scale, + 0, colour, false, false)) + return false; + } else if (c->type == BOX_INLINE_CONTAINER || + c->type == BOX_BLOCK) { + if (!html_redraw_text_decoration_block(c, + x + c->x, y + c->y, + scale, colour, ratio)) + return false; + } + } + return true; +} + + /** * Plot scrollbars for a scrolling box. * diff --git a/render/layout.c b/render/layout.c index 3e6c2a367..8cf417c4e 100644 --- a/render/layout.c +++ b/render/layout.c @@ -761,7 +761,7 @@ bool layout_line(struct box *first, int width, int *y, 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_BR || b->type == BOX_TEXT); x += space_after; @@ -784,7 +784,7 @@ bool layout_line(struct box *first, int width, int *y, if (b->type == BOX_BR) break; - if (b->type != BOX_INLINE) + if (b->type != BOX_INLINE && b->type != BOX_TEXT) continue; if (!b->object && !b->gadget) { @@ -908,7 +908,8 @@ bool layout_line(struct box *first, int width, int *y, /* pass 2: place boxes in line: loop body executed at least once */ for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) { - if (b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK) { + if (b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK || + b->type == BOX_TEXT) { assert(b->width != UNKNOWN_WIDTH); x_previous = x; @@ -1000,7 +1001,9 @@ bool layout_line(struct box *first, int width, int *y, x = x_previous; - if (split_box->type == BOX_INLINE && !split_box->object && + if ((split_box->type == BOX_INLINE || + split_box->type == BOX_TEXT) && + !split_box->object && !split_box->gadget && split_box->text) { for (i = 0; i != split_box->length && split_box->text[i] != ' '; i++) @@ -1116,7 +1119,7 @@ bool layout_line(struct box *first, int width, int *y, for (d = first; d != b; d = d->next) { if (d->type == BOX_INLINE || d->type == BOX_INLINE_BLOCK || - d->type == BOX_BR) { + d->type == BOX_BR || d->type == BOX_TEXT) { d->x += x0; d->y = *y + d->border[TOP]; h = d->border[TOP] + d->padding[TOP] + d->height + @@ -1800,6 +1803,7 @@ bool calculate_inline_container_widths(struct box *box) for (child = box->children; child != 0; child = child->next) { switch (child->type) { case BOX_INLINE: + case BOX_TEXT: if (child->object) calculate_inline_replaced_widths(child, &min, &max, &line_max); -- cgit v1.2.3