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.
parent c45dd9f2
......@@ -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 \
......
......@@ -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,
......
......@@ -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)
{
......
......@@ -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);
......
......@@ -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")))
......
......@@ -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;
}
}
}
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment