Remove all Lyon dependencies.

We may want to re-merge at a later date, but for now all relevant algorithms
have been appropriately SIMD-ified.
This commit is contained in:
Patrick Walton 2019-02-20 16:46:50 -08:00
parent 23943c7428
commit 3a8478a048
10 changed files with 1 additions and 720 deletions

4
Cargo.lock generated
View File

@ -535,8 +535,6 @@ dependencies = [
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.19.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_geom 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_simd 0.3.0", "pathfinder_simd 0.3.0",
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1024,8 +1022,6 @@ dependencies = [
"fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "hashbrown 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "jemallocator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_geom 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lyon_path 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_geometry 0.3.0", "pathfinder_geometry 0.3.0",
"pathfinder_renderer 0.1.0", "pathfinder_renderer 0.1.0",
"pathfinder_svg 0.1.0", "pathfinder_svg 0.1.0",

View File

@ -8,8 +8,6 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
arrayvec = "0.4" arrayvec = "0.4"
bitflags = "1.0" bitflags = "1.0"
euclid = "0.19" euclid = "0.19"
lyon_geom = "0.12"
lyon_path = "0.12"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
smallvec = "0.6" smallvec = "0.6"

View File

@ -14,8 +14,6 @@ use crate::basic::point::Point2DF32;
use crate::basic::rect::RectF32; use crate::basic::rect::RectF32;
use crate::basic::transform3d::Transform3DF32; use crate::basic::transform3d::Transform3DF32;
use crate::segment::Segment; use crate::segment::Segment;
use euclid::Transform2D;
use lyon_path::PathEvent;
use pathfinder_simd::default::F32x4; use pathfinder_simd::default::F32x4;
use std::ops::Sub; use std::ops::Sub;
@ -302,50 +300,3 @@ where
} }
} }
} }
/// Transforms a path with a Euclid 2D transform.
pub struct Transform2DPathIter<I> where I: Iterator<Item = PathEvent> {
inner: I,
transform: Transform2D<f32>,
}
impl<I> Transform2DPathIter<I> where I: Iterator<Item = PathEvent> {
#[inline]
pub fn new(inner: I, transform: &Transform2D<f32>) -> Transform2DPathIter<I> {
Transform2DPathIter {
inner: inner,
transform: *transform,
}
}
}
impl<I> Iterator for Transform2DPathIter<I> where I: Iterator<Item = PathEvent> {
type Item = PathEvent;
fn next(&mut self) -> Option<PathEvent> {
match self.inner.next() {
Some(PathEvent::MoveTo(to)) => {
Some(PathEvent::MoveTo(self.transform.transform_point(&to)))
}
Some(PathEvent::LineTo(to)) => {
Some(PathEvent::LineTo(self.transform.transform_point(&to)))
}
Some(PathEvent::QuadraticTo(ctrl, to)) => {
Some(PathEvent::QuadraticTo(self.transform.transform_point(&ctrl),
self.transform.transform_point(&to)))
}
Some(PathEvent::CubicTo(ctrl1, ctrl2, to)) => {
Some(PathEvent::CubicTo(self.transform.transform_point(&ctrl1),
self.transform.transform_point(&ctrl2),
self.transform.transform_point(&to)))
}
Some(PathEvent::Arc(center, radius, start, end)) => {
Some(PathEvent::Arc(self.transform.transform_point(&center),
self.transform.transform_vector(&radius),
start,
end))
}
event => event,
}
}
}

View File

