[gtk: 1/2] gdk_rgba_parse: Support HSL colors




commit 0782c8a051831889cdfe0f85239d41c101d42234
Author: James Westman <james jwestman net>
Date:   Sat Aug 28 21:08:47 2021 -0500

    gdk_rgba_parse: Support HSL colors

 gtk/gtkhsla.c => gdk/gdkhsla.c               | 42 ++++++-------
 gtk/gtkhslaprivate.h => gdk/gdkhslaprivate.h | 12 ++--
 gdk/gdkrgba.c                                | 90 ++++++++++++++++++++++++++--
 gdk/meson.build                              |  2 +
 gtk/gtkcsscolorvalue.c                       | 10 ++--
 gtk/gtkrenderborder.c                        |  8 +--
 gtk/meson.build                              |  1 -
 testsuite/css/parser/hsl.css                 | 23 +++++++
 testsuite/css/parser/hsl.errors              |  1 +
 testsuite/css/parser/hsl.ref.css             | 19 ++++++
 testsuite/css/parser/meson.build             |  3 +
 testsuite/gdk/rgba.c                         | 24 ++++++++
 12 files changed, 195 insertions(+), 40 deletions(-)
---
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 <math.h>
 
 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 <errno.h>
 #include <math.h>
 
+#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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]