diff --git a/gdk/broadway/broadway-protocol.h b/gdk/broadway/broadway-protocol.h index bc772d98ea..e4ce21e6e1 100644 --- a/gdk/broadway/broadway-protocol.h +++ b/gdk/broadway/broadway-protocol.h @@ -16,6 +16,7 @@ typedef enum { /* Sync changes with broadway.js */ BROADWAY_NODE_OUTSET_SHADOW = 4, BROADWAY_NODE_INSET_SHADOW = 5, BROADWAY_NODE_ROUNDED_CLIP = 6, + BROADWAY_NODE_LINEAR_GRADIENT = 7, } BroadwayNodeType; typedef enum { diff --git a/gdk/broadway/broadway.js b/gdk/broadway/broadway.js index 68f7b8afbc..45dae027f1 100644 --- a/gdk/broadway/broadway.js +++ b/gdk/broadway/broadway.js @@ -331,15 +331,16 @@ SwapNodes.prototype.decode_int32 = function() { SwapNodes.prototype.decode_color = function() { var rgba = this.decode_uint32(); - a = (rgba >> 24) & 0xff; - r = (rgba >> 16) & 0xff; - g = (rgba >> 8) & 0xff; - b = (rgba >> 0) & 0xff; + var a = (rgba >> 24) & 0xff; + var r = (rgba >> 16) & 0xff; + var g = (rgba >> 8) & 0xff; + var b = (rgba >> 0) & 0xff; + var c; if (a == 0) c = "rgb(" + r + "," + g + "," + b + ")"; else c = "rgba(" + r + "," + g + "," + b + "," + (a / 255.0) + ")"; - return c + return c; } SwapNodes.prototype.decode_float = function() { @@ -350,7 +351,14 @@ SwapNodes.prototype.decode_size = function() { var s = new Object(); s.width = this.decode_float (); s.height = this.decode_float (); - return s + return s; +} + +SwapNodes.prototype.decode_point = function() { + var p = new Object(); + p.x = this.decode_float (); + p.y = this.decode_float (); + return p; } SwapNodes.prototype.decode_rect = function() { @@ -374,10 +382,25 @@ SwapNodes.prototype.decode_irect = function() { SwapNodes.prototype.decode_rounded_rect = function() { var r = new Object(); r.bounds = this.decode_rect(); - r.sizes = [] + r.sizes = []; for (var i = 0; i < 4; i++) r.sizes[i] = this.decode_size(); - return r + return r; +} + +SwapNodes.prototype.decode_color_stop = function() { + var s = new Object(); + s.offset = this.decode_float (); + s.color = this.decode_color (); + return s; +} + +SwapNodes.prototype.decode_color_stops = function() { + var stops = []; + var len = this.decode_uint32(); + for (var i = 0; i < len; i++) + stops[i] = this.decode_color_stop(); + return stops; } function args() { @@ -524,6 +547,51 @@ SwapNodes.prototype.handle_node = function(parent, offset_x, offset_y) } break; + case 7: // LINEAR_GRADIENT + { + var rect = this.decode_rect(); + var start = this.decode_point (); + var end = this.decode_point (); + var stops = this.decode_color_stops (); + var div = document.createElement('div'); + div.style["position"] = "absolute"; + set_rect_style(div, rect, offset_x, offset_y); + + // direction: + var dx = end.x - start.x; + var dy = end.y - start.y; + + // Angle in css coords (clockwise degrees, up = 0), note that y goes downwards so we have to invert + var angle = Math.atan2(dx, -dy) * 180.0 / Math.PI; + + // Figure out which corner has offset == 0 in css + var start_corner_x, start_corner_y; + if (dx >= 0) // going right + start_corner_x = rect.x; + else + start_corner_x = rect.x + rect.width; + if (dy >= 0) // going down + start_corner_y = rect.y; + else + start_corner_y = rect.y + rect.height; + + /* project start corner on the line */ + var l2 = dx*dx + dy*dy; + var l = Math.sqrt(l2); + var offset = ((start_corner_x - start.x) * dx + (start_corner_y - start.y) * dy) / l2; + + var gradient = "linear-gradient(" + angle + "deg"; + for (var i = 0; i < stops.length; i++) { + var stop = stops[i]; + gradient = gradient + ", " + stop.color + " " + px(stop.offset * l - offset); + } + gradient = gradient + ")"; + + div.style["background-image"] = gradient; + parent.appendChild(div); + } + break; + default: alert("Unexpected node type " + type); } diff --git a/gdk/broadway/broadwayd.c b/gdk/broadway/broadwayd.c index b3ebd4b02d..693e76cab5 100644 --- a/gdk/broadway/broadwayd.c +++ b/gdk/broadway/broadwayd.c @@ -221,13 +221,14 @@ get_client_serial (BroadwayClient *client, guint32 daemon_serial) #define NODE_SIZE_SIZE 2 #define NODE_SIZE_RECT (NODE_SIZE_POINT + NODE_SIZE_SIZE) #define NODE_SIZE_RRECT (NODE_SIZE_RECT + 4 * NODE_SIZE_SIZE) +#define NODE_SIZE_COLOR_STOP (NODE_SIZE_FLOAT + NODE_SIZE_COLOR) static int rewrite_node_textures (BroadwayClient *client, int len, guint32 data[], int pos) { guint32 type; - guint32 i, n_children; + guint32 i, n_children, n_stops; g_assert (pos < len); @@ -257,6 +258,11 @@ rewrite_node_textures (BroadwayClient *client, pos += NODE_SIZE_RRECT; pos = rewrite_node_textures (client, len, data, pos); break; + case BROADWAY_NODE_LINEAR_GRADIENT: + pos += NODE_SIZE_RECT + 2 * NODE_SIZE_POINT; + n_stops = data[pos++]; + pos += n_stops * NODE_SIZE_COLOR_STOP; + break; default: g_assert_not_reached (); } diff --git a/gsk/gskbroadwayrenderer.c b/gsk/gskbroadwayrenderer.c index 0720369078..b2ead65792 100644 --- a/gsk/gskbroadwayrenderer.c +++ b/gsk/gskbroadwayrenderer.c @@ -145,6 +145,13 @@ add_rounded_rect (GArray *nodes, const GskRoundedRect *rrect) add_size (nodes, &rrect->corner[i]); } +static void +add_color_stop (GArray *nodes, const GskColorStop *stop) +{ + add_float (nodes, stop->offset); + add_rgba (nodes, &stop->color); +} + static void gsk_broadway_renderer_add_node (GskRenderer *self, GArray *nodes, @@ -228,6 +235,21 @@ gsk_broadway_renderer_add_node (GskRenderer *self, } return; + case GSK_LINEAR_GRADIENT_NODE: + { + guint i, n; + + add_uint32 (nodes, BROADWAY_NODE_LINEAR_GRADIENT); + add_rect (nodes, &node->bounds); + add_point (nodes, gsk_linear_gradient_node_peek_start (node)); + add_point (nodes, gsk_linear_gradient_node_peek_end (node)); + n = gsk_linear_gradient_node_get_n_color_stops (node); + add_uint32 (nodes, n); + for (i = 0; i < n; i++) + add_color_stop (nodes, &gsk_linear_gradient_node_peek_color_stops (node)[i]); + } + return; + default: { cairo_surface_t *surface;