Merge branch 'wip/otte/for-main' into 'main'

gsk: Don't print any sRGB color as rgb() or rgba()

See merge request GNOME/gtk!7619
This commit is contained in:
Benjamin Otte 2024-08-17 19:28:07 +00:00
commit 0815359a20
9 changed files with 247 additions and 125 deletions

View File

@ -331,6 +331,68 @@ gdk_default_color_state_get_cicp (GdkColorState *color_state)
return &self->cicp;
}
static gboolean
gdk_color_state_check_inf_nan (const float src[4],
float dest[4])
{
if (isnan (src[0]) ||
isnan (src[1]) ||
isnan (src[2]) ||
isnan (src[3]))
{
dest = (float[4]) { 1.0, 0.0, 0.8, 1.0 };
return TRUE;
}
if (isinf (src[0]) ||
isinf (src[1]) ||
isinf (src[2]) ||
isinf (src[3]))
{
dest = (float[4]) { 0.0, 0.8, 1.0, 1.0 };
return TRUE;
}
return FALSE;
}
static void
gdk_color_state_clamp_0_1 (GdkColorState *self,
const float src[4],
float dest[4])
{
if (gdk_color_state_check_inf_nan (src, dest))
return;
dest[0] = CLAMP (src[0], 0.0f, 1.0f);
dest[1] = CLAMP (src[1], 0.0f, 1.0f);
dest[2] = CLAMP (src[2], 0.0f, 1.0f);
dest[3] = CLAMP (src[3], 0.0f, 1.0f);
}
static void
gdk_color_state_clamp_unbounded (GdkColorState *self,
const float src[4],
float dest[4])
{
if (gdk_color_state_check_inf_nan (src, dest))
return;
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = CLAMP (src[3], 0.0f, 1.0f);
}
static void
gdk_default_color_state_clamp (GdkColorState *color_state,
const float in[4],
float out[4])
{
GdkDefaultColorState *self = (GdkDefaultColorState *) color_state;
self->clamp (color_state, in, out);
}
/* }}} */
static const
@ -342,6 +404,7 @@ GdkColorStateClass GDK_DEFAULT_COLOR_STATE_CLASS = {
.get_convert_to = gdk_default_color_state_get_convert_to,
.get_convert_from = gdk_default_color_state_get_convert_from,
.get_cicp = gdk_default_color_state_get_cicp,
.clamp = gdk_default_color_state_clamp,
};
GdkDefaultColorState gdk_default_color_states[] = {
@ -360,6 +423,7 @@ GdkDefaultColorState gdk_default_color_states[] = {
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_srgb_to_rec2100_pq,
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_srgb_to_rec2100_linear,
},
.clamp = gdk_color_state_clamp_0_1,
.cicp = { 1, 13, 0, 1 },
},
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = {
@ -377,6 +441,7 @@ GdkDefaultColorState gdk_default_color_states[] = {
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_srgb_linear_to_rec2100_pq,
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_srgb_linear_to_rec2100_linear,
},
.clamp = gdk_color_state_clamp_0_1,
.cicp = { 1, 8, 0, 1 },
},
[GDK_COLOR_STATE_ID_REC2100_PQ] = {
@ -394,6 +459,7 @@ GdkDefaultColorState gdk_default_color_states[] = {
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_rec2100_pq_to_srgb_linear,
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_rec2100_pq_to_rec2100_linear,
},
.clamp = gdk_color_state_clamp_0_1,
.cicp = { 9, 16, 0, 1 },
},
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = {
@ -411,6 +477,7 @@ GdkDefaultColorState gdk_default_color_states[] = {
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_rec2100_linear_to_srgb_linear,
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_rec2100_linear_to_rec2100_pq,
},
.clamp = gdk_color_state_clamp_unbounded,
.cicp = { 9, 8, 0, 1 },
},
};
@ -566,6 +633,7 @@ GdkColorStateClass GDK_CICP_COLOR_STATE_CLASS = {
.get_convert_to = gdk_cicp_color_state_get_convert_to,
.get_convert_from = gdk_cicp_color_state_get_convert_from,
.get_cicp = gdk_cicp_color_state_get_cicp,
.clamp = gdk_color_state_clamp_0_1,
};
static inline float *
@ -770,6 +838,24 @@ gdk_color_state_get_no_srgb_tf (GdkColorState *self)
return self->klass->get_no_srgb_tf (self);
}
/*< private >
* gdk_color_state_clamp:
* @self: a `GdkColorState`
* @src: the values to clamp
* @dest: (out): location to store the result, may be identical to
* the src argument
*
* Clamps the values to be within the allowed ranges for the given
* color state.
*/
void
gdk_color_state_clamp (GdkColorState *self,
const float src[4],
float dest[4])
{
self->klass->clamp (self, src, dest);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@ -46,6 +46,9 @@ struct _GdkColorStateClass
GdkFloatColorConvert (* get_convert_from) (GdkColorState *self,
GdkColorState *source);
const GdkCicp * (* get_cicp) (GdkColorState *self);
void (* clamp) (GdkColorState *self,
const float src[4],
float dest[4]);
};
typedef struct _GdkDefaultColorState GdkDefaultColorState;
@ -57,6 +60,9 @@ struct _GdkDefaultColorState
const char *name;
GdkColorState *no_srgb;
GdkFloatColorConvert convert_to[GDK_COLOR_STATE_N_IDS];
void (* clamp) (GdkColorState *self,
const float src[4],
float dest[4]);
GdkCicp cicp;
};
@ -78,6 +84,10 @@ GdkColorState * gdk_color_state_get_no_srgb_tf (GdkColorState
GdkColorState * gdk_color_state_new_for_cicp (const GdkCicp *cicp,
GError **error);
void gdk_color_state_clamp (GdkColorState *self,
const float src[4],
float dest[4]);
static inline GdkColorState *
gdk_color_state_get_rendering_color_state (GdkColorState *self)
{
@ -214,4 +224,3 @@ gdk_color_state_from_rgba (GdkColorState *self,
self,
out_color);
}

View File

@ -712,9 +712,130 @@ parse_float4 (GtkCssParser *parser,
return TRUE;
}
static gboolean parse_color2 (GtkCssParser *parser,
Context *context,
gpointer color);
static gboolean
parse_color_state (GtkCssParser *parser,
Context *context,
gpointer color_state)
{
GdkColorState *cs = NULL;
if (gtk_css_parser_try_ident (parser, "srgb"))
cs = gdk_color_state_get_srgb ();
else if (gtk_css_parser_try_ident (parser, "srgb-linear"))
cs = gdk_color_state_get_srgb_linear ();
else if (gtk_css_parser_try_ident (parser, "rec2100-pq"))
cs = gdk_color_state_get_rec2100_pq ();
else if (gtk_css_parser_try_ident (parser, "rec2100-linear"))
cs = gdk_color_state_get_rec2100_linear ();
else if (gtk_css_token_is (gtk_css_parser_get_token (parser), GTK_CSS_TOKEN_STRING))
{
char *name = gtk_css_parser_consume_string (parser);
if (context->named_color_states)
cs = g_hash_table_lookup (context->named_color_states, name);
if (!cs)
{
gtk_css_parser_error_value (parser, "No color state named \"%s\"", name);
g_free (name);
return FALSE;
}
g_free (name);
}
else
{
gtk_css_parser_error_syntax (parser, "Expected a valid color state");
return FALSE;
}
*(GdkColorState **) color_state = gdk_color_state_ref (cs);
return TRUE;
}
typedef struct {
Context *context;
GdkColor *color;
} ColorArgData;
static guint
parse_color_arg (GtkCssParser *parser,
guint arg,
gpointer data)
{
ColorArgData *d = data;
GdkColorState *color_state;
float values[4], clamped[4];
if (!parse_color_state (parser, d->context, &color_state))
return 0;
for (int i = 0; i < 3; i++)
{
double number;
if (!gtk_css_parser_consume_number_or_percentage (parser, 0, 1, &number))
return 0;
values[i] = number;
}
if (gtk_css_parser_try_delim (parser, '/'))
{
double number;
if (!gtk_css_parser_consume_number_or_percentage (parser, 0, 1, &number))
return 0;
values[3] = number;
}
else
{
values[3] = 1;
}
gdk_color_state_clamp (color_state, values, clamped);
if (values[0] != clamped[0] ||
values[1] != clamped[1] ||
values[2] != clamped[2] ||
values[3] != clamped[3])
{
gtk_css_parser_error (parser,
GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE,
gtk_css_parser_get_block_location (parser),
gtk_css_parser_get_end_location (parser),
"Color values out of range for color state");
}
gdk_color_init (d->color, color_state, clamped);
return 1;
}
static gboolean
parse_color (GtkCssParser *parser,
Context *context,
gpointer color)
{
GdkRGBA rgba;
if (gtk_css_parser_has_function (parser, "color"))
{
ColorArgData data = { context, color };
if (!gtk_css_parser_consume_function (parser, 1, 1, parse_color_arg, &data))
return FALSE;
return TRUE;
}
else if (gdk_rgba_parser_parse (parser, &rgba))
{
gdk_color_init_from_rgba ((GdkColor *) color, &rgba);
return TRUE;
}
return FALSE;
}
static gboolean
parse_shadows (GtkCssParser *parser,
@ -729,7 +850,7 @@ parse_shadows (GtkCssParser *parser,
GdkColor color = GDK_COLOR_SRGB (0, 0, 0, 1);
double dx = 0, dy = 0, radius = 0;
if (!parse_color2 (parser, context, &color))
if (!parse_color (parser, context, &color))
gtk_css_parser_error_value (parser, "Expected shadow color");
if (!gtk_css_parser_consume_number (parser, &dx))
@ -1565,117 +1686,6 @@ parse_color_state_rule (GtkCssParser *parser,
return TRUE;
}
static gboolean
parse_color_state (GtkCssParser *parser,
Context *context,
gpointer color_state)
{
GdkColorState *cs = NULL;
if (gtk_css_parser_try_ident (parser, "srgb"))
cs = gdk_color_state_get_srgb ();
else if (gtk_css_parser_try_ident (parser, "srgb-linear"))
cs = gdk_color_state_get_srgb_linear ();
else if (gtk_css_parser_try_ident (parser, "rec2100-pq"))
cs = gdk_color_state_get_rec2100_pq ();
else if (gtk_css_parser_try_ident (parser, "rec2100-linear"))
cs = gdk_color_state_get_rec2100_linear ();
else if (gtk_css_token_is (gtk_css_parser_get_token (parser), GTK_CSS_TOKEN_STRING))
{
char *name = gtk_css_parser_consume_string (parser);
if (context->named_color_states)
cs = g_hash_table_lookup (context->named_color_states, name);
if (!cs)
{
gtk_css_parser_error_value (parser, "No color state named \"%s\"", name);
g_free (name);
return FALSE;
}
g_free (name);
}
else
{
gtk_css_parser_error_syntax (parser, "Expected a valid color state");
return FALSE;
}
*(GdkColorState **) color_state = gdk_color_state_ref (cs);
return TRUE;
}
typedef struct {
Context *context;
GdkColor *color;
} ColorArgData;
static guint
parse_color_arg (GtkCssParser *parser,
guint arg,
gpointer data)
{
ColorArgData *d = data;
GdkColorState *color_state;
float values[4];
if (!parse_color_state (parser, d->context, &color_state))
return 0;
for (int i = 0; i < 3; i++)
{
double number;
if (!gtk_css_parser_consume_number_or_percentage (parser, 0, 1, &number))
return 0;
values[i] = number;
}
if (gtk_css_parser_try_delim (parser, '/'))
{
double number;
if (!gtk_css_parser_consume_number_or_percentage (parser, 0, 1, &number))
return 0;
values[3] = number;
}
else
{
values[3] = 1;
}
gdk_color_init (d->color, color_state, values);
return 1;
}
static gboolean
parse_color2 (GtkCssParser *parser,
Context *context,
gpointer color)
{
GdkRGBA rgba;
if (gtk_css_parser_has_function (parser, "color"))
{
ColorArgData data = { context, color };
if (!gtk_css_parser_consume_function (parser, 1, 1, parse_color_arg, &data))
return FALSE;
return TRUE;
}
else if (gdk_rgba_parser_parse (parser, &rgba))
{
gdk_color_init_from_rgba ((GdkColor *) color, &rgba);
return TRUE;
}
return FALSE;
}
static gboolean
parse_colors4 (GtkCssParser *parser,
Context *context,
@ -1686,7 +1696,7 @@ parse_colors4 (GtkCssParser *parser,
for (i = 0; i < 4 && !gtk_css_parser_has_token (parser, GTK_CSS_TOKEN_EOF); i ++)
{
if (!parse_color2 (parser, context, &colors[i]))
if (!parse_color (parser, context, &colors[i]))
return FALSE;
}
if (i == 0)
@ -1712,7 +1722,7 @@ parse_color_node (GtkCssParser *parser,
GdkColor color = GDK_COLOR_SRGB (1, 0, 0.8, 1);
const Declaration declarations[] = {
{ "bounds", parse_rect, NULL, &bounds },
{ "color", parse_color2, NULL, &color },
{ "color", parse_color, NULL, &color },
};
GskRenderNode *node;
@ -1890,7 +1900,7 @@ parse_inset_shadow_node (GtkCssParser *parser,
double dx = 1, dy = 1, blur = 0, spread = 0;
const Declaration declarations[] = {
{ "outline", parse_rounded_rect, NULL, &outline },
{ "color", parse_color2, NULL, &color },
{ "color", parse_color, NULL, &color },
{ "dx", parse_double, NULL, &dx },
{ "dy", parse_double, NULL, &dy },
{ "spread", parse_double, NULL, &spread },
@ -2304,7 +2314,7 @@ parse_outset_shadow_node (GtkCssParser *parser,
double dx = 1, dy = 1, blur = 0, spread = 0;
const Declaration declarations[] = {
{ "outline", parse_rounded_rect, NULL, &outline },
{ "color", parse_color2, NULL, &color },
{ "color", parse_color, NULL, &color },
{ "dx", parse_double, NULL, &dx },
{ "dy", parse_double, NULL, &dy },
{ "spread", parse_double, NULL, &spread },
@ -2615,7 +2625,7 @@ parse_text_node (GtkCssParser *parser,
const Declaration declarations[] = {
{ "font", parse_font, clear_font, &font },
{ "offset", parse_point, NULL, &offset },
{ "color", parse_color2, NULL, &color },
{ "color", parse_color, NULL, &color },
{ "glyphs", parse_glyphs, clear_glyphs, &glyphs },
{ "hint-style", parse_hint_style, NULL, &hint_style },
{ "antialias", parse_antialias, NULL, &antialias },
@ -3668,7 +3678,10 @@ static void
print_color (Printer *p,
const GdkColor *color)
{
if (gdk_color_state_equal (color->color_state, GDK_COLOR_STATE_SRGB))
if (gdk_color_state_equal (color->color_state, GDK_COLOR_STATE_SRGB) &&
round (CLAMP (color->red, 0, 1) * 255) == color->red * 255 &&
round (CLAMP (color->green, 0, 1) * 255) == color->green * 255 &&
round (CLAMP (color->blue, 0, 1) * 255) == color->blue * 255)
{
gdk_rgba_print ((const GdkRGBA *) color->values, p->str);
}

View File

@ -431,6 +431,7 @@ node_parser_tests = [
'shadow-fail.node',
'shadow-fail.ref.node',
'shadow-fail.errors',
'srgb-high-accuracy.node',
'string-error.errors',
'string-error.node',
'string-error.ref.node',

View File

@ -4,7 +4,7 @@ color {
}
color {
bounds: 100 100 200 300;
color: rgb(1,1,0);
color: color(srgb 0.00392157 0.00196078 0.00117647);
}
color {
bounds: 100 100 200 300;

View File

@ -1 +1,2 @@
<data>:2:27-28: error: GTK_CSS_PARSER_ERROR_SYNTAX
<data>:2:10-27: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
<data>:6:27-28: error: GTK_CSS_PARSER_ERROR_SYNTAX

View File

@ -1,3 +1,7 @@
color {
color: color(srgb 1 2 3 4 5 6);
color: color(srgb 1 2 3);
}
color {
color: color(srgb 1 1 1 1 1 1);
}

View File

@ -2,3 +2,7 @@ color {
bounds: 0 0 50 50;
color: rgb(255,255,255);
}
color {
bounds: 0 0 50 50;
color: rgb(255,255,255);
}

View File

@ -0,0 +1,4 @@
color {
bounds: 0 0 50 50;
color: color(srgb 0.999 0 0);
}