diff options
author | Michael Drake <tlsa@netsurf-browser.org> | 2013-01-02 18:02:15 +0000 |
---|---|---|
committer | Michael Drake <tlsa@netsurf-browser.org> | 2013-01-02 18:02:15 +0000 |
commit | 96841ae2ff8d6a08a1ea453a7fcc14e9a8729401 (patch) | |
tree | 443573fdeaf426a62f52e105ebfc5f194d6a6fa9 /render | |
parent | 3f33f5327e783b3f4d7474007672c2c60a2969ea (diff) | |
download | netsurf-96841ae2ff8d6a08a1ea453a7fcc14e9a8729401.tar.gz netsurf-96841ae2ff8d6a08a1ea453a7fcc14e9a8729401.tar.bz2 |
Remove forward declaration.
Diffstat (limited to 'render')
-rw-r--r-- | render/html_redraw.c | 2437 |
1 files changed, 1200 insertions, 1237 deletions
diff --git a/render/html_redraw.c b/render/html_redraw.c index e7474f8c4..26bc46c98 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -53,125 +53,9 @@ #include "utils/utils.h" -static bool html_redraw_box(const html_content *html, struct box *box, - int x, int y, const struct rect *clip, float scale, - colour current_background_color, - const struct redraw_context *ctx); -static bool html_redraw_box_children(const html_content *html, struct box *box, - int x_parent, int y_parent, const struct rect *clip, - float scale, colour current_background_color, - const struct redraw_context *ctx); -static bool html_redraw_text_box(const html_content *html, struct box *box, - int x, int y, const struct rect *clip, float scale, - colour current_background_color, - const struct redraw_context *ctx); -static bool html_redraw_borders(struct box *box, int x_parent, int y_parent, - int p_width, int p_height, const struct rect *clip, - float scale, const struct redraw_context *ctx); -static bool html_redraw_inline_borders(struct box *box, struct rect b, - const struct rect *clip, float scale, bool first, bool last, - const struct redraw_context *ctx); -static bool html_redraw_border_plot(const int side, const int *p, colour c, - enum css_border_style_e style, int thickness, bool rectangular, - const struct rect *clip, const struct redraw_context *ctx); -static bool html_redraw_checkbox(int x, int y, int width, int height, - bool selected, const struct redraw_context *ctx); -static bool html_redraw_radio(int x, int y, int width, int height, - bool selected, const struct redraw_context *ctx); -static bool html_redraw_file(int x, int y, int width, int height, - struct box *box, float scale, colour background_colour, - const struct redraw_context *ctx); -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); -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 struct redraw_context *ctx); -static bool html_redraw_text_decoration(struct box *box, - int x_parent, int y_parent, float scale, - colour background_colour, const struct redraw_context *ctx); -static bool html_redraw_text_decoration_inline(struct box *box, int x, int y, - float scale, colour colour, float ratio, - const struct redraw_context *ctx); -static bool html_redraw_text_decoration_block(struct box *box, int x, int y, - float scale, colour colour, float ratio, - const struct redraw_context *ctx); - -bool html_redraw_debug = false; - -/** - * Draw a CONTENT_HTML using the current set of plotters (plot). - * - * \param c content of type CONTENT_HTML - * \param data redraw data for this content redraw - * \param clip current clip region - * \param ctx current redraw context - * \return true if successful, false otherwise - * - * x, y, clip_[xy][01] are in target coordinates. - */ - -bool html_redraw(struct content *c, struct content_redraw_data *data, - const struct rect *clip, const struct redraw_context *ctx) -{ - html_content *html = (html_content *) c; - struct box *box; - bool result = true; - bool select, select_only; - plot_style_t pstyle_fill_bg = { - .fill_type = PLOT_OP_TYPE_SOLID, - .fill_colour = data->background_colour, - }; - box = html->layout; - assert(box); - /* The select menu needs special treating because, when opened, it - * reaches beyond its layout box. - */ - select = false; - select_only = false; - if (ctx->interactive && html->visible_select_menu != NULL) { - struct form_control *control = html->visible_select_menu; - select = true; - /* check if the redraw rectangle is completely inside of the - select menu */ - select_only = form_clip_inside_select_menu(control, - data->scale, clip); - } - - if (!select_only) { - /* clear to background colour */ - result = ctx->plot->clip(clip); - - if (html->background_colour != NS_TRANSPARENT) - pstyle_fill_bg.fill_colour = html->background_colour; - - result &= ctx->plot->rectangle(clip->x0, clip->y0, - clip->x1, clip->y1, - &pstyle_fill_bg); - - result &= html_redraw_box(html, box, data->x, data->y, clip, - data->scale, pstyle_fill_bg.fill_colour, ctx); - } - - if (select) { - int menu_x, menu_y; - box = html->visible_select_menu->box; - box_coords(box, &menu_x, &menu_y); - - menu_x -= box->border[LEFT].width; - menu_y += box->height + box->border[BOTTOM].width + - box->padding[BOTTOM] + box->padding[TOP]; - result &= form_redraw_select_menu(html->visible_select_menu, - data->x + menu_x, data->y + menu_y, - data->scale, clip, ctx); - } - - return result; - -} +bool html_redraw_debug = false; /** * Determine if a box has a background that needs drawing @@ -239,678 +123,6 @@ static struct box *html_redraw_find_bg_box(struct box *box) } /** - * Recursively draw a box. - * - * \param html html content - * \param box box to draw - * \param x_parent coordinate of parent box - * \param y_parent coordinate of parent box - * \param clip clip rectangle - * \param scale scale for redraw - * \param current_background_color background colour under this box - * \param ctx current redraw context - * \return true if successful, false otherwise - * - * x, y, clip_[xy][01] are in target coordinates. - */ - -bool html_redraw_box(const html_content *html, struct box *box, - int x_parent, int y_parent, - const struct rect *clip, float scale, - colour current_background_color, - const struct redraw_context *ctx) -{ - const struct plotter_table *plot = ctx->plot; - int x, y; - int width, height; - int padding_left, padding_top, padding_width, padding_height; - int border_left, border_top, border_right, border_bottom; - struct rect r; - int x_scrolled, y_scrolled; - struct box *bg_box = NULL; - bool has_x_scroll, has_y_scroll; - css_computed_clip_rect css_rect; - - if (html_redraw_printing && (box->flags & PRINTED)) - return true; - - /* avoid trivial FP maths */ - if (scale == 1.0) { - x = x_parent + box->x; - y = y_parent + box->y; - width = box->width; - height = box->height; - padding_left = box->padding[LEFT]; - padding_top = box->padding[TOP]; - padding_width = padding_left + box->width + box->padding[RIGHT]; - padding_height = padding_top + box->height + - box->padding[BOTTOM]; - border_left = box->border[LEFT].width; - border_top = box->border[TOP].width; - border_right = box->border[RIGHT].width; - border_bottom = box->border[BOTTOM].width; - } else { - x = (x_parent + box->x) * scale; - y = (y_parent + box->y) * scale; - width = box->width * scale; - height = box->height * scale; - /* left and top padding values are normally zero, - * so avoid trivial FP maths */ - padding_left = box->padding[LEFT] ? box->padding[LEFT] * scale - : 0; - padding_top = box->padding[TOP] ? box->padding[TOP] * scale - : 0; - padding_width = (box->padding[LEFT] + box->width + - box->padding[RIGHT]) * scale; - padding_height = (box->padding[TOP] + box->height + - box->padding[BOTTOM]) * scale; - border_left = box->border[LEFT].width * scale; - border_top = box->border[TOP].width * scale; - border_right = box->border[RIGHT].width * scale; - border_bottom = box->border[BOTTOM].width * scale; - } - - /* calculate rectangle covering this box and descendants */ - if (box->style && css_computed_overflow(box->style) != - CSS_OVERFLOW_VISIBLE) { - /* box contents clipped to box size */ - r.x0 = x - border_left; - r.y0 = y - border_top; - r.x1 = x + padding_width + border_right; - r.y1 = y + padding_height + border_bottom; - } else { - /* box contents can hang out of the box; use descendant box */ - if (scale == 1.0) { - r.x0 = x + box->descendant_x0; - r.y0 = y + box->descendant_y0; - r.x1 = x + box->descendant_x1 + 1; - r.y1 = y + box->descendant_y1 + 1; - } else { - r.x0 = x + box->descendant_x0 * scale; - r.y0 = y + box->descendant_y0 * scale; - r.x1 = x + box->descendant_x1 * scale + 1; - r.y1 = y + box->descendant_y1 * scale + 1; - } - if (!box->parent) { - /* root element */ - int margin_left, margin_right; - int margin_top, margin_bottom; - if (scale == 1.0) { - margin_left = box->margin[LEFT]; - margin_top = box->margin[TOP]; - margin_right = box->margin[RIGHT]; - margin_bottom = box->margin[BOTTOM]; - } else { - margin_left = box->margin[LEFT] * scale; - margin_top = box->margin[TOP] * scale; - margin_right = box->margin[RIGHT] * scale; - margin_bottom = box->margin[BOTTOM] * scale; - } - r.x0 = x - border_left - margin_left < r.x0 ? - x - border_left - margin_left : r.x0; - r.y0 = y - border_top - margin_top < r.y0 ? - y - border_top - margin_top : r.y0; - r.x1 = x + padding_width + border_right + - margin_right > r.x1 ? - x + padding_width + border_right + - margin_right : r.x1; - r.y1 = y + padding_height + border_bottom + - margin_bottom > r.y1 ? - y + padding_height + border_bottom + - margin_bottom : r.y1; - } - } - - /* return if the rectangle is completely outside the clip rectangle */ - if (clip->y1 < r.y0 || r.y1 < clip->y0 || - clip->x1 < r.x0 || r.x1 < clip->x0) - return true; - - /*if the rectangle is under the page bottom but it can fit in a page, - don't print it now*/ - if (html_redraw_printing) { - if (r.y1 > html_redraw_printing_border) { - if (r.y1 - r.y0 <= html_redraw_printing_border && - (box->type == BOX_TEXT || - box->type == BOX_TABLE_CELL - || box->object || box->gadget)) { - /*remember the highest of all points from the - not printed elements*/ - if (r.y0 < html_redraw_printing_top_cropped) - html_redraw_printing_top_cropped = r.y0; - return true; - } - } - else box->flags |= PRINTED; /*it won't be printed anymore*/ - } - - /* if visibility is hidden render children only */ - if (box->style && css_computed_visibility(box->style) == - CSS_VISIBILITY_HIDDEN) { - if ((plot->group_start) && (!plot->group_start("hidden box"))) - return false; - if (!html_redraw_box_children(html, box, x_parent, y_parent, - &r, scale, current_background_color, ctx)) - return false; - return ((!plot->group_end) || (plot->group_end())); - } - - if ((plot->group_start) && (!plot->group_start("vis box"))) - return false; - - - if (box->style != NULL && - css_computed_position(box->style) == - CSS_POSITION_ABSOLUTE && - css_computed_clip(box->style, &css_rect) == - CSS_CLIP_RECT) { - /* We have an absolutly positioned box with a clip rect */ - if (css_rect.left_auto == false) - r.x0 = x - border_left + FIXTOINT(nscss_len2px( - css_rect.left, css_rect.lunit, - box->style)); - - if (css_rect.top_auto == false) - r.y0 = y - border_top + FIXTOINT(nscss_len2px( - css_rect.top, css_rect.tunit, - box->style)); - - if (css_rect.right_auto == false) - r.x1 = x - border_left + FIXTOINT(nscss_len2px( - css_rect.right, css_rect.runit, - box->style)); - - if (css_rect.bottom_auto == false) - r.y1 = y - border_top + FIXTOINT(nscss_len2px( - css_rect.bottom, css_rect.bunit, - box->style)); - - /* find intersection of clip rectangle and box */ - if (r.x0 < clip->x0) r.x0 = clip->x0; - if (r.y0 < clip->y0) r.y0 = clip->y0; - if (clip->x1 < r.x1) r.x1 = clip->x1; - if (clip->y1 < r.y1) r.y1 = clip->y1; - /* no point trying to draw 0-width/height boxes */ - if (r.x0 == r.x1 || r.y0 == r.y1) - /* not an error */ - return ((!plot->group_end) || (plot->group_end())); - /* clip to it */ - if (!plot->clip(&r)) - return false; - - } else if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || - box->type == BOX_TABLE_CELL || box->object) { - /* find intersection of clip rectangle and box */ - if (r.x0 < clip->x0) r.x0 = clip->x0; - if (r.y0 < clip->y0) r.y0 = clip->y0; - if (clip->x1 < r.x1) r.x1 = clip->x1; - if (clip->y1 < r.y1) r.y1 = clip->y1; - /* no point trying to draw 0-width/height boxes */ - if (r.x0 == r.x1 || r.y0 == r.y1) - /* not an error */ - return ((!plot->group_end) || (plot->group_end())); - /* clip to it */ - if (!plot->clip(&r)) - return false; - } else { - /* clip box is fine, clip to it */ - r = *clip; - if (!plot->clip(&r)) - return false; - } - - /* background colour and image for block level content and replaced - * inlines */ - - bg_box = html_redraw_find_bg_box(box); - - /* bg_box == NULL implies that this box should not have - * its background rendered. Otherwise filter out linebreaks, - * optimize away non-differing inlines, only plot background - * for BOX_TEXT it's in an inline */ - if (bg_box && bg_box->type != BOX_BR && - bg_box->type != BOX_TEXT && - bg_box->type != BOX_INLINE_END && - (bg_box->type != BOX_INLINE || bg_box->object || - bg_box->flags & IFRAME || box->flags & REPLACE_DIM)) { - /* find intersection of clip box and border edge */ - struct rect p; - p.x0 = x - border_left < r.x0 ? r.x0 : x - border_left; - p.y0 = y - border_top < r.y0 ? r.y0 : y - border_top; - p.x1 = x + padding_width + border_right < r.x1 ? - x + padding_width + border_right : r.x1; - p.y1 = y + padding_height + border_bottom < r.y1 ? - y + padding_height + border_bottom : r.y1; - if (!box->parent) { - /* Root element, special case: - * background covers margins too */ - int m_left, m_top, m_right, m_bottom; - if (scale == 1.0) { - m_left = box->margin[LEFT]; - m_top = box->margin[TOP]; - m_right = box->margin[RIGHT]; - m_bottom = box->margin[BOTTOM]; - } else { - m_left = box->margin[LEFT] * scale; - m_top = box->margin[TOP] * scale; - m_right = box->margin[RIGHT] * scale; - m_bottom = box->margin[BOTTOM] * scale; - } - p.x0 = p.x0 - m_left < r.x0 ? r.x0 : p.x0 - m_left; - p.y0 = p.y0 - m_top < r.y0 ? r.y0 : p.y0 - m_top; - p.x1 = p.x1 + m_right < r.x1 ? p.x1 + m_right : r.x1; - p.y1 = p.y1 + m_bottom < r.y1 ? p.y1 + m_bottom : r.y1; - } - /* valid clipping rectangles only */ - 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)) - return false; - /* restore previous graphics window */ - if (!plot->clip(&r)) - return false; - } - } - - /* borders for block level content and replaced inlines */ - if (box->style && box->type != BOX_TEXT && - box->type != BOX_INLINE_END && - (box->type != BOX_INLINE || box->object || - box->flags & IFRAME || box->flags & REPLACE_DIM) && - (border_top || border_right || - border_bottom || border_left)) { - if (!html_redraw_borders(box, x_parent, y_parent, - padding_width, padding_height, &r, - scale, ctx)) - return false; - } - - /* backgrounds and borders for non-replaced inlines */ - if (box->style && box->type == BOX_INLINE && box->inline_end && - (html_redraw_box_has_background(box) || - border_top || border_right || - border_bottom || border_left)) { - /* inline backgrounds and borders span other boxes and may - * wrap onto separate lines */ - struct box *ib; - struct rect b; /* border edge rectangle */ - struct rect p; /* clipped rect */ - bool first = true; - int ib_x; - int ib_y = y; - int ib_p_width; - int ib_b_left, ib_b_right; - - b.x0 = x - border_left; - b.x1 = x + padding_width + border_right; - b.y0 = y - border_top; - b.y1 = y + padding_height + border_bottom; - - p.x0 = b.x0 < r.x0 ? r.x0 : b.x0; - p.x1 = b.x1 < r.x1 ? b.x1 : r.x1; - p.y0 = b.y0 < r.y0 ? r.y0 : b.y0; - p.y1 = b.y1 < r.y1 ? b.y1 : r.y1; - for (ib = box; ib; ib = ib->next) { - /* to get extents of rectangle(s) associated with - * inline, cycle though all boxes in inline, skipping - * over floats */ - if (ib->type == BOX_FLOAT_LEFT || - ib->type == BOX_FLOAT_RIGHT) - continue; - if (scale == 1.0) { - ib_x = x_parent + ib->x; - ib_y = y_parent + ib->y; - ib_p_width = ib->padding[LEFT] + ib->width + - ib->padding[RIGHT]; - ib_b_left = ib->border[LEFT].width; - ib_b_right = ib->border[RIGHT].width; - } else { - ib_x = (x_parent + ib->x) * scale; - ib_y = (y_parent + ib->y) * scale; - ib_p_width = (ib->padding[LEFT] + ib->width + - ib->padding[RIGHT]) * scale; - ib_b_left = ib->border[LEFT].width * scale; - ib_b_right = ib->border[RIGHT].width * scale; - } - - if ((ib->flags & NEW_LINE) && ib != box) { - /* inline element has wrapped, plot background - * and borders */ - if (!html_redraw_inline_background( - x, y, box, scale, &p, b, - first, false, - ¤t_background_color, ctx)) - return false; - /* restore previous graphics window */ - if (!plot->clip(&r)) - return false; - if (!html_redraw_inline_borders(box, b, &r, - scale, first, false, ctx)) - return false; - /* reset coords */ - b.x0 = ib_x - ib_b_left; - b.y0 = ib_y - border_top - padding_top; - b.y1 = ib_y + padding_height - padding_top + - border_bottom; - - p.x0 = b.x0 < r.x0 ? r.x0 : b.x0; - p.y0 = b.y0 < r.y0 ? r.y0 : b.y0; - p.y1 = b.y1 < r.y1 ? b.y1 : r.y1; - - first = false; - } - - /* increase width for current box */ - b.x1 = ib_x + ib_p_width + ib_b_right; - p.x1 = b.x1 < r.x1 ? b.x1 : r.x1; - - if (ib == box->inline_end) - /* reached end of BOX_INLINE span */ - break; - } - /* 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)) - return false; - /* restore previous graphics window */ - if (!plot->clip(&r)) - return false; - if (!html_redraw_inline_borders(box, b, &r, scale, first, true, - ctx)) - return false; - - } - - /* Debug outlines */ - if (html_redraw_debug) { - int margin_left, margin_right; - int margin_top, margin_bottom; - if (scale == 1.0) { - /* avoid trivial fp maths */ - margin_left = box->margin[LEFT]; - margin_top = box->margin[TOP]; - margin_right = box->margin[RIGHT]; - margin_bottom = box->margin[BOTTOM]; - } else { - margin_left = box->margin[LEFT] * scale; - margin_top = box->margin[TOP] * scale; - margin_right = box->margin[RIGHT] * scale; - margin_bottom = box->margin[BOTTOM] * scale; - } - /* Content edge -- blue */ - if (!plot->rectangle(x + padding_left, - y + padding_top, - x + padding_left + width, - y + padding_top + height, - plot_style_content_edge)) - return false; - /* Padding edge -- red */ - if (!plot->rectangle(x, y, - x + padding_width, y + padding_height, - plot_style_padding_edge)) - return false; - /* Margin edge -- yellow */ - if (!plot->rectangle( - x - border_left - margin_left, - y - border_top - margin_top, - x + padding_width + border_right + - margin_right, - y + padding_height + border_bottom + - margin_bottom, - plot_style_margin_edge)) - return false; - } - - /* clip to the padding edge for objects, or boxes with overflow hidden - * or scroll */ - if ((box->style && css_computed_overflow(box->style) != - CSS_OVERFLOW_VISIBLE) || box->object || - box->flags & IFRAME) { - r.x0 = x; - r.y0 = y; - r.x1 = x + padding_width; - r.y1 = y + padding_height; - if (r.x0 < clip->x0) r.x0 = clip->x0; - if (r.y0 < clip->y0) r.y0 = clip->y0; - if (clip->x1 < r.x1) r.x1 = clip->x1; - if (clip->y1 < r.y1) r.y1 = clip->y1; - if (r.x1 <= r.x0 || r.y1 <= r.y0) - return ((!plot->group_end) || (plot->group_end())); - if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || - box->type == BOX_TABLE_CELL || box->object) { - if (!plot->clip(&r)) - return false; - } - } - - /* text decoration */ - if (box->type != BOX_TEXT && box->style && - css_computed_text_decoration(box->style) != - CSS_TEXT_DECORATION_NONE) - if (!html_redraw_text_decoration(box, x_parent, y_parent, - scale, current_background_color, ctx)) - return false; - - if (box->object && width != 0 && height != 0) { - struct content_redraw_data obj_data; - - x_scrolled = x - scrollbar_get_offset(box->scroll_x) * scale; - y_scrolled = y - scrollbar_get_offset(box->scroll_y) * scale; - - obj_data.x = x_scrolled + padding_left; - obj_data.y = y_scrolled + padding_top; - obj_data.width = width; - obj_data.height = height; - obj_data.background_colour = current_background_color; - obj_data.scale = scale; - obj_data.repeat_x = false; - obj_data.repeat_y = false; - - if (content_get_type(box->object) == CONTENT_HTML) { - obj_data.x /= scale; - obj_data.y /= scale; - } - - if (!content_redraw(box->object, &obj_data, &r, ctx)) { - /* Show image fail */ - /* Unicode (U+FFFC) 'OBJECT REPLACEMENT CHARACTER' */ - const char *obj = "\xef\xbf\xbc"; - int obj_width; - int obj_x = x + padding_left; - if (!plot->rectangle(x + padding_left, - y + padding_top, - x + padding_left + width - 1, - y + padding_top + height - 1, - plot_style_broken_object)) - return false; - if (!nsfont.font_width(plot_fstyle_broken_object, obj, - sizeof(obj) - 1, &obj_width)) - obj_x += 1; - else - obj_x += width / 2 - obj_width / 2; - - if (!plot->text(obj_x, y + padding_top + (int) - (height * 0.75), - obj, sizeof(obj) - 1, - plot_fstyle_broken_object)) - return false; - } - - - } else if (box->iframe) { - /* Offset is passed to browser window redraw unscaled */ - browser_window_redraw(box->iframe, - (x + padding_left) / scale, - (y + padding_top) / scale, &r, ctx); - - } else if (box->gadget && box->gadget->type == GADGET_CHECKBOX) { - if (!html_redraw_checkbox(x + padding_left, y + padding_top, - width, height, box->gadget->selected, ctx)) - return false; - - } else if (box->gadget && box->gadget->type == GADGET_RADIO) { - if (!html_redraw_radio(x + padding_left, y + padding_top, - width, height, box->gadget->selected, ctx)) - return false; - - } 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)) - return false; - - } else if (box->text) { - if (!html_redraw_text_box(html, box, x, y, &r, scale, - current_background_color, ctx)) - return false; - - } else { - if (!html_redraw_box_children(html, box, x_parent, y_parent, &r, - scale, current_background_color, ctx)) - return false; - } - - if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || - box->type == BOX_TABLE_CELL || box->type == BOX_INLINE) - if (!plot->clip(clip)) - return false; - - /* list marker */ - if (box->list_marker) - if (!html_redraw_box(html, box->list_marker, - x_parent + box->x - - scrollbar_get_offset(box->scroll_x), - y_parent + box->y - - scrollbar_get_offset(box->scroll_y), - clip, scale, current_background_color, ctx)) - return false; - - /* scrollbars */ - if (((box->style && box->type != BOX_BR && - box->type != BOX_TABLE && box->type != BOX_INLINE && - (css_computed_overflow(box->style) == - CSS_OVERFLOW_SCROLL || - css_computed_overflow(box->style) == - CSS_OVERFLOW_AUTO)) || (box->object && - content_get_type(box->object) == CONTENT_HTML)) && - box->parent != NULL) { - - has_x_scroll = box_hscrollbar_present(box); - has_y_scroll = box_vscrollbar_present(box); - - if (!box_handle_scrollbars((struct content *)html, - box, has_x_scroll, has_y_scroll)) - return false; - - if (box->scroll_x != NULL) - scrollbar_redraw(box->scroll_x, - x_parent + box->x, - y_parent + box->y + box->padding[TOP] + - box->height + box->padding[BOTTOM] - - SCROLLBAR_WIDTH, clip, scale, ctx); - if (box->scroll_y != NULL) - scrollbar_redraw(box->scroll_y, - x_parent + box->x + box->padding[LEFT] + - box->width + box->padding[RIGHT] - - SCROLLBAR_WIDTH, - y_parent + box->y, clip, scale, ctx); - } - - if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || - box->type == BOX_TABLE_CELL || box->type == BOX_INLINE) - if (!plot->clip(clip)) - return false; - - return ((!plot->group_end) || (plot->group_end())); -} - - -/** - * Draw the various children of a box. - * - * \param html html content - * \param box box to draw children of - * \param x_parent coordinate of parent box - * \param y_parent coordinate of parent box - * \param clip clip rectangle - * \param scale scale for redraw - * \param current_background_color background colour under this box - * \param ctx current redraw context - * \return true if successful, false otherwise - */ - -bool html_redraw_box_children(const html_content *html, struct box *box, - int x_parent, int y_parent, - const struct rect *clip, float scale, - colour current_background_color, - const struct redraw_context *ctx) -{ - struct box *c; - - for (c = box->children; c; c = c->next) { - - if (c->type != BOX_FLOAT_LEFT && c->type != BOX_FLOAT_RIGHT) - if (!html_redraw_box(html, c, - x_parent + box->x - - scrollbar_get_offset(box->scroll_x), - y_parent + box->y - - scrollbar_get_offset(box->scroll_y), - clip, scale, current_background_color, - ctx)) - return false; - } - for (c = box->float_children; c; c = c->next_float) - if (!html_redraw_box(html, c, - x_parent + box->x - - scrollbar_get_offset(box->scroll_x), - y_parent + box->y - - scrollbar_get_offset(box->scroll_y), - clip, scale, current_background_color, - ctx)) - return false; - - return true; -} - - -/** - * Redraw the text content of a box, possibly partially highlighted - * because the text has been selected, or matches a search operation. - * - * \param box box with text content - * \param x x co-ord of box - * \param y y co-ord of box - * \param clip current clip rectangle - * \param scale current scale setting (1.0 = 100%) - * \param current_background_color - * \param ctx current redraw context - * \return true iff successful and redraw should proceed - */ - -bool html_redraw_text_box(const html_content *html, struct box *box, - int x, int y, const struct rect *clip, float scale, - colour current_background_color, - const struct redraw_context *ctx) -{ - bool excluded = (box->object != NULL); - plot_font_style_t fstyle; - - font_plot_style_from_css(box->style, &fstyle); - fstyle.background = current_background_color; - - if (!text_redraw(box->text, box->length, box->byte_offset, - box->space, &fstyle, x, y, - clip, box->height, scale, excluded, - (struct content *)html, &html->sel, - html->search, ctx)) - return false; - - return true; -} - -/** * Redraw a short text string, complete with highlighting * (for selection/search) * @@ -1084,6 +296,386 @@ bool text_redraw(const char *utf8_text, size_t utf8_len, return true; } +static plot_style_t plot_style_bdr = { + .stroke_type = PLOT_OP_TYPE_DASH, +}; +static plot_style_t plot_style_fillbdr = { + .fill_type = PLOT_OP_TYPE_SOLID, +}; +static plot_style_t plot_style_fillbdr_dark = { + .fill_type = PLOT_OP_TYPE_SOLID, +}; +static plot_style_t plot_style_fillbdr_light = { + .fill_type = PLOT_OP_TYPE_SOLID, +}; +static plot_style_t plot_style_fillbdr_ddark = { + .fill_type = PLOT_OP_TYPE_SOLID, +}; +static plot_style_t plot_style_fillbdr_dlight = { + .fill_type = PLOT_OP_TYPE_SOLID, +}; + +/** + * Draw one border. + * + * \param side index of border side (TOP, RIGHT, BOTTOM, LEFT) + * \param p array of precomputed border vertices + * \param c colour for border + * \param style border line style + * \param thickness border thickness + * \param rectangular whether border is rectangular + * \param ctx current redraw context + * \return true if successful, false otherwise + */ + +static bool html_redraw_border_plot(const int side, const int *p, colour c, + enum css_border_style_e style, int thickness, bool rectangular, + const struct rect *clip, const struct redraw_context *ctx) +{ + const struct plotter_table *plot = ctx->plot; + int z[8]; /* Vertices of border part */ + unsigned int light = side; + plot_style_t *plot_style_bdr_in; + plot_style_t *plot_style_bdr_out; + + if (c == NS_TRANSPARENT) + return true; + + plot_style_bdr.stroke_type = PLOT_OP_TYPE_DASH; + plot_style_bdr.stroke_colour = c; + plot_style_bdr.stroke_width = thickness; + plot_style_fillbdr.fill_colour = c; + plot_style_fillbdr_dark.fill_colour = darken_colour(c); + plot_style_fillbdr_light.fill_colour = lighten_colour(c); + plot_style_fillbdr_ddark.fill_colour = double_darken_colour(c); + plot_style_fillbdr_dlight.fill_colour = double_lighten_colour(c); + + switch (style) { + case CSS_BORDER_STYLE_DOTTED: + plot_style_bdr.stroke_type = PLOT_OP_TYPE_DOT; + /* fall through */ + case CSS_BORDER_STYLE_DASHED: + if (!plot->line((p[0] + p[2]) / 2, + (p[1] + p[3]) / 2, + (p[4] + p[6]) / 2, + (p[5] + p[7]) / 2, + &plot_style_bdr)) + return false; + break; + + case CSS_BORDER_STYLE_SOLID: + /* fall through to default */ + default: + if (rectangular || thickness == 1) { + int x0, y0, x1, y1; + if (side == TOP || side == RIGHT) { + x0 = p[2]; y0 = p[3]; + x1 = p[6]; y1 = p[7]; + x1 = ((side == TOP) && (p[4] - p[6] != 0)) ? + x1 + p[4] - p[6] : x1; + } else { + x0 = p[6]; y0 = p[7]; + x1 = p[2]; y1 = p[3]; + y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ? + y1 + p[1] - p[3] : y1; + } + /* find intersection of clip rectangle and border */ + x0 = (clip->x0 > x0) ? clip->x0 : x0; + y0 = (clip->y0 > y0) ? clip->y0 : y0; + x1 = (clip->x1 < x1) ? clip->x1 : x1; + y1 = (clip->y1 < y1) ? clip->y1 : y1; + if ((x0 < x1) && (y0 < y1)) { + /* valid clip rectangles only */ + if (!plot->rectangle(x0, y0, x1, y1, + &plot_style_fillbdr)) + return false; + } + } else { + if (!plot->polygon(p, 4, &plot_style_fillbdr)) + return false; + } + break; + + case CSS_BORDER_STYLE_DOUBLE: + z[0] = p[0]; + z[1] = p[1]; + z[2] = (p[0] * 2 + p[2]) / 3; + z[3] = (p[1] * 2 + p[3]) / 3; + z[4] = (p[6] * 2 + p[4]) / 3; + z[5] = (p[7] * 2 + p[5]) / 3; + z[6] = p[6]; + z[7] = p[7]; + if (!plot->polygon(z, 4, &plot_style_fillbdr)) + return false; + z[0] = p[2]; + z[1] = p[3]; + z[2] = (p[2] * 2 + p[0]) / 3; + z[3] = (p[3] * 2 + p[1]) / 3; + z[4] = (p[4] * 2 + p[6]) / 3; + z[5] = (p[5] * 2 + p[7]) / 3; + z[6] = p[4]; + z[7] = p[5]; + if (!plot->polygon(z, 4, &plot_style_fillbdr)) + return false; + break; + + case CSS_BORDER_STYLE_GROOVE: + light = 3 - light; + /* fall through */ + case CSS_BORDER_STYLE_RIDGE: + /* choose correct colours for each part of the border line */ + if (light <= 1) { + plot_style_bdr_in = &plot_style_fillbdr_dark; + plot_style_bdr_out = &plot_style_fillbdr_light; + } else { + plot_style_bdr_in = &plot_style_fillbdr_light; + plot_style_bdr_out = &plot_style_fillbdr_dark; + } + + /* Render border */ + if ((rectangular || thickness == 2) && thickness != 1) { + /* Border made up from two parts and can be plotted + * with rectangles */ + int x0, y0, x1, y1; + + /* First part */ + if (side == TOP || side == RIGHT) { + x0 = (p[0] + p[2]) / 2; y0 = (p[1] + p[3]) / 2; + x1 = p[6]; y1 = p[7]; + } else { + x0 = p[6]; y0 = p[7]; + x1 = (p[0] + p[2]) / 2; y1 = (p[1] + p[3]) / 2; + } + /* find intersection of clip rectangle and border */ + x0 = (clip->x0 > x0) ? clip->x0 : x0; + y0 = (clip->y0 > y0) ? clip->y0 : y0; + x1 = (clip->x1 < x1) ? clip->x1 : x1; + y1 = (clip->y1 < y1) ? clip->y1 : y1; + if ((x0 < x1) && (y0 < y1)) { + /* valid clip rectangles only */ + if (!plot->rectangle(x0, y0, x1, y1, + plot_style_bdr_in)) + return false; + } + + /* Second part */ + if (side == TOP || side == RIGHT) { + x0 = p[2]; y0 = p[3]; + x1 = (p[6] + p[4]) / 2; y1 = (p[7] + p[5]) / 2; + } else { + x0 = (p[6] + p[4]) / 2; y0 = (p[7] + p[5]) / 2; + x1 = p[2]; y1 = p[3]; + } + /* find intersection of clip rectangle and border */ + x0 = (clip->x0 > x0) ? clip->x0 : x0; + y0 = (clip->y0 > y0) ? clip->y0 : y0; + x1 = (clip->x1 < x1) ? clip->x1 : x1; + y1 = (clip->y1 < y1) ? clip->y1 : y1; + if ((x0 < x1) && (y0 < y1)) { + /* valid clip rectangles only */ + if (!plot->rectangle(x0, y0, x1, y1, + plot_style_bdr_out)) + return false; + } + } else if (thickness == 1) { + /* Border made up from one part which can be plotted + * as a rectangle */ + int x0, y0, x1, y1; + if (side == TOP || side == RIGHT) { + x0 = p[2]; y0 = p[3]; + x1 = p[6]; y1 = p[7]; + x1 = ((side == TOP) && (p[4] - p[6] != 0)) ? + x1 + p[4] - p[6] : x1; + /* find intersection of clip rectangle and + * border */ + x0 = (clip->x0 > x0) ? clip->x0 : x0; + y0 = (clip->y0 > y0) ? clip->y0 : y0; + x1 = (clip->x1 < x1) ? clip->x1 : x1; + y1 = (clip->y1 < y1) ? clip->y1 : y1; + if ((x0 < x1) && (y0 < y1)) { + /* valid clip rectangles only */ + if (!plot->rectangle(x0, y0, x1, y1, + plot_style_bdr_in)) + return false; + } + } else { + x0 = p[6]; y0 = p[7]; + x1 = p[2]; y1 = p[3]; + y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ? + y1 + p[1] - p[3] : y1; + /* find intersection of clip rectangle and + * border */ + x0 = (clip->x0 > x0) ? clip->x0 : x0; + y0 = (clip->y0 > y0) ? clip->y0 : y0; + x1 = (clip->x1 < x1) ? clip->x1 : x1; + y1 = (clip->y1 < y1) ? clip->y1 : y1; + if ((x0 < x1) && (y0 < y1)) { + /* valid clip rectangles only */ + if (!plot->rectangle(x0, y0, x1, y1, + plot_style_bdr_out)) + return false; + } + } + } else { + /* Border made up from two parts and can't be plotted + * with rectangles */ + z[0] = p[0]; + z[1] = p[1]; + z[2] = (p[0] + p[2]) / 2; + z[3] = (p[1] + p[3]) / 2; + z[4] = (p[6] + p[4]) / 2; + z[5] = (p[7] + p[5]) / 2; + z[6] = p[6]; + z[7] = p[7]; + if (!plot->polygon(z, 4, plot_style_bdr_in)) + return false; + z[0] = p[2]; + z[1] = p[3]; + z[6] = p[4]; + z[7] = p[5]; + if (!plot->polygon(z, 4, plot_style_bdr_out)) + return false; + } + break; + + case CSS_BORDER_STYLE_INSET: + light = (light + 2) % 4; + /* fall through */ + case CSS_BORDER_STYLE_OUTSET: + /* choose correct colours for each part of the border line */ + switch (light) { + case 0: + plot_style_bdr_in = &plot_style_fillbdr_light; + plot_style_bdr_out = &plot_style_fillbdr_dlight; + break; + case 1: + plot_style_bdr_in = &plot_style_fillbdr_ddark; + plot_style_bdr_out = &plot_style_fillbdr_dark; + break; + case 2: + plot_style_bdr_in = &plot_style_fillbdr_dark; + plot_style_bdr_out = &plot_style_fillbdr_ddark; + break; + case 3: + plot_style_bdr_in = &plot_style_fillbdr_dlight; + plot_style_bdr_out = &plot_style_fillbdr_light; + break; + default: + plot_style_bdr_in = &plot_style_fillbdr; + plot_style_bdr_out = &plot_style_fillbdr; + break; + } + + /* Render border */ + if ((rectangular || thickness == 2) && thickness != 1) { + /* Border made up from two parts and can be plotted + * with rectangles */ + int x0, y0, x1, y1; + + /* First part */ + if (side == TOP || side == RIGHT) { + x0 = (p[0] + p[2]) / 2; y0 = (p[1] + p[3]) / 2; + x1 = p[6]; y1 = p[7]; + } else { + x0 = p[6]; y0 = p[7]; + x1 = (p[0] + p[2]) / 2; y1 = (p[1] + p[3]) / 2; + } + /* find intersection of clip rectangle and border */ + x0 = (clip->x0 > x0) ? clip->x0 : x0; + y0 = (clip->y0 > y0) ? clip->y0 : y0; + x1 = (clip->x1 < x1) ? clip->x1 : x1; + y1 = (clip->y1 < y1) ? clip->y1 : y1; + if ((x0 < x1) && (y0 < y1)) { + /* valid clip rectangles only */ + if (!plot->rectangle(x0, y0, x1, y1, + plot_style_bdr_in)) + return false; + } + + /* Second part */ + if (side == TOP || side == RIGHT) { + x0 = p[2]; y0 = p[3]; + x1 = (p[6] + p[4]) / 2; y1 = (p[7] + p[5]) / 2; + } else { + x0 = (p[6] + p[4]) / 2; y0 = (p[7] + p[5]) / 2; + x1 = p[2]; y1 = p[3]; + } + /* find intersection of clip rectangle and border */ + x0 = (clip->x0 > x0) ? clip->x0 : x0; + y0 = (clip->y0 > y0) ? clip->y0 : y0; + x1 = (clip->x1 < x1) ? clip->x1 : x1; + y1 = (clip->y1 < y1) ? clip->y1 : y1; + if ((x0 < x1) && (y0 < y1)) { + /* valid clip rectangles only */ + if (!plot->rectangle(x0, y0, x1, y1, + plot_style_bdr_out)) + return false; + } + } else if (thickness == 1) { + /* Border made up from one part which can be plotted + * as a rectangle */ + int x0, y0, x1, y1; + if (side == TOP || side == RIGHT) { + x0 = p[2]; y0 = p[3]; + x1 = p[6]; y1 = p[7]; + x1 = ((side == TOP) && (p[4] - p[6] != 0)) ? + x1 + p[4] - p[6] : x1; + /* find intersection of clip rectangle and + * border */ + x0 = (clip->x0 > x0) ? clip->x0 : x0; + y0 = (clip->y0 > y0) ? clip->y0 : y0; + x1 = (clip->x1 < x1) ? clip->x1 : x1; + y1 = (clip->y1 < y1) ? clip->y1 : y1; + if ((x0 < x1) && (y0 < y1)) { + /* valid clip rectangles only */ + if (!plot->rectangle(x0, y0, x1, y1, + plot_style_bdr_in)) + return false; + } + } else { + x0 = p[6]; y0 = p[7]; + x1 = p[2]; y1 = p[3]; + y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ? + y1 + p[1] - p[3] : y1; + /* find intersection of clip rectangle and + * border */ + x0 = (clip->x0 > x0) ? clip->x0 : x0; + y0 = (clip->y0 > y0) ? clip->y0 : y0; + x1 = (clip->x1 < x1) ? clip->x1 : x1; + y1 = (clip->y1 < y1) ? clip->y1 : y1; + if ((x0 < x1) && (y0 < y1)) { + /* valid clip rectangles only */ + if (!plot->rectangle(x0, y0, x1, y1, + plot_style_bdr_out)) + return false; + } + } + } else { + /* Border made up from two parts and can't be plotted + * with rectangles */ + z[0] = p[0]; + z[1] = p[1]; + z[2] = (p[0] + p[2]) / 2; + z[3] = (p[1] + p[3]) / 2; + z[4] = (p[6] + p[4]) / 2; + z[5] = (p[7] + p[5]) / 2; + z[6] = p[6]; + z[7] = p[7]; + if (!plot->polygon(z, 4, plot_style_bdr_in)) + return false; + z[0] = p[2]; + z[1] = p[3]; + z[6] = p[4]; + z[7] = p[5]; + if (!plot->polygon(z, 4, plot_style_bdr_out)) + return false; + } + break; + } + + return true; +} + /** * Draw borders for a box. @@ -1098,7 +690,7 @@ bool text_redraw(const char *utf8_text, size_t utf8_len, * \return true if successful, false otherwise */ -bool html_redraw_borders(struct box *box, int x_parent, int y_parent, +static bool html_redraw_borders(struct box *box, int x_parent, int y_parent, int p_width, int p_height, const struct rect *clip, float scale, const struct redraw_context *ctx) { @@ -1333,7 +925,7 @@ bool html_redraw_borders(struct box *box, int x_parent, int y_parent, * \return true if successful, false otherwise */ -bool html_redraw_inline_borders(struct box *box, struct rect b, +static bool html_redraw_inline_borders(struct box *box, struct rect b, const struct rect *clip, float scale, bool first, bool last, const struct redraw_context *ctx) { @@ -1528,386 +1120,6 @@ bool html_redraw_inline_borders(struct box *box, struct rect b, return true; } -static plot_style_t plot_style_bdr = { - .stroke_type = PLOT_OP_TYPE_DASH, -}; -static plot_style_t plot_style_fillbdr = { - .fill_type = PLOT_OP_TYPE_SOLID, -}; -static plot_style_t plot_style_fillbdr_dark = { - .fill_type = PLOT_OP_TYPE_SOLID, -}; -static plot_style_t plot_style_fillbdr_light = { - .fill_type = PLOT_OP_TYPE_SOLID, -}; -static plot_style_t plot_style_fillbdr_ddark = { - .fill_type = PLOT_OP_TYPE_SOLID, -}; -static plot_style_t plot_style_fillbdr_dlight = { - .fill_type = PLOT_OP_TYPE_SOLID, -}; - -/** - * Draw one border. - * - * \param side index of border side (TOP, RIGHT, BOTTOM, LEFT) - * \param p array of precomputed border vertices - * \param c colour for border - * \param style border line style - * \param thickness border thickness - * \param rectangular whether border is rectangular - * \param ctx current redraw context - * \return true if successful, false otherwise - */ - -bool html_redraw_border_plot(const int side, const int *p, colour c, - enum css_border_style_e style, int thickness, bool rectangular, - const struct rect *clip, const struct redraw_context *ctx) -{ - const struct plotter_table *plot = ctx->plot; - int z[8]; /* Vertices of border part */ - unsigned int light = side; - plot_style_t *plot_style_bdr_in; - plot_style_t *plot_style_bdr_out; - - if (c == NS_TRANSPARENT) - return true; - - plot_style_bdr.stroke_type = PLOT_OP_TYPE_DASH; - plot_style_bdr.stroke_colour = c; - plot_style_bdr.stroke_width = thickness; - plot_style_fillbdr.fill_colour = c; - plot_style_fillbdr_dark.fill_colour = darken_colour(c); - plot_style_fillbdr_light.fill_colour = lighten_colour(c); - plot_style_fillbdr_ddark.fill_colour = double_darken_colour(c); - plot_style_fillbdr_dlight.fill_colour = double_lighten_colour(c); - - switch (style) { - case CSS_BORDER_STYLE_DOTTED: - plot_style_bdr.stroke_type = PLOT_OP_TYPE_DOT; - /* fall through */ - case CSS_BORDER_STYLE_DASHED: - if (!plot->line((p[0] + p[2]) / 2, - (p[1] + p[3]) / 2, - (p[4] + p[6]) / 2, - (p[5] + p[7]) / 2, - &plot_style_bdr)) - return false; - break; - - case CSS_BORDER_STYLE_SOLID: - /* fall through to default */ - default: - if (rectangular || thickness == 1) { - int x0, y0, x1, y1; - if (side == TOP || side == RIGHT) { - x0 = p[2]; y0 = p[3]; - x1 = p[6]; y1 = p[7]; - x1 = ((side == TOP) && (p[4] - p[6] != 0)) ? - x1 + p[4] - p[6] : x1; - } else { - x0 = p[6]; y0 = p[7]; - x1 = p[2]; y1 = p[3]; - y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ? - y1 + p[1] - p[3] : y1; - } - /* find intersection of clip rectangle and border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - &plot_style_fillbdr)) - return false; - } - } else { - if (!plot->polygon(p, 4, &plot_style_fillbdr)) - return false; - } - break; - - case CSS_BORDER_STYLE_DOUBLE: - z[0] = p[0]; - z[1] = p[1]; - z[2] = (p[0] * 2 + p[2]) / 3; - z[3] = (p[1] * 2 + p[3]) / 3; - z[4] = (p[6] * 2 + p[4]) / 3; - z[5] = (p[7] * 2 + p[5]) / 3; - z[6] = p[6]; - z[7] = p[7]; - if (!plot->polygon(z, 4, &plot_style_fillbdr)) - return false; - z[0] = p[2]; - z[1] = p[3]; - z[2] = (p[2] * 2 + p[0]) / 3; - z[3] = (p[3] * 2 + p[1]) / 3; - z[4] = (p[4] * 2 + p[6]) / 3; - z[5] = (p[5] * 2 + p[7]) / 3; - z[6] = p[4]; - z[7] = p[5]; - if (!plot->polygon(z, 4, &plot_style_fillbdr)) - return false; - break; - - case CSS_BORDER_STYLE_GROOVE: - light = 3 - light; - /* fall through */ - case CSS_BORDER_STYLE_RIDGE: - /* choose correct colours for each part of the border line */ - if (light <= 1) { - plot_style_bdr_in = &plot_style_fillbdr_dark; - plot_style_bdr_out = &plot_style_fillbdr_light; - } else { - plot_style_bdr_in = &plot_style_fillbdr_light; - plot_style_bdr_out = &plot_style_fillbdr_dark; - } - - /* Render border */ - if ((rectangular || thickness == 2) && thickness != 1) { - /* Border made up from two parts and can be plotted - * with rectangles */ - int x0, y0, x1, y1; - - /* First part */ - if (side == TOP || side == RIGHT) { - x0 = (p[0] + p[2]) / 2; y0 = (p[1] + p[3]) / 2; - x1 = p[6]; y1 = p[7]; - } else { - x0 = p[6]; y0 = p[7]; - x1 = (p[0] + p[2]) / 2; y1 = (p[1] + p[3]) / 2; - } - /* find intersection of clip rectangle and border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_in)) - return false; - } - - /* Second part */ - if (side == TOP || side == RIGHT) { - x0 = p[2]; y0 = p[3]; - x1 = (p[6] + p[4]) / 2; y1 = (p[7] + p[5]) / 2; - } else { - x0 = (p[6] + p[4]) / 2; y0 = (p[7] + p[5]) / 2; - x1 = p[2]; y1 = p[3]; - } - /* find intersection of clip rectangle and border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_out)) - return false; - } - } else if (thickness == 1) { - /* Border made up from one part which can be plotted - * as a rectangle */ - int x0, y0, x1, y1; - if (side == TOP || side == RIGHT) { - x0 = p[2]; y0 = p[3]; - x1 = p[6]; y1 = p[7]; - x1 = ((side == TOP) && (p[4] - p[6] != 0)) ? - x1 + p[4] - p[6] : x1; - /* find intersection of clip rectangle and - * border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_in)) - return false; - } - } else { - x0 = p[6]; y0 = p[7]; - x1 = p[2]; y1 = p[3]; - y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ? - y1 + p[1] - p[3] : y1; - /* find intersection of clip rectangle and - * border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_out)) - return false; - } - } - } else { - /* Border made up from two parts and can't be plotted - * with rectangles */ - z[0] = p[0]; - z[1] = p[1]; - z[2] = (p[0] + p[2]) / 2; - z[3] = (p[1] + p[3]) / 2; - z[4] = (p[6] + p[4]) / 2; - z[5] = (p[7] + p[5]) / 2; - z[6] = p[6]; - z[7] = p[7]; - if (!plot->polygon(z, 4, plot_style_bdr_in)) - return false; - z[0] = p[2]; - z[1] = p[3]; - z[6] = p[4]; - z[7] = p[5]; - if (!plot->polygon(z, 4, plot_style_bdr_out)) - return false; - } - break; - - case CSS_BORDER_STYLE_INSET: - light = (light + 2) % 4; - /* fall through */ - case CSS_BORDER_STYLE_OUTSET: - /* choose correct colours for each part of the border line */ - switch (light) { - case 0: - plot_style_bdr_in = &plot_style_fillbdr_light; - plot_style_bdr_out = &plot_style_fillbdr_dlight; - break; - case 1: - plot_style_bdr_in = &plot_style_fillbdr_ddark; - plot_style_bdr_out = &plot_style_fillbdr_dark; - break; - case 2: - plot_style_bdr_in = &plot_style_fillbdr_dark; - plot_style_bdr_out = &plot_style_fillbdr_ddark; - break; - case 3: - plot_style_bdr_in = &plot_style_fillbdr_dlight; - plot_style_bdr_out = &plot_style_fillbdr_light; - break; - default: - plot_style_bdr_in = &plot_style_fillbdr; - plot_style_bdr_out = &plot_style_fillbdr; - break; - } - - /* Render border */ - if ((rectangular || thickness == 2) && thickness != 1) { - /* Border made up from two parts and can be plotted - * with rectangles */ - int x0, y0, x1, y1; - - /* First part */ - if (side == TOP || side == RIGHT) { - x0 = (p[0] + p[2]) / 2; y0 = (p[1] + p[3]) / 2; - x1 = p[6]; y1 = p[7]; - } else { - x0 = p[6]; y0 = p[7]; - x1 = (p[0] + p[2]) / 2; y1 = (p[1] + p[3]) / 2; - } - /* find intersection of clip rectangle and border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_in)) - return false; - } - - /* Second part */ - if (side == TOP || side == RIGHT) { - x0 = p[2]; y0 = p[3]; - x1 = (p[6] + p[4]) / 2; y1 = (p[7] + p[5]) / 2; - } else { - x0 = (p[6] + p[4]) / 2; y0 = (p[7] + p[5]) / 2; - x1 = p[2]; y1 = p[3]; - } - /* find intersection of clip rectangle and border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_out)) - return false; - } - } else if (thickness == 1) { - /* Border made up from one part which can be plotted - * as a rectangle */ - int x0, y0, x1, y1; - if (side == TOP || side == RIGHT) { - x0 = p[2]; y0 = p[3]; - x1 = p[6]; y1 = p[7]; - x1 = ((side == TOP) && (p[4] - p[6] != 0)) ? - x1 + p[4] - p[6] : x1; - /* find intersection of clip rectangle and - * border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_in)) - return false; - } - } else { - x0 = p[6]; y0 = p[7]; - x1 = p[2]; y1 = p[3]; - y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ? - y1 + p[1] - p[3] : y1; - /* find intersection of clip rectangle and - * border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_out)) - return false; - } - } - } else { - /* Border made up from two parts and can't be plotted - * with rectangles */ - z[0] = p[0]; - z[1] = p[1]; - z[2] = (p[0] + p[2]) / 2; - z[3] = (p[1] + p[3]) / 2; - z[4] = (p[6] + p[4]) / 2; - z[5] = (p[7] + p[5]) / 2; - z[6] = p[6]; - z[7] = p[7]; - if (!plot->polygon(z, 4, plot_style_bdr_in)) - return false; - z[0] = p[2]; - z[1] = p[3]; - z[6] = p[4]; - z[7] = p[5]; - if (!plot->polygon(z, 4, plot_style_bdr_out)) - return false; - } - break; - } - - return true; -} - /** * Plot a checkbox. @@ -1921,8 +1133,8 @@ bool html_redraw_border_plot(const int side, const int *p, colour c, * \return true if successful, false otherwise */ -bool html_redraw_checkbox(int x, int y, int width, int height, bool selected, - const struct redraw_context *ctx) +static bool html_redraw_checkbox(int x, int y, int width, int height, + bool selected, const struct redraw_context *ctx) { const struct plotter_table *plot = ctx->plot; double z = width * 0.15; @@ -1977,8 +1189,8 @@ bool html_redraw_checkbox(int x, int y, int width, int height, bool selected, * \param ctx current redraw context * \return true if successful, false otherwise */ -bool html_redraw_radio(int x, int y, int width, int height, bool selected, - const struct redraw_context *ctx) +static bool html_redraw_radio(int x, int y, int width, int height, + bool selected, const struct redraw_context *ctx) { const struct plotter_table *plot = ctx->plot; @@ -2034,7 +1246,7 @@ bool html_redraw_radio(int x, int y, int width, int height, bool selected, * \return true if successful, false otherwise */ -bool html_redraw_file(int x, int y, int width, int height, +static bool html_redraw_file(int x, int y, int width, int height, struct box *box, float scale, colour background_colour, const struct redraw_context *ctx) { @@ -2082,7 +1294,7 @@ bool html_redraw_file(int x, int y, int width, int height, * to ::box, using the background information contained within ::background. */ -bool html_redraw_background(int x, int y, struct box *box, float scale, +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) { @@ -2302,9 +1514,10 @@ bool html_redraw_background(int x, int y, struct box *box, float scale, * \return true if successful, false otherwise */ -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 struct redraw_context *ctx) +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 struct redraw_context *ctx) { const struct plotter_table *plot = ctx->plot; struct rect r = *clip; @@ -2433,6 +1646,91 @@ bool html_redraw_inline_background(int x, int y, struct box *box, float scale, /** + * 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 + * \param ctx current redraw context + * \return true if successful, false otherwise + */ + +static bool html_redraw_text_decoration_inline(struct box *box, int x, int y, + float scale, colour colour, float ratio, + const struct redraw_context *ctx) +{ + const struct plotter_table *plot = ctx->plot; + struct box *c; + plot_style_t plot_style_box = { + .stroke_type = PLOT_OP_TYPE_SOLID, + .stroke_colour = colour, + }; + + for (c = box->next; + c && c != box->inline_end; + c = c->next) { + if (c->type != BOX_TEXT) + continue; + 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, + &plot_style_box)) + 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 + * \param ctx current redraw context + * \return true if successful, false otherwise + */ + +static bool html_redraw_text_decoration_block(struct box *box, int x, int y, + float scale, colour colour, float ratio, + const struct redraw_context *ctx) +{ + const struct plotter_table *plot = ctx->plot; + struct box *c; + plot_style_t plot_style_box = { + .stroke_type = PLOT_OP_TYPE_SOLID, + .stroke_colour = colour, + }; + + /* draw through text descendants */ + for (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, + &plot_style_box)) + 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, ctx)) + return false; + } + } + return true; +} + + +/** * Plot text decoration for a box. * * \param box box to plot decorations for @@ -2444,7 +1742,7 @@ bool html_redraw_inline_background(int x, int y, struct box *box, float scale, * \return true if successful, false otherwise */ -bool html_redraw_text_decoration(struct box *box, +static bool html_redraw_text_decoration(struct box *box, int x_parent, int y_parent, float scale, colour background_colour, const struct redraw_context *ctx) { @@ -2490,85 +1788,750 @@ bool html_redraw_text_decoration(struct box *box, /** - * Plot text decoration for an inline box. + * Redraw the text content of a box, possibly partially highlighted + * because the text has been selected, or matches a search operation. * - * \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 - * \param ctx current redraw context + * \param box box with text content + * \param x x co-ord of box + * \param y y co-ord of box + * \param clip current clip rectangle + * \param scale current scale setting (1.0 = 100%) + * \param current_background_color + * \param ctx current redraw context + * \return true iff successful and redraw should proceed + */ + +static bool html_redraw_text_box(const html_content *html, struct box *box, + int x, int y, const struct rect *clip, float scale, + colour current_background_color, + const struct redraw_context *ctx) +{ + bool excluded = (box->object != NULL); + plot_font_style_t fstyle; + + font_plot_style_from_css(box->style, &fstyle); + fstyle.background = current_background_color; + + if (!text_redraw(box->text, box->length, box->byte_offset, + box->space, &fstyle, x, y, + clip, box->height, scale, excluded, + (struct content *)html, &html->sel, + html->search, ctx)) + return false; + + return true; +} + +bool html_redraw_box(const html_content *html, struct box *box, + int x_parent, int y_parent, + const struct rect *clip, float scale, + colour current_background_color, + const struct redraw_context *ctx); + +/** + * Draw the various children of a box. + * + * \param html html content + * \param box box to draw children of + * \param x_parent coordinate of parent box + * \param y_parent coordinate of parent box + * \param clip clip rectangle + * \param scale scale for redraw + * \param current_background_color background colour under this box + * \param ctx current redraw context * \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, +static bool html_redraw_box_children(const html_content *html, struct box *box, + int x_parent, int y_parent, + const struct rect *clip, float scale, + colour current_background_color, const struct redraw_context *ctx) { - const struct plotter_table *plot = ctx->plot; struct box *c; - plot_style_t plot_style_box = { - .stroke_type = PLOT_OP_TYPE_SOLID, - .stroke_colour = colour, - }; - for (c = box->next; - c && c != box->inline_end; - c = c->next) { - if (c->type != BOX_TEXT) - continue; - 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, - &plot_style_box)) - return false; + for (c = box->children; c; c = c->next) { + + if (c->type != BOX_FLOAT_LEFT && c->type != BOX_FLOAT_RIGHT) + if (!html_redraw_box(html, c, + x_parent + box->x - + scrollbar_get_offset(box->scroll_x), + y_parent + box->y - + scrollbar_get_offset(box->scroll_y), + clip, scale, current_background_color, + ctx)) + return false; } + for (c = box->float_children; c; c = c->next_float) + if (!html_redraw_box(html, c, + x_parent + box->x - + scrollbar_get_offset(box->scroll_x), + y_parent + box->y - + scrollbar_get_offset(box->scroll_y), + clip, scale, current_background_color, + ctx)) + return false; + return true; } - /** - * Plot text decoration for an non-inline box. + * Recursively draw a 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 - * \param ctx current redraw context + * \param html html content + * \param box box to draw + * \param x_parent coordinate of parent box + * \param y_parent coordinate of parent box + * \param clip clip rectangle + * \param scale scale for redraw + * \param current_background_color background colour under this box + * \param ctx current redraw context * \return true if successful, false otherwise + * + * x, y, clip_[xy][01] are in target coordinates. */ -bool html_redraw_text_decoration_block(struct box *box, int x, int y, - float scale, colour colour, float ratio, +bool html_redraw_box(const html_content *html, struct box *box, + int x_parent, int y_parent, + const struct rect *clip, float scale, + colour current_background_color, const struct redraw_context *ctx) { const struct plotter_table *plot = ctx->plot; - struct box *c; - plot_style_t plot_style_box = { - .stroke_type = PLOT_OP_TYPE_SOLID, - .stroke_colour = colour, - }; + int x, y; + int width, height; + int padding_left, padding_top, padding_width, padding_height; + int border_left, border_top, border_right, border_bottom; + struct rect r; + int x_scrolled, y_scrolled; + struct box *bg_box = NULL; + bool has_x_scroll, has_y_scroll; + css_computed_clip_rect css_rect; - /* draw through text descendants */ - for (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, - &plot_style_box)) + if (html_redraw_printing && (box->flags & PRINTED)) + return true; + + /* avoid trivial FP maths */ + if (scale == 1.0) { + x = x_parent + box->x; + y = y_parent + box->y; + width = box->width; + height = box->height; + padding_left = box->padding[LEFT]; + padding_top = box->padding[TOP]; + padding_width = padding_left + box->width + box->padding[RIGHT]; + padding_height = padding_top + box->height + + box->padding[BOTTOM]; + border_left = box->border[LEFT].width; + border_top = box->border[TOP].width; + border_right = box->border[RIGHT].width; + border_bottom = box->border[BOTTOM].width; + } else { + x = (x_parent + box->x) * scale; + y = (y_parent + box->y) * scale; + width = box->width * scale; + height = box->height * scale; + /* left and top padding values are normally zero, + * so avoid trivial FP maths */ + padding_left = box->padding[LEFT] ? box->padding[LEFT] * scale + : 0; + padding_top = box->padding[TOP] ? box->padding[TOP] * scale + : 0; + padding_width = (box->padding[LEFT] + box->width + + box->padding[RIGHT]) * scale; + padding_height = (box->padding[TOP] + box->height + + box->padding[BOTTOM]) * scale; + border_left = box->border[LEFT].width * scale; + border_top = box->border[TOP].width * scale; + border_right = box->border[RIGHT].width * scale; + border_bottom = box->border[BOTTOM].width * scale; + } + + /* calculate rectangle covering this box and descendants */ + if (box->style && css_computed_overflow(box->style) != + CSS_OVERFLOW_VISIBLE) { + /* box contents clipped to box size */ + r.x0 = x - border_left; + r.y0 = y - border_top; + r.x1 = x + padding_width + border_right; + r.y1 = y + padding_height + border_bottom; + } else { + /* box contents can hang out of the box; use descendant box */ + if (scale == 1.0) { + r.x0 = x + box->descendant_x0; + r.y0 = y + box->descendant_y0; + r.x1 = x + box->descendant_x1 + 1; + r.y1 = y + box->descendant_y1 + 1; + } else { + r.x0 = x + box->descendant_x0 * scale; + r.y0 = y + box->descendant_y0 * scale; + r.x1 = x + box->descendant_x1 * scale + 1; + r.y1 = y + box->descendant_y1 * scale + 1; + } + if (!box->parent) { + /* root element */ + int margin_left, margin_right; + int margin_top, margin_bottom; + if (scale == 1.0) { + margin_left = box->margin[LEFT]; + margin_top = box->margin[TOP]; + margin_right = box->margin[RIGHT]; + margin_bottom = box->margin[BOTTOM]; + } else { + margin_left = box->margin[LEFT] * scale; + margin_top = box->margin[TOP] * scale; + margin_right = box->margin[RIGHT] * scale; + margin_bottom = box->margin[BOTTOM] * scale; + } + r.x0 = x - border_left - margin_left < r.x0 ? + x - border_left - margin_left : r.x0; + r.y0 = y - border_top - margin_top < r.y0 ? + y - border_top - margin_top : r.y0; + r.x1 = x + padding_width + border_right + + margin_right > r.x1 ? + x + padding_width + border_right + + margin_right : r.x1; + r.y1 = y + padding_height + border_bottom + + margin_bottom > r.y1 ? + y + padding_height + border_bottom + + margin_bottom : r.y1; + } + } + + /* return if the rectangle is completely outside the clip rectangle */ + if (clip->y1 < r.y0 || r.y1 < clip->y0 || + clip->x1 < r.x0 || r.x1 < clip->x0) + return true; + + /*if the rectangle is under the page bottom but it can fit in a page, + don't print it now*/ + if (html_redraw_printing) { + if (r.y1 > html_redraw_printing_border) { + if (r.y1 - r.y0 <= html_redraw_printing_border && + (box->type == BOX_TEXT || + box->type == BOX_TABLE_CELL + || box->object || box->gadget)) { + /*remember the highest of all points from the + not printed elements*/ + if (r.y0 < html_redraw_printing_top_cropped) + html_redraw_printing_top_cropped = r.y0; + return true; + } + } + else box->flags |= PRINTED; /*it won't be printed anymore*/ + } + + /* if visibility is hidden render children only */ + if (box->style && css_computed_visibility(box->style) == + CSS_VISIBILITY_HIDDEN) { + if ((plot->group_start) && (!plot->group_start("hidden box"))) + return false; + if (!html_redraw_box_children(html, box, x_parent, y_parent, + &r, scale, current_background_color, ctx)) + return false; + return ((!plot->group_end) || (plot->group_end())); + } + + if ((plot->group_start) && (!plot->group_start("vis box"))) + return false; + + + if (box->style != NULL && + css_computed_position(box->style) == + CSS_POSITION_ABSOLUTE && + css_computed_clip(box->style, &css_rect) == + CSS_CLIP_RECT) { + /* We have an absolutly positioned box with a clip rect */ + if (css_rect.left_auto == false) + r.x0 = x - border_left + FIXTOINT(nscss_len2px( + css_rect.left, css_rect.lunit, + box->style)); + + if (css_rect.top_auto == false) + r.y0 = y - border_top + FIXTOINT(nscss_len2px( + css_rect.top, css_rect.tunit, + box->style)); + + if (css_rect.right_auto == false) + r.x1 = x - border_left + FIXTOINT(nscss_len2px( + css_rect.right, css_rect.runit, + box->style)); + + if (css_rect.bottom_auto == false) + r.y1 = y - border_top + FIXTOINT(nscss_len2px( + css_rect.bottom, css_rect.bunit, + box->style)); + + /* find intersection of clip rectangle and box */ + if (r.x0 < clip->x0) r.x0 = clip->x0; + if (r.y0 < clip->y0) r.y0 = clip->y0; + if (clip->x1 < r.x1) r.x1 = clip->x1; + if (clip->y1 < r.y1) r.y1 = clip->y1; + /* no point trying to draw 0-width/height boxes */ + if (r.x0 == r.x1 || r.y0 == r.y1) + /* not an error */ + return ((!plot->group_end) || (plot->group_end())); + /* clip to it */ + if (!plot->clip(&r)) + return false; + + } else if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || + box->type == BOX_TABLE_CELL || box->object) { + /* find intersection of clip rectangle and box */ + if (r.x0 < clip->x0) r.x0 = clip->x0; + if (r.y0 < clip->y0) r.y0 = clip->y0; + if (clip->x1 < r.x1) r.x1 = clip->x1; + if (clip->y1 < r.y1) r.y1 = clip->y1; + /* no point trying to draw 0-width/height boxes */ + if (r.x0 == r.x1 || r.y0 == r.y1) + /* not an error */ + return ((!plot->group_end) || (plot->group_end())); + /* clip to it */ + if (!plot->clip(&r)) + return false; + } else { + /* clip box is fine, clip to it */ + r = *clip; + if (!plot->clip(&r)) + return false; + } + + /* background colour and image for block level content and replaced + * inlines */ + + bg_box = html_redraw_find_bg_box(box); + + /* bg_box == NULL implies that this box should not have + * its background rendered. Otherwise filter out linebreaks, + * optimize away non-differing inlines, only plot background + * for BOX_TEXT it's in an inline */ + if (bg_box && bg_box->type != BOX_BR && + bg_box->type != BOX_TEXT && + bg_box->type != BOX_INLINE_END && + (bg_box->type != BOX_INLINE || bg_box->object || + bg_box->flags & IFRAME || box->flags & REPLACE_DIM)) { + /* find intersection of clip box and border edge */ + struct rect p; + p.x0 = x - border_left < r.x0 ? r.x0 : x - border_left; + p.y0 = y - border_top < r.y0 ? r.y0 : y - border_top; + p.x1 = x + padding_width + border_right < r.x1 ? + x + padding_width + border_right : r.x1; + p.y1 = y + padding_height + border_bottom < r.y1 ? + y + padding_height + border_bottom : r.y1; + if (!box->parent) { + /* Root element, special case: + * background covers margins too */ + int m_left, m_top, m_right, m_bottom; + if (scale == 1.0) { + m_left = box->margin[LEFT]; + m_top = box->margin[TOP]; + m_right = box->margin[RIGHT]; + m_bottom = box->margin[BOTTOM]; + } else { + m_left = box->margin[LEFT] * scale; + m_top = box->margin[TOP] * scale; + m_right = box->margin[RIGHT] * scale; + m_bottom = box->margin[BOTTOM] * scale; + } + p.x0 = p.x0 - m_left < r.x0 ? r.x0 : p.x0 - m_left; + p.y0 = p.y0 - m_top < r.y0 ? r.y0 : p.y0 - m_top; + p.x1 = p.x1 + m_right < r.x1 ? p.x1 + m_right : r.x1; + p.y1 = p.y1 + m_bottom < r.y1 ? p.y1 + m_bottom : r.y1; + } + /* valid clipping rectangles only */ + 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)) 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, ctx)) + /* restore previous graphics window */ + if (!plot->clip(&r)) return false; } } - return true; + + /* borders for block level content and replaced inlines */ + if (box->style && box->type != BOX_TEXT && + box->type != BOX_INLINE_END && + (box->type != BOX_INLINE || box->object || + box->flags & IFRAME || box->flags & REPLACE_DIM) && + (border_top || border_right || + border_bottom || border_left)) { + if (!html_redraw_borders(box, x_parent, y_parent, + padding_width, padding_height, &r, + scale, ctx)) + return false; + } + + /* backgrounds and borders for non-replaced inlines */ + if (box->style && box->type == BOX_INLINE && box->inline_end && + (html_redraw_box_has_background(box) || + border_top || border_right || + border_bottom || border_left)) { + /* inline backgrounds and borders span other boxes and may + * wrap onto separate lines */ + struct box *ib; + struct rect b; /* border edge rectangle */ + struct rect p; /* clipped rect */ + bool first = true; + int ib_x; + int ib_y = y; + int ib_p_width; + int ib_b_left, ib_b_right; + + b.x0 = x - border_left; + b.x1 = x + padding_width + border_right; + b.y0 = y - border_top; + b.y1 = y + padding_height + border_bottom; + + p.x0 = b.x0 < r.x0 ? r.x0 : b.x0; + p.x1 = b.x1 < r.x1 ? b.x1 : r.x1; + p.y0 = b.y0 < r.y0 ? r.y0 : b.y0; + p.y1 = b.y1 < r.y1 ? b.y1 : r.y1; + for (ib = box; ib; ib = ib->next) { + /* to get extents of rectangle(s) associated with + * inline, cycle though all boxes in inline, skipping + * over floats */ + if (ib->type == BOX_FLOAT_LEFT || + ib->type == BOX_FLOAT_RIGHT) + continue; + if (scale == 1.0) { + ib_x = x_parent + ib->x; + ib_y = y_parent + ib->y; + ib_p_width = ib->padding[LEFT] + ib->width + + ib->padding[RIGHT]; + ib_b_left = ib->border[LEFT].width; + ib_b_right = ib->border[RIGHT].width; + } else { + ib_x = (x_parent + ib->x) * scale; + ib_y = (y_parent + ib->y) * scale; + ib_p_width = (ib->padding[LEFT] + ib->width + + ib->padding[RIGHT]) * scale; + ib_b_left = ib->border[LEFT].width * scale; + ib_b_right = ib->border[RIGHT].width * scale; + } + + if ((ib->flags & NEW_LINE) && ib != box) { + /* inline element has wrapped, plot background + * and borders */ + if (!html_redraw_inline_background( + x, y, box, scale, &p, b, + first, false, + ¤t_background_color, ctx)) + return false; + /* restore previous graphics window */ + if (!plot->clip(&r)) + return false; + if (!html_redraw_inline_borders(box, b, &r, + scale, first, false, ctx)) + return false; + /* reset coords */ + b.x0 = ib_x - ib_b_left; + b.y0 = ib_y - border_top - padding_top; + b.y1 = ib_y + padding_height - padding_top + + border_bottom; + + p.x0 = b.x0 < r.x0 ? r.x0 : b.x0; + p.y0 = b.y0 < r.y0 ? r.y0 : b.y0; + p.y1 = b.y1 < r.y1 ? b.y1 : r.y1; + + first = false; + } + + /* increase width for current box */ + b.x1 = ib_x + ib_p_width + ib_b_right; + p.x1 = b.x1 < r.x1 ? b.x1 : r.x1; + + if (ib == box->inline_end) + /* reached end of BOX_INLINE span */ + break; + } + /* 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)) + return false; + /* restore previous graphics window */ + if (!plot->clip(&r)) + return false; + if (!html_redraw_inline_borders(box, b, &r, scale, first, true, + ctx)) + return false; + + } + + /* Debug outlines */ + if (html_redraw_debug) { + int margin_left, margin_right; + int margin_top, margin_bottom; + if (scale == 1.0) { + /* avoid trivial fp maths */ + margin_left = box->margin[LEFT]; + margin_top = box->margin[TOP]; + margin_right = box->margin[RIGHT]; + margin_bottom = box->margin[BOTTOM]; + } else { + margin_left = box->margin[LEFT] * scale; + margin_top = box->margin[TOP] * scale; + margin_right = box->margin[RIGHT] * scale; + margin_bottom = box->margin[BOTTOM] * scale; + } + /* Content edge -- blue */ + if (!plot->rectangle(x + padding_left, + y + padding_top, + x + padding_left + width, + y + padding_top + height, + plot_style_content_edge)) + return false; + /* Padding edge -- red */ + if (!plot->rectangle(x, y, + x + padding_width, y + padding_height, + plot_style_padding_edge)) + return false; + /* Margin edge -- yellow */ + if (!plot->rectangle( + x - border_left - margin_left, + y - border_top - margin_top, + x + padding_width + border_right + + margin_right, + y + padding_height + border_bottom + + margin_bottom, + plot_style_margin_edge)) + return false; + } + + /* clip to the padding edge for objects, or boxes with overflow hidden + * or scroll */ + if ((box->style && css_computed_overflow(box->style) != + CSS_OVERFLOW_VISIBLE) || box->object || + box->flags & IFRAME) { + r.x0 = x; + r.y0 = y; + r.x1 = x + padding_width; + r.y1 = y + padding_height; + if (r.x0 < clip->x0) r.x0 = clip->x0; + if (r.y0 < clip->y0) r.y0 = clip->y0; + if (clip->x1 < r.x1) r.x1 = clip->x1; + if (clip->y1 < r.y1) r.y1 = clip->y1; + if (r.x1 <= r.x0 || r.y1 <= r.y0) + return ((!plot->group_end) || (plot->group_end())); + if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || + box->type == BOX_TABLE_CELL || box->object) { + if (!plot->clip(&r)) + return false; + } + } + + /* text decoration */ + if (box->type != BOX_TEXT && box->style && + css_computed_text_decoration(box->style) != + CSS_TEXT_DECORATION_NONE) + if (!html_redraw_text_decoration(box, x_parent, y_parent, + scale, current_background_color, ctx)) + return false; + + if (box->object && width != 0 && height != 0) { + struct content_redraw_data obj_data; + + x_scrolled = x - scrollbar_get_offset(box->scroll_x) * scale; + y_scrolled = y - scrollbar_get_offset(box->scroll_y) * scale; + + obj_data.x = x_scrolled + padding_left; + obj_data.y = y_scrolled + padding_top; + obj_data.width = width; + obj_data.height = height; + obj_data.background_colour = current_background_color; + obj_data.scale = scale; + obj_data.repeat_x = false; + obj_data.repeat_y = false; + + if (content_get_type(box->object) == CONTENT_HTML) { + obj_data.x /= scale; + obj_data.y /= scale; + } + + if (!content_redraw(box->object, &obj_data, &r, ctx)) { + /* Show image fail */ + /* Unicode (U+FFFC) 'OBJECT REPLACEMENT CHARACTER' */ + const char *obj = "\xef\xbf\xbc"; + int obj_width; + int obj_x = x + padding_left; + if (!plot->rectangle(x + padding_left, + y + padding_top, + x + padding_left + width - 1, + y + padding_top + height - 1, + plot_style_broken_object)) + return false; + if (!nsfont.font_width(plot_fstyle_broken_object, obj, + sizeof(obj) - 1, &obj_width)) + obj_x += 1; + else + obj_x += width / 2 - obj_width / 2; + + if (!plot->text(obj_x, y + padding_top + (int) + (height * 0.75), + obj, sizeof(obj) - 1, + plot_fstyle_broken_object)) + return false; + } + + + } else if (box->iframe) { + /* Offset is passed to browser window redraw unscaled */ + browser_window_redraw(box->iframe, + (x + padding_left) / scale, + (y + padding_top) / scale, &r, ctx); + + } else if (box->gadget && box->gadget->type == GADGET_CHECKBOX) { + if (!html_redraw_checkbox(x + padding_left, y + padding_top, + width, height, box->gadget->selected, ctx)) + return false; + + } else if (box->gadget && box->gadget->type == GADGET_RADIO) { + if (!html_redraw_radio(x + padding_left, y + padding_top, + width, height, box->gadget->selected, ctx)) + return false; + + } 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)) + return false; + + } else if (box->text) { + if (!html_redraw_text_box(html, box, x, y, &r, scale, + current_background_color, ctx)) + return false; + + } else { + if (!html_redraw_box_children(html, box, x_parent, y_parent, &r, + scale, current_background_color, ctx)) + return false; + } + + if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || + box->type == BOX_TABLE_CELL || box->type == BOX_INLINE) + if (!plot->clip(clip)) + return false; + + /* list marker */ + if (box->list_marker) + if (!html_redraw_box(html, box->list_marker, + x_parent + box->x - + scrollbar_get_offset(box->scroll_x), + y_parent + box->y - + scrollbar_get_offset(box->scroll_y), + clip, scale, current_background_color, ctx)) + return false; + + /* scrollbars */ + if (((box->style && box->type != BOX_BR && + box->type != BOX_TABLE && box->type != BOX_INLINE && + (css_computed_overflow(box->style) == + CSS_OVERFLOW_SCROLL || + css_computed_overflow(box->style) == + CSS_OVERFLOW_AUTO)) || (box->object && + content_get_type(box->object) == CONTENT_HTML)) && + box->parent != NULL) { + + has_x_scroll = box_hscrollbar_present(box); + has_y_scroll = box_vscrollbar_present(box); + + if (!box_handle_scrollbars((struct content *)html, + box, has_x_scroll, has_y_scroll)) + return false; + + if (box->scroll_x != NULL) + scrollbar_redraw(box->scroll_x, + x_parent + box->x, + y_parent + box->y + box->padding[TOP] + + box->height + box->padding[BOTTOM] - + SCROLLBAR_WIDTH, clip, scale, ctx); + if (box->scroll_y != NULL) + scrollbar_redraw(box->scroll_y, + x_parent + box->x + box->padding[LEFT] + + box->width + box->padding[RIGHT] - + SCROLLBAR_WIDTH, + y_parent + box->y, clip, scale, ctx); + } + + if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || + box->type == BOX_TABLE_CELL || box->type == BOX_INLINE) + if (!plot->clip(clip)) + return false; + + return ((!plot->group_end) || (plot->group_end())); +} + +/** + * Draw a CONTENT_HTML using the current set of plotters (plot). + * + * \param c content of type CONTENT_HTML + * \param data redraw data for this content redraw + * \param clip current clip region + * \param ctx current redraw context + * \return true if successful, false otherwise + * + * x, y, clip_[xy][01] are in target coordinates. + */ + +bool html_redraw(struct content *c, struct content_redraw_data *data, + const struct rect *clip, const struct redraw_context *ctx) +{ + html_content *html = (html_content *) c; + struct box *box; + bool result = true; + bool select, select_only; + plot_style_t pstyle_fill_bg = { + .fill_type = PLOT_OP_TYPE_SOLID, + .fill_colour = data->background_colour, + }; + + box = html->layout; + assert(box); + + /* The select menu needs special treating because, when opened, it + * reaches beyond its layout box. + */ + select = false; + select_only = false; + if (ctx->interactive && html->visible_select_menu != NULL) { + struct form_control *control = html->visible_select_menu; + select = true; + /* check if the redraw rectangle is completely inside of the + select menu */ + select_only = form_clip_inside_select_menu(control, + data->scale, clip); + } + + if (!select_only) { + /* clear to background colour */ + result = ctx->plot->clip(clip); + + if (html->background_colour != NS_TRANSPARENT) + pstyle_fill_bg.fill_colour = html->background_colour; + + result &= ctx->plot->rectangle(clip->x0, clip->y0, + clip->x1, clip->y1, + &pstyle_fill_bg); + + result &= html_redraw_box(html, box, data->x, data->y, clip, + data->scale, pstyle_fill_bg.fill_colour, ctx); + } + + if (select) { + int menu_x, menu_y; + box = html->visible_select_menu->box; + box_coords(box, &menu_x, &menu_y); + + menu_x -= box->border[LEFT].width; + menu_y += box->height + box->border[BOTTOM].width + + box->padding[BOTTOM] + box->padding[TOP]; + result &= form_redraw_select_menu(html->visible_select_menu, + data->x + menu_x, data->y + menu_y, + data->scale, clip, ctx); + } + + return result; + } |