[librsvg/rustification] Be explicit about how stop-color and stop-opacity are inherited



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]