forked from AuroraMiddleware/gtk
Switch to CSS interpretation of rgb() and rgba() colors
CSS3 defines a somewhat odd syntax for rgba() colors - the rgb values are integers from 0 to 255 or percentages and the a value is a float from 0 to 1. To avoid increasing the total amount of confusion in the world, make gdk_rgb_to_string() and gdk_rgb_parse() follow this syntax rather than using floats for r, g, and b. https://bugzilla.gnome.org/show_bug.cgi?id=633762
This commit is contained in:
parent
4bdff81f2e
commit
d2b64a1db2
@ -72,6 +72,43 @@ gdk_rgba_free (GdkRGBA *rgba)
|
||||
g_slice_free (GdkRGBA, rgba);
|
||||
}
|
||||
|
||||
#define SKIP_WHITESPACES(s) while (*(s) == ' ') (s)++;
|
||||
|
||||
/* Parses a single color component from a rgb() or rgba() specification
|
||||
* according to CSS3 rules. Compared to exact CSS3 parsing we are liberal
|
||||
* in what we accept as follows:
|
||||
*
|
||||
* - For non-percentage values, we accept floats in the range 0-255
|
||||
* not just [0-9]+ integers
|
||||
* - For percentage values we accept any float, not just
|
||||
* [ 0-9]+ | [0-9]* '.' [0-9]+
|
||||
* - We accept mixed percentages and non-percentages in a single
|
||||
* rgb() or rgba() specification.
|
||||
*/
|
||||
static double
|
||||
parse_rgb_value (const char *str,
|
||||
char **endp)
|
||||
{
|
||||
double number;
|
||||
const char *p;
|
||||
|
||||
number = g_ascii_strtod (str, endp);
|
||||
|
||||
p = *endp;
|
||||
|
||||
SKIP_WHITESPACES (p);
|
||||
|
||||
if (*p == '%')
|
||||
{
|
||||
*endp = (char *)(p + 1);
|
||||
return CLAMP(number / 100., 0., 1.);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CLAMP(number / 255., 0., 1.);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_rgba_parse:
|
||||
* @spec: the string specifying the color
|
||||
@ -100,8 +137,9 @@ gdk_rgba_free (GdkRGBA *rgba)
|
||||
* </itemizedlist>
|
||||
*
|
||||
* Where 'r', 'g', 'b' and 'a' are respectively the red, green, blue and
|
||||
* alpha color values, parsed in the last 2 cases as double numbers in
|
||||
* the range [0..1], any other value out of that range will be clamped.
|
||||
* alpha color values. In the last two cases, r g and b are either integers
|
||||
* in the range 0 to 255 or precentage values in the range 0% to 100%, and
|
||||
* a is a floating point value in the range 0 to 1.
|
||||
*
|
||||
* Returns: %TRUE if the parsing succeeded
|
||||
**/
|
||||
@ -113,8 +151,6 @@ gdk_rgba_parse (const gchar *spec,
|
||||
gdouble r, g, b, a;
|
||||
gchar *str = (gchar *) spec;
|
||||
|
||||
#define SKIP_WHITESPACES(s) while (*(s) == ' ') (s)++;
|
||||
|
||||
if (strncmp (str, "rgba", 4) == 0)
|
||||
{
|
||||
has_alpha = TRUE;
|
||||
@ -157,7 +193,7 @@ gdk_rgba_parse (const gchar *spec,
|
||||
|
||||
/* Parse red */
|
||||
SKIP_WHITESPACES (str);
|
||||
r = g_ascii_strtod (str, &str);
|
||||
r = parse_rgb_value (str, &str);
|
||||
SKIP_WHITESPACES (str);
|
||||
|
||||
if (*str != ',')
|
||||
@ -167,7 +203,7 @@ gdk_rgba_parse (const gchar *spec,
|
||||
|
||||
/* Parse green */
|
||||
SKIP_WHITESPACES (str);
|
||||
g = g_ascii_strtod (str, &str);
|
||||
g = parse_rgb_value (str, &str);
|
||||
SKIP_WHITESPACES (str);
|
||||
|
||||
if (*str != ',')
|
||||
@ -177,7 +213,7 @@ gdk_rgba_parse (const gchar *spec,
|
||||
|
||||
/* Parse blue */
|
||||
SKIP_WHITESPACES (str);
|
||||
b = g_ascii_strtod (str, &str);
|
||||
b = parse_rgb_value (str, &str);
|
||||
SKIP_WHITESPACES (str);
|
||||
|
||||
if (has_alpha)
|
||||
@ -195,8 +231,6 @@ gdk_rgba_parse (const gchar *spec,
|
||||
if (*str != ')')
|
||||
return FALSE;
|
||||
|
||||
#undef SKIP_WHITESPACES
|
||||
|
||||
if (rgba)
|
||||
{
|
||||
rgba->red = CLAMP (r, 0, 1);
|
||||
@ -208,6 +242,8 @@ gdk_rgba_parse (const gchar *spec,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef SKIP_WHITESPACES
|
||||
|
||||
/**
|
||||
* gdk_rgba_hash:
|
||||
* @p: a #GdkRGBA pointer.
|
||||
@ -259,25 +295,36 @@ gdk_rgba_equal (gconstpointer p1,
|
||||
* gdk_rgba_to_string:
|
||||
* @rgba: a #GdkRGBA
|
||||
*
|
||||
* Returns a textual specification of @rgba in the form
|
||||
* <literal>rgba (r, g, b, a)</literal>, where 'r', 'g',
|
||||
* 'b' and 'a' represent the red, green, blue and alpha
|
||||
* values respectively.
|
||||
* Returns a textual specification of @rgba in the form <literal>rgb
|
||||
* (r, g, b)</literal> or <literal>rgba (r, g, b, a)</literal>,
|
||||
* where 'r', 'g', 'b' and 'a' represent the red, green, blue and alpha values
|
||||
* respectively. r, g, and b are integers in the range 0 to 255, and a
|
||||
* is a floating point value in the range 0 to 1.
|
||||
*
|
||||
* (These string forms are string forms those supported by the CSS3 colors module)
|
||||
*
|
||||
* Returns: A newly allocated text string
|
||||
**/
|
||||
gchar *
|
||||
gdk_rgba_to_string (const GdkRGBA *rgba)
|
||||
{
|
||||
gchar red[G_ASCII_DTOSTR_BUF_SIZE];
|
||||
gchar green[G_ASCII_DTOSTR_BUF_SIZE];
|
||||
gchar blue[G_ASCII_DTOSTR_BUF_SIZE];
|
||||
gchar alpha[G_ASCII_DTOSTR_BUF_SIZE];
|
||||
if (rgba->alpha > 0.999)
|
||||
{
|
||||
return g_strdup_printf ("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.));
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar alpha[G_ASCII_DTOSTR_BUF_SIZE];
|
||||
|
||||
g_ascii_dtostr (red, G_ASCII_DTOSTR_BUF_SIZE, CLAMP (rgba->red, 0, 1));
|
||||
g_ascii_dtostr (green, G_ASCII_DTOSTR_BUF_SIZE, CLAMP (rgba->green, 0, 1));
|
||||
g_ascii_dtostr (blue, G_ASCII_DTOSTR_BUF_SIZE, CLAMP (rgba->blue, 0, 1));
|
||||
g_ascii_dtostr (alpha, G_ASCII_DTOSTR_BUF_SIZE, CLAMP (rgba->alpha, 0, 1));
|
||||
g_ascii_dtostr (alpha, G_ASCII_DTOSTR_BUF_SIZE, CLAMP (rgba->alpha, 0, 1));
|
||||
|
||||
return g_strdup_printf ("rgba(%s,%s,%s,%s)", red, green, blue, alpha);
|
||||
return g_strdup_printf ("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);
|
||||
}
|
||||
}
|
||||
|
@ -14,23 +14,23 @@ test_color_parse (void)
|
||||
res = gdk_rgba_parse ("", &color);
|
||||
g_assert (!res);
|
||||
|
||||
expected.red = 100/255.;
|
||||
expected.green = 90/255.;
|
||||
expected.blue = 80/255.;
|
||||
expected.alpha = 0.1;
|
||||
res = gdk_rgba_parse ("rgba(100,90,80,0.1)", &color);
|
||||
g_assert (res);
|
||||
g_assert (gdk_rgba_equal (&color, &expected));
|
||||
|
||||
expected.red = 0.4;
|
||||
expected.green = 0.3;
|
||||
expected.blue = 0.2;
|
||||
expected.alpha = 0.1;
|
||||
res = gdk_rgba_parse ("rgba(0.4,0.3,0.2,0.1)", &color);
|
||||
res = gdk_rgba_parse ("rgba(40%,30%,20%,0.1)", &color);
|
||||
g_assert (res);
|
||||
g_assert (gdk_rgba_equal (&color, &expected));
|
||||
|
||||
res = gdk_rgba_parse ("rgba ( 0.4 , 0.3 , 0.2 , 0.1 )", &color);
|
||||
g_assert (res);
|
||||
g_assert (gdk_rgba_equal (&color, &expected));
|
||||
|
||||
expected.red = 0.4;
|
||||
expected.green = 0.3;
|
||||
expected.blue = 0.2;
|
||||
expected.alpha = 1.0;
|
||||
res = gdk_rgba_parse ("rgb(0.4,0.3,0.2)", &color);
|
||||
res = gdk_rgba_parse ("rgba( 40 % , 30 % , 20 % , 0.1 )", &color);
|
||||
g_assert (res);
|
||||
g_assert (gdk_rgba_equal (&color, &expected));
|
||||
|
||||
@ -61,10 +61,13 @@ test_color_to_string (void)
|
||||
gchar *res_en;
|
||||
gchar *orig;
|
||||
|
||||
/* Using /255. values for the r, g, b components should
|
||||
* make sure they round-trip exactly without rounding
|
||||
* from the double => integer => double conversions */
|
||||
rgba.red = 1.0;
|
||||
rgba.green = 0.5;
|
||||
rgba.blue = 0.1;
|
||||
rgba.alpha = 1.0;
|
||||
rgba.green = 128/255.;
|
||||
rgba.blue = 64/255.;
|
||||
rgba.alpha = 0.5;
|
||||
|
||||
orig = g_strdup (setlocale (LC_ALL, NULL));
|
||||
res = gdk_rgba_to_string (&rgba);
|
||||
|
Loading…
Reference in New Issue
Block a user