diff --git a/render/html_redraw.c b/render/html_redraw.c
index 9cf0e58c3..b41cfeebc 100644
--- a/render/html_redraw.c
+++ b/render/html_redraw.c
@@ -70,6 +70,7 @@ static bool html_redraw_border_plot(int i, int *p, colour c,
css_border_style style, int thickness);
static colour html_redraw_darker(colour c);
static colour html_redraw_lighter(colour c);
+static colour html_redraw_blend(colour c0, colour c1);
static colour html_redraw_aa(colour c0, colour c1);
static bool html_redraw_checkbox(int x, int y, int width, int height,
bool selected);
@@ -97,6 +98,17 @@ static bool html_redraw_scrollbars(struct box *box, float scale,
bool html_redraw_debug = false;
+/** Overflow scrollbar colours
+ *
+ * Overflow scrollbar colours can be set by front end code to try to match
+ * scrollbar colours used on the desktop.
+ *
+ * If a front end doesn't set scrollbar colours, these defaults are used.
+ */
+colour css_scrollbar_fg_colour = 0x00d9d9d9; /* light grey */
+colour css_scrollbar_bg_colour = 0x006b6b6b; /* mid grey */
+colour css_scrollbar_arrow_colour = 0x00444444; /* dark grey */
+
/**
* Draw a CONTENT_HTML using the current set of plotters (plot).
*
@@ -1245,6 +1257,20 @@ colour html_redraw_lighter(colour c)
}
+/**
+ * Blend two colours.
+ *
+ * \param c0 colour
+ * \param c1 colour
+ * \return a blended colour
+ */
+
+colour html_redraw_blend(colour c0, colour c1)
+{
+ return mix_colour(c0, c1)
+}
+
+
/**
* Mix two colours to produce a colour suitable for anti-aliasing.
*
@@ -1915,116 +1941,174 @@ bool html_redraw_scrollbars(struct box *box, float scale,
bool vscroll, hscroll;
int well_height, bar_top, bar_height;
int well_width, bar_left, bar_width;
- colour vcolour = box->style->border[RIGHT].color;
- colour hcolour = box->style->border[BOTTOM].color;
-
- /** \todo We probably want to clamp to either end of the spectrum,
- * rather than simply taking the inverse colour. */
- if (vcolour == TRANSPARENT || vcolour == background_colour)
- vcolour = background_colour ^ 0xffffff;
-
- if (hcolour == TRANSPARENT || hcolour == background_colour)
- hcolour = background_colour ^ 0xffffff;
+ colour c0, c1; /* highlight and shadow colours */
+ int v[6]; /* array of triangle vertices */
box_scrollbar_dimensions(box, padding_width, padding_height, w,
&vscroll, &hscroll,
&well_height, &bar_top, &bar_height,
&well_width, &bar_left, &bar_width);
-#define TRIANGLE(x0, y0, x1, y1, x2, y2, c) \
- if (!plot.line(x0, y0, x1, y1, scale, c, false, false)) \
+#define RECTANGLE(x0, y0, x1, y1, c, inset) \
+ c0 = inset ? html_redraw_darker(c) : html_redraw_lighter(c); \
+ c1 = inset ? html_redraw_lighter(c) : html_redraw_darker(c); \
+ if (!plot.line(x0, y0, x1, y0, 1, c0, false, false)) \
return false; \
- if (!plot.line(x0, y0, x2, y2, scale, c, false, false)) \
+ if (!plot.line(x1, y0, x1, y1 + 1, 1, c1, false, false)) \
return false; \
- if (!plot.line(x1, y1, x2, y2, scale, c, false, false)) \
+ if (!plot.line(x1, y0, x1, y0 + 1, 1, \
+ html_redraw_blend(c0, c1), false, false)) \
+ return false; \
+ if (!plot.line(x1, y1, x0, y1, 1, c1, false, false)) \
+ return false; \
+ if (!plot.line(x0, y1, x0, y0, 1, c0, false, false)) \
+ return false; \
+ if (!plot.line(x0, y1, x0, y1 + 1, 1, \
+ html_redraw_blend(c0, c1), false, false)) \
return false;
- /* fill scrollbar well(s) with background colour */
- if (vscroll)
- if (!plot.fill(x + padding_width - w, y,
- x + padding_width, y + padding_height,
- background_colour))
- return false;
- if (hscroll)
- if (!plot.fill(x, y + padding_height - w,
- x + padding_width, y + padding_height,
- background_colour))
- return false;
-
- /* vertical scrollbar */
- if (vscroll) {
- /* left line */
- if (!plot.line(x + padding_width - w, y,
- x + padding_width - w, y + padding_height,
- scale, vcolour, false, false))
- return false;
- /* up arrow */
- TRIANGLE(x + padding_width - w / 2, y + w / 4,
- x + padding_width - w * 3 / 4, y + w * 3 / 4,
- x + padding_width - w / 4, y + w * 3 / 4,
- vcolour);
- /* separator */
- if (!plot.line(x + padding_width - w, y + w,
- x + padding_width, y + w,
- scale, vcolour, false, false))
- return false;
- /* bar */
- if (!plot.rectangle(x + padding_width - w * 3 / 4,
- y + w + bar_top + w / 4,
- w / 2, bar_height - w / 2,
- scale, vcolour, false, false))
- return false;
- /* separator */
- if (!plot.line(x + padding_width - w, y + w + well_height,
- x + padding_width, y + w + well_height,
- scale, vcolour, false, false))
- return false;
- /* down arrow */
- TRIANGLE(x + padding_width - w / 2,
- y + w + well_height + w * 3 / 4,
- x + padding_width - w * 3 / 4,
- y + w + well_height + w / 4,
- x + padding_width - w / 4,
- y + w + well_height + w / 4,
- vcolour);
- }
-
/* horizontal scrollbar */
if (hscroll) {
- /* top line */
- if (!plot.line(x, y + padding_height - w,
- x + well_width + w + w, y + padding_height - w,
- scale, hcolour, false, false))
+ /* scrollbar outline */
+ RECTANGLE(x,
+ y + padding_height - w,
+ x + padding_width - 1,
+ y + padding_height - 1,
+ css_scrollbar_bg_colour, true);
+ /* left arrow icon border */
+ RECTANGLE(x + 1,
+ y + padding_height - w + 1,
+ x + w - 2,
+ y + padding_height - 2,
+ css_scrollbar_fg_colour, false);
+ /* left arrow icon background */
+ if (!plot.fill(x + 2,
+ y + padding_height - w + 2,
+ x + w - 2,
+ y + padding_height - 2,
+ css_scrollbar_fg_colour))
return false;
/* left arrow */
- TRIANGLE(x + w / 4, y + padding_height - w / 2,
- x + w * 3 / 4, y + padding_height - w * 3 / 4,
- x + w * 3 / 4, y + padding_height - w / 4,
- hcolour);
- /* separator */
- if (!plot.line(x + w, y + padding_height - w,
- x + w, y + padding_height,
- scale, hcolour, false, false))
+ v[0] = x + w / 4;
+ v[1] = y + padding_height - w / 2;
+ v[2] = x + w * 3 / 4;
+ v[3] = y + padding_height - w * 3 / 4;
+ v[4] = x + w * 3 / 4;
+ v[5] = y + padding_height - w / 4;
+ if (!plot.polygon(v, 3, css_scrollbar_arrow_colour))
return false;
- /* bar */
- if (!plot.rectangle(x + w + bar_left + w / 4,
- y + padding_height - w * 3 / 4,
- bar_width - w / 2, w / 2,
- scale, hcolour, false, false))
+ /* scroll well background */
+ if (!plot.fill(x + w - 1,
+ y + padding_height - w + 1,
+ x + w + well_width + (vscroll ? 2 : 1),
+ y + padding_height - 1,
+ css_scrollbar_bg_colour))
return false;
- /* separator */
- if (!plot.line(x + w + well_width, y + padding_height - w,
- x + w + well_width, y + padding_height,
- scale, hcolour, false, false))
+ /* scroll position indicator bar */
+ RECTANGLE(x + w + bar_left,
+ y + padding_height - w + 1,
+ x + w + bar_left + bar_width + (vscroll? 1 : 0),
+ y + padding_height - 2,
+ css_scrollbar_fg_colour, false);
+ if (!plot.fill(x + w + bar_left + 1,
+ y + padding_height - w + 2,
+ x + w + bar_left + bar_width + (vscroll? 1 : 0),
+ y + padding_height - 2,
+ css_scrollbar_fg_colour))
+ return false;
+ /* right arrow icon border */
+ RECTANGLE(x + w + well_width + 2,
+ y + padding_height - w + 1,
+ x + w + well_width + w - (vscroll ? 1 : 2),
+ y + padding_height - 2,
+ css_scrollbar_fg_colour, false);
+ /* right arrow icon background */
+ if (!plot.fill(x + w + well_width + 3,
+ y + padding_height - w + 2,
+ x + w + well_width + w - (vscroll ? 1 : 2),
+ y + padding_height - 2,
+ css_scrollbar_fg_colour))
return false;
/* right arrow */
- TRIANGLE(x + w + well_width + w * 3 / 4,
- y + padding_height - w / 2,
- x + w + well_width + w / 4,
- y + padding_height - w * 3 / 4,
- x + w + well_width + w / 4,
- y + padding_height - w / 4,
- hcolour);
+ v[0] = x + w + well_width + w * 3 / 4 + (vscroll ? 1 : 0);
+ v[1] = y + padding_height - w / 2;
+ v[2] = x + w + well_width + w / 4 + (vscroll ? 1 : 0);
+ v[3] = y + padding_height - w * 3 / 4;
+ v[4] = x + w + well_width + w / 4 + (vscroll ? 1 : 0);
+ v[5] = y + padding_height - w / 4;
+ if (!plot.polygon(v, 3, css_scrollbar_arrow_colour))
+ return false;
+ }
+
+ /* vertical scrollbar */
+ if (vscroll) {
+ /* outline */
+ RECTANGLE(x + padding_width - w,
+ y,
+ x + padding_width - 1,
+ y + padding_height - 1,
+ css_scrollbar_bg_colour, true);
+ /* top arrow background */
+ RECTANGLE(x + padding_width - w + 1,
+ y + 1,
+ x + padding_width - 2,
+ y + w - 2,
+ css_scrollbar_fg_colour, false);
+ if (!plot.fill(x + padding_width - w + 2,
+ y + 2,
+ x + padding_width - 2,
+ y + w - 2,
+ css_scrollbar_fg_colour))
+ return false;
+ /* up arrow */
+ v[0] = x + padding_width - w / 2;
+ v[1] = y + w / 4;
+ v[2] = x + padding_width - w * 3 / 4;
+ v[3] = y + w * 3 / 4;
+ v[4] = x + padding_width - w / 4;
+ v[5] = y + w * 3 / 4;
+ if (!plot.polygon(v, 3, css_scrollbar_arrow_colour))
+ return false;
+ /* scroll well background */
+ if (!plot.fill(x + padding_width - w + 1,
+ y + w - 1,
+ x + padding_width - 1,
+ y + padding_height - w + 1,
+ css_scrollbar_bg_colour))
+ return false;
+ /* scroll position indicator bar */
+ RECTANGLE(x + padding_width - w + 1,
+ y + w + bar_top,
+ x + padding_width - 2,
+ y + w + bar_top + bar_height,
+ css_scrollbar_fg_colour, false);
+ if (!plot.fill(x + padding_width - w + 2,
+ y + w + bar_top + 1,
+ x + padding_width - 2,
+ y + w + bar_top + bar_height,
+ css_scrollbar_fg_colour))
+ return false;
+ /* bottom arrow background */
+ RECTANGLE(x + padding_width - w + 1,
+ y + padding_height - w + 1,
+ x + padding_width - 2,
+ y + padding_height - 2,
+ css_scrollbar_fg_colour, false);
+ if (!plot.fill(x + padding_width - w + 2,
+ y + padding_height - w + 2,
+ x + padding_width - 2,
+ y + padding_height - 2,
+ css_scrollbar_fg_colour))
+ return false;
+ /* down arrow */
+ v[0] = x + padding_width - w / 2;
+ v[1] = y + w + well_height + w * 3 / 4;
+ v[2] = x + padding_width - w * 3 / 4;
+ v[3] = y + w + well_height + w / 4;
+ v[4] = x + padding_width - w / 4;
+ v[5] = y + w + well_height + w / 4;
+ if (!plot.polygon(v, 3, css_scrollbar_arrow_colour))
+ return false;
}
return true;