diff options
author | Matthias Clasen <mclasen@redhat.com> | 2020-09-11 22:55:37 -0400 |
---|---|---|
committer | Timm Bäder <mail@baedert.org> | 2020-09-18 15:38:55 +0200 |
commit | 0c6226c20b2b3dcf3bc77595edcd28b0d4626dfb (patch) | |
tree | 0a88574f105476f8c3185ec563b76635689be2b6 | |
parent | 9267f705ef115716128c7afabcf080728f6b70a6 (diff) | |
download | gtk+-0c6226c20b2b3dcf3bc77595edcd28b0d4626dfb.tar.gz |
gsk: Add a radial gradient node
Only a fallback implementation for now.
Fixes #2262
-rw-r--r-- | gsk/gl/gskglrenderer.c | 2 | ||||
-rw-r--r-- | gsk/gskenums.h | 4 | ||||
-rw-r--r-- | gsk/gskrendernode.h | 43 | ||||
-rw-r--r-- | gsk/gskrendernodeimpl.c | 312 | ||||
-rw-r--r-- | gsk/gskrendernodeparser.c | 36 | ||||
-rw-r--r-- | gsk/vulkan/gskvulkanrenderpass.c | 2 | ||||
-rw-r--r-- | gtk/inspector/recorder.c | 13 |
7 files changed, 412 insertions, 0 deletions
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index edc2fd2618..2af766c99b 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -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: { diff --git a/gsk/gskenums.h b/gsk/gskenums.h index d7607fbcb1..24aafec502 100644 --- a/gsk/gskenums.h +++ b/gsk/gskenums.h @@ -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, diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index 331be3230b..613a2d7370 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -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; @@ -197,6 +201,45 @@ GskRenderNode * gsk_repeating_linear_gradient_node_new (const graph 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 GskRenderNode * gsk_border_node_new (const GskRoundedRect *outline, diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index c89da757ad..271f8b214d 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -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) @@ -4294,6 +4574,38 @@ gsk_render_node_init_types_once (void) { 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 = + { GSK_BORDER_NODE, sizeof (GskBorderNode), NULL, diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c index 87bfca110c..4b31493fc3 100644 --- a/gsk/gskrendernodeparser.c +++ b/gsk/gskrendernodeparser.c @@ -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"); diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 51ed812ce7..2ea547881c 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -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)); diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c index e48200a909..043d407dbb 100644 --- a/gtk/inspector/recorder.c +++ b/gtk/inspector/recorder.c @@ -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); |