[librsvg] css.rs: New file; start porting the CSS processing code to Rust
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg] css.rs: New file; start porting the CSS processing code to Rust
- Date: Mon, 24 Sep 2018 23:57:06 +0000 (UTC)
commit 08f28816868878962647651118d5a1eb95d06d17
Author: Federico Mena Quintero <federico gnome org>
Date: Mon Sep 24 18:54:07 2018 -0500
css.rs: New file; start porting the CSS processing code to Rust
This commit moves the bookkeeping of CSS-derived style declarations
into Rust. The parsing code that calls libcroco is still in C.
librsvg/rsvg-handle.c | 13 +++--
librsvg/rsvg-private.h | 23 ++++++++-
librsvg/rsvg-styles.c | 104 ++++------------------------------------
librsvg/rsvg-styles.h | 3 --
rsvg_internals/src/css.rs | 111 +++++++++++++++++++++++++++++++++++++++++++
rsvg_internals/src/handle.rs | 7 +++
rsvg_internals/src/lib.rs | 5 +-
rsvg_internals/src/node.rs | 110 +++++++++++++++++-------------------------
rsvg_internals/src/state.rs | 35 +-------------
9 files changed, 206 insertions(+), 205 deletions(-)
---
diff --git a/librsvg/rsvg-handle.c b/librsvg/rsvg-handle.c
index 25eca410..912197b9 100644
--- a/librsvg/rsvg-handle.c
+++ b/librsvg/rsvg-handle.c
@@ -160,10 +160,7 @@ rsvg_handle_init (RsvgHandle * self)
self->priv->dpi_x = rsvg_internal_dpi_x;
self->priv->dpi_y = rsvg_internal_dpi_y;
- self->priv->css_props = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) g_hash_table_destroy);
+ self->priv->css_styles = rsvg_css_styles_new ();
self->priv->tree = NULL;
@@ -191,7 +188,7 @@ rsvg_handle_dispose (GObject *instance)
g_clear_pointer (&self->priv->load, rsvg_load_free);
g_clear_pointer (&self->priv->defs, rsvg_defs_free);
- g_clear_pointer (&self->priv->css_props, g_hash_table_destroy);
+ g_clear_pointer (&self->priv->css_styles, rsvg_css_styles_free);
g_clear_pointer (&self->priv->tree, rsvg_tree_free);
g_clear_pointer (&self->priv->base_uri, g_free);
g_clear_object (&self->priv->base_gfile);
@@ -1001,6 +998,12 @@ rsvg_handle_get_defs (RsvgHandle *handle)
return handle->priv->defs;
}
+RsvgCssStyles *
+rsvg_handle_get_css_styles (RsvgHandle *handle)
+{
+ return handle->priv->css_styles;
+}
+
RsvgHandle *
rsvg_handle_load_extern (RsvgHandle *handle, const char *uri)
{
diff --git a/librsvg/rsvg-private.h b/librsvg/rsvg-private.h
index 4efdebbe..5c2c61e1 100644
--- a/librsvg/rsvg-private.h
+++ b/librsvg/rsvg-private.h
@@ -83,6 +83,8 @@ typedef struct RsvgLoad RsvgLoad;
typedef struct RsvgTree RsvgTree;
+typedef struct RsvgCssStyles RsvgCssStyles;
+
struct RsvgHandlePrivate {
RsvgHandleFlags flags;
@@ -98,7 +100,7 @@ struct RsvgHandlePrivate {
RsvgDefs *defs; /* lookup table for nodes that have an id="foo" attribute */
- GHashTable *css_props;
+ RsvgCssStyles *css_styles;
GCancellable *cancellable;
@@ -188,6 +190,22 @@ gboolean rsvg_tree_root_is_svg (RsvgTree *tree);
G_GNUC_INTERNAL
void rsvg_tree_cascade (RsvgTree *tree);
+/* Implemented in rsvg_internals/src/css.rs */
+G_GNUC_INTERNAL
+RsvgCssStyles *rsvg_css_styles_new (void);
+
+/* Implemented in rsvg_internals/src/css.rs */
+G_GNUC_INTERNAL
+void rsvg_css_styles_free (RsvgCssStyles *styles);
+
+/* Implemented in rsvg_internals/src/css.rs */
+G_GNUC_INTERNAL
+void rsvg_css_styles_define (RsvgCssStyles *styles,
+ const char *selector,
+ const char *style_name,
+ const char *style_value,
+ gboolean important);
+
/* Implemented in rsvg_internals/src/structure.rs */
G_GNUC_INTERNAL
gboolean rsvg_node_svg_get_size (RsvgNode *node, double dpi_x, double dpi_y, int *out_width, int
*out_height);
@@ -294,6 +312,9 @@ RsvgNode *rsvg_defs_lookup (const RsvgDefs * defs, const char *name);
G_GNUC_INTERNAL
RsvgDefs *rsvg_handle_get_defs (RsvgHandle *handle);
+G_GNUC_INTERNAL
+RsvgCssStyles *rsvg_handle_get_css_styles (RsvgHandle *handle);
+
G_GNUC_INTERNAL
char *rsvg_handle_resolve_uri (RsvgHandle *handle,
const char *uri);
diff --git a/librsvg/rsvg-styles.c b/librsvg/rsvg-styles.c
index 005780ff..e296fb50 100644
--- a/librsvg/rsvg-styles.c
+++ b/librsvg/rsvg-styles.c
@@ -36,64 +36,6 @@
#include <libcroco/libcroco.h>
-/* Defined in rsvg_internals/src/state.rs */
-extern gboolean rsvg_state_parse_style_pair(RsvgState *state, const char *attr, const char *value, gboolean
important) G_GNUC_WARN_UNUSED_RESULT;
-
-typedef struct _StyleValueData {
- gchar *value;
- gboolean important;
-} StyleValueData;
-
-static StyleValueData *
-style_value_data_new (const gchar *value, gboolean important)
-{
- StyleValueData *ret;
-
- ret = g_new0 (StyleValueData, 1);
- ret->value = g_strdup (value);
- ret->important = important;
-
- return ret;
-}
-
-static void
-style_value_data_free (StyleValueData *value)
-{
- if (!value)
- return;
- g_free (value->value);
- g_free (value);
-}
-
-static void
-rsvg_css_define_style (RsvgHandle *handle,
- const gchar *selector,
- const gchar *style_name,
- const gchar *style_value,
- gboolean important)
-{
- GHashTable *styles;
- gboolean need_insert = FALSE;
-
- /* push name/style pair into HT */
- styles = g_hash_table_lookup (handle->priv->css_props, selector);
- if (styles == NULL) {
- styles = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, (GDestroyNotify) style_value_data_free);
- g_hash_table_insert (handle->priv->css_props, (gpointer) g_strdup (selector), styles);
- need_insert = TRUE;
- } else {
- StyleValueData *current_value;
- current_value = g_hash_table_lookup (styles, style_name);
- if (current_value == NULL || !current_value->important)
- need_insert = TRUE;
- }
- if (need_insert) {
- g_hash_table_insert (styles,
- (gpointer) g_strdup (style_name),
- (gpointer) style_value_data_new (style_value, important));
- }
-}
typedef struct _CSSUserData {
RsvgHandle *handle;
@@ -133,7 +75,7 @@ ccss_end_selector (CRDocHandler * a_handler, CRSelector * a_selector_list)
}
static void
-ccss_property (CRDocHandler * a_handler, CRString * a_name, CRTerm * a_expr, gboolean a_important)
+ccss_property (CRDocHandler * a_handler, CRString * a_name, CRTerm * a_expr, gboolean important)
{
CSSUserData *user_data;
gchar *name = NULL;
@@ -149,19 +91,19 @@ ccss_property (CRDocHandler * a_handler, CRString * a_name, CRTerm * a_expr, gbo
if (cur->simple_sel) {
gchar *selector = (gchar *) cr_simple_sel_to_string (cur->simple_sel);
if (selector) {
- gchar *style_name, *style_value;
+ gchar *prop_name, *prop_value;
name = (gchar *) cr_string_peek_raw_str (a_name);
len = cr_string_peek_raw_str_len (a_name);
- style_name = g_strndup (name, len);
- style_value = (gchar *)cr_term_to_string (a_expr);
- rsvg_css_define_style (user_data->handle,
+ prop_name = g_strndup (name, len);
+ prop_value = (gchar *)cr_term_to_string (a_expr);
+ rsvg_css_styles_define (user_data->handle->priv->css_styles,
selector,
- style_name,
- style_value,
- a_important);
+ prop_name,
+ prop_value,
+ important);
g_free (selector);
- g_free (style_name);
- g_free (style_value);
+ g_free (prop_name);
+ g_free (prop_value);
}
}
}
@@ -278,32 +220,6 @@ ccss_import_style (CRDocHandler * a_this,
g_free (mime_type);
}
-static void
-apply_style (const gchar *key, StyleValueData *value, gpointer user_data)
-{
- RsvgState *state = user_data;
-
- /* FIXME: this is ignoring errors */
- gboolean success = rsvg_state_parse_style_pair (state,
- key,
- value->value,
- value->important);
-}
-
-gboolean
-rsvg_lookup_apply_css_style (RsvgHandle *handle, const char *target, RsvgState * state)
-{
- GHashTable *styles;
-
- styles = g_hash_table_lookup (handle->priv->css_props, target);
-
- if (styles != NULL) {
- g_hash_table_foreach (styles, (GHFunc) apply_style, state);
- return TRUE;
- }
- return FALSE;
-}
-
/* This is defined like this so that we can export the Rust function... just for
* the benefit of rsvg-convert.c
*/
diff --git a/librsvg/rsvg-styles.h b/librsvg/rsvg-styles.h
index 7ba81672..7b6a3dbc 100644
--- a/librsvg/rsvg-styles.h
+++ b/librsvg/rsvg-styles.h
@@ -35,9 +35,6 @@ G_BEGIN_DECLS
G_GNUC_INTERNAL
void rsvg_parse_cssbuffer (RsvgHandle *handle, const char *buff, size_t buflen);
-G_GNUC_INTERNAL
-gboolean rsvg_lookup_apply_css_style (RsvgHandle *handle, const char *target, RsvgState * state);
-
G_END_DECLS
#endif /* RSVG_STYLES_H */
diff --git a/rsvg_internals/src/css.rs b/rsvg_internals/src/css.rs
new file mode 100644
index 00000000..09e372bd
--- /dev/null
+++ b/rsvg_internals/src/css.rs
@@ -0,0 +1,111 @@
+use std::collections::hash_map::Entry;
+use std::collections::HashMap;
+use std::str::FromStr;
+
+use libc;
+
+use glib::translate::*;
+use glib_sys;
+
+use attributes::Attribute;
+use state::State;
+use util::utf8_cstr;
+
+pub enum RsvgCssStyles {}
+
+struct Declaration {
+ prop_value: String,
+ important: bool,
+}
+
+// Maps property_name -> Declaration
+type DeclarationList = HashMap<String, Declaration>;
+
+pub struct CssStyles {
+ selectors_to_declarations: HashMap<String, DeclarationList>,
+}
+
+impl CssStyles {
+ fn new() -> CssStyles {
+ CssStyles {
+ selectors_to_declarations: HashMap::new(),
+ }
+ }
+
+ fn define(&mut self, selector: &str, prop_name: &str, prop_value: &str, important: bool) {
+ let decl_list = self
+ .selectors_to_declarations
+ .entry(selector.to_string())
+ .or_insert_with(|| DeclarationList::new());
+
+ match decl_list.entry(prop_name.to_string()) {
+ Entry::Occupied(mut e) => {
+ let decl = e.get_mut();
+
+ if !decl.important {
+ decl.prop_value = prop_value.to_string();
+ decl.important = important;
+ }
+ }
+
+ Entry::Vacant(v) => {
+ v.insert(Declaration {
+ prop_value: prop_value.to_string(),
+ important,
+ });
+ }
+ }
+ }
+
+ pub fn lookup_apply(&self, selector: &str, state: &mut State) -> bool {
+ if let Some(decl_list) = self.selectors_to_declarations.get(selector) {
+ for (prop_name, declaration) in decl_list.iter() {
+ if let Ok(attr) = Attribute::from_str(prop_name) {
+ // FIXME: this is ignoring errors
+ let _ = state.parse_style_pair(
+ attr,
+ &declaration.prop_value,
+ declaration.important,
+ );
+ }
+ }
+
+ true
+ } else {
+ false
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn rsvg_css_styles_new() -> *mut RsvgCssStyles {
+ Box::into_raw(Box::new(CssStyles::new())) as *mut RsvgCssStyles
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rsvg_css_styles_free(raw_styles: *mut RsvgCssStyles) {
+ assert!(!raw_styles.is_null());
+
+ Box::from_raw(raw_styles as *mut CssStyles);
+}
+
+#[no_mangle]
+pub extern "C" fn rsvg_css_styles_define(
+ raw_styles: *mut RsvgCssStyles,
+ selector: *const libc::c_char,
+ prop_name: *const libc::c_char,
+ prop_value: *const libc::c_char,
+ important: glib_sys::gboolean,
+) {
+ assert!(!raw_styles.is_null());
+ assert!(!selector.is_null());
+ assert!(!prop_name.is_null());
+ assert!(!prop_value.is_null());
+
+ let styles = unsafe { &mut *(raw_styles as *mut CssStyles) };
+ let selector = unsafe { utf8_cstr(selector) };
+ let prop_name = unsafe { utf8_cstr(prop_name) };
+ let prop_value = unsafe { utf8_cstr(prop_value) };
+
+ styles.define(selector, prop_name, prop_value, from_glib(important));
+}
diff --git a/rsvg_internals/src/handle.rs b/rsvg_internals/src/handle.rs
index aabaa023..c17b6bad 100644
--- a/rsvg_internals/src/handle.rs
+++ b/rsvg_internals/src/handle.rs
@@ -1,6 +1,7 @@
use glib::translate::*;
use libc;
+use css::{CssStyles, RsvgCssStyles};
use defs::{Defs, RsvgDefs};
pub enum RsvgHandle {}
@@ -18,6 +19,8 @@ extern "C" {
handle: *const RsvgHandle,
uri: *const libc::c_char,
) -> *const RsvgHandle;
+
+ fn rsvg_handle_get_css_styles(handle: *const RsvgHandle) -> *mut RsvgCssStyles;
}
pub fn get_defs<'a>(handle: *const RsvgHandle) -> &'a Defs {
@@ -41,3 +44,7 @@ pub fn resolve_uri(handle: *const RsvgHandle, uri: &str) -> Option<String> {
pub fn load_extern(handle: *const RsvgHandle, uri: &str) -> *const RsvgHandle {
unsafe { rsvg_handle_load_extern(handle, uri.to_glib_none().0) }
}
+
+pub fn get_css_styles<'a>(handle: *const RsvgHandle) -> &'a CssStyles {
+ unsafe { &*(rsvg_handle_get_css_styles(handle) as *const CssStyles) }
+}
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index d4ac2cd7..08668927 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -27,6 +27,8 @@ extern crate downcast_rs;
pub use color::{rsvg_css_parse_color, ColorKind, ColorSpec};
+pub use css::{rsvg_css_styles_define, rsvg_css_styles_free, rsvg_css_styles_new};
+
pub use defs::{rsvg_defs_free, rsvg_defs_lookup, rsvg_defs_new};
pub use drawing_ctx::{
@@ -67,8 +69,6 @@ pub use property_bag::{
rsvg_property_bag_new,
};
-pub use state::rsvg_state_parse_style_pair;
-
pub use structure::rsvg_node_svg_get_size;
pub use text::{rsvg_node_chars_append, rsvg_node_chars_new};
@@ -91,6 +91,7 @@ mod bbox;
mod clip_path;
mod color;
mod cond;
+mod css;
mod defs;
mod drawing_ctx;
mod error;
diff --git a/rsvg_internals/src/node.rs b/rsvg_internals/src/node.rs
index f0c2c810..0e394cad 100644
--- a/rsvg_internals/src/node.rs
+++ b/rsvg_internals/src/node.rs
@@ -3,7 +3,6 @@ use downcast_rs::*;
use glib;
use glib::translate::*;
use glib_sys;
-use libc;
use std::cell::{Cell, Ref, RefCell};
use std::ptr;
use std::rc::{Rc, Weak};
@@ -12,18 +11,10 @@ use attributes::Attribute;
use cond::{RequiredExtensions, RequiredFeatures, SystemLanguage};
use drawing_ctx::DrawingCtx;
use error::*;
-use handle::RsvgHandle;
+use handle::{self, RsvgHandle};
use parsers::Parse;
use property_bag::PropertyBag;
-use state::{ComputedValues, Overflow, RsvgState, SpecifiedValue, State};
-
-extern "C" {
- fn rsvg_lookup_apply_css_style(
- handle: *const RsvgHandle,
- target: *const libc::c_char,
- state: *mut RsvgState,
- ) -> glib_sys::gboolean;
-}
+use state::{ComputedValues, Overflow, SpecifiedValue, State};
// A *const RsvgNode is just a pointer for the C code's benefit: it
// points to an Rc<Node>, which is our refcounted Rust representation
@@ -451,66 +442,53 @@ impl Node {
//
// This is basically a semi-compliant CSS2 selection engine
- unsafe {
- let state_ptr = self.state.as_ptr() as *mut RsvgState;
-
- // *
- rsvg_lookup_apply_css_style(handle, "*".to_glib_none().0, state_ptr);
-
- // tag
- rsvg_lookup_apply_css_style(handle, self.element_name.to_glib_none().0, state_ptr);
-
- if let Some(klazz) = self.get_class() {
- for cls in klazz.split_whitespace() {
- let mut found = false;
-
- if !cls.is_empty() {
- // tag.class#id
- if let Some(id) = self.get_id() {
- let target = format!("{}.{}#{}", self.element_name, cls, id);
- found = found || from_glib(rsvg_lookup_apply_css_style(
- handle,
- target.to_glib_none().0,
- state_ptr,
- ));
- }
-
- // .class#id
- if let Some(id) = self.get_id() {
- let target = format!(".{}#{}", cls, id);
- found = found || from_glib(rsvg_lookup_apply_css_style(
- handle,
- target.to_glib_none().0,
- state_ptr,
- ));
- }
-
- // tag.class
- let target = format!("{}.{}", self.element_name, cls);
- found = found || from_glib(rsvg_lookup_apply_css_style(
- handle,
- target.to_glib_none().0,
- state_ptr,
- ));
-
- if !found {
- // didn't find anything more specific, just apply the class style
- let target = format!(".{}", cls);
- rsvg_lookup_apply_css_style(handle, target.to_glib_none().0, state_ptr);
- }
+ let css_styles = handle::get_css_styles(handle);
+ let mut state = self.state.borrow_mut();
+
+ // *
+ css_styles.lookup_apply("*", &mut state);
+
+ // tag
+ css_styles.lookup_apply(&self.element_name, &mut state);
+
+ if let Some(klazz) = self.get_class() {
+ for cls in klazz.split_whitespace() {
+ let mut found = false;
+
+ if !cls.is_empty() {
+ // tag.class#id
+ if let Some(id) = self.get_id() {
+ let target = format!("{}.{}#{}", self.element_name, cls, id);
+ found = found || css_styles.lookup_apply(&target, &mut state);
+ }
+
+ // .class#id
+ if let Some(id) = self.get_id() {
+ let target = format!(".{}#{}", cls, id);
+ found = found || css_styles.lookup_apply(&target, &mut state);
+ }
+
+ // tag.class
+ let target = format!("{}.{}", self.element_name, cls);
+ found = found || css_styles.lookup_apply(&target, &mut state);
+
+ if !found {
+ // didn't find anything more specific, just apply the class style
+ let target = format!(".{}", cls);
+ css_styles.lookup_apply(&target, &mut state);
}
}
}
+ }
- if let Some(id) = self.get_id() {
- // id
- let target = format!("#{}", id);
- rsvg_lookup_apply_css_style(handle, target.to_glib_none().0, state_ptr);
+ if let Some(id) = self.get_id() {
+ // id
+ let target = format!("#{}", id);
+ css_styles.lookup_apply(&target, &mut state);
- // tag#id
- let target = format!("{}#{}", self.element_name, id);
- rsvg_lookup_apply_css_style(handle, target.to_glib_none().0, state_ptr);
- }
+ // tag#id
+ let target = format!("{}#{}", self.element_name, id);
+ css_styles.lookup_apply(&target, &mut state);
}
}
diff --git a/rsvg_internals/src/state.rs b/rsvg_internals/src/state.rs
index ef1cf3da..9faa5bc1 100644
--- a/rsvg_internals/src/state.rs
+++ b/rsvg_internals/src/state.rs
@@ -1,7 +1,4 @@
use cssparser::{self, Parser, Token};
-use glib::translate::*;
-use glib_sys;
-use libc;
use std::cell::RefCell;
use std::collections::HashSet;
use std::str::FromStr;
@@ -16,7 +13,6 @@ use parsers::{Parse, ParseError};
use property_bag::PropertyBag;
use property_macros::Property;
use unitinterval::UnitInterval;
-use util::utf8_cstr;
/// Representation of a single CSS property value.
///
@@ -70,9 +66,6 @@ where
}
}
-// This is only used as *const RsvgState or *mut RsvgState, as an opaque pointer for C
-pub enum RsvgState {}
-
/// Holds the state of CSS properties
///
/// This is used for various purposes:
@@ -550,7 +543,7 @@ impl State {
Ok(())
}
- fn parse_style_pair(
+ pub fn parse_style_pair(
&mut self,
attr: Attribute,
value: &str,
@@ -1386,29 +1379,3 @@ make_property!(
"default" => Default,
"preserve" => Preserve,
);
-
-#[no_mangle]
-pub extern "C" fn rsvg_state_parse_style_pair(
- state: *mut RsvgState,
- name: *const libc::c_char,
- value: *const libc::c_char,
- important: glib_sys::gboolean,
-) -> glib_sys::gboolean {
- assert!(!state.is_null());
- let state = unsafe { &mut *(state as *mut State) };
-
- assert!(!name.is_null());
- let name = unsafe { utf8_cstr(name) };
-
- assert!(!value.is_null());
- let value = unsafe { utf8_cstr(value) };
-
- if let Ok(attr) = Attribute::from_str(name) {
- match state.parse_style_pair(attr, value, from_glib(important)) {
- Ok(_) => true.to_glib(),
- Err(_) => false.to_glib(),
- }
- } else {
- false.to_glib()
- }
-}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]