use crate::events::PathEvent;
use crate::geom::{Arc, ArcFlags, SvgArc, LineSegment, traits::Transformation};
use crate::math::*;
use crate::polygon::Polygon;
use crate::path::Verb;
use crate::{EndpointId, Winding};
use std::marker::Sized;
use std::iter::IntoIterator;
#[derive(Copy, Clone)]
pub struct BorderRadii {
pub top_left: f32,
pub top_right: f32,
pub bottom_left: f32,
pub bottom_right: f32,
}
impl BorderRadii {
pub fn new(radius: f32) -> Self {
let r = radius.abs();
BorderRadii {
top_left: r,
top_right: r,
bottom_left: r,
bottom_right: r,
}
}
}
pub trait PathBuilder {
fn begin(&mut self, at: Point) -> EndpointId;
fn end(&mut self, close: bool);
fn close(&mut self) {
self.end(true)
}
fn line_to(&mut self, to: Point) -> EndpointId;
fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) -> EndpointId;
fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) -> EndpointId;
fn reserve(&mut self, _endpoints: usize, _ctrl_points: usize) {}
fn path_event(&mut self, event: PathEvent) {
match event {
PathEvent::Begin { at } => {
self.begin(at);
}
PathEvent::Line { to, .. } => {
self.line_to(to);
}
PathEvent::Quadratic { ctrl, to, .. } => {
self.quadratic_bezier_to(ctrl, to);
}
PathEvent::Cubic { ctrl1, ctrl2, to, .. } => {
self.cubic_bezier_to(ctrl1, ctrl2, to);
}
PathEvent::End { close, .. } => {
self.end(close);
}
}
}
fn extend<Evts>(&mut self, events: Evts)
where
Evts: IntoIterator<Item = PathEvent>
{
for evt in events.into_iter() {
self.path_event(evt)
}
}
fn add_polygon(&mut self, polygon: Polygon<Point>) {
if polygon.points.is_empty() {
return;
}
self.reserve(polygon.points.len(), 0);
self.begin(polygon.points[0]);
for p in &polygon.points[1..] {
self.line_to(*p);
}
self.end(polygon.closed);
}
fn add_point(&mut self, at: Point) -> EndpointId {
let id = self.begin(at);
self.end(false);
id
}
fn add_line_segment(&mut self, line: &LineSegment<f32>) -> (EndpointId, EndpointId) {
let a = self.begin(line.from);
let b = self.line_to(line.to);
self.end(false);
(a, b)
}
fn add_ellipse(&mut self, center: Point, radii: Vector, x_rotation: Angle, winding: Winding) {
let dir = match winding {
Winding::Positive => 1.0,
Winding::Negative => -1.0,
};
use std::f32::consts::PI;
let arc = Arc {
center,
radii,
x_rotation,
start_angle: Angle::radians(0.0),
sweep_angle: Angle::radians(2.0 * PI) * dir,
};
self.begin(arc.sample(0.0));
arc.for_each_quadratic_bezier(&mut |curve| {
self.quadratic_bezier_to(curve.ctrl, curve.to);
});
self.end(true);
}
fn add_circle(&mut self, center: Point, radius: f32, winding: Winding)
where
Self: Sized
{
add_circle(self, center, radius, winding);
}
fn add_rectangle(&mut self, rect: &Rect, winding: Winding) {
match winding {
Winding::Positive => self.add_polygon(Polygon {
points: &[
rect.min(),
point(rect.max_x(), rect.min_y()),
rect.max(),
point(rect.min_x(), rect.max_y()),
],
closed: true,
}),
Winding::Negative => self.add_polygon(Polygon {
points: &[
rect.min(),
point(rect.min_x(), rect.max_y()),
rect.max(),
point(rect.max_x(), rect.min_y()),
],
closed: true,
}),
};
}
fn add_rounded_rectangle(&mut self, rect: &Rect, radii: &BorderRadii, winding: Winding)
where
Self: Sized
{
add_rounded_rectangle(self, rect, radii, winding);
}
fn flattened(self, tolerance: f32) -> Flattened<Self>
where
Self: Sized,
{
Flattened::new(self, tolerance)
}
fn transformed<Transform>(self, transform: Transform) -> Transformed<Self, Transform>
where
Self: Sized,
Transform: Transformation<f32>
{
Transformed::new(self, transform)
}
fn with_svg(self) -> WithSvg<Self>
where
Self: Sized,
{
WithSvg::new(self)
}
}
pub trait SvgPathBuilder {
fn move_to(&mut self, to: Point);
fn close(&mut self);
fn line_to(&mut self, to: Point);
fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point);
fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point);
fn relative_move_to(&mut self, to: Vector);
fn relative_line_to(&mut self, to: Vector);
fn relative_quadratic_bezier_to(&mut self, ctrl: Vector, to: Vector);
fn relative_cubic_bezier_to(&mut self, ctrl1: Vector, ctrl2: Vector, to: Vector);
fn smooth_cubic_bezier_to(&mut self, ctrl2: Point, to: Point);
fn smooth_relative_cubic_bezier_to(&mut self, ctrl2: Vector, to: Vector);
fn smooth_quadratic_bezier_to(&mut self, to: Point);
fn smooth_relative_quadratic_bezier_to(&mut self, to: Vector);
fn horizontal_line_to(&mut self, x: f32);
fn relative_horizontal_line_to(&mut self, dx: f32);
fn vertical_line_to(&mut self, y: f32);
fn relative_vertical_line_to(&mut self, dy: f32);
fn arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Point);
fn relative_arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Vector);
fn reserve(&mut self, _endpoints: usize, _ctrl_points: usize) {}
fn add_polygon(&mut self, polygon: Polygon<Point>) {
if polygon.points.is_empty() {
return;
}
self.reserve(polygon.points.len(), 0);
self.move_to(polygon.points[0]);
for p in &polygon.points[1..] {
self.line_to(*p);
}
if polygon.closed {
self.close();
}
}
}
pub trait Build {
type PathType;
fn build(self) -> Self::PathType;
}
pub struct Flattened<Builder> {
builder: Builder,
current_position: Point,
tolerance: f32,
}
impl<Builder: Build> Build for Flattened<Builder> {
type PathType = Builder::PathType;
fn build(self) -> Builder::PathType {
self.builder.build()
}
}
impl<Builder: PathBuilder> PathBuilder for Flattened<Builder> {
fn begin(&mut self, at: Point) -> EndpointId {
self.current_position = at;
self.builder.begin(at)
}
fn end(&mut self, close: bool) {
self.builder.end(close)
}
fn line_to(&mut self, to: Point) -> EndpointId {
let id = self.builder.line_to(to);
self.current_position = to;
id
}
fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) -> EndpointId {
let id = crate::private::flatten_quadratic_bezier(self.tolerance, self.current_position, ctrl, to, self);
self.current_position = to;
id
}
fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) -> EndpointId {
let id = crate::private::flatten_cubic_bezier(self.tolerance, self.current_position, ctrl1, ctrl2, to, self);
self.current_position = to;
id
}
fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
self.builder.reserve(endpoints + ctrl_points * 4, 0);
}
}
impl<Builder: PathBuilder> Flattened<Builder> {
pub fn new(builder: Builder, tolerance: f32) -> Flattened<Builder> {
Flattened {
builder,
current_position: point(0.0, 0.0),
tolerance,
}
}
pub fn build(self) -> Builder::PathType where Builder: Build {
self.builder.build()
}
pub fn set_tolerance(&mut self, tolerance: f32) {
self.tolerance = tolerance
}
}
pub struct Transformed<Builder, Transform> {
builder: Builder,
transform: Transform,
}
impl<Builder, Transform> Transformed<Builder, Transform> {
#[inline]
pub fn new(builder: Builder, transform: Transform) -> Self {
Transformed {
builder,
transform,
}
}
#[inline]
pub fn set_transform(&mut self, transform: Transform) {
self.transform = transform;
}
}
impl<Builder: Build, Transform> Build for Transformed<Builder, Transform> {
type PathType = Builder::PathType;
#[inline]
fn build(self) -> Builder::PathType {
self.builder.build()
}
}
impl<Builder, Transform> PathBuilder for Transformed<Builder, Transform>
where
Builder: PathBuilder,
Transform: Transformation<f32>,
{
#[inline]
fn begin(&mut self, at: Point) -> EndpointId {
self.builder.begin(self.transform.transform_point(at))
}
#[inline]
fn end(&mut self, close: bool) {
self.builder.end(close)
}
#[inline]
fn line_to(&mut self, to: Point) -> EndpointId {
self.builder.line_to(self.transform.transform_point(to))
}
#[inline]
fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) -> EndpointId {
self.builder.quadratic_bezier_to(
self.transform.transform_point(ctrl),
self.transform.transform_point(to),
)
}
#[inline]
fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) -> EndpointId {
self.builder.cubic_bezier_to(
self.transform.transform_point(ctrl1),
self.transform.transform_point(ctrl2),
self.transform.transform_point(to),
)
}
#[inline]
fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
self.builder.reserve(endpoints, ctrl_points);
}
}
pub struct WithSvg<Builder: PathBuilder> {
builder: Builder,
first_position: Point,
current_position: Point,
last_ctrl: Point,
last_cmd: Verb,
need_moveto: bool,
is_empty: bool,
}
impl<Builder: PathBuilder> WithSvg<Builder> {
pub fn new(builder: Builder) -> Self {
WithSvg {
builder,
first_position: point(0.0, 0.0),
current_position: point(0.0, 0.0),
last_ctrl: point(0.0, 0.0),
need_moveto: true,
is_empty: true,
last_cmd: Verb::End,
}
}
pub fn build(mut self) -> Builder::PathType where Builder: Build {
self.end_if_needed();
self.builder.build()
}
pub fn flattened(self, tolerance: f32) -> WithSvg<Flattened<Builder>> {
WithSvg::new(Flattened::new(self.builder, tolerance))
}
pub fn transformed<Transform>(self, transform: Transform) -> WithSvg<Transformed<Builder, Transform>>
where
Transform: Transformation<f32>
{
WithSvg::new(Transformed::new(self.builder, transform))
}
pub fn move_to(&mut self, to: Point) -> EndpointId {
self.end_if_needed();
let id = self.builder.begin(to);
self.is_empty = false;
self.need_moveto = false;
self.first_position = to;
self.current_position = to;
self.last_cmd = Verb::Begin;
id
}
pub fn line_to(&mut self, to: Point) -> EndpointId {
if let Some(id) = self.begin_if_needed(&to) {
return id;
}
self.current_position = to;
self.last_cmd = Verb::LineTo;
self.builder.line_to(to)
}
pub fn close(&mut self) {
if self.need_moveto {
return;
}
self.current_position = self.first_position;
self.need_moveto = true;
self.last_cmd = Verb::Close;
self.builder.close();
}
pub fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) -> EndpointId {
if let Some(id) = self.begin_if_needed(&to) {
return id;
}
self.current_position = to;
self.last_cmd = Verb::QuadraticTo;
self.last_ctrl = ctrl;
self.builder.quadratic_bezier_to(ctrl, to)
}
pub fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) -> EndpointId {
if let Some(id) = self.begin_if_needed(&to) {
return id;
}
self.current_position = to;
self.last_cmd = Verb::CubicTo;
self.last_ctrl = ctrl2;
self.builder.cubic_bezier_to(ctrl1, ctrl2, to)
}
pub fn arc(&mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle) {
nan_check(center);
nan_check(radii.to_point());
debug_assert!(!sweep_angle.get().is_nan());
debug_assert!(!x_rotation.get().is_nan());
let start_angle = (self.current_position - center).angle_from_x_axis() - x_rotation;
let arc = Arc {
start_angle,
center,
radii,
sweep_angle,
x_rotation,
};
let arc_start = arc.from();
if self.need_moveto {
self.move_to(arc_start);
} else if (arc_start - self.current_position).square_length() < 0.01 {
self.builder.line_to(arc_start);
}
arc.for_each_quadratic_bezier(&mut |curve| {
self.builder.quadratic_bezier_to(curve.ctrl, curve.to);
});
self.last_ctrl = self.current_position;
}
#[inline(always)]
fn begin_if_needed(&mut self, default: &Point) -> Option<EndpointId> {
if self.need_moveto {
return self.insert_move_to(default)
}
None
}
#[inline(never)]
fn insert_move_to(&mut self, default: &Point) -> Option<EndpointId> {
if self.is_empty {
return Some(self.move_to(*default))
}
self.move_to(self.first_position);
None
}
fn end_if_needed(&mut self) {
if (self.last_cmd as u8) <= (Verb::Begin as u8) {
self.builder.end(false);
}
}
pub fn current_position(&self) -> Point {
self.current_position
}
pub fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
self.builder.reserve(endpoints, ctrl_points);
}
fn get_smooth_cubic_ctrl(&self) -> Point {
match self.last_cmd {
Verb::CubicTo => self.current_position + (self.current_position - self.last_ctrl),
_ => self.current_position,
}
}
fn get_smooth_quadratic_ctrl(&self) -> Point {
match self.last_cmd {
Verb::QuadraticTo => self.current_position + (self.current_position - self.last_ctrl),
_ => self.current_position,
}
}
fn relative_to_absolute(&self, v: Vector) -> Point {
self.current_position + v
}
}
impl<Builder, Transform> WithSvg<Transformed<Builder, Transform>>
where
Builder: PathBuilder,
Transform: Transformation<f32>,
{
#[inline]
pub fn set_transform(&mut self, transform: Transform) {
self.builder.set_transform(transform);
}
}
impl<Builder: PathBuilder + Build> Build for WithSvg<Builder> {
type PathType = Builder::PathType;
fn build(mut self) -> Builder::PathType {
self.end_if_needed();
self.builder.build()
}
}
impl<Builder: PathBuilder> SvgPathBuilder for WithSvg<Builder> {
fn move_to(&mut self, to: Point) {
self.move_to(to);
}
fn line_to(&mut self, to: Point) {
self.line_to(to);
}
fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) {
self.quadratic_bezier_to(ctrl, to);
}
fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) {
self.cubic_bezier_to(ctrl1, ctrl2, to);
}
fn close(&mut self) {
self.close();
}
fn relative_move_to(&mut self, to: Vector) {
let to = self.relative_to_absolute(to);
self.move_to(to);
}
fn relative_line_to(&mut self, to: Vector) {
let to = self.relative_to_absolute(to);
self.line_to(to);
}
fn relative_quadratic_bezier_to(&mut self, ctrl: Vector, to: Vector) {
let ctrl = self.relative_to_absolute(ctrl);
let to = self.relative_to_absolute(to);
self.builder.quadratic_bezier_to(ctrl, to);
}
fn relative_cubic_bezier_to(&mut self, ctrl1: Vector, ctrl2: Vector, to: Vector) {
let to = self.relative_to_absolute(to);
let ctrl1 = self.relative_to_absolute(ctrl1);
let ctrl2 = self.relative_to_absolute(ctrl2);
self.cubic_bezier_to(ctrl1, ctrl2, to);
}
fn smooth_cubic_bezier_to(&mut self, ctrl2: Point, to: Point) {
let ctrl1 = self.get_smooth_cubic_ctrl();
self.cubic_bezier_to(ctrl1, ctrl2, to);
}
fn smooth_relative_cubic_bezier_to(&mut self, ctrl2: Vector, to: Vector) {
let ctrl1 = self.get_smooth_cubic_ctrl();
let ctrl2 = self.relative_to_absolute(ctrl2);
let to = self.relative_to_absolute(to);
self.cubic_bezier_to(ctrl1, ctrl2, to);
}
fn smooth_quadratic_bezier_to(&mut self, to: Point) {
let ctrl = self.get_smooth_quadratic_ctrl();
self.quadratic_bezier_to(ctrl, to);
}
fn smooth_relative_quadratic_bezier_to(&mut self, to: Vector) {
let ctrl = self.get_smooth_quadratic_ctrl();
let to = self.relative_to_absolute(to);
self.quadratic_bezier_to(ctrl, to);
}
fn horizontal_line_to(&mut self, x: f32) {
let y = self.current_position.y;
self.line_to(point(x, y));
}
fn relative_horizontal_line_to(&mut self, dx: f32) {
let p = self.current_position;
self.line_to(point(p.x + dx, p.y));
}
fn vertical_line_to(&mut self, y: f32) {
let x = self.current_position.x;
self.line_to(point(x, y));
}
fn relative_vertical_line_to(&mut self, dy: f32) {
let p = self.current_position;
self.line_to(point(p.x, p.y + dy));
}
fn arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Point) {
let arc = SvgArc {
from: self.current_position,
to,
radii,
x_rotation,
flags: ArcFlags {
large_arc: flags.large_arc,
sweep: flags.sweep,
},
}.to_arc();
self.arc(arc.center, arc.radii, arc.sweep_angle, arc.x_rotation);
}
fn relative_arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Vector) {
let to = self.relative_to_absolute(to);
self.arc_to(radii, x_rotation, flags, to);
}
fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
self.builder.reserve(endpoints, ctrl_points);
}
}
fn add_circle<Builder: PathBuilder>(
builder: &mut Builder,
center: Point,
radius: f32,
winding: Winding,
) {
let radius = radius.abs();
let dir = match winding {
Winding::Positive => 1.0,
Winding::Negative => -1.0,
};
let tan_pi_over_8 = 0.41421356237;
let cos_pi_over_4 = 0.70710678118;
let d = radius * tan_pi_over_8;
builder.begin(center + vector(-radius, 0.0));
let ctrl_0 = center + vector(-radius, -d * dir);
let mid_0 = center + vector(-1.0, -dir) * radius * cos_pi_over_4;
let ctrl_1 = center + vector(-d, -radius * dir);
let mid_1 = center + vector(0.0, -radius * dir);
builder.quadratic_bezier_to(ctrl_0, mid_0);
builder.quadratic_bezier_to(ctrl_1, mid_1);
let ctrl_0 = center + vector(d, -radius * dir);
let mid_0 = center + vector(1.0, -dir) * radius * cos_pi_over_4;
let ctrl_1 = center + vector(radius, -d * dir);
let mid_1 = center + vector(radius, 0.0);
builder.quadratic_bezier_to(ctrl_0, mid_0);
builder.quadratic_bezier_to(ctrl_1, mid_1);
let ctrl_0 = center + vector(radius, d * dir);
let mid_0 = center + vector(1.0, dir) * radius * cos_pi_over_4;
let ctrl_1 = center + vector(d, radius * dir);
let mid_1 = center + vector(0.0, radius * dir);
builder.quadratic_bezier_to(ctrl_0, mid_0);
builder.quadratic_bezier_to(ctrl_1, mid_1);
let ctrl_0 = center + vector(-d, radius * dir);
let mid_0 = center + vector(-1.0, dir) * radius * cos_pi_over_4;
let ctrl_1 = center + vector(-radius, d * dir);
let mid_1 = center + vector(-radius, 0.0);
builder.quadratic_bezier_to(ctrl_0, mid_0);
builder.quadratic_bezier_to(ctrl_1, mid_1);
builder.close();
}
fn add_rounded_rectangle<Builder: PathBuilder>(
builder: &mut Builder,
rect: &Rect,
radii: &BorderRadii,
winding: Winding,
) {
let w = rect.size.width;
let h = rect.size.height;
let x_min = rect.min_x();
let y_min = rect.min_y();
let x_max = rect.max_x();
let y_max = rect.max_y();
let min_wh = w.min(h);
let mut tl = radii.top_left.abs().min(min_wh);
let mut tr = radii.top_right.abs().min(min_wh);
let mut bl = radii.bottom_left.abs().min(min_wh);
let mut br = radii.bottom_right.abs().min(min_wh);
if tl + tr > w {
let x = (tl + tr - w) * 0.5;
tl -= x;
tr -= x;
}
if bl + br > w {
let x = (bl + br - w) * 0.5;
bl -= x;
br -= x;
}
if tr + br > h {
let x = (tr + br - h) * 0.5;
tr -= x;
br -= x;
}
if tl + bl > h {
let x = (tl + bl - h) * 0.5;
tl -= x;
bl -= x;
}
let tan_pi_over_8 = 0.41421356237;
let cos_pi_over_4 = 0.70710678118;
let tl_d = tl * tan_pi_over_8;
let tl_corner = point(x_min, y_min);
let tr_d = tr * tan_pi_over_8;
let tr_corner = point(x_max, y_min);
let br_d = br * tan_pi_over_8;
let br_corner = point(x_max, y_max);
let bl_d = bl * tan_pi_over_8;
let bl_corner = point(x_min, y_max);
let points = [
point(x_min, y_min + tl),
tl_corner + vector(0.0, tl - tl_d),
tl_corner + vector(1.0, 1.0) * tl * (1.0 - cos_pi_over_4),
tl_corner + vector(tl - tl_d, 0.0),
tl_corner + vector(tl, 0.0),
point(x_max - tr, y_min),
tr_corner + vector(-tr + tr_d, 0.0),
tr_corner + vector(-1.0, 1.0) * tr * (1.0 - cos_pi_over_4),
tr_corner + vector(0.0, tr - tr_d),
tr_corner + vector(0.0, tr),
point(x_max, y_max - br),
br_corner + vector(0.0, -br + br_d),
br_corner + vector(-1.0, -1.0) * br * (1.0 - cos_pi_over_4),
br_corner + vector(-br + br_d, 0.0),
br_corner + vector(-br, 0.0),
point(x_min + bl, y_max),
bl_corner + vector(bl - bl_d, 0.0),
bl_corner + vector(1.0, -1.0) * bl * (1.0 - cos_pi_over_4),
bl_corner + vector(0.0, -bl + bl_d),
bl_corner + vector(0.0, -bl),
];
if winding == Winding::Positive {
builder.begin(points[0]);
if tl > 0.0 {
builder.quadratic_bezier_to(points[1], points[2]);
builder.quadratic_bezier_to(points[3], points[4]);
}
builder.line_to(points[5]);
if tl > 0.0 {
builder.quadratic_bezier_to(points[6], points[7]);
builder.quadratic_bezier_to(points[8], points[9]);
}
builder.line_to(points[10]);
if br > 0.0 {
builder.quadratic_bezier_to(points[11], points[12]);
builder.quadratic_bezier_to(points[13], points[14]);
}
builder.line_to(points[15]);
if bl > 0.0 {
builder.quadratic_bezier_to(points[16], points[17]);
builder.quadratic_bezier_to(points[18], points[19]);
}
builder.end(true);
} else {
builder.begin(points[19]);
if bl > 0.0 {
builder.quadratic_bezier_to(points[18], points[17]);
builder.quadratic_bezier_to(points[16], points[15]);
}
builder.line_to(points[14]);
if br > 0.0 {
builder.quadratic_bezier_to(points[13], points[12]);
builder.quadratic_bezier_to(points[11], points[10]);
}
builder.line_to(points[9]);
if tl > 0.0 {
builder.quadratic_bezier_to(points[8], points[7]);
builder.quadratic_bezier_to(points[6], points[5]);
}
builder.line_to(points[4]);
if tl > 0.0 {
builder.quadratic_bezier_to(points[3], points[2]);
builder.quadratic_bezier_to(points[1], points[0]);
}
builder.end(true);
}
}
#[inline]
fn nan_check(p: Point) {
debug_assert!(p.x.is_finite());
debug_assert!(p.y.is_finite());
}
#[test]
fn svg_builder_line_to_after_close() {
use crate::Path;
use crate::PathEvent;
let mut p = Path::svg_builder();
p.line_to(point(1.0, 0.0));
p.close();
p.line_to(point(2.0, 0.0));
let path = p.build();
let mut it = path.iter();
assert_eq!(
it.next(),
Some(PathEvent::Begin {
at: point(1.0, 0.0)
})
);
assert_eq!(
it.next(),
Some(PathEvent::End {
last: point(1.0, 0.0),
first: point(1.0, 0.0),
close: true
})
);
assert_eq!(
it.next(),
Some(PathEvent::Begin {
at: point(1.0, 0.0)
})
);
assert_eq!(
it.next(),
Some(PathEvent::Line {
from: point(1.0, 0.0),
to: point(2.0, 0.0)
})
);
assert_eq!(
it.next(),
Some(PathEvent::End {
last: point(2.0, 0.0),
first: point(1.0, 0.0),
close: false
})
);
assert_eq!(it.next(), None);
}