css: Add support for xyz colors

This is somewhat central, and we have all the pieces to support
it, so we might as well add the css syntax for it.
This commit is contained in:
Matthias Clasen 2024-06-10 00:13:35 -04:00
parent d71fc41152
commit 2d1e978599
5 changed files with 72 additions and 9 deletions

View File

@ -424,18 +424,18 @@ gtk_linear_srgb_to_rgb (float linear_red, float linear_green, float linear_bl
*blue = apply_gamma (linear_blue);
}
static void
gtk_linrgb_to_xyz (float r, float g, float b,
float *x, float *y, float *z)
void
gtk_linear_srgb_to_xyz (float r, float g, float b,
float *x, float *y, float *z)
{
*x = (506752.0 / 1228815.0) * r + (87881.0 / 245763.0) * g + (12673.0 / 70218.0) * b;
*y = (87098.0 / 409605.0) * r + (175762.0 / 245763.0) * g + (12673.0 / 175545.0) * b;
*z = ( 7918.0 / 409605.0) * r + (87881.0 / 737289.0) * g + (1001167.0 / 1053270.0) * b;
}
static void
gtk_xyz_to_linrgb (float x, float y, float z,
float *r, float *g, float *b)
void
gtk_xyz_to_linear_srgb (float x, float y, float z,
float *r, float *g, float *b)
{
*r = (12831.0 / 3959.0) * x - (329.0 / 214.0) * y - (1974.0 / 3959.0) * z;
*g = - (851781.0 / 878810.0) * x + (1648619.0 / 878810.0) * y + (36519.0 / 878810.0) * z;
@ -467,7 +467,7 @@ void gtk_rgb_to_p3 (float red, float green, float blue,
float x, y, z;
gtk_rgb_to_linear_srgb (red, green, blue, &r, &g, &b);
gtk_linrgb_to_xyz (r, g, b, &x, &y, &z);
gtk_linear_srgb_to_xyz (r, g, b, &x, &y, &z);
gtk_xyz_to_lin_p3 (x, y, z, &r, &g, &b);
gtk_linear_srgb_to_rgb (r, g, b, pr, pg, pb);
}
@ -481,6 +481,6 @@ gtk_p3_to_rgb (float pr, float pg, float pb,
gtk_rgb_to_linear_srgb (pr, pg, pb, &r, &g, &b);
gtk_lin_p3_to_xyz (r, g, b, &x, &y, &z);
gtk_xyz_to_linrgb (x, y, z, &r, &g, &b);
gtk_xyz_to_linear_srgb (x, y, z, &r, &g, &b);
gtk_linear_srgb_to_rgb (r, g, b, red, green, blue);
}

View File

@ -56,4 +56,10 @@ void gtk_rgb_to_p3 (float red, float green, float blue,
void gtk_p3_to_rgb (float pr, float pg, float pb,
float *red, float *green, float *blue);
void gtk_xyz_to_linear_srgb (float x, float y, float z,
float *r, float *g, float *b);
void gtk_linear_srgb_to_xyz (float r, float g, float b,
float *x, float *y, float *z);
G_END_DECLS

View File

@ -36,6 +36,7 @@ gtk_css_color_init (GtkCssColor *color,
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
case GTK_CSS_COLOR_SPACE_OKLAB:
case GTK_CSS_COLOR_SPACE_DISPLAY_P3:
case GTK_CSS_COLOR_SPACE_XYZ:
break;
case GTK_CSS_COLOR_SPACE_HSL:
@ -141,6 +142,10 @@ gtk_css_color_print (const GtkCssColor *color,
g_string_append (string, "color(display-p3 ");
break;
case GTK_CSS_COLOR_SPACE_XYZ:
g_string_append (string, "color(xyz ");
break;
default:
g_assert_not_reached ();
}
@ -194,6 +199,14 @@ gtk_css_color_space_get_coord_name (GtkCssColorSpace color_space,
case 2: return "b";
default: g_assert_not_reached ();
}
case GTK_CSS_COLOR_SPACE_XYZ:
switch (coord)
{
case 0: return "x";
case 1: return "y";
case 2: return "z";
default: g_assert_not_reached ();
}
case GTK_CSS_COLOR_SPACE_HSL:
switch (coord)
{
@ -253,6 +266,7 @@ gtk_css_color_space_get_coord_range (GtkCssColorSpace color_space,
return;
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
case GTK_CSS_COLOR_SPACE_DISPLAY_P3:
case GTK_CSS_COLOR_SPACE_XYZ:
*lower = 0;
*upper = 1;
return;
@ -295,6 +309,7 @@ color_space_is_polar (GtkCssColorSpace color_space)
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
case GTK_CSS_COLOR_SPACE_OKLAB:
case GTK_CSS_COLOR_SPACE_DISPLAY_P3:
case GTK_CSS_COLOR_SPACE_XYZ:
return FALSE;
case GTK_CSS_COLOR_SPACE_HSL:
case GTK_CSS_COLOR_SPACE_HWB:
@ -320,6 +335,7 @@ convert_to_rectangular (GtkCssColor *output)
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
case GTK_CSS_COLOR_SPACE_OKLAB:
case GTK_CSS_COLOR_SPACE_DISPLAY_P3:
case GTK_CSS_COLOR_SPACE_XYZ:
break;
case GTK_CSS_COLOR_SPACE_HSL:
@ -362,7 +378,8 @@ convert_to_linear (GtkCssColor *output)
g_assert (output->color_space == GTK_CSS_COLOR_SPACE_SRGB ||
output->color_space == GTK_CSS_COLOR_SPACE_SRGB_LINEAR ||
output->color_space == GTK_CSS_COLOR_SPACE_OKLAB ||
output->color_space == GTK_CSS_COLOR_SPACE_DISPLAY_P3);
output->color_space == GTK_CSS_COLOR_SPACE_DISPLAY_P3 ||
output->color_space == GTK_CSS_COLOR_SPACE_XYZ);
if (output->color_space == GTK_CSS_COLOR_SPACE_SRGB)
{
@ -384,6 +401,15 @@ convert_to_linear (GtkCssColor *output)
v[3] = output->values[3];
gtk_css_color_init (output, GTK_CSS_COLOR_SPACE_SRGB_LINEAR, v);
}
else if (output->color_space == GTK_CSS_COLOR_SPACE_XYZ)
{
gtk_xyz_to_linear_srgb (output->values[0],
output->values[1],
output->values[2],
&v[0], &v[1], &v[2]);
v[3] = output->values[3];
gtk_css_color_init (output, GTK_CSS_COLOR_SPACE_SRGB_LINEAR, v);
}
}
static void
@ -409,6 +435,15 @@ convert_from_linear (GtkCssColor *output,
gtk_css_color_init (output, GTK_CSS_COLOR_SPACE_SRGB, v);
break;
case GTK_CSS_COLOR_SPACE_XYZ:
gtk_linear_srgb_to_xyz (output->values[0],
output->values[1],
output->values[2],
&v[0], &v[1], &v[2]);
v[3] = output->values[3];
gtk_css_color_init (output, GTK_CSS_COLOR_SPACE_XYZ, v);
break;
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
case GTK_CSS_COLOR_SPACE_OKLAB:
case GTK_CSS_COLOR_SPACE_OKLCH:
@ -431,6 +466,7 @@ convert_from_rectangular (GtkCssColor *output,
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
case GTK_CSS_COLOR_SPACE_OKLAB:
case GTK_CSS_COLOR_SPACE_DISPLAY_P3:
case GTK_CSS_COLOR_SPACE_XYZ:
g_assert (output->color_space == dest);
break;
@ -598,6 +634,7 @@ apply_hue_interpolation (GtkCssColor *from,
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
case GTK_CSS_COLOR_SPACE_OKLAB:
case GTK_CSS_COLOR_SPACE_DISPLAY_P3:
case GTK_CSS_COLOR_SPACE_XYZ:
break;
case GTK_CSS_COLOR_SPACE_HSL:
@ -631,6 +668,7 @@ normalize_hue (GtkCssColor *color)
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
case GTK_CSS_COLOR_SPACE_OKLAB:
case GTK_CSS_COLOR_SPACE_DISPLAY_P3:
case GTK_CSS_COLOR_SPACE_XYZ:
break;
case GTK_CSS_COLOR_SPACE_HSL:
@ -669,6 +707,7 @@ premultiply (GtkCssColor *color)
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
case GTK_CSS_COLOR_SPACE_OKLAB:
case GTK_CSS_COLOR_SPACE_DISPLAY_P3:
case GTK_CSS_COLOR_SPACE_XYZ:
premultiply_component (color, 0);
premultiply_component (color, 1);
premultiply_component (color, 2);
@ -712,6 +751,7 @@ unpremultiply (GtkCssColor *color)
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
case GTK_CSS_COLOR_SPACE_OKLAB:
case GTK_CSS_COLOR_SPACE_DISPLAY_P3:
case GTK_CSS_COLOR_SPACE_XYZ:
unpremultiply_component (color, 0);
unpremultiply_component (color, 1);
unpremultiply_component (color, 2);
@ -749,6 +789,7 @@ collect_analogous_missing (const GtkCssColor *color,
{ -1, -1, -1, 0, -1, -1, 1, 2, 3 }, /* oklab */
{ -1, -1, -1, 0, 1, 2, -1, -1, 3 }, /* oklch */
{ 0, 1, 2, -1, -1, -1, -1, -1, 3 }, /* display-p3 */
{ 0, 1, 2, -1, -1, -1, -1, -1, 3 }, /* xyz */
};
int *src = analogous[color->color_space];
@ -960,6 +1001,9 @@ gtk_css_color_interpolation_method_print (GtkCssColorSpace in,
case GTK_CSS_COLOR_SPACE_DISPLAY_P3:
g_string_append (string, "display-p3");
break;
case GTK_CSS_COLOR_SPACE_XYZ:
g_string_append (string, "xyz");
break;
default:
g_assert_not_reached ();
}

View File

@ -32,6 +32,7 @@ typedef enum {
GTK_CSS_COLOR_SPACE_OKLAB,
GTK_CSS_COLOR_SPACE_OKLCH,
GTK_CSS_COLOR_SPACE_DISPLAY_P3,
GTK_CSS_COLOR_SPACE_XYZ,
} GtkCssColorSpace;
typedef struct

View File

@ -363,6 +363,12 @@ gtk_css_value_color_print (const GtkCssValue *value,
g_string_append (string, " display-p3");
break;
case GTK_CSS_COLOR_SPACE_XYZ:
g_string_append (string, "color(from ");
gtk_css_value_print (value->relative.origin, string);
g_string_append (string, " xyz");
break;
case GTK_CSS_COLOR_SPACE_HSL:
g_string_append (string, "hsl(from ");
gtk_css_value_print (value->relative.origin, string);
@ -1654,6 +1660,12 @@ parse_color_color_channel (GtkCssParser *parser,
return 1;
}
if (gtk_css_parser_try_ident (parser, "xyz"))
{
data->ctx.color_space = GTK_CSS_COLOR_SPACE_XYZ;
return 1;
}
gtk_css_parser_error_syntax (parser, "Invalid color space in color()");
return 0;