[librsvg] rsvg_css_parse_opacity(): Move entirely to Rust. Yay!



commit fd0f38b44436af67679335240e797e262b36aa4c
Author: Federico Mena Quintero <federico gnome org>
Date:   Wed May 31 08:26:47 2017 -0500

    rsvg_css_parse_opacity(): Move entirely to Rust. Yay!
    
    We also move RsvgOpacitySpec and RsvgOpacityKind to rsvg-css.h, to keep
    them together with RsvgColorSpec/Kind.

 Makefile.am         |    1 +
 rsvg-css.c          |   17 -----------
 rsvg-css.h          |   19 +++++++++++-
 rsvg-styles.c       |   54 +++++++++++++++++++++++++++--------
 rsvg-styles.h       |   14 ---------
 rust/src/lib.rs     |    6 ++++
 rust/src/opacity.rs |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 144 insertions(+), 45 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index cb21eac..8ac975f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -82,6 +82,7 @@ RUST_SOURCES =                                        \
        rust/src/lib.rs                         \
        rust/src/marker.rs                      \
        rust/src/node.rs                        \
+       rust/src/opacity.rs                     \
        rust/src/paint_server.rs                \
        rust/src/parsers.rs                     \
        rust/src/parse_transform.lalrpop        \
diff --git a/rsvg-css.c b/rsvg-css.c
index 097472d..ab11247 100644
--- a/rsvg-css.c
+++ b/rsvg-css.c
@@ -113,23 +113,6 @@ RsvgCssColorSpec rsvg_css_parse_color_ (const char       *str,
     return rsvg_css_parse_color (str, allow_inherit, allow_current_color);
 }
 
