diff --git a/clutter/clutter-color.c b/clutter/clutter-color.c
index 7d0ab2981..2d20734be 100644
--- a/clutter/clutter-color.c
+++ b/clutter/clutter-color.c
@@ -441,6 +441,99 @@ clutter_color_from_pixel (ClutterColor *color,
color->alpha = pixel & 0xff;
}
+static inline void
+skip_whitespace (gchar **str)
+{
+ while (g_ascii_isspace (**str))
+ *str += 1;
+}
+
+static inline void
+parse_rgb_value (gchar *str,
+ guint8 *color,
+ gchar **endp)
+{
+ gdouble number;
+ gchar *p;
+
+ skip_whitespace (&str);
+
+ number = g_ascii_strtod (str, endp);
+
+ p = *endp;
+
+ skip_whitespace (&p);
+
+ if (*p == '%')
+ {
+ *endp = (gchar *) (p + 1);
+
+ *color = CLAMP (number / 100.0, 0.0, 1.0) * 255;
+ }
+ else
+ *color = CLAMP (number, 0, 255);
+}
+
+static gboolean
+parse_rgba (ClutterColor *color,
+ gchar *str,
+ gboolean has_alpha)
+{
+ skip_whitespace (&str);
+
+ if (*str != '(')
+ return FALSE;
+
+ str += 1;
+
+ /* red */
+ parse_rgb_value (str, &color->red, &str);
+ skip_whitespace (&str);
+ if (*str != ',')
+ return FALSE;
+
+ str += 1;
+
+ /* green */
+ parse_rgb_value (str, &color->green, &str);
+ skip_whitespace (&str);
+ if (*str != ',')
+ return FALSE;
+
+ str += 1;
+
+ /* blue */
+ parse_rgb_value (str, &color->blue, &str);
+ skip_whitespace (&str);
+
+ /* alpha (optional); since the alpha channel value can only
+ * be between 0 and 1 we don't use the parse_rgb_value()
+ * function
+ */
+ if (has_alpha)
+ {
+ gdouble number;
+
+ if (*str != ',')
+ return FALSE;
+
+ str += 1;
+
+ skip_whitespace (&str);
+ number = g_ascii_strtod (str, &str);
+
+ color->alpha = CLAMP (number * 255.0, 0, 255);
+ }
+ else
+ color->alpha = 255;
+
+ skip_whitespace (&str);
+ if (*str != ')')
+ return FALSE;
+
+ return TRUE;
+}
+
/**
* clutter_color_from_string:
* @color: (out caller-allocates): return location for a #ClutterColor
@@ -453,11 +546,28 @@ clutter_color_from_pixel (ClutterColor *color,
*
* The @color is not allocated.
*
- * The color may be defined by any of the formats understood by
- * pango_color_from_string(); these include literal color names, like
- * Red or DarkSlateGray, or
- * hexadecimal specifications like #3050b2 or
- * #333.
+ * The format of @str can be either one of:
+ *
+ * a standard name (taken from the X11 rgb.txt
+ * file");
+ * an hexadecimal value in the form: '#rgb', '#rrggbb',
+ * '#rgba' or '#rrggbbaa';
+ * a RGB color in the form 'rgb(r, g, b)';
+ * a RGBA color in the form 'rgba(r, g, b,
+ * a)';
+ *
+ * where 'r', 'g', 'b' and 'a' are (respectively) the red, green, blue and
+ * alpha color values.
+ *
+ * In the last two cases, the 'r', 'g', and 'b' values are either integers
+ * between 0 and 255, or percentage values in the range between 0% and 100%;
+ * the percentages require the '%' character. The 'a' value, if specified,
+ * can only be a floating point value between 0.0 and 1.0.
+ *
+ * Whitespace is ignored.
+ *
+ * If the alpha component is not specified then it is assumed to be set to
+ * be fully opaque.
*
* Return value: %TRUE if parsing succeeded.
*
@@ -472,6 +582,19 @@ clutter_color_from_string (ClutterColor *color,
g_return_val_if_fail (color != NULL, FALSE);
g_return_val_if_fail (str != NULL, FALSE);
+ if (strncmp (str, "rgb", 3) == 0)
+ {
+ gchar *s = (gchar *) str;
+ gboolean res;
+
+ if (strncmp (str, "rgba", 4) == 0)
+ res = parse_rgba (color, s + 4, TRUE);
+ else
+ res = parse_rgba (color, s + 3, FALSE);
+
+ return res;
+ }
+
/* if the string contains a color encoded using the hexadecimal
* notations (#rrggbbaa or #rgba) we attempt a rough pass at
* parsing the color ourselves, as we need the alpha channel that
@@ -537,7 +660,7 @@ clutter_color_from_string (ClutterColor *color,
}
}
}
-
+
/* Fall back to pango for named colors */
if (pango_color_parse (&pango_color, str))
{
diff --git a/tests/conform/test-color.c b/tests/conform/test-color.c
index 71b080736..e9681e1a6 100644
--- a/tests/conform/test-color.c
+++ b/tests/conform/test-color.c
@@ -78,7 +78,7 @@ test_color_from_string (TestConformSimpleFixture *fixture,
{
ClutterColor color;
- clutter_color_from_string (&color, "#ff0000ff");
+ g_assert (clutter_color_from_string (&color, "#ff0000ff"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0xff, 0, 0, 0xff }\n",
@@ -92,7 +92,7 @@ test_color_from_string (TestConformSimpleFixture *fixture,
g_assert (color.blue == 0);
g_assert (color.alpha == 0xff);
- clutter_color_from_string (&color, "#0f0f");
+ g_assert (clutter_color_from_string (&color, "#0f0f"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0, 0xff, 0, 0xff }\n",
@@ -106,7 +106,7 @@ test_color_from_string (TestConformSimpleFixture *fixture,
g_assert (color.blue == 0);
g_assert (color.alpha == 0xff);
- clutter_color_from_string (&color, "#0000ff");
+ g_assert (clutter_color_from_string (&color, "#0000ff"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0, 0, 0xff, 0xff }\n",
@@ -120,7 +120,7 @@ test_color_from_string (TestConformSimpleFixture *fixture,
g_assert (color.blue == 0xff);
g_assert (color.alpha == 0xff);
- clutter_color_from_string (&color, "#abc");
+ g_assert (clutter_color_from_string (&color, "#abc"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0xaa, 0xbb, 0xcc, 0xff }\n",
@@ -134,7 +134,7 @@ test_color_from_string (TestConformSimpleFixture *fixture,
g_assert (color.blue == 0xcc);
g_assert (color.alpha == 0xff);
- clutter_color_from_string (&color, "#123abc");
+ g_assert (clutter_color_from_string (&color, "#123abc"));
if (g_test_verbose ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0x12, 0x3a, 0xbc, 0xff }\n",
@@ -147,6 +147,50 @@ test_color_from_string (TestConformSimpleFixture *fixture,
g_assert (color.green == 0x3a);
g_assert (color.blue == 0xbc);
g_assert (color.alpha == 0xff);
+
+ g_assert (clutter_color_from_string (&color, "rgb(255, 128, 64)"));
+ if (g_test_verbose ())
+ {
+ g_print ("color = { %x, %x, %x, %x }, expected = { 255, 128, 64, 255 }\n",
+ color.red,
+ color.green,
+ color.blue,
+ color.alpha);
+ }
+ g_assert_cmpint (color.red, ==, 255);
+ g_assert_cmpint (color.green, ==, 128);
+ g_assert_cmpint (color.blue, ==, 64);
+ g_assert_cmpint (color.alpha, ==, 255);
+
+ g_assert (clutter_color_from_string (&color, "rgba ( 30%, 0, 25%, 0.5 ) "));
+ if (g_test_verbose ())
+ {
+ g_print ("color = { %x, %x, %x, %x }, expected = { %.1f, 0, %.1f, 128 }\n",
+ color.red,
+ color.green,
+ color.blue,
+ color.alpha,
+ CLAMP (255.0 / 100.0 * 30.0, 0, 255),
+ CLAMP (255.0 / 100.0 * 25.0, 0, 255));
+ }
+ g_assert_cmpint (color.red, ==, (255.0 / 100.0 * 30.0));
+ g_assert_cmpint (color.green, ==, 0);
+ g_assert_cmpint (color.blue, ==, (255.0 / 100.0 * 25.0));
+ g_assert_cmpint (color.alpha, ==, 127);
+
+ g_assert (clutter_color_from_string (&color, "rgb( 50%, -50%, 150% )"));
+ if (g_test_verbose ())
+ {
+ g_print ("color = { %x, %x, %x, %x }, expected = { 127, 0, 255, 255 }\n",
+ color.red,
+ color.green,
+ color.blue,
+ color.alpha);
+ }
+ g_assert_cmpint (color.red, ==, 127);
+ g_assert_cmpint (color.green, ==, 0);
+ g_assert_cmpint (color.blue, ==, 255);
+ g_assert_cmpint (color.alpha, ==, 255);
}
void