[librsvg: 1/2] Implement svg switch conditions in rust
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 1/2] Implement svg switch conditions in rust
- Date: Tue, 20 Mar 2018 01:45:29 +0000 (UTC)
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]