diff --git a/gtk/gtkhsla.c b/gdk/gdkhsla.c similarity index 93% rename from gtk/gtkhsla.c rename to gdk/gdkhsla.c index ad1298df70..1d51d26e40 100644 --- a/gtk/gtkhsla.c +++ b/gdk/gdkhsla.c @@ -17,12 +17,12 @@ #include "config.h" -#include "gtkhslaprivate.h" +#include "gdkhslaprivate.h" #include void -_gtk_hsla_init_from_rgba (GtkHSLA *hsla, +_gdk_hsla_init_from_rgba (GdkHSLA *hsla, const GdkRGBA *rgba) { float min; @@ -31,21 +31,21 @@ _gtk_hsla_init_from_rgba (GtkHSLA *hsla, float green; float blue; float delta; - + g_return_if_fail (hsla != NULL); g_return_if_fail (rgba != NULL); red = rgba->red; green = rgba->green; blue = rgba->blue; - + if (red > green) { if (red > blue) max = red; else max = blue; - + if (green < blue) min = green; else @@ -57,25 +57,25 @@ _gtk_hsla_init_from_rgba (GtkHSLA *hsla, max = green; else max = blue; - + if (red < blue) min = red; else min = blue; } - + hsla->lightness = (max + min) / 2; hsla->saturation = 0; hsla->hue = 0; hsla->alpha = rgba->alpha; - + if (max != min) { if (hsla->lightness <= 0.5) hsla->saturation = (max - min) / (max + min); else hsla->saturation = (max - min) / (2 - max - min); - + delta = max -min; if (red == max) hsla->hue = (green - blue) / delta; @@ -83,7 +83,7 @@ _gtk_hsla_init_from_rgba (GtkHSLA *hsla, hsla->hue = 2 + (blue - red) / delta; else if (blue == max) hsla->hue = 4 + (red - green) / delta; - + hsla->hue *= 60; if (hsla->hue < 0.0) hsla->hue += 360; @@ -92,22 +92,22 @@ _gtk_hsla_init_from_rgba (GtkHSLA *hsla, void _gdk_rgba_init_from_hsla (GdkRGBA *rgba, - const GtkHSLA *hsla) + const GdkHSLA *hsla) { float hue; float lightness; float saturation; float m1, m2; - + lightness = hsla->lightness; saturation = hsla->saturation; - + if (lightness <= 0.5) m2 = lightness * (1 + saturation); else m2 = lightness + saturation - lightness * saturation; m1 = 2 * lightness - m2; - + rgba->alpha = hsla->alpha; if (saturation == 0) @@ -123,7 +123,7 @@ _gdk_rgba_init_from_hsla (GdkRGBA *rgba, hue -= 360; while (hue < 0) hue += 360; - + if (hue < 60) rgba->red = m1 + (m2 - m1) * hue / 60; else if (hue < 180) @@ -132,13 +132,13 @@ _gdk_rgba_init_from_hsla (GdkRGBA *rgba, rgba->red = m1 + (m2 - m1) * (240 - hue) / 60; else rgba->red = m1; - + hue = hsla->hue; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; - + if (hue < 60) rgba->green = m1 + (m2 - m1) * hue / 60; else if (hue < 180) @@ -147,13 +147,13 @@ _gdk_rgba_init_from_hsla (GdkRGBA *rgba, rgba->green = m1 + (m2 - m1) * (240 - hue) / 60; else rgba->green = m1; - + hue = hsla->hue - 120; while (hue > 360) hue -= 360; while (hue < 0) hue += 360; - + if (hue < 60) rgba->blue = m1 + (m2 - m1) * hue / 60; else if (hue < 180) @@ -166,8 +166,8 @@ _gdk_rgba_init_from_hsla (GdkRGBA *rgba, } void -_gtk_hsla_shade (GtkHSLA *dest, - const GtkHSLA *src, +_gdk_hsla_shade (GdkHSLA *dest, + const GdkHSLA *src, float factor) { g_return_if_fail (dest != NULL); diff --git a/gtk/gtkhslaprivate.h b/gdk/gdkhslaprivate.h similarity index 80% rename from gtk/gtkhslaprivate.h rename to gdk/gdkhslaprivate.h index 304dcfb899..751ea28c67 100644 --- a/gtk/gtkhslaprivate.h +++ b/gdk/gdkhslaprivate.h @@ -22,23 +22,23 @@ G_BEGIN_DECLS -typedef struct _GtkHSLA GtkHSLA; +typedef struct _GdkHSLA GdkHSLA; -struct _GtkHSLA { +struct _GdkHSLA { float hue; float saturation; float lightness; float alpha; }; -void _gtk_hsla_init_from_rgba (GtkHSLA *hsla, +void _gdk_hsla_init_from_rgba (GdkHSLA *hsla, const GdkRGBA *rgba); /* Yes, I can name that function like this! */ void _gdk_rgba_init_from_hsla (GdkRGBA *rgba, - const GtkHSLA *hsla); + const GdkHSLA *hsla); -void _gtk_hsla_shade (GtkHSLA *dest, - const GtkHSLA *src, +void _gdk_hsla_shade (GdkHSLA *dest, + const GdkHSLA *src, float factor); G_END_DECLS diff --git a/gdk/gdkrgba.c b/gdk/gdkrgba.c index 18b7790ba1..251d86b0dd 100644 --- a/gdk/gdkrgba.c +++ b/gdk/gdkrgba.c @@ -30,6 +30,7 @@ #include #include +#include "gdkhslaprivate.h" G_DEFINE_BOXED_TYPE (GdkRGBA, gdk_rgba, gdk_rgba_copy, gdk_rgba_free) @@ -186,6 +187,7 @@ gdk_rgba_parse (GdkRGBA *rgba, const char *spec) { gboolean has_alpha; + gboolean is_hsl; double r, g, b, a; char *str = (char *) spec; char *p; @@ -196,11 +198,26 @@ gdk_rgba_parse (GdkRGBA *rgba, if (strncmp (str, "rgba", 4) == 0) { has_alpha = TRUE; + is_hsl = FALSE; str += 4; } else if (strncmp (str, "rgb", 3) == 0) { has_alpha = FALSE; + is_hsl = FALSE; + a = 1; + str += 3; + } + else if (strncmp (str, "hsla", 4) == 0) + { + has_alpha = TRUE; + is_hsl = TRUE; + str += 4; + } + else if (strncmp (str, "hsl", 3) == 0) + { + has_alpha = FALSE; + is_hsl = TRUE; a = 1; str += 3; } @@ -291,10 +308,22 @@ gdk_rgba_parse (GdkRGBA *rgba, if (rgba) { - rgba->red = CLAMP (r, 0, 1); - rgba->green = CLAMP (g, 0, 1); - rgba->blue = CLAMP (b, 0, 1); - rgba->alpha = CLAMP (a, 0, 1); + if (is_hsl) + { + GdkHSLA hsla; + hsla.hue = r * 255; + hsla.saturation = CLAMP (g, 0, 1); + hsla.lightness = CLAMP (b, 0, 1); + hsla.alpha = CLAMP (a, 0, 1); + _gdk_rgba_init_from_hsla (rgba, &hsla); + } + else + { + rgba->red = CLAMP (r, 0, 1); + rgba->green = CLAMP (g, 0, 1); + rgba->blue = CLAMP (b, 0, 1); + rgba->alpha = CLAMP (a, 0, 1); + } } return TRUE; @@ -462,6 +491,47 @@ parse_color_channel (GtkCssParser *parser, } } +static guint +parse_hsla_color_channel (GtkCssParser *parser, + guint arg, + gpointer data) +{ + GdkHSLA *hsla = data; + double dvalue; + + switch (arg) + { + case 0: + if (!gtk_css_parser_consume_number (parser, &dvalue)) + return 0; + hsla->hue = dvalue; + return 1; + + case 1: + if (!gtk_css_parser_consume_percentage (parser, &dvalue)) + return 0; + hsla->saturation = CLAMP (dvalue, 0.0, 100.0) / 100.0; + return 1; + + case 2: + if (!gtk_css_parser_consume_percentage (parser, &dvalue)) + return 0; + hsla->lightness = CLAMP (dvalue, 0.0, 100.0) / 100.0; + return 1; + + case 3: + if (!gtk_css_parser_consume_number (parser, &dvalue)) + return 0; + + hsla->alpha = CLAMP (dvalue, 0.0, 1.0) / 1.0; + return 1; + + default: + g_assert_not_reached (); + return 0; + } +} + static gboolean rgba_init_chars (GdkRGBA *rgba, const char s[8]) @@ -501,6 +571,18 @@ gdk_rgba_parser_parse (GtkCssParser *parser, { return gtk_css_parser_consume_function (parser, 4, 4, parse_color_channel, rgba); } + else if (gtk_css_token_is_function (token, "hsl") || gtk_css_token_is_function (token, "hsla")) + { + GdkHSLA hsla; + + hsla.alpha = 1.0; + + if (!gtk_css_parser_consume_function (parser, 3, 4, parse_hsla_color_channel, &hsla)) + return FALSE; + + _gdk_rgba_init_from_hsla (rgba, &hsla); + return TRUE; + } else if (gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID) || gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_UNRESTRICTED)) { diff --git a/gdk/meson.build b/gdk/meson.build index db64565c2c..ccc1738eab 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -27,6 +27,7 @@ gdk_public_sources = files([ 'gdkglcontext.c', 'gdkglobals.c', 'gdkgltexture.c', + 'gdkhsla.c', 'gdkkeys.c', 'gdkkeyuni.c', 'gdkmemorytexture.c', @@ -107,6 +108,7 @@ gdk_sources = gdk_public_sources gdk_private_h_sources = files([ 'gdkeventsprivate.h', 'gdkdevicetoolprivate.h', + 'gdkhslaprivate.h', 'gdkmonitorprivate.h', 'gdkseatdefaultprivate.h', 'gdktoplevelsizeprivate.h', diff --git a/gtk/gtkcsscolorvalue.c b/gtk/gtkcsscolorvalue.c index cbd8988c01..5430489401 100644 --- a/gtk/gtkcsscolorvalue.c +++ b/gtk/gtkcsscolorvalue.c @@ -20,10 +20,10 @@ #include "gtkcsscolorvalueprivate.h" #include "gtkcssstylepropertyprivate.h" -#include "gtkhslaprivate.h" #include "gtkprivate.h" #include "gtkstylepropertyprivate.h" +#include "gdk/gdkhslaprivate.h" #include "gdk/gdkrgbaprivate.h" typedef enum { @@ -309,10 +309,10 @@ apply_shade (const GdkRGBA *in, GdkRGBA *out, double factor) { - GtkHSLA hsla; + GdkHSLA hsla; - _gtk_hsla_init_from_rgba (&hsla, in); - _gtk_hsla_shade (&hsla, &hsla, factor); + _gdk_hsla_init_from_rgba (&hsla, in); + _gdk_hsla_shade (&hsla, &hsla, factor); _gdk_rgba_init_from_hsla (out, &hsla); } @@ -699,6 +699,8 @@ gtk_css_color_value_can_parse (GtkCssParser *parser) || gtk_css_parser_has_function (parser, "shade") || gtk_css_parser_has_function (parser, "alpha") || gtk_css_parser_has_function (parser, "mix") + || gtk_css_parser_has_function (parser, "hsl") + || gtk_css_parser_has_function (parser, "hsla") || gtk_css_parser_has_function (parser, "rgb") || gtk_css_parser_has_function (parser, "rgba"); } diff --git a/gtk/gtkrenderborder.c b/gtk/gtkrenderborder.c index 3031f26a6b..c9415c4ebf 100644 --- a/gtk/gtkrenderborder.c +++ b/gtk/gtkrenderborder.c @@ -33,10 +33,10 @@ #include "gtkcssrepeatvalueprivate.h" #include "gtkcsscolorvalueprivate.h" #include "gtkcssstyleprivate.h" -#include "gtkhslaprivate.h" #include "gtkroundedboxprivate.h" #include "gtksnapshotprivate.h" +#include "gdk/gdkhslaprivate.h" #include "gsk/gskroundedrectprivate.h" typedef struct _GtkBorderImage GtkBorderImage; @@ -513,10 +513,10 @@ color_shade (const GdkRGBA *color, double factor, GdkRGBA *color_return) { - GtkHSLA hsla; + GdkHSLA hsla; - _gtk_hsla_init_from_rgba (&hsla, color); - _gtk_hsla_shade (&hsla, &hsla, factor); + _gdk_hsla_init_from_rgba (&hsla, color); + _gdk_hsla_shade (&hsla, &hsla, factor); _gdk_rgba_init_from_hsla (color_return, &hsla); } diff --git a/gtk/meson.build b/gtk/meson.build index 21b7bb8b29..bc097fdd6f 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -111,7 +111,6 @@ gtk_private_sources = files([ 'gtkfilechooserutils.c', 'gtkfilesystemmodel.c', 'gtkgizmo.c', - 'gtkhsla.c', 'gtkiconcache.c', 'gtkiconcachevalidator.c', 'gtkiconhelper.c', diff --git a/testsuite/css/parser/hsl.css b/testsuite/css/parser/hsl.css new file mode 100644 index 0000000000..2423137eed --- /dev/null +++ b/testsuite/css/parser/hsl.css @@ -0,0 +1,23 @@ +a { + color: hsl(0, 0%, 0%); +} + +b { + color: hsl(120, 100%, 50%); +} + +c { + color: hsl(360, 100%, 50%); +} + +d { + color: hsl(-314.159, 50%, 50%); +} + +e { + color: hsl(0, 0%, 0%, 0.5); +} + +f { + color: hsl(1, 2, 3); +} diff --git a/testsuite/css/parser/hsl.errors b/testsuite/css/parser/hsl.errors new file mode 100644 index 0000000000..e51e4704ba --- /dev/null +++ b/testsuite/css/parser/hsl.errors @@ -0,0 +1 @@ +hsl.css:22:17-18: error: GTK_CSS_PARSER_ERROR_SYNTAX diff --git a/testsuite/css/parser/hsl.ref.css b/testsuite/css/parser/hsl.ref.css new file mode 100644 index 0000000000..6f5c60dc1e --- /dev/null +++ b/testsuite/css/parser/hsl.ref.css @@ -0,0 +1,19 @@ +a { + color: rgb(0,0,0); +} + +b { + color: rgb(0,255,0); +} + +c { + color: rgb(255,0,0); +} + +d { + color: rgb(191,161,64); +} + +e { + color: rgba(0,0,0,0.5); +} diff --git a/testsuite/css/parser/meson.build b/testsuite/css/parser/meson.build index 9f5dd0673f..07f2ca4a73 100644 --- a/testsuite/css/parser/meson.build +++ b/testsuite/css/parser/meson.build @@ -358,6 +358,9 @@ test_data = [ 'freed-string-in-error-messages.css', 'freed-string-in-error-messages.errors', 'freed-string-in-error-messages.ref.css', + 'hsl.css', + 'hsl.errors', + 'hsl.ref.css', 'import-cyclic-1.css', 'import-cyclic-1.errors', 'import-cyclic-1.ref.css', diff --git a/testsuite/gdk/rgba.c b/testsuite/gdk/rgba.c index 0ab68f429d..e6f691ed77 100644 --- a/testsuite/gdk/rgba.c +++ b/testsuite/gdk/rgba.c @@ -65,6 +65,30 @@ test_color_parse (void) res = gdk_rgba_parse (&color, "#0080ff88"); g_assert_true (res); g_assert_true (gdk_rgba_equal (&color, &expected)); + + expected.red = 1.0; + expected.green = 0.0; + expected.blue = 0.0; + expected.alpha = 1.0; + res = gdk_rgba_parse (&color, "hsl (0, 100%, 50%)"); + g_assert_true (res); + g_assert_true (gdk_rgba_equal (&color, &expected)); + + expected.red = 0.0; + expected.green = 1.0; + expected.blue = 0.0; + expected.alpha = 0.1; + res = gdk_rgba_parse (&color, "hsla (120, 255, 50%, 0.1)"); + g_assert_true (res); + g_assert_true (gdk_rgba_equal (&color, &expected)); + + expected.red = 0.0; + expected.green = 0.5; + expected.blue = 0.5; + expected.alpha = 1.0; + res = gdk_rgba_parse (&color, "hsl(180, 100%, 25%)"); + g_assert_true (res); + g_assert_true (gdk_rgba_equal (&color, &expected)); } static void