[librsvg] Fully move rsvg_css_parse_color() to Rust. Yay!



commit 7294c856b9f15f81e7ed95eb2302845032d8023b
Author: Federico Mena Quintero <federico gnome org>
Date:   Fri May 19 22:44:01 2017 -0500

    Fully move rsvg_css_parse_color() to Rust.  Yay!
    
    We keep a C function rsvg_css_parse_color_() that just calls the Rust
    one.  This is so that the linker will make the C symbol visible; this is
    the quirky function that gets exported just for the benefit of
    rsvg-convert.c.

 Makefile.am         |    1 +
 rsvg-convert.c      |   10 ++++-
 rsvg-css.c          |  123 +++------------------------------------------------
 rsvg-css.h          |   34 ++++++++++++++-
 rsvg-filter.c       |   65 +++++++++++++++++++++++++--
 rsvg-paint-server.c |   70 ++++++++++++++++++++---------
 rsvg-styles.c       |   93 ++++++++++++++++++++++++++++++++------
 7 files changed, 237 insertions(+), 159 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 340e8e1..a7cbe94 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -73,6 +73,7 @@ RUST_SOURCES =                                        \
        rust/src/aspect_ratio.rs                \
        rust/src/bbox.rs                        \
        rust/src/cnode.rs                       \
+       rust/src/color.rs                       \
        rust/src/drawing_ctx.rs                 \
        rust/src/error.rs                       \
        rust/src/gradient.rs                    \
diff --git a/rsvg-convert.c b/rsvg-convert.c
index ac90e23..9770f5c 100644
--- a/rsvg-convert.c
+++ b/rsvg-convert.c
@@ -372,7 +372,15 @@ main (int argc, char **argv)
 
         // Set background color
         if (background_color_str && g_ascii_strcasecmp(background_color_str, "none") != 0) {
-            background_color = rsvg_css_parse_color(background_color_str, FALSE);
+            RsvgCssColorSpec spec;
+
+            spec = rsvg_css_parse_color_ (background_color_str, ALLOW_INHERIT_NO, ALLOW_CURRENT_COLOR_NO);
+            if (spec.kind == RSVG_CSS_COLOR_SPEC_ARGB) {
+                background_color = spec.argb;
+            } else {
+                g_printerr (_("Invalid color specification."));
+                exit (1);
+            }
 
             cairo_set_source_rgb (
                 cr, 
diff --git a/rsvg-css.c b/rsvg-css.c
index 296d868..067768c 100644
--- a/rsvg-css.c
+++ b/rsvg-css.c
@@ -142,127 +142,16 @@ _rsvg_css_accumulate_baseline_shift (RsvgState * state, RsvgDrawingCtx * ctx)
     return shift;
 }
 
-static gint
-rsvg_css_clip_rgb_percent (const char *s, double max)
-{
-    double value;
-    char *end;
-
-    value = g_ascii_strtod (s, &end);
-
-    if (*end == '%') {
-        value = CLAMP (value, 0, 100) / 100.0;
-    }
-    else {
-        value = CLAMP (value, 0, max) / max;
-    }
-    
-    return (gint) floor (value * 255 + 0.5);
-}
-
-/* pack 3 [0,255] ints into one 32 bit one */
-#define PACK_RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
-#define PACK_RGB(r,g,b) PACK_RGBA(r, g, b, 255)
-
-/**
- * rsvg_css_parse_color:
- * @str: string to parse
- * @inherit: whether to inherit
- *
- * Parse a CSS2 color specifier, return RGB value
- *
- * Returns: and RGB value
+/* This is defined like this so that we can export the Rust function... just for
+ * the benefit of rsvg-convert.c
  */
-guint32
-rsvg_css_parse_color (const char *str, gboolean * inherit)
+RsvgCssColorSpec rsvg_css_parse_color_ (const char       *str,
+                                        AllowInherit      allow_inherit,
+                                        AllowCurrentColor allow_current_color)
 {
-    gint val = 0;
-
-    SETINHERIT ();
-
-    if (str[0] == '#') {
-        int i;
-        for (i = 1; str[i]; i++) {
-            int hexval;
-            if (str[i] >= '0' && str[i] <= '9')
-                hexval = str[i] - '0';
-            else if (str[i] >= 'A' && str[i] <= 'F')
-                hexval = str[i] - 'A' + 10;
-            else if (str[i] >= 'a' && str[i] <= 'f')
-                hexval = str[i] - 'a' + 10;
-            else
-                break;
-            val = (val << 4) + hexval;
-        }
-        /* handle #rgb case */
-        if (i == 4) {
-            val = ((val & 0xf00) << 8) | ((val & 0x0f0) << 4) | (val & 0x00f);
-            val |= val << 4;
-        }
-
-        val |= 0xff000000; /* opaque */
-    }
-    else if (g_str_has_prefix (str, "rgb")) {
-        gint r, g, b, a;
-        gboolean has_alpha;
-        guint nb_toks;
-        char **toks;
-
-        r = g = b = 0;
-        a = 255;
-
-        if (str[3] == 'a') {
-            /* "rgba" */
-            has_alpha = TRUE;
-            str += 4;
-        }
-        else {
-            /* "rgb" */
-            has_alpha = FALSE;
-            str += 3;
-        }
-
-        str = strchr (str, '(');
-        if (str == NULL)
-          return val;
-
-        toks = rsvg_css_parse_list (str + 1, &nb_toks);
-
-        if (toks) {
-            if (nb_toks == (has_alpha ? 4 : 3)) {
-                r = rsvg_css_clip_rgb_percent (toks[0], 255.0);
-                g = rsvg_css_clip_rgb_percent (toks[1], 255.0);
-                b = rsvg_css_clip_rgb_percent (toks[2], 255.0);
-                if (has_alpha)
-                    a = rsvg_css_clip_rgb_percent (toks[3], 1.0);
-                else
-                    a = 255;
-            }
-
-            g_strfreev (toks);
-        }
-
-        val = PACK_RGBA (r, g, b, a);
-    } else if (!strcmp (str, "inherit"))
-        UNSETINHERIT ();
-    else {
-        CRRgb rgb;
-
-        if (cr_rgb_set_from_name (&rgb, (const guchar *) str) == CR_OK) {
-            val = PACK_RGB (rgb.red, rgb.green, rgb.blue);
-        } else {
-            /* default to opaque black on failed lookup */
-            UNSETINHERIT ();
-            val = PACK_RGB (0, 0, 0);
-        }
-    }
-
-    return val;
+    return rsvg_css_parse_color (str, allow_inherit, allow_current_color);
 }
 
-#undef PACK_RGB
-#undef PACK_RGBA
-
 guint
 rsvg_css_parse_opacity (const char *str)
 {
diff --git a/rsvg-css.h b/rsvg-css.h
index 5023c29..7c7400b 100644
--- a/rsvg-css.h
+++ b/rsvg-css.h
@@ -48,11 +48,43 @@ G_BEGIN_DECLS
 #define RSVG_ASPECT_RATIO_SLICE (1 << 30)
 #define RSVG_ASPECT_RATIO_DEFER (1 << 31)
 
+/* Keep this in sync with rust/src/color.rs:ColorKind */
+typedef enum {
+    RSVG_CSS_COLOR_SPEC_INHERIT,
+    RSVG_CSS_COLOR_SPEC_CURRENT_COLOR,
+    RSVG_CSS_COLOR_SPEC_ARGB,
+    RSVG_CSS_COLOR_PARSE_ERROR
+} RsvgCssColorKind;
+
+/* Keep this in sync with rust/src/color.rs:RsvgCssColor */
+typedef struct {
+    RsvgCssColorKind kind;
+    guint32 argb; /* only valid if kind == RSVG_CSS_COLOR_SPEC_ARGB */
+} RsvgCssColorSpec;
+
+typedef enum {
+    ALLOW_INHERIT_NO,
+    ALLOW_INHERIT_YES,
+} AllowInherit;
+
+typedef enum {
+    ALLOW_CURRENT_COLOR_NO,
+    ALLOW_CURRENT_COLOR_YES
+} AllowCurrentColor;
+
 /* This one is semi-public for mis-use in rsvg-convert */
-guint32            rsvg_css_parse_color        (const char *str, gboolean * inherit);
+RsvgCssColorSpec rsvg_css_parse_color_ (const char       *str,
+                                        AllowInherit      allow_inherit,
+                                        AllowCurrentColor allow_current_color);
 
 #ifdef RSVG_COMPILATION
 
+/* Implemented in rust/src/color.rs */
+G_GNUC_INTERNAL
+RsvgCssColorSpec rsvg_css_parse_color (const char       *str,
+                                       AllowInherit      allow_inherit,
+                                       AllowCurrentColor allow_current_color);
+
 /* This is implemented in rust/src/aspect_ratio.rs */
 G_GNUC_INTERNAL
 guint32 rsvg_aspect_ratio_parse (const char *str);
diff --git a/rsvg-filter.c b/rsvg-filter.c
index 22b1362..ce739d9 100644
--- a/rsvg-filter.c
+++ b/rsvg-filter.c
@@ -4561,6 +4561,7 @@ rsvg_filter_primitive_diffuse_lighting_set_atts (RsvgNode *node, gpointer impl,
 {
     RsvgFilterPrimitiveDiffuseLighting *filter = impl;
     const char *value;
+    RsvgState *state;
 
     if ((value = rsvg_property_bag_lookup (atts, "in")))
         g_string_assign (filter->super.in, value);
@@ -4571,8 +4572,36 @@ rsvg_filter_primitive_diffuse_lighting_set_atts (RsvgNode *node, gpointer impl,
 
     if ((value = rsvg_property_bag_lookup (atts, "kernelUnitLength")))
         rsvg_css_parse_number_optional_number (value, &filter->dx, &filter->dy);
-    if ((value = rsvg_property_bag_lookup (atts, "lighting-color")))
-        filter->lightingcolor = rsvg_css_parse_color (value, 0);
+
+    if ((value = rsvg_property_bag_lookup (atts, "lighting-color"))) {
+        RsvgCssColorSpec spec;
+
+        spec = rsvg_css_parse_color (value, ALLOW_INHERIT_YES, ALLOW_CURRENT_COLOR_YES);
+
+        switch (spec.kind) {
+        case RSVG_CSS_COLOR_SPEC_INHERIT:
+            /* FIXME: we should inherit; see how stop-color is handled in rsvg-styles.c */
+            break;
+
+        case RSVG_CSS_COLOR_SPEC_CURRENT_COLOR:
+            state = rsvg_state_new ();
+            rsvg_state_reconstruct (state, node);
+            filter->lightingcolor = state->current_color;
+            break;
+
+        case RSVG_CSS_COLOR_SPEC_ARGB:
+            filter->lightingcolor = spec.argb;
+            break;
+
+        case RSVG_CSS_COLOR_PARSE_ERROR:
+            rsvg_node_set_attribute_parse_error (node, "lighting-color", "Invalid color");
+            break;
+
+        default:
+            g_assert_not_reached ();
+        }
+    }
+
     if ((value = rsvg_property_bag_lookup (atts, "diffuseConstant")))
         filter->diffuseConstant = g_ascii_strtod (value, NULL);
     if ((value = rsvg_property_bag_lookup (atts, "surfaceScale")))
@@ -4730,8 +4759,36 @@ rsvg_filter_primitive_specular_lighting_set_atts (RsvgNode *node, gpointer impl,
 
     filter_primitive_set_x_y_width_height_atts ((RsvgFilterPrimitive *) filter, atts);
 
-    if ((value = rsvg_property_bag_lookup (atts, "lighting-color")))
-        filter->lightingcolor = rsvg_css_parse_color (value, 0);
+    if ((value = rsvg_property_bag_lookup (atts, "lighting-color"))) {
+        RsvgCssColorSpec spec;
+        RsvgState *state;
+
+        spec = rsvg_css_parse_color (value, ALLOW_INHERIT_YES, ALLOW_CURRENT_COLOR_YES);
+
+        switch (spec.kind) {
+        case RSVG_CSS_COLOR_SPEC_INHERIT:
+            /* FIXME: we should inherit; see how stop-color is handled in rsvg-styles.c */
+            break;
+
+        case RSVG_CSS_COLOR_SPEC_CURRENT_COLOR:
+            state = rsvg_state_new ();
+            rsvg_state_reconstruct (state, node);
+            filter->lightingcolor = state->current_color;
+            break;
+
+        case RSVG_CSS_COLOR_SPEC_ARGB:
+            filter->lightingcolor = spec.argb;
+            break;
+
+        case RSVG_CSS_COLOR_PARSE_ERROR:
+            rsvg_node_set_attribute_parse_error (node, "lighting-color", "Invalid color");
+            break;
+
+        default:
+            g_assert_not_reached ();
+        }
+    }
+
     if ((value = rsvg_property_bag_lookup (atts, "specularConstant")))
         filter->specularConstant = g_ascii_strtod (value, NULL);
     if ((value = rsvg_property_bag_lookup (atts, "specularExponent")))
diff --git a/rsvg-paint-server.c b/rsvg-paint-server.c
index 367323b..98714ac 100644
--- a/rsvg-paint-server.c
+++ b/rsvg-paint-server.c
@@ -81,17 +81,34 @@ rsvg_paint_server_iri (char *iri, gboolean has_alternate, RsvgSolidColor alterna
 static gboolean
 parse_current_color_or_argb (const char *str, RsvgSolidColor *dest)
 {
-    if (!strcmp (str, "currentColor")) {
-        dest->currentcolor = TRUE;
+    if (!strcmp (str, "none")) {
+        dest->currentcolor = FALSE;
         dest->argb = 0;
-        return TRUE;
+        return FALSE;
     } else {
-        gboolean parsed;
-
-        dest->currentcolor = FALSE;
-        dest->argb = rsvg_css_parse_color (str, &parsed);
-
-        return parsed;
+        RsvgCssColorSpec spec;
+
+        spec = rsvg_css_parse_color (str, ALLOW_INHERIT_NO, ALLOW_CURRENT_COLOR_YES);
+        switch (spec.kind) {
+        case RSVG_CSS_COLOR_SPEC_CURRENT_COLOR:
+            dest->currentcolor = TRUE;
+            dest->argb = 0;
+            return TRUE;
+
+        case RSVG_CSS_COLOR_SPEC_ARGB:
+            dest->currentcolor = FALSE;
+            dest->argb = spec.argb;
+            return TRUE;
+
+        case RSVG_CSS_COLOR_PARSE_ERROR:
+            dest->currentcolor = FALSE;
+            dest->argb = 0;
+            return FALSE;
+
+        default:
+            g_assert_not_reached ();
+            return FALSE;
+        }
     }
 }
 
@@ -110,7 +127,6 @@ rsvg_paint_server_parse (gboolean *inherit, const char *str)
 {
     char *name;
     const char *rest;
-    guint32 argb;
 
     if (inherit != NULL)
         *inherit = TRUE;
@@ -130,18 +146,30 @@ rsvg_paint_server_parse (gboolean *inherit, const char *str)
         has_alternate = parse_current_color_or_argb (rest, &alternate);
 
         return rsvg_paint_server_iri (name, has_alternate, alternate);
-    } else if (!strcmp (str, "inherit")) {
-        /* Do the fallback to black here; don't let the caller do it via inheritance */
-        if (inherit != NULL)
-            *inherit = FALSE;
-        return rsvg_paint_server_solid (0);
-    } else if (!strcmp (str, "currentColor")) {
-        RsvgPaintServer *ps;
-        ps = rsvg_paint_server_solid_current_color ();
-        return ps;
     } else {
-        argb = rsvg_css_parse_color (str, inherit);
-        return rsvg_paint_server_solid (argb);
+        RsvgCssColorSpec spec;
+
+        spec = rsvg_css_parse_color (str, ALLOW_INHERIT_YES, ALLOW_CURRENT_COLOR_YES);
+        switch (spec.kind) {
+        case RSVG_CSS_COLOR_SPEC_INHERIT:
+            /* FIXME: this is incorrect; we should inherit the paint server */
+            if (inherit != NULL)
+                *inherit = FALSE;
+            return rsvg_paint_server_solid (0);
+
+        case RSVG_CSS_COLOR_SPEC_CURRENT_COLOR:
+            return rsvg_paint_server_solid_current_color ();
+
+        case RSVG_CSS_COLOR_SPEC_ARGB:
+            return rsvg_paint_server_solid (spec.argb);
+
+        case RSVG_CSS_COLOR_PARSE_ERROR:
+            return NULL;
+
+        default:
+            g_assert_not_reached ();
+            return NULL;
+        }
     }
 }
 
diff --git a/rsvg-styles.c b/rsvg-styles.c
index 79fea5d..00a500d 100644
--- a/rsvg-styles.c
+++ b/rsvg-styles.c
@@ -528,13 +528,60 @@ rsvg_parse_style_pair (RsvgState * state,
                          (gpointer) g_strdup (name),
                          (gpointer) style_value_data_new (value, important));
 
-    if (g_str_equal (name, "color"))
-        state->current_color = rsvg_css_parse_color (value, &state->has_current_color);
-    else if (g_str_equal (name, "opacity"))
+    if (g_str_equal (name, "color")) {
+        RsvgCssColorSpec spec;
+
+        spec = rsvg_css_parse_color (value, ALLOW_INHERIT_YES, ALLOW_CURRENT_COLOR_NO);
+        switch (spec.kind) {
+        case RSVG_CSS_COLOR_SPEC_INHERIT:
+            /* FIXME: we should inherit; see how stop-color is handled in rsvg-styles.c */
+            state->has_current_color = FALSE;
+            break;
+
+        case RSVG_CSS_COLOR_SPEC_ARGB:
+            state->current_color = spec.argb;
+            state->has_current_color = TRUE;
+            break;
+
+        case RSVG_CSS_COLOR_PARSE_ERROR:
+            /* FIXME: no error handling */
+            state->has_current_color = FALSE;
+            break;
+
+        default:
+            g_assert_not_reached ();
+        }
+    } else if (g_str_equal (name, "opacity"))
         state->opacity = rsvg_css_parse_opacity (value);
-    else if (g_str_equal (name, "flood-color"))
-        state->flood_color = rsvg_css_parse_color (value, &state->has_flood_color);
-    else if (g_str_equal (name, "flood-opacity")) {
+    else if (g_str_equal (name, "flood-color")) {
+        RsvgCssColorSpec spec;
+
+        spec = rsvg_css_parse_color (value, ALLOW_INHERIT_YES, ALLOW_CURRENT_COLOR_YES);
+        switch (spec.kind) {
+        case RSVG_CSS_COLOR_SPEC_INHERIT:
+            /* FIXME: we should inherit; see how stop-color is handled in rsvg-styles.c */
+            state->has_current_color = FALSE;
+            break;
+
+        case RSVG_CSS_COLOR_SPEC_CURRENT_COLOR:
+            /* FIXME: in the caller, fix up the current color */
+            state->has_flood_color = FALSE;
+            break;
+
+        case RSVG_CSS_COLOR_SPEC_ARGB:
+            state->flood_color = spec.argb;
+            state->has_flood_color = TRUE;
+            break;
+
+        case RSVG_CSS_COLOR_PARSE_ERROR:
+            /* FIXME: no error handling */
+            state->has_current_color = FALSE;
+            break;
+
+        default:
+            g_assert_not_reached ();
+        }
+    } else if (g_str_equal (name, "flood-opacity")) {
         state->flood_opacity = rsvg_css_parse_opacity (value);
         state->has_flood_opacity = TRUE;
     } else if (g_str_equal (name, "filter")) {
@@ -793,17 +840,33 @@ rsvg_parse_style_pair (RsvgState * state,
        state->has_letter_spacing = TRUE;
        state->letter_spacing = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
     } else if (g_str_equal (name, "stop-color")) {
-        state->has_stop_color = TRUE;
-        if (g_str_equal (value, "inherit")) {
+        RsvgCssColorSpec spec;
+
+        spec = rsvg_css_parse_color (value, ALLOW_INHERIT_YES, ALLOW_CURRENT_COLOR_YES);
+        switch (spec.kind) {
+        case RSVG_CSS_COLOR_SPEC_INHERIT:
             state->stop_color_mode = STOP_COLOR_INHERIT;
             state->has_stop_color = FALSE;
-        } else if (g_str_equal (value, "currentColor")) {
-            state->stop_color_mode = STOP_COLOR_CURRENT_COLOR;
-        } else {
-            state->stop_color = rsvg_css_parse_color (value, &state->has_stop_color);
-            if (state->has_stop_color) {
-                state->stop_color_mode = STOP_COLOR_SPECIFIED;
-            }
+            break;
+
+        case RSVG_CSS_COLOR_SPEC_CURRENT_COLOR:
+            state->stop_color_mode= STOP_COLOR_CURRENT_COLOR;
+            state->has_flood_color = TRUE;
+            break;
+
+        case RSVG_CSS_COLOR_SPEC_ARGB:
+            state->stop_color = spec.argb;
+            state->stop_color_mode = STOP_COLOR_SPECIFIED;
+            state->has_stop_color = TRUE;
+            break;
+
+        case RSVG_CSS_COLOR_PARSE_ERROR:
+            /* FIXME: no error handling */
+            state->has_stop_color = FALSE;
+            break;
+
+        default:
+            g_assert_not_reached ();
         }
     } else if (g_str_equal (name, "stop-opacity")) {
         state->has_stop_opacity = TRUE;


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