diff --git a/gtk/gtkcsscolorvalue.c b/gtk/gtkcsscolorvalue.c index a068c863af..df92f6b427 100644 --- a/gtk/gtkcsscolorvalue.c +++ b/gtk/gtkcsscolorvalue.c @@ -30,6 +30,7 @@ #include "gdk/gdkrgbaprivate.h" #include "gtkcolorutilsprivate.h" + typedef enum { GTK_CSS_COLOR_SPACE_SRGB, GTK_CSS_COLOR_SPACE_SRGB_LINEAR, @@ -38,7 +39,8 @@ typedef enum { static GtkCssValue * gtk_css_color_value_new_mix (GtkCssValue *color1, GtkCssValue *color2, double factor); -static GtkCssValue * gtk_css_color_value_new_literal (const GdkRGBA *color); +static GtkCssValue * gtk_css_color_value_new_literal (const GdkRGBA *color, + gboolean missing[4]); typedef enum { COLOR_TYPE_LITERAL, @@ -56,6 +58,7 @@ struct _GtkCssValue { GTK_CSS_VALUE_BASE ColorType type; + guint missing; union { @@ -217,11 +220,13 @@ gtk_css_value_color_equal (const GtkCssValue *value1, switch (value1->type) { case COLOR_TYPE_LITERAL: - return gdk_rgba_equal (&value1->rgba, &value2->rgba); + return gdk_rgba_equal (&value1->rgba, &value2->rgba) && + value1->missing == value2->missing; case COLOR_TYPE_COLOR: return value1->color.color_space == value2->color.color_space && - memcmp (value1->color.values, value2->color.values, sizeof (float) * 4) == 0; + memcmp (value1->color.values, value2->color.values, sizeof (float) * 4) == 0 && + value1->missing == value2->missing; case COLOR_TYPE_NAME: return g_str_equal (value1->name, value2->name); @@ -250,13 +255,15 @@ gtk_css_value_color_equal (const GtkCssValue *value1, return value1->oklab.L == value2->oklab.L && value1->oklab.a == value2->oklab.a && value1->oklab.b == value2->oklab.b && - value1->oklab.alpha == value2->oklab.alpha; + value1->oklab.alpha == value2->oklab.alpha && + value1->missing == value2->missing; case COLOR_TYPE_OKLCH: return value1->oklch.L == value2->oklch.L && value1->oklch.C == value2->oklch.C && value1->oklch.H == value2->oklch.H && - value1->oklch.alpha == value2->oklch.alpha; + value1->oklch.alpha == value2->oklch.alpha && + value1->missing == value2->missing; default: g_assert_not_reached (); @@ -273,6 +280,17 @@ gtk_css_value_color_transition (GtkCssValue *start, return gtk_css_color_value_new_mix (start, end, progress); } +static inline void +append_color_component (GString *string, + float value, + gboolean missing) +{ + if (missing) + g_string_append (string, "none"); + else + g_string_append_printf (string, "%g", value); +} + static void gtk_css_value_color_print (const GtkCssValue *value, GString *string) @@ -309,15 +327,13 @@ gtk_css_value_color_print (const GtkCssValue *value, for (guint i = 0; i < 3; i++) { g_string_append_c (string, ' '); - g_ascii_formatd (buffer, sizeof (buffer), "%g", value->color.values[i]); - g_string_append (string, buffer); + append_color_component (string, value->color.values[i], value->missing & (1 << i)); } - if (value->color.values[3] < 0.999) + if ((value->missing & (1 << 3)) != 0 || value->color.values[3] < 0.999) { g_string_append (string, " / "); - g_ascii_formatd (buffer, sizeof (buffer), "%g", value->color.values[3]); - g_string_append (string, buffer); + append_color_component (string, value->color.values[3], value->missing & (1 << 3)); } g_string_append_c (string, ')'); @@ -363,38 +379,31 @@ gtk_css_value_color_print (const GtkCssValue *value, case COLOR_TYPE_OKLAB: g_string_append (string, "oklab("); - g_ascii_dtostr (buffer, sizeof (buffer), value->oklab.L); - g_string_append (string, buffer); + append_color_component (string, value->oklab.L, value->missing & (1 << 0)); g_string_append_c (string, ' '); - g_ascii_dtostr (buffer, sizeof (buffer), value->oklab.a); - g_string_append (string, buffer); + append_color_component (string, value->oklab.a, value->missing & (1 << 1)); g_string_append_c (string, ' '); - g_ascii_dtostr (buffer, sizeof (buffer), value->oklab.b); - g_string_append (string, buffer); - if (value->oklab.alpha < 0.999) + append_color_component (string, value->oklab.b, value->missing & (1 << 2)); + + if ((value->missing & (1 << 3)) != 0 || value->oklab.alpha < 0.999) { g_string_append (string, " / "); - g_ascii_dtostr (buffer, sizeof (buffer), value->oklab.alpha); - g_string_append (string, buffer); + append_color_component (string, value->oklab.alpha, value->missing & (1 << 3)); } g_string_append_c (string, ')'); break; case COLOR_TYPE_OKLCH: g_string_append (string, "oklch("); - g_ascii_dtostr (buffer, sizeof (buffer), value->oklch.L); - g_string_append (string, buffer); + append_color_component (string, value->oklch.L, value->missing & (1 << 0)); g_string_append_c (string, ' '); - g_ascii_dtostr (buffer, sizeof (buffer), value->oklch.C); - g_string_append (string, buffer); + append_color_component (string, value->oklch.C, value->missing & (1 << 1)); g_string_append_c (string, ' '); - g_ascii_dtostr (buffer, sizeof (buffer), value->oklch.H); - g_string_append (string, buffer); - if (value->oklch.alpha < 0.999) + append_color_component (string, value->oklch.H, value->missing & (1 << 2)); + if ((value->missing & (1 << 3)) != 0 || value->oklch.alpha < 0.999) { g_string_append (string, " / "); - g_ascii_dtostr (buffer, sizeof (buffer), value->oklch.alpha); - g_string_append (string, buffer); + append_color_component (string, value->oklab.alpha, value->missing & (1 << 3)); } g_string_append_c (string, ')'); break; @@ -507,7 +516,13 @@ gtk_css_color_value_do_resolve (GtkCssValue *color, g_assert_not_reached (); } - value = gtk_css_color_value_new_literal (&rgba); + value = gtk_css_color_value_new_literal (&rgba, + (gboolean []) { + (color->missing & (1 << 0)) != 0, + (color->missing & (1 << 1)) != 0, + (color->missing & (1 << 2)) != 0, + (color->missing & (1 << 3)) != 0, + }); } break; @@ -542,7 +557,7 @@ gtk_css_color_value_do_resolve (GtkCssValue *color, apply_shade (c, &shade, color->shade.factor); - value = gtk_css_color_value_new_literal (&shade); + value = gtk_css_color_value_new_literal (&shade, NULL); gtk_css_value_unref (val); } break; @@ -560,7 +575,7 @@ gtk_css_color_value_do_resolve (GtkCssValue *color, apply_alpha (c, &alpha, color->alpha.factor); - value = gtk_css_color_value_new_literal (&alpha); + value = gtk_css_color_value_new_literal (&alpha, NULL); gtk_css_value_unref (val); } break; @@ -583,7 +598,7 @@ gtk_css_color_value_do_resolve (GtkCssValue *color, apply_mix (color1, color2, &res, color->mix.factor); - value = gtk_css_color_value_new_literal (&res); + value = gtk_css_color_value_new_literal (&res, NULL); gtk_css_value_unref (val1); gtk_css_value_unref (val2); } @@ -604,7 +619,7 @@ gtk_css_color_value_do_resolve (GtkCssValue *color, &rgba.red, &rgba.green, &rgba.blue); rgba.alpha = color->oklab.alpha; - value = gtk_css_color_value_new_literal (&rgba); + value = gtk_css_color_value_new_literal (&rgba, NULL); } break; @@ -618,7 +633,7 @@ gtk_css_color_value_do_resolve (GtkCssValue *color, rgba.alpha = color->oklab.alpha; - value = gtk_css_color_value_new_literal (&rgba); + value = gtk_css_color_value_new_literal (&rgba, NULL); } break; @@ -656,8 +671,9 @@ gtk_css_color_value_new_white (void) return gtk_css_value_ref (&white_singleton); } -GtkCssValue * -gtk_css_color_value_new_literal (const GdkRGBA *color) +static GtkCssValue * +gtk_css_color_value_new_literal (const GdkRGBA *color, + gboolean missing[4]) { GtkCssValue *value; @@ -671,6 +687,8 @@ gtk_css_color_value_new_literal (const GdkRGBA *color) value = gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_COLOR); value->type = COLOR_TYPE_LITERAL; + if (missing) + value->missing = missing[0] | (missing[1] << 1) | (missing[2] << 2) | missing[3] << 3; value->is_computed = TRUE; value->rgba = *color; @@ -679,12 +697,14 @@ gtk_css_color_value_new_literal (const GdkRGBA *color) static GtkCssValue * gtk_css_value_value_new_color (GtkCssColorSpace color_space, - float values[4]) + float values[4], + gboolean missing[4]) { GtkCssValue *value; value = gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_COLOR); value->type = COLOR_TYPE_COLOR; + value->missing = missing[0] | (missing[1] << 1) | (missing[2] << 2) | missing[3] << 3; value->color.color_space = color_space; memcpy (value->color.values, values, sizeof (float) * 4); @@ -719,7 +739,7 @@ gtk_css_color_value_new_shade (GtkCssValue *color, apply_shade (&color->rgba, &c, factor); - return gtk_css_color_value_new_literal (&c); + return gtk_css_color_value_new_literal (&c, (gboolean[]) { 0, 0, 0, 0 }); } value = gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_COLOR); @@ -744,7 +764,7 @@ gtk_css_color_value_new_alpha (GtkCssValue *color, apply_alpha (&color->rgba, &c, factor); - return gtk_css_color_value_new_literal (&c); + return gtk_css_color_value_new_literal (&c, NULL); } value = gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_COLOR); @@ -772,7 +792,7 @@ gtk_css_color_value_new_mix (GtkCssValue *color1, apply_mix (&color1->rgba, &color2->rgba, &result, factor); - return gtk_css_color_value_new_literal (&result); + return gtk_css_color_value_new_literal (&result, NULL); } @@ -794,15 +814,17 @@ gtk_css_color_value_new_current_color (void) } static GtkCssValue * -gtk_css_color_value_new_oklab (float L, - float a, - float b, - float alpha) +gtk_css_color_value_new_oklab (float L, + float a, + float b, + float alpha, + gboolean missing[4]) { GtkCssValue *value; value = gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_COLOR); value->type = COLOR_TYPE_OKLAB; + value->missing = missing[0] | (missing[1] << 1) | (missing[2] << 2) | missing[3] << 3; value->oklab.L = L; value->oklab.a = a; value->oklab.b = b; @@ -812,15 +834,17 @@ gtk_css_color_value_new_oklab (float L, } static GtkCssValue * -gtk_css_color_value_new_oklch (float L, - float C, - float H, - float alpha) +gtk_css_color_value_new_oklch (float L, + float C, + float H, + float alpha, + gboolean missing[4]) { GtkCssValue *value; value = gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_COLOR); value->type = COLOR_TYPE_OKLCH; + value->missing = missing[0] | (missing[1] << 1) | (missing[2] << 2) | missing[3] << 3; value->oklab.L = L; value->oklab.a = C; value->oklab.b = H; @@ -919,6 +943,7 @@ typedef struct { GdkRGBA *rgba; gboolean use_percentages; + gboolean missing[4]; } ParseRGBAData; typedef enum @@ -931,14 +956,14 @@ typedef enum static gboolean parse_rgb_channel_value (GtkCssParser *parser, float *value, - ColorSyntax syntax, + gboolean *missing, + ColorSyntax *syntax, ParseRGBAData *data) { gboolean has_percentage = gtk_css_token_is (gtk_css_parser_get_token (parser), GTK_CSS_TOKEN_PERCENTAGE); - GtkCssValue *val; - switch (syntax) + switch (*syntax) { case COLOR_SYNTAX_DETECTING: data->use_percentages = has_percentage; @@ -960,14 +985,28 @@ parse_rgb_channel_value (GtkCssParser *parser, g_assert_not_reached (); } - val = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER | GTK_CSS_PARSE_PERCENT); - if (val == NULL) - return FALSE; + if (*syntax != COLOR_SYNTAX_LEGACY && + gtk_css_parser_try_ident (parser, "none")) + { + *syntax = COLOR_SYNTAX_MODERN; + *missing = TRUE; + *value = 0; + } + else + { + GtkCssValue *val; - *value = gtk_css_number_value_get_canonical (val, 255); - *value = CLAMP (*value, 0.0, 255.0) / 255.0; + *missing = FALSE; - gtk_css_value_unref (val); + val = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER | GTK_CSS_PARSE_PERCENT); + if (val == NULL) + return FALSE; + + *value = gtk_css_number_value_get_canonical (val, 255); + *value = CLAMP (*value, 0.0, 255.0) / 255.0; + + gtk_css_value_unref (val); + } return TRUE; } @@ -975,22 +1014,36 @@ parse_rgb_channel_value (GtkCssParser *parser, static gboolean parse_alpha_value (GtkCssParser *parser, float *value, - ColorSyntax syntax) + gboolean *missing, + ColorSyntax *syntax) { GtkCssNumberParseFlags flags = GTK_CSS_PARSE_NUMBER; - GtkCssValue *val; - if (syntax == COLOR_SYNTAX_MODERN) + if (*syntax == COLOR_SYNTAX_MODERN) flags |= GTK_CSS_PARSE_PERCENT; - val = gtk_css_number_value_parse (parser, flags); - if (val == NULL) - return FALSE; + if (*syntax != COLOR_SYNTAX_LEGACY && + gtk_css_parser_try_ident (parser, "none")) + { + *syntax = COLOR_SYNTAX_MODERN; + *missing = TRUE; + *value = 0; + } + else + { + GtkCssValue *val; - *value = gtk_css_number_value_get_canonical (val, 1); - *value = CLAMP (*value, 0.0, 1.0); + *missing = FALSE; - gtk_css_value_unref (val); + val = gtk_css_number_value_parse (parser, flags); + if (val == NULL) + return FALSE; + + *value = gtk_css_number_value_get_canonical (val, 1); + *value = CLAMP (*value, 0.0, 1.0); + + gtk_css_value_unref (val); + } return TRUE; } @@ -998,114 +1051,186 @@ parse_alpha_value (GtkCssParser *parser, static gboolean parse_hsl_channel_value (GtkCssParser *parser, float *value, - ColorSyntax syntax) + gboolean *missing, + ColorSyntax *syntax) { - GtkCssNumberParseFlags flags = GTK_CSS_PARSE_PERCENT; - GtkCssValue *val; + if (*syntax != COLOR_SYNTAX_LEGACY && + gtk_css_parser_try_ident (parser, "none")) + { + *syntax = COLOR_SYNTAX_MODERN; + *missing = TRUE; + *value = 0; + } + else + { + GtkCssNumberParseFlags flags = GTK_CSS_PARSE_PERCENT; + GtkCssValue *val; - if (syntax == COLOR_SYNTAX_MODERN) - flags |= GTK_CSS_PARSE_NUMBER; + *missing = FALSE; - val = gtk_css_number_value_parse (parser, flags); - if (val == NULL) - return FALSE; + if (*syntax == COLOR_SYNTAX_MODERN) + flags |= GTK_CSS_PARSE_NUMBER; - *value = gtk_css_number_value_get_canonical (val, 100); - *value = CLAMP (*value, 0.0, 100.0) / 100.0; + val = gtk_css_number_value_parse (parser, flags); + if (val == NULL) + return FALSE; - gtk_css_value_unref (val); + *value = gtk_css_number_value_get_canonical (val, 100); + *value = CLAMP (*value, 0.0, 100.0) / 100.0; + + gtk_css_value_unref (val); + } return TRUE; } static gboolean parse_hwb_channel_value (GtkCssParser *parser, - float *value) + float *value, + gboolean *missing, + ColorSyntax *syntax) { - GtkCssNumberParseFlags flags = GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_NUMBER; - GtkCssValue *val; + if (*syntax != COLOR_SYNTAX_LEGACY && + gtk_css_parser_try_ident (parser, "none")) + { + *syntax = COLOR_SYNTAX_MODERN; + *missing = TRUE; + *value = 0; + } + else + { + GtkCssNumberParseFlags flags = GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_NUMBER; + GtkCssValue *val; - val = gtk_css_number_value_parse (parser, flags); - if (val == NULL) - return FALSE; + *missing = FALSE; - *value = gtk_css_number_value_get_canonical (val, 100); - *value = CLAMP (*value, 0.0, 100.0); + val = gtk_css_number_value_parse (parser, flags); + if (val == NULL) + return FALSE; - gtk_css_value_unref (val); + *value = gtk_css_number_value_get_canonical (val, 100); + *value = CLAMP (*value, 0.0, 100.0); + + gtk_css_value_unref (val); + } return TRUE; } static gboolean parse_hue_value (GtkCssParser *parser, - float *value) + float *value, + gboolean *missing, + ColorSyntax *syntax) { - GtkCssValue *hue; + if (*syntax != COLOR_SYNTAX_LEGACY && + gtk_css_parser_try_ident (parser, "none")) + { + *syntax = COLOR_SYNTAX_MODERN; + *missing = TRUE; + *value = 0; + } + else + { + GtkCssValue *hue; - hue = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER | GTK_CSS_PARSE_ANGLE); - if (hue == NULL) - return FALSE; + *missing = FALSE; - *value = gtk_css_number_value_get_canonical (hue, 360); + hue = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_NUMBER | GTK_CSS_PARSE_ANGLE); + if (hue == NULL) + return FALSE; - gtk_css_value_unref (hue); + *value = gtk_css_number_value_get_canonical (hue, 360); + + gtk_css_value_unref (hue); + } return TRUE; } static gboolean parse_ok_L_value (GtkCssParser *parser, - float *value) + float *value, + gboolean *missing) { - GtkCssNumberParseFlags flags = GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_NUMBER; - GtkCssValue *val; + if (gtk_css_parser_try_ident (parser, "none")) + { + *missing = TRUE; + *value = 0; + } + else + { + GtkCssNumberParseFlags flags = GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_NUMBER; + GtkCssValue *val; - val = gtk_css_number_value_parse (parser, flags); - if (val == NULL) - return FALSE; + *missing = FALSE; - *value = gtk_css_number_value_get_canonical (val, 1); - *value = CLAMP (*value, 0.0, 1.0); + val = gtk_css_number_value_parse (parser, flags); + if (val == NULL) + return FALSE; - gtk_css_value_unref (val); + *value = gtk_css_number_value_get_canonical (val, 1); + *value = CLAMP (*value, 0.0, 1.0); + + gtk_css_value_unref (val); + } return TRUE; } static gboolean parse_ok_C_value (GtkCssParser *parser, - float *value) + float *value, + gboolean *missing) { - GtkCssNumberParseFlags flags = GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_NUMBER; - GtkCssValue *val; + if (gtk_css_parser_try_ident (parser, "none")) + { + *missing = TRUE; + *value = 0; + } + else + { + GtkCssNumberParseFlags flags = GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_NUMBER; + GtkCssValue *val; - val = gtk_css_number_value_parse (parser, flags); - if (val == NULL) - return FALSE; + *missing = FALSE; - *value = gtk_css_number_value_get_canonical (val, 1); - *value = MAX (*value, 0.0); + val = gtk_css_number_value_parse (parser, flags); + if (val == NULL) + return FALSE; - gtk_css_value_unref (val); + *value = gtk_css_number_value_get_canonical (val, 1); + *value = MAX (*value, 0.0); + + gtk_css_value_unref (val); + } return TRUE; } static gboolean parse_ok_ab_value (GtkCssParser *parser, - float *value) + float *value, + gboolean *missing) { - GtkCssNumberParseFlags flags = GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_NUMBER; - GtkCssValue *val; + if (gtk_css_parser_try_ident (parser, "none")) + { + *missing = TRUE; + *value = 0; + } + else + { + GtkCssNumberParseFlags flags = GTK_CSS_PARSE_PERCENT | GTK_CSS_PARSE_NUMBER; + GtkCssValue *val; - val = gtk_css_number_value_parse (parser, flags); - if (val == NULL) - return FALSE; + val = gtk_css_number_value_parse (parser, flags); + if (val == NULL) + return FALSE; - *value = gtk_css_number_value_get_canonical (val, 0.4); + *value = gtk_css_number_value_get_canonical (val, 0.4); - gtk_css_value_unref (val); + gtk_css_value_unref (val); + } return TRUE; } @@ -1113,215 +1238,194 @@ parse_ok_ab_value (GtkCssParser *parser, static guint parse_rgba_color_channel (GtkCssParser *parser, guint arg, - ColorSyntax syntax, + ColorSyntax *syntax, gpointer data) { ParseRGBAData *rgba_data = data; GdkRGBA *rgba = rgba_data->rgba; + gboolean *missing = rgba_data->missing; switch (arg) - { + { case 0: - if (!parse_rgb_channel_value (parser, &rgba->red, syntax, rgba_data)) - return 0; - return 1; + return parse_rgb_channel_value (parser, &rgba->red, &missing[0], syntax, rgba_data); case 1: - if (!parse_rgb_channel_value (parser, &rgba->green, syntax, rgba_data)) - return 0; - return 1; + return parse_rgb_channel_value (parser, &rgba->green, &missing[1], syntax, rgba_data); case 2: - if (!parse_rgb_channel_value (parser, &rgba->blue, syntax, rgba_data)) - return 0; - return 1; + return parse_rgb_channel_value (parser, &rgba->blue, &missing[2], syntax, rgba_data); case 3: - if (!parse_alpha_value (parser, &rgba->alpha, syntax)) - return 0; - return 1; + return parse_alpha_value (parser, &rgba->alpha, &missing[3], syntax); default: g_assert_not_reached (); - return 0; - } + } } +typedef struct +{ + GdkHSLA *hsla; + gboolean missing[4]; +} ParseHSLAData; + static guint parse_hsla_color_channel (GtkCssParser *parser, guint arg, - ColorSyntax syntax, + ColorSyntax *syntax, gpointer data) { - GdkHSLA *hsla = data; + ParseHSLAData *hsla_data = data; + GdkHSLA *hsla = hsla_data->hsla; + gboolean *missing = hsla_data->missing; switch (arg) - { + { case 0: - if (!parse_hue_value (parser, &hsla->hue)) - return 0; - return 1; + return parse_hue_value (parser, &hsla->hue, &missing[0], syntax); case 1: - if (!parse_hsl_channel_value (parser, &hsla->saturation, syntax)) - return 0; - return 1; + return parse_hsl_channel_value (parser, &hsla->saturation, &missing[1], syntax); case 2: - if (!parse_hsl_channel_value (parser, &hsla->lightness, syntax)) - return 0; - return 1; + return parse_hsl_channel_value (parser, &hsla->lightness, &missing[2], syntax); case 3: - if (!parse_alpha_value (parser, &hsla->alpha, syntax)) - return 0; - return 1; + return parse_alpha_value (parser, &hsla->alpha, &missing[3], syntax); default: g_assert_not_reached (); - return 0; - } + } } typedef struct { float hue, white, black, alpha; + gboolean missing[4]; } HwbData; static guint parse_hwb_color_channel (GtkCssParser *parser, guint arg, - ColorSyntax syntax, + ColorSyntax *syntax, gpointer data) { HwbData *hwb = data; switch (arg) - { + { case 0: - if (!parse_hue_value (parser, &hwb->hue)) - return 0; - return 1; + return parse_hue_value (parser, &hwb->hue, &hwb->missing[0], syntax); case 1: - if (!parse_hwb_channel_value (parser, &hwb->white)) - return 0; - return 1; + return parse_hwb_channel_value (parser, &hwb->white, &hwb->missing[1], syntax); case 2: - if (!parse_hwb_channel_value (parser, &hwb->black)) - return 0; - return 1; + return parse_hwb_channel_value (parser, &hwb->black, &hwb->missing[2], syntax); case 3: - if (!parse_alpha_value (parser, &hwb->alpha, syntax)) - return 0; - return 1; + return parse_alpha_value (parser, &hwb->alpha, &hwb->missing[3], syntax); default: g_assert_not_reached (); - return 0; - } + } } typedef struct { float L, a, b, alpha; + gboolean missing[4]; } LabData; static guint parse_oklab_color_channel (GtkCssParser *parser, guint arg, - ColorSyntax syntax, + ColorSyntax *syntax, gpointer data) { LabData *oklab = data; switch (arg) - { + { case 0: - if (!parse_ok_L_value (parser, &oklab->L)) - return 0; - return 1; + return parse_ok_L_value (parser, &oklab->L, &oklab->missing[0]); case 1: - if (!parse_ok_ab_value (parser, &oklab->a)) - return 0; - return 1; + return parse_ok_ab_value (parser, &oklab->a, &oklab->missing[1]); case 2: - if (!parse_ok_ab_value (parser, &oklab->b)) - return 0; - return 1; + return parse_ok_ab_value (parser, &oklab->b, &oklab->missing[2]); case 3: - if (!parse_alpha_value (parser, &oklab->alpha, syntax)) - return 0; - return 1; + return parse_alpha_value (parser, &oklab->alpha, &oklab->missing[3], syntax); default: g_assert_not_reached (); - return 0; - } + } } typedef struct { float L, C, H, alpha; + gboolean missing[4]; } LchData; static guint parse_oklch_color_channel (GtkCssParser *parser, guint arg, - ColorSyntax syntax, + ColorSyntax *syntax, gpointer data) { LchData *oklch = data; switch (arg) - { + { case 0: - if (!parse_ok_L_value (parser, &oklch->L)) - return 0; - return 1; + return parse_ok_L_value (parser, &oklch->L, &oklch->missing[0]); case 1: - if (!parse_ok_C_value (parser, &oklch->C)) - return 0; - return 1; + return parse_ok_C_value (parser, &oklch->C, &oklch->missing[1]); case 2: - if (!parse_hue_value (parser, &oklch->H)) - return 0; - return 1; + return parse_hue_value (parser, &oklch->H, &oklch->missing[2], syntax); case 3: - if (!parse_alpha_value (parser, &oklch->alpha, syntax)) - return 0; - return 1; + return parse_alpha_value (parser, &oklch->alpha, &oklch->missing[3], syntax); default: g_assert_not_reached (); - return 0; - } + } } typedef struct { GtkCssColorSpace color_space; float values[4]; + gboolean missing[4]; } ParseColorData; static gboolean parse_color_channel_value (GtkCssParser *parser, - float *value) + float *value, + gboolean *missing) { - GtkCssNumberParseFlags flags = GTK_CSS_PARSE_NUMBER | GTK_CSS_PARSE_PERCENT; - GtkCssValue *val; + if (gtk_css_parser_try_ident (parser, "none")) + { + *missing = TRUE; + *value = 0; + } + else + { + GtkCssNumberParseFlags flags = GTK_CSS_PARSE_NUMBER | GTK_CSS_PARSE_PERCENT; + GtkCssValue *val; - val = gtk_css_number_value_parse (parser, flags); - if (val == NULL) - return FALSE; + *missing = FALSE; - *value = gtk_css_number_value_get_canonical (val, 1); + val = gtk_css_number_value_parse (parser, flags); + if (val == NULL) + return FALSE; - gtk_css_value_unref (val); + *value = gtk_css_number_value_get_canonical (val, 1); + + gtk_css_value_unref (val); + } return TRUE; } @@ -1329,13 +1433,13 @@ parse_color_channel_value (GtkCssParser *parser, static guint parse_color_color_channel (GtkCssParser *parser, guint arg, - ColorSyntax syntax, + ColorSyntax *syntax, gpointer data) { ParseColorData *color_data = data; switch (arg) - { + { case 0: if (gtk_css_parser_try_ident (parser, "srgb")) { @@ -1353,29 +1457,20 @@ parse_color_color_channel (GtkCssParser *parser, return 0; case 1: - if (!parse_color_channel_value (parser, &color_data->values[0])) - return 0; - return 1; + return parse_color_channel_value (parser, &color_data->values[0], &color_data->missing[0]); case 2: - if (!parse_color_channel_value (parser, &color_data->values[1])) - return 0; - return 1; + return parse_color_channel_value (parser, &color_data->values[1], &color_data->missing[1]); case 3: - if (!parse_color_channel_value (parser, &color_data->values[2])) - return 0; - return 1; + return parse_color_channel_value (parser, &color_data->values[2], &color_data->missing[2]); case 4: - if (!parse_alpha_value (parser, &color_data->values[3], syntax)) - return 0; - return 1; + return parse_alpha_value (parser, &color_data->values[3], &color_data->missing[3], syntax); default: g_assert_not_reached (); - return 0; - } + } } static gboolean @@ -1384,7 +1479,7 @@ parse_color_function (GtkCssParser *self, gboolean parse_color_space, gboolean allow_alpha, gboolean require_alpha, - guint (* parse_func) (GtkCssParser *, guint, ColorSyntax, gpointer), + guint (* parse_func) (GtkCssParser *, guint, ColorSyntax *, gpointer), gpointer data) { const GtkCssToken *token; @@ -1409,7 +1504,7 @@ parse_color_function (GtkCssParser *self, arg = 0; while (TRUE) { - guint parse_args = parse_func (self, arg, syntax, data); + guint parse_args = parse_func (self, arg, &syntax, data); if (parse_args == 0) break; arg += parse_args; @@ -1517,7 +1612,7 @@ gtk_css_color_value_parse (GtkCssParser *parser) else if (gtk_css_parser_has_function (parser, "rgb") || gtk_css_parser_has_function (parser, "rgba")) { gboolean has_alpha; - ParseRGBAData data = { NULL, }; + ParseRGBAData data = { NULL, FALSE, { FALSE, } }; data.rgba = &rgba; rgba.alpha = 1.0; @@ -1527,28 +1622,27 @@ gtk_css_color_value_parse (GtkCssParser *parser) if (!parse_color_function (parser, COLOR_SYNTAX_DETECTING, FALSE, has_alpha, has_alpha, parse_rgba_color_channel, &data)) return NULL; - return gtk_css_color_value_new_literal (&rgba); + return gtk_css_color_value_new_literal (&rgba, data.missing); } else if (gtk_css_parser_has_function (parser, "hsl") || gtk_css_parser_has_function (parser, "hsla")) { - GdkHSLA hsla; + GdkHSLA hsla = { 0, 0, 0, 1 }; + ParseHSLAData data = { NULL, { FALSE, } }; + data.hsla = &hsla; - hsla.alpha = 1.0; - - if (!parse_color_function (parser, COLOR_SYNTAX_DETECTING, FALSE, TRUE, FALSE, parse_hsla_color_channel, &hsla)) + if (!parse_color_function (parser, COLOR_SYNTAX_DETECTING, FALSE, TRUE, FALSE, parse_hsla_color_channel, &data)) return NULL; - _gdk_rgba_init_from_hsla (&rgba, &hsla); + _gdk_rgba_init_from_hsla (&rgba, data.hsla); - return gtk_css_color_value_new_literal (&rgba); + /* FIXME */ + return gtk_css_color_value_new_literal (&rgba, (gboolean[]) { 0, 0, 0, 0 } ); } else if (gtk_css_parser_has_function (parser, "hwb")) { - HwbData hwb = { 0, }; + HwbData hwb = { 0, 0, 0, 1, { FALSE, } }; float red, green, blue; - hwb.alpha = 1.0; - if (!parse_color_function (parser, COLOR_SYNTAX_MODERN, FALSE, TRUE, FALSE, parse_hwb_color_channel, &hwb)) return NULL; @@ -1562,42 +1656,36 @@ gtk_css_color_value_parse (GtkCssParser *parser) rgba.blue = blue; rgba.alpha = hwb.alpha; - return gtk_css_color_value_new_literal (&rgba); + return gtk_css_color_value_new_literal (&rgba, (gboolean[]) { 0, 0, 0, 0 } ); } else if (gtk_css_parser_has_function (parser, "oklab")) { - LabData oklab = { 0, }; - - oklab.alpha = 1.0; + LabData oklab = { 0, 0, 0, 1, { FALSE, } }; if (!parse_color_function (parser, COLOR_SYNTAX_MODERN, FALSE, TRUE, FALSE, parse_oklab_color_channel, &oklab)) return NULL; - return gtk_css_color_value_new_oklab (oklab.L, oklab.a, oklab.b, oklab.alpha); + return gtk_css_color_value_new_oklab (oklab.L, oklab.a, oklab.b, oklab.alpha, + oklab.missing); } else if (gtk_css_parser_has_function (parser, "oklch")) { - LchData oklch = { 0, }; - - oklch.alpha = 1.0; + LchData oklch = { 0, 0, 0, 1, { FALSE, } }; if (!parse_color_function (parser, COLOR_SYNTAX_MODERN, FALSE, TRUE, FALSE, parse_oklch_color_channel, &oklch)) return NULL; - rgba.alpha = oklch.alpha; - - return gtk_css_color_value_new_oklch (oklch.L, oklch.C, oklch.H, oklch.alpha); + return gtk_css_color_value_new_oklch (oklch.L, oklch.C, oklch.H, oklch.alpha, + oklch.missing); } else if (gtk_css_parser_has_function (parser, "color")) { - ParseColorData data; - - data.values[3] = 1.0; + ParseColorData data = { 0, { 0, 0, 0, 1 }, { FALSE, } }; if (!parse_color_function (parser, COLOR_SYNTAX_MODERN, TRUE, TRUE, FALSE, parse_color_color_channel, &data)) return NULL; - return gtk_css_value_value_new_color (data.color_space, data.values); + return gtk_css_value_value_new_color (data.color_space, data.values, data.missing); } else if (gtk_css_parser_has_function (parser, "lighter")) { @@ -1662,7 +1750,7 @@ gtk_css_color_value_parse (GtkCssParser *parser) } if (gdk_rgba_parser_parse (parser, &rgba)) - return gtk_css_color_value_new_literal (&rgba); + return gtk_css_color_value_new_literal (&rgba, (gboolean[]) { 0, 0, 0, 0 }); else return NULL; }