1 | //! The default path data structure. |
2 | //! |
3 | |
4 | use crate::builder::*; |
5 | use crate::geom::traits::Transformation; |
6 | use crate::geom::{CubicBezierSegment, QuadraticBezierSegment}; |
7 | use crate::iterator::NoAttributes as IterNoAttributes; |
8 | use crate::math::*; |
9 | use crate::private::DebugValidator; |
10 | use crate::{ |
11 | AttributeStore, Attributes, ControlPointId, EndpointId, Event, IdEvent, PathEvent, |
12 | PositionStore, NO_ATTRIBUTES, |
13 | }; |
14 | |
15 | use core::fmt; |
16 | use core::iter::{FromIterator, IntoIterator}; |
17 | use core::u32; |
18 | |
19 | use alloc::boxed::Box; |
20 | use alloc::vec; |
21 | use alloc::vec::Vec; |
22 | |
23 | /// Enumeration corresponding to the [Event](https://docs.rs/lyon_core/*/lyon_core/events/enum.Event.html) enum |
24 | /// without the parameters. |
25 | /// |
26 | /// This is used by the [Path](struct.Path.html) data structure to store path events a tad |
27 | /// more efficiently. |
28 | #[derive (Copy, Clone, Debug, PartialEq, Eq)] |
29 | #[cfg_attr (feature = "serialization" , derive(Serialize, Deserialize))] |
30 | pub(crate) enum Verb { |
31 | LineTo, |
32 | QuadraticTo, |
33 | CubicTo, |
34 | Begin, |
35 | Close, |
36 | End, |
37 | } |
38 | |
39 | /// A simple path data structure. |
40 | /// |
41 | /// # Custom attributes |
42 | /// |
43 | /// Paths can store a fixed number of extra `f32` values per endpoint, called |
44 | /// "custom attributes" or "interpolated attributes" through the documentation. |
45 | /// These can be handy to represent arbitrary attributes such as variable colors, |
46 | /// line width, etc. |
47 | /// |
48 | /// See also: |
49 | /// - [`BuilderWithAttributes`](struct.BuilderWithAttributes.html). |
50 | /// - [`Path::builder_with_attributes`](struct.Path.html#method.builder_with_attributes). |
51 | /// - [`Path::attributes`](struct.Path.html#method.attributes). |
52 | /// |
53 | /// # Representation |
54 | /// |
55 | /// Paths contain two buffers: |
56 | /// - a buffer of commands (Begin, Line, Quadratic, Cubic, Close or End), |
57 | /// - and a buffer of pairs of floats that can be endpoints control points or custom attributes. |
58 | /// |
59 | /// The order of storage for points is determined by the sequence of commands. |
60 | /// Custom attributes (if any) always directly follow endpoints. If there is an odd number |
61 | /// of attributes, the last float of the each attribute sequence is set to zero and is not used. |
62 | /// |
63 | /// ```ascii |
64 | /// __________________________ |
65 | /// | | | | |
66 | /// | Begin | Line |Quadratic| ... |
67 | /// |_______|______|_________|_ |
68 | /// __________________________________________________________________________ |
69 | /// | | | | | | | | |
70 | /// |start x,y|attributes| to x, y |attributes|ctrl x,y | to x, y |attributes| ... |
71 | /// |_________|__________|_________|__________|_________|_________|__________|_ |
72 | /// ``` |
73 | /// |
74 | #[derive (Clone, Default)] |
75 | #[cfg_attr (feature = "serialization" , derive(Serialize, Deserialize))] |
76 | pub struct Path { |
77 | points: Box<[Point]>, |
78 | verbs: Box<[Verb]>, |
79 | num_attributes: usize, |
80 | } |
81 | |
82 | /// A view on a `Path`. |
83 | #[derive (Copy, Clone)] |
84 | pub struct PathSlice<'l> { |
85 | pub(crate) points: &'l [Point], |
86 | pub(crate) verbs: &'l [Verb], |
87 | pub(crate) num_attributes: usize, |
88 | } |
89 | |
90 | pub type Builder = NoAttributes<BuilderImpl>; |
91 | |
92 | impl Path { |
93 | /// Creates a [Builder](struct.Builder.html) to build a path. |
94 | pub fn builder() -> Builder { |
95 | NoAttributes::wrap(BuilderImpl::new()) |
96 | } |
97 | |
98 | /// Creates a [BuilderWithAttributes](struct.BuilderWithAttributes.html) to build a path |
99 | /// with custom attributes. |
100 | pub fn builder_with_attributes(num_attributes: usize) -> BuilderWithAttributes { |
101 | BuilderWithAttributes::new(num_attributes) |
102 | } |
103 | |
104 | /// Creates an [WithSvg](../builder/struct.WithSvg.html) to build a path |
105 | /// with a rich set of commands. |
106 | pub fn svg_builder() -> WithSvg<BuilderImpl> { |
107 | WithSvg::new(BuilderImpl::new()) |
108 | } |
109 | |
110 | /// Creates an Empty `Path`. |
111 | #[inline ] |
112 | pub fn new() -> Path { |
113 | Path { |
114 | points: Box::new([]), |
115 | verbs: Box::new([]), |
116 | num_attributes: 0, |
117 | } |
118 | } |
119 | |
120 | #[inline ] |
121 | pub fn with_attributes(num_attributes: usize) -> Path { |
122 | Path { |
123 | points: Box::new([]), |
124 | verbs: Box::new([]), |
125 | num_attributes, |
126 | } |
127 | } |
128 | |
129 | /// Returns a view on this `Path`. |
130 | #[inline ] |
131 | pub fn as_slice(&self) -> PathSlice { |
132 | PathSlice { |
133 | points: &self.points[..], |
134 | verbs: &self.verbs[..], |
135 | num_attributes: self.num_attributes, |
136 | } |
137 | } |
138 | |
139 | /// Returns a slice over an endpoint's custom attributes. |
140 | #[inline ] |
141 | pub fn attributes(&self, endpoint: EndpointId) -> Attributes { |
142 | interpolated_attributes(self.num_attributes, &self.points, endpoint) |
143 | } |
144 | |
145 | /// Iterates over the entire `Path`, ignoring custom attributes. |
146 | pub fn iter(&self) -> Iter { |
147 | Iter::new(self.num_attributes, &self.points[..], &self.verbs[..]) |
148 | } |
149 | |
150 | /// Iterates over the endpoint and control point ids of the `Path`. |
151 | pub fn id_iter(&self) -> IdIter { |
152 | IdIter::new(self.num_attributes, &self.verbs[..]) |
153 | } |
154 | |
155 | /// Iterates over the entire `Path` with custom attributes. |
156 | pub fn iter_with_attributes(&self) -> IterWithAttributes { |
157 | IterWithAttributes::new(self.num_attributes(), &self.points[..], &self.verbs[..]) |
158 | } |
159 | |
160 | /// Applies a transform to all endpoints and control points of this path and |
161 | /// Returns the result. |
162 | pub fn transformed<T: Transformation<f32>>(mut self, transform: &T) -> Self { |
163 | self.apply_transform(transform); |
164 | |
165 | self |
166 | } |
167 | |
168 | /// Returns a reversed version of this path in the form of an iterator |
169 | pub fn reversed(&self) -> IterNoAttributes<Reversed> { |
170 | IterNoAttributes(Reversed::new(self.as_slice())) |
171 | } |
172 | |
173 | /// Returns the first endpoint and its custom attributes if any. |
174 | #[inline ] |
175 | pub fn first_endpoint(&self) -> Option<(Point, Attributes)> { |
176 | self.as_slice().first_endpoint() |
177 | } |
178 | |
179 | /// Returns the last endpoint and its custom attributes if any. |
180 | #[inline ] |
181 | pub fn last_endpoint(&self) -> Option<(Point, Attributes)> { |
182 | self.as_slice().last_endpoint() |
183 | } |
184 | |
185 | fn apply_transform<T: Transformation<f32>>(&mut self, transform: &T) { |
186 | let iter = IdIter::new(self.num_attributes, &self.verbs[..]); |
187 | |
188 | for evt in iter { |
189 | match evt { |
190 | IdEvent::Begin { at } => { |
191 | self.points[at.to_usize()] = |
192 | transform.transform_point(self.points[at.to_usize()]); |
193 | } |
194 | IdEvent::Line { to, .. } => { |
195 | self.points[to.to_usize()] = |
196 | transform.transform_point(self.points[to.to_usize()]); |
197 | } |
198 | IdEvent::Quadratic { ctrl, to, .. } => { |
199 | self.points[ctrl.to_usize()] = |
200 | transform.transform_point(self.points[ctrl.to_usize()]); |
201 | self.points[to.to_usize()] = |
202 | transform.transform_point(self.points[to.to_usize()]); |
203 | } |
204 | IdEvent::Cubic { |
205 | ctrl1, ctrl2, to, .. |
206 | } => { |
207 | self.points[ctrl1.to_usize()] = |
208 | transform.transform_point(self.points[ctrl1.to_usize()]); |
209 | self.points[ctrl2.to_usize()] = |
210 | transform.transform_point(self.points[ctrl2.to_usize()]); |
211 | self.points[to.to_usize()] = |
212 | transform.transform_point(self.points[to.to_usize()]); |
213 | } |
214 | IdEvent::End { .. } => {} |
215 | } |
216 | } |
217 | } |
218 | } |
219 | |
220 | impl FromIterator<PathEvent> for Path { |
221 | fn from_iter<T: IntoIterator<Item = PathEvent>>(iter: T) -> Path { |
222 | let mut builder: NoAttributes = Path::builder(); |
223 | for event: Event, …> in iter.into_iter() { |
224 | builder.path_event(event); |
225 | } |
226 | |
227 | builder.build() |
228 | } |
229 | } |
230 | |
231 | impl core::ops::Index<EndpointId> for Path { |
232 | type Output = Point; |
233 | fn index(&self, id: EndpointId) -> &Point { |
234 | &self.points[id.to_usize()] |
235 | } |
236 | } |
237 | |
238 | impl core::ops::Index<ControlPointId> for Path { |
239 | type Output = Point; |
240 | fn index(&self, id: ControlPointId) -> &Point { |
241 | &self.points[id.to_usize()] |
242 | } |
243 | } |
244 | |
245 | impl<'l> IntoIterator for &'l Path { |
246 | type Item = PathEvent; |
247 | type IntoIter = Iter<'l>; |
248 | |
249 | fn into_iter(self) -> Iter<'l> { |
250 | self.iter() |
251 | } |
252 | } |
253 | |
254 | impl<'l> From<&'l Path> for PathSlice<'l> { |
255 | fn from(path: &'l Path) -> Self { |
256 | path.as_slice() |
257 | } |
258 | } |
259 | |
260 | impl PositionStore for Path { |
261 | fn get_endpoint(&self, id: EndpointId) -> Point { |
262 | self.points[id.to_usize()] |
263 | } |
264 | |
265 | fn get_control_point(&self, id: ControlPointId) -> Point { |
266 | self.points[id.to_usize()] |
267 | } |
268 | } |
269 | |
270 | impl AttributeStore for Path { |
271 | fn get(&self, id: EndpointId) -> Attributes { |
272 | interpolated_attributes(self.num_attributes, &self.points, endpoint:id) |
273 | } |
274 | |
275 | fn num_attributes(&self) -> usize { |
276 | self.num_attributes |
277 | } |
278 | } |
279 | |
280 | impl fmt::Debug for Path { |
281 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
282 | self.as_slice().fmt(formatter) |
283 | } |
284 | } |
285 | |
286 | /// An immutable view over a Path. |
287 | impl<'l> PathSlice<'l> { |
288 | pub fn first_endpoint(&self) -> Option<(Point, Attributes<'l>)> { |
289 | if self.points.is_empty() { |
290 | return None; |
291 | } |
292 | |
293 | let pos = self.points[0]; |
294 | let attributes = interpolated_attributes(self.num_attributes, self.points, EndpointId(0)); |
295 | |
296 | Some((pos, attributes)) |
297 | } |
298 | |
299 | pub fn last_endpoint(&self) -> Option<(Point, Attributes<'l>)> { |
300 | if self.points.is_empty() { |
301 | return None; |
302 | } |
303 | |
304 | let attrib_stride = (self.num_attributes() + 1) / 2; |
305 | let offset = self.points.len() - attrib_stride - 1; |
306 | |
307 | let pos = self.points[offset]; |
308 | let attributes = |
309 | interpolated_attributes(self.num_attributes, self.points, EndpointId(offset as u32)); |
310 | |
311 | Some((pos, attributes)) |
312 | } |
313 | |
314 | /// Iterates over the path. |
315 | pub fn iter<'a>(&'a self) -> Iter<'l> { |
316 | Iter::new(self.num_attributes, self.points, self.verbs) |
317 | } |
318 | |
319 | /// Iterates over the endpoint and control point ids of the `Path`. |
320 | pub fn id_iter(&self) -> IdIter { |
321 | IdIter::new(self.num_attributes, self.verbs) |
322 | } |
323 | |
324 | /// Iterates over the entire `Path` with custom attributes. |
325 | pub fn iter_with_attributes(&self) -> IterWithAttributes { |
326 | IterWithAttributes::new(self.num_attributes(), self.points, self.verbs) |
327 | } |
328 | |
329 | pub fn is_empty(&self) -> bool { |
330 | self.verbs.is_empty() |
331 | } |
332 | |
333 | /// Returns a slice over an endpoint's custom attributes. |
334 | #[inline ] |
335 | pub fn attributes(&self, endpoint: EndpointId) -> Attributes<'l> { |
336 | interpolated_attributes(self.num_attributes, self.points, endpoint) |
337 | } |
338 | |
339 | /// Returns a reversed version of this path in the form of an iterator |
340 | pub fn reversed(&self) -> IterNoAttributes<Reversed> { |
341 | IterNoAttributes(Reversed::new(*self)) |
342 | } |
343 | } |
344 | |
345 | impl<'l> fmt::Debug for PathSlice<'l> { |
346 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
347 | fn write_point(formatter: &mut fmt::Formatter, point: Point) -> fmt::Result { |
348 | write!(formatter, " " )?; |
349 | fmt::Debug::fmt(&point.x, formatter)?; |
350 | write!(formatter, " " )?; |
351 | fmt::Debug::fmt(&point.y, formatter) |
352 | } |
353 | |
354 | fn write_attributes(formatter: &mut fmt::Formatter, attributes: Attributes) -> fmt::Result { |
355 | for val in attributes { |
356 | write!(formatter, " " )?; |
357 | fmt::Debug::fmt(val, formatter)?; |
358 | } |
359 | |
360 | Ok(()) |
361 | } |
362 | |
363 | write!(formatter, " \"" )?; |
364 | |
365 | for evt in self.iter_with_attributes() { |
366 | match evt { |
367 | Event::Begin { |
368 | at: (at, attributes), |
369 | } => { |
370 | write!(formatter, " M" )?; |
371 | write_point(formatter, at)?; |
372 | write_attributes(formatter, attributes)?; |
373 | } |
374 | Event::End { close, .. } => { |
375 | if close { |
376 | write!(formatter, " Z" )?; |
377 | } |
378 | } |
379 | Event::Line { |
380 | to: (to, attributes), |
381 | .. |
382 | } => { |
383 | write!(formatter, " L" )?; |
384 | write_point(formatter, to)?; |
385 | write_attributes(formatter, attributes)?; |
386 | } |
387 | Event::Quadratic { |
388 | ctrl, |
389 | to: (to, attributes), |
390 | .. |
391 | } => { |
392 | write!(formatter, " Q" )?; |
393 | write_point(formatter, ctrl)?; |
394 | write_point(formatter, to)?; |
395 | write_attributes(formatter, attributes)?; |
396 | } |
397 | Event::Cubic { |
398 | ctrl1, |
399 | ctrl2, |
400 | to: (to, attributes), |
401 | .. |
402 | } => { |
403 | write!(formatter, " C" )?; |
404 | write_point(formatter, ctrl1)?; |
405 | write_point(formatter, ctrl2)?; |
406 | write_point(formatter, to)?; |
407 | write_attributes(formatter, attributes)?; |
408 | } |
409 | } |
410 | } |
411 | |
412 | write!(formatter, " \"" ) |
413 | } |
414 | } |
415 | |
416 | impl<'l> core::ops::Index<EndpointId> for PathSlice<'l> { |
417 | type Output = Point; |
418 | fn index(&self, id: EndpointId) -> &Point { |
419 | &self.points[id.to_usize()] |
420 | } |
421 | } |
422 | |
423 | impl<'l> core::ops::Index<ControlPointId> for PathSlice<'l> { |
424 | type Output = Point; |
425 | fn index(&self, id: ControlPointId) -> &Point { |
426 | &self.points[id.to_usize()] |
427 | } |
428 | } |
429 | |
430 | impl<'l> IntoIterator for PathSlice<'l> { |
431 | type Item = PathEvent; |
432 | type IntoIter = Iter<'l>; |
433 | |
434 | fn into_iter(self) -> Iter<'l> { |
435 | self.iter() |
436 | } |
437 | } |
438 | |
439 | impl<'l, 'a> IntoIterator for &'a PathSlice<'l> { |
440 | type Item = PathEvent; |
441 | type IntoIter = Iter<'l>; |
442 | |
443 | fn into_iter(self) -> Iter<'l> { |
444 | self.iter() |
445 | } |
446 | } |
447 | |
448 | impl<'l> PositionStore for PathSlice<'l> { |
449 | fn get_endpoint(&self, id: EndpointId) -> Point { |
450 | self.points[id.to_usize()] |
451 | } |
452 | |
453 | fn get_control_point(&self, id: ControlPointId) -> Point { |
454 | self.points[id.to_usize()] |
455 | } |
456 | } |
457 | |
458 | impl<'l> AttributeStore for PathSlice<'l> { |
459 | fn get(&self, id: EndpointId) -> Attributes<'l> { |
460 | interpolated_attributes(self.num_attributes, self.points, endpoint:id) |
461 | } |
462 | |
463 | fn num_attributes(&self) -> usize { |
464 | self.num_attributes |
465 | } |
466 | } |
467 | |
468 | // TODO: measure the overhead of building no attributes and |
469 | // see if BuilderImpl and BuilderWithAttributes can be merged. |
470 | |
471 | /// The default builder for `Path`. |
472 | #[derive (Clone)] |
473 | pub struct BuilderImpl { |
474 | pub(crate) points: Vec<Point>, |
475 | pub(crate) verbs: Vec<Verb>, |
476 | first: Point, |
477 | validator: DebugValidator, |
478 | } |
479 | |
480 | impl BuilderImpl { |
481 | pub fn new() -> Self { |
482 | BuilderImpl { |
483 | points: Vec::new(), |
484 | verbs: Vec::new(), |
485 | first: point(0.0, 0.0), |
486 | validator: DebugValidator::new(), |
487 | } |
488 | } |
489 | |
490 | pub fn with_capacity(points: usize, edges: usize) -> Self { |
491 | BuilderImpl { |
492 | points: Vec::with_capacity(points), |
493 | verbs: Vec::with_capacity(edges), |
494 | first: point(0.0, 0.0), |
495 | validator: DebugValidator::new(), |
496 | } |
497 | } |
498 | |
499 | pub fn with_svg(self) -> WithSvg<Self> { |
500 | assert!(self.verbs.is_empty()); |
501 | WithSvg::new(self) |
502 | } |
503 | |
504 | #[inline ] |
505 | pub fn extend_from_paths(&mut self, paths: &[PathSlice]) { |
506 | concatenate_paths(&mut self.points, &mut self.verbs, paths, 0); |
507 | } |
508 | } |
509 | |
510 | impl NoAttributes<BuilderImpl> { |
511 | #[inline ] |
512 | pub fn extend_from_paths(&mut self, paths: &[PathSlice]) { |
513 | concatenate_paths(&mut self.inner.points, &mut self.inner.verbs, paths, num_attributes:0); |
514 | } |
515 | } |
516 | |
517 | impl PathBuilder for BuilderImpl { |
518 | fn num_attributes(&self) -> usize { |
519 | 0 |
520 | } |
521 | |
522 | fn begin(&mut self, at: Point, _attributes: Attributes) -> EndpointId { |
523 | self.validator.begin(); |
524 | nan_check(at); |
525 | |
526 | let id = EndpointId(self.points.len() as u32); |
527 | |
528 | self.first = at; |
529 | self.points.push(at); |
530 | self.verbs.push(Verb::Begin); |
531 | |
532 | id |
533 | } |
534 | |
535 | fn end(&mut self, close: bool) { |
536 | self.validator.end(); |
537 | |
538 | if close { |
539 | self.points.push(self.first); |
540 | } |
541 | |
542 | self.verbs.push(if close { Verb::Close } else { Verb::End }); |
543 | } |
544 | |
545 | fn line_to(&mut self, to: Point, _attributes: Attributes) -> EndpointId { |
546 | self.validator.edge(); |
547 | nan_check(to); |
548 | |
549 | let id = EndpointId(self.points.len() as u32); |
550 | self.points.push(to); |
551 | self.verbs.push(Verb::LineTo); |
552 | |
553 | id |
554 | } |
555 | |
556 | fn quadratic_bezier_to( |
557 | &mut self, |
558 | ctrl: Point, |
559 | to: Point, |
560 | _attributes: Attributes, |
561 | ) -> EndpointId { |
562 | self.validator.edge(); |
563 | nan_check(ctrl); |
564 | nan_check(to); |
565 | |
566 | self.points.push(ctrl); |
567 | let id = EndpointId(self.points.len() as u32); |
568 | self.points.push(to); |
569 | self.verbs.push(Verb::QuadraticTo); |
570 | |
571 | id |
572 | } |
573 | |
574 | fn cubic_bezier_to( |
575 | &mut self, |
576 | ctrl1: Point, |
577 | ctrl2: Point, |
578 | to: Point, |
579 | _attributes: Attributes, |
580 | ) -> EndpointId { |
581 | self.validator.edge(); |
582 | nan_check(ctrl1); |
583 | nan_check(ctrl2); |
584 | nan_check(to); |
585 | |
586 | self.points.push(ctrl1); |
587 | self.points.push(ctrl2); |
588 | let id = EndpointId(self.points.len() as u32); |
589 | self.points.push(to); |
590 | self.verbs.push(Verb::CubicTo); |
591 | |
592 | id |
593 | } |
594 | |
595 | fn reserve(&mut self, endpoints: usize, ctrl_points: usize) { |
596 | self.points.reserve(endpoints + ctrl_points); |
597 | self.verbs.reserve(endpoints); |
598 | } |
599 | } |
600 | |
601 | impl Build for BuilderImpl { |
602 | type PathType = Path; |
603 | |
604 | fn build(self) -> Path { |
605 | self.validator.build(); |
606 | Path { |
607 | points: self.points.into_boxed_slice(), |
608 | verbs: self.verbs.into_boxed_slice(), |
609 | num_attributes: 0, |
610 | } |
611 | } |
612 | } |
613 | |
614 | impl Default for BuilderImpl { |
615 | fn default() -> Self { |
616 | BuilderImpl::new() |
617 | } |
618 | } |
619 | |
620 | /// A builder for `Path` with custom attributes. |
621 | /// |
622 | /// Custom attributes are a fixed number of `f32` values associated with each endpoint. |
623 | /// All endpoints must have the same number of custom attributes, |
624 | #[derive (Clone)] |
625 | pub struct BuilderWithAttributes { |
626 | pub(crate) builder: BuilderImpl, |
627 | pub(crate) num_attributes: usize, |
628 | pub(crate) first_attributes: Vec<f32>, |
629 | } |
630 | |
631 | impl BuilderWithAttributes { |
632 | pub fn new(num_attributes: usize) -> Self { |
633 | BuilderWithAttributes { |
634 | builder: BuilderImpl::new(), |
635 | num_attributes, |
636 | first_attributes: vec![0.0; num_attributes], |
637 | } |
638 | } |
639 | |
640 | #[inline ] |
641 | pub fn extend_from_paths(&mut self, paths: &[PathSlice]) { |
642 | concatenate_paths( |
643 | &mut self.builder.points, |
644 | &mut self.builder.verbs, |
645 | paths, |
646 | self.num_attributes, |
647 | ); |
648 | } |
649 | |
650 | #[inline (always)] |
651 | fn push_attributes_impl( |
652 | points: &mut Vec<Point>, |
653 | num_attributes: usize, |
654 | attributes: Attributes, |
655 | ) { |
656 | assert_eq!(attributes.len(), num_attributes); |
657 | for i in 0..(num_attributes / 2) { |
658 | let x = attributes[i * 2]; |
659 | let y = attributes[i * 2 + 1]; |
660 | points.push(point(x, y)); |
661 | } |
662 | if num_attributes % 2 == 1 { |
663 | let x = attributes[num_attributes - 1]; |
664 | points.push(point(x, 0.0)); |
665 | } |
666 | } |
667 | |
668 | fn push_attributes(&mut self, attributes: Attributes) { |
669 | Self::push_attributes_impl(&mut self.builder.points, self.num_attributes, attributes); |
670 | } |
671 | |
672 | #[inline ] |
673 | pub fn num_attributes(&self) -> usize { |
674 | self.num_attributes |
675 | } |
676 | |
677 | #[inline ] |
678 | pub fn begin(&mut self, at: Point, attributes: Attributes) -> EndpointId { |
679 | let id = self.builder.begin(at, attributes); |
680 | self.push_attributes(attributes); |
681 | |
682 | self.first_attributes.copy_from_slice(attributes); |
683 | |
684 | id |
685 | } |
686 | |
687 | #[inline ] |
688 | pub fn end(&mut self, close: bool) { |
689 | self.builder.end(close); |
690 | |
691 | if close { |
692 | Self::push_attributes_impl( |
693 | &mut self.builder.points, |
694 | self.num_attributes, |
695 | &self.first_attributes, |
696 | ); |
697 | } |
698 | } |
699 | |
700 | #[inline ] |
701 | pub fn line_to(&mut self, to: Point, attributes: Attributes) -> EndpointId { |
702 | let id = self.builder.line_to(to, attributes); |
703 | self.push_attributes(attributes); |
704 | |
705 | id |
706 | } |
707 | |
708 | #[inline ] |
709 | pub fn quadratic_bezier_to( |
710 | &mut self, |
711 | ctrl: Point, |
712 | to: Point, |
713 | attributes: Attributes, |
714 | ) -> EndpointId { |
715 | let id = self.builder.quadratic_bezier_to(ctrl, to, attributes); |
716 | self.push_attributes(attributes); |
717 | |
718 | id |
719 | } |
720 | |
721 | #[inline ] |
722 | pub fn cubic_bezier_to( |
723 | &mut self, |
724 | ctrl1: Point, |
725 | ctrl2: Point, |
726 | to: Point, |
727 | attributes: Attributes, |
728 | ) -> EndpointId { |
729 | let id = self.builder.cubic_bezier_to(ctrl1, ctrl2, to, attributes); |
730 | self.push_attributes(attributes); |
731 | |
732 | id |
733 | } |
734 | |
735 | #[inline ] |
736 | pub fn reserve(&mut self, endpoints: usize, ctrl_points: usize) { |
737 | let attr = self.num_attributes / 2 + self.num_attributes % 2; |
738 | let n_points = endpoints * (1 + attr) + ctrl_points; |
739 | self.builder.points.reserve(n_points); |
740 | self.builder.verbs.reserve(endpoints); |
741 | } |
742 | |
743 | #[inline ] |
744 | pub fn build(self) -> Path { |
745 | self.builder.validator.build(); |
746 | Path { |
747 | points: self.builder.points.into_boxed_slice(), |
748 | verbs: self.builder.verbs.into_boxed_slice(), |
749 | num_attributes: self.num_attributes, |
750 | } |
751 | } |
752 | } |
753 | |
754 | impl PathBuilder for BuilderWithAttributes { |
755 | #[inline ] |
756 | fn num_attributes(&self) -> usize { |
757 | self.num_attributes() |
758 | } |
759 | |
760 | #[inline ] |
761 | fn begin(&mut self, at: Point, attributes: Attributes) -> EndpointId { |
762 | self.begin(at, attributes) |
763 | } |
764 | |
765 | #[inline ] |
766 | fn end(&mut self, close: bool) { |
767 | self.end(close); |
768 | } |
769 | |
770 | #[inline ] |
771 | fn line_to(&mut self, to: Point, attributes: Attributes) -> EndpointId { |
772 | self.line_to(to, attributes) |
773 | } |
774 | |
775 | #[inline ] |
776 | fn quadratic_bezier_to( |
777 | &mut self, |
778 | ctrl: Point, |
779 | to: Point, |
780 | attributes: Attributes, |
781 | ) -> EndpointId { |
782 | self.quadratic_bezier_to(ctrl, to, attributes) |
783 | } |
784 | |
785 | #[inline ] |
786 | fn cubic_bezier_to( |
787 | &mut self, |
788 | ctrl1: Point, |
789 | ctrl2: Point, |
790 | to: Point, |
791 | attributes: Attributes, |
792 | ) -> EndpointId { |
793 | self.cubic_bezier_to(ctrl1, ctrl2, to, attributes) |
794 | } |
795 | |
796 | #[inline ] |
797 | fn reserve(&mut self, endpoints: usize, ctrl_points: usize) { |
798 | self.reserve(endpoints, ctrl_points) |
799 | } |
800 | } |
801 | |
802 | impl Build for BuilderWithAttributes { |
803 | type PathType = Path; |
804 | |
805 | fn build(self) -> Path { |
806 | self.build() |
807 | } |
808 | } |
809 | |
810 | #[inline ] |
811 | fn nan_check(p: Point) { |
812 | debug_assert!(p.x.is_finite()); |
813 | debug_assert!(p.y.is_finite()); |
814 | } |
815 | |
816 | /// An iterator for `Path` and `PathSlice`. |
817 | #[derive (Clone)] |
818 | pub struct Iter<'l> { |
819 | points: PointIter<'l>, |
820 | verbs: ::core::slice::Iter<'l, Verb>, |
821 | current: Point, |
822 | first: Point, |
823 | // Number of slots in the points array occupied by the custom attributes. |
824 | attrib_stride: usize, |
825 | } |
826 | |
827 | impl<'l> Iter<'l> { |
828 | fn new(num_attributes: usize, points: &'l [Point], verbs: &'l [Verb]) -> Self { |
829 | Iter { |
830 | points: PointIter::new(slice:points), |
831 | verbs: verbs.iter(), |
832 | current: point(x:0.0, y:0.0), |
833 | first: point(x:0.0, y:0.0), |
834 | attrib_stride: (num_attributes + 1) / 2, |
835 | } |
836 | } |
837 | |
838 | #[inline ] |
839 | fn skip_attributes(&mut self) { |
840 | self.points.advance_n(self.attrib_stride); |
841 | } |
842 | } |
843 | |
844 | impl<'l> Iterator for Iter<'l> { |
845 | type Item = PathEvent; |
846 | #[inline ] |
847 | fn next(&mut self) -> Option<PathEvent> { |
848 | match self.verbs.next() { |
849 | Some(&Verb::Begin) => { |
850 | self.current = self.points.next(); |
851 | self.skip_attributes(); |
852 | self.first = self.current; |
853 | Some(PathEvent::Begin { at: self.current }) |
854 | } |
855 | Some(&Verb::LineTo) => { |
856 | let from = self.current; |
857 | self.current = self.points.next(); |
858 | self.skip_attributes(); |
859 | Some(PathEvent::Line { |
860 | from, |
861 | to: self.current, |
862 | }) |
863 | } |
864 | Some(&Verb::QuadraticTo) => { |
865 | let from = self.current; |
866 | let ctrl = self.points.next(); |
867 | self.current = self.points.next(); |
868 | self.skip_attributes(); |
869 | Some(PathEvent::Quadratic { |
870 | from, |
871 | ctrl, |
872 | to: self.current, |
873 | }) |
874 | } |
875 | Some(&Verb::CubicTo) => { |
876 | let from = self.current; |
877 | let ctrl1 = self.points.next(); |
878 | let ctrl2 = self.points.next(); |
879 | self.current = self.points.next(); |
880 | self.skip_attributes(); |
881 | Some(PathEvent::Cubic { |
882 | from, |
883 | ctrl1, |
884 | ctrl2, |
885 | to: self.current, |
886 | }) |
887 | } |
888 | Some(&Verb::Close) => { |
889 | let last = self.current; |
890 | let _ = self.points.next(); |
891 | self.skip_attributes(); |
892 | Some(PathEvent::End { |
893 | last, |
894 | first: self.first, |
895 | close: true, |
896 | }) |
897 | } |
898 | Some(&Verb::End) => { |
899 | let last = self.current; |
900 | self.current = self.first; |
901 | Some(PathEvent::End { |
902 | last, |
903 | first: self.first, |
904 | close: false, |
905 | }) |
906 | } |
907 | None => None, |
908 | } |
909 | } |
910 | } |
911 | |
912 | /// Manually implemented to avoid iterator overhead when skipping over |
913 | /// several points where the custom attributes are stored. |
914 | /// |
915 | /// It makes an unfortunately large difference (the simple iterator |
916 | /// benchmarks are 2 to 3 times faster). |
917 | #[derive (Copy, Clone)] |
918 | struct PointIter<'l> { |
919 | ptr: *const Point, |
920 | end: *const Point, |
921 | _marker: core::marker::PhantomData<&'l Point>, |
922 | } |
923 | |
924 | impl<'l> PointIter<'l> { |
925 | fn new(slice: &'l [Point]) -> Self { |
926 | let ptr = slice.as_ptr(); |
927 | let end = unsafe { ptr.add(slice.len()) }; |
928 | PointIter { |
929 | ptr, |
930 | end, |
931 | _marker: core::marker::PhantomData, |
932 | } |
933 | } |
934 | |
935 | #[inline ] |
936 | fn remaining_len(&self) -> usize { |
937 | (self.end as usize - self.ptr as usize) / core::mem::size_of::<Point>() |
938 | } |
939 | |
940 | #[inline ] |
941 | fn next(&mut self) -> Point { |
942 | // Don't bother panicking here. calls to next |
943 | // are always followed by advance_n which will |
944 | // catch the issue and panic. |
945 | if self.ptr >= self.end { |
946 | return point(f32::NAN, f32::NAN); |
947 | } |
948 | |
949 | unsafe { |
950 | let output = *self.ptr; |
951 | self.ptr = self.ptr.offset(1); |
952 | |
953 | output |
954 | } |
955 | } |
956 | |
957 | #[inline ] |
958 | fn advance_n(&mut self, n: usize) { |
959 | unsafe { |
960 | assert!(self.remaining_len() >= n); |
961 | self.ptr = self.ptr.add(n); |
962 | } |
963 | } |
964 | } |
965 | |
966 | /// An iterator for `Path` and `PathSlice`. |
967 | #[derive (Clone)] |
968 | pub struct IterWithAttributes<'l> { |
969 | points: PointIter<'l>, |
970 | verbs: ::core::slice::Iter<'l, Verb>, |
971 | current: (Point, Attributes<'l>), |
972 | first: (Point, Attributes<'l>), |
973 | num_attributes: usize, |
974 | attrib_stride: usize, |
975 | } |
976 | |
977 | impl<'l> IterWithAttributes<'l> { |
978 | fn new(num_attributes: usize, points: &'l [Point], verbs: &'l [Verb]) -> Self { |
979 | IterWithAttributes { |
980 | points: PointIter::new(points), |
981 | verbs: verbs.iter(), |
982 | current: (point(0.0, 0.0), NO_ATTRIBUTES), |
983 | first: (point(0.0, 0.0), NO_ATTRIBUTES), |
984 | num_attributes, |
985 | attrib_stride: (num_attributes + 1) / 2, |
986 | } |
987 | } |
988 | |
989 | pub fn points(self) -> Iter<'l> { |
990 | Iter { |
991 | points: self.points, |
992 | verbs: self.verbs, |
993 | current: self.current.0, |
994 | first: self.first.0, |
995 | attrib_stride: self.attrib_stride, |
996 | } |
997 | } |
998 | |
999 | /// Iterate on a flattened approximation of the path with interpolated custom attributes |
1000 | /// using callbacks. |
1001 | /// |
1002 | /// At the time of writing, it is impossible to implement this efficiently |
1003 | /// with the `Iterator` trait, because of the need to express some lifetime |
1004 | /// constraints in an associated type, see #701. |
1005 | pub fn for_each_flattened<F>(self, tolerance: f32, callback: &mut F) |
1006 | where |
1007 | F: FnMut(&Event<(Point, Attributes), Point>), |
1008 | { |
1009 | let num_attributes = self.num_attributes; |
1010 | // Some scratch space for writing the interpolated custom attributes. |
1011 | let mut stack_buffer = [0.0; 16]; |
1012 | let mut vec_buffer; |
1013 | // No need to allocate memory if the number of custom attributes is small, |
1014 | // which is likely the common case. |
1015 | let buffer = if num_attributes <= 8 { |
1016 | &mut stack_buffer[..] |
1017 | } else { |
1018 | vec_buffer = vec![0.0; num_attributes * 2]; |
1019 | &mut vec_buffer[..] |
1020 | }; |
1021 | |
1022 | for evt in self { |
1023 | match evt { |
1024 | Event::Begin { at } => { |
1025 | callback(&Event::Begin { at }); |
1026 | } |
1027 | Event::End { last, first, close } => { |
1028 | callback(&Event::End { last, first, close }); |
1029 | } |
1030 | Event::Line { from, to } => { |
1031 | callback(&Event::Line { from, to }); |
1032 | } |
1033 | Event::Quadratic { from, ctrl, to } => { |
1034 | let from_attr = from.1; |
1035 | let to_attr = to.1; |
1036 | let curve = QuadraticBezierSegment { |
1037 | from: from.0, |
1038 | ctrl, |
1039 | to: to.0, |
1040 | }; |
1041 | let mut offset = num_attributes; |
1042 | buffer[0..num_attributes].copy_from_slice(from_attr); |
1043 | curve.for_each_flattened_with_t(tolerance, &mut |line, t| { |
1044 | for i in 0..num_attributes { |
1045 | buffer[offset + i] = (1.0 - t.end) * from_attr[i] + t.end * to_attr[i]; |
1046 | } |
1047 | |
1048 | let next_offset = if offset == 0 { num_attributes } else { 0 }; |
1049 | |
1050 | callback(&Event::Line { |
1051 | from: ( |
1052 | line.from, |
1053 | &buffer[next_offset..(next_offset + num_attributes)], |
1054 | ), |
1055 | to: (line.to, &buffer[offset..(offset + num_attributes)]), |
1056 | }); |
1057 | |
1058 | offset = next_offset; |
1059 | }); |
1060 | } |
1061 | Event::Cubic { |
1062 | from, |
1063 | ctrl1, |
1064 | ctrl2, |
1065 | to, |
1066 | } => { |
1067 | let from_attr = from.1; |
1068 | let to_attr = to.1; |
1069 | let curve = CubicBezierSegment { |
1070 | from: from.0, |
1071 | ctrl1, |
1072 | ctrl2, |
1073 | to: to.0, |
1074 | }; |
1075 | let mut offset = num_attributes; |
1076 | buffer[0..num_attributes].copy_from_slice(from_attr); |
1077 | curve.for_each_flattened_with_t(tolerance, &mut |line, t| { |
1078 | for i in 0..num_attributes { |
1079 | buffer[offset + i] = (1.0 - t.end) * from_attr[i] + t.end * to_attr[i]; |
1080 | } |
1081 | |
1082 | let next_offset = if offset == 0 { num_attributes } else { 0 }; |
1083 | |
1084 | callback(&Event::Line { |
1085 | from: ( |
1086 | line.from, |
1087 | &buffer[next_offset..(next_offset + num_attributes)], |
1088 | ), |
1089 | to: (line.to, &buffer[offset..(offset + num_attributes)]), |
1090 | }); |
1091 | |
1092 | offset = next_offset; |
1093 | }); |
1094 | } |
1095 | } |
1096 | } |
1097 | } |
1098 | |
1099 | #[inline ] |
1100 | fn pop_endpoint(&mut self) -> (Point, Attributes<'l>) { |
1101 | let position = self.points.next(); |
1102 | let attributes_ptr = self.points.ptr as *const f32; |
1103 | self.points.advance_n(self.attrib_stride); |
1104 | let attributes = unsafe { |
1105 | // SAFETY: advance_n would have panicked if the slice is out of bounds |
1106 | core::slice::from_raw_parts(attributes_ptr, self.num_attributes) |
1107 | }; |
1108 | |
1109 | (position, attributes) |
1110 | } |
1111 | } |
1112 | |
1113 | impl<'l> Iterator for IterWithAttributes<'l> { |
1114 | type Item = Event<(Point, Attributes<'l>), Point>; |
1115 | #[inline ] |
1116 | fn next(&mut self) -> Option<Self::Item> { |
1117 | match self.verbs.next() { |
1118 | Some(&Verb::Begin) => { |
1119 | self.current = self.pop_endpoint(); |
1120 | self.first = self.current; |
1121 | Some(Event::Begin { at: self.current }) |
1122 | } |
1123 | Some(&Verb::LineTo) => { |
1124 | let from = self.current; |
1125 | self.current = self.pop_endpoint(); |
1126 | Some(Event::Line { |
1127 | from, |
1128 | to: self.current, |
1129 | }) |
1130 | } |
1131 | Some(&Verb::QuadraticTo) => { |
1132 | let from = self.current; |
1133 | let ctrl = self.points.next(); |
1134 | self.current = self.pop_endpoint(); |
1135 | Some(Event::Quadratic { |
1136 | from, |
1137 | ctrl, |
1138 | to: self.current, |
1139 | }) |
1140 | } |
1141 | Some(&Verb::CubicTo) => { |
1142 | let from = self.current; |
1143 | let ctrl1 = self.points.next(); |
1144 | let ctrl2 = self.points.next(); |
1145 | self.current = self.pop_endpoint(); |
1146 | Some(Event::Cubic { |
1147 | from, |
1148 | ctrl1, |
1149 | ctrl2, |
1150 | to: self.current, |
1151 | }) |
1152 | } |
1153 | Some(&Verb::Close) => { |
1154 | let last = self.current; |
1155 | self.current = self.pop_endpoint(); |
1156 | Some(Event::End { |
1157 | last, |
1158 | first: self.first, |
1159 | close: true, |
1160 | }) |
1161 | } |
1162 | Some(&Verb::End) => { |
1163 | let last = self.current; |
1164 | self.current = self.first; |
1165 | Some(Event::End { |
1166 | last, |
1167 | first: self.first, |
1168 | close: false, |
1169 | }) |
1170 | } |
1171 | None => None, |
1172 | } |
1173 | } |
1174 | } |
1175 | |
1176 | /// An iterator of endpoint and control point ids for `Path` and `PathSlice`. |
1177 | #[derive (Clone, Debug)] |
1178 | pub struct IdIter<'l> { |
1179 | verbs: ::core::slice::Iter<'l, Verb>, |
1180 | current: u32, |
1181 | first: u32, |
1182 | evt: u32, |
1183 | endpoint_stride: u32, |
1184 | } |
1185 | |
1186 | impl<'l> IdIter<'l> { |
1187 | fn new(num_attributes: usize, verbs: &'l [Verb]) -> Self { |
1188 | IdIter { |
1189 | verbs: verbs.iter(), |
1190 | current: 0, |
1191 | first: 0, |
1192 | evt: 0, |
1193 | endpoint_stride: (num_attributes as u32 + 1) / 2 + 1, |
1194 | } |
1195 | } |
1196 | } |
1197 | |
1198 | impl<'l> Iterator for IdIter<'l> { |
1199 | type Item = IdEvent; |
1200 | #[inline ] |
1201 | fn next(&mut self) -> Option<IdEvent> { |
1202 | match self.verbs.next() { |
1203 | Some(&Verb::Begin) => { |
1204 | let at = self.current; |
1205 | self.first = at; |
1206 | Some(IdEvent::Begin { at: EndpointId(at) }) |
1207 | } |
1208 | Some(&Verb::LineTo) => { |
1209 | let from = EndpointId(self.current); |
1210 | self.current += self.endpoint_stride; |
1211 | let to = EndpointId(self.current); |
1212 | self.evt += 1; |
1213 | Some(IdEvent::Line { from, to }) |
1214 | } |
1215 | Some(&Verb::QuadraticTo) => { |
1216 | let from = EndpointId(self.current); |
1217 | let base = self.current + self.endpoint_stride; |
1218 | let ctrl = ControlPointId(base); |
1219 | let to = EndpointId(base + 1); |
1220 | self.current = base + 1; |
1221 | self.evt += 1; |
1222 | Some(IdEvent::Quadratic { from, ctrl, to }) |
1223 | } |
1224 | Some(&Verb::CubicTo) => { |
1225 | let from = EndpointId(self.current); |
1226 | let base = self.current + self.endpoint_stride; |
1227 | let ctrl1 = ControlPointId(base); |
1228 | let ctrl2 = ControlPointId(base + 1); |
1229 | let to = EndpointId(base + 2); |
1230 | self.current = base + 2; |
1231 | self.evt += 1; |
1232 | Some(IdEvent::Cubic { |
1233 | from, |
1234 | ctrl1, |
1235 | ctrl2, |
1236 | to, |
1237 | }) |
1238 | } |
1239 | Some(&Verb::Close) => { |
1240 | let last = EndpointId(self.current); |
1241 | let first = EndpointId(self.first); |
1242 | self.current += self.endpoint_stride * 2; |
1243 | self.evt += 1; |
1244 | Some(IdEvent::End { |
1245 | last, |
1246 | first, |
1247 | close: true, |
1248 | }) |
1249 | } |
1250 | Some(&Verb::End) => { |
1251 | let last = EndpointId(self.current); |
1252 | let first = EndpointId(self.first); |
1253 | self.current += self.endpoint_stride; |
1254 | self.evt += 1; |
1255 | Some(IdEvent::End { |
1256 | last, |
1257 | first, |
1258 | close: false, |
1259 | }) |
1260 | } |
1261 | None => None, |
1262 | } |
1263 | } |
1264 | } |
1265 | |
1266 | #[inline ] |
1267 | fn interpolated_attributes( |
1268 | num_attributes: usize, |
1269 | points: &[Point], |
1270 | endpoint: EndpointId, |
1271 | ) -> Attributes { |
1272 | if num_attributes == 0 { |
1273 | return &[]; |
1274 | } |
1275 | |
1276 | let idx: usize = endpoint.0 as usize + 1; |
1277 | assert!(idx + (num_attributes + 1) / 2 <= points.len()); |
1278 | |
1279 | unsafe { |
1280 | let ptr: *const f32 = &points[idx].x as *const f32; |
1281 | core::slice::from_raw_parts(data:ptr, len:num_attributes) |
1282 | } |
1283 | } |
1284 | |
1285 | fn concatenate_paths( |
1286 | points: &mut Vec<Point>, |
1287 | verbs: &mut Vec<Verb>, |
1288 | paths: &[PathSlice], |
1289 | num_attributes: usize, |
1290 | ) { |
1291 | let mut np: usize = 0; |
1292 | let mut nv: usize = 0; |
1293 | |
1294 | for path: &PathSlice<'_> in paths { |
1295 | assert_eq!(path.num_attributes(), num_attributes); |
1296 | np += path.points.len(); |
1297 | nv += path.verbs.len(); |
1298 | } |
1299 | |
1300 | verbs.reserve(additional:nv); |
1301 | points.reserve(additional:np); |
1302 | |
1303 | for path: &PathSlice<'_> in paths { |
1304 | verbs.extend_from_slice(path.verbs); |
1305 | points.extend_from_slice(path.points); |
1306 | } |
1307 | } |
1308 | |
1309 | /// An iterator of over a `Path` traversing the path in reverse. |
1310 | pub struct Reversed<'l> { |
1311 | verbs: core::iter::Rev<core::slice::Iter<'l, Verb>>, |
1312 | path: PathSlice<'l>, |
1313 | num_attributes: usize, |
1314 | attrib_stride: usize, |
1315 | p: usize, |
1316 | need_close: bool, |
1317 | first: Option<(Point, Attributes<'l>)>, |
1318 | } |
1319 | |
1320 | impl<'l> Reversed<'l> { |
1321 | fn new(path: PathSlice<'l>) -> Self { |
1322 | Reversed { |
1323 | verbs: path.verbs.iter().rev(), |
1324 | num_attributes: path.num_attributes(), |
1325 | attrib_stride: (path.num_attributes() + 1) / 2, |
1326 | path, |
1327 | p: path.points.len(), |
1328 | need_close: false, |
1329 | first: None, |
1330 | } |
1331 | } |
1332 | |
1333 | /// Builds a `Path` from This iterator. |
1334 | /// |
1335 | /// The iterator must be at the beginning. |
1336 | pub fn into_path(self) -> Path { |
1337 | let mut builder = Path::builder_with_attributes(self.num_attributes); |
1338 | for event in self { |
1339 | builder.event(event); |
1340 | } |
1341 | |
1342 | builder.build() |
1343 | } |
1344 | } |
1345 | |
1346 | impl<'l> Iterator for Reversed<'l> { |
1347 | type Item = Event<(Point, Attributes<'l>), Point>; |
1348 | fn next(&mut self) -> Option<Self::Item> { |
1349 | // At the beginning of each iteration, `self.p` points to the index |
1350 | // directly after the endpoint of the current verb. |
1351 | let endpoint_stride = self.attrib_stride + 1; |
1352 | let v = self.verbs.next()?; |
1353 | let event = match v { |
1354 | Verb::Close => { |
1355 | self.need_close = true; |
1356 | // Close event contain the first endpoint, so skip over that by |
1357 | // offsetting by an extra endpoint stride. |
1358 | let idx = self.p - 2 * endpoint_stride; |
1359 | let first = ( |
1360 | self.path.points[idx], |
1361 | self.path.attributes(EndpointId(idx as u32)), |
1362 | ); |
1363 | self.first = Some(first); |
1364 | Event::Begin { at: first } |
1365 | } |
1366 | Verb::End => { |
1367 | // End events don't push an endpoint, the current endpoint |
1368 | // is the one of the previous command (or next going in reverse). |
1369 | let idx = self.p - endpoint_stride; |
1370 | self.need_close = false; |
1371 | let first = ( |
1372 | self.path.points[idx], |
1373 | self.path.attributes(EndpointId(idx as u32)), |
1374 | ); |
1375 | self.first = Some(first); |
1376 | Event::Begin { at: first } |
1377 | } |
1378 | Verb::Begin => { |
1379 | let close = self.need_close; |
1380 | self.need_close = false; |
1381 | let idx = self.p - endpoint_stride; |
1382 | Event::End { |
1383 | last: ( |
1384 | self.path.points[idx], |
1385 | self.path.attributes(EndpointId(idx as u32)), |
1386 | ), |
1387 | first: self.first.take().unwrap(), |
1388 | close, |
1389 | } |
1390 | } |
1391 | Verb::LineTo => { |
1392 | let from = self.p - endpoint_stride; |
1393 | let to = from - endpoint_stride; |
1394 | Event::Line { |
1395 | from: ( |
1396 | self.path.points[from], |
1397 | self.path.attributes(EndpointId(from as u32)), |
1398 | ), |
1399 | to: ( |
1400 | self.path.points[to], |
1401 | self.path.attributes(EndpointId(to as u32)), |
1402 | ), |
1403 | } |
1404 | } |
1405 | Verb::QuadraticTo => { |
1406 | let from = self.p - endpoint_stride; |
1407 | let ctrl = from - 1; |
1408 | let to = ctrl - endpoint_stride; |
1409 | Event::Quadratic { |
1410 | from: ( |
1411 | self.path.points[from], |
1412 | self.path.attributes(EndpointId(from as u32)), |
1413 | ), |
1414 | ctrl: self.path.points[ctrl], |
1415 | to: ( |
1416 | self.path.points[to], |
1417 | self.path.attributes(EndpointId(to as u32)), |
1418 | ), |
1419 | } |
1420 | } |
1421 | Verb::CubicTo => { |
1422 | let from = self.p - endpoint_stride; |
1423 | let ctrl1 = from - 1; |
1424 | let ctrl2 = ctrl1 - 1; |
1425 | let to = ctrl2 - endpoint_stride; |
1426 | Event::Cubic { |
1427 | from: ( |
1428 | self.path.points[from], |
1429 | self.path.attributes(EndpointId(from as u32)), |
1430 | ), |
1431 | ctrl1: self.path.points[ctrl1], |
1432 | ctrl2: self.path.points[ctrl2], |
1433 | to: ( |
1434 | self.path.points[to], |
1435 | self.path.attributes(EndpointId(to as u32)), |
1436 | ), |
1437 | } |
1438 | } |
1439 | }; |
1440 | |
1441 | self.p -= n_stored_points(*v, self.attrib_stride); |
1442 | |
1443 | Some(event) |
1444 | } |
1445 | } |
1446 | |
1447 | fn n_stored_points(verb: Verb, attrib_stride: usize) -> usize { |
1448 | match verb { |
1449 | Verb::Begin => attrib_stride + 1, |
1450 | Verb::LineTo => attrib_stride + 1, |
1451 | Verb::QuadraticTo => attrib_stride + 2, |
1452 | Verb::CubicTo => attrib_stride + 3, |
1453 | Verb::Close => attrib_stride + 1, |
1454 | Verb::End => 0, |
1455 | } |
1456 | } |
1457 | |
1458 | #[cfg (test)] |
1459 | fn slice(a: &[f32]) -> &[f32] { |
1460 | a |
1461 | } |
1462 | |
1463 | #[test ] |
1464 | fn test_reverse_path_simple() { |
1465 | let mut builder = Path::builder_with_attributes(1); |
1466 | builder.begin(point(0.0, 0.0), &[1.0]); |
1467 | builder.line_to(point(1.0, 0.0), &[2.0]); |
1468 | builder.line_to(point(1.0, 1.0), &[3.0]); |
1469 | builder.line_to(point(0.0, 1.0), &[4.0]); |
1470 | builder.end(false); |
1471 | |
1472 | let p1 = builder.build(); |
1473 | let p2 = p1.reversed().with_attributes().into_path(); |
1474 | |
1475 | let mut it = p2.iter_with_attributes(); |
1476 | |
1477 | // Using a function that explicits the argument types works around type inference issue. |
1478 | fn check<'l>( |
1479 | a: Option<Event<(Point, Attributes<'l>), Point>>, |
1480 | b: Option<Event<(Point, Attributes<'l>), Point>>, |
1481 | ) -> bool { |
1482 | if a != b { |
1483 | std::println!("left: {a:?}" ); |
1484 | std::println!("right: {b:?}" ); |
1485 | } |
1486 | |
1487 | a == b |
1488 | } |
1489 | |
1490 | assert!(check( |
1491 | it.next(), |
1492 | Some(Event::Begin { |
1493 | at: (point(0.0, 1.0), &[4.0]) |
1494 | }) |
1495 | )); |
1496 | assert!(check( |
1497 | it.next(), |
1498 | Some(Event::Line { |
1499 | from: (point(0.0, 1.0), &[4.0]), |
1500 | to: (point(1.0, 1.0), &[3.0]), |
1501 | }) |
1502 | )); |
1503 | assert!(check( |
1504 | it.next(), |
1505 | Some(Event::Line { |
1506 | from: (point(1.0, 1.0), &[3.0]), |
1507 | to: (point(1.0, 0.0), &[2.0]), |
1508 | }) |
1509 | )); |
1510 | assert!(check( |
1511 | it.next(), |
1512 | Some(Event::Line { |
1513 | from: (point(1.0, 0.0), &[2.0]), |
1514 | to: (point(0.0, 0.0), &[1.0]), |
1515 | }) |
1516 | )); |
1517 | assert!(check( |
1518 | it.next(), |
1519 | Some(Event::End { |
1520 | last: (point(0.0, 0.0), &[1.0]), |
1521 | first: (point(0.0, 1.0), &[4.0]), |
1522 | close: false |
1523 | }) |
1524 | )); |
1525 | |
1526 | assert!(check(it.next(), None)); |
1527 | } |
1528 | |
1529 | #[test ] |
1530 | fn test_reverse_path_1() { |
1531 | let mut builder = Path::builder_with_attributes(1); |
1532 | builder.begin(point(0.0, 0.0), &[1.0]); |
1533 | builder.line_to(point(1.0, 0.0), &[2.0]); |
1534 | builder.line_to(point(1.0, 1.0), &[3.0]); |
1535 | builder.line_to(point(0.0, 1.0), &[4.0]); |
1536 | builder.end(false); |
1537 | |
1538 | builder.begin(point(10.0, 0.0), &[5.0]); |
1539 | builder.line_to(point(11.0, 0.0), &[6.0]); |
1540 | builder.line_to(point(11.0, 1.0), &[7.0]); |
1541 | builder.line_to(point(10.0, 1.0), &[8.0]); |
1542 | builder.end(true); |
1543 | |
1544 | builder.begin(point(20.0, 0.0), &[9.0]); |
1545 | builder.quadratic_bezier_to(point(21.0, 0.0), point(21.0, 1.0), &[10.0]); |
1546 | builder.end(false); |
1547 | |
1548 | builder.begin(point(20.0, 0.0), &[9.0]); |
1549 | builder.quadratic_bezier_to(point(21.0, 0.0), point(21.0, 1.0), &[10.0]); |
1550 | builder.end(true); |
1551 | |
1552 | let p1 = builder.build(); |
1553 | |
1554 | let mut it = p1.reversed().with_attributes(); |
1555 | |
1556 | // Using a function that explicits the argument types works around type inference issue. |
1557 | fn check<'l>( |
1558 | a: Option<Event<(Point, Attributes<'l>), Point>>, |
1559 | b: Option<Event<(Point, Attributes<'l>), Point>>, |
1560 | ) -> bool { |
1561 | if a != b { |
1562 | std::println!("left: {a:?}" ); |
1563 | std::println!("right: {b:?}" ); |
1564 | } |
1565 | |
1566 | a == b |
1567 | } |
1568 | |
1569 | assert!(check( |
1570 | it.next(), |
1571 | Some(Event::Begin { |
1572 | at: (point(21.0, 1.0), &[10.0]), |
1573 | }) |
1574 | )); |
1575 | assert!(check( |
1576 | it.next(), |
1577 | Some(Event::Quadratic { |
1578 | from: (point(21.0, 1.0), &[10.0]), |
1579 | ctrl: point(21.0, 0.0), |
1580 | to: (point(20.0, 0.0), &[9.0]), |
1581 | }) |
1582 | )); |
1583 | assert!(check( |
1584 | it.next(), |
1585 | Some(Event::End { |
1586 | last: (point(20.0, 0.0), &[9.0]), |
1587 | first: (point(21.0, 1.0), &[10.0]), |
1588 | close: true |
1589 | }) |
1590 | )); |
1591 | |
1592 | assert!(check( |
1593 | it.next(), |
1594 | Some(Event::Begin { |
1595 | at: (point(21.0, 1.0), &[10.0]), |
1596 | }) |
1597 | )); |
1598 | assert!(check( |
1599 | it.next(), |
1600 | Some(Event::Quadratic { |
1601 | from: (point(21.0, 1.0), &[10.0]), |
1602 | ctrl: point(21.0, 0.0), |
1603 | to: (point(20.0, 0.0), &[9.0]), |
1604 | }) |
1605 | )); |
1606 | assert!(check( |
1607 | it.next(), |
1608 | Some(Event::End { |
1609 | last: (point(20.0, 0.0), &[9.0]), |
1610 | first: (point(21.0, 1.0), &[10.0]), |
1611 | close: false |
1612 | }) |
1613 | )); |
1614 | |
1615 | assert!(check( |
1616 | it.next(), |
1617 | Some(Event::Begin { |
1618 | at: (point(10.0, 1.0), &[8.0]), // <-- |
1619 | }) |
1620 | )); |
1621 | assert!(check( |
1622 | it.next(), |
1623 | Some(Event::Line { |
1624 | from: (point(10.0, 1.0), &[8.0]), |
1625 | to: (point(11.0, 1.0), &[7.0]), |
1626 | }) |
1627 | )); |
1628 | assert!(check( |
1629 | it.next(), |
1630 | Some(Event::Line { |
1631 | from: (point(11.0, 1.0), &[7.0]), |
1632 | to: (point(11.0, 0.0), &[6.0]), |
1633 | }) |
1634 | )); |
1635 | assert!(check( |
1636 | it.next(), |
1637 | Some(Event::Line { |
1638 | from: (point(11.0, 0.0), &[6.0]), |
1639 | to: (point(10.0, 0.0), &[5.0]), |
1640 | }) |
1641 | )); |
1642 | assert!(check( |
1643 | it.next(), |
1644 | Some(Event::End { |
1645 | last: (point(10.0, 0.0), &[5.0]), |
1646 | first: (point(10.0, 1.0), &[8.0]), |
1647 | close: true |
1648 | }) |
1649 | )); |
1650 | |
1651 | assert!(check( |
1652 | it.next(), |
1653 | Some(Event::Begin { |
1654 | at: (point(0.0, 1.0), &[4.0]), |
1655 | }) |
1656 | )); |
1657 | assert!(check( |
1658 | it.next(), |
1659 | Some(Event::Line { |
1660 | from: (point(0.0, 1.0), &[4.0]), |
1661 | to: (point(1.0, 1.0), &[3.0]), |
1662 | }) |
1663 | )); |
1664 | assert!(check( |
1665 | it.next(), |
1666 | Some(Event::Line { |
1667 | from: (point(1.0, 1.0), &[3.0]), |
1668 | to: (point(1.0, 0.0), &[2.0]), |
1669 | }) |
1670 | )); |
1671 | assert!(check( |
1672 | it.next(), |
1673 | Some(Event::Line { |
1674 | from: (point(1.0, 0.0), &[2.0]), |
1675 | to: (point(0.0, 0.0), &[1.0]), |
1676 | }) |
1677 | )); |
1678 | assert!(check( |
1679 | it.next(), |
1680 | Some(Event::End { |
1681 | last: (point(0.0, 0.0), &[1.0]), |
1682 | first: (point(0.0, 1.0), &[4.0]), |
1683 | close: false |
1684 | }) |
1685 | )); |
1686 | |
1687 | assert!(check(it.next(), None)); |
1688 | } |
1689 | |
1690 | #[test ] |
1691 | fn test_reverse_path_no_close() { |
1692 | let mut builder = Path::builder(); |
1693 | builder.begin(point(0.0, 0.0)); |
1694 | builder.line_to(point(1.0, 0.0)); |
1695 | builder.line_to(point(1.0, 1.0)); |
1696 | builder.end(false); |
1697 | |
1698 | let p1 = builder.build(); |
1699 | |
1700 | let mut it = p1.reversed(); |
1701 | |
1702 | assert_eq!( |
1703 | it.next(), |
1704 | Some(PathEvent::Begin { |
1705 | at: point(1.0, 1.0) |
1706 | }) |
1707 | ); |
1708 | assert_eq!( |
1709 | it.next(), |
1710 | Some(PathEvent::Line { |
1711 | from: point(1.0, 1.0), |
1712 | to: point(1.0, 0.0) |
1713 | }) |
1714 | ); |
1715 | assert_eq!( |
1716 | it.next(), |
1717 | Some(PathEvent::Line { |
1718 | from: point(1.0, 0.0), |
1719 | to: point(0.0, 0.0) |
1720 | }) |
1721 | ); |
1722 | assert_eq!( |
1723 | it.next(), |
1724 | Some(PathEvent::End { |
1725 | last: point(0.0, 0.0), |
1726 | first: point(1.0, 1.0), |
1727 | close: false |
1728 | }) |
1729 | ); |
1730 | assert_eq!(it.next(), None); |
1731 | } |
1732 | |
1733 | #[test ] |
1734 | fn test_reverse_empty_path() { |
1735 | let p: Path = Path::builder().build(); |
1736 | assert_eq!(p.reversed().next(), None); |
1737 | } |
1738 | |
1739 | #[test ] |
1740 | fn test_reverse_single_point() { |
1741 | let mut builder: NoAttributes = Path::builder(); |
1742 | builder.begin(at:point(x:0.0, y:0.0)); |
1743 | builder.end(close:false); |
1744 | |
1745 | let p1: Path = builder.build(); |
1746 | let mut it: NoAttributes> = p1.reversed(); |
1747 | assert_eq!( |
1748 | it.next(), |
1749 | Some(PathEvent::Begin { |
1750 | at: point(0.0, 0.0) |
1751 | }) |
1752 | ); |
1753 | assert_eq!( |
1754 | it.next(), |
1755 | Some(PathEvent::End { |
1756 | last: point(0.0, 0.0), |
1757 | first: point(0.0, 0.0), |
1758 | close: false |
1759 | }) |
1760 | ); |
1761 | assert_eq!(it.next(), None); |
1762 | } |
1763 | |
1764 | #[test ] |
1765 | fn test_path_builder_1() { |
1766 | let mut p = BuilderWithAttributes::new(1); |
1767 | p.begin(point(0.0, 0.0), &[0.0]); |
1768 | p.line_to(point(1.0, 0.0), &[1.0]); |
1769 | p.line_to(point(2.0, 0.0), &[2.0]); |
1770 | p.line_to(point(3.0, 0.0), &[3.0]); |
1771 | p.quadratic_bezier_to(point(4.0, 0.0), point(4.0, 1.0), &[4.0]); |
1772 | p.cubic_bezier_to(point(5.0, 0.0), point(5.0, 1.0), point(5.0, 2.0), &[5.0]); |
1773 | p.end(true); |
1774 | |
1775 | p.begin(point(10.0, 0.0), &[6.0]); |
1776 | p.line_to(point(11.0, 0.0), &[7.0]); |
1777 | p.line_to(point(12.0, 0.0), &[8.0]); |
1778 | p.line_to(point(13.0, 0.0), &[9.0]); |
1779 | p.quadratic_bezier_to(point(14.0, 0.0), point(14.0, 1.0), &[10.0]); |
1780 | p.cubic_bezier_to( |
1781 | point(15.0, 0.0), |
1782 | point(15.0, 1.0), |
1783 | point(15.0, 2.0), |
1784 | &[11.0], |
1785 | ); |
1786 | p.end(true); |
1787 | |
1788 | p.begin(point(1.0, 1.0), &[12.0]); |
1789 | p.end(false); |
1790 | p.begin(point(2.0, 2.0), &[13.0]); |
1791 | p.end(false); |
1792 | p.begin(point(3.0, 3.0), &[14.0]); |
1793 | p.line_to(point(4.0, 4.0), &[15.0]); |
1794 | p.end(false); |
1795 | |
1796 | let path = p.build(); |
1797 | |
1798 | let mut it = path.iter_with_attributes(); |
1799 | assert_eq!( |
1800 | it.next(), |
1801 | Some(Event::Begin { |
1802 | at: (point(0.0, 0.0), slice(&[0.0])), |
1803 | }) |
1804 | ); |
1805 | assert_eq!( |
1806 | it.next(), |
1807 | Some(Event::Line { |
1808 | from: (point(0.0, 0.0), slice(&[0.0])), |
1809 | to: (point(1.0, 0.0), slice(&[1.0])), |
1810 | }) |
1811 | ); |
1812 | assert_eq!( |
1813 | it.next(), |
1814 | Some(Event::Line { |
1815 | from: (point(1.0, 0.0), slice(&[1.0])), |
1816 | to: (point(2.0, 0.0), slice(&[2.0])), |
1817 | }) |
1818 | ); |
1819 | assert_eq!( |
1820 | it.next(), |
1821 | Some(Event::Line { |
1822 | from: (point(2.0, 0.0), slice(&[2.0])), |
1823 | to: (point(3.0, 0.0), slice(&[3.0])), |
1824 | }) |
1825 | ); |
1826 | assert_eq!( |
1827 | it.next(), |
1828 | Some(Event::Quadratic { |
1829 | from: (point(3.0, 0.0), slice(&[3.0])), |
1830 | ctrl: point(4.0, 0.0), |
1831 | to: (point(4.0, 1.0), slice(&[4.0])), |
1832 | }) |
1833 | ); |
1834 | assert_eq!( |
1835 | it.next(), |
1836 | Some(Event::Cubic { |
1837 | from: (point(4.0, 1.0), slice(&[4.0])), |
1838 | ctrl1: point(5.0, 0.0), |
1839 | ctrl2: point(5.0, 1.0), |
1840 | to: (point(5.0, 2.0), slice(&[5.0])), |
1841 | }) |
1842 | ); |
1843 | assert_eq!( |
1844 | it.next(), |
1845 | Some(Event::End { |
1846 | last: (point(5.0, 2.0), slice(&[5.0])), |
1847 | first: (point(0.0, 0.0), slice(&[0.0])), |
1848 | close: true |
1849 | }) |
1850 | ); |
1851 | |
1852 | assert_eq!( |
1853 | it.next(), |
1854 | Some(Event::Begin { |
1855 | at: (point(10.0, 0.0), slice(&[6.0])), |
1856 | }) |
1857 | ); |
1858 | assert_eq!( |
1859 | it.next(), |
1860 | Some(Event::Line { |
1861 | from: (point(10.0, 0.0), slice(&[6.0])), |
1862 | to: (point(11.0, 0.0), slice(&[7.0])), |
1863 | }) |
1864 | ); |
1865 | assert_eq!( |
1866 | it.next(), |
1867 | Some(Event::Line { |
1868 | from: (point(11.0, 0.0), slice(&[7.0])), |
1869 | to: (point(12.0, 0.0), slice(&[8.0])), |
1870 | }) |
1871 | ); |
1872 | assert_eq!( |
1873 | it.next(), |
1874 | Some(Event::Line { |
1875 | from: (point(12.0, 0.0), slice(&[8.0])), |
1876 | to: (point(13.0, 0.0), slice(&[9.0])), |
1877 | }) |
1878 | ); |
1879 | assert_eq!( |
1880 | it.next(), |
1881 | Some(Event::Quadratic { |
1882 | from: (point(13.0, 0.0), slice(&[9.0])), |
1883 | ctrl: point(14.0, 0.0), |
1884 | to: (point(14.0, 1.0), slice(&[10.0])), |
1885 | }) |
1886 | ); |
1887 | assert_eq!( |
1888 | it.next(), |
1889 | Some(Event::Cubic { |
1890 | from: (point(14.0, 1.0), slice(&[10.0])), |
1891 | ctrl1: point(15.0, 0.0), |
1892 | ctrl2: point(15.0, 1.0), |
1893 | to: (point(15.0, 2.0), slice(&[11.0])), |
1894 | }) |
1895 | ); |
1896 | assert_eq!( |
1897 | it.next(), |
1898 | Some(Event::End { |
1899 | last: (point(15.0, 2.0), slice(&[11.0])), |
1900 | first: (point(10.0, 0.0), slice(&[6.0])), |
1901 | close: true |
1902 | }) |
1903 | ); |
1904 | |
1905 | assert_eq!( |
1906 | it.next(), |
1907 | Some(Event::Begin { |
1908 | at: (point(1.0, 1.0), slice(&[12.0])) |
1909 | }) |
1910 | ); |
1911 | assert_eq!( |
1912 | it.next(), |
1913 | Some(Event::End { |
1914 | last: (point(1.0, 1.0), slice(&[12.0])), |
1915 | first: (point(1.0, 1.0), slice(&[12.0])), |
1916 | close: false |
1917 | }) |
1918 | ); |
1919 | assert_eq!( |
1920 | it.next(), |
1921 | Some(Event::Begin { |
1922 | at: (point(2.0, 2.0), slice(&[13.0])), |
1923 | }) |
1924 | ); |
1925 | assert_eq!( |
1926 | it.next(), |
1927 | Some(Event::End { |
1928 | last: (point(2.0, 2.0), slice(&[13.0])), |
1929 | first: (point(2.0, 2.0), slice(&[13.0])), |
1930 | close: false |
1931 | }) |
1932 | ); |
1933 | assert_eq!( |
1934 | it.next(), |
1935 | Some(Event::Begin { |
1936 | at: (point(3.0, 3.0), slice(&[14.0])), |
1937 | }) |
1938 | ); |
1939 | assert_eq!( |
1940 | it.next(), |
1941 | Some(Event::Line { |
1942 | from: (point(3.0, 3.0), slice(&[14.0])), |
1943 | to: (point(4.0, 4.0), slice(&[15.0])), |
1944 | }) |
1945 | ); |
1946 | assert_eq!( |
1947 | it.next(), |
1948 | Some(Event::End { |
1949 | last: (point(4.0, 4.0), slice(&[15.0])), |
1950 | first: (point(3.0, 3.0), slice(&[14.0])), |
1951 | close: false |
1952 | }) |
1953 | ); |
1954 | assert_eq!(it.next(), None); |
1955 | assert_eq!(it.next(), None); |
1956 | assert_eq!(it.next(), None); |
1957 | } |
1958 | |
1959 | #[test ] |
1960 | fn test_path_builder_empty() { |
1961 | let path: Path = Path::builder_with_attributes(num_attributes:5).build(); |
1962 | let mut it: Iter<'_> = path.iter(); |
1963 | assert_eq!(it.next(), None); |
1964 | assert_eq!(it.next(), None); |
1965 | } |
1966 | |
1967 | #[test ] |
1968 | fn test_path_builder_empty_begin() { |
1969 | let mut p = Path::builder_with_attributes(1); |
1970 | p.begin(point(1.0, 2.0), &[0.0]); |
1971 | p.end(false); |
1972 | p.begin(point(3.0, 4.0), &[1.0]); |
1973 | p.end(false); |
1974 | p.begin(point(5.0, 6.0), &[2.0]); |
1975 | p.end(false); |
1976 | |
1977 | let path = p.build(); |
1978 | let mut it = path.iter(); |
1979 | assert_eq!( |
1980 | it.next(), |
1981 | Some(PathEvent::Begin { |
1982 | at: point(1.0, 2.0) |
1983 | }) |
1984 | ); |
1985 | assert_eq!( |
1986 | it.next(), |
1987 | Some(PathEvent::End { |
1988 | last: point(1.0, 2.0), |
1989 | first: point(1.0, 2.0), |
1990 | close: false, |
1991 | }) |
1992 | ); |
1993 | assert_eq!( |
1994 | it.next(), |
1995 | Some(PathEvent::Begin { |
1996 | at: point(3.0, 4.0) |
1997 | }) |
1998 | ); |
1999 | assert_eq!( |
2000 | it.next(), |
2001 | Some(PathEvent::End { |
2002 | last: point(3.0, 4.0), |
2003 | first: point(3.0, 4.0), |
2004 | close: false, |
2005 | }) |
2006 | ); |
2007 | assert_eq!( |
2008 | it.next(), |
2009 | Some(PathEvent::Begin { |
2010 | at: point(5.0, 6.0) |
2011 | }) |
2012 | ); |
2013 | assert_eq!( |
2014 | it.next(), |
2015 | Some(PathEvent::End { |
2016 | last: point(5.0, 6.0), |
2017 | first: point(5.0, 6.0), |
2018 | close: false, |
2019 | }) |
2020 | ); |
2021 | assert_eq!(it.next(), None); |
2022 | assert_eq!(it.next(), None); |
2023 | } |
2024 | |
2025 | #[test ] |
2026 | fn test_extend_from_paths() { |
2027 | let mut builder = Path::builder(); |
2028 | builder.begin(point(0.0, 0.0)); |
2029 | builder.line_to(point(5.0, 0.0)); |
2030 | builder.line_to(point(5.0, 5.0)); |
2031 | builder.end(true); |
2032 | |
2033 | let path1 = builder.build(); |
2034 | |
2035 | let mut builder = Path::builder(); |
2036 | builder.begin(point(1.0, 1.0)); |
2037 | builder.line_to(point(4.0, 0.0)); |
2038 | builder.line_to(point(4.0, 4.0)); |
2039 | builder.end(true); |
2040 | |
2041 | let path2 = builder.build(); |
2042 | |
2043 | let mut builder = Path::builder(); |
2044 | builder.extend_from_paths(&[path1.as_slice(), path2.as_slice()]); |
2045 | let path = builder.build(); |
2046 | |
2047 | let mut it = path.iter(); |
2048 | assert_eq!( |
2049 | it.next(), |
2050 | Some(PathEvent::Begin { |
2051 | at: point(0.0, 0.0) |
2052 | }) |
2053 | ); |
2054 | assert_eq!( |
2055 | it.next(), |
2056 | Some(PathEvent::Line { |
2057 | from: point(0.0, 0.0), |
2058 | to: point(5.0, 0.0) |
2059 | }) |
2060 | ); |
2061 | assert_eq!( |
2062 | it.next(), |
2063 | Some(PathEvent::Line { |
2064 | from: point(5.0, 0.0), |
2065 | to: point(5.0, 5.0) |
2066 | }) |
2067 | ); |
2068 | assert_eq!( |
2069 | it.next(), |
2070 | Some(PathEvent::End { |
2071 | last: point(5.0, 5.0), |
2072 | first: point(0.0, 0.0), |
2073 | close: true |
2074 | }) |
2075 | ); |
2076 | assert_eq!( |
2077 | it.next(), |
2078 | Some(PathEvent::Begin { |
2079 | at: point(1.0, 1.0) |
2080 | }) |
2081 | ); |
2082 | assert_eq!( |
2083 | it.next(), |
2084 | Some(PathEvent::Line { |
2085 | from: point(1.0, 1.0), |
2086 | to: point(4.0, 0.0) |
2087 | }) |
2088 | ); |
2089 | assert_eq!( |
2090 | it.next(), |
2091 | Some(PathEvent::Line { |
2092 | from: point(4.0, 0.0), |
2093 | to: point(4.0, 4.0) |
2094 | }) |
2095 | ); |
2096 | assert_eq!( |
2097 | it.next(), |
2098 | Some(PathEvent::End { |
2099 | last: point(4.0, 4.0), |
2100 | first: point(1.0, 1.0), |
2101 | close: true |
2102 | }) |
2103 | ); |
2104 | assert_eq!(it.next(), None); |
2105 | } |
2106 | |
2107 | #[test ] |
2108 | fn flattened_custom_attributes() { |
2109 | let mut path = Path::builder_with_attributes(1); |
2110 | path.begin(point(0.0, 0.0), &[0.0]); |
2111 | path.quadratic_bezier_to(point(1.0, 0.0), point(1.0, 1.0), &[1.0]); |
2112 | path.cubic_bezier_to(point(1.0, 2.0), point(0.0, 2.0), point(0.0, 1.0), &[2.0]); |
2113 | path.end(false); |
2114 | |
2115 | let path = path.build(); |
2116 | |
2117 | let mut prev = -1.0; |
2118 | path.iter_with_attributes() |
2119 | .for_each_flattened(0.01, &mut |evt| { |
2120 | let attribute = match evt { |
2121 | Event::Begin { at: (_, attr) } => attr[0], |
2122 | Event::Line { |
2123 | from: (_, from_attr), |
2124 | to: (_, to_attr), |
2125 | } => { |
2126 | assert_eq!(from_attr[0], prev); |
2127 | to_attr[0] |
2128 | } |
2129 | Event::End { |
2130 | last: (_, last_attr), |
2131 | .. |
2132 | } => { |
2133 | assert_eq!(last_attr[0], prev); |
2134 | return; |
2135 | } |
2136 | Event::Quadratic { .. } | Event::Cubic { .. } => { |
2137 | panic!("Should not get a curve in for_each_flattened" ); |
2138 | } |
2139 | }; |
2140 | |
2141 | assert!(attribute > prev); |
2142 | prev = attribute; |
2143 | }); |
2144 | } |
2145 | |
2146 | #[test ] |
2147 | fn first_last() { |
2148 | let mut path = Path::builder_with_attributes(1); |
2149 | path.begin(point(0.0, 0.0), &[1.0]); |
2150 | path.line_to(point(2.0, 2.0), &[3.0]); |
2151 | path.line_to(point(4.0, 4.0), &[5.0]); |
2152 | path.end(false); |
2153 | let path = path.build(); |
2154 | |
2155 | assert_eq!( |
2156 | path.first_endpoint(), |
2157 | Some((point(0.0, 0.0), slice(&[1.0]))) |
2158 | ); |
2159 | assert_eq!(path.last_endpoint(), Some((point(4.0, 4.0), slice(&[5.0])))); |
2160 | |
2161 | let mut path = Path::builder_with_attributes(1); |
2162 | path.begin(point(0.0, 0.0), &[1.0]); |
2163 | path.line_to(point(2.0, 2.0), &[3.0]); |
2164 | path.line_to(point(4.0, 4.0), &[5.0]); |
2165 | path.end(true); |
2166 | let path = path.build(); |
2167 | |
2168 | assert_eq!( |
2169 | path.first_endpoint(), |
2170 | Some((point(0.0, 0.0), slice(&[1.0]))) |
2171 | ); |
2172 | assert_eq!(path.last_endpoint(), Some((point(0.0, 0.0), slice(&[1.0])))); |
2173 | } |
2174 | |
2175 | #[test ] |
2176 | fn id_events() { |
2177 | let mut path = Path::builder_with_attributes(1); |
2178 | let e1 = path.begin(point(0.0, 0.0), &[1.0]); |
2179 | let e2 = path.line_to(point(2.0, 2.0), &[3.0]); |
2180 | let e3 = path.line_to(point(4.0, 4.0), &[5.0]); |
2181 | path.end(false); |
2182 | |
2183 | let e4 = path.begin(point(6.0, 6.0), &[7.0]); |
2184 | let e5 = path.line_to(point(8.0, 8.0), &[9.0]); |
2185 | let e6 = path.line_to(point(10.0, 10.0), &[11.0]); |
2186 | path.end(true); |
2187 | |
2188 | let e7 = path.begin(point(12.0, 12.0), &[13.0]); |
2189 | let e8 = path.line_to(point(14.0, 14.0), &[15.0]); |
2190 | path.end(false); |
2191 | |
2192 | let path = path.build(); |
2193 | |
2194 | let mut iter = path.id_iter(); |
2195 | |
2196 | assert_eq!(iter.next().unwrap(), Event::Begin { at: e1 }); |
2197 | assert_eq!(iter.next().unwrap(), Event::Line { from: e1, to: e2 }); |
2198 | assert_eq!(iter.next().unwrap(), Event::Line { from: e2, to: e3 }); |
2199 | assert_eq!( |
2200 | iter.next().unwrap(), |
2201 | Event::End { |
2202 | last: e3, |
2203 | first: e1, |
2204 | close: false |
2205 | } |
2206 | ); |
2207 | |
2208 | assert_eq!(iter.next().unwrap(), Event::Begin { at: e4 }); |
2209 | assert_eq!(iter.next().unwrap(), Event::Line { from: e4, to: e5 }); |
2210 | assert_eq!(iter.next().unwrap(), Event::Line { from: e5, to: e6 }); |
2211 | assert_eq!( |
2212 | iter.next().unwrap(), |
2213 | Event::End { |
2214 | last: e6, |
2215 | first: e4, |
2216 | close: true |
2217 | } |
2218 | ); |
2219 | |
2220 | assert_eq!(iter.next().unwrap(), Event::Begin { at: e7 }); |
2221 | assert_eq!(iter.next().unwrap(), Event::Line { from: e7, to: e8 }); |
2222 | assert_eq!( |
2223 | iter.next().unwrap(), |
2224 | Event::End { |
2225 | last: e8, |
2226 | first: e7, |
2227 | close: false |
2228 | } |
2229 | ); |
2230 | |
2231 | assert_eq!(iter.next(), None); |
2232 | } |
2233 | |