Be explicit about how stop-color and stop-opacity are inherited

These can live in the <stop> element attributes, or in its style="..."
attribute.

Neither of them inherits by default; they have to be explicitly
specified as "inherit" to do that.

Inheritance is from the gradient's parent element, not from where it is
referenced, hence the call to rsvg_state_reconstruct().

Also, stop-color can be currentColor.

We now have explicit enums to indicate all of these cases.  Previously,
all the meanings were overloaded into state->has_stop_color and
state->has_stop_opacity, and those didn't handle all cases correctly.

Added the hexchat.svg icon to the tests, which is how I caught the lack
of proper handling for style="stop-color: ...;".
parent cd7028ed
......@@ -149,17 +149,17 @@ rsvg_paint_server_unref (RsvgPaintServer * ps)
static void
rsvg_stop_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
gboolean has_stop_color = FALSE;
gboolean has_stop_opacity = FALSE;
gboolean is_current_color = FALSE;
const char *value;
RsvgGradientStop *stop;
RsvgState *state;
RsvgState *inherited_state;
int opacity;
guint32 color;
stop = (RsvgGradientStop *) self;
state = rsvg_node_get_state (self);
if ((value = rsvg_property_bag_lookup (atts, "offset"))) {
/* either a number [0,1] or a percentage */
RsvgLength length = rsvg_length_parse (value, LENGTH_DIR_BOTH);
......@@ -182,43 +182,56 @@ rsvg_stop_set_atts (RsvgNode * self, RsvgHandle * ctx, RsvgPropertyBag * atts)
}
}
if ((value = rsvg_property_bag_lookup (atts, "style")))
rsvg_parse_style (ctx, rsvg_node_get_state (self), value);
rsvg_parse_style (ctx, state, value);
if ((value = rsvg_property_bag_lookup (atts, "stop-color"))) {
has_stop_color = TRUE;
rsvg_parse_style_pairs (ctx, state, atts);
if (!strcmp (value, "currentColor"))
is_current_color = TRUE;
}
inherited_state = rsvg_state_new ();
rsvg_state_reconstruct (inherited_state, self);
if ((value = rsvg_property_bag_lookup (atts, "stop-opacity"))) {
has_stop_opacity = TRUE;
}
switch (state->stop_color_mode) {
case STOP_COLOR_UNSPECIFIED:
color = 0x0;
break;
rsvg_parse_style_pairs (ctx, rsvg_node_get_state (self), atts);
case STOP_COLOR_SPECIFIED:
color = state->stop_color & 0x00ffffff;
break;
state = rsvg_state_new ();
rsvg_state_reconstruct (state, self);
case STOP_COLOR_INHERIT:
color = inherited_state->stop_color;
break;
if (has_stop_color) {
if (is_current_color)
color = state->current_color;
else {
color = state->stop_color & 0x00ffffff;
}
} else {
color = 0x0;
case STOP_COLOR_CURRENT_COLOR:
color = inherited_state->current_color;
break;
default:
g_assert_not_reached ();
color = 0;
}
if (has_stop_opacity) {
opacity = state->stop_opacity;
} else {
switch (state->stop_opacity_mode) {
case STOP_OPACITY_UNSPECIFIED:
opacity = 0xff;
break;
case STOP_OPACITY_SPECIFIED:
opacity = state->stop_opacity;
break;
case STOP_OPACITY_INHERIT:
opacity = inherited_state->stop_opacity;
break;
default:
g_assert_not_reached ();
opacity = 0;
}
stop->rgba = (color << 8) | opacity;
rsvg_state_free (state);
rsvg_state_free (inherited_state);
}
RsvgNode *
......
......@@ -118,7 +118,10 @@ rsvg_state_init (RsvgState * state)
state->miter_limit = 4;
state->cap = CAIRO_LINE_CAP_BUTT;
state->join = CAIRO_LINE_JOIN_MITER;
state->stop_color = 0x00;
state->stop_color_mode = STOP_COLOR_UNSPECIFIED;
state->stop_opacity = 0xff;
state->stop_opacity_mode = STOP_OPACITY_UNSPECIFIED;
state->fill_rule = CAIRO_FILL_RULE_WINDING;
state->clip_rule = CAIRO_FILL_RULE_WINDING;
state->enable_background = RSVG_ENABLE_BACKGROUND_ACCUMULATE;
......@@ -350,10 +353,14 @@ rsvg_state_inherit_run (RsvgState * dst, const RsvgState * src,
dst->cap = src->cap;
if (function (dst->has_join, src->has_join))
dst->join = src->join;
if (function (dst->has_stop_color, src->has_stop_color))
if (function (dst->has_stop_color, src->has_stop_color)) {
dst->stop_color = src->stop_color;
if (function (dst->has_stop_opacity, src->has_stop_opacity))
dst->stop_color_mode = src->stop_color_mode;
}
if (function (dst->has_stop_opacity, src->has_stop_opacity)) {
dst->stop_opacity = src->stop_opacity;
dst->stop_opacity_mode = src->stop_opacity_mode;
}
if (function (dst->has_cond, src->has_cond))
dst->cond_true = src->cond_true;
if (function (dst->has_font_size, src->has_font_size))
......@@ -801,13 +808,26 @@ rsvg_parse_style_pair (RsvgHandle * ctx,
state->has_letter_spacing = TRUE;
state->letter_spacing = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
} else if (g_str_equal (name, "stop-color")) {
if (!g_str_equal (value, "inherit")) {
state->has_stop_color = TRUE;
if (g_str_equal (value, "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;
}
}
} else if (g_str_equal (name, "stop-opacity")) {
if (!g_str_equal (value, "inherit")) {
state->has_stop_opacity = TRUE;
state->has_stop_opacity = TRUE;
if (g_str_equal (value, "inherit")) {
state->has_stop_opacity = FALSE;
state->stop_opacity_mode = STOP_OPACITY_INHERIT;
} else {
state->stop_opacity = rsvg_css_parse_opacity (value);
state->stop_opacity_mode = STOP_OPACITY_SPECIFIED;
}
} else if (g_str_equal (name, "marker-start")) {
g_free (state->startMarker);
......
......@@ -72,6 +72,19 @@ struct _RsvgVpathDash {
double *dash;
};
typedef enum {
STOP_COLOR_UNSPECIFIED,
STOP_COLOR_SPECIFIED,
STOP_COLOR_INHERIT,
STOP_COLOR_CURRENT_COLOR
} StopColor;
typedef enum {
STOP_OPACITY_UNSPECIFIED,
STOP_OPACITY_SPECIFIED,
STOP_OPACITY_INHERIT
} StopOpacity;
/* end libart theft... */
struct _RsvgState {
......@@ -143,8 +156,10 @@ struct _RsvgState {
guint32 stop_color; /* rgb */
gboolean has_stop_color;
StopColor stop_color_mode;
gint stop_opacity; /* 0..255 */
gboolean has_stop_opacity;
StopOpacity stop_opacity_mode;
gboolean visible;
gboolean has_visible;
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xlink="http://www.w3.org/1999/xlink"
height="64"
width="64">
<metadata>
<rdf:RDF>
<cc:Work>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>Guglielmi David</dc:title>
</cc:Agent>
</dc:creator>
<cc:license rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
<dc:rights>
<cc:Agent>
<dc:title>Peter Zelezny</dc:title>
</cc:Agent>
</dc:rights>
<dc:contributor>
<cc:Agent>
<dc:title>Samuel Messner</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
<cc:requires rdf:resource="http://web.resource.org/cc/Notice" />
<cc:requires rdf:resource="http://web.resource.org/cc/ShareAlike" />
<cc:requires rdf:resource="http://web.resource.org/cc/SourceCode" />
<cc:permits rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:permits rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<defs>
<linearGradient id="hexchatGradient" x1="0" y1="0" x2="0" y2="1">
<stop id="hgYellowStop" offset="0" style="stop-color: #FFD600" />
<stop id="hgRedStop" offset="1" style="stop-color: #FF2600" />
</linearGradient>
</defs>
<use xlink:href="#outline" style="opacity:0.15" transform="translate(0,2)" id="shadow" />
<path
style="fill:#000000; fill-opacity: 1;"
d="M 31.71875,4.1088109 C 24.433462,4.1801109 17.123427,4.6356469 15.75,5.4213109 13.003148,6.9926379 0.06149557,29.207739 0.09374996,32.296311 0.12600597,35.384884 13.564642,57.372816 16.34375,58.890061 19.122855,60.407306 45.503149,60.148888 48.25,58.577561 50.996852,57.006233 63.938504,34.791133 63.90625,31.702561 63.87399,28.613989 50.466608,6.5948049 47.6875,5.0775609 46.297948,4.3189379 39.004037,4.0375089 31.71875,4.1088109 Z m -0.1875,9.2500001 c 3.386631,-0.03246 6.676687,0.05409 8.75,0.28125 l -8.71875,9.71875 -9.0625,-9.5 c 2.055746,-0.283043 5.521157,-0.466366 9.03125,-0.5 z m 17.34375,9.84375 c 2.298293,3.744897 4.302354,7.392556 4.3125,8.34375 0.01126,1.055883 -2.358157,5.507241 -4.875,9.6875 l -9.03125,-8.03125 z m -34.46875,0.25 8.75,9.75 -8.1875,7.875 c -2.482342,-3.992634 -4.707927,-8.110307 -4.71875,-9.125 -0.01021,-0.95736 1.927117,-4.687748 4.15625,-8.5 z m 17.15625,16.90625 9.8125,9.21875 c -4.111037,0.67314 -16.108253,0.781873 -19.46875,0.125 z"
id="outline" />
<path
style="fill:url(#hexchatGradient); fill-opacity: 1;"
d="m 31.34375,6.1713109 c -6.857093,0.06521 -13.707297,0.469014 -15,1.1875 C 13.758345,8.7957819 1.5633917,29.128076 1.5937497,31.952561 c 0.03036,2.824486 12.6654863,22.924987 15.2812503,24.3125 2.615763,1.387513 27.445846,1.186972 30.03125,-0.25 2.585405,-1.436972 14.780359,-21.769265 14.75,-24.59375 C 61.62589,28.596826 48.990764,8.4650729 46.375,7.0775609 45.067119,6.3838039 38.200842,6.1061049 31.34375,6.1713109 Z m 0.0625,5.0625001 c 5.36199,-0.05245 10.696035,0.19201 11.71875,0.75 0.06132,0.03346 0.143803,0.127745 0.21875,0.1875 l -11.28125,12.59375 -0.5,0.53125 -0.46875,-0.53125 -11.75,-12.3125 c 0.10903,-0.09884 0.228263,-0.201843 0.3125,-0.25 1.010846,-0.577879 6.38801,-0.916306 11.75,-0.96875 z m 18.0625,9.46875 c 2.883844,4.661341 5.612556,9.652893 5.625,10.84375 0.01348,1.290331 -3.064699,7.087557 -6.09375,12.09375 l -11.09375,-9.90625 -0.53125,-0.46875 0.5,-0.46875 11.59375,-12.09375 z m -35.78125,0.03125 10.84375,12.0625 0.4375,0.46875 -0.46875,0.4375 -10.28125,9.90625 c -3.04689,-4.86606 -6.0493623,-10.36778 -6.0625003,-11.625 -0.01271,-1.216102 2.6892393,-6.451996 5.5312503,-11.25 z m 17.875,17.78125 0.4375,0.4375 12.34375,11.59375 c -0.318014,0.365376 -0.587006,0.638955 -0.78125,0.75 -2.02169,1.155758 -21.423322,1.397228 -23.46875,0.28125 -0.228202,-0.124506 -0.601742,-0.47821 -1,-0.9375 l 12,-11.6875 0.46875,-0.4375 z"
id="coloredX" />
</svg>
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