summaryrefslogtreecommitdiff
path: root/gdk/gdkrgba.c
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2019-04-06 02:40:29 +0200
committerBenjamin Otte <otte@redhat.com>2019-04-12 19:34:28 +0200
commit98e076b51ea05fae38d75514f0144b68ff4aabfd (patch)
tree447f978ed95bc07edd1be70fef124f6845a724fd /gdk/gdkrgba.c
parentf3db19d6948b6237c4011497f31a6f08e91f0a87 (diff)
downloadgtk+-98e076b51ea05fae38d75514f0144b68ff4aabfd.tar.gz
rgba: Add gdk_rgba_parser_parse()
This function is a (private) function to parse a GdkRGBA accoridng to the CSS specs. We should probably use it for gdk_rgba_parse(), but that would change the syntax we accept there... This also introduces a dependency of libgdk on libgtkcss. So far, no users for this function exist.
Diffstat (limited to 'gdk/gdkrgba.c')
-rw-r--r--gdk/gdkrgba.c184
1 files changed, 183 insertions, 1 deletions
diff --git a/gdk/gdkrgba.c b/gdk/gdkrgba.c
index 8e36523dc2..b52e0254e6 100644
--- a/gdk/gdkrgba.c
+++ b/gdk/gdkrgba.c
@@ -23,7 +23,9 @@
*/
#include "config.h"
-#include "gdkrgba.h"
+
+#include "gdkrgbaprivate.h"
+
#include <string.h>
#include <errno.h>
#include <math.h>
@@ -393,3 +395,183 @@ gdk_rgba_to_string (const GdkRGBA *rgba)
alpha);
}
}
+
+static gboolean
+parse_color_channel_value (GtkCssParser *parser,
+ double *value,
+ gboolean is_percentage)
+{
+ if (is_percentage)
+ {
+ if (!gtk_css_parser_consume_percentage (parser, value))
+ return FALSE;
+
+ *value = CLAMP (*value, 0.0, 100.0) / 100.0;
+ return TRUE;
+ }
+ else
+ {
+ if (!gtk_css_parser_consume_number (parser, value))
+ return FALSE;
+
+ *value = CLAMP (*value, 0.0, 255.0) / 255.0;
+ return TRUE;
+ }
+}
+
+static guint
+parse_color_channel (GtkCssParser *parser,
+ guint arg,
+ gpointer data)
+{
+ GdkRGBA *rgba = data;
+
+ switch (arg)
+ {
+ case 0:
+ /* We abuse rgba->alpha to store if we use percentages or numbers */
+ if (gtk_css_token_is (gtk_css_parser_get_token (parser), GTK_CSS_TOKEN_PERCENTAGE))
+ rgba->alpha = 1.0;
+ else
+ rgba->alpha = 0.0;
+
+ if (!parse_color_channel_value (parser, &rgba->red, rgba->alpha != 0.0))
+ return 0;
+ return 1;
+
+ case 1:
+ if (!parse_color_channel_value (parser, &rgba->green, rgba->alpha != 0.0))
+ return 0;
+ return 1;
+
+ case 2:
+ if (!parse_color_channel_value (parser, &rgba->blue, rgba->alpha != 0.0))
+ return 0;
+ return 1;
+
+ case 3:
+ if (!gtk_css_parser_consume_number (parser, &rgba->alpha))
+ return 0;
+
+ rgba->alpha = CLAMP (rgba->alpha, 0.0, 1.0);
+ return 1;
+
+ default:
+ g_assert_not_reached ();
+ return 0;
+ }
+}
+
+static gboolean
+rgba_init_chars (GdkRGBA *rgba,
+ const char s[8])
+{
+ guint i;
+
+ for (i = 0; i < 8; i++)
+ {
+ if (!g_ascii_isxdigit (s[i]))
+ return FALSE;
+ }
+
+ rgba->red = (g_ascii_xdigit_value (s[0]) * 16 + g_ascii_xdigit_value (s[1])) / 255.0;
+ rgba->green = (g_ascii_xdigit_value (s[2]) * 16 + g_ascii_xdigit_value (s[3])) / 255.0;
+ rgba->blue = (g_ascii_xdigit_value (s[4]) * 16 + g_ascii_xdigit_value (s[5])) / 255.0;
+ rgba->alpha = (g_ascii_xdigit_value (s[6]) * 16 + g_ascii_xdigit_value (s[7])) / 255.0;
+
+ return TRUE;
+}
+
+gboolean
+gdk_rgba_parser_parse (GtkCssParser *parser,
+ GdkRGBA *rgba)
+{
+ const GtkCssToken *token;
+
+ token = gtk_css_parser_get_token (parser);
+ if (gtk_css_token_is_function (token, "rgb"))
+ {
+ if (!gtk_css_parser_consume_function (parser, 3, 3, parse_color_channel, rgba))
+ return FALSE;
+
+ rgba->alpha = 1.0;
+ return TRUE;
+ }
+ else if (gtk_css_token_is_function (token, "rgba"))
+ {
+ return gtk_css_parser_consume_function (parser, 4, 4, parse_color_channel, rgba);
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID) ||
+ gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_UNRESTRICTED))
+ {
+ const char *s = token->string.string;
+
+ switch (strlen (s))
+ {
+ case 3:
+ if (!rgba_init_chars (rgba, (char[8]) {s[0], s[0], s[1], s[1], s[2], s[2], 'F', 'F' }))
+ {
+ gtk_css_parser_error_value (parser, "Hash code is not a valid hex color.");
+ return FALSE;
+ }
+ break;
+
+ case 4:
+ if (!rgba_init_chars (rgba, (char[8]) {s[0], s[0], s[1], s[1], s[2], s[2], s[3], s[3] }))
+ {
+ gtk_css_parser_error_value (parser, "Hash code is not a valid hex color.");
+ return FALSE;
+ }
+ break;
+
+ case 6:
+ if (!rgba_init_chars (rgba, (char[8]) {s[0], s[1], s[2], s[3], s[4], s[5], 'F', 'F' }))
+ {
+ gtk_css_parser_error_value (parser, "Hash code is not a valid hex color.");
+ return FALSE;
+ }
+ break;
+
+ case 8:
+ if (!rgba_init_chars (rgba, s))
+ {
+ gtk_css_parser_error_value (parser, "Hash code is not a valid hex color.");
+ return FALSE;
+ }
+ break;
+
+ default:
+ gtk_css_parser_error_value (parser, "Hash code is not a valid hex color.");
+ return FALSE;
+ break;
+ }
+
+ gtk_css_parser_consume_token (parser);
+ return TRUE;
+ }
+ else if (gtk_css_token_is (token, GTK_CSS_TOKEN_IDENT))
+ {
+ if (gtk_css_token_is_ident (token, "transparent"))
+ {
+ *rgba = (GdkRGBA) { 0, 0, 0, 0 };
+ }
+ else if (gdk_rgba_parse (rgba, token->string.string))
+ {
+ /* everything's fine */
+ }
+ else
+ {
+ gtk_css_parser_error_syntax (parser, "\"%s\" is not a valid color name.", token->string.string);
+ return FALSE;
+ }
+
+ gtk_css_parser_consume_token (parser);
+ return TRUE;
+ }
+ else
+ {
+ gtk_css_parser_error_syntax (parser, "Expected a valid color.");
+ return FALSE;
+ }
+}
+