Merge branch 'color-fixes' into 'main'

Fix oklch conversion

See merge request GNOME/gtk!7324
This commit is contained in:
Matthias Clasen
2024-06-01 01:42:45 +00:00
11 changed files with 432 additions and 131 deletions

View File

@@ -396,10 +396,18 @@ gboolean
*/
char *
gdk_rgba_to_string (const GdkRGBA *rgba)
{
return g_string_free (gdk_rgba_print (rgba, g_string_new ("")), FALSE);
}
GString *
gdk_rgba_print (const GdkRGBA *rgba,
GString *string)
{
if (rgba->alpha > 0.999)
{
return g_strdup_printf ("rgb(%d,%d,%d)",
g_string_append_printf (string,
"rgb(%d,%d,%d)",
(int)(0.5 + CLAMP (rgba->red, 0., 1.) * 255.),
(int)(0.5 + CLAMP (rgba->green, 0., 1.) * 255.),
(int)(0.5 + CLAMP (rgba->blue, 0., 1.) * 255.));
@@ -410,12 +418,15 @@ gdk_rgba_to_string (const GdkRGBA *rgba)
g_ascii_formatd (alpha, G_ASCII_DTOSTR_BUF_SIZE, "%g", CLAMP (rgba->alpha, 0, 1));
return g_strdup_printf ("rgba(%d,%d,%d,%s)",
g_string_append_printf (string,
"rgba(%d,%d,%d,%s)",
(int)(0.5 + CLAMP (rgba->red, 0., 1.) * 255.),
(int)(0.5 + CLAMP (rgba->green, 0., 1.) * 255.),
(int)(0.5 + CLAMP (rgba->blue, 0., 1.) * 255.),
alpha);
}
return string;
}
static gboolean

View File

@@ -72,5 +72,8 @@ _gdk_rgba_equal (gconstpointer p1,
rgba1->alpha == rgba2->alpha;
}
GString * gdk_rgba_print (const GdkRGBA *rgba,
GString *string);
G_END_DECLS

View File

@@ -3232,17 +3232,6 @@ append_rounded_rect (GString *str,
}
}
static void
append_rgba (GString *str,
const GdkRGBA *rgba)
{
char *rgba_str = gdk_rgba_to_string (rgba);
g_string_append (str, rgba_str);
g_free (rgba_str);
}
static void
append_point (GString *str,
const graphene_point_t *p)
@@ -3288,7 +3277,7 @@ append_rgba_param (Printer *p,
{
_indent (p);
g_string_append_printf (p->str, "%s: ", param_name);
append_rgba (p->str, value);
gdk_rgba_print (value, p->str);
g_string_append_c (p->str, ';');
g_string_append_c (p->str, '\n');
}
@@ -3442,7 +3431,7 @@ append_stops_param (Printer *p,
string_append_double (p->str, stops[i].offset);
g_string_append_c (p->str, ' ');
append_rgba (p->str, &stops[i].color);
gdk_rgba_print (&stops[i].color, p->str);
}
g_string_append (p->str, ";\n");
}
@@ -4068,7 +4057,7 @@ render_node_print (Printer *p,
{
if (i > 0)
g_string_append_c (p->str, ' ');
append_rgba (p->str, &colors[i]);
gdk_rgba_print (&colors[i], p->str);
}
g_string_append (p->str, ";\n");
}

View File

@@ -301,13 +301,29 @@ gtk_hwb_to_rgb (float hue, float white, float black,
#define DEG_TO_RAD(x) ((x) * G_PI / 180)
#define RAD_TO_DEG(x) ((x) * 180 / G_PI)
static inline void
_sincosf (float angle,
float *out_s,
float *out_c)
{
#ifdef HAVE_SINCOSF
sincosf (angle, out_s, out_c);
#else
*out_s = sinf (angle);
*out_c = cosf (angle);
#endif
}
void
gtk_oklab_to_oklch (float L, float a, float b,
float *L2, float *C, float *H)
{
*L2 = L;
*C = sqrtf (a * a + b * b);
*H = atan2 (b, a);
*C = hypotf (a, b);
*H = RAD_TO_DEG (atan2 (b, a));
*H = fmod (*H, 360);
if (*H < 0)
*H += 360;
}
void
@@ -315,16 +331,9 @@ gtk_oklch_to_oklab (float L, float C, float H,
float *L2, float *a, float *b)
{
*L2 = L;
if (H == 0)
{
*a = *b = 0;
}
else
{
*a = C * cosf (DEG_TO_RAD (H));
*b = C * sinf (DEG_TO_RAD (H));
}
_sincosf (DEG_TO_RAD (H), b, a);
*a *= C;
*b *= C;
}
static float

View File

@@ -59,6 +59,104 @@ gtk_css_color_init (GtkCssColor *color,
gtk_css_color_init_with_missing (color, color_space, values, missing);
}
/* }}} */
/* {{{ Utilities */
static inline void
append_color_component (GString *string,
const GtkCssColor *color,
guint idx)
{
if (gtk_css_color_component_missing (color, idx))
g_string_append (string, "none");
else
g_string_append_printf (string, "%g", gtk_css_color_get_component (color, idx));
}
GString *
gtk_css_color_print (const GtkCssColor *color,
gboolean serialize_as_rgb,
GString *string)
{
switch (color->color_space)
{
case GTK_CSS_COLOR_SPACE_HSL:
case GTK_CSS_COLOR_SPACE_HWB:
print_rgb:
{
GtkCssColor tmp;
gtk_css_color_convert (color, GTK_CSS_COLOR_SPACE_SRGB, &tmp);
if (tmp.values[3] > 0.999)
{
g_string_append_printf (string, "rgb(%d,%d,%d)",
(int)(0.5 + CLAMP (tmp.values[0], 0., 1.) * 255.),
(int)(0.5 + CLAMP (tmp.values[1], 0., 1.) * 255.),
(int)(0.5 + CLAMP (tmp.values[2], 0., 1.) * 255.));
}
else
{
char alpha[G_ASCII_DTOSTR_BUF_SIZE];
g_ascii_formatd (alpha, G_ASCII_DTOSTR_BUF_SIZE, "%g", CLAMP (tmp.values[3], 0, 1));
g_string_append_printf (string, "rgba(%d,%d,%d,%s)",
(int)(0.5 + CLAMP (tmp.values[0], 0., 1.) * 255.),
(int)(0.5 + CLAMP (tmp.values[1], 0., 1.) * 255.),
(int)(0.5 + CLAMP (tmp.values[2], 0., 1.) * 255.),
alpha);
}
}
return string;
case GTK_CSS_COLOR_SPACE_SRGB:
if (serialize_as_rgb)
goto print_rgb;
g_string_append (string, "color(srgb ");
break;
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
g_string_append (string, "color(srgb-linear ");
break;
case GTK_CSS_COLOR_SPACE_OKLAB:
g_string_append (string, "oklab(");
break;
case GTK_CSS_COLOR_SPACE_OKLCH:
g_string_append (string, "oklch(");
break;
default:
g_assert_not_reached ();
}
for (guint i = 0; i < 3; i++)
{
if (i > 0)
g_string_append_c (string, ' ');
append_color_component (string, color, i);
}
if (gtk_css_color_component_missing (color, 3) ||
color->values[3] < 0.999)
{
g_string_append (string, " / ");
append_color_component (string, color, 3);
}
g_string_append_c (string, ')');
return string;
}
char *
gtk_css_color_to_string (const GtkCssColor *color)
{
return g_string_free (gtk_css_color_print (color, FALSE, g_string_new ("")), FALSE);
}
/* }}} */
/* {{{ Color conversion */
@@ -66,6 +164,7 @@ static void
convert_to_rectangular (GtkCssColor *output)
{
float v[4];
gboolean no_missing[4] = { 0, };
switch (output->color_space)
{
@@ -80,7 +179,7 @@ convert_to_rectangular (GtkCssColor *output)
output->values[2] / 100,
&v[0], &v[1], &v[2]);
v[3] = output->values[3];
gtk_css_color_init (output, GTK_CSS_COLOR_SPACE_SRGB, v);
gtk_css_color_init_with_missing (output, GTK_CSS_COLOR_SPACE_SRGB, v, no_missing);
break;
case GTK_CSS_COLOR_SPACE_HWB:
@@ -89,16 +188,16 @@ convert_to_rectangular (GtkCssColor *output)
output->values[2] / 100,
&v[0], &v[1], &v[2]);
v[3] = output->values[3];
gtk_css_color_init (output, GTK_CSS_COLOR_SPACE_SRGB, v);
gtk_css_color_init_with_missing (output, GTK_CSS_COLOR_SPACE_SRGB, v, no_missing);
break;
case GTK_CSS_COLOR_SPACE_OKLCH:
gtk_oklch_to_oklab (output->values[0],
output->values[1] / 100,
output->values[2] / 100,
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_OKLAB, v);
gtk_css_color_init_with_missing (output, GTK_CSS_COLOR_SPACE_OKLAB, v, no_missing);
break;
default:
@@ -238,7 +337,7 @@ convert_linear_to_linear (GtkCssColor *output,
gtk_css_color_init (output, dest_linear, v);
}
else if (dest_linear == GTK_CSS_COLOR_SPACE_OKLAB &&
output->color_space == GTK_CSS_COLOR_SPACE_SRGB_LINEAR)
output->color_space == GTK_CSS_COLOR_SPACE_SRGB_LINEAR)
{
gtk_linear_srgb_to_oklab (output->values[0],
output->values[1],
@@ -472,15 +571,15 @@ collect_analogous_missing (const GtkCssColor *color,
gboolean missing[4])
{
/* Coords for red, green, blue, lightness, colorfulness, hue,
* opposite a, opposite b, for each of our colorspaces
* opposite a, opposite b, alpha, for each of our colorspaces,
*/
static int analogous[][8] = {
{ 0, 1, 2, -1, -1, -1, -1, -1 }, /* srgb */
{ 0, 1, 2, -1, -1, -1, -1, -1 }, /* srgb-linear */
{ -1, -1, -1, 2, 1, 0, -1, -1 }, /* hsl */
{ -1, -1, -1, -1, -1, 0, -1, -1 }, /* hwb */
{ -1, -1, -1, 0, -1, -1, 1, 2 }, /* oklab */
{ -1, -1, -1, 0, 1, 2, -1, -1 }, /* oklch */
static int analogous[][9] = {
{ 0, 1, 2, -1, -1, -1, -1, -1, 3 }, /* srgb */
{ 0, 1, 2, -1, -1, -1, -1, -1, 3 }, /* srgb-linear */
{ -1, -1, -1, 2, 1, 0, -1, -1, 3 }, /* hsl */
{ -1, -1, -1, -1, -1, 0, -1, -1, 3 }, /* hwb */
{ -1, -1, -1, 0, -1, -1, 1, 2, 3 }, /* oklab */
{ -1, -1, -1, 0, 1, 2, -1, -1, 3 }, /* oklch */
};
@@ -495,7 +594,7 @@ collect_analogous_missing (const GtkCssColor *color,
if ((color->missing & (1 << i)) == 0)
continue;
for (guint j = 0; j < 8; j++)
for (guint j = 0; j < 9; j++)
{
if (src[j] == i)
{
@@ -537,13 +636,16 @@ gtk_css_color_interpolate (const GtkCssColor *from,
gboolean m2 = to_missing[i];
if (m1 && !m2)
from1.values[i] = to1.values[1];
from1.values[i] = to1.values[i];
else if (!m1 && m2)
to1.values[i] = from1.values[1];
to1.values[i] = from1.values[i];
missing[i] = from_missing[i] && to_missing[i];
}
from1.missing = 0;
to1.missing = 0;
apply_hue_interpolation (&from1, &to1, in, interp);
premultiply (&from1);

View File

@@ -84,6 +84,12 @@ void gtk_css_color_init (GtkCssColor *color,
GtkCssColorSpace color_space,
const float values[4]);
GString * gtk_css_color_print (const GtkCssColor *color,
gboolean serialize_as_rgb,
GString *string);
char * gtk_css_color_to_string (const GtkCssColor *color);
void gtk_css_color_convert (const GtkCssColor *input,
GtkCssColorSpace dest,
GtkCssColor *output);

View File

@@ -267,83 +267,11 @@ gtk_css_value_color_print (const GtkCssValue *value,
switch (value->type)
{
case COLOR_TYPE_LITERAL:
{
char *s = gdk_rgba_to_string (&value->rgba);
g_string_append (string, s);
g_free (s);
}
gdk_rgba_print (&value->rgba, string);
break;
case COLOR_TYPE_COLOR:
switch (value->color.color_space)
{
case GTK_CSS_COLOR_SPACE_HSL:
case GTK_CSS_COLOR_SPACE_HWB:
print_rgb:
{
GtkCssColor tmp;
gtk_css_color_convert (&value->color, GTK_CSS_COLOR_SPACE_SRGB, &tmp);
if (tmp.values[3] > 0.999)
{
g_string_append_printf (string, "rgb(%d,%d,%d)",
(int)(0.5 + CLAMP (tmp.values[0], 0., 1.) * 255.),
(int)(0.5 + CLAMP (tmp.values[1], 0., 1.) * 255.),
(int)(0.5 + CLAMP (tmp.values[2], 0., 1.) * 255.));
}
else
{
char alpha[G_ASCII_DTOSTR_BUF_SIZE];
g_ascii_formatd (alpha, G_ASCII_DTOSTR_BUF_SIZE, "%g", CLAMP (tmp.values[3], 0, 1));
g_string_append_printf (string, "rgba(%d,%d,%d,%s)",
(int)(0.5 + CLAMP (tmp.values[0], 0., 1.) * 255.),
(int)(0.5 + CLAMP (tmp.values[1], 0., 1.) * 255.),
(int)(0.5 + CLAMP (tmp.values[2], 0., 1.) * 255.),
alpha);
}
}
return;
case GTK_CSS_COLOR_SPACE_SRGB:
if (value->serialize_as_rgb)
goto print_rgb;
g_string_append (string, "color(srgb ");
break;
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
g_string_append (string, "color(srgb-linear ");
break;
case GTK_CSS_COLOR_SPACE_OKLAB:
g_string_append (string, "oklab(");
break;
case GTK_CSS_COLOR_SPACE_OKLCH:
g_string_append (string, "oklch(");
break;
default:
g_assert_not_reached ();
}
for (guint i = 0; i < 3; i++)
{
if (i > 0)
g_string_append_c (string, ' ');
append_color_component (string, &value->color, i);
}
if (gtk_css_color_component_missing (&value->color, 3) ||
gtk_css_color_get_component (&value->color, 3) < 0.999)
{
g_string_append (string, " / ");
append_color_component (string, &value->color, 3);
}
g_string_append_c (string, ')');
gtk_css_color_print (&value->color, value->serialize_as_rgb, string);
break;
case COLOR_TYPE_NAME:
@@ -608,10 +536,10 @@ gtk_css_color_value_new_literal (const GdkRGBA *color)
return value;
}
static GtkCssValue *
GtkCssValue *
gtk_css_color_value_new_color (GtkCssColorSpace color_space,
gboolean serialize_as_rgb,
float values[4],
const float values[4],
gboolean missing[4])
{
GtkCssValue *value;
@@ -1085,7 +1013,7 @@ parse_ok_C_value (GtkCssParser *parser,
if (val == NULL)
return FALSE;
*value = gtk_css_number_value_get_canonical (val, 1);
*value = gtk_css_number_value_get_canonical (val, 0.4);
*value = MAX (*value, 0.0);
gtk_css_value_unref (val);
@@ -1633,3 +1561,12 @@ gtk_css_color_value_get_rgba (const GtkCssValue *color)
return &color->rgba;
}
const GtkCssColor *
gtk_css_color_value_get_color (const GtkCssValue *color)
{
g_assert (color->class == &GTK_CSS_VALUE_COLOR);
g_assert (color->type == COLOR_TYPE_COLOR);
return &color->color;
}

View File

@@ -21,6 +21,7 @@
#include "gtk/css/gtkcsstokenizerprivate.h"
#include "gtk/css/gtkcssparserprivate.h"
#include "gtkcssvalueprivate.h"
#include "gtkcsscolorprivate.h"
G_BEGIN_DECLS
@@ -37,6 +38,14 @@ GtkCssValue * gtk_css_color_value_resolve (GtkCssValue *color
GtkCssValue *current);
const GdkRGBA * gtk_css_color_value_get_rgba (const GtkCssValue *color) G_GNUC_CONST;
GtkCssValue * gtk_css_color_value_new_color (GtkCssColorSpace color_space,
gboolean serialize_as_rgb,
const float values[4],
gboolean missing[4]) G_GNUC_PURE;
const GtkCssColor *
gtk_css_color_value_get_color (const GtkCssValue *color) G_GNUC_CONST;
G_END_DECLS

View File

@@ -55,6 +55,7 @@
#include <gdk/gdksubsurfaceprivate.h>
#include <gdk/gdksurfaceprivate.h>
#include <gdk/gdktextureprivate.h>
#include <gdk/gdkrgbaprivate.h>
#include "gtk/gtkdebug.h"
#include "gtk/gtkbuiltiniconprivate.h"
#include "gtk/gtkrendernodepaintableprivate.h"
@@ -1083,9 +1084,9 @@ populate_render_node_properties (GListStore *store,
s = g_string_new ("");
for (i = 0; i < n_stops; i++)
{
char *tmp = gdk_rgba_to_string (&stops[i].color);
g_string_append_printf (s, "%.2f, %s\n", stops[i].offset, tmp);
g_free (tmp);
g_string_append_printf (s, "%.2f, ", stops[i].offset);
gdk_rgba_print (&stops[i].color, s);
g_string_append_c (s, '\n');
}
texture = get_linear_gradient_texture (n_stops, stops);
@@ -1117,9 +1118,9 @@ populate_render_node_properties (GListStore *store,
s = g_string_new ("");
for (i = 0; i < n_stops; i++)
{
char *tmp = gdk_rgba_to_string (&stops[i].color);
g_string_append_printf (s, "%.2f, %s\n", stops[i].offset, tmp);
g_free (tmp);
g_string_append_printf (s, "%.2f, ", stops[i].offset);
gdk_rgba_print (&stops[i].color, s);
g_string_append_c (s, '\n');
}
texture = get_linear_gradient_texture (n_stops, stops);
@@ -1146,9 +1147,9 @@ populate_render_node_properties (GListStore *store,
s = g_string_new ("");
for (i = 0; i < n_stops; i++)
{
char *tmp = gdk_rgba_to_string (&stops[i].color);
g_string_append_printf (s, "%.2f, %s\n", stops[i].offset, tmp);
g_free (tmp);
g_string_append_printf (s, "%.2f, ", stops[i].offset);
gdk_rgba_print (&stops[i].color, s);
g_string_append_c (s, '\n');
}
texture = get_linear_gradient_texture (n_stops, stops);

222
testsuite/css/color.c Normal file
View File

@@ -0,0 +1,222 @@
/*
* Copyright (C) 2024 Red Hat Inc.
*
* Author:
* Matthias Clasen <mclasen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gtk/gtkcssvalueprivate.h"
#include "gtk/gtkcsscolorprivate.h"
#include "gtk/gtkcsscolorvalueprivate.h"
#include "gtk/gtkcssstylepropertyprivate.h"
#include "gtk/gtkcssstaticstyleprivate.h"
#define EPSILON 0.001
static gboolean
color_is_near (const GtkCssColor *color1,
const GtkCssColor *color2)
{
return color1->color_space == color2->color_space &&
color1->missing == color2->missing &&
fabs (color1->values[0] - color2->values[0]) <= EPSILON &&
fabs (color1->values[1] - color2->values[1]) <= EPSILON &&
fabs (color1->values[2] - color2->values[2]) <= EPSILON &&
fabs (color1->values[3] - color2->values[3]) <= EPSILON;
}
static void
error_cb (GtkCssParser *parser,
const GtkCssLocation *start,
const GtkCssLocation *end,
const GError *error,
gpointer user_data)
{
*(GError **)user_data = g_error_copy (error);
}
static void
color_from_string (const char *str,
GtkCssColor *res)
{
GtkStyleProperty *prop;
GBytes *bytes;
GtkCssParser *parser;
GtkCssValue *value;
GError *error = NULL;
bytes = g_bytes_new_static (str, strlen (str));
parser = gtk_css_parser_new_for_bytes (bytes, NULL, error_cb, &error, NULL);
prop = _gtk_style_property_lookup ("color");
value = _gtk_style_property_parse_value (prop, parser);
g_assert_nonnull (value);
g_assert_no_error (error);
gtk_css_parser_unref (parser);
g_bytes_unref (bytes);
gtk_css_color_init_from_color (res, gtk_css_color_value_get_color (value));
gtk_css_value_unref (value);
}
static void
print_css_color (const char *prefix,
const GtkCssColor *c)
{
GtkCssValue *v;
char *s;
v = gtk_css_color_value_new_color (c->color_space,
FALSE,
c->values,
(gboolean[4]) {
gtk_css_color_component_missing (c, 0),
gtk_css_color_component_missing (c, 1),
gtk_css_color_component_missing (c, 2),
gtk_css_color_component_missing (c, 3),
});
s = gtk_css_value_to_string (v);
g_print ("%s: %s\n", prefix, s);
g_free (s);
gtk_css_value_unref (v);
}
/* Tests for css color conversions */
typedef struct {
const char *input;
GtkCssColorSpace dest;
const char *expected;
} ColorConversionTest;
static ColorConversionTest conversion_tests[] = {
{ "rgb(255,0,0)", GTK_CSS_COLOR_SPACE_SRGB_LINEAR, "color(srgb-linear 1 0 0)" },
{ "color(srgb 0.5 none 1 / 0.7)", GTK_CSS_COLOR_SPACE_SRGB_LINEAR, "color(srgb-linear 0.214041 0 1 / 0.7)" },
{ "rgb(100,100,100)", GTK_CSS_COLOR_SPACE_HSL, "hsla(0deg 0 39.215687 / 1)" },
/* the following are from color-4, Example 26 */
{ "oklch(40.101% 0.12332 21.555)", GTK_CSS_COLOR_SPACE_SRGB, "rgb(49.06% 13.87% 15.9%)" },
{ "oklch(59.686% 0.15619 49.7694)", GTK_CSS_COLOR_SPACE_SRGB, "rgb(77.61% 36.34% 2.45%)" },
{ "oklch(0.65125 0.13138 104.097)", GTK_CSS_COLOR_SPACE_SRGB, "rgb(61.65% 57.51% 9.28%)" },
{ "oklch(0.66016 0.15546 134.231)", GTK_CSS_COLOR_SPACE_SRGB, "rgb(40.73% 65.12% 22.35%)" },
{ "oklch(72.322% 0.12403 247.996)", GTK_CSS_COLOR_SPACE_SRGB, "rgb(38.29% 67.27% 93.85%)" },
{ "oklch(42.1% 48.25% 328.4)", GTK_CSS_COLOR_SPACE_SRGB, "color(srgb 0.501808 0.00257216 0.501403)" },
/* more random tests */
{ "oklch(0.392 0.4 none)", GTK_CSS_COLOR_SPACE_OKLCH, "oklch(0.392 0.4 0)" },
};
static void
test_conversion (gconstpointer data)
{
ColorConversionTest *test = &conversion_tests[GPOINTER_TO_INT (data)];
GtkCssColor input;
GtkCssColor expected;
GtkCssColor result;
color_from_string (test->input, &input);
color_from_string (test->expected, &expected);
gtk_css_color_convert (&input, test->dest, &result);
if (g_test_verbose ())
{
print_css_color ("expected", &expected);
print_css_color ("converted", &result);
}
g_assert_true (color_is_near (&result, &expected));
}
/* Tests for css color interpolation */
typedef struct {
const char *input1;
const char *input2;
float progress;
GtkCssColorSpace in;
GtkCssHueInterpolation interp;
const char *expected;
} ColorInterpolationTest;
static ColorInterpolationTest interpolation_tests[] = {
/* color-4, example 33 */
{ "oklch(78.3% 0.108 326.5)", "oklch(39.2% 0.4 none)", 0.5, GTK_CSS_COLOR_SPACE_OKLCH, GTK_CSS_HUE_INTERPOLATION_SHORTER, "oklch(58.75% 0.254 326.5)" },
/* color-4, example 34 */
{ "oklch(0.783 0.108 326.5 / 0.5)", "oklch(0.392 0.4 0 / none)", 0.5, GTK_CSS_COLOR_SPACE_OKLCH, GTK_CSS_HUE_INTERPOLATION_SHORTER, "oklch(0.5875 0.254 343.25 / 0.5)" },
/* color-4, example 35 */
{ "rgb(24% 12% 98% / 0.4)", "rgb(62% 26% 64% / 0.6)", 0.5, GTK_CSS_COLOR_SPACE_SRGB, GTK_CSS_HUE_INTERPOLATION_SHORTER, "rgb(46.8% 20.4% 77.6% / 0.5)" },
/* color-4, example 38 */
{ "oklch(0.6 0.24 30)", "oklch(0.8 0.15 90)", 0.5, GTK_CSS_COLOR_SPACE_OKLCH, GTK_CSS_HUE_INTERPOLATION_SHORTER, "oklch(0.7 0.195 60)" },
/* color-4, example 39 */
{ "oklch(0.6 0.24 30)", "oklch(0.8 0.15 90)", 0.5, GTK_CSS_COLOR_SPACE_OKLCH, GTK_CSS_HUE_INTERPOLATION_LONGER, "oklch(0.7 0.195 240)" },
};
static void
test_interpolation (gconstpointer data)
{
ColorInterpolationTest *test = &interpolation_tests[GPOINTER_TO_INT (data)];
GtkCssColor input1;
GtkCssColor input2;
GtkCssColor expected;
GtkCssColor result;
color_from_string (test->input1, &input1);
color_from_string (test->input2, &input2);
color_from_string (test->expected, &expected);
gtk_css_color_interpolate (&input1,
&input2,
test->progress,
test->in,
test->interp,
&result);
if (g_test_verbose ())
{
print_css_color ("expected", &expected);
print_css_color ("interpolated", &result);
}
g_assert_true (color_is_near (&result, &expected));
}
int
main (int argc, char **argv)
{
gtk_test_init (&argc, &argv);
for (int i = 0; i < G_N_ELEMENTS (conversion_tests); i++)
{
char *path;
path = g_strdup_printf ("/css/color/conversion/%d", i);
g_test_add_data_func (path, GINT_TO_POINTER (i), test_conversion);
g_free (path);
}
for (int i = 0; i < G_N_ELEMENTS (interpolation_tests); i++)
{
char *path;
path = g_strdup_printf ("/css/color/interpolation/%d", i);
g_test_add_data_func (path, GINT_TO_POINTER (i), test_interpolation);
g_free (path);
}
return g_test_run ();
}

View File

@@ -52,3 +52,15 @@ test('transition', transition,
suite: 'css'
)
color = executable('color',
sources: ['color.c'],
c_args: common_cflags + ['-DGTK_COMPILATION'],
dependencies: libgtk_static_dep,
)
test('color', color,
args: [ '--tap', '-k'],
protocol: 'tap',
env: csstest_env,
suite: 'css'
)