diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | config.h.win32.in | 3 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | librsvg/rsvg-cond.c | 192 | ||||
-rw-r--r-- | librsvg/rsvg-css.c | 83 | ||||
-rw-r--r-- | librsvg/rsvg-css.h | 3 | ||||
-rw-r--r-- | librsvg/rsvg-private.h | 12 | ||||
-rw-r--r-- | librsvg/rsvg-styles.c | 47 | ||||
-rw-r--r-- | rsvg_internals/src/cond.rs | 224 | ||||
-rw-r--r-- | 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-cond.c b/librsvg/rsvg-cond.c deleted file mode 100644 index 0fd2c67b..00000000 --- a/librsvg/rsvg-cond.c +++ /dev/null @@ -1,192 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim: set sw=4 sts=4 expandtab: */ -/* - rsvg-cond.c: Handle SVG conditionals - - Copyright (C) 2004-2005 Dom Lachowicz <cinamod@hotmail.com> - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Dom Lachowicz -*/ - -#include "config.h" - -#include "rsvg-private.h" -#include "rsvg-css.h" -#include "rsvg-styles.h" - -#include <string.h> -#include <stdlib.h> -#include <locale.h> - -/* Keep these sorted alphabetically! These are used with bsearch() */ -static const char *implemented_features[] = { - "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 */ -}; -static const guint nb_implemented_features = G_N_ELEMENTS (implemented_features); - -static const char **implemented_extensions = NULL; -static const guint nb_implemented_extensions = 0; - -static int -rsvg_feature_compare (const void *a, const void *b) -{ - return strcmp ((const char *) a, *(const char **) b); -} - -/* http://www.w3.org/TR/SVG/struct.html#RequiredFeaturesAttribute */ -static gboolean -rsvg_cond_fulfills_requirement (const char *value, const char **features, guint nb_features) -{ - guint nb_elems = 0; - char **elems; - gboolean permitted = TRUE; - - elems = rsvg_css_parse_list (value, &nb_elems); - - if (elems && nb_elems) { - guint i; - - for (i = 0; (i < nb_elems) && permitted; i++) - if (!bsearch (elems[i], features, nb_features, sizeof (char *), rsvg_feature_compare)) - permitted = FALSE; - - g_strfreev (elems); - } else - permitted = FALSE; - - return permitted; -} - -/* http://www.w3.org/TR/SVG/struct.html#SystemLanguageAttribute */ -static gboolean -rsvg_locale_compare (const char *a, const char *b) -{ - const char *hyphen; - - /* check for an exact-ish match first */ - if (!g_ascii_strncasecmp (a, b, strlen (b))) - return TRUE; - - /* check to see if there's a hyphen */ - hyphen = strstr (b, "-"); - if (!hyphen) - return FALSE; - - /* compare up to the hyphen */ - return !g_ascii_strncasecmp (a, b, (hyphen - b)); -} - -/* http://www.w3.org/TR/SVG/struct.html#SystemLanguageAttribute */ -static gboolean -rsvg_cond_parse_system_language (const char *value) -{ - guint nb_elems = 0; - char **elems; - gboolean permitted = FALSE; - - elems = rsvg_css_parse_list (value, &nb_elems); - - if (elems && nb_elems) { - const gchar * const *languages; - - languages = g_get_language_names (); - - if (languages) { - guint i, j; - - for (i = 0; (i < nb_elems) && !permitted; i++) { - for (j = 0; languages[j] && !permitted; j++) { - permitted = rsvg_locale_compare (languages[j], elems[i]); - } - } - } - - g_strfreev (elems); - } - - return permitted; -} - -/* returns TRUE if this element should be processed according to <switch> semantics - http://www.w3.org/TR/SVG/struct.html#SwitchElement */ -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_fulfills_requirement (value, implemented_features, - nb_implemented_features); - has_cond = TRUE; - break; - - case RSVG_ATTRIBUTE_REQUIRED_EXTENSIONS: - required_extensions_ok = rsvg_cond_fulfills_requirement (value, implemented_extensions, - nb_implemented_extensions); - has_cond = TRUE; - break; - - case RSVG_ATTRIBUTE_SYSTEM_LANGUAGE: - system_language_ok = rsvg_cond_parse_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; -} 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; |