[librsvg] Port StrokeLinejoin parsing to Rust



commit 156d4791589b4447d7917991da98f4a9fc31219e
Author: Federico Mena Quintero <federico gnome org>
Date:   Wed Mar 21 08:28:17 2018 -0600

    Port StrokeLinejoin parsing to Rust
    
    This is an experiment in porting individual property parsers to Rust.
    The idea is to drain rsvg_parse_style_pair() gradually.
    
    Right now the C code has a lot of verbosity to handle "inherit" values
    and to overlook parsing errors.  We will remove all that in the Rust
    version.

 librsvg/rsvg-styles.c       | 31 ++++++++++++++-------
 librsvg/rsvg-styles.h       | 18 +++++++++++--
 rsvg_internals/src/draw.rs  | 15 +++++++++--
 rsvg_internals/src/lib.rs   |  2 ++
 rsvg_internals/src/state.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 118 insertions(+), 14 deletions(-)
---
diff --git a/librsvg/rsvg-styles.c b/librsvg/rsvg-styles.c
index cc337bae..453b0a30 100644
--- a/librsvg/rsvg-styles.c
+++ b/librsvg/rsvg-styles.c
@@ -524,6 +524,10 @@ typedef enum {
     PAIR_SOURCE_PRESENTATION_ATTRIBUTE
 } PairSource;
 
