summaryrefslogtreecommitdiff
path: root/src/utils.rs
diff options
context:
space:
mode:
authorRazrFalcon <razrfalcon@gmail.com>2018-11-07 20:03:06 +0200
committerRazrFalcon <razrfalcon@gmail.com>2018-11-07 20:03:06 +0200
commitf5c28ec82fe7d762ac4538808da4cc7862b61248 (patch)
tree413cfef37075def5813328960be9dfd9eb29162a /src/utils.rs
parent244f30fec7c1233e063616fc436b8125c074029e (diff)
(cairo-backend) Fixed rendering of a zero length subpath with a square cap.
Diffstat (limited to 'src/utils.rs')
-rw-r--r--src/utils.rs63
1 files changed, 63 insertions, 0 deletions
diff --git a/src/utils.rs b/src/utils.rs
index d27e243..d9bc440 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -160,6 +160,69 @@ pub fn path_bbox(
(minx as f64, miny as f64, width as f64, height as f64).into()
}
+/// Calculates path's length.
+///
+/// Length from the first segment to the first MoveTo, ClosePath or slice end.
+pub fn path_length(segments: &[usvg::PathSegment]) -> f64 {
+ debug_assert!(!segments.is_empty());
+
+ use lyon_geom;
+
+ let (mut prev_x, mut prev_y) = {
+ if let usvg::PathSegment::MoveTo { x, y } = segments[0] {
+ (x as f32, y as f32)
+ } else {
+ panic!("first segment must be MoveTo");
+ }
+ };
+
+ let start_x = prev_x;
+ let start_y = prev_y;
+
+ let mut is_first_seg = true;
+ let mut length = 0.0f64;
+ for seg in segments {
+ match *seg {
+ usvg::PathSegment::MoveTo { .. } => {
+ if !is_first_seg {
+ break;
+ }
+ }
+ usvg::PathSegment::LineTo { x, y } => {
+ length += Line::new(prev_x as f64, prev_y as f64, x, y).length();
+
+ prev_x = x as f32;
+ prev_y = y as f32;
+ }
+ usvg::PathSegment::CurveTo { x1, y1, x2, y2, x, y } => {
+ let x = x as f32;
+ let y = y as f32;
+
+ let curve = lyon_geom::CubicBezierSegment {
+ from: lyon_geom::math::Point::new(prev_x, prev_y),
+ ctrl1: lyon_geom::math::Point::new(x1 as f32, y1 as f32),
+ ctrl2: lyon_geom::math::Point::new(x2 as f32, y2 as f32),
+ to: lyon_geom::math::Point::new(x, y),
+ };
+
+ length += curve.approximate_length(1.0) as f64;
+
+ prev_x = x;
+ prev_y = y;
+ }
+ usvg::PathSegment::ClosePath => {
+ length += Line::new(prev_x as f64, prev_y as f64,
+ start_x as f64, start_y as f64).length();
+ break;
+ }
+ }
+
+ is_first_seg = false;
+ }
+
+ length
+}
+
/// Applies the transform to the path segments.
pub fn transform_path(segments: &mut [usvg::PathSegment], ts: &usvg::Transform) {
for seg in segments {