[librsvg/rustification] Be explicit about how stop-color and stop-opacity are inherited
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg/rustification] Be explicit about how stop-color and stop-opacity are inherited
- Date: Wed, 14 Dec 2016 03:29:30 +0000 (UTC)
commit c32694be3bf3355cb6c849577d7085173c94814e
Author: Federico Mena Quintero <federico gnome org>
Date: Tue Dec 13 20:50:56 2016 -0600
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: ...;".
rsvg-paint-server.c | 67 ++++++++++++++++++------------
rsvg-styles.c | 30 +++++++++++--
rsvg-styles.h | 15 +++++++
tests/fixtures/reftests/hexchat-ref.png | Bin 0 -> 3930 bytes
tests/fixtures/reftests/hexchat.svg | 58 ++++++++++++++++++++++++++
5 files changed, 138 insertions(+), 32 deletions(-)
---
diff --git a/rsvg-paint-server.c b/rsvg-paint-server.c
index 7f81217..07860d8 100644
--- a/rsvg-paint-server.c
+++ b/rsvg-paint-server.c
@@ -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 *
diff --git a/rsvg-styles.c b/rsvg-styles.c
index 8ad677c..d1dc54d 100644
--- a/rsvg-styles.c
+++ b/rsvg-styles.c
@@ -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);
diff --git a/rsvg-styles.h b/rsvg-styles.h
index b4d5962..8205d99 100644
--- a/rsvg-styles.h
+++ b/rsvg-styles.h
@@ -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;
diff --git a/tests/fixtures/reftests/hexchat-ref.png b/tests/fixtures/reftests/hexchat-ref.png
new file mode 100644
index 0000000..9b2bf0d
Binary files /dev/null and b/tests/fixtures/reftests/hexchat-ref.png differ
diff --git a/tests/fixtures/reftests/hexchat.svg b/tests/fixtures/reftests/hexchat.svg
new file mode 100644
index 0000000..07be27f
--- /dev/null
+++ b/tests/fixtures/reftests/hexchat.svg
@@ -0,0 +1,58 @@
+<?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.2
8125,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>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]