[librsvg] Handle !important directive.
- From: Hiroyuki Ikezoe <hiikezoe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] Handle !important directive.
- Date: Tue, 27 Apr 2010 11:19:57 +0000 (UTC)
commit 20dd6a3ae7fa5fcddfbcf3bcfc39d8783890135d
Author: Hiroyuki Ikezoe <hiikezoe gnome org>
Date: Tue Apr 27 20:18:49 2010 +0900
Handle !important directive.
Fix for bug #61406.
RsvgState keeps style information with "!important" in hash table.
rsvg-css.c | 31 ---
rsvg-css.h | 3 -
rsvg-gobject.c | 5 +-
rsvg-styles.c | 570 ++++++++++++++++++++++++++++++++-----------------------
rsvg-styles.h | 3 +-
tests/styles.c | 3 +
6 files changed, 341 insertions(+), 274 deletions(-)
---
diff --git a/rsvg-css.c b/rsvg-css.c
index 8ef197e..5f0b558 100644
--- a/rsvg-css.c
+++ b/rsvg-css.c
@@ -252,37 +252,6 @@ _rsvg_css_hand_normalize_length (const RsvgLength * in, gdouble pixels_per_inch,
return 0;
}
-gboolean
-rsvg_css_param_match (const char *str, const char *param_name)
-{
- int i;
-
- for (i = 0; str[i] != '\0' && param_name[i] != '\0'; i++)
- if (param_name[i] != str[i])
- return FALSE;
- return str[i] == ':' && param_name[i] == '\0';
-}
-
-int
-rsvg_css_param_arg_offset (const char *str)
-{
- int i;
- int found;
- found = -1;
- i = 0;
- while (str[i] != '\0') {
- for (; str[i] != '\0' && str[i] != ':'; i++);
- if (str[i] != '\0')
- i++;
- for (; str[i] == ' '; i++);
- if (str[i] != '\0')
- found = i;
- }
- if (found == -1)
- found = i;
- return found;
-}
-
static gint
rsvg_css_clip_rgb_percent (gdouble in_percent)
{
diff --git a/rsvg-css.h b/rsvg-css.h
index 6fa2561..65446b7 100644
--- a/rsvg-css.h
+++ b/rsvg-css.h
@@ -45,9 +45,6 @@ G_BEGIN_DECLS
int rsvg_css_parse_aspect_ratio (const char *str);
-gboolean rsvg_css_param_match (const char *str, const char *param_name);
-int rsvg_css_param_arg_offset (const char *str);
-
guint32 rsvg_css_parse_color (const char *str, gboolean * inherit);
guint rsvg_css_parse_opacity (const char *str);
double rsvg_css_parse_angle (const char *str);
diff --git a/rsvg-gobject.c b/rsvg-gobject.c
index 00a252a..09a67b2 100644
--- a/rsvg-gobject.c
+++ b/rsvg-gobject.c
@@ -53,7 +53,10 @@ instance_init (RsvgHandle * self)
self->priv->dpi_x = rsvg_internal_dpi_x;
self->priv->dpi_y = rsvg_internal_dpi_y;
- self->priv->css_props = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ self->priv->css_props = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) g_hash_table_destroy);
self->priv->ctxt = NULL;
self->priv->currentnode = NULL;
diff --git a/rsvg-styles.c b/rsvg-styles.c
index e32fc69..3740612 100644
--- a/rsvg-styles.c
+++ b/rsvg-styles.c
@@ -36,6 +36,32 @@
#define RSVG_DEFAULT_FONT "Times New Roman"
+typedef struct _StyleValueData {
+ gchar *value;
+ gboolean important;
+} StyleValueData;
+
+static StyleValueData *
+style_value_data_new (const gchar *value, gboolean important)
+{
+ StyleValueData *ret;
+
+ ret = g_new (StyleValueData, 1);
+ ret->value = g_strdup (value);
+ ret->important = important;
+
+ return ret;
+}
+
+static void
+style_value_data_free (StyleValueData *value)
+{
+ if (!value)
+ return;
+ g_free (value->value);
+ g_free (value);
+}
+
gdouble
rsvg_viewport_percentage (gdouble width, gdouble height)
{
@@ -132,6 +158,9 @@ rsvg_state_init (RsvgState * state)
state->has_shape_rendering_type = FALSE;
state->text_rendering_type = TEXT_RENDERING_AUTO;
state->has_text_rendering_type = FALSE;
+
+ state->styles = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) style_value_data_free);
}
typedef int (*InheritanceFunction) (int dst, int src);
@@ -149,6 +178,8 @@ rsvg_state_clone (RsvgState * dst, const RsvgState * src)
rsvg_paint_server_ref (dst->fill);
rsvg_paint_server_ref (dst->stroke);
+ dst->styles = g_hash_table_ref (src->styles);
+
if (src->dash.n_dash > 0) {
dst->dash.dash = g_new (gdouble, src->dash.n_dash);
for (i = 0; i < src->dash.n_dash; i++)
@@ -370,343 +401,358 @@ rsvg_state_finalize (RsvgState * state)
if (state->dash.n_dash != 0)
g_free (state->dash.dash);
+
+ if (state->styles) {
+ g_hash_table_unref (state->styles);
+ state->styles = NULL;
+ }
}
/* Parse a CSS2 style argument, setting the SVG context attributes. */
static void
-rsvg_parse_style_arg (RsvgHandle * ctx, RsvgState * state, const char *str)
+rsvg_parse_style_pair (RsvgHandle * ctx,
+ RsvgState * state,
+ const gchar * name,
+ const gchar * value,
+ gboolean important)
{
- int arg_off;
-
- arg_off = rsvg_css_param_arg_offset (str);
-
- if (rsvg_css_param_match (str, "color"))
- state->current_color = rsvg_css_parse_color (str + arg_off, &state->has_current_color);
- else if (rsvg_css_param_match (str, "opacity"))
- state->opacity = rsvg_css_parse_opacity (str + arg_off);
- else if (rsvg_css_param_match (str, "flood-color"))
- state->flood_color = rsvg_css_parse_color (str + arg_off, &state->has_flood_color);
- else if (rsvg_css_param_match (str, "flood-opacity")) {
- state->flood_opacity = rsvg_css_parse_opacity (str + arg_off);
+ StyleValueData *data;
+
+ data = g_hash_table_lookup (state->styles, name);
+ if (data && data->important && !important)
+ return;
+
+ g_hash_table_insert (state->styles,
+ (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"))
+ 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")) {
+ state->flood_opacity = rsvg_css_parse_opacity (value);
state->has_flood_opacity = TRUE;
- } else if (rsvg_css_param_match (str, "filter"))
- state->filter = rsvg_filter_parse (ctx->priv->defs, str + arg_off);
- else if (rsvg_css_param_match (str, "a:adobe-blending-mode")) {
- if (!strcmp (str + arg_off, "normal"))
+ } else if (g_str_equal (name, "filter"))
+ state->filter = rsvg_filter_parse (ctx->priv->defs, value);
+ else if (g_str_equal (name, "a:adobe-blending-mode")) {
+ if (g_str_equal (value, "normal"))
state->adobe_blend = 0;
- else if (!strcmp (str + arg_off, "multiply"))
+ else if (g_str_equal (value, "multiply"))
state->adobe_blend = 1;
- else if (!strcmp (str + arg_off, "screen"))
+ else if (g_str_equal (value, "screen"))
state->adobe_blend = 2;
- else if (!strcmp (str + arg_off, "darken"))
+ else if (g_str_equal (value, "darken"))
state->adobe_blend = 3;
- else if (!strcmp (str + arg_off, "lighten"))
+ else if (g_str_equal (value, "lighten"))
state->adobe_blend = 4;
- else if (!strcmp (str + arg_off, "softlight"))
+ else if (g_str_equal (value, "softlight"))
state->adobe_blend = 5;
- else if (!strcmp (str + arg_off, "hardlight"))
+ else if (g_str_equal (value, "hardlight"))
state->adobe_blend = 6;
- else if (!strcmp (str + arg_off, "colordodge"))
+ else if (g_str_equal (value, "colordodge"))
state->adobe_blend = 7;
- else if (!strcmp (str + arg_off, "colorburn"))
+ else if (g_str_equal (value, "colorburn"))
state->adobe_blend = 8;
- else if (!strcmp (str + arg_off, "overlay"))
+ else if (g_str_equal (value, "overlay"))
state->adobe_blend = 9;
- else if (!strcmp (str + arg_off, "exclusion"))
+ else if (g_str_equal (value, "exclusion"))
state->adobe_blend = 10;
- else if (!strcmp (str + arg_off, "difference"))
+ else if (g_str_equal (value, "difference"))
state->adobe_blend = 11;
else
state->adobe_blend = 0;
- } else if (rsvg_css_param_match (str, "mask"))
- state->mask = rsvg_mask_parse (ctx->priv->defs, str + arg_off);
- else if (rsvg_css_param_match (str, "clip-path")) {
- state->clip_path_ref = rsvg_clip_path_parse (ctx->priv->defs, str + arg_off);
- } else if (rsvg_css_param_match (str, "overflow")) {
- if (strcmp (str + arg_off, "inherit")) {
- state->overflow = rsvg_css_parse_overflow (str + arg_off, &state->has_overflow);
+ } else if (g_str_equal (name, "mask"))
+ state->mask = rsvg_mask_parse (ctx->priv->defs, value);
+ else if (g_str_equal (name, "clip-path")) {
+ state->clip_path_ref = rsvg_clip_path_parse (ctx->priv->defs, value);
+ } else if (g_str_equal (name, "overflow")) {
+ if (!g_str_equal (value, "inherit")) {
+ state->overflow = rsvg_css_parse_overflow (value, &state->has_overflow);
}
- } else if (rsvg_css_param_match (str, "enable-background")) {
- if (!strcmp (str + arg_off, "new"))
+ } else if (g_str_equal (name, "enable-background")) {
+ if (g_str_equal (value, "new"))
state->enable_background = RSVG_ENABLE_BACKGROUND_NEW;
else
state->enable_background = RSVG_ENABLE_BACKGROUND_ACCUMULATE;
- } else if (rsvg_css_param_match (str, "comp-op")) {
- if (!strcmp (str + arg_off, "clear"))
+ } else if (g_str_equal (name, "comp-op")) {
+ if (g_str_equal (value, "clear"))
state->comp_op = RSVG_COMP_OP_CLEAR;
- else if (!strcmp (str + arg_off, "src"))
+ else if (g_str_equal (value, "src"))
state->comp_op = RSVG_COMP_OP_SRC;
- else if (!strcmp (str + arg_off, "dst"))
+ else if (g_str_equal (value, "dst"))
state->comp_op = RSVG_COMP_OP_DST;
- else if (!strcmp (str + arg_off, "src-over"))
+ else if (g_str_equal (value, "src-over"))
state->comp_op = RSVG_COMP_OP_SRC_OVER;
- else if (!strcmp (str + arg_off, "dst-over"))
+ else if (g_str_equal (value, "dst-over"))
state->comp_op = RSVG_COMP_OP_DST_OVER;
- else if (!strcmp (str + arg_off, "src-in"))
+ else if (g_str_equal (value, "src-in"))
state->comp_op = RSVG_COMP_OP_SRC_IN;
- else if (!strcmp (str + arg_off, "dst-in"))
+ else if (g_str_equal (value, "dst-in"))
state->comp_op = RSVG_COMP_OP_DST_IN;
- else if (!strcmp (str + arg_off, "src-out"))
+ else if (g_str_equal (value, "src-out"))
state->comp_op = RSVG_COMP_OP_SRC_OUT;
- else if (!strcmp (str + arg_off, "dst-out"))
+ else if (g_str_equal (value, "dst-out"))
state->comp_op = RSVG_COMP_OP_DST_OUT;
- else if (!strcmp (str + arg_off, "src-atop"))
+ else if (g_str_equal (value, "src-atop"))
state->comp_op = RSVG_COMP_OP_SRC_ATOP;
- else if (!strcmp (str + arg_off, "dst-atop"))
+ else if (g_str_equal (value, "dst-atop"))
state->comp_op = RSVG_COMP_OP_DST_ATOP;
- else if (!strcmp (str + arg_off, "xor"))
+ else if (g_str_equal (value, "xor"))
state->comp_op = RSVG_COMP_OP_XOR;
- else if (!strcmp (str + arg_off, "plus"))
+ else if (g_str_equal (value, "plus"))
state->comp_op = RSVG_COMP_OP_PLUS;
- else if (!strcmp (str + arg_off, "multiply"))
+ else if (g_str_equal (value, "multiply"))
state->comp_op = RSVG_COMP_OP_MULTIPLY;
- else if (!strcmp (str + arg_off, "screen"))
+ else if (g_str_equal (value, "screen"))
state->comp_op = RSVG_COMP_OP_SCREEN;
- else if (!strcmp (str + arg_off, "overlay"))
+ else if (g_str_equal (value, "overlay"))
state->comp_op = RSVG_COMP_OP_OVERLAY;
- else if (!strcmp (str + arg_off, "darken"))
+ else if (g_str_equal (value, "darken"))
state->comp_op = RSVG_COMP_OP_DARKEN;
- else if (!strcmp (str + arg_off, "lighten"))
+ else if (g_str_equal (value, "lighten"))
state->comp_op = RSVG_COMP_OP_LIGHTEN;
- else if (!strcmp (str + arg_off, "color-dodge"))
+ else if (g_str_equal (value, "color-dodge"))
state->comp_op = RSVG_COMP_OP_COLOR_DODGE;
- else if (!strcmp (str + arg_off, "color-burn"))
+ else if (g_str_equal (value, "color-burn"))
state->comp_op = RSVG_COMP_OP_COLOR_BURN;
- else if (!strcmp (str + arg_off, "hard-light"))
+ else if (g_str_equal (value, "hard-light"))
state->comp_op = RSVG_COMP_OP_HARD_LIGHT;
- else if (!strcmp (str + arg_off, "soft-light"))
+ else if (g_str_equal (value, "soft-light"))
state->comp_op = RSVG_COMP_OP_SOFT_LIGHT;
- else if (!strcmp (str + arg_off, "difference"))
+ else if (g_str_equal (value, "difference"))
state->comp_op = RSVG_COMP_OP_DIFFERENCE;
- else if (!strcmp (str + arg_off, "exclusion"))
+ else if (g_str_equal (value, "exclusion"))
state->comp_op = RSVG_COMP_OP_EXCLUSION;
else
state->comp_op = RSVG_COMP_OP_SRC_OVER;
- } else if (rsvg_css_param_match (str, "display")) {
+ } else if (g_str_equal (name, "display")) {
state->has_visible = TRUE;
- if (!strcmp (str + arg_off, "none"))
+ if (g_str_equal (value, "none"))
state->visible = FALSE;
- else if (strcmp (str + arg_off, "inherit") != 0)
+ else if (!g_str_equal (value, "inherit") != 0)
state->visible = TRUE;
else
state->has_visible = FALSE;
- } else if (rsvg_css_param_match (str, "xml:space")) {
+ } else if (g_str_equal (name, "xml:space")) {
state->has_space_preserve = TRUE;
- if (!strcmp (str + arg_off, "default"))
+ if (g_str_equal (value, "default"))
state->space_preserve = FALSE;
- else if (strcmp (str + arg_off, "preserve") == 0)
+ else if (!g_str_equal (value, "preserve") == 0)
state->space_preserve = TRUE;
else
state->space_preserve = FALSE;
- } else if (rsvg_css_param_match (str, "visibility")) {
+ } else if (g_str_equal (name, "visibility")) {
state->has_visible = TRUE;
- if (!strcmp (str + arg_off, "visible"))
+ if (g_str_equal (value, "visible"))
state->visible = TRUE;
- else if (strcmp (str + arg_off, "inherit") != 0)
+ else if (!g_str_equal (value, "inherit") != 0)
state->visible = FALSE; /* collapse or hidden */
else
state->has_visible = FALSE;
- } else if (rsvg_css_param_match (str, "fill")) {
+ } else if (g_str_equal (name, "fill")) {
RsvgPaintServer *fill = state->fill;
state->fill =
- rsvg_paint_server_parse (&state->has_fill_server, ctx->priv->defs, str + arg_off, 0);
+ rsvg_paint_server_parse (&state->has_fill_server, ctx->priv->defs, value, 0);
rsvg_paint_server_unref (fill);
- } else if (rsvg_css_param_match (str, "fill-opacity")) {
- state->fill_opacity = rsvg_css_parse_opacity (str + arg_off);
+ } else if (g_str_equal (name, "fill-opacity")) {
+ state->fill_opacity = rsvg_css_parse_opacity (value);
state->has_fill_opacity = TRUE;
- } else if (rsvg_css_param_match (str, "fill-rule")) {
+ } else if (g_str_equal (name, "fill-rule")) {
state->has_fill_rule = TRUE;
- if (!strcmp (str + arg_off, "nonzero"))
+ if (g_str_equal (value, "nonzero"))
state->fill_rule = FILL_RULE_NONZERO;
- else if (!strcmp (str + arg_off, "evenodd"))
+ else if (g_str_equal (value, "evenodd"))
state->fill_rule = FILL_RULE_EVENODD;
else
state->has_fill_rule = FALSE;
- } else if (rsvg_css_param_match (str, "clip-rule")) {
+ } else if (g_str_equal (name, "clip-rule")) {
state->has_clip_rule = TRUE;
- if (!strcmp (str + arg_off, "nonzero"))
+ if (g_str_equal (value, "nonzero"))
state->clip_rule = FILL_RULE_NONZERO;
- else if (!strcmp (str + arg_off, "evenodd"))
+ else if (g_str_equal (value, "evenodd"))
state->clip_rule = FILL_RULE_EVENODD;
else
state->has_clip_rule = FALSE;
- } else if (rsvg_css_param_match (str, "stroke")) {
+ } else if (g_str_equal (name, "stroke")) {
RsvgPaintServer *stroke = state->stroke;
state->stroke =
- rsvg_paint_server_parse (&state->has_stroke_server, ctx->priv->defs, str + arg_off, 0);
+ rsvg_paint_server_parse (&state->has_stroke_server, ctx->priv->defs, value, 0);
rsvg_paint_server_unref (stroke);
- } else if (rsvg_css_param_match (str, "stroke-width")) {
- state->stroke_width = _rsvg_css_parse_length (str + arg_off);
+ } else if (g_str_equal (name, "stroke-width")) {
+ state->stroke_width = _rsvg_css_parse_length (value);
state->has_stroke_width = TRUE;
- } else if (rsvg_css_param_match (str, "stroke-linecap")) {
+ } else if (g_str_equal (name, "stroke-linecap")) {
state->has_cap = TRUE;
- if (!strcmp (str + arg_off, "butt"))
+ if (g_str_equal (value, "butt"))
state->cap = RSVG_PATH_STROKE_CAP_BUTT;
- else if (!strcmp (str + arg_off, "round"))
+ else if (g_str_equal (value, "round"))
state->cap = RSVG_PATH_STROKE_CAP_ROUND;
- else if (!strcmp (str + arg_off, "square"))
+ else if (g_str_equal (value, "square"))
state->cap = RSVG_PATH_STROKE_CAP_SQUARE;
else
- g_warning (_("unknown line cap style %s\n"), str + arg_off);
- } else if (rsvg_css_param_match (str, "stroke-opacity")) {
- state->stroke_opacity = rsvg_css_parse_opacity (str + arg_off);
+ g_warning (_("unknown line cap style %s\n"), value);
+ } else if (g_str_equal (name, "stroke-opacity")) {
+ state->stroke_opacity = rsvg_css_parse_opacity (value);
state->has_stroke_opacity = TRUE;
- } else if (rsvg_css_param_match (str, "stroke-linejoin")) {
+ } else if (g_str_equal (name, "stroke-linejoin")) {
state->has_join = TRUE;
- if (!strcmp (str + arg_off, "miter"))
+ if (g_str_equal (value, "miter"))
state->join = RSVG_PATH_STROKE_JOIN_MITER;
- else if (!strcmp (str + arg_off, "round"))
+ else if (g_str_equal (value, "round"))
state->join = RSVG_PATH_STROKE_JOIN_ROUND;
- else if (!strcmp (str + arg_off, "bevel"))
+ else if (g_str_equal (value, "bevel"))
state->join = RSVG_PATH_STROKE_JOIN_BEVEL;
else
- g_warning (_("unknown line join style %s\n"), str + arg_off);
- } else if (rsvg_css_param_match (str, "font-size")) {
- state->font_size = _rsvg_css_parse_length (str + arg_off);
+ g_warning (_("unknown line join style %s\n"), value);
+ } else if (g_str_equal (name, "font-size")) {
+ state->font_size = _rsvg_css_parse_length (value);
state->has_font_size = TRUE;
- } else if (rsvg_css_param_match (str, "font-family")) {
- char *save = g_strdup (rsvg_css_parse_font_family (str + arg_off, &state->has_font_family));
+ } else if (g_str_equal (name, "font-family")) {
+ char *save = g_strdup (rsvg_css_parse_font_family (value, &state->has_font_family));
g_free (state->font_family);
state->font_family = save;
- } else if (rsvg_css_param_match (str, "xml:lang")) {
- char *save = g_strdup (str + arg_off);
+ } else if (g_str_equal (name, "xml:lang")) {
+ char *save = g_strdup (value);
g_free (state->lang);
state->lang = save;
state->has_lang = TRUE;
- } else if (rsvg_css_param_match (str, "font-style")) {
- state->font_style = rsvg_css_parse_font_style (str + arg_off, &state->has_font_style);
- } else if (rsvg_css_param_match (str, "font-variant")) {
- state->font_variant = rsvg_css_parse_font_variant (str + arg_off, &state->has_font_variant);
- } else if (rsvg_css_param_match (str, "font-weight")) {
- state->font_weight = rsvg_css_parse_font_weight (str + arg_off, &state->has_font_weight);
- } else if (rsvg_css_param_match (str, "font-stretch")) {
- state->font_stretch = rsvg_css_parse_font_stretch (str + arg_off, &state->has_font_stretch);
- } else if (rsvg_css_param_match (str, "text-decoration")) {
- if (!strcmp (str + arg_off, "inherit")) {
+ } else if (g_str_equal (name, "font-style")) {
+ state->font_style = rsvg_css_parse_font_style (value, &state->has_font_style);
+ } else if (g_str_equal (name, "font-variant")) {
+ state->font_variant = rsvg_css_parse_font_variant (value, &state->has_font_variant);
+ } else if (g_str_equal (name, "font-weight")) {
+ state->font_weight = rsvg_css_parse_font_weight (value, &state->has_font_weight);
+ } else if (g_str_equal (name, "font-stretch")) {
+ state->font_stretch = rsvg_css_parse_font_stretch (value, &state->has_font_stretch);
+ } else if (g_str_equal (name, "text-decoration")) {
+ if (g_str_equal (value, "inherit")) {
state->has_font_decor = FALSE;
state->font_decor = TEXT_NORMAL;
} else {
- if (strstr (str + arg_off, "underline"))
+ if (strstr (value, "underline"))
state->font_decor |= TEXT_UNDERLINE;
- if (strstr (str + arg_off, "overline"))
+ if (strstr (value, "overline"))
state->font_decor |= TEXT_OVERLINE;
- if (strstr (str + arg_off, "strike") || strstr (str + arg_off, "line-through")) /* strike though or line-through */
+ if (strstr (value, "strike") || strstr (value, "line-through")) /* strike though or line-through */
state->font_decor |= TEXT_STRIKE;
state->has_font_decor = TRUE;
}
- } else if (rsvg_css_param_match (str, "direction")) {
+ } else if (g_str_equal (name, "direction")) {
state->has_text_dir = TRUE;
- if (!strcmp (str + arg_off, "inherit")) {
+ if (g_str_equal (value, "inherit")) {
state->text_dir = PANGO_DIRECTION_LTR;
state->has_text_dir = FALSE;
- } else if (!strcmp (str + arg_off, "rtl"))
+ } else if (g_str_equal (value, "rtl"))
state->text_dir = PANGO_DIRECTION_RTL;
else /* ltr */
state->text_dir = PANGO_DIRECTION_LTR;
- } else if (rsvg_css_param_match (str, "unicode-bidi")) {
+ } else if (g_str_equal (name, "unicode-bidi")) {
state->has_unicode_bidi = TRUE;
- if (!strcmp (str + arg_off, "inherit")) {
+ if (g_str_equal (value, "inherit")) {
state->unicode_bidi = PANGO_DIRECTION_LTR;
state->has_unicode_bidi = FALSE;
- } else if (!strcmp (str + arg_off, "embed"))
+ } else if (g_str_equal (value, "embed"))
state->unicode_bidi = UNICODE_BIDI_EMBED;
- else if (!strcmp (str + arg_off, "bidi-override"))
+ else if (g_str_equal (value, "bidi-override"))
state->unicode_bidi = UNICODE_BIDI_OVERRIDE;
else /* normal */
state->unicode_bidi = UNICODE_BIDI_NORMAL;
- } else if (rsvg_css_param_match (str, "writing-mode")) {
+ } else if (g_str_equal (name, "writing-mode")) {
/* TODO: these aren't quite right... */
state->has_text_dir = TRUE;
- if (!strcmp (str + arg_off, "inherit")) {
+ if (g_str_equal (value, "inherit")) {
state->text_dir = PANGO_DIRECTION_LTR;
state->has_text_dir = FALSE;
- } else if (!strcmp (str + arg_off, "lr-tb") || !strcmp (str + arg_off, "tb"))
+ } else if (g_str_equal (value, "lr-tb") || g_str_equal (value, "tb"))
state->text_dir = PANGO_DIRECTION_TTB_LTR;
- else if (!strcmp (str + arg_off, "rl"))
+ else if (g_str_equal (value, "rl"))
state->text_dir = PANGO_DIRECTION_RTL;
- else if (!strcmp (str + arg_off, "tb-rl") || !strcmp (str + arg_off, "rl-tb"))
+ else if (g_str_equal (value, "tb-rl") || g_str_equal (value, "rl-tb"))
state->text_dir = PANGO_DIRECTION_TTB_RTL;
else
state->text_dir = PANGO_DIRECTION_LTR;
- } else if (rsvg_css_param_match (str, "text-anchor")) {
+ } else if (g_str_equal (name, "text-anchor")) {
state->has_text_anchor = TRUE;
- if (!strcmp (str + arg_off, "inherit")) {
+ if (g_str_equal (value, "inherit")) {
state->text_anchor = TEXT_ANCHOR_START;
state->has_text_anchor = FALSE;
} else {
- if (strstr (str + arg_off, "start"))
+ if (strstr (value, "start"))
state->text_anchor = TEXT_ANCHOR_START;
- else if (strstr (str + arg_off, "middle"))
+ else if (strstr (value, "middle"))
state->text_anchor = TEXT_ANCHOR_MIDDLE;
- else if (strstr (str + arg_off, "end"))
+ else if (strstr (value, "end"))
state->text_anchor = TEXT_ANCHOR_END;
}
- } else if (rsvg_css_param_match (str, "letter-spacing")) {
+ } else if (g_str_equal (name, "letter-spacing")) {
state->has_letter_spacing = TRUE;
- state->letter_spacing = _rsvg_css_parse_length (str + arg_off);
- } else if (rsvg_css_param_match (str, "stop-color")) {
- if (strcmp (str + arg_off, "inherit")) {
- state->stop_color = rsvg_css_parse_color (str + arg_off, &state->has_stop_color);
+ state->letter_spacing = _rsvg_css_parse_length (value);
+ } else if (g_str_equal (name, "stop-color")) {
+ if (!g_str_equal (value, "inherit")) {
+ state->stop_color = rsvg_css_parse_color (value, &state->has_stop_color);
}
- } else if (rsvg_css_param_match (str, "stop-opacity")) {
- if (strcmp (str + arg_off, "inherit")) {
+ } else if (g_str_equal (name, "stop-opacity")) {
+ if (!g_str_equal (value, "inherit")) {
state->has_stop_opacity = TRUE;
- state->stop_opacity = rsvg_css_parse_opacity (str + arg_off);
+ state->stop_opacity = rsvg_css_parse_opacity (value);
}
- } else if (rsvg_css_param_match (str, "marker-start")) {
- state->startMarker = rsvg_marker_parse (ctx->priv->defs, str + arg_off);
+ } else if (g_str_equal (name, "marker-start")) {
+ state->startMarker = rsvg_marker_parse (ctx->priv->defs, value);
state->has_startMarker = TRUE;
- } else if (rsvg_css_param_match (str, "marker-mid")) {
- state->middleMarker = rsvg_marker_parse (ctx->priv->defs, str + arg_off);
+ } else if (g_str_equal (name, "marker-mid")) {
+ state->middleMarker = rsvg_marker_parse (ctx->priv->defs, value);
state->has_middleMarker = TRUE;
- } else if (rsvg_css_param_match (str, "marker-end")) {
- state->endMarker = rsvg_marker_parse (ctx->priv->defs, str + arg_off);
+ } else if (g_str_equal (name, "marker-end")) {
+ state->endMarker = rsvg_marker_parse (ctx->priv->defs, value);
state->has_endMarker = TRUE;
- } else if (rsvg_css_param_match (str, "stroke-miterlimit")) {
+ } else if (g_str_equal (name, "stroke-miterlimit")) {
state->has_miter_limit = TRUE;
- state->miter_limit = g_ascii_strtod (str + arg_off, NULL);
- } else if (rsvg_css_param_match (str, "stroke-dashoffset")) {
+ state->miter_limit = g_ascii_strtod (value, NULL);
+ } else if (g_str_equal (name, "stroke-dashoffset")) {
state->has_dashoffset = TRUE;
- state->dash.offset = _rsvg_css_parse_length (str + arg_off);
+ state->dash.offset = _rsvg_css_parse_length (value);
if (state->dash.offset.length < 0.)
state->dash.offset.length = 0.;
- } else if (rsvg_css_param_match (str, "shape-rendering")) {
+ } else if (g_str_equal (name, "shape-rendering")) {
state->has_shape_rendering_type = TRUE;
- if (!strcmp (str + arg_off, "auto") || !strcmp (str + arg_off, "default"))
+ if (g_str_equal (value, "auto") || g_str_equal (value, "default"))
state->shape_rendering_type = SHAPE_RENDERING_AUTO;
- else if (!strcmp (str + arg_off, "optimizeSpeed"))
+ else if (g_str_equal (value, "optimizeSpeed"))
state->shape_rendering_type = SHAPE_RENDERING_OPTIMIZE_SPEED;
- else if (!strcmp (str + arg_off, "crispEdges"))
+ else if (g_str_equal (value, "crispEdges"))
state->shape_rendering_type = SHAPE_RENDERING_CRISP_EDGES;
- else if (!strcmp (str + arg_off, "geometricPrecision"))
+ else if (g_str_equal (value, "geometricPrecision"))
state->shape_rendering_type = SHAPE_RENDERING_GEOMETRIC_PRECISION;
- } else if (rsvg_css_param_match (str, "text-rendering")) {
+ } else if (g_str_equal (name, "text-rendering")) {
state->has_text_rendering_type = TRUE;
- if (!strcmp (str + arg_off, "auto") || !strcmp (str + arg_off, "default"))
+ if (g_str_equal (value, "auto") || g_str_equal (value, "default"))
state->text_rendering_type = TEXT_RENDERING_AUTO;
- else if (!strcmp (str + arg_off, "optimizeSpeed"))
+ else if (g_str_equal (value, "optimizeSpeed"))
state->text_rendering_type = TEXT_RENDERING_OPTIMIZE_SPEED;
- else if (!strcmp (str + arg_off, "optimizeLegibility"))
+ else if (g_str_equal (value, "optimizeLegibility"))
state->text_rendering_type = TEXT_RENDERING_OPTIMIZE_LEGIBILITY;
- else if (!strcmp (str + arg_off, "geometricPrecision"))
+ else if (g_str_equal (value, "geometricPrecision"))
state->text_rendering_type = TEXT_RENDERING_GEOMETRIC_PRECISION;
- } else if (rsvg_css_param_match (str, "stroke-dasharray")) {
+ } else if (g_str_equal (name, "stroke-dasharray")) {
state->has_dash = TRUE;
- if (!strcmp (str + arg_off, "none")) {
+ if (g_str_equal (value, "none")) {
if (state->dash.n_dash != 0) {
/* free any cloned dash data */
g_free (state->dash.dash);
state->dash.n_dash = 0;
}
} else {
- gchar **dashes = g_strsplit (str + arg_off, ",", -1);
+ gchar **dashes = g_strsplit (value, ",", -1);
if (NULL != dashes) {
gint n_dashes, i;
gboolean is_even = FALSE;
@@ -743,14 +789,6 @@ rsvg_parse_style_arg (RsvgHandle * ctx, RsvgState * state, const char *str)
}
}
-void
-rsvg_parse_style_pair (RsvgHandle * ctx, RsvgState * state, const char *key, const char *val)
-{
- gchar *str = g_strdup_printf ("%s:%s", key, val);
- rsvg_parse_style_arg (ctx, state, str);
- g_free (str);
-}
-
static void
rsvg_lookup_parse_style_pair (RsvgHandle * ctx, RsvgState * state,
const char *key, RsvgPropertyBag * atts)
@@ -758,7 +796,7 @@ rsvg_lookup_parse_style_pair (RsvgHandle * ctx, RsvgState * state,
const char *value;
if ((value = rsvg_property_bag_lookup (atts, key)) != NULL)
- rsvg_parse_style_pair (ctx, state, key, value);
+ rsvg_parse_style_pair (ctx, state, key, value, FALSE);
}
/* take a pair of the form (fill="#ff00ff") and parse it as a style */
@@ -824,6 +862,23 @@ rsvg_parse_style_pairs (RsvgHandle * ctx, RsvgState * state, RsvgPropertyBag * a
}
}
+static gboolean
+is_important (const gchar *value)
+{
+ gchar **strings;
+ gboolean important = FALSE;
+
+ strings = g_strsplit (value, "!", 2);
+ if (g_strv_length (strings) == 2 &&
+ g_str_equal (g_strstrip (strings[1]), "important")) {
+ important = TRUE;
+ }
+
+ g_strfreev (strings);
+
+ return important;
+}
+
/* Split a CSS2 style into individual style arguments, setting attributes
in the SVG context.
@@ -833,40 +888,55 @@ rsvg_parse_style_pairs (RsvgHandle * ctx, RsvgState * state, RsvgPropertyBag * a
void
rsvg_parse_style (RsvgHandle * ctx, RsvgState * state, const char *str)
{
- int start, end;
- char *arg;
-
- start = 0;
- while (str[start] != '\0') {
- for (end = start; str[end] != '\0' && str[end] != ';'; end++);
- arg = g_new (char, 1 + end - start);
- memcpy (arg, str + start, end - start);
- arg[end - start] = '\0';
- rsvg_parse_style_arg (ctx, state, arg);
- g_free (arg);
- start = end;
- if (str[start] == ';')
- start++;
- while (str[start] == ' ')
- start++;
+ gchar **styles;
+ guint i;
+
+ styles = g_strsplit (str, ";", -1);
+ for (i = 0; i < g_strv_length (styles); i++) {
+ gchar **values;
+ values = g_strsplit (styles[i], ":", 2);
+ if (!values)
+ continue;
+
+ if (g_strv_length (values) == 2) {
+ rsvg_parse_style_pair (ctx, state,
+ g_strstrip (values[0]),
+ g_strstrip (values[1]),
+ is_important (values[1]));
+ }
+ g_strfreev (values);
}
+ g_strfreev (styles);
}
static void
-rsvg_css_define_style (RsvgHandle * ctx, const gchar * style_name, const char *style_def)
+rsvg_css_define_style (RsvgHandle * ctx,
+ const gchar * selector,
+ const gchar * style_name,
+ const gchar * style_value,
+ gboolean important)
{
- GString *str = g_string_new (style_def);
- char *existing = NULL;
+ GHashTable *styles;
+ gboolean need_insert = FALSE;
/* push name/style pair into HT */
- existing = (char *) g_hash_table_lookup (ctx->priv->css_props, style_name);
- if (existing != NULL)
- g_string_append_len (str, existing, strlen (existing));
-
- /* will destroy the existing key and value for us */
- g_hash_table_insert (ctx->priv->css_props, (gpointer) g_strdup ((gchar *) style_name),
- (gpointer) str->str);
- g_string_free (str, FALSE);
+ styles = g_hash_table_lookup (ctx->priv->css_props, selector);
+ if (styles == NULL) {
+ styles = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify) style_value_data_free);
+ g_hash_table_insert (ctx->priv->css_props, (gpointer) g_strdup (selector), styles);
+ need_insert = TRUE;
+ } else {
+ StyleValueData *current_value;
+ current_value = g_hash_table_lookup (styles, style_name);
+ if (current_value == NULL || !current_value->important)
+ need_insert = TRUE;
+ }
+ if (need_insert) {
+ g_hash_table_insert (styles,
+ (gpointer) g_strdup (style_name),
+ (gpointer) style_value_data_new (style_value, important));
+ }
}
#ifdef HAVE_LIBCROCO
@@ -875,14 +945,14 @@ rsvg_css_define_style (RsvgHandle * ctx, const gchar * style_name, const char *s
typedef struct _CSSUserData {
RsvgHandle *ctx;
- GString *def;
+ CRSelector *selector;
} CSSUserData;
static void
css_user_data_init (CSSUserData * user_data, RsvgHandle * ctx)
{
user_data->ctx = ctx;
- user_data->def = NULL;
+ user_data->selector = NULL;
}
static void
@@ -893,54 +963,56 @@ ccss_start_selector (CRDocHandler * a_handler, CRSelector * a_selector_list)
g_return_if_fail (a_handler);
user_data = (CSSUserData *) a_handler->app_data;
- user_data->def = g_string_new (NULL);
+ cr_selector_ref (a_selector_list);
+ user_data->selector = a_selector_list;
}
static void
ccss_end_selector (CRDocHandler * a_handler, CRSelector * a_selector_list)
{
CSSUserData *user_data;
- CRSelector *cur;
g_return_if_fail (a_handler);
user_data = (CSSUserData *) a_handler->app_data;
- if (a_selector_list)
- for (cur = a_selector_list; cur; cur = cur->next) {
- if (cur->simple_sel) {
- gchar *style_name = (gchar *) cr_simple_sel_to_string (cur->simple_sel);
- if (style_name) {
- rsvg_css_define_style (user_data->ctx, style_name, user_data->def->str);
- g_free (style_name);
- }
- }
- }
-
- g_string_free (user_data->def, TRUE);
+ cr_selector_unref (user_data->selector);
+ user_data->selector = NULL;
}
static void
ccss_property (CRDocHandler * a_handler, CRString * a_name, CRTerm * a_expr, gboolean a_important)
{
CSSUserData *user_data;
- gchar *expr = NULL, *name = NULL;
+ gchar *name = NULL;
size_t len = 0;
g_return_if_fail (a_handler);
user_data = (CSSUserData *) a_handler->app_data;
- if (a_name && a_expr && user_data->def) {
- name = (gchar *) cr_string_peek_raw_str (a_name);
- len = cr_string_peek_raw_str_len (a_name);
-
- g_string_append_len (user_data->def, (gchar *) name, len);
- g_string_append (user_data->def, ": ");
- expr = (gchar *) cr_term_to_string (a_expr);
- g_string_append_len (user_data->def, expr, strlen (expr));
- g_free (expr);
- g_string_append (user_data->def, "; ");
+ if (a_name && a_expr && user_data->selector) {
+ CRSelector *cur;
+ for (cur = user_data->selector; cur; cur = cur->next) {
+ if (cur->simple_sel) {
+ gchar *selector = (gchar *) cr_simple_sel_to_string (cur->simple_sel);
+ if (selector) {
+ gchar *style_name, *style_value;
+ name = (gchar *) cr_string_peek_raw_str (a_name);
+ len = cr_string_peek_raw_str_len (a_name);
+ style_name = g_strndup (name, len);
+ style_value = (gchar *)cr_term_to_string (a_expr);
+ rsvg_css_define_style (user_data->ctx,
+ selector,
+ style_name,
+ style_value,
+ a_important);
+ g_free (selector);
+ g_free (style_name);
+ g_free (style_value);
+ }
+ }
+ }
}
}
@@ -1052,9 +1124,9 @@ rsvg_real_parse_cssbuffer (RsvgHandle * ctx, const char *buff, size_t buflen)
size_t loc = 0;
while (loc < buflen) {
- gchar **styles;
+ gchar **selectors;
guint i;
- GString *style_name = g_string_new (NULL);
+ GString *selector = g_string_new (NULL);
GString *style_props = g_string_new (NULL);
/* advance to the style's name */
@@ -1063,7 +1135,7 @@ rsvg_real_parse_cssbuffer (RsvgHandle * ctx, const char *buff, size_t buflen)
/* advance to the first { that defines the style's properties */
while (loc < buflen && buff[loc] != '{')
- g_string_append_c (style_name, buff[loc++]);
+ g_string_append_c (selector, buff[loc++]);
loc++;
while (loc < buflen && g_ascii_isspace (buff[loc]))
@@ -1086,12 +1158,16 @@ rsvg_real_parse_cssbuffer (RsvgHandle * ctx, const char *buff, size_t buflen)
}
}
- styles = g_strsplit (style_name->str, ",", -1);
- for (i = 0; i < g_strv_length (styles); i++)
- rsvg_css_define_style (ctx, g_strstrip (styles[i]), style_props->str);
- g_strfreev (styles);
+ selectors = g_strsplit (selector->str, ",", -1);
+ for (i = 0; i < g_strv_length (selectors); i++) {
+ rsvg_css_define_style (ctx,
+ g_strstrip (selectors[i]),
+ style_props->str,
+ FALSE);
+ }
+ g_strfreev (selectors);
- g_string_free (style_name, TRUE);
+ g_string_free (selector, TRUE);
g_string_free (style_props, TRUE);
loc++;
@@ -1254,13 +1330,31 @@ rsvg_parse_transform_attr (RsvgHandle * ctx, RsvgState * state, const char *str)
}
}
+typedef struct _StylesData {
+ RsvgHandle *ctx;
+ RsvgState *state;
+} StylesData;
+
+static void
+apply_style (const gchar *key, StyleValueData *value, gpointer user_data)
+{
+ StylesData *data = (StylesData *) user_data;
+ rsvg_parse_style_pair (data->ctx, data->state, key, value->value, value->important);
+}
+
static gboolean
rsvg_lookup_apply_css_style (RsvgHandle * ctx, const char *target, RsvgState * state)
{
- const char *value = (const char *) g_hash_table_lookup (ctx->priv->css_props, target);
+ GHashTable *styles;
+
+ styles = g_hash_table_lookup (ctx->priv->css_props, target);
- if (value != NULL) {
- rsvg_parse_style (ctx, state, value);
+ if (styles != NULL) {
+ StylesData *data = g_new (StylesData, 1);
+ data->ctx = ctx;
+ data->state = state;
+ g_hash_table_foreach (styles, (GHFunc) apply_style, data);
+ g_free (data);
return TRUE;
}
return FALSE;
diff --git a/rsvg-styles.h b/rsvg-styles.h
index 7f91836..290a9a9 100644
--- a/rsvg-styles.h
+++ b/rsvg-styles.h
@@ -235,6 +235,8 @@ struct _RsvgState {
TextRenderingProperty text_rendering_type;
gboolean has_text_rendering_type;
+
+ GHashTable *styles;
};
RsvgState *rsvg_state_new ();
@@ -248,7 +250,6 @@ void rsvg_state_override (RsvgState * dst, const RsvgState * src);
void rsvg_state_finalize (RsvgState * state);
void rsvg_parse_style_pairs (RsvgHandle * ctx, RsvgState * state, RsvgPropertyBag * atts);
-void rsvg_parse_style_pair (RsvgHandle * ctx, RsvgState * state, const char *key, const char *val);
void rsvg_parse_style (RsvgHandle * ctx, RsvgState * state, const char *str);
void rsvg_parse_cssbuffer (RsvgHandle * ctx, const char *buff, size_t buflen);
diff --git a/tests/styles.c b/tests/styles.c
index d3db402..7107c6c 100644
--- a/tests/styles.c
+++ b/tests/styles.c
@@ -95,6 +95,9 @@ static const FixtureData fixtures[] =
{"/styles/!important", "379629", "fixtures/styles/bug379629.svg", "#base_shadow", "stroke-width", .expected.length = {POINTS_LENGTH(5.), 'i'}},
{"/styles/!important/class", "614606", "fixtures/styles/bug614606.svg", "#path6306", "fill", .expected.color = 0xff0000 /* red */ },
{"/styles/!important/element", "614606", "fixtures/styles/bug614606.svg", "#path6308", "fill", .expected.color = 0x000000},
+ {"/styles/!important/#id prior than class", NULL, "fixtures/styles/important.svg", "#red", "fill", .expected.color = 0xff0000 },
+ {"/styles/!important/class prior than type", NULL, "fixtures/styles/important.svg", "#blue", "fill", .expected.color = 0x0000ff },
+ {"/styles/!important/presentation attribute is invalid", NULL, "fixtures/styles/important.svg", "#white", "fill", .expected.color = 0xffffff },
{"/styles/selectors/descendant", "338160", "fixtures/styles/bug338160.svg", "#base_shadow", "stroke-width", .expected.length = {2., '\0'}},
};
static const gint n_fixtures = G_N_ELEMENTS (fixtures);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]