-guint
-rsvg_css_parse_opacity (const char *str)
-{
-    char *end_ptr = NULL;
-    double opacity;
-
-    opacity = g_ascii_strtod (str, &end_ptr);
-
-    if (((opacity == -HUGE_VAL || opacity == HUGE_VAL) && (ERANGE == errno)) ||
-        *end_ptr != '\0')
-        opacity = 1.;
-
-    opacity = CLAMP (opacity, 0., 1.);
-
-    return (guint) floor (opacity * 255. + 0.5);
-}
-
 PangoStyle
 rsvg_css_parse_font_style (const char *str, gboolean * inherit)
 {
diff --git a/rsvg-css.h b/rsvg-css.h
index 1c8beba..719820f 100644
--- a/rsvg-css.h
+++ b/rsvg-css.h
@@ -85,6 +85,23 @@ RsvgCssColorSpec rsvg_css_parse_color (const char       *str,
                                        AllowInherit      allow_inherit,
                                        AllowCurrentColor allow_current_color);
 
+/* Keep this in sync with rust/src/opacity.rs:OpacityKind */
+typedef enum {
+    RSVG_OPACITY_INHERIT,
+    RSVG_OPACITY_SPECIFIED,
+    RSVG_OPACITY_PARSE_ERROR
+} RsvgOpacityKind;
+
+/* Keep this in sync with rust/src/opacity.rs:OpacitySpec */
+typedef struct {
+    RsvgOpacityKind kind;
+    guint8 opacity; /* 0..255; only valid if kind == RSVG_OPACITY_SPECIFIED */
+} RsvgOpacitySpec;
+
+/* This is implemented in rust/src/opacity.rs */
+G_GNUC_INTERNAL
+RsvgOpacitySpec rsvg_css_parse_opacity (const char *str);
+
 /* This is implemented in rust/src/aspect_ratio.rs */
 G_GNUC_INTERNAL
 guint32 rsvg_aspect_ratio_parse (const char *str);
@@ -102,8 +119,6 @@ void rsvg_aspect_ratio_compute (guint32 aspect,
 G_GNUC_INTERNAL
 int        rsvg_css_parse_aspect_ratio     (const char *str);
 G_GNUC_INTERNAL
-guint       rsvg_css_parse_opacity         (const char *str);
-G_GNUC_INTERNAL
 PangoStyle   rsvg_css_parse_font_style      (const char *str, gboolean * inherit);
 G_GNUC_INTERNAL
 PangoVariant rsvg_css_parse_font_variant    (const char *str, gboolean * inherit);
diff --git a/rsvg-styles.c b/rsvg-styles.c
index 5ef1966..9e7502f 100644
--- a/rsvg-styles.c
+++ b/rsvg-styles.c
@@ -560,9 +560,17 @@ rsvg_parse_style_pair (RsvgState * state,
         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")) {
+    } else if (g_str_equal (name, "opacity")) {
+        RsvgOpacitySpec spec;
+
+        spec = rsvg_css_parse_opacity (value);
+        if (spec.kind == RSVG_OPACITY_SPECIFIED) {
+            state->opacity = spec.opacity;
+        } else {
+            state->opacity = 0;
+            /* FIXME: handle INHERIT and PARSE_ERROR */
+        }
+    } else if (g_str_equal (name, "flood-color")) {
         RsvgCssColorSpec spec;
 
         spec = rsvg_css_parse_color (value, ALLOW_INHERIT_YES, ALLOW_CURRENT_COLOR_YES);
@@ -591,7 +599,16 @@ rsvg_parse_style_pair (RsvgState * state,
             g_assert_not_reached ();
         }
     } else if (g_str_equal (name, "flood-opacity")) {
-        state->flood_opacity = rsvg_css_parse_opacity (value);
+        RsvgOpacitySpec spec;
+
+        spec = rsvg_css_parse_opacity (value);
+        if (spec.kind == RSVG_OPACITY_SPECIFIED) {
+            state->flood_opacity = spec.opacity;
+        } else {
+            state->flood_opacity = 0;
+            /* FIXME: handle INHERIT and PARSE_ERROR */
+        }
+
         state->has_flood_opacity = TRUE;
     } else if (g_str_equal (name, "filter")) {
         g_free (state->filter);
@@ -708,7 +725,16 @@ rsvg_parse_style_pair (RsvgState * state,
             rsvg_paint_server_parse (&state->has_fill_server, value);
         rsvg_paint_server_unref (fill);
     } else if (g_str_equal (name, "fill-opacity")) {
-        state->fill_opacity = rsvg_css_parse_opacity (value);
+        RsvgOpacitySpec spec;
+
+        spec = rsvg_css_parse_opacity (value);
+        if (spec.kind == RSVG_OPACITY_SPECIFIED) {
+            state->fill_opacity = spec.opacity;
+        } else {
+            state->fill_opacity = 0;
+            /* FIXME: handle INHERIT and PARSE_ERROR */
+        }
+
         state->has_fill_opacity = TRUE;
     } else if (g_str_equal (name, "fill-rule")) {
         state->has_fill_rule = TRUE;
@@ -747,7 +773,16 @@ rsvg_parse_style_pair (RsvgState * state,
         else
             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);
+        RsvgOpacitySpec spec;
+
+        spec = rsvg_css_parse_opacity (value);
+        if (spec.kind == RSVG_OPACITY_SPECIFIED) {
+            state->stroke_opacity = spec.opacity;
+        } else {
+            state->stroke_opacity = 0;
+            /* FIXME: handle INHERIT and PARSE_ERROR */
+        }
+
         state->has_stroke_opacity = TRUE;
     } else if (g_str_equal (name, "stroke-linejoin")) {
         state->has_join = TRUE;
@@ -852,13 +887,8 @@ rsvg_parse_style_pair (RsvgState * state,
         state->has_stop_color = TRUE;
         state->stop_color = rsvg_css_parse_color (value, ALLOW_INHERIT_YES, ALLOW_CURRENT_COLOR_YES);
     } else if (g_str_equal (name, "stop-opacity")) {
+        state->stop_opacity = rsvg_css_parse_opacity (value);
         state->has_stop_opacity = TRUE;
-        if (g_str_equal (value, "inherit")) {
-            state->stop_opacity.kind = RSVG_OPACITY_INHERIT;
-        } else {
-            state->stop_opacity.kind = RSVG_OPACITY_SPECIFIED;
-            state->stop_opacity.opacity = rsvg_css_parse_opacity (value);
-        }
     } else if (g_str_equal (name, "marker-start")) {
         g_free (state->startMarker);
         state->startMarker = rsvg_get_url_string (value, NULL);
diff --git a/rsvg-styles.h b/rsvg-styles.h
index 8dfbc74..2466ed6 100644
--- a/rsvg-styles.h
+++ b/rsvg-styles.h
@@ -62,8 +62,6 @@ typedef enum {
     RSVG_ENABLE_BACKGROUND_NEW
 } RsvgEnableBackgroundType;
 
-/* enums and data structures are ABI compatible with libart */
-
 typedef struct _RsvgVpathDash RsvgVpathDash;
 
 struct _RsvgVpathDash {
@@ -72,18 +70,6 @@ struct _RsvgVpathDash {
     double *dash;
 };
 
-typedef enum {
-    RSVG_OPACITY_INHERIT,
-    RSVG_OPACITY_SPECIFIED
-} RsvgOpacityKind;
-
-typedef struct {
-    RsvgOpacityKind kind;
-    guint8 opacity; /* 0..255; only valid if kind == RSVG_OPACITY_SPECIFIED */
-} RsvgOpacitySpec;
-
-/* end libart theft... */
-
 struct _RsvgState {
     RsvgState *parent;
     cairo_matrix_t affine;
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 7dfc25f..a4093a5 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -74,6 +74,12 @@ pub use node::{
     rsvg_node_draw_children,
 };
 
+pub use opacity::{
+    OpacityKind,
+    OpacitySpec,
+    rsvg_css_parse_opacity
+};
+
 pub use path_builder::{
     rsvg_path_builder_add_to_cairo_context
 };
diff --git a/rust/src/opacity.rs b/rust/src/opacity.rs
index 51c3bc5..6eaeb7c 100644
--- a/rust/src/opacity.rs
+++ b/rust/src/opacity.rs
@@ -2,18 +2,67 @@
 /// https://www.w3.org/TR/SVG/masking.html#OpacityProperty
 
 use ::cssparser::{Parser, Token, NumericValue};
+use ::libc;
 
 use std::str::FromStr;
 
+use ::glib::translate::*;
+
 use parsers::ParseError;
 use error::*;
 
+// Keep this in sync with rsvg-css.h:RsvgOpacityKind
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub enum OpacityKind {
+    Inherit,
+    Specified,
+    ParseError
+}
+
+// Keep this in sync with rsvg-css.h:RsvgOpacitySpec
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct OpacitySpec {
+    kind: OpacityKind,
+    opacity: u8
+}
+
+// This is the Rust version of the above
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub enum Opacity {
     Inherit,
     Specified (f64)
 }
 
+impl From<Result<Opacity, AttributeError>> for OpacitySpec {
+    fn from (result: Result<Opacity, AttributeError>) -> OpacitySpec {
+        match result {
+            Ok (Opacity::Inherit) =>
+                OpacitySpec {
+                    kind: OpacityKind::Inherit,
+                    opacity: 0
+                },
+
+            Ok (Opacity::Specified (val)) =>
+                OpacitySpec {
+                    kind: OpacityKind::Specified,
+                    opacity: opacity_to_u8 (val)
+                },
+
+            _ =>
+                OpacitySpec {
+                    kind: OpacityKind::ParseError,
+                    opacity: 0
+                }
+        }
+    }
+}
+
+fn opacity_to_u8 (val: f64) -> u8 {
+    (val * 255.0 + 0.5).floor () as u8
+}
+
 impl FromStr for Opacity {
     type Err = AttributeError;
 
@@ -51,6 +100,13 @@ impl FromStr for Opacity {
     }
 }
 
+#[no_mangle]
+pub extern fn rsvg_css_parse_opacity (string: *const libc::c_char) -> OpacitySpec {
+    let s = unsafe { String::from_glib_none (string) };
+
+    OpacitySpec::from (Opacity::from_str (&s))
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -86,4 +142,26 @@ mod tests {
         assert! (is_parse_error (&Opacity::from_str ("inherit a million dollars")));
         assert! (is_parse_error (&Opacity::from_str ("0.0foo")));
     }
+
+    fn parse (s: &str) -> OpacitySpec {
+        rsvg_css_parse_opacity (s.to_glib_none ().0)
+    }
+
+    #[test]
+    fn converts_result_to_opacity_spec () {
+        assert_eq! (parse ("inherit"),
+                    OpacitySpec { kind: OpacityKind::Inherit,
+                                  opacity: 0 });
+
+        assert_eq! (parse ("0"),
+                    OpacitySpec { kind: OpacityKind::Specified,
+                                  opacity: 0 });
+        assert_eq! (parse ("1"),
+                    OpacitySpec { kind: OpacityKind::Specified,
+                                  opacity: 255 });
+
+        assert_eq! (parse ("foo"),
+                    OpacitySpec { kind: OpacityKind::ParseError,
+                                  opacity: 0 });
+    }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]