From 5610af1b77c363dfd49142e549df24c98c6c4e4f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 16 Jun 2024 11:39:39 -0400 Subject: [PATCH] css: Parse interpolation for radial gradients Parse things like "in hsl hue longer". For details, see the CSS Images Module Level 4, https://www.w3.org/TR/css-images-4. Tests included. Gradient interpolation color spaces aren't supported for rendering yet. --- gtk/gtkcssimageradial.c | 30 ++++++++++++++++++++++++++--- gtk/gtkcssimageradialprivate.h | 5 +++++ testsuite/css/parser/radial.css | 15 +++++++++++++++ testsuite/css/parser/radial.ref.css | 15 +++++++++++++++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/gtk/gtkcssimageradial.c b/gtk/gtkcssimageradial.c index d70817d9b3..3cd5afe7de 100644 --- a/gtk/gtkcssimageradial.c +++ b/gtk/gtkcssimageradial.c @@ -194,6 +194,9 @@ gtk_css_image_radial_snapshot (GtkCssImage *image, last = i; } + if (radial->color_space != GTK_CSS_COLOR_SPACE_SRGB) + g_warning_once ("Gradient interpolation color spaces are not supported yet"); + if (radial->repeating) gtk_snapshot_append_repeating_radial_gradient (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height), @@ -255,6 +258,7 @@ gtk_css_image_radial_parse_first_arg (GtkCssImageRadial *radial, { gboolean has_shape = FALSE; gboolean has_size = FALSE; + gboolean has_colorspace = FALSE; gboolean found_one = FALSE; guint i; static struct { @@ -270,7 +274,13 @@ gtk_css_image_radial_parse_first_arg (GtkCssImageRadial *radial, found_one = FALSE; do { - if (!has_shape && gtk_css_parser_try_ident (parser, "circle")) + if (!has_colorspace && gtk_css_color_interpolation_method_can_parse (parser)) + { + if (!gtk_css_color_interpolation_method_parse (parser, &radial->color_space, &radial->hue_interp)) + return 0; + has_colorspace = TRUE; + } + else if (!has_shape && gtk_css_parser_try_ident (parser, "circle")) { radial->circle = TRUE; found_one = has_shape = TRUE; @@ -467,6 +477,14 @@ gtk_css_image_radial_print (GtkCssImage *image, g_string_append (string, " at "); gtk_css_value_print (radial->position, string); + if (radial->color_space != GTK_CSS_COLOR_SPACE_SRGB) + { + g_string_append_c (string, ' '); + gtk_css_color_interpolation_method_print (radial->color_space, + radial->hue_interp, + string); + } + g_string_append (string, ", "); for (i = 0; i < radial->n_stops; i++) @@ -501,6 +519,8 @@ gtk_css_image_radial_compute (GtkCssImage *image, copy->repeating = radial->repeating; copy->circle = radial->circle; copy->size = radial->size; + copy->color_space = radial->color_space; + copy->hue_interp = radial->hue_interp; copy->position = gtk_css_value_compute (radial->position, property_id, context); @@ -554,7 +574,9 @@ gtk_css_image_radial_transition (GtkCssImage *start_image, if (start->repeating != end->repeating || start->n_stops != end->n_stops || start->size != end->size || - start->circle != end->circle) + start->circle != end->circle || + start->color_space != end->color_space || + start->hue_interp != end->hue_interp) return GTK_CSS_IMAGE_CLASS (_gtk_css_image_radial_parent_class)->transition (start_image, end_image, property_id, progress); result = g_object_new (GTK_TYPE_CSS_IMAGE_RADIAL, NULL); @@ -645,7 +667,9 @@ gtk_css_image_radial_equal (GtkCssImage *image1, (radial1->sizes[0] && radial2->sizes[0] && !gtk_css_value_equal (radial1->sizes[0], radial2->sizes[0])) || ((radial1->sizes[1] == NULL) != (radial2->sizes[1] == NULL)) || (radial1->sizes[1] && radial2->sizes[1] && !gtk_css_value_equal (radial1->sizes[1], radial2->sizes[1])) || - radial1->n_stops != radial2->n_stops) + radial1->n_stops != radial2->n_stops || + radial1->color_space != radial2->color_space || + radial1->hue_interp != radial2->hue_interp) return FALSE; for (i = 0; i < radial1->n_stops; i++) diff --git a/gtk/gtkcssimageradialprivate.h b/gtk/gtkcssimageradialprivate.h index aceec9b58f..16269c8a58 100644 --- a/gtk/gtkcssimageradialprivate.h +++ b/gtk/gtkcssimageradialprivate.h @@ -54,8 +54,13 @@ struct _GtkCssImageRadial GtkCssValue *position; GtkCssValue *sizes[2]; + + GtkCssColorSpace color_space; + GtkCssHueInterpolation hue_interp; + guint n_stops; GtkCssImageRadialColorStop *color_stops; + GtkCssRadialSize size; guint circle : 1; guint repeating :1; diff --git a/testsuite/css/parser/radial.css b/testsuite/css/parser/radial.css index 16343638fd..bf9b8a58a6 100644 --- a/testsuite/css/parser/radial.css +++ b/testsuite/css/parser/radial.css @@ -37,3 +37,18 @@ i { j { background-image: radial-gradient(20px 20px at 20px 30px, red, yellow, green); } + +k { + background-image: radial-gradient(in srgb 20px 20px, red, yellow); + border-image-source: repeating-radial-gradient(in srgb 20px 20px, red, yellow); +} + +l { + background-image: radial-gradient(in oklch 20px 20px, red, yellow); + border-image-source: repeating-radial-gradient(in oklch 20px 20px, red, yellow); +} + +m { + background-image: radial-gradient(circle in hsl longer hue, red, yellow); + border-image-source: repeating-radial-gradient(circle in hsl longer hue, red, yellow); +} diff --git a/testsuite/css/parser/radial.ref.css b/testsuite/css/parser/radial.ref.css index cdb2acf0a1..7cb02f3ab8 100644 --- a/testsuite/css/parser/radial.ref.css +++ b/testsuite/css/parser/radial.ref.css @@ -37,3 +37,18 @@ i { j { background-image: radial-gradient(ellipse 20px 20px at 20px 30px, rgb(255,0,0), rgb(255,255,0), rgb(0,128,0)); } + +k { + background-image: radial-gradient(ellipse 20px 20px at center, rgb(255,0,0), rgb(255,255,0)); + border-image-source: repeating-radial-gradient(ellipse 20px 20px at center, rgb(255,0,0), rgb(255,255,0)); +} + +l { + background-image: radial-gradient(ellipse 20px 20px at center in oklch, rgb(255,0,0), rgb(255,255,0)); + border-image-source: repeating-radial-gradient(ellipse 20px 20px at center in oklch, rgb(255,0,0), rgb(255,255,0)); +} + +m { + background-image: radial-gradient(circle farthest-corner at center in hsl longer hue, rgb(255,0,0), rgb(255,255,0)); + border-image-source: repeating-radial-gradient(circle farthest-corner at center in hsl longer hue, rgb(255,0,0), rgb(255,255,0)); +}