diff --git a/gtk/gtkcsscolor.c b/gtk/gtkcsscolor.c index b76b1f855a..5604ef72dd 100644 --- a/gtk/gtkcsscolor.c +++ b/gtk/gtkcsscolor.c @@ -994,6 +994,11 @@ parse_hue_interpolation (GtkCssParser *parser, gtk_css_parser_consume_token (parser); *interp = GTK_CSS_HUE_INTERPOLATION_DECREASING; } + else if (gtk_css_token_is_ident (token, "hue")) + { + gtk_css_parser_error_syntax (parser, "'hue' goes after the interpolation method"); + return FALSE; + } else { *interp = GTK_CSS_HUE_INTERPOLATION_SHORTER; @@ -1009,6 +1014,12 @@ parse_hue_interpolation (GtkCssParser *parser, return TRUE; } +gboolean +gtk_css_color_interpolation_method_can_parse (GtkCssParser *parser) +{ + return gtk_css_token_is_ident (gtk_css_parser_get_token (parser), "in"); +} + gboolean gtk_css_color_interpolation_method_parse (GtkCssParser *parser, GtkCssColorSpace *in, @@ -1044,19 +1055,39 @@ gtk_css_color_interpolation_method_parse (GtkCssParser *parser, gtk_css_parser_consume_token (parser); *in = GTK_CSS_COLOR_SPACE_HWB; } - else if (gtk_css_token_is_ident (token, "oklch")) - { - gtk_css_parser_consume_token (parser); - *in = GTK_CSS_COLOR_SPACE_OKLCH; - } else if (gtk_css_token_is_ident (token, "oklab")) { gtk_css_parser_consume_token (parser); *in = GTK_CSS_COLOR_SPACE_OKLAB; } + else if (gtk_css_token_is_ident (token, "oklch")) + { + gtk_css_parser_consume_token (parser); + *in = GTK_CSS_COLOR_SPACE_OKLCH; + } + else if (gtk_css_token_is_ident (token, "display-p3")) + { + gtk_css_parser_consume_token (parser); + *in = GTK_CSS_COLOR_SPACE_DISPLAY_P3; + } + else if (gtk_css_token_is_ident (token, "xyz")) + { + gtk_css_parser_consume_token (parser); + *in = GTK_CSS_COLOR_SPACE_XYZ; + } + else if (gtk_css_token_is_ident (token, "rec2020")) + { + gtk_css_parser_consume_token (parser); + *in = GTK_CSS_COLOR_SPACE_REC2020; + } + else if (gtk_css_token_is_ident (token, "rec2100-pq")) + { + gtk_css_parser_consume_token (parser); + *in = GTK_CSS_COLOR_SPACE_REC2100_PQ; + } else { - gtk_css_parser_error_syntax (parser, "Invalid color space"); + gtk_css_parser_error_syntax (parser, "Invalid color space: %s", gtk_css_token_to_string (token)); return FALSE; } diff --git a/gtk/gtkcsscolorprivate.h b/gtk/gtkcsscolorprivate.h index 27f16372ff..5b88a023ac 100644 --- a/gtk/gtkcsscolorprivate.h +++ b/gtk/gtkcsscolorprivate.h @@ -21,21 +21,10 @@ #include #include "gtk/css/gtkcssparserprivate.h" +#include "gtkcsstypesprivate.h" G_BEGIN_DECLS -typedef enum { - GTK_CSS_COLOR_SPACE_SRGB, - GTK_CSS_COLOR_SPACE_SRGB_LINEAR, - GTK_CSS_COLOR_SPACE_HSL, - GTK_CSS_COLOR_SPACE_HWB, - GTK_CSS_COLOR_SPACE_OKLAB, - GTK_CSS_COLOR_SPACE_OKLCH, - GTK_CSS_COLOR_SPACE_DISPLAY_P3, - GTK_CSS_COLOR_SPACE_XYZ, - GTK_CSS_COLOR_SPACE_REC2020, - GTK_CSS_COLOR_SPACE_REC2100_PQ, -} GtkCssColorSpace; typedef struct { @@ -100,14 +89,6 @@ void gtk_css_color_convert (const GtkCssColor *input, GtkCssColorSpace dest, GtkCssColor *output); -typedef enum -{ - GTK_CSS_HUE_INTERPOLATION_SHORTER, - GTK_CSS_HUE_INTERPOLATION_LONGER, - GTK_CSS_HUE_INTERPOLATION_INCREASING, - GTK_CSS_HUE_INTERPOLATION_DECREASING, -} GtkCssHueInterpolation; - void gtk_css_color_interpolate (const GtkCssColor *from, const GtkCssColor *to, float progress, @@ -124,6 +105,8 @@ void gtk_css_color_space_get_coord_range (GtkCssColorSpace color_space, float *lower, float *upper); +gboolean gtk_css_color_interpolation_method_can_parse (GtkCssParser *parser); + gboolean gtk_css_color_interpolation_method_parse (GtkCssParser *parser, GtkCssColorSpace *in, GtkCssHueInterpolation *interp); diff --git a/gtk/gtkcsscolorvalue.c b/gtk/gtkcsscolorvalue.c index 5f8d830bb4..1c31751f38 100644 --- a/gtk/gtkcsscolorvalue.c +++ b/gtk/gtkcsscolorvalue.c @@ -1651,6 +1651,8 @@ parse_color_color_channel (GtkCssParser *parser, ParseData *data, guint arg) { + const GtkCssToken *token; + switch (arg) { case 0: @@ -1690,7 +1692,11 @@ parse_color_color_channel (GtkCssParser *parser, return 1; } - gtk_css_parser_error_syntax (parser, "Invalid color space in color()"); + token = gtk_css_parser_get_token (parser); + gtk_css_parser_error_syntax (parser, + "Invalid color space in color(): %s", + gtk_css_token_to_string (token)); + return 0; case 1: diff --git a/gtk/gtkcssimageconic.c b/gtk/gtkcssimageconic.c index ceef29e59e..d48bfcc30a 100644 --- a/gtk/gtkcssimageconic.c +++ b/gtk/gtkcssimageconic.c @@ -81,7 +81,10 @@ gtk_css_image_conic_snapshot (GtkCssImage *image, last = i; } - gtk_snapshot_append_conic_gradient ( + if (self->color_space != GTK_CSS_COLOR_SPACE_SRGB) + g_warning_once ("Gradient interpolation color spaces are not supported yet"); + + gtk_snapshot_append_conic_gradient ( snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height), &GRAPHENE_POINT_INIT (_gtk_css_position_value_get_x (self->center, width), @@ -172,37 +175,57 @@ gtk_css_image_conic_parse_first_arg (GtkCssImageConic *self, GtkCssParser *parser, GArray *stop_array) { - gboolean nothing_parsed = TRUE; + gboolean has_rotation = FALSE; + gboolean has_center = FALSE; + gboolean has_colorspace = FALSE; + int retval = 1; - if (gtk_css_parser_try_ident (parser, "from")) + do { - self->rotation = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE); - if (self->rotation == NULL) - return 0; - nothing_parsed = FALSE; - } - else - { - self->rotation = gtk_css_number_value_new (0, GTK_CSS_DEG); + if (!has_colorspace && gtk_css_color_interpolation_method_can_parse (parser)) + { + if (!gtk_css_color_interpolation_method_parse (parser, &self->color_space, &self->hue_interp)) + return 0; + has_colorspace = TRUE; + } + else if (!has_rotation && gtk_css_parser_try_ident (parser, "from")) + { + self->rotation = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE); + if (self->rotation == NULL) + return 0; + has_rotation = TRUE; + } + else if (!has_center && gtk_css_parser_try_ident (parser, "at")) + { + self->center = _gtk_css_position_value_parse (parser); + if (self->center == NULL) + return 0; + has_center = TRUE; + } + else if (gtk_css_token_is (gtk_css_parser_get_token (parser), GTK_CSS_TOKEN_COMMA)) + { + retval = 1; + break; + } + else + { + if (gtk_css_image_conic_parse_color_stop (self, parser, stop_array)) + { + retval = 2; + break; + } + } } + while (!(has_colorspace && has_rotation && has_center)); - if (gtk_css_parser_try_ident (parser, "at")) - { - self->center = _gtk_css_position_value_parse (parser); - if (self->center == NULL) - return 0; - nothing_parsed = FALSE; - } - else - { - self->center = _gtk_css_position_value_new (gtk_css_number_value_new (50, GTK_CSS_PERCENT), - gtk_css_number_value_new (50, GTK_CSS_PERCENT)); - } + if (!has_rotation) + self->rotation = gtk_css_number_value_new (0, GTK_CSS_DEG); - if (!nothing_parsed) - return 1; + if (!has_center) + self->center = _gtk_css_position_value_new (gtk_css_number_value_new (50, GTK_CSS_PERCENT), + gtk_css_number_value_new (50, GTK_CSS_PERCENT)); - return 1 + gtk_css_image_conic_parse_color_stop (self, parser, stop_array); + return retval; } typedef struct @@ -265,7 +288,7 @@ gtk_css_image_conic_print (GtkCssImage *image, gboolean written = FALSE; guint i; - g_string_append (string, "self-gradient("); + g_string_append (string, "conic-gradient("); if (self->center) { @@ -274,7 +297,7 @@ gtk_css_image_conic_print (GtkCssImage *image, if (!gtk_css_value_equal (self->center, compare)) { - g_string_append (string, "from "); + g_string_append (string, "at "); gtk_css_value_print (self->center, string); written = TRUE; } @@ -286,8 +309,19 @@ gtk_css_image_conic_print (GtkCssImage *image, { if (written) g_string_append_c (string, ' '); - g_string_append (string, "at "); + g_string_append (string, "from "); gtk_css_value_print (self->rotation, string); + written = TRUE; + } + + if (self->color_space != GTK_CSS_COLOR_SPACE_SRGB) + { + if (written) + g_string_append_c (string, ' '); + gtk_css_color_interpolation_method_print (self->color_space, + self->hue_interp, + string); + written = TRUE; } if (written) @@ -325,6 +359,8 @@ gtk_css_image_conic_compute (GtkCssImage *image, copy->center = gtk_css_value_compute (self->center, property_id, context); copy->rotation = gtk_css_value_compute (self->rotation, property_id, context); + copy->color_space = self->color_space; + copy->hue_interp = self->hue_interp; copy->n_stops = self->n_stops; copy->color_stops = g_malloc (sizeof (GtkCssImageConicColorStop) * copy->n_stops); @@ -380,6 +416,9 @@ gtk_css_image_conic_transition (GtkCssImage *start_image, if (result->rotation == NULL) goto fail; + result->color_space = start->color_space; + result->hue_interp = start->hue_interp; + result->color_stops = g_malloc (sizeof (GtkCssImageConicColorStop) * start->n_stops); result->n_stops = 0; for (i = 0; i < start->n_stops; i++) @@ -435,7 +474,9 @@ gtk_css_image_conic_equal (GtkCssImage *image1, guint i; if (!gtk_css_value_equal (conic1->center, conic2->center) || - !gtk_css_value_equal (conic1->rotation, conic2->rotation)) + !gtk_css_value_equal (conic1->rotation, conic2->rotation) || + conic1->color_space != conic2->color_space || + conic1->hue_interp != conic2->hue_interp) return FALSE; for (i = 0; i < conic1->n_stops; i++) diff --git a/gtk/gtkcssimageconicprivate.h b/gtk/gtkcssimageconicprivate.h index b0d33bf23b..521557734d 100644 --- a/gtk/gtkcssimageconicprivate.h +++ b/gtk/gtkcssimageconicprivate.h @@ -47,6 +47,9 @@ struct _GtkCssImageConic GtkCssValue *center; GtkCssValue *rotation; + GtkCssColorSpace color_space; + GtkCssHueInterpolation hue_interp; + guint n_stops; GtkCssImageConicColorStop *color_stops; }; diff --git a/gtk/gtkcssimagelinear.c b/gtk/gtkcssimagelinear.c index 939d9b2fb4..046299801c 100644 --- a/gtk/gtkcssimagelinear.c +++ b/gtk/gtkcssimagelinear.c @@ -244,6 +244,9 @@ gtk_css_image_linear_snapshot (GtkCssImage *image, last = i; } + if (linear->color_space != GTK_CSS_COLOR_SPACE_SRGB) + g_warning_once ("Gradient interpolation color spaces are not supported yet"); + if (linear->repeating) { gtk_snapshot_append_repeating_linear_gradient ( @@ -304,75 +307,102 @@ gtk_css_image_linear_parse_first_arg (GtkCssImageLinear *linear, GArray *stop_array) { guint i; + gboolean has_colorspace = FALSE; + gboolean has_side_or_angle = FALSE; + guint retval = 1; - if (gtk_css_parser_try_ident (parser, "to")) + do { - for (i = 0; i < 2; i++) + if (!has_colorspace &>k_css_color_interpolation_method_can_parse (parser)) { - if (gtk_css_parser_try_ident (parser, "left")) - { - if (linear->side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT))) - { - gtk_css_parser_error_syntax (parser, "Expected 'top', 'bottom' or comma"); - return 0; - } - linear->side |= (1 << GTK_CSS_LEFT); - } - else if (gtk_css_parser_try_ident (parser, "right")) - { - if (linear->side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT))) - { - gtk_css_parser_error_syntax (parser, "Expected 'top', 'bottom' or comma"); - return 0; - } - linear->side |= (1 << GTK_CSS_RIGHT); - } - else if (gtk_css_parser_try_ident (parser, "top")) - { - if (linear->side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM))) - { - gtk_css_parser_error_syntax (parser, "Expected 'left', 'right' or comma"); - return 0; - } - linear->side |= (1 << GTK_CSS_TOP); - } - else if (gtk_css_parser_try_ident (parser, "bottom")) - { - if (linear->side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM))) - { - gtk_css_parser_error_syntax (parser, "Expected 'left', 'right' or comma"); - return 0; - } - linear->side |= (1 << GTK_CSS_BOTTOM); - } - else - break; + if (!gtk_css_color_interpolation_method_parse (parser, &linear->color_space, &linear->hue_interp)) + return 0; + has_colorspace = TRUE; } - - if (linear->side == 0) + else if (!has_side_or_angle && gtk_css_parser_try_ident (parser, "to")) { - gtk_css_parser_error_syntax (parser, "Expected side that gradient should go to"); + gtk_css_parser_consume_token (parser); + + for (i = 0; i < 2; i++) + { + if (gtk_css_parser_try_ident (parser, "left")) + { + if (linear->side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT))) + { + gtk_css_parser_error_syntax (parser, "Expected 'top', 'bottom' or comma"); + return 0; + } + linear->side |= (1 << GTK_CSS_LEFT); + } + else if (gtk_css_parser_try_ident (parser, "right")) + { + if (linear->side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT))) + { + gtk_css_parser_error_syntax (parser, "Expected 'top', 'bottom' or comma"); + return 0; + } + linear->side |= (1 << GTK_CSS_RIGHT); + } + else if (gtk_css_parser_try_ident (parser, "top")) + { + if (linear->side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM))) + { + gtk_css_parser_error_syntax (parser, "Expected 'left', 'right' or comma"); + return 0; + } + linear->side |= (1 << GTK_CSS_TOP); + } + else if (gtk_css_parser_try_ident (parser, "bottom")) + { + if (linear->side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM))) + { + gtk_css_parser_error_syntax (parser, "Expected 'left', 'right' or comma"); + return 0; + } + linear->side |= (1 << GTK_CSS_BOTTOM); + } + else + break; + } + + if (linear->side == 0) + { + gtk_css_parser_error_syntax (parser, "Expected side that gradient should go to"); + return 0; + } + + has_side_or_angle = TRUE; + } + else if (!has_side_or_angle && gtk_css_number_value_can_parse (parser)) + { + linear->angle = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE); + if (linear->angle == NULL) + return 0; + + has_side_or_angle = TRUE; + } + else if (gtk_css_token_is (gtk_css_parser_get_token (parser), GTK_CSS_TOKEN_COMMA)) + { + retval = 1; + break; + } + else + { + if (gtk_css_image_linear_parse_color_stop (linear, parser, stop_array)) + { + retval = 2; + break; + } + return 0; } - - return 1; } - else if (gtk_css_number_value_can_parse (parser)) - { - linear->angle = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE); - if (linear->angle == NULL) - return 0; + while (!(has_colorspace && has_side_or_angle)); - return 1; - } - else - { - linear->side = 1 << GTK_CSS_BOTTOM; - if (!gtk_css_image_linear_parse_color_stop (linear, parser, stop_array)) - return 0; + if (linear->angle == NULL && linear->side == 0) + linear->side = (1 << GTK_CSS_BOTTOM); - return 2; - } + return retval; } typedef struct @@ -437,6 +467,7 @@ gtk_css_image_linear_print (GtkCssImage *image, { GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image); guint i; + gboolean has_printed = FALSE; if (linear->repeating) g_string_append (string, "repeating-linear-gradient("); @@ -459,15 +490,29 @@ gtk_css_image_linear_print (GtkCssImage *image, else if (linear->side & (1 << GTK_CSS_RIGHT)) g_string_append (string, " right"); - g_string_append (string, ", "); + has_printed = TRUE; } } else { gtk_css_value_print (linear->angle, string); - g_string_append (string, ", "); + has_printed = TRUE; } + if (linear->color_space != GTK_CSS_COLOR_SPACE_SRGB) + { + if (has_printed) + g_string_append_c (string, ' '); + + gtk_css_color_interpolation_method_print (linear->color_space, + linear->hue_interp, + string); + has_printed = TRUE; + } + + if (has_printed) + g_string_append (string, ", "); + for (i = 0; i < linear->n_stops; i++) { const GtkCssImageLinearColorStop *stop = &linear->color_stops[i]; @@ -499,6 +544,8 @@ gtk_css_image_linear_compute (GtkCssImage *image, copy = g_object_new (GTK_TYPE_CSS_IMAGE_LINEAR, NULL); copy->repeating = linear->repeating; copy->side = linear->side; + copy->color_space = linear->color_space; + copy->hue_interp = linear->hue_interp; if (linear->angle) copy->angle = gtk_css_value_compute (linear->angle, property_id, context); @@ -545,11 +592,15 @@ gtk_css_image_linear_transition (GtkCssImage *start_image, end = GTK_CSS_IMAGE_LINEAR (end_image); if ((start->repeating != end->repeating) - || (start->n_stops != end->n_stops)) + || (start->n_stops != end->n_stops) + || (start->color_space != end->color_space) + || (start->hue_interp != end->hue_interp)) return GTK_CSS_IMAGE_CLASS (_gtk_css_image_linear_parent_class)->transition (start_image, end_image, property_id, progress); result = g_object_new (GTK_TYPE_CSS_IMAGE_LINEAR, NULL); result->repeating = start->repeating; + result->color_space = start->color_space; + result->hue_interp = start->hue_interp; if (start->side != end->side) goto fail; @@ -618,7 +669,9 @@ gtk_css_image_linear_equal (GtkCssImage *image1, if (linear1->repeating != linear2->repeating || linear1->side != linear2->side || (linear1->side == 0 && !gtk_css_value_equal (linear1->angle, linear2->angle)) || - linear1->n_stops != linear2->n_stops) + linear1->n_stops != linear2->n_stops || + linear1->color_space != linear2->color_space || + linear1->hue_interp != linear2->hue_interp) return FALSE; for (i = 0; i < linear1->n_stops; i++) diff --git a/gtk/gtkcssimagelinearprivate.h b/gtk/gtkcssimagelinearprivate.h index 4ddc4eb424..0e93807b2d 100644 --- a/gtk/gtkcssimagelinearprivate.h +++ b/gtk/gtkcssimagelinearprivate.h @@ -48,6 +48,9 @@ struct _GtkCssImageLinear guint repeating :1; GtkCssValue *angle; + GtkCssColorSpace color_space; + GtkCssHueInterpolation hue_interp; + guint n_stops; GtkCssImageLinearColorStop *color_stops; }; 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/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h index 59967b3e9c..52c1f3e284 100644 --- a/gtk/gtkcsstypesprivate.h +++ b/gtk/gtkcsstypesprivate.h @@ -573,5 +573,26 @@ gtk_css_hash_id (GQuark id) return id * 11; } -G_END_DECLS +typedef enum { + GTK_CSS_COLOR_SPACE_SRGB, + GTK_CSS_COLOR_SPACE_SRGB_LINEAR, + GTK_CSS_COLOR_SPACE_HSL, + GTK_CSS_COLOR_SPACE_HWB, + GTK_CSS_COLOR_SPACE_OKLAB, + GTK_CSS_COLOR_SPACE_OKLCH, + GTK_CSS_COLOR_SPACE_DISPLAY_P3, + GTK_CSS_COLOR_SPACE_XYZ, + GTK_CSS_COLOR_SPACE_REC2020, + GTK_CSS_COLOR_SPACE_REC2100_PQ, +} GtkCssColorSpace; +typedef enum +{ + GTK_CSS_HUE_INTERPOLATION_SHORTER, + GTK_CSS_HUE_INTERPOLATION_LONGER, + GTK_CSS_HUE_INTERPOLATION_INCREASING, + GTK_CSS_HUE_INTERPOLATION_DECREASING, +} GtkCssHueInterpolation; + + +G_END_DECLS diff --git a/testsuite/css/parser/color-mix.css b/testsuite/css/parser/color-mix.css index d8a8cf9d0b..79dba1ddbd 100644 --- a/testsuite/css/parser/color-mix.css +++ b/testsuite/css/parser/color-mix.css @@ -125,3 +125,19 @@ ae { af { color: color-mix(in srgb, 30% red, 70% blue); } + +ag { + color: color-mix(in display-p3, 30% red, 70% blue); +} + +ah { + color: color-mix(in xyz, 30% red, 70% blue); +} + +ai { + color: color-mix(in rec2020, 30% red, 70% blue); +} + +aj { + color: color-mix(in rec2100-pq, 30% red, 70% blue); +} diff --git a/testsuite/css/parser/color-mix.ref.css b/testsuite/css/parser/color-mix.ref.css index 4ee1cf81d3..d17ff80b87 100644 --- a/testsuite/css/parser/color-mix.ref.css +++ b/testsuite/css/parser/color-mix.ref.css @@ -101,3 +101,19 @@ ae { af { color: color(srgb 0.3 0 0.7); } + +ag { + color: color(display-p3 0.275246 0.0600861 0.71328); +} + +ah { + color: color(xyz 0.250054 0.114326 0.671172); +} + +ai { + color: color(rec2020 0.355452 0.105084 0.684877); +} + +aj { + color: color(rec2100-pq 0.362517 0.235874 0.464457); +} diff --git a/testsuite/css/parser/color.css b/testsuite/css/parser/color.css index df9d5153fd..81cfbfd2a8 100644 --- a/testsuite/css/parser/color.css +++ b/testsuite/css/parser/color.css @@ -131,3 +131,19 @@ af { ag { color: oklab(100% 100% 100% / 100%); } + +ah { + color: color(display-p3 0.5 0.5 0.5); +} + +ai { + color: color(xyz 0.5 0.5 0.5); +} + +aj { + color: color(rec2020 0.5 0.5 0.5); +} + +ak { + color: color(rec2100-pq 0.5 0.5 0.5); +} diff --git a/testsuite/css/parser/color.ref.css b/testsuite/css/parser/color.ref.css index 584f7f4954..11257f9a09 100644 --- a/testsuite/css/parser/color.ref.css +++ b/testsuite/css/parser/color.ref.css @@ -131,3 +131,19 @@ af { ag { color: oklab(1 0.4 0.4); } + +ah { + color: color(display-p3 0.5 0.5 0.5); +} + +ai { + color: color(xyz 0.5 0.5 0.5); +} + +aj { + color: color(rec2020 0.5 0.5 0.5); +} + +ak { + color: color(rec2100-pq 0.5 0.5 0.5); +} diff --git a/testsuite/css/parser/conic.css b/testsuite/css/parser/conic.css new file mode 100644 index 0000000000..52b639f8f7 --- /dev/null +++ b/testsuite/css/parser/conic.css @@ -0,0 +1,43 @@ +a { + background-image: conic-gradient(yellow, green); +} + +b { + background-image: conic-gradient(at center, yellow 0%, green 100%); +} + +c { + background-image: conic-gradient(at 50% 50%, yellow, green); +} + +d { + background-image: conic-gradient(at left top, yellow, green); +} + +e { + background-image: conic-gradient(at 25% bottom, red, yellow, green); +} + +f { + background-image: conic-gradient(from 20deg, red, yellow 50%, green); +} + +g { + background-image: conic-gradient(from 0.25turn at 20px 20px, red, yellow, green); +} + +h { + background-image: conic-gradient(from 20deg in oklab, red, yellow, green); +} + +i { + background-image: conic-gradient(in rec2020 at center, red, yellow, green); +} + +j { + background-image: conic-gradient(in hsl longer hue from 10deg, red, yellow, green); +} + +k { + background-image: conic-gradient(in srgb from -10deg at 20px 20px, red, yellow); +} diff --git a/testsuite/css/parser/conic.ref.css b/testsuite/css/parser/conic.ref.css new file mode 100644 index 0000000000..ef3fe63264 --- /dev/null +++ b/testsuite/css/parser/conic.ref.css @@ -0,0 +1,43 @@ +a { + background-image: conic-gradient(rgb(255,255,0), rgb(0,128,0)); +} + +b { + background-image: conic-gradient(rgb(255,255,0) 0, rgb(0,128,0) 100%); +} + +c { + background-image: conic-gradient(rgb(255,255,0), rgb(0,128,0)); +} + +d { + background-image: conic-gradient(at left top, rgb(255,255,0), rgb(0,128,0)); +} + +e { + background-image: conic-gradient(at 25% bottom, rgb(255,0,0), rgb(255,255,0), rgb(0,128,0)); +} + +f { + background-image: conic-gradient(from 20deg, rgb(255,0,0), rgb(255,255,0) 50%, rgb(0,128,0)); +} + +g { + background-image: conic-gradient(at 20px 20px from 0.25turn, rgb(255,0,0), rgb(255,255,0), rgb(0,128,0)); +} + +h { + background-image: conic-gradient(from 20deg in oklab, rgb(255,0,0), rgb(255,255,0), rgb(0,128,0)); +} + +i { + background-image: conic-gradient(in rec2020, rgb(255,0,0), rgb(255,255,0), rgb(0,128,0)); +} + +j { + background-image: conic-gradient(from 10deg in hsl longer hue, rgb(255,0,0), rgb(255,255,0), rgb(0,128,0)); +} + +k { + background-image: conic-gradient(at 20px 20px from -10deg, rgb(255,0,0), rgb(255,255,0)); +} diff --git a/testsuite/css/parser/linear-gradient-invalid.css b/testsuite/css/parser/linear-gradient-invalid.css new file mode 100644 index 0000000000..162a9292e8 --- /dev/null +++ b/testsuite/css/parser/linear-gradient-invalid.css @@ -0,0 +1,39 @@ +a { + background-image: linear-gradient(to top bottom, red 0% blue 100%); + border-image-source: repeating-linear-gradient(to top bottom, red 0% blue 100%); +} + +b { + background-image: linear-gradient(to top left bottom, red 0% blue 100%); + border-image-source: repeating-linear-gradient(to top left bottom, red 0% blue 100%); +} + +c { + background-image: linear-gradient(to top top, red 0% blue 100%); + border-image-source: repeating-linear-gradient(to top top, red 0% blue 100%); +} + +d { + background-image: linear-gradient(to top to left, red 0% blue 100%); + border-image-source: repeating-linear-gradient(to top to left, red 0% blue 100%); +} + +e { + background-image: linear-gradient(to top left 0turn, red 0% blue 100%); + border-image-source: repeating-linear-gradient(to top left 0turn, red 0% blue 100%); +} + +f { + background-image: linear-gradient(in swishy, red 0% blue 100%); + border-image-source: repeating-linear-gradient(in swishy, red 0% blue 100%); +} + +g { + background-image: linear-gradient(in srgb longer hue, red 0% blue 100%); + border-image-source: repeating-linear-gradient(in srgb longer hue, red 0% blue 100%); +} + +h { + background-image: linear-gradient(in srgb in srgb, red 0% blue 100%); + border-image-source: repeating-linear-gradient(in srgb in srgb, red 0% blue 100%); +} diff --git a/testsuite/css/parser/linear-gradient-invalid.errors b/testsuite/css/parser/linear-gradient-invalid.errors new file mode 100644 index 0000000000..30b7715b30 --- /dev/null +++ b/testsuite/css/parser/linear-gradient-invalid.errors @@ -0,0 +1,16 @@ +linear-gradient-invalid.css:2:44-50: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:3:57-63: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:7:49-55: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:8:62-68: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:12:44-47: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:13:57-60: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:17:44-46: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:18:57-59: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:22:49-54: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:23:62-67: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:27:40-46: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:28:53-59: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:32:45-51: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:33:58-64: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:37:45-47: error: GTK_CSS_PARSER_ERROR_SYNTAX +linear-gradient-invalid.css:38:58-60: error: GTK_CSS_PARSER_ERROR_SYNTAX diff --git a/testsuite/css/parser/linear-gradient-invalid.ref.css b/testsuite/css/parser/linear-gradient-invalid.ref.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testsuite/css/parser/linear-gradient.css b/testsuite/css/parser/linear-gradient.css index 91dc474321..939c5bd665 100644 --- a/testsuite/css/parser/linear-gradient.css +++ b/testsuite/css/parser/linear-gradient.css @@ -102,3 +102,23 @@ u { background-image: linear-gradient(red -5px, green 20em, blue, purple -42%, pink 3pt); border-image-source: repeating-linear-gradient(red -5px, green 20em, blue, purple -42%, pink 3pt); } + +v { + background-image: linear-gradient(to left top in srgb, red 0, green 100%); + border-image-source: repeating-linear-gradient(to left top in srgb, red 0, green 100%); +} + +w { + background-image: linear-gradient(to left top in hsl longer hue, red 0, green 100%); + border-image-source: repeating-linear-gradient(to left top in hsl longer hue, red 0, green 100%); +} + +x { + background-image: linear-gradient(25deg in rec2020, red 0, green 100%); + border-image-source: repeating-linear-gradient(25deg in rec2020, red 0, green 100%); +} + +y { + background-image: linear-gradient(in hwb to bottom, red 0, green 100%); + border-image-source: repeating-linear-gradient(in hwb to bottom, red 0, green 100%); +} diff --git a/testsuite/css/parser/linear-gradient.ref.css b/testsuite/css/parser/linear-gradient.ref.css index f20227dbcf..2e87b44934 100644 --- a/testsuite/css/parser/linear-gradient.ref.css +++ b/testsuite/css/parser/linear-gradient.ref.css @@ -102,3 +102,23 @@ u { background-image: linear-gradient(rgb(255,0,0) -5px, rgb(0,128,0) 20em, rgb(0,0,255), rgb(128,0,128) -42%, rgb(255,192,203) 3pt); border-image-source: repeating-linear-gradient(rgb(255,0,0) -5px, rgb(0,128,0) 20em, rgb(0,0,255), rgb(128,0,128) -42%, rgb(255,192,203) 3pt); } + +v { + background-image: linear-gradient(to top left, rgb(255,0,0) 0, rgb(0,128,0) 100%); + border-image-source: repeating-linear-gradient(to top left, rgb(255,0,0) 0, rgb(0,128,0) 100%); +} + +w { + background-image: linear-gradient(to top left in hsl longer hue, rgb(255,0,0) 0, rgb(0,128,0) 100%); + border-image-source: repeating-linear-gradient(to top left in hsl longer hue, rgb(255,0,0) 0, rgb(0,128,0) 100%); +} + +x { + background-image: linear-gradient(25deg in rec2020, rgb(255,0,0) 0, rgb(0,128,0) 100%); + border-image-source: repeating-linear-gradient(25deg in rec2020, rgb(255,0,0) 0, rgb(0,128,0) 100%); +} + +y { + background-image: linear-gradient(in hwb, rgb(255,0,0) 0, rgb(0,128,0) 100%); + border-image-source: repeating-linear-gradient(in hwb, rgb(255,0,0) 0, rgb(0,128,0) 100%); +} 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)); +} diff --git a/testsuite/css/style/gradient.nodes b/testsuite/css/style/gradient.nodes index b5755cea54..cc34f9ff8c 100644 --- a/testsuite/css/style/gradient.nodes +++ b/testsuite/css/style/gradient.nodes @@ -7,4 +7,4 @@ window.background:dir(ltr) label:dir(ltr) background-image: radial-gradient(ellipse farthest-corner at center 30px, rgb(255,255,0), rgb(255,0,0) 30%, rgb(0,0,255)); /* gradient.css:10:3-89 */ image:dir(ltr) - background-image: self-gradient(from center 30px at 25deg, rgb(255,255,0), rgb(255,0,0) 30%, rgb(0,0,255)); /* gradient.css:14:3-83 */ + background-image: conic-gradient(at center 30px from 25deg, rgb(255,255,0), rgb(255,0,0) 30%, rgb(0,0,255)); /* gradient.css:14:3-83 */