Add a cubic curve command stream.
This is a prerequisite for handling CFF fonts.
This commit is contained in:
parent
2b5dea3263
commit
0a4fcb4841
|
@ -366,7 +366,7 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
|
||||||
&control_point_1,
|
&control_point_1,
|
||||||
&endpoint_1);
|
&endpoint_1);
|
||||||
last_point = endpoint_1;
|
last_point = endpoint_1;
|
||||||
stream.extend(cubic.approximate_curve(CUBIC_ERROR_TOLERANCE)
|
stream.extend(cubic.approx_curve(CUBIC_ERROR_TOLERANCE)
|
||||||
.map(|curve| curve.to_path_segment()));
|
.map(|curve| curve.to_path_segment()));
|
||||||
}
|
}
|
||||||
'Z' => stream.push(PathCommand::ClosePath),
|
'Z' => stream.push(PathCommand::ClosePath),
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
use euclid::Point2D;
|
use euclid::Point2D;
|
||||||
|
|
||||||
use curve::Curve;
|
use curve::Curve;
|
||||||
|
use PathCommand;
|
||||||
|
|
||||||
const MAX_APPROXIMATION_ITERATIONS: u8 = 32;
|
const MAX_APPROXIMATION_ITERATIONS: u8 = 32;
|
||||||
|
|
||||||
|
@ -53,21 +54,97 @@ impl CubicCurve {
|
||||||
CubicCurve::new(&p0p1p2p3, &p1p2p3, &p2p3, &p3))
|
CubicCurve::new(&p0p1p2p3, &p1p2p3, &p2p3, &p3))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn approximate_curve(&self, error_bound: f32) -> ApproximateCurveIter {
|
pub fn approx_curve(&self, error_bound: f32) -> ApproxCurveIter {
|
||||||
ApproximateCurveIter::new(self, error_bound)
|
ApproxCurveIter::new(self, error_bound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ApproximateCurveIter {
|
/// A series of path commands that can contain cubic Bézier segments.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum CubicPathCommand {
|
||||||
|
MoveTo(Point2D<f32>),
|
||||||
|
LineTo(Point2D<f32>),
|
||||||
|
QuadCurveTo(Point2D<f32>, Point2D<f32>),
|
||||||
|
CubicCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>),
|
||||||
|
ClosePath,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CubicPathCommandApproxStream<I> {
|
||||||
|
inner: I,
|
||||||
|
error_bound: f32,
|
||||||
|
last_endpoint: Point2D<f32>,
|
||||||
|
approx_curve_iter: Option<ApproxCurveIter>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> CubicPathCommandApproxStream<I> where I: Iterator<Item = CubicPathCommand> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(inner: I, error_bound: f32) -> CubicPathCommandApproxStream<I> {
|
||||||
|
CubicPathCommandApproxStream {
|
||||||
|
inner: inner,
|
||||||
|
error_bound: error_bound,
|
||||||
|
last_endpoint: Point2D::zero(),
|
||||||
|
approx_curve_iter: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I> Iterator for CubicPathCommandApproxStream<I> where I: Iterator<Item = CubicPathCommand> {
|
||||||
|
type Item = PathCommand;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<PathCommand> {
|
||||||
|
loop {
|
||||||
|
if let Some(ref mut approx_curve_iter) = self.approx_curve_iter {
|
||||||
|
if let Some(curve) = approx_curve_iter.next() {
|
||||||
|
return Some(curve.to_path_segment())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.approx_curve_iter = None;
|
||||||
|
|
||||||
|
let next_command = match self.inner.next() {
|
||||||
|
None => return None,
|
||||||
|
Some(next_command) => next_command,
|
||||||
|
};
|
||||||
|
|
||||||
|
match next_command {
|
||||||
|
CubicPathCommand::ClosePath => {
|
||||||
|
self.last_endpoint = Point2D::zero();
|
||||||
|
return Some(PathCommand::ClosePath)
|
||||||
|
}
|
||||||
|
CubicPathCommand::MoveTo(endpoint) => {
|
||||||
|
self.last_endpoint = endpoint;
|
||||||
|
return Some(PathCommand::MoveTo(endpoint))
|
||||||
|
}
|
||||||
|
CubicPathCommand::LineTo(endpoint) => {
|
||||||
|
self.last_endpoint = endpoint;
|
||||||
|
return Some(PathCommand::LineTo(endpoint))
|
||||||
|
}
|
||||||
|
CubicPathCommand::QuadCurveTo(control_point, endpoint) => {
|
||||||
|
self.last_endpoint = endpoint;
|
||||||
|
return Some(PathCommand::CurveTo(control_point, endpoint))
|
||||||
|
}
|
||||||
|
CubicPathCommand::CubicCurveTo(control_point_0, control_point_1, endpoint) => {
|
||||||
|
let curve = CubicCurve::new(&self.last_endpoint,
|
||||||
|
&control_point_0,
|
||||||
|
&control_point_1,
|
||||||
|
&endpoint);
|
||||||
|
self.last_endpoint = endpoint;
|
||||||
|
self.approx_curve_iter = Some(ApproxCurveIter::new(&curve, self.error_bound));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ApproxCurveIter {
|
||||||
curves: Vec<CubicCurve>,
|
curves: Vec<CubicCurve>,
|
||||||
error_bound: f32,
|
error_bound: f32,
|
||||||
iteration: u8,
|
iteration: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApproximateCurveIter {
|
impl ApproxCurveIter {
|
||||||
fn new(cubic: &CubicCurve, error_bound: f32) -> ApproximateCurveIter {
|
fn new(cubic: &CubicCurve, error_bound: f32) -> ApproxCurveIter {
|
||||||
let (curve_a, curve_b) = cubic.subdivide(0.5);
|
let (curve_a, curve_b) = cubic.subdivide(0.5);
|
||||||
ApproximateCurveIter {
|
ApproxCurveIter {
|
||||||
curves: vec![curve_b, curve_a],
|
curves: vec![curve_b, curve_a],
|
||||||
error_bound: error_bound,
|
error_bound: error_bound,
|
||||||
iteration: 0,
|
iteration: 0,
|
||||||
|
@ -75,7 +152,7 @@ impl ApproximateCurveIter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for ApproximateCurveIter {
|
impl Iterator for ApproxCurveIter {
|
||||||
type Item = Curve;
|
type Item = Curve;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Curve> {
|
fn next(&mut self) -> Option<Curve> {
|
||||||
|
|
|
@ -13,7 +13,6 @@ extern crate euclid;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
use euclid::approxeq::ApproxEq;
|
|
||||||
use euclid::{Point2D, Transform2D};
|
use euclid::{Point2D, Transform2D};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
Loading…
Reference in New Issue