[librsvg: 1/2] Implement svg switch conditions in rust



commit 2eb933da6d271dcbb7a07c02150af8577cc07242
Author: Paolo Borelli <borellip amazon com>
Date:   Sat Mar 17 15:33:49 2018 +0100

    Implement svg switch conditions in rust

 Makefile.am                |   1 -
 config.h.win32.in          |   3 -
 configure.ac               |   4 -
 librsvg/rsvg-cond.c        | 192 --------------------------------------
 librsvg/rsvg-css.c         |  83 -----------------
 librsvg/rsvg-css.h         |   3 -
 librsvg/rsvg-private.h     |  12 ++-
 librsvg/rsvg-styles.c      |  47 ++++++++++
 rsvg_internals/src/cond.rs | 224 +++++++++++++++++++++++++++++++++++++++++++++
 rsvg_internals/src/lib.rs  |   7 ++
 10 files changed, 289 insertions(+), 287 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index cd7324a1..fafacd96 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -34,7 +34,6 @@ librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
        librsvg/rsvg-cairo-render.c             \
        librsvg/rsvg-cairo-render.h             \
        librsvg/rsvg-cairo.h                    \
-       librsvg/rsvg-cond.c                     \
        librsvg/rsvg-css.c                      \
        librsvg/rsvg-css.h                      \
        librsvg/rsvg-defs.c                     \
diff --git a/config.h.win32.in b/config.h.win32.in
index 7d4ee6b6..7cfdd175 100644
--- a/config.h.win32.in
+++ b/config.h.win32.in
@@ -39,9 +39,6 @@
 /* Define to 1 if you have the <string.h> header file. */
 #define HAVE_STRING_H 1
 
-/* Define to 1 if you have the `strtok_r' function. */
-/* #undef HAVE_STRTOK_R */
-
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #define HAVE_SYS_STAT_H 1
 
diff --git a/configure.ac b/configure.ac
index 4a653d0d..63b10627 100644
--- a/configure.ac
+++ b/configure.ac
@@ -151,10 +151,6 @@ esac
 
 GLIB_TESTS
 
-dnl ===========================================================================
-
-AC_CHECK_FUNCS(strtok_r)
-
 # ===========================================================================
 # GTK
 # ===========================================================================
diff --git a/librsvg/rsvg-css.c b/librsvg/rsvg-css.c
index 467fb363..17e3ae96 100644
--- a/librsvg/rsvg-css.c
+++ b/librsvg/rsvg-css.c
@@ -254,89 +254,6 @@ rsvg_css_parse_font_family (const char *str, gboolean * inherit)
         return str;
 }
 
