summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2017-02-06 18:17:39 +0000
committerVincent Sanders <vince@kyllikki.org>2017-02-11 13:57:06 +0000
commit18abdadac83789019ae1a36a1e1cad2e98601efa (patch)
treef49fa7b8c8f00694684c597544cd8e5ed00d5880 /render
parent30df27c3babe188cc553df77e84a36b4db84bd47 (diff)
downloadnetsurf-18abdadac83789019ae1a36a1e1cad2e98601efa.tar.gz
netsurf-18abdadac83789019ae1a36a1e1cad2e98601efa.tar.bz2
split border drawing out of html redraw
Diffstat (limited to 'render')
-rw-r--r--render/Makefile3
-rw-r--r--render/html_internal.h9
-rw-r--r--render/html_redraw.c846
-rw-r--r--render/html_redraw_border.c928
4 files changed, 939 insertions, 847 deletions
diff --git a/render/Makefile b/render/Makefile
index 148c2c39d..dc2e31c9e 100644
--- a/render/Makefile
+++ b/render/Makefile
@@ -3,7 +3,8 @@
S_RENDER := box.c box_construct.c box_normalise.c box_textarea.c \
font.c form.c imagemap.c layout.c search.c table.c textplain.c \
html.c html_css.c html_css_fetcher.c html_script.c \
- html_interaction.c html_redraw.c html_forms.c html_object.c
+ html_interaction.c html_redraw.c html_redraw_border.c \
+ html_forms.c html_object.c
S_RENDER := $(addprefix render/,$(S_RENDER))
diff --git a/render/html_internal.h b/render/html_internal.h
index fd65707ce..2f84cf869 100644
--- a/render/html_internal.h
+++ b/render/html_internal.h
@@ -258,6 +258,15 @@ bool html_begin_conversion(html_content *htmlc);
bool html_redraw(struct content *c, struct content_redraw_data *data,
const struct rect *clip, const struct redraw_context *ctx);
+/* in render/html_redraw_border.c */
+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);
+
+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);
+
/* in render/html_interaction.c */
void html_mouse_track(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
diff --git a/render/html_redraw.c b/render/html_redraw.c
index e58918d81..598e613ca 100644
--- a/render/html_redraw.c
+++ b/render/html_redraw.c
@@ -344,852 +344,6 @@ text_redraw(const char *utf8_text,
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,
-};
-
-static inline nserror
-plot_clipped_rectangle(const struct redraw_context *ctx,
- const plot_style_t *style,
- const struct rect *clip,
- struct rect *rect)
-{
- nserror res;
-
- rect->x0 = (clip->x0 > rect->x0) ? clip->x0 : rect->x0;
- rect->y0 = (clip->y0 > rect->y0) ? clip->y0 : rect->y0;
- rect->x1 = (clip->x1 < rect->x1) ? clip->x1 : rect->x1;
- rect->y1 = (clip->y1 < rect->y1) ? clip->y1 : rect->y1;
- if ((rect->x0 < rect->x1) && (rect->y0 < rect->y1)) {
- /* valid clip rectangles only */
- res = ctx->plot->rectangle(ctx, style, rect);
- } else {
- res = NSERROR_OK;
- }
- return res;
-}
-
-/**
- * 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 clip cliping area for redrawing border.
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static nserror
-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)
-{
- 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;
- nserror res = NSERROR_OK;
- struct rect rect;
-
- if (c == NS_TRANSPARENT) {
- return res;
- }
-
- 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:
- rect.x0 = (p[0] + p[2]) / 2;
- rect.y0 = (p[1] + p[3]) / 2;
- rect.x1 = (p[4] + p[6]) / 2;
- rect.y1 = (p[5] + p[7]) / 2;
- res = ctx->plot->line(ctx, &plot_style_bdr, &rect);
- break;
-
- case CSS_BORDER_STYLE_SOLID:
- /* fall through to default */
- default:
- if (rectangular || thickness == 1) {
-
- if (side == TOP || side == RIGHT) {
- rect.x0 = p[2];
- rect.y0 = p[3];
- if ((side == TOP) &&
- (p[4] - p[6] != 0)) {
- rect.x1 = p[4];
- } else {
- rect.x1 = p[6];
- }
- rect.y1 = p[7];
- } else {
- rect.x0 = p[6];
- rect.y0 = p[7];
- rect.x1 = p[2];
- if ((side == LEFT) &&
- (p[1] - p[3] != 0)) {
- rect.y1 = p[1];
- } else {
- rect.y1 = p[3];
- }
- }
- res = plot_clipped_rectangle(ctx, &plot_style_fillbdr, clip, &rect);
- } else {
- res = ctx->plot->polygon(ctx, &plot_style_fillbdr, p, 4);
- }
- 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];
- res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4);
- if (res == NSERROR_OK) {
- 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];
- res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4);
- }
- 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
- */
-
- /* First part */
- if (side == TOP || side == RIGHT) {
- rect.x0 = (p[0] + p[2]) / 2;
- rect.y0 = (p[1] + p[3]) / 2;
- rect.x1 = p[6];
- rect.y1 = p[7];
- } else {
- rect.x0 = p[6];
- rect.y0 = p[7];
- rect.x1 = (p[0] + p[2]) / 2;
- rect.y1 = (p[1] + p[3]) / 2;
- }
- res = plot_clipped_rectangle(ctx, plot_style_bdr_in, clip, &rect);
- if (res != NSERROR_OK) {
- return res;
- }
-
- /* Second part */
- if (side == TOP || side == RIGHT) {
- rect.x0 = p[2];
- rect.y0 = p[3];
- rect.x1 = (p[6] + p[4]) / 2;
- rect.y1 = (p[7] + p[5]) / 2;
- } else {
- rect.x0 = (p[6] + p[4]) / 2;
- rect.y0 = (p[7] + p[5]) / 2;
- rect.x1 = p[2];
- rect.y1 = p[3];
- }
- res = plot_clipped_rectangle(ctx, plot_style_bdr_out, clip, &rect);
- } else if (thickness == 1) {
- /* Border made up from one part which can be
- * plotted as a rectangle
- */
-
- if (side == TOP || side == RIGHT) {
- rect.x0 = p[2];
- rect.y0 = p[3];
- rect.x1 = p[6];
- rect.y1 = p[7];
- rect.x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
- rect.x1 + p[4] - p[6] : rect.x1;
-
- res = plot_clipped_rectangle(ctx, plot_style_bdr_in, clip, &rect);
- } else {
- rect.x0 = p[6];
- rect.y0 = p[7];
- rect.x1 = p[2];
- rect.y1 = p[3];
- rect.y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
- rect.y1 + p[1] - p[3] : rect.y1;
- res = plot_clipped_rectangle(ctx, plot_style_bdr_out, clip, &rect);
- }
- } 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];
- res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4);
- if (res != NSERROR_OK) {
- return res;
- }
- z[0] = p[2];
- z[1] = p[3];
- z[6] = p[4];
- z[7] = p[5];
- res = ctx->plot->polygon(ctx, plot_style_bdr_out, z, 4);
- }
- 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
- */
-
- /* First part */
- if (side == TOP || side == RIGHT) {
- rect.x0 = (p[0] + p[2]) / 2;
- rect.y0 = (p[1] + p[3]) / 2;
- rect.x1 = p[6];
- rect.y1 = p[7];
- } else {
- rect.x0 = p[6];
- rect.y0 = p[7];
- rect.x1 = (p[0] + p[2]) / 2;
- rect.y1 = (p[1] + p[3]) / 2;
- }
- res = plot_clipped_rectangle(ctx, plot_style_bdr_in, clip, &rect);
- if (res != NSERROR_OK) {
- return res;
- }
-
- /* Second part */
- if (side == TOP || side == RIGHT) {
- rect.x0 = p[2];
- rect.y0 = p[3];
- rect.x1 = (p[6] + p[4]) / 2;
- rect.y1 = (p[7] + p[5]) / 2;
- } else {
- rect.x0 = (p[6] + p[4]) / 2;
- rect.y0 = (p[7] + p[5]) / 2;
- rect.x1 = p[2];
- rect.y1 = p[3];
- }
- res = plot_clipped_rectangle(ctx, plot_style_bdr_out, clip, &rect);
- } else if (thickness == 1) {
- /* Border made up from one part which can be
- * plotted as a rectangle
- */
-
- if (side == TOP || side == RIGHT) {
- rect.x0 = p[2];
- rect.y0 = p[3];
- rect.x1 = p[6];
- rect.y1 = p[7];
- rect.x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
- rect.x1 + p[4] - p[6] : rect.x1;
- res = plot_clipped_rectangle(ctx, plot_style_bdr_in, clip, &rect);
- } else {
- rect.x0 = p[6];
- rect.y0 = p[7];
- rect.x1 = p[2];
- rect.y1 = p[3];
- rect.y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
- rect.y1 + p[1] - p[3] : rect.y1;
- res = plot_clipped_rectangle(ctx, plot_style_bdr_out, clip, &rect);
- }
- } 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];
- res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4);
- if (res != NSERROR_OK) {
- return res;
- }
- z[0] = p[2];
- z[1] = p[3];
- z[6] = p[4];
- z[7] = p[5];
- res = ctx->plot->polygon(ctx, plot_style_bdr_out, z, 4);
- }
- break;
- }
-
- return res;
-}
-
-
-/**
- * Draw borders for a box.
- *
- * \param box box to draw
- * \param x_parent coordinate of left padding edge of parent of box
- * \param y_parent coordinate of top padding edge of parent of box
- * \param p_width width of padding box
- * \param p_height height of padding box
- * \param clip cliping area for redrawing border.
- * \param scale scale for redraw
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-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)
-{
- unsigned int sides[] = { LEFT, RIGHT, TOP, BOTTOM };
- int top = box->border[TOP].width;
- int right = box->border[RIGHT].width;
- int bottom = box->border[BOTTOM].width;
- int left = box->border[LEFT].width;
- int x, y;
- unsigned int i, side;
- int p[8]; /* Box border vertices */
- int z[8]; /* Border vertices */
- bool square_end_1 = false;
- bool square_end_2 = false;
- nserror res;
-
- x = x_parent + box->x;
- y = y_parent + box->y;
-
- if (scale != 1.0) {
- top *= scale;
- right *= scale;
- bottom *= scale;
- left *= scale;
- x *= scale;
- y *= scale;
- }
-
- assert(box->style);
-
- /* Calculate border vertices
- *
- * A----------------------+
- * | \ / |
- * | B--------------+ |
- * | | | |
- * | +--------------C |
- * | / \ |
- * +----------------------D
- */
- p[0] = x - left; p[1] = y - top; /* A */
- p[2] = x; p[3] = y; /* B */
- p[4] = x + p_width; p[5] = y + p_height; /* C */
- p[6] = x + p_width + right; p[7] = y + p_height + bottom; /* D */
-
- for (i = 0; i != 4; i++) {
- colour col = 0;
- side = sides[i]; /* plot order */
-
- if (box->border[side].width == 0 ||
- nscss_color_is_transparent(box->border[side].c))
- continue;
-
- switch (side) {
- case LEFT:
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
-
- z[0] = p[0]; z[1] = p[7];
- z[2] = p[2]; z[3] = p[5];
- z[4] = p[2]; z[5] = p[3];
- z[6] = p[0]; z[7] = p[1];
-
- if (nscss_color_is_transparent(box->border[TOP].c) ==
- false &&
- box->border[TOP].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque */
- z[5] -= top;
- square_end_1 = true;
- }
- if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
- false &&
- box->border[BOTTOM].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque */
- z[3] += bottom;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- res = html_redraw_border_plot(side,
- z,
- col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- break;
-
- case RIGHT:
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
-
- z[0] = p[6]; z[1] = p[1];
- z[2] = p[4]; z[3] = p[3];
- z[4] = p[4]; z[5] = p[5];
- z[6] = p[6]; z[7] = p[7];
-
- if (nscss_color_is_transparent(box->border[TOP].c) ==
- false &&
- box->border[TOP].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque */
- z[3] -= top;
- square_end_1 = true;
- }
- if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
- false &&
- box->border[BOTTOM].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque */
- z[5] += bottom;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- res = html_redraw_border_plot(side,
- z,
- col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- break;
-
- case TOP:
- if (clip->y0 > p[3])
- /* clip rectangle is below border; nothing to
- * plot */
- continue;
-
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
-
- z[0] = p[2]; z[1] = p[3];
- z[2] = p[0]; z[3] = p[1];
- z[4] = p[6]; z[5] = p[1];
- z[6] = p[4]; z[7] = p[3];
-
- if (box->border[TOP].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c ==
- box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway */
- z[2] += left;
- square_end_1 = true;
- }
- if (box->border[TOP].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c ==
- box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway */
- z[4] -= right;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- res = html_redraw_border_plot(side,
- z,
- col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- break;
-
- case BOTTOM:
- if (clip->y1 < p[5])
- /* clip rectangle is above border; nothing to
- * plot */
- continue;
-
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
-
- z[0] = p[4]; z[1] = p[5];
- z[2] = p[6]; z[3] = p[7];
- z[4] = p[0]; z[5] = p[7];
- z[6] = p[2]; z[7] = p[5];
-
- if (box->border[BOTTOM].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c ==
- box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway */
- z[4] += left;
- square_end_1 = true;
- }
- if (box->border[BOTTOM].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c ==
- box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway */
- z[2] -= right;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- res = html_redraw_border_plot(side,
- z,
- col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- break;
-
- default:
- assert(side == TOP || side == BOTTOM ||
- side == LEFT || side == RIGHT);
- break;
- }
- }
-
- return true;
-}
-
-
-/**
- * Draw an inline's borders.
- *
- * \param box BOX_INLINE which created the border
- * \param b coordinates of border edge rectangle
- * \param clip cliping area for redrawing border.
- * \param scale scale for redraw
- * \param first true if this is the first rectangle associated with the inline
- * \param last true if this is the last rectangle associated with the inline
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-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)
-{
- int top = box->border[TOP].width;
- int right = box->border[RIGHT].width;
- int bottom = box->border[BOTTOM].width;
- int left = box->border[LEFT].width;
- colour col;
- int p[8]; /* Box border vertices */
- int z[8]; /* Border vertices */
- bool square_end_1;
- bool square_end_2;
- nserror res;
-
- if (scale != 1.0) {
- top *= scale;
- right *= scale;
- bottom *= scale;
- left *= scale;
- }
-
- /* Calculate border vertices
- *
- * A----------------------+
- * | \ / |
- * | B--------------+ |
- * | | | |
- * | +--------------C |
- * | / \ |
- * +----------------------D
- */
- p[0] = b.x0; p[1] = b.y0; /* A */
- p[2] = first ? b.x0 + left : b.x0; p[3] = b.y0 + top; /* B */
- p[4] = last ? b.x1 - right : b.x1; p[5] = b.y1 - bottom; /* C */
- p[6] = b.x1; p[7] = b.y1; /* D */
-
- assert(box->style);
-
- /* Left */
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
- if (left != 0 && first && nscss_color_is_transparent(
- box->border[LEFT].c) == false) {
- col = nscss_color_to_ns(box->border[LEFT].c);
-
- z[0] = p[0]; z[1] = p[7];
- z[2] = p[2]; z[3] = p[5];
- z[4] = p[2]; z[5] = p[3];
- z[6] = p[0]; z[7] = p[1];
-
- if (nscss_color_is_transparent(box->border[TOP].c) == false &&
- box->border[TOP].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque */
- z[5] -= top;
- square_end_1 = true;
- }
-
- if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
- false &&
- box->border[BOTTOM].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque */
- z[3] += bottom;
- square_end_2 = true;
- }
-
- res = html_redraw_border_plot(LEFT,
- z,
- col,
- box->border[LEFT].style,
- left,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- }
-
- /* Right */
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
- if (right != 0 && last && nscss_color_is_transparent(
- box->border[RIGHT].c) == false) {
- col = nscss_color_to_ns(box->border[RIGHT].c);
-
- z[0] = p[6]; z[1] = p[1];
- z[2] = p[4]; z[3] = p[3];
- z[4] = p[4]; z[5] = p[5];
- z[6] = p[6]; z[7] = p[7];
-
- if (nscss_color_is_transparent(box->border[TOP].c) == false &&
- box->border[TOP].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque */
- z[3] -= top;
- square_end_1 = true;
- }
-
- if (nscss_color_is_transparent(box->border[BOTTOM].c) ==
- false &&
- box->border[BOTTOM].style !=
- CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque */
- z[5] += bottom;
- square_end_2 = true;
- }
-
- res = html_redraw_border_plot(RIGHT, z, col,
- box->border[RIGHT].style,
- right, square_end_1 && square_end_2,
- clip, ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- }
-
- /* Top */
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
- if (top != 0 && nscss_color_is_transparent(
- box->border[TOP].c) == false) {
- col = nscss_color_to_ns(box->border[TOP].c);
-
- z[0] = p[2]; z[1] = p[3];
- z[2] = p[0]; z[3] = p[1];
- z[4] = p[6]; z[5] = p[1];
- z[6] = p[4]; z[7] = p[3];
-
- if (first && box->border[TOP].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c ==
- box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway */
- z[2] += left;
- square_end_1 = true;
- }
-
- if (last && box->border[TOP].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c ==
- box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway */
- z[4] -= right;
- square_end_2 = true;
- }
-
- res = html_redraw_border_plot(TOP, z, col,
- box->border[TOP].style,
- top, square_end_1 && square_end_2,
- clip, ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- }
-
- /* Bottom */
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
- if (bottom != 0 && nscss_color_is_transparent(
- box->border[BOTTOM].c) == false) {
- col = nscss_color_to_ns(box->border[BOTTOM].c);
-
- z[0] = p[4]; z[1] = p[5];
- z[2] = p[6]; z[3] = p[7];
- z[4] = p[0]; z[5] = p[7];
- z[6] = p[2]; z[7] = p[5];
-
- if (first && box->border[BOTTOM].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c ==
- box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway */
- z[4] += left;
- square_end_1 = true;
- }
-
- if (last && box->border[BOTTOM].style ==
- CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c ==
- box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway */
- z[2] -= right;
- square_end_2 = true;
- }
-
- res = html_redraw_border_plot(BOTTOM, z, col,
- box->border[BOTTOM].style,
- bottom, square_end_1 && square_end_2,
- clip, ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- }
-
- return true;
-}
-
/**
* Plot a checkbox.
diff --git a/render/html_redraw_border.c b/render/html_redraw_border.c
new file mode 100644
index 000000000..07c503c41
--- /dev/null
+++ b/render/html_redraw_border.c
@@ -0,0 +1,928 @@
+/*
+ * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ *
+ * Redrawing CONTENT_HTML borders implementation.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "utils/log.h"
+#include "netsurf/plotters.h"
+#include "netsurf/css.h"
+
+#include "render/box.h"
+#include "render/html_internal.h"
+
+
+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,
+};
+
+
+static inline nserror
+plot_clipped_rectangle(const struct redraw_context *ctx,
+ const plot_style_t *style,
+ const struct rect *clip,
+ struct rect *rect)
+{
+ nserror res;
+
+ rect->x0 = (clip->x0 > rect->x0) ? clip->x0 : rect->x0;
+ rect->y0 = (clip->y0 > rect->y0) ? clip->y0 : rect->y0;
+ rect->x1 = (clip->x1 < rect->x1) ? clip->x1 : rect->x1;
+ rect->y1 = (clip->y1 < rect->y1) ? clip->y1 : rect->y1;
+ if ((rect->x0 < rect->x1) && (rect->y0 < rect->y1)) {
+ /* valid clip rectangles only */
+ res = ctx->plot->rectangle(ctx, style, rect);
+ } else {
+ res = NSERROR_OK;
+ }
+ return res;
+}
+
+
+/**
+ * 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 clip cliping area for redrawing border.
+ * \param ctx current redraw context
+ * \return NSERROR_OK if successful otherwise appropriate error code
+ */
+static nserror
+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)
+{
+ 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;
+ nserror res = NSERROR_OK;
+ struct rect rect;
+
+ if (c == NS_TRANSPARENT) {
+ return res;
+ }
+
+ 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:
+ rect.x0 = (p[0] + p[2]) / 2;
+ rect.y0 = (p[1] + p[3]) / 2;
+ rect.x1 = (p[4] + p[6]) / 2;
+ rect.y1 = (p[5] + p[7]) / 2;
+ res = ctx->plot->line(ctx, &plot_style_bdr, &rect);
+ break;
+
+ case CSS_BORDER_STYLE_SOLID:
+ /* fall through to default */
+ default:
+ if (rectangular || thickness == 1) {
+
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = p[2];
+ rect.y0 = p[3];
+ if ((side == TOP) &&
+ (p[4] - p[6] != 0)) {
+ rect.x1 = p[4];
+ } else {
+ rect.x1 = p[6];
+ }
+ rect.y1 = p[7];
+ } else {
+ rect.x0 = p[6];
+ rect.y0 = p[7];
+ rect.x1 = p[2];
+ if ((side == LEFT) &&
+ (p[1] - p[3] != 0)) {
+ rect.y1 = p[1];
+ } else {
+ rect.y1 = p[3];
+ }
+ }
+ res = plot_clipped_rectangle(ctx,
+ &plot_style_fillbdr,
+ clip,
+ &rect);
+ } else {
+ res = ctx->plot->polygon(ctx, &plot_style_fillbdr, p, 4);
+ }
+ 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];
+ res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4);
+ if (res == NSERROR_OK) {
+ 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];
+ res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4);
+ }
+ 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
+ */
+
+ /* First part */
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = (p[0] + p[2]) / 2;
+ rect.y0 = (p[1] + p[3]) / 2;
+ rect.x1 = p[6];
+ rect.y1 = p[7];
+ } else {
+ rect.x0 = p[6];
+ rect.y0 = p[7];
+ rect.x1 = (p[0] + p[2]) / 2;
+ rect.y1 = (p[1] + p[3]) / 2;
+ }
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_in,
+ clip,
+ &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* Second part */
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = p[2];
+ rect.y0 = p[3];
+ rect.x1 = (p[6] + p[4]) / 2;
+ rect.y1 = (p[7] + p[5]) / 2;
+ } else {
+ rect.x0 = (p[6] + p[4]) / 2;
+ rect.y0 = (p[7] + p[5]) / 2;
+ rect.x1 = p[2];
+ rect.y1 = p[3];
+ }
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_out,
+ clip,
+ &rect);
+ } else if (thickness == 1) {
+ /* Border made up from one part which can be
+ * plotted as a rectangle
+ */
+
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = p[2];
+ rect.y0 = p[3];
+ rect.x1 = p[6];
+ rect.y1 = p[7];
+ rect.x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
+ rect.x1 + p[4] - p[6] : rect.x1;
+
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_in,
+ clip,
+ &rect);
+ } else {
+ rect.x0 = p[6];
+ rect.y0 = p[7];
+ rect.x1 = p[2];
+ rect.y1 = p[3];
+ rect.y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
+ rect.y1 + p[1] - p[3] : rect.y1;
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_out,
+ clip,
+ &rect);
+ }
+ } 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];
+ res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4);
+ if (res == NSERROR_OK) {
+ z[0] = p[2];
+ z[1] = p[3];
+ z[6] = p[4];
+ z[7] = p[5];
+ res = ctx->plot->polygon(ctx,
+ plot_style_bdr_out,
+ z,
+ 4);
+ }
+ }
+ 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
+ */
+
+ /* First part */
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = (p[0] + p[2]) / 2;
+ rect.y0 = (p[1] + p[3]) / 2;
+ rect.x1 = p[6];
+ rect.y1 = p[7];
+ } else {
+ rect.x0 = p[6];
+ rect.y0 = p[7];
+ rect.x1 = (p[0] + p[2]) / 2;
+ rect.y1 = (p[1] + p[3]) / 2;
+ }
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_in,
+ clip,
+ &rect);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ /* Second part */
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = p[2];
+ rect.y0 = p[3];
+ rect.x1 = (p[6] + p[4]) / 2;
+ rect.y1 = (p[7] + p[5]) / 2;
+ } else {
+ rect.x0 = (p[6] + p[4]) / 2;
+ rect.y0 = (p[7] + p[5]) / 2;
+ rect.x1 = p[2];
+ rect.y1 = p[3];
+ }
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_out,
+ clip,
+ &rect);
+ } else if (thickness == 1) {
+ /* Border made up from one part which can be
+ * plotted as a rectangle
+ */
+
+ if (side == TOP || side == RIGHT) {
+ rect.x0 = p[2];
+ rect.y0 = p[3];
+ rect.x1 = p[6];
+ rect.y1 = p[7];
+ rect.x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
+ rect.x1 + p[4] - p[6] : rect.x1;
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_in,
+ clip,
+ &rect);
+ } else {
+ rect.x0 = p[6];
+ rect.y0 = p[7];
+ rect.x1 = p[2];
+ rect.y1 = p[3];
+ rect.y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
+ rect.y1 + p[1] - p[3] : rect.y1;
+ res = plot_clipped_rectangle(ctx,
+ plot_style_bdr_out,
+ clip,
+ &rect);
+ }
+ } 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];
+ res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+ z[0] = p[2];
+ z[1] = p[3];
+ z[6] = p[4];
+ z[7] = p[5];
+ res = ctx->plot->polygon(ctx, plot_style_bdr_out, z, 4);
+ }
+ break;
+ }
+
+ return res;
+}
+
+
+/**
+ * Draw borders for a box.
+ *
+ * \param box box to draw
+ * \param x_parent coordinate of left padding edge of parent of box
+ * \param y_parent coordinate of top padding edge of parent of box
+ * \param p_width width of padding box
+ * \param p_height height of padding box
+ * \param clip cliping area for redrawing border.
+ * \param scale scale for redraw
+ * \param ctx current redraw context
+ * \return true if successful, false otherwise
+ */
+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)
+{
+ unsigned int sides[] = { LEFT, RIGHT, TOP, BOTTOM };
+ int top = box->border[TOP].width;
+ int right = box->border[RIGHT].width;
+ int bottom = box->border[BOTTOM].width;
+ int left = box->border[LEFT].width;
+ int x, y;
+ unsigned int i, side;
+ int p[8]; /* Box border vertices */
+ int z[8]; /* Border vertices */
+ bool square_end_1 = false;
+ bool square_end_2 = false;
+ nserror res;
+
+ x = x_parent + box->x;
+ y = y_parent + box->y;
+
+ if (scale != 1.0) {
+ top *= scale;
+ right *= scale;
+ bottom *= scale;
+ left *= scale;
+ x *= scale;
+ y *= scale;
+ }
+
+ assert(box->style);
+
+ /* Calculate border vertices
+ *
+ * A----------------------+
+ * | \ / |
+ * | B--------------+ |
+ * | | | |
+ * | +--------------C |
+ * | / \ |
+ * +----------------------D
+ */
+ p[0] = x - left; p[1] = y - top; /* A */
+ p[2] = x; p[3] = y; /* B */
+ p[4] = x + p_width; p[5] = y + p_height; /* C */
+ p[6] = x + p_width + right; p[7] = y + p_height + bottom; /* D */
+
+ for (i = 0; i != 4; i++) {
+ colour col = 0;
+ side = sides[i]; /* plot order */
+
+ if (box->border[side].width == 0 ||
+ nscss_color_is_transparent(box->border[side].c)) {
+ continue;
+ }
+
+ switch (side) {
+ case LEFT:
+ square_end_1 = (top == 0);
+ square_end_2 = (bottom == 0);
+
+ z[0] = p[0]; z[1] = p[7];
+ z[2] = p[2]; z[3] = p[5];
+ z[4] = p[2]; z[5] = p[3];
+ z[6] = p[0]; z[7] = p[1];
+
+ if (nscss_color_is_transparent(box->border[TOP].c) == false &&
+ box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang top corner fully,
+ * if top border is opaque
+ */
+ z[5] -= top;
+ square_end_1 = true;
+ }
+ if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
+ box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang bottom corner fully,
+ * if bottom border is opaque
+ */
+ z[3] += bottom;
+ square_end_2 = true;
+ }
+
+ col = nscss_color_to_ns(box->border[side].c);
+
+ res = html_redraw_border_plot(side,
+ z,
+ col,
+ box->border[side].style,
+ box->border[side].width * scale,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ break;
+
+ case RIGHT:
+ square_end_1 = (top == 0);
+ square_end_2 = (bottom == 0);
+
+ z[0] = p[6]; z[1] = p[1];
+ z[2] = p[4]; z[3] = p[3];
+ z[4] = p[4]; z[5] = p[5];
+ z[6] = p[6]; z[7] = p[7];
+
+ if (nscss_color_is_transparent(box->border[TOP].c) == false &&
+ box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang top corner fully,
+ * if top border is opaque
+ */
+ z[3] -= top;
+ square_end_1 = true;
+ }
+ if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
+ box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang bottom corner fully,
+ * if bottom border is opaque
+ */
+ z[5] += bottom;
+ square_end_2 = true;
+ }
+
+ col = nscss_color_to_ns(box->border[side].c);
+
+ res = html_redraw_border_plot(side,
+ z,
+ col,
+ box->border[side].style,
+ box->border[side].width * scale,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ break;
+
+ case TOP:
+ if (clip->y0 > p[3]) {
+ /* clip rectangle is below border; nothing to
+ * plot
+ */
+ continue;
+ }
+
+ square_end_1 = (left == 0);
+ square_end_2 = (right == 0);
+
+ z[0] = p[2]; z[1] = p[3];
+ z[2] = p[0]; z[3] = p[1];
+ z[4] = p[6]; z[5] = p[1];
+ z[6] = p[4]; z[7] = p[3];
+
+ if (box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[TOP].c == box->border[LEFT].c) {
+ /* don't bother overlapping left corner if
+ * it's the same colour anyway
+ */
+ z[2] += left;
+ square_end_1 = true;
+ }
+ if (box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[TOP].c == box->border[RIGHT].c) {
+ /* don't bother overlapping right corner if
+ * it's the same colour anyway
+ */
+ z[4] -= right;
+ square_end_2 = true;
+ }
+
+ col = nscss_color_to_ns(box->border[side].c);
+
+ res = html_redraw_border_plot(side,
+ z,
+ col,
+ box->border[side].style,
+ box->border[side].width * scale,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ break;
+
+ case BOTTOM:
+ if (clip->y1 < p[5]) {
+ /* clip rectangle is above border; nothing to
+ * plot
+ */
+ continue;
+ }
+
+ square_end_1 = (left == 0);
+ square_end_2 = (right == 0);
+
+ z[0] = p[4]; z[1] = p[5];
+ z[2] = p[6]; z[3] = p[7];
+ z[4] = p[0]; z[5] = p[7];
+ z[6] = p[2]; z[7] = p[5];
+
+ if (box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[BOTTOM].c == box->border[LEFT].c) {
+ /* don't bother overlapping left corner if
+ * it's the same colour anyway
+ */
+ z[4] += left;
+ square_end_1 = true;
+ }
+ if (box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[BOTTOM].c == box->border[RIGHT].c) {
+ /* don't bother overlapping right corner if
+ * it's the same colour anyway
+ */
+ z[2] -= right;
+ square_end_2 = true;
+ }
+
+ col = nscss_color_to_ns(box->border[side].c);
+
+ res = html_redraw_border_plot(side,
+ z,
+ col,
+ box->border[side].style,
+ box->border[side].width * scale,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ break;
+
+ default:
+ assert(side == TOP || side == BOTTOM ||
+ side == LEFT || side == RIGHT);
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+/**
+ * Draw an inline's borders.
+ *
+ * \param box BOX_INLINE which created the border
+ * \param b coordinates of border edge rectangle
+ * \param clip cliping area for redrawing border.
+ * \param scale scale for redraw
+ * \param first true if this is the first rectangle associated with the inline
+ * \param last true if this is the last rectangle associated with the inline
+ * \param ctx current redraw context
+ * \return true if successful, false otherwise
+ */
+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)
+{
+ int top = box->border[TOP].width;
+ int right = box->border[RIGHT].width;
+ int bottom = box->border[BOTTOM].width;
+ int left = box->border[LEFT].width;
+ colour col;
+ int p[8]; /* Box border vertices */
+ int z[8]; /* Border vertices */
+ bool square_end_1;
+ bool square_end_2;
+ nserror res;
+
+ if (scale != 1.0) {
+ top *= scale;
+ right *= scale;
+ bottom *= scale;
+ left *= scale;
+ }
+
+ /* Calculate border vertices
+ *
+ * A----------------------+
+ * | \ / |
+ * | B--------------+ |
+ * | | | |
+ * | +--------------C |
+ * | / \ |
+ * +----------------------D
+ */
+ p[0] = b.x0; p[1] = b.y0; /* A */
+ p[2] = first ? b.x0 + left : b.x0; p[3] = b.y0 + top; /* B */
+ p[4] = last ? b.x1 - right : b.x1; p[5] = b.y1 - bottom; /* C */
+ p[6] = b.x1; p[7] = b.y1; /* D */
+
+ assert(box->style);
+
+ /* Left */
+ square_end_1 = (top == 0);
+ square_end_2 = (bottom == 0);
+ if (left != 0 &&
+ first &&
+ nscss_color_is_transparent(box->border[LEFT].c) == false) {
+ col = nscss_color_to_ns(box->border[LEFT].c);
+
+ z[0] = p[0]; z[1] = p[7];
+ z[2] = p[2]; z[3] = p[5];
+ z[4] = p[2]; z[5] = p[3];
+ z[6] = p[0]; z[7] = p[1];
+
+ if (nscss_color_is_transparent(box->border[TOP].c) == false &&
+ box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang top corner fully,
+ * if top border is opaque
+ */
+ z[5] -= top;
+ square_end_1 = true;
+ }
+
+ if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
+ box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang bottom corner fully,
+ * if bottom border is opaque
+ */
+ z[3] += bottom;
+ square_end_2 = true;
+ }
+
+ res = html_redraw_border_plot(LEFT,
+ z,
+ col,
+ box->border[LEFT].style,
+ left,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ }
+
+ /* Right */
+ square_end_1 = (top == 0);
+ square_end_2 = (bottom == 0);
+ if (right != 0 &&
+ last &&
+ nscss_color_is_transparent(box->border[RIGHT].c) == false) {
+ col = nscss_color_to_ns(box->border[RIGHT].c);
+
+ z[0] = p[6]; z[1] = p[1];
+ z[2] = p[4]; z[3] = p[3];
+ z[4] = p[4]; z[5] = p[5];
+ z[6] = p[6]; z[7] = p[7];
+
+ if (nscss_color_is_transparent(box->border[TOP].c) == false &&
+ box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang top corner fully,
+ * if top border is opaque
+ */
+ z[3] -= top;
+ square_end_1 = true;
+ }
+
+ if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
+ box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
+ /* make border overhang bottom corner fully,
+ * if bottom border is opaque
+ */
+ z[5] += bottom;
+ square_end_2 = true;
+ }
+
+ res = html_redraw_border_plot(RIGHT,
+ z,
+ col,
+ box->border[RIGHT].style,
+ right,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ }
+
+ /* Top */
+ square_end_1 = (left == 0);
+ square_end_2 = (right == 0);
+ if (top != 0 &&
+ nscss_color_is_transparent(box->border[TOP].c) == false) {
+ col = nscss_color_to_ns(box->border[TOP].c);
+
+ z[0] = p[2]; z[1] = p[3];
+ z[2] = p[0]; z[3] = p[1];
+ z[4] = p[6]; z[5] = p[1];
+ z[6] = p[4]; z[7] = p[3];
+
+ if (first &&
+ box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[TOP].c == box->border[LEFT].c) {
+ /* don't bother overlapping left corner if
+ * it's the same colour anyway
+ */
+ z[2] += left;
+ square_end_1 = true;
+ }
+
+ if (last &&
+ box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[TOP].c == box->border[RIGHT].c) {
+ /* don't bother overlapping right corner if
+ * it's the same colour anyway
+ */
+ z[4] -= right;
+ square_end_2 = true;
+ }
+
+ res = html_redraw_border_plot(TOP,
+ z,
+ col,
+ box->border[TOP].style,
+ top,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ }
+
+ /* Bottom */
+ square_end_1 = (left == 0);
+ square_end_2 = (right == 0);
+ if (bottom != 0 &&
+ nscss_color_is_transparent(box->border[BOTTOM].c) == false) {
+ col = nscss_color_to_ns(box->border[BOTTOM].c);
+
+ z[0] = p[4]; z[1] = p[5];
+ z[2] = p[6]; z[3] = p[7];
+ z[4] = p[0]; z[5] = p[7];
+ z[6] = p[2]; z[7] = p[5];
+
+ if (first &&
+ box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[BOTTOM].c == box->border[LEFT].c) {
+ /* don't bother overlapping left corner if
+ * it's the same colour anyway
+ */
+ z[4] += left;
+ square_end_1 = true;
+ }
+
+ if (last &&
+ box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
+ box->border[BOTTOM].c == box->border[RIGHT].c) {
+ /* don't bother overlapping right corner if
+ * it's the same colour anyway
+ */
+ z[2] -= right;
+ square_end_2 = true;
+ }
+
+ res = html_redraw_border_plot(BOTTOM,
+ z,
+ col,
+ box->border[BOTTOM].style,
+ bottom,
+ square_end_1 && square_end_2,
+ clip,
+ ctx);
+ if (res != NSERROR_OK) {
+ return false;
+ }
+ }
+
+ return true;
+}