+/* Defined in rsvg_internals/src/state.rs */
+extern StrokeLinejoin rsvg_stroke_linejoin_get_default(void);
+extern StrokeLinejoinResult rsvg_stroke_linejoin_parse(const char *s);
+
 /* Parse a CSS2 style argument, setting the SVG context attributes. */
 static void
 rsvg_parse_style_pair (RsvgState *state,
@@ -884,15 +888,22 @@ rsvg_parse_style_pair (RsvgState *state,
 
     case RSVG_ATTRIBUTE_STROKE_LINEJOIN:
     {
-        state->has_join = TRUE;
-        if (g_str_equal (value, "miter"))
-            state->join = CAIRO_LINE_JOIN_MITER;
-        else if (g_str_equal (value, "round"))
-            state->join = CAIRO_LINE_JOIN_ROUND;
-        else if (g_str_equal (value, "bevel"))
-            state->join = CAIRO_LINE_JOIN_BEVEL;
-        else
-            g_warning (_("unknown line join style %s\n"), value);
+        StrokeLinejoinResult result = rsvg_stroke_linejoin_parse(value);
+
+        if (result.valid) {
+            if (result.linejoin == STROKE_LINEJOIN_INHERIT) {
+                /* FIXME: handle INHERIT */
+                state->has_join = FALSE;
+                state->join = rsvg_stroke_linejoin_get_default ();
+            } else {
+                state->has_join = TRUE;
+                state->join = result.linejoin;
+            }
+        } else {
+            /* FIXME: do error handling */
+            state->has_join = FALSE;
+            state->join = rsvg_stroke_linejoin_get_default ();
+        }
     }
     break;
 
@@ -1882,7 +1893,7 @@ rsvg_state_get_line_cap (RsvgState *state)
     return state->cap;
 }
 
-cairo_line_join_t
+StrokeLinejoin
 rsvg_state_get_line_join (RsvgState *state)
 {
     return state->join;
diff --git a/librsvg/rsvg-styles.h b/librsvg/rsvg-styles.h
index fe4ad1ca..1642970e 100644
--- a/librsvg/rsvg-styles.h
+++ b/librsvg/rsvg-styles.h
@@ -61,6 +61,20 @@ typedef enum {
     RSVG_ENABLE_BACKGROUND_NEW
 } RsvgEnableBackgroundType;
 
+/* Keep in sync with rsvg_internals/src/state.rs:StrokeLinejoin */
+typedef enum {
+    STROKE_LINEJOIN_MITER,
+    STROKE_LINEJOIN_ROUND,
+    STROKE_LINEJOIN_BEVEL,
+    STROKE_LINEJOIN_INHERIT
+} StrokeLinejoin;
+
+/* Keep in sync with rsvg_internals/src/state.rs:StrokeLinejoinResult */
+typedef struct {
+    gboolean valid;
+    StrokeLinejoin linejoin;
+} StrokeLinejoinResult;
+
 /* Opaque; defined in rsvg_internals/src/length.rs */
 typedef struct RsvgStrokeDasharray RsvgStrokeDasharray;
 
@@ -99,7 +113,7 @@ struct _RsvgState {
 
     cairo_line_cap_t cap;
     gboolean has_cap;
-    cairo_line_join_t join;
+    StrokeLinejoin join;
     gboolean has_join;
 
     RsvgLength font_size;
@@ -248,7 +262,7 @@ G_GNUC_INTERNAL
 cairo_line_cap_t rsvg_state_get_line_cap (RsvgState *state);
 
 G_GNUC_INTERNAL
-cairo_line_join_t rsvg_state_get_line_join (RsvgState *state);
+StrokeLinejoin rsvg_state_get_line_join (RsvgState *state);
 
 G_GNUC_INTERNAL
 gboolean rsvg_state_get_cond_true (RsvgState *state);
diff --git a/rsvg_internals/src/draw.rs b/rsvg_internals/src/draw.rs
index 5e74b144..cfc94164 100644
--- a/rsvg_internals/src/draw.rs
+++ b/rsvg_internals/src/draw.rs
@@ -11,7 +11,7 @@ use float_eq_cairo::ApproxEqCairo;
 use length::StrokeDasharray;
 use paint_server;
 use path_builder::RsvgPathBuilder;
-use state::{self, RsvgState};
+use state::{self, RsvgState, StrokeLinejoin};
 use text;
 
 pub fn draw_path_builder(draw_ctx: *mut RsvgDrawingCtx, builder: &RsvgPathBuilder, clipping: bool) {
@@ -88,11 +88,22 @@ fn stroke_and_fill(cr: &cairo::Context, draw_ctx: *mut RsvgDrawingCtx) {
     cr.new_path();
 }
 
+impl From<StrokeLinejoin> for cairo::LineJoin {
+    fn from(j: StrokeLinejoin) -> cairo::LineJoin {
+        match j {
+            StrokeLinejoin::Miter => cairo::LineJoin::Miter,
+            StrokeLinejoin::Round => cairo::LineJoin::Round,
+            StrokeLinejoin::Bevel => cairo::LineJoin::Bevel,
+            StrokeLinejoin::Inherit => unreachable!(),
+        }
+    }
+}
+
 fn setup_cr_for_stroke(cr: &cairo::Context, draw_ctx: *mut RsvgDrawingCtx, state: *mut RsvgState) {
     cr.set_line_width(state::get_stroke_width(state).normalize(draw_ctx));
     cr.set_miter_limit(state::get_miter_limit(state));
     cr.set_line_cap(state::get_line_cap(state));
-    cr.set_line_join(state::get_line_join(state));
+    cr.set_line_join(cairo::LineJoin::from(state::get_line_join(state)));
 
     let dash = state::get_stroke_dasharray(state);
 
diff --git a/rsvg_internals/src/lib.rs b/rsvg_internals/src/lib.rs
index be3d6a1d..0128416a 100644
--- a/rsvg_internals/src/lib.rs
+++ b/rsvg_internals/src/lib.rs
@@ -124,6 +124,8 @@ pub use shapes::{
 
 pub use space::rsvg_xml_space_normalize;
 
+pub use state::{rsvg_stroke_linejoin_get_default, rsvg_stroke_linejoin_parse};
+
 pub use stop::rsvg_node_stop_new;
 
 pub use structure::{
diff --git a/rsvg_internals/src/state.rs b/rsvg_internals/src/state.rs
index 919f630a..4832ad17 100644
--- a/rsvg_internals/src/state.rs
+++ b/rsvg_internals/src/state.rs
@@ -11,6 +11,8 @@ use length::{RsvgLength, StrokeDasharray};
 use node::RsvgNode;
 use opacity::{Opacity, OpacitySpec};
 use paint_server::PaintServer;
+use parsers::Parse;
+use util::utf8_cstr;
 
 pub enum RsvgState {}
 
@@ -290,3 +292,67 @@ pub fn get_fill_opacity(state: *const RsvgState) -> u8 {
 pub fn get_fill_rule(state: *const RsvgState) -> cairo::FillRule {
     unsafe { rsvg_state_get_fill_rule(state) }
 }
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub enum StrokeLinejoin {
+    Miter,
+    Round,
+    Bevel,
+    Inherit,
+}
+
+#[repr(C)]
+pub struct StrokeLinejoinResult {
+    valid: glib_sys::gboolean,
+    linejoin: StrokeLinejoin,
+}
+
+impl Default for StrokeLinejoin {
+    fn default() -> StrokeLinejoin {
+        StrokeLinejoin::Miter
+    }
+}
+
+impl Parse for StrokeLinejoin {
+    type Data = ();
+    type Err = ();
+
+    fn parse(s: &str, _: Self::Data) -> Result<StrokeLinejoin, ()> {
+        match s.trim() {
+            "miter" => Ok(StrokeLinejoin::Miter),
+            "round" => Ok(StrokeLinejoin::Round),
+            "bevel" => Ok(StrokeLinejoin::Bevel),
+            "inherit" => Ok(StrokeLinejoin::Inherit),
+            _ => Err(()),
+        }
+    }
+}
+
+impl From<Result<StrokeLinejoin, ()>> for StrokeLinejoinResult {
+    fn from(v: Result<StrokeLinejoin, ()>) -> StrokeLinejoinResult {
+        match v {
+            Ok(j) => StrokeLinejoinResult {
+                valid: true.to_glib(),
+                linejoin: j,
+            },
+
+            Err(()) => StrokeLinejoinResult {
+                valid: false.to_glib(),
+                linejoin: StrokeLinejoin::default(),
+            },
+        }
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn rsvg_stroke_linejoin_get_default() -> StrokeLinejoin {
+    StrokeLinejoin::default()
+}
+
+#[no_mangle]
+pub extern "C" fn rsvg_stroke_linejoin_parse(s: *const libc::c_char) -> StrokeLinejoinResult {
+    let s = unsafe { utf8_cstr(s) };
+
+    StrokeLinejoinResult::from(StrokeLinejoin::parse(s, ()))
+}


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