-#if !defined(HAVE_STRTOK_R)
-
-static char *
-strtok_r (char *s, const char *delim, char **last)
-{
-    char *p;
-
-    if (s == NULL)
-        s = *last;
-
-    if (s == NULL)
-        return NULL;
-
-    while (*s && strchr (delim, *s))
-        s++;
-
-    if (*s == '\0') {
-        *last = NULL;
-        return NULL;
-    }
-
-    p = s;
-    while (*p && !strchr (delim, *p))
-        p++;
-
-    if (*p == '\0')
-        *last = NULL;
-    else {
-        *p = '\0';
-        p++;
-        *last = p;
-    }
-
-    return s;
-}
-
-#endif                          /* !HAVE_STRTOK_R */
-
-gchar **
-rsvg_css_parse_list (const char *in_str, guint * out_list_len)
-{
-    char *ptr, *tok;
-    char *str;
-
-    guint n = 0;
-    GSList *string_list = NULL;
-    gchar **string_array = NULL;
-
-    str = g_strdup (in_str);
-    tok = strtok_r (str, ", \t", &ptr);
-    if (tok != NULL) {
-        if (strcmp (tok, " ") != 0) {
-            string_list = g_slist_prepend (string_list, g_strdup (tok));
-            n++;
-        }
-
-        while ((tok = strtok_r (NULL, ", \t", &ptr)) != NULL) {
-            if (strcmp (tok, " ") != 0) {
-                string_list = g_slist_prepend (string_list, g_strdup (tok));
-                n++;
-            }
-        }
-    }
-    g_free (str);
-
-    if (out_list_len)
-        *out_list_len = n;
-
-    if (string_list) {
-        GSList *slist;
-
-        string_array = g_new0 (gchar *, n + 1);
-
-        string_array[n--] = NULL;
-        for (slist = string_list; slist; slist = slist->next)
-            string_array[n--] = (gchar *) slist->data;
-
-        g_slist_free (string_list);
-    }
-
-    return string_array;
-}
-
 gboolean
 rsvg_css_parse_overflow (const char *str, gboolean * inherit)
 {
diff --git a/librsvg/rsvg-css.h b/librsvg/rsvg-css.h
index 088521da..3ada0f08 100644
--- a/librsvg/rsvg-css.h
+++ b/librsvg/rsvg-css.h
@@ -104,9 +104,6 @@ const char  *rsvg_css_parse_font_family         (const char *str, gboolean * inherit
 G_GNUC_INTERNAL
 gboolean rsvg_css_parse_number_optional_number (const char *str, double *out_x, double *out_y);
 
-G_GNUC_INTERNAL
-gchar       **rsvg_css_parse_list           (const char *in_str, guint * out_list_len);
-
 /* Keep in sync with rust/src/parsers.rs:NumberListLength */
 typedef enum {
     NUMBER_LIST_LENGTH_EXACT,
diff --git a/librsvg/rsvg-private.h b/librsvg/rsvg-private.h
index 0ce62284..e529d3ca 100644
--- a/librsvg/rsvg-private.h
+++ b/librsvg/rsvg-private.h
@@ -472,8 +472,18 @@ GdkPixbuf *rsvg_pixbuf_from_data_with_size_data (const guchar * buff,
                                                  size_t len,
                                                  gpointer data,
                                                  const char *base_uri, GError ** error);
+
+/* Implemented in rust/src/cond.rs */
+G_GNUC_INTERNAL
+gboolean rsvg_cond_check_required_features (const char *value);
+
+/* Implemented in rust/src/cond.rs */
+G_GNUC_INTERNAL
+gboolean rsvg_cond_check_required_extensions (const char *value);
+
+/* Implemented in rust/src/cond.rs */
 G_GNUC_INTERNAL
-gboolean     rsvg_eval_switch_attributes       (RsvgPropertyBag * atts, gboolean * p_has_cond);
+gboolean rsvg_cond_check_system_language (const char *value);
 
 G_GNUC_INTERNAL
 void rsvg_pop_discrete_layer    (RsvgDrawingCtx * ctx);
diff --git a/librsvg/rsvg-styles.c b/librsvg/rsvg-styles.c
index 4932aeed..cc337bae 100644
--- a/librsvg/rsvg-styles.c
+++ b/librsvg/rsvg-styles.c
@@ -1173,6 +1173,53 @@ rsvg_parse_style_pair (RsvgState *state,
     }
 }
 
+/* returns TRUE if this element should be processed according to <switch> semantics
+   http://www.w3.org/TR/SVG/struct.html#SwitchElement */
+static gboolean
+rsvg_eval_switch_attributes (RsvgPropertyBag * atts, gboolean * p_has_cond)
+{
+    gboolean required_features_ok = TRUE;
+    gboolean required_extensions_ok = TRUE;
+    gboolean system_language_ok = TRUE;
+    gboolean has_cond = FALSE;
+
+    RsvgPropertyBagIter *iter;
+    const char *key;
+    RsvgAttribute attr;
+    const char *value;
+
+    iter = rsvg_property_bag_iter_begin (atts);
+
+    while (rsvg_property_bag_iter_next (iter, &key, &attr, &value)) {
+        switch (attr) {
+        case RSVG_ATTRIBUTE_REQUIRED_FEATURES:
+            required_features_ok = rsvg_cond_check_required_features (value);
+            has_cond = TRUE;
+            break;
+
+        case RSVG_ATTRIBUTE_REQUIRED_EXTENSIONS:
+            required_extensions_ok = rsvg_cond_check_required_extensions (value);
+            has_cond = TRUE;
+            break;
+
+        case RSVG_ATTRIBUTE_SYSTEM_LANGUAGE:
+            system_language_ok = rsvg_cond_check_system_language (value);
+            has_cond = TRUE;
+            break;
+
+        default:
+            break;
+        }
+    }
+
+    rsvg_property_bag_iter_end (iter);
+
+    if (p_has_cond)
+        *p_has_cond = has_cond;
+
+    return required_features_ok && required_extensions_ok && system_language_ok;
+}
+
 /* take a pair of the form (fill="#ff00ff") and parse it as a style */
 void
 rsvg_parse_presentation_attributes (RsvgState * state, RsvgPropertyBag * atts)
diff --git a/rsvg_internals/src/cond.rs b/rsvg_internals/src/cond.rs
new file mode 100644
index 00000000..f9c4d315
--- /dev/null
+++ b/rsvg_internals/src/cond.rs
@@ -0,0 +1,224 @@
+use glib;
+use glib_sys;
+use libc;
+
+use error::*;
+use parsers::Parse;
+use std::marker::PhantomData;
+use util::utf8_cstr;
+
+use self::glib::translate::*;
+
+// No extensions at the moment.
+static IMPLEMENTED_EXTENSIONS: &[&str] = &[];
+
+#[derive(Debug, PartialEq)]
+struct RequiredExtensions(bool);
+
+impl Parse for RequiredExtensions {
+    type Data = ();
+    type Err = AttributeError;
+
+    // Parse a requiredExtensions attribute
+    // http://www.w3.org/TR/SVG/struct.html#RequiredExtensionsAttribute
+    fn parse(s: &str, _: ()) -> Result<RequiredExtensions, AttributeError> {
+        Ok(RequiredExtensions(
+            s.split_whitespace()
+                .all(|f| IMPLEMENTED_EXTENSIONS.binary_search(&f).is_ok()),
+        ))
+    }
+}
+
+// Keep these sorted alphabetically for binary_search.
+static IMPLEMENTED_FEATURES: &[&str] = &[
+    "http://www.w3.org/TR/SVG11/feature#BasicFilter";,
+    "http://www.w3.org/TR/SVG11/feature#BasicGraphicsAttribute";,
+    "http://www.w3.org/TR/SVG11/feature#BasicPaintAttribute";,
+    "http://www.w3.org/TR/SVG11/feature#BasicStructure";,
+    "http://www.w3.org/TR/SVG11/feature#BasicText";,
+    "http://www.w3.org/TR/SVG11/feature#ConditionalProcessing";,
+    "http://www.w3.org/TR/SVG11/feature#ContainerAttribute";,
+    "http://www.w3.org/TR/SVG11/feature#Filter";,
+    "http://www.w3.org/TR/SVG11/feature#Gradient";,
+    "http://www.w3.org/TR/SVG11/feature#Image";,
+    "http://www.w3.org/TR/SVG11/feature#Marker";,
+    "http://www.w3.org/TR/SVG11/feature#Mask";,
+    "http://www.w3.org/TR/SVG11/feature#OpacityAttribute";,
+    "http://www.w3.org/TR/SVG11/feature#Pattern";,
+    "http://www.w3.org/TR/SVG11/feature#SVG";,
+    "http://www.w3.org/TR/SVG11/feature#SVG-static";,
+    "http://www.w3.org/TR/SVG11/feature#Shape";,
+    "http://www.w3.org/TR/SVG11/feature#Structure";,
+    "http://www.w3.org/TR/SVG11/feature#Style";,
+    "http://www.w3.org/TR/SVG11/feature#View";,
+    "org.w3c.svg.static", // deprecated SVG 1.0 feature string
+];
+
+#[derive(Debug, PartialEq)]
+struct RequiredFeatures(bool);
+
+impl Parse for RequiredFeatures {
+    type Data = ();
+    type Err = AttributeError;
+
+    // Parse a requiredFeatures attribute
+    // http://www.w3.org/TR/SVG/struct.html#RequiredFeaturesAttribute
+    fn parse(s: &str, _: ()) -> Result<RequiredFeatures, AttributeError> {
+        Ok(RequiredFeatures(
+            s.split_whitespace()
+                .all(|f| IMPLEMENTED_FEATURES.binary_search(&f).is_ok()),
+        ))
+    }
+}
+
+#[derive(Debug, PartialEq)]
+struct SystemLanguage<'a>(bool, PhantomData<&'a i8>);
+
+impl<'a> Parse for SystemLanguage<'a> {
+    type Data = &'a [String];
+    type Err = AttributeError;
+
+    // Parse a systemLanguage attribute
+    // http://www.w3.org/TR/SVG/struct.html#SystemLanguageAttribute
+    fn parse(s: &str, system_languages: &[String]) -> Result<SystemLanguage<'a>, AttributeError> {
+        Ok(SystemLanguage(
+            s.split(',')
+                .map(|s| s.trim())
+                .filter(|s| !s.is_empty())
+                .any(|l| {
+                    system_languages.iter().any(|sl| {
+                        if sl.eq_ignore_ascii_case(l) {
+                            return true;
+                        }
+
+                        if let Some(offset) = l.find('-') {
+                            return sl.eq_ignore_ascii_case(&l[..offset]);
+                        }
+
+                        false
+                    })
+                }),
+            PhantomData,
+        ))
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn rsvg_cond_check_required_extensions(
+    raw_value: *const libc::c_char,
+) -> glib_sys::gboolean {
+    let value = unsafe { utf8_cstr(raw_value) };
+
+    match RequiredExtensions::parse(value, ()) {
+        Ok(RequiredExtensions(res)) => res.to_glib(),
+        Err(_) => false.to_glib(),
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn rsvg_cond_check_required_features(
+    raw_value: *const libc::c_char,
+) -> glib_sys::gboolean {
+    let value = unsafe { utf8_cstr(raw_value) };
+
+    match RequiredFeatures::parse(value, ()) {
+        Ok(RequiredFeatures(res)) => res.to_glib(),
+        Err(_) => false.to_glib(),
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn rsvg_cond_check_system_language(
+    raw_value: *const libc::c_char,
+) -> glib_sys::gboolean {
+    let value = unsafe { utf8_cstr(raw_value) };
+
+    match SystemLanguage::parse(value, &glib::get_language_names()) {
+        Ok(SystemLanguage(res, _)) => res.to_glib(),
+        Err(_) => false.to_glib(),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn parse_required_extensions() {
+        assert_eq!(
+            RequiredExtensions::parse("http://test.org/NotExisting/1.0";, ()),
+            Ok(RequiredExtensions(false))
+        );
+    }
+
+    #[test]
+    fn parse_required_features() {
+        assert_eq!(
+            RequiredFeatures::parse("http://www.w3.org/TR/SVG11/feature#NotExisting";, ()),
+            Ok(RequiredFeatures(false))
+        );
+
+        assert_eq!(
+            RequiredFeatures::parse("http://www.w3.org/TR/SVG11/feature#BasicFilter";, ()),
+            Ok(RequiredFeatures(true))
+        );
+
+        assert_eq!(
+            RequiredFeatures::parse(
+                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
+                 http://www.w3.org/TR/SVG11/feature#NotExisting";,
+                ()
+            ),
+            Ok(RequiredFeatures(false))
+        );
+
+        assert_eq!(
+            RequiredFeatures::parse(
+                "http://www.w3.org/TR/SVG11/feature#BasicFilter \
+                 http://www.w3.org/TR/SVG11/feature#BasicText";,
+                ()
+            ),
+            Ok(RequiredFeatures(true))
+        );
+    }
+
+    #[test]
+    fn parse_system_language() {
+        let system_languages = vec![String::from("de"), String::from("en_US")];
+
+        assert_eq!(
+            SystemLanguage::parse("", &system_languages),
+            Ok(SystemLanguage(false, PhantomData))
+        );
+
+        assert_eq!(
+            SystemLanguage::parse("fr", &system_languages),
+            Ok(SystemLanguage(false, PhantomData))
+        );
+
+        assert_eq!(
+            SystemLanguage::parse("de", &system_languages),
+            Ok(SystemLanguage(true, PhantomData))
+        );
+
+        assert_eq!(
+            SystemLanguage::parse("en_US", &system_languages),
+            Ok(SystemLanguage(true, PhantomData))
+        );
+
+        assert_eq!(
+            SystemLanguage::parse("DE", &system_languages),
+            Ok(SystemLanguage(true, PhantomData))
+        );
+
+        assert_eq!(
+            SystemLanguage::parse("de-LU", &system_languages),
+            Ok(SystemLanguage(true, PhantomData))
+        );
+
+        assert_eq!(
+            SystemLanguage::parse("fr, de", &system_languages),
+            Ok(SystemLanguage(true, PhantomData))
+        );
+    }
+}
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index 282b349c..be3d6a1d 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -33,6 +33,12 @@ pub use cnode::{rsvg_rust_cnode_get_impl, rsvg_rust_cnode_new};
 
 pub use color::{rsvg_css_parse_color, AllowCurrentColor, AllowInherit, ColorKind, ColorSpec};
 
+pub use cond::{
+    rsvg_cond_check_required_extensions,
+    rsvg_cond_check_required_features,
+    rsvg_cond_check_system_language,
+};
+
 pub use draw::{rsvg_draw_pango_layout, rsvg_draw_path_builder};
 
 pub use gradient::{rsvg_node_linear_gradient_new, rsvg_node_radial_gradient_new};
@@ -149,6 +155,7 @@ mod chars;
 mod clip_path;
 mod cnode;
 mod color;
+mod cond;
 mod draw;
 mod drawing_ctx;
 mod error;


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