@ -15,90 +15,9 @@ use crate::outline::{Contour, PointFlags};
use crate::segment::{CubicSegment, Segment}; use crate::segment::{CubicSegment, Segment};
use crate::util::lerp; use crate::util::lerp;
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use lyon_path::PathEvent;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::mem; use std::mem;
pub struct RectClipper<'a> {
clip_rect: RectF32,
subject: &'a [PathEvent],
}
impl<'a> RectClipper<'a> {
pub fn new<'aa>(clip_rect: RectF32, subject: &'aa [PathEvent]) -> RectClipper<'aa> {
RectClipper { clip_rect, subject }
}
pub fn clip(&self) -> Vec<PathEvent> {
let mut output = self.subject.to_vec();
self.clip_against(Edge::left(self.clip_rect), &mut output);
self.clip_against(Edge::top(self.clip_rect), &mut output);
self.clip_against(Edge::right(self.clip_rect), &mut output);
self.clip_against(Edge::bottom(self.clip_rect), &mut output);
output
}
fn clip_against(&self, edge: Edge, output: &mut Vec<PathEvent>) {
let (mut from, mut path_start, mut first_point) = (Point2DF32::default(), None, false);
let input = mem::replace(output, vec![]);
for event in input {
let to = match event {
PathEvent::MoveTo(to) => {
let to = Point2DF32::from_euclid(to);
path_start = Some(to);
from = to;
first_point = true;
continue
}
PathEvent::Close => {
match path_start {
None => continue,
Some(path_start) => path_start,
}
}
PathEvent::LineTo(to) |
PathEvent::QuadraticTo(_, to) |
PathEvent::CubicTo(_, _, to) => Point2DF32::from_euclid(to),
PathEvent::Arc(..) => panic!("Arcs unsupported!"),
};
if edge.point_is_inside(&to) {
if !edge.point_is_inside(&from) {
let line_segment = LineSegmentF32::new(&from, &to);
for t in edge.intersect_line_segment(&line_segment) {
let intersection = line_segment.sample(t);
add_line(&intersection, output, &mut first_point);
}
}
add_line(&to, output, &mut first_point);
} else if edge.point_is_inside(&from) {
let line_segment = LineSegmentF32::new(&from, &to);
for t in edge.intersect_line_segment(&line_segment) {
let intersection = line_segment.sample(t);
add_line(&intersection, output, &mut first_point);
}
}
from = to;
if let PathEvent::Close = event {
output.push(PathEvent::Close);
path_start = None;
}
}
fn add_line(to: &Point2DF32, output: &mut Vec<PathEvent>, first_point: &mut bool) {
let to = to.as_euclid();
if *first_point {
output.push(PathEvent::MoveTo(to));
*first_point = false;
} else {
output.push(PathEvent::LineTo(to));
}
}
}
}
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
struct Edge(LineSegmentF32); struct Edge(LineSegmentF32);
@ -121,28 +40,6 @@ impl TEdge for Edge {
} }
} }
impl Edge {
#[inline]
fn left(rect: RectF32) -> Edge {
Edge(LineSegmentF32::new(&rect.lower_left(), &rect.origin()))
}
#[inline]
fn top(rect: RectF32) -> Edge {
Edge(LineSegmentF32::new(&rect.origin(), &rect.upper_right()))
}
#[inline]
fn right(rect: RectF32) -> Edge {
Edge(LineSegmentF32::new(&rect.upper_right(), &rect.lower_right()))
}
#[inline]
fn bottom(rect: RectF32) -> Edge {
Edge(LineSegmentF32::new(&rect.lower_right(), &rect.lower_left()))
}
}
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
enum AxisAlignedEdge { enum AxisAlignedEdge {
Left(f32), Left(f32),

View File

@ -21,7 +21,6 @@ pub mod monotonic;
pub mod orientation; pub mod orientation;
pub mod outline; pub mod outline;
pub mod segment; pub mod segment;
pub mod segments;
pub mod stroke; pub mod stroke;
pub mod util; pub mod util;

View File

@ -12,7 +12,6 @@
use crate::basic::line_segment::LineSegmentF32; use crate::basic::line_segment::LineSegmentF32;
use crate::basic::point::Point2DF32; use crate::basic::point::Point2DF32;
use lyon_path::PathEvent;
use pathfinder_simd::default::F32x4; use pathfinder_simd::default::F32x4;
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
@ -316,156 +315,3 @@ impl<'s> CubicSegment<'s> {
#[inline] #[inline]
pub fn max_y(&self) -> f32 { f32::max(self.0.baseline.max_y(), self.0.ctrl.max_y()) } pub fn max_y(&self) -> f32 { f32::max(self.0.baseline.max_y(), self.0.ctrl.max_y()) }
} }
// Lyon interoperability
pub struct PathEventsToSegments<I>
where
I: Iterator<Item = PathEvent>,
{
iter: I,
first_subpath_point: Point2DF32,
last_subpath_point: Point2DF32,
just_moved: bool,
}
impl<I> PathEventsToSegments<I>
where
I: Iterator<Item = PathEvent>,
{
#[inline]
pub fn new(iter: I) -> PathEventsToSegments<I> {
PathEventsToSegments {
iter,
first_subpath_point: Point2DF32::default(),
last_subpath_point: Point2DF32::default(),
just_moved: false,
}
}
}
impl<I> Iterator for PathEventsToSegments<I>
where
I: Iterator<Item = PathEvent>,
{
type Item = Segment;
#[inline]
fn next(&mut self) -> Option<Segment> {
match self.iter.next()? {
PathEvent::MoveTo(to) => {
let to = Point2DF32::from_euclid(to);
self.first_subpath_point = to;
self.last_subpath_point = to;
self.just_moved = true;
self.next()
}
PathEvent::LineTo(to) => {
let to = Point2DF32::from_euclid(to);
let mut segment =
Segment::line(&LineSegmentF32::new(&self.last_subpath_point, &to));
if self.just_moved {
segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH);
}
self.last_subpath_point = to;
self.just_moved = false;
Some(segment)
}
PathEvent::QuadraticTo(ctrl, to) => {
let (ctrl, to) = (Point2DF32::from_euclid(ctrl), Point2DF32::from_euclid(to));
let mut segment =
Segment::quadratic(&LineSegmentF32::new(&self.last_subpath_point, &to), &ctrl);
if self.just_moved {
segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH);
}
self.last_subpath_point = to;
self.just_moved = false;
Some(segment)
}
PathEvent::CubicTo(ctrl0, ctrl1, to) => {
let ctrl0 = Point2DF32::from_euclid(ctrl0);
let ctrl1 = Point2DF32::from_euclid(ctrl1);
let to = Point2DF32::from_euclid(to);
let mut segment = Segment::cubic(
&LineSegmentF32::new(&self.last_subpath_point, &to),
&LineSegmentF32::new(&ctrl0, &ctrl1),
);
if self.just_moved {
segment.flags.insert(SegmentFlags::FIRST_IN_SUBPATH);
}
self.last_subpath_point = to;
self.just_moved = false;
Some(segment)
}
PathEvent::Close => {
let mut segment = Segment::line(&LineSegmentF32::new(
&self.last_subpath_point,
&self.first_subpath_point,
));
segment.flags.insert(SegmentFlags::CLOSES_SUBPATH);
self.just_moved = false;
self.last_subpath_point = self.first_subpath_point;
Some(segment)
}
PathEvent::Arc(..) => panic!("TODO: arcs"),
}
}
}
pub struct SegmentsToPathEvents<I>
where
I: Iterator<Item = Segment>,
{
iter: I,
buffer: Option<PathEvent>,
}
impl<I> SegmentsToPathEvents<I>
where
I: Iterator<Item = Segment>,
{
#[inline]
pub fn new(iter: I) -> SegmentsToPathEvents<I> {
SegmentsToPathEvents { iter, buffer: None }
}
}
impl<I> Iterator for SegmentsToPathEvents<I>
where
I: Iterator<Item = Segment>,
{
type Item = PathEvent;
#[inline]
fn next(&mut self) -> Option<PathEvent> {
if let Some(event) = self.buffer.take() {
return Some(event);
}
let segment = self.iter.next()?;
if segment.flags.contains(SegmentFlags::CLOSES_SUBPATH) {
return Some(PathEvent::Close);
}
let event = match segment.kind {
SegmentKind::None => return self.next(),
SegmentKind::Line => PathEvent::LineTo(segment.baseline.to().as_euclid()),
SegmentKind::Quadratic => PathEvent::QuadraticTo(
segment.ctrl.from().as_euclid(),
segment.baseline.to().as_euclid(),
),
SegmentKind::Cubic => PathEvent::CubicTo(
segment.ctrl.from().as_euclid(),
segment.ctrl.to().as_euclid(),
segment.baseline.to().as_euclid(),
),
};
if segment.flags.contains(SegmentFlags::FIRST_IN_SUBPATH) {
self.buffer = Some(event);
Some(PathEvent::MoveTo(segment.baseline.from().as_euclid()))
} else {
Some(event)
}
}
}

View File

@ -1,262 +0,0 @@
// pathfinder/geometry/src/segments.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Returns each segment of a path.
use euclid::approxeq::ApproxEq;
use euclid::{Point2D, Vector2D};
use lyon_geom::{CubicBezierSegment, LineSegment, QuadraticBezierSegment};
use lyon_path::iterator::{PathIter, PathIterator};
use lyon_path::PathEvent;
pub struct SegmentIter<I> where I: Iterator<Item = PathEvent> {
inner: PathIter<I>,
stack: Vec<Segment>,
was_just_closed: bool,
}
impl<I> SegmentIter<I> where I: Iterator<Item = PathEvent> {
#[inline]
pub fn new(inner: I) -> SegmentIter<I> {
SegmentIter {
inner: PathIter::new(inner),
stack: vec![],
was_just_closed: true,
}
}
}
impl<I> Iterator for SegmentIter<I> where I: Iterator<Item = PathEvent> {
type Item = Segment;
fn next(&mut self) -> Option<Segment> {
if let Some(segment) = self.stack.pop() {
return Some(segment)
}
let current_point = self.inner.get_state().current;
match self.inner.next() {
None => None,
Some(PathEvent::Close) => {
self.was_just_closed = true;
let state = self.inner.get_state();
self.stack.push(Segment::EndSubpath(true));
Some(Segment::Line(LineSegment {
from: current_point,
to: state.first,
}))
}
Some(PathEvent::MoveTo(_)) => {
if self.was_just_closed {
self.was_just_closed = false;
return self.next();
}
Some(Segment::EndSubpath(false))
}
Some(PathEvent::LineTo(to)) => {
Some(Segment::Line(LineSegment {
from: current_point,
to: to,
}))
}
Some(PathEvent::QuadraticTo(ctrl, to)) => {
Some(Segment::Quadratic(QuadraticBezierSegment {
from: current_point,
ctrl: ctrl,
to: to,
}))
}
Some(PathEvent::CubicTo(ctrl1, ctrl2, to)) => {
Some(Segment::Cubic(CubicBezierSegment {
from: current_point,
ctrl1: ctrl1,
ctrl2: ctrl2,
to: to,
}))
}
Some(PathEvent::Arc(..)) => {
panic!("SegmentIter doesn't support cubics and arcs yet!")
}
}
}
}
#[derive(Clone, Copy)]
pub enum Segment {
Line(LineSegment<f32>),
Quadratic(QuadraticBezierSegment<f32>),
Cubic(CubicBezierSegment<f32>),
/// True if the subpath is closed.
EndSubpath(bool),
}
impl Segment {
pub fn flip(&self) -> Segment {
match *self {
Segment::EndSubpath(closed) => Segment::EndSubpath(closed),
Segment::Line(line_segment) => Segment::Line(line_segment.flip()),
Segment::Quadratic(quadratic_segment) => Segment::Quadratic(quadratic_segment.flip()),
Segment::Cubic(cubic_segment) => Segment::Cubic(cubic_segment.flip()),
}
}
pub fn offset<F>(&self, distance: f32, mut sink: F) where F: FnMut(&Segment) {
match *self {
Segment::EndSubpath(_) => {}
Segment::Line(ref segment) => {
sink(&Segment::Line(offset_line_segment(segment, distance)))
}
Segment::Quadratic(ref quadratic_segment) => {
// This is the Tiller & Hanson 1984 algorithm for approximate Bézier offset curves.
// We take the cage (i.e. convex hull) and push its edges out along their normals,
// then recompute the control point with a miter join.
let line_segments = (LineSegment {
from: quadratic_segment.from,
to: quadratic_segment.ctrl,
}, LineSegment {
from: quadratic_segment.ctrl,
to: quadratic_segment.to,
});
// Miter join.
let (from, intersection, to) = match offset_and_join_line_segments(line_segments.0,
line_segments.1,
distance) {
None => return sink(self),
Some(intersection) => intersection,
};
sink(&Segment::Quadratic(QuadraticBezierSegment {
from: from,
ctrl: intersection,
to: to,
}))
}
Segment::Cubic(ref cubic_segment) if points_overlap(&cubic_segment.from,
&cubic_segment.ctrl1) => {
// As above.
let line_segments = (LineSegment {
from: cubic_segment.from,
to: cubic_segment.ctrl2,
}, LineSegment {
from: cubic_segment.ctrl2,
to: cubic_segment.to,
});
// Miter join.
let (from, intersection, to) = match offset_and_join_line_segments(line_segments.0,
line_segments.1,
distance) {
None => return sink(self),
Some(intersection) => intersection,
};
sink(&Segment::Cubic(CubicBezierSegment {
from: from,
ctrl1: from,
ctrl2: intersection,
to: to,
}))
}
Segment::Cubic(ref cubic_segment) if points_overlap(&cubic_segment.ctrl2,
&cubic_segment.to) => {
// As above.
let line_segments = (LineSegment {
from: cubic_segment.from,
to: cubic_segment.ctrl1,
}, LineSegment {
from: cubic_segment.ctrl1,
to: cubic_segment.to,
});
// Miter join.
let (from, intersection, to) = match offset_and_join_line_segments(line_segments.0,
line_segments.1,
distance) {
None => return sink(self),
Some(intersection) => intersection,
};
sink(&Segment::Cubic(CubicBezierSegment {
from: from,
ctrl1: intersection,
ctrl2: to,
to: to,
}))
}
Segment::Cubic(ref cubic_segment) => {
// As above.
let line_segments = (LineSegment {
from: cubic_segment.from,
to: cubic_segment.ctrl1,
}, LineSegment {
from: cubic_segment.ctrl1,
to: cubic_segment.ctrl2,
}, LineSegment {
from: cubic_segment.ctrl2,
to: cubic_segment.to,
});
let (from, intersection_0, _) =
match offset_and_join_line_segments(line_segments.0,
line_segments.1,
distance) {
None => return sink(self),
Some(intersection) => intersection,
};
let (_, intersection_1, to) = match offset_and_join_line_segments(line_segments.1,
line_segments.2,
distance) {
None => return sink(self),
Some(intersection) => intersection,
};
sink(&Segment::Cubic(CubicBezierSegment {
from: from,
ctrl1: intersection_0,
ctrl2: intersection_1,
to: to,
}))
}
}
}
}
fn offset_line_segment(segment: &LineSegment<f32>, distance: f32) -> LineSegment<f32> {
let mut segment = *segment;
let vector = segment.to_vector();
if vector.square_length() < f32::approx_epsilon() {
return segment
}
let tangent = vector.normalize() * distance;
segment.translate(Vector2D::new(-tangent.y, tangent.x))
}
// Performs a miter join.
fn offset_and_join_line_segments(mut line_segment_0: LineSegment<f32>,
mut line_segment_1: LineSegment<f32>,
distance: f32)
-> Option<(Point2D<f32>, Point2D<f32>, Point2D<f32>)> {
line_segment_0 = offset_line_segment(&line_segment_0, distance);
line_segment_1 = offset_line_segment(&line_segment_1, distance);
match line_segment_0.to_line().intersection(&line_segment_1.to_line()) {
None => None,
Some(intersection) => Some((line_segment_0.from, intersection, line_segment_1.to)),
}
}
fn points_overlap(a: &Point2D<f32>, b: &Point2D<f32>) -> bool {
a.x.approx_eq(&b.x) && a.y.approx_eq(&b.y)
}

View File

@ -14,144 +14,8 @@ use crate::basic::line_segment::LineSegmentF32;
use crate::basic::rect::RectF32; use crate::basic::rect::RectF32;
use crate::outline::{Contour, Outline}; use crate::outline::{Contour, Outline};
use crate::segment::Segment as SegmentPF3; use crate::segment::Segment as SegmentPF3;
use crate::segments::{Segment, SegmentIter};
use lyon_path::PathEvent;
use lyon_path::iterator::PathIterator;
use std::mem; use std::mem;
#[derive(Clone, Copy, Debug)]
pub struct StrokeStyle {
pub width: f32,
}
impl StrokeStyle {
#[inline]
pub fn new(width: f32) -> StrokeStyle {
StrokeStyle {
width: width,
}
}
}
pub struct StrokeToFillIter<I> where I: PathIterator {
inner: SegmentIter<I>,
subpath: Vec<Segment>,
stack: Vec<PathEvent>,
state: StrokeToFillState,
style: StrokeStyle,
first_point_in_subpath: bool,
}
impl<I> StrokeToFillIter<I> where I: PathIterator {
#[inline]
pub fn new(inner: I, style: StrokeStyle) -> StrokeToFillIter<I> {
StrokeToFillIter {
inner: SegmentIter::new(inner),
subpath: vec![],
stack: vec![],
state: StrokeToFillState::Forward,
style: style,
first_point_in_subpath: true,
}
}
}
impl<I> Iterator for StrokeToFillIter<I> where I: PathIterator {
type Item = PathEvent;
// TODO(pcwalton): Support miter and round joins. This will probably require the inner iterator
// to be `Peekable`, I guess.
fn next(&mut self) -> Option<PathEvent> {
// If we have path events queued, return the latest.
if let Some(path_event) = self.stack.pop() {
return Some(path_event)
}
// Fetch the next segment.
let next_segment = match self.state {
StrokeToFillState::Forward => {
match self.inner.next() {
None | Some(Segment::EndSubpath(false)) => {
if self.subpath.is_empty() {
return None
}
self.state = StrokeToFillState::Backward;
return self.next()
}
Some(Segment::EndSubpath(true)) => {
if self.subpath.is_empty() {
return None
}
self.state = StrokeToFillState::Backward;
self.first_point_in_subpath = true;
return Some(PathEvent::Close)
}
Some(segment) => {
self.subpath.push(segment);
segment
}
}
}
StrokeToFillState::Backward => {
match self.subpath.pop() {
None | Some(Segment::EndSubpath(_)) => {
self.state = StrokeToFillState::Forward;
self.first_point_in_subpath = true;
return Some(PathEvent::Close)
}
Some(segment) => segment.flip(),
}
}
};
next_segment.offset(self.style.width * 0.5, |offset_segment| {
match *offset_segment {
Segment::EndSubpath(_) => unreachable!(),
Segment::Line(ref offset_segment) => {
if self.first_point_in_subpath {
self.first_point_in_subpath = false;
self.stack.push(PathEvent::MoveTo(offset_segment.from))
} else if self.stack.is_empty() {
self.stack.push(PathEvent::LineTo(offset_segment.from))
}
self.stack.push(PathEvent::LineTo(offset_segment.to))
}
Segment::Quadratic(ref offset_segment) => {
if self.first_point_in_subpath {
self.first_point_in_subpath = false;
self.stack.push(PathEvent::MoveTo(offset_segment.from))
} else if self.stack.is_empty() {
self.stack.push(PathEvent::LineTo(offset_segment.from))
}
self.stack.push(PathEvent::QuadraticTo(offset_segment.ctrl, offset_segment.to))
}
Segment::Cubic(ref offset_segment) => {
if self.first_point_in_subpath {
self.first_point_in_subpath = false;
self.stack.push(PathEvent::MoveTo(offset_segment.from))
} else if self.stack.is_empty() {
self.stack.push(PathEvent::LineTo(offset_segment.from))
}
self.stack.push(PathEvent::CubicTo(offset_segment.ctrl1,
offset_segment.ctrl2,
offset_segment.to))
}
}
});
self.stack.reverse();
return self.next()
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
enum StrokeToFillState {
Forward,
Backward,
}
// Pathfinder 3
pub struct OutlineStrokeToFill { pub struct OutlineStrokeToFill {
pub outline: Outline, pub outline: Outline,
pub radius: f32, pub radius: f32,

View File

@ -10,14 +10,12 @@
//! Converts a subset of SVG to a Pathfinder scene. //! Converts a subset of SVG to a Pathfinder scene.
use lyon_path::iterator::PathIter;
use pathfinder_geometry::basic::line_segment::LineSegmentF32; use pathfinder_geometry::basic::line_segment::LineSegmentF32;
use pathfinder_geometry::basic::point::Point2DF32; use pathfinder_geometry::basic::point::Point2DF32;
use pathfinder_geometry::basic::rect::RectF32; use pathfinder_geometry::basic::rect::RectF32;
use pathfinder_geometry::basic::transform2d::{Transform2DF32, Transform2DF32PathIter}; use pathfinder_geometry::basic::transform2d::{Transform2DF32, Transform2DF32PathIter};
use pathfinder_geometry::outline::Outline; use pathfinder_geometry::outline::Outline;
use pathfinder_geometry::segment::{PathEventsToSegments, Segment}; use pathfinder_geometry::segment::{Segment, SegmentFlags};
use pathfinder_geometry::segment::{SegmentFlags, SegmentsToPathEvents};
use pathfinder_geometry::stroke::OutlineStrokeToFill; use pathfinder_geometry::stroke::OutlineStrokeToFill;
use pathfinder_renderer::paint::{ColorU, Paint}; use pathfinder_renderer::paint::{ColorU, Paint};
use pathfinder_renderer::scene::{PathObject, PathObjectKind, Scene}; use pathfinder_renderer::scene::{PathObject, PathObjectKind, Scene};
@ -91,10 +89,6 @@ fn process_node(scene: &mut Scene, node: &Node, transform: &Transform2DF32) {
f32::max(stroke.width.value() as f32, HAIRLINE_STROKE_WIDTH); f32::max(stroke.width.value() as f32, HAIRLINE_STROKE_WIDTH);
let path = UsvgPathToSegments::new(path.segments.iter().cloned()); let path = UsvgPathToSegments::new(path.segments.iter().cloned());
/*let path = SegmentsToPathEvents::new(path);
let path = PathIter::new(path);
let path = StrokeToFillIter::new(path, StrokeStyle::new(stroke_width));
let path = PathEventsToSegments::new(path);*/
let path = Transform2DF32PathIter::new(path, &transform); let path = Transform2DF32PathIter::new(path, &transform);
let outline = Outline::from_segments(path); let outline = Outline::from_segments(path);

View File

@ -15,8 +15,6 @@ euclid = "0.19"
fixedbitset = "0.1" fixedbitset = "0.1"
hashbrown = "0.1" hashbrown = "0.1"
jemallocator = "0.1" jemallocator = "0.1"
lyon_geom = "0.12"
lyon_path = "0.12"
rayon = "1.0" rayon = "1.0"
svgtypes = "0.3" svgtypes = "0.3"
usvg = "0.4" usvg = "0.4"