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.
This commit is contained in:
Benjamin Otte
2019-04-06 02:40:29 +02:00
parent f3db19d694
commit 98e076b51e
3 changed files with 219 additions and 3 deletions

View File

@@ -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;
}
}

33
gdk/gdkrgbaprivate.h Normal file
View File

@@ -0,0 +1,33 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2010, Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_RGBA_PRIVATE_H__
#define __GDK_RGBA_PRIVATE_H__
#include "gdkrgba.h"
#include <gtk/css/gtkcss.h>
#include "gtk/css/gtkcssparserprivate.h"
gboolean gdk_rgba_parser_parse (GtkCssParser *parser,
GdkRGBA *rgba);
G_END_DECLS
#endif

View File

@@ -224,7 +224,8 @@ endif
# FIXME: might have to add '-xobjective-c' to c_args for quartz backend?
libgdk = static_library('gdk',
sources: [gdk_sources, gdk_backends_gen_headers, gdkconfig],
dependencies: gdk_deps,
dependencies: gdk_deps + [libgtk_css_dep],
link_with: [libgtk_css, ],
include_directories: [confinc, gdkx11_inc, wlinc],
c_args: [
'-DGDK_COMPILATION',
@@ -239,4 +240,4 @@ libgdk = static_library('gdk',
libgdk_dep = declare_dependency(
sources: ['gdk.h', gdkconfig, gdkenum_h],
include_directories: [confinc, gdkx11_inc, wlinc],
dependencies: gdk_deps)
dependencies: gdk_deps + [libgtk_css_dep])