gsk: Add a radial gradient node

Only a fallback implementation for now.

Fixes #2262
This commit is contained in:
Matthias Clasen
2020-09-11 22:55:37 -04:00
committed by Timm Bäder
parent 9267f705ef
commit 0c6226c20b
7 changed files with 412 additions and 0 deletions

View File

@@ -3384,6 +3384,8 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
break;
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_CAIRO_NODE:
default:
{

View File

@@ -30,6 +30,8 @@
* @GSK_COLOR_NODE: A node drawing a single color rectangle
* @GSK_LINEAR_GRADIENT_NODE: A node drawing a linear gradient
* @GSK_REPEATING_LINEAR_GRADIENT_NODE: A node drawing a repeating linear gradient
* @GSK_RADIAL_GRADIENT_NODE: A node drawing a radial gradient
* @GSK_REPEATING_RADIAL_GRADIENT_NODE: A node drawing a repeating radial gradient
* @GSK_BORDER_NODE: A node stroking a border around an area
* @GSK_TEXTURE_NODE: A node drawing a #GdkTexture
* @GSK_INSET_SHADOW_NODE: A node drawing an inset shadow
@@ -56,6 +58,8 @@ typedef enum {
GSK_COLOR_NODE,
GSK_LINEAR_GRADIENT_NODE,
GSK_REPEATING_LINEAR_GRADIENT_NODE,
GSK_RADIAL_GRADIENT_NODE,
GSK_REPEATING_RADIAL_GRADIENT_NODE,
GSK_BORDER_NODE,
GSK_TEXTURE_NODE,
GSK_INSET_SHADOW_NODE,

View File

@@ -104,6 +104,8 @@ GskRenderNode * gsk_render_node_deserialize (GBytes
#define GSK_TYPE_TEXTURE_NODE (gsk_texture_node_get_type())
#define GSK_TYPE_LINEAR_GRADIENT_NODE (gsk_linear_gradient_node_get_type())
#define GSK_TYPE_REPEATING_LINEAR_GRADIENT_NODE (gsk_repeating_linear_gradient_node_get_type())
#define GSK_TYPE_RADIAL_GRADIENT_NODE (gsk_radial_gradient_node_get_type())
#define GSK_TYPE_REPEATING_RADIAL_GRADIENT_NODE (gsk_repeating_radial_gradient_node_get_type())
#define GSK_TYPE_BORDER_NODE (gsk_border_node_get_type())
#define GSK_TYPE_INSET_SHADOW_NODE (gsk_inset_shadow_node_get_type())
#define GSK_TYPE_OUTSET_SHADOW_NODE (gsk_outset_shadow_node_get_type())
@@ -126,6 +128,8 @@ typedef struct _GskColorNode GskColorNode;
typedef struct _GskTextureNode GskTextureNode;
typedef struct _GskLinearGradientNode GskLinearGradientNode;
typedef struct _GskRepeatingLinearGradientNode GskRepeatingLinearGradientNode;
typedef struct _GskRadialGradientNode GskRadialGradientNode;
typedef struct _GskRepeatingRadialGradientNode GskRepeatingRadialGradientNode;
typedef struct _GskBorderNode GskBorderNode;
typedef struct _GskInsetShadowNode GskInsetShadowNode;
typedef struct _GskOutsetShadowNode GskOutsetShadowNode;
@@ -196,6 +200,45 @@ GskRenderNode * gsk_repeating_linear_gradient_node_new (const graph
const GskColorStop *color_stops,
gsize n_color_stops);
GDK_AVAILABLE_IN_ALL
GType gsk_radial_gradient_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_radial_gradient_node_new (const graphene_rect_t *bounds,
const graphene_point_t *center,
float radius,
float scale,
float start,
float end,
const GskColorStop *color_stops,
gsize n_color_stops);
GDK_AVAILABLE_IN_ALL
gsize gsk_radial_gradient_node_get_n_color_stops (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
const GskColorStop * gsk_radial_gradient_node_peek_color_stops (GskRenderNode *node,
gsize *n_stops);
GDK_AVAILABLE_IN_ALL
const graphene_point_t *gsk_radial_gradient_node_peek_center (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
float gsk_radial_gradient_node_get_radius (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
float gsk_radial_gradient_node_get_scale (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
float gsk_radial_gradient_node_get_start (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
float gsk_radial_gradient_node_get_end (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GType gsk_repeating_radial_gradient_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_repeating_radial_gradient_node_new (const graphene_rect_t *bounds,
const graphene_point_t *center,
float radius,
float scale,
float start,
float end,
const GskColorStop *color_stops,
gsize n_color_stops);
GDK_AVAILABLE_IN_ALL
GType gsk_border_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL

View File

@@ -386,6 +386,284 @@ gsk_linear_gradient_node_peek_color_stops (GskRenderNode *node,
return self->stops;
}
/*** GSK_RADIAL_GRADIENT_NODE ***/
struct _GskRadialGradientNode
{
GskRenderNode render_node;
graphene_point_t center;
gboolean circle;
float radius;
float scale;
float start;
float end;
gsize n_stops;
GskColorStop *stops;
};
static void
gsk_radial_gradient_node_finalize (GskRenderNode *node)
{
GskRadialGradientNode *self = (GskRadialGradientNode *) node;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_RADIAL_GRADIENT_NODE));
g_free (self->stops);
parent_class->finalize (node);
}
static void
gsk_radial_gradient_node_draw (GskRenderNode *node,
cairo_t *cr)
{
GskRadialGradientNode *self = (GskRadialGradientNode *) node;
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
gsize i;
float offset;
int last;
pattern = cairo_pattern_create_radial (0, 0, self->radius * self->start,
0, 0, self->radius * self->end);
if (self->scale != 1.0)
{
cairo_matrix_init_scale (&matrix, 1.0, 1.0 / self->scale);
cairo_pattern_set_matrix (pattern, &matrix);
}
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE)
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
else
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
offset = self->start;
last = -1;
for (i = 0; i < self->n_stops; i++)
{
double pos, step;
if (self->stops[i].offset == 0.0)
{
if (i == 0)
pos = 0.0;
else if (i + 1 == self->n_stops)
pos = 1.0;
else
continue;
}
else
pos = self->stops[i].offset;
pos = MAX (pos, 0);
step = (pos - offset) / (i - last);
for (last = last + 1; last <= i; last++)
{
offset += step;
cairo_pattern_add_color_stop_rgba (pattern,
(offset - self->start) / (self->end - self->start),
self->stops[i].color.red,
self->stops[i].color.green,
self->stops[i].color.blue,
self->stops[i].color.alpha);
}
offset = pos;
last = i;
}
gsk_cairo_rectangle (cr, &node->bounds);
cairo_translate (cr, self->center.x, self->center.y);
cairo_set_source (cr, pattern);
cairo_fill (cr);
cairo_pattern_destroy (pattern);
}
static void
gsk_radial_gradient_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
cairo_region_t *region)
{
GskRadialGradientNode *self1 = (GskRadialGradientNode *) node1;
GskRadialGradientNode *self2 = (GskRadialGradientNode *) node2;
if (graphene_point_equal (&self1->center, &self2->center) &&
self1->radius == self2->radius &&
self1->scale == self2->scale &&
self1->start == self2->start &&
self1->end == self2->end &&
self1->n_stops == self2->n_stops)
{
gsize i;
for (i = 0; i < self1->n_stops; i++)
{
GskColorStop *stop1 = &self1->stops[i];
GskColorStop *stop2 = &self2->stops[i];
if (stop1->offset == stop2->offset &&
gdk_rgba_equal (&stop1->color, &stop2->color))
continue;
gsk_render_node_diff_impossible (node1, node2, region);
return;
}
return;
}
gsk_render_node_diff_impossible (node1, node2, region);
}
GskRenderNode *
gsk_radial_gradient_node_new (const graphene_rect_t *bounds,
const graphene_point_t *center,
float radius,
float scale,
float start,
float end,
const GskColorStop *color_stops,
gsize n_color_stops)
{
GskRadialGradientNode *self;
GskRenderNode *node;
gsize i;
g_return_val_if_fail (bounds != NULL, NULL);
g_return_val_if_fail (center != NULL, NULL);
g_return_val_if_fail (color_stops != NULL, NULL);
g_return_val_if_fail (n_color_stops >= 2, NULL);
g_return_val_if_fail (color_stops[0].offset >= 0, NULL);
for (i = 1; i < n_color_stops; i++)
g_return_val_if_fail (color_stops[i].offset >= color_stops[i - 1].offset, NULL);
g_return_val_if_fail (color_stops[n_color_stops - 1].offset <= 1, NULL);
self = gsk_render_node_alloc (GSK_RADIAL_GRADIENT_NODE);
node = (GskRenderNode *) self;
graphene_rect_init_from_rect (&node->bounds, bounds);
graphene_point_init_from_point (&self->center, center);
self->radius = radius;
self->scale = scale;
self->start = start;
self->end = end;
self->n_stops = n_color_stops;
self->stops = g_malloc_n (n_color_stops, sizeof (GskColorStop));
memcpy (self->stops, color_stops, n_color_stops * sizeof (GskColorStop));
return node;
}
GskRenderNode *
gsk_repeating_radial_gradient_node_new (const graphene_rect_t *bounds,
const graphene_point_t *center,
float radius,
float scale,
float start,
float end,
const GskColorStop *color_stops,
gsize n_color_stops)
{
GskRadialGradientNode *self;
GskRenderNode *node;
gsize i;
g_return_val_if_fail (bounds != NULL, NULL);
g_return_val_if_fail (center != NULL, NULL);
g_return_val_if_fail (color_stops != NULL, NULL);
g_return_val_if_fail (n_color_stops >= 2, NULL);
g_return_val_if_fail (color_stops[0].offset >= 0, NULL);
for (i = 1; i < n_color_stops; i++)
g_return_val_if_fail (color_stops[i].offset >= color_stops[i - 1].offset, NULL);
g_return_val_if_fail (color_stops[n_color_stops - 1].offset <= 1, NULL);
self = gsk_render_node_alloc (GSK_REPEATING_RADIAL_GRADIENT_NODE);
node = (GskRenderNode *) self;
graphene_rect_init_from_rect (&node->bounds, bounds);
graphene_point_init_from_point (&self->center, center);
self->radius = radius;
self->scale = scale;
self->start = start;
self->end = end;
self->n_stops = n_color_stops;
self->stops = g_malloc_n (n_color_stops, sizeof (GskColorStop));
memcpy (self->stops, color_stops, n_color_stops * sizeof (GskColorStop));
return node;
}
gsize
gsk_radial_gradient_node_get_n_color_stops (GskRenderNode *node)
{
GskRadialGradientNode *self = (GskRadialGradientNode *) node;
return self->n_stops;
}
const GskColorStop *
gsk_radial_gradient_node_peek_color_stops (GskRenderNode *node,
gsize *n_stops)
{
GskRadialGradientNode *self = (GskRadialGradientNode *) node;
if (n_stops != NULL)
*n_stops = self->n_stops;
return self->stops;
}
const graphene_point_t *
gsk_radial_gradient_node_peek_center (GskRenderNode *node)
{
GskRadialGradientNode *self = (GskRadialGradientNode *) node;
return &self->center;
}
float
gsk_radial_gradient_node_get_radius (GskRenderNode *node)
{
GskRadialGradientNode *self = (GskRadialGradientNode *) node;
return self->radius;
}
float
gsk_radial_gradient_node_get_scale (GskRenderNode *node)
{
GskRadialGradientNode *self = (GskRadialGradientNode *) node;
return self->scale;
}
float
gsk_radial_gradient_node_get_start (GskRenderNode *node)
{
GskRadialGradientNode *self = (GskRadialGradientNode *) node;
return self->start;
}
float
gsk_radial_gradient_node_get_end (GskRenderNode *node)
{
GskRadialGradientNode *self = (GskRadialGradientNode *) node;
return self->end;
}
/*** GSK_BORDER_NODE ***/
struct _GskBorderNode
@@ -4191,6 +4469,8 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_cairo_node, GSK_CAIRO_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_color_node, GSK_COLOR_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_linear_gradient_node, GSK_LINEAR_GRADIENT_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_repeating_linear_gradient_node, GSK_REPEATING_LINEAR_GRADIENT_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_radial_gradient_node, GSK_RADIAL_GRADIENT_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_repeating_radial_gradient_node, GSK_REPEATING_RADIAL_GRADIENT_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_border_node, GSK_BORDER_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_texture_node, GSK_TEXTURE_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_inset_shadow_node, GSK_INSET_SHADOW_NODE)
@@ -4291,6 +4571,38 @@ gsk_render_node_init_types_once (void)
gsk_render_node_types[GSK_REPEATING_LINEAR_GRADIENT_NODE] = node_type;
}
{
const GskRenderNodeTypeInfo node_info =
{
GSK_RADIAL_GRADIENT_NODE,
sizeof (GskRadialGradientNode),
NULL,
gsk_radial_gradient_node_finalize,
gsk_radial_gradient_node_draw,
NULL,
gsk_radial_gradient_node_diff,
};
GType node_type = gsk_render_node_type_register_static (I_("GskRadialGradientNode"), &node_info);
gsk_render_node_types[GSK_RADIAL_GRADIENT_NODE] = node_type;
}
{
const GskRenderNodeTypeInfo node_info =
{
GSK_REPEATING_RADIAL_GRADIENT_NODE,
sizeof (GskRadialGradientNode),
NULL,
gsk_radial_gradient_node_finalize,
gsk_radial_gradient_node_draw,
NULL,
gsk_radial_gradient_node_diff,
};
GType node_type = gsk_render_node_type_register_static (I_("GskRepeatingRadialGradientNode"), &node_info);
gsk_render_node_types[GSK_REPEATING_RADIAL_GRADIENT_NODE] = node_type;
}
{
const GskRenderNodeTypeInfo node_info =
{

View File

@@ -2003,6 +2003,42 @@ render_node_print (Printer *p,
}
break;
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
{
const gsize n_stops = gsk_radial_gradient_node_get_n_color_stops (node);
const GskColorStop *stops = gsk_radial_gradient_node_peek_color_stops (node, NULL);
gsize i;
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE)
start_node (p, "repeating-radial-gradient");
else
start_node (p, "radial-gradient");
append_rect_param (p, "bounds", &node->bounds);
append_point_param (p, "center", gsk_radial_gradient_node_peek_center (node));
append_float_param (p, "radius", gsk_radial_gradient_node_get_radius (node), 0.0f);
append_float_param (p, "scale", gsk_radial_gradient_node_get_scale (node), 1.0f);
append_float_param (p, "start", gsk_radial_gradient_node_get_start (node), 0.0f);
append_float_param (p, "end", gsk_radial_gradient_node_get_end (node), 1.0f);
_indent (p);
g_string_append (p->str, "stops: ");
for (i = 0; i < n_stops; i ++)
{
if (i > 0)
g_string_append (p->str, ", ");
string_append_double (p->str, stops[i].offset);
g_string_append_c (p->str, ' ');
append_rgba (p->str, &stops[i].color);
}
g_string_append (p->str, ";\n");
end_node (p);
}
break;
case GSK_OPACITY_NODE:
{
start_node (p, "opacity");

View File

@@ -257,6 +257,8 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
g_assert_not_reached ();
return;
case GSK_SHADOW_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
default:
FALLBACK ("Unsupported node '%s'", g_type_name_from_instance ((GTypeInstance *) node));

View File

@@ -131,6 +131,8 @@ create_list_model_for_render_node (GskRenderNode *node)
case GSK_COLOR_NODE:
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_BORDER_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_OUTSET_SHADOW_NODE:
@@ -234,6 +236,10 @@ node_type_name (GskRenderNodeType type)
return "Linear Gradient";
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
return "Repeating Linear Gradient";
case GSK_RADIAL_GRADIENT_NODE:
return "Radial Gradient";
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
return "Repeating Radial Gradient";
case GSK_BORDER_NODE:
return "Border";
case GSK_TEXTURE_NODE:
@@ -279,6 +285,8 @@ node_name (GskRenderNode *node)
case GSK_CAIRO_NODE:
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_BORDER_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_OUTSET_SHADOW_NODE:
@@ -625,6 +633,11 @@ populate_render_node_properties (GtkListStore *store,
}
break;
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
/* TODO */
break;
case GSK_TEXT_NODE:
{
const PangoFont *font = gsk_text_node_peek_font (node);