[librsvg] Fully move rsvg_css_parse_color() to Rust. Yay!
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] Fully move rsvg_css_parse_color() to Rust. Yay!
- Date: Sat, 20 May 2017 03:48:36 +0000 (UTC)
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]