1//! A generic representation for paths that allow more control over how
2//! endpoints and control points are stored.
3//!
4//! # Motivation
5//!
6//! The default `Path` data structure in this crate is works well for the
7//! most common use cases. Sometimes, however, it is useful to be able to
8//! specify exactly how endpoints and control points are stored instead of
9//! relying on implicitly following the order of the events.
10//!
11//! This module contains bricks to help with building custom path representations.
12//! The central piece is the [`PathCommands`](struct.PathCommands.html) buffer and
13//! its [`PathCommandsBuilder`](struct.PathCommandsBuilder.html), providing a compact
14//! representation for path events with IDs instead of positions.
15//!
16//! # Examples
17//!
18//! The following example shows how `PathCommands` can be used together with an
19//! external buffers for positions to implement features similar to the default
20//! Path type with a different data structure.
21//!
22//! ```
23//! use lyon_path::{EndpointId, Event, IdEvent, commands::PathCommands};
24//! let points = &[
25//! [0.0, 0.0],
26//! [1.0, 1.0],
27//! [0.0, 2.0],
28//! ];
29//!
30//! let mut cmds = PathCommands::builder();
31//! cmds.begin(EndpointId(0));
32//! cmds.line_to(EndpointId(1));
33//! cmds.line_to(EndpointId(2));
34//! cmds.end(true);
35//!
36//! let cmds = cmds.build();
37//!
38//! for event in &cmds {
39//! match event {
40//! IdEvent::Begin { at } => { println!("move to {:?}", points[at.to_usize()]); }
41//! IdEvent::Line { to, .. } => { println!("line to {:?}", points[to.to_usize()]); }
42//! IdEvent::End { close: true, .. } => { println!("close"); }
43//! _ => { panic!("unexpected event!") }
44//! }
45//! }
46//!
47//! // Iterate over the points directly using CommandsPathSlice
48//! for event in cmds.path_slice(points, points).events() {
49//! match event {
50//! Event::Begin { at } => { println!("move to {:?}", at); }
51//! Event::Line { to, .. } => { println!("line to {:?}", to); }
52//! Event::End { close: true, .. } => { println!("close"); }
53//! _ => { panic!("unexpected event!") }
54//! }
55//! }
56//!
57//! ```
58
59use crate::events::{Event, IdEvent, PathEvent};
60use crate::math::Point;
61use crate::{ControlPointId, EndpointId, EventId, Position, PositionStore};
62
63use core::fmt;
64
65use crate::private::DebugValidator;
66use alloc::boxed::Box;
67use alloc::vec::Vec;
68
69// Note: Tried making the path generic over the integer type used to store
70// the commands to allow u16 and u32, but the performance difference is very
71// small and not worth the added complexity.
72
73mod verb {
74 pub const LINE: u32 = 0;
75 pub const QUADRATIC: u32 = 1;
76 pub const CUBIC: u32 = 2;
77 pub const BEGIN: u32 = 3;
78 pub const CLOSE: u32 = 4;
79 pub const END: u32 = 5;
80}
81
82/// Sadly this is very close to core::slice::Iter but reimplementing
83/// it manually to iterate over u32 makes a difference.
84/// It would seem that having next return u32 with a special value
85/// for the end of the iteration instead of Option<u32> should
86/// improve performance (simpler code and a bunch of unwraps removed),
87/// however a naive initial attempt led to worse performance.
88#[derive(Copy, Clone)]
89struct CmdIter<'l> {
90 ptr: *const u32,
91 end: *const u32,
92 _marker: core::marker::PhantomData<&'l u32>,
93}
94
95impl<'l> CmdIter<'l> {
96 fn new(slice: &'l [u32]) -> Self {
97 let ptr = slice.as_ptr();
98 let end = unsafe { ptr.add(slice.len()) };
99 CmdIter {
100 ptr,
101 end,
102 _marker: core::marker::PhantomData,
103 }
104 }
105
106 #[inline]
107 fn next(&mut self) -> Option<u32> {
108 unsafe {
109 if self.ptr == self.end {
110 return None;
111 }
112
113 let val = *self.ptr;
114 self.ptr = self.ptr.offset(1);
115
116 Some(val)
117 }
118 }
119}
120
121/// The commands of a path encoded in a single array using IDs to refer
122/// to endpoints and control points externally.
123///
124/// `PathCommands` is a good fit when the a custom endpoint and control point
125/// types are needed or when their the user needs full control over their storage.
126///
127/// # Representation
128///
129/// Path commands contains a single array of 32 bits integer values encoding path
130/// commands, endpoint IDs or control point IDs.
131///
132/// ```ascii
133/// __________________________________________________________________________
134/// | | | | | | | |
135/// | Begin |EndpointID| Line |EndpointID|Quadratic|ControlPointId|EndpointID| ...
136/// |_______|__________|______|__________|_________|______________|__________|_
137///
138/// ```
139///
140/// # Example
141///
142/// ```
143/// use lyon_path::{EndpointId, PathCommands};
144///
145/// let mut cmds = PathCommands::builder();
146///
147/// cmds.begin(EndpointId(0));
148/// cmds.line_to(EndpointId(1));
149/// cmds.line_to(EndpointId(2));
150/// cmds.end(true);
151///
152/// let cmds = cmds.build();
153///
154#[derive(Clone)]
155#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
156pub struct PathCommands {
157 cmds: Box<[u32]>,
158}
159
160impl PathCommands {
161 /// Creates a [PathCommandsBuilder](struct.PathCommandsBuilder.html) to create path commands.
162 pub fn builder() -> PathCommandsBuilder {
163 PathCommandsBuilder::new()
164 }
165
166 /// Returns an iterator over the path commands.
167 pub fn iter(&self) -> Iter {
168 Iter::new(&self.cmds)
169 }
170
171 /// Returns a view on the path commands.
172 pub fn as_slice(&self) -> PathCommandsSlice {
173 PathCommandsSlice { cmds: &self.cmds }
174 }
175
176 /// Returns a view on a path made of these commands with endpoint and
177 /// control point slices.
178 pub fn path_slice<'l, Endpoint, ControlPoint>(
179 &'l self,
180 endpoints: &'l [Endpoint],
181 control_points: &'l [ControlPoint],
182 ) -> CommandsPathSlice<Endpoint, ControlPoint> {
183 CommandsPathSlice {
184 endpoints,
185 control_points,
186 cmds: self.as_slice(),
187 }
188 }
189
190 /// Returns an iterator over the path, with endpoints and control points.
191 pub fn events<'l, Endpoint, ControlPoint>(
192 &'l self,
193 endpoints: &'l [Endpoint],
194 control_points: &'l [ControlPoint],
195 ) -> Events<Endpoint, ControlPoint> {
196 Events {
197 cmds: CmdIter::new(&self.cmds),
198 first_endpoint: 0,
199 prev_endpoint: 0,
200 endpoints,
201 control_points,
202 }
203 }
204
205 /// Returns the event for a given event ID.
206 pub fn event(&self, id: EventId) -> IdEvent {
207 self.as_slice().event(id)
208 }
209
210 /// Returns the next event id within the path.
211 pub fn next_event_id_in_path(&self, id: EventId) -> Option<EventId> {
212 self.as_slice().next_event_id_in_path(id)
213 }
214
215 /// Returns the next event id within the sub-path.
216 ///
217 /// Loops back to the first event after the end of the sub-path.
218 pub fn next_event_id_in_sub_path(&self, id: EventId) -> EventId {
219 self.as_slice().next_event_id_in_sub_path(id)
220 }
221}
222
223impl fmt::Debug for PathCommands {
224 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
225 self.as_slice().fmt(f)
226 }
227}
228
229impl<'l> IntoIterator for &'l PathCommands {
230 type Item = IdEvent;
231 type IntoIter = Iter<'l>;
232
233 fn into_iter(self) -> Iter<'l> {
234 self.iter()
235 }
236}
237
238impl<'l> From<&'l PathCommands> for PathCommandsSlice<'l> {
239 fn from(commands: &'l PathCommands) -> Self {
240 commands.as_slice()
241 }
242}
243
244/// A view over [`PathCommands`](struct.PathCommands.html).
245#[derive(Copy, Clone)]
246pub struct PathCommandsSlice<'l> {
247 cmds: &'l [u32],
248}
249
250impl<'l> PathCommandsSlice<'l> {
251 /// Returns an iterator over the path commands.
252 pub fn iter(&self) -> Iter {
253 Iter::new(self.cmds)
254 }
255
256 /// Returns the event for a given event ID.
257 pub fn event(&self, id: EventId) -> IdEvent {
258 let idx = id.to_usize();
259 match self.cmds[idx] {
260 verb::LINE => IdEvent::Line {
261 from: EndpointId(self.cmds[idx - 1]),
262 to: EndpointId(self.cmds[idx + 1]),
263 },
264 verb::QUADRATIC => IdEvent::Quadratic {
265 from: EndpointId(self.cmds[idx - 1]),
266 ctrl: ControlPointId(self.cmds[idx + 1]),
267 to: EndpointId(self.cmds[idx + 2]),
268 },
269 verb::CUBIC => IdEvent::Cubic {
270 from: EndpointId(self.cmds[idx - 1]),
271 ctrl1: ControlPointId(self.cmds[idx + 1]),
272 ctrl2: ControlPointId(self.cmds[idx + 2]),
273 to: EndpointId(self.cmds[idx + 3]),
274 },
275 verb::BEGIN => IdEvent::Begin {
276 at: EndpointId(self.cmds[idx + 1]),
277 },
278 verb::END => {
279 let first_event = self.cmds[idx + 1] as usize;
280 IdEvent::End {
281 last: EndpointId(self.cmds[idx - 1]),
282 first: EndpointId(self.cmds[first_event + 1]),
283 close: false,
284 }
285 }
286 _ => {
287 // CLOSE
288 let first_event = self.cmds[idx + 1] as usize;
289 IdEvent::End {
290 last: EndpointId(self.cmds[idx - 1]),
291 first: EndpointId(self.cmds[first_event + 1]),
292 close: true,
293 }
294 }
295 }
296 }
297
298 /// Returns the next event id within the path.
299 pub fn next_event_id_in_sub_path(&self, id: EventId) -> EventId {
300 let idx = id.to_usize();
301 match self.cmds[idx] {
302 verb::LINE | verb::BEGIN => EventId(id.0 + 2),
303 verb::QUADRATIC => EventId(id.0 + 3),
304 verb::CUBIC => EventId(id.0 + 4),
305 //verb::END | verb::CLOSE
306 _ => EventId(self.cmds[idx + 1]),
307 }
308 }
309
310 /// Returns the next event id within the path.
311 pub fn next_event_id_in_path(&self, id: EventId) -> Option<EventId> {
312 let idx = id.to_usize();
313 let next = match self.cmds[idx] {
314 verb::QUADRATIC => EventId(id.0 + 3),
315 verb::CUBIC => EventId(id.0 + 4),
316 // verb::LINE | verb::BEGIN | verb::END | verb::CLOSE
317 _ => EventId(id.0 + 2),
318 };
319
320 if next.0 < self.cmds.len() as u32 {
321 return Some(next);
322 }
323
324 None
325 }
326}
327
328impl<'l> fmt::Debug for PathCommandsSlice<'l> {
329 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
330 write!(f, "\"")?;
331 for evt: Event in self.iter() {
332 match evt {
333 IdEvent::Line { to: EndpointId, .. } => write!(f, "L {to:?}"),
334 IdEvent::Quadratic { ctrl: ControlPointId, to: EndpointId, .. } => write!(f, "Q {ctrl:?} {to:?} "),
335 IdEvent::Cubic {
336 ctrl1: ControlPointId, ctrl2: ControlPointId, to: EndpointId, ..
337 } => write!(f, "C {ctrl1:?} {ctrl2:?} {to:?} "),
338 IdEvent::Begin { at: EndpointId, .. } => write!(f, "M {at:?} "),
339 IdEvent::End { close: true, .. } => write!(f, "Z "),
340 IdEvent::End { close: false, .. } => Ok(()),
341 }?;
342 }
343 write!(f, "\"")
344 }
345}
346
347/// A view on a [`PathCommands`](struct.PathCommands.html) buffer and
348/// two slices for endpoints and control points, providing similar
349/// functionalities as `PathSlice`.
350#[derive(Copy, Clone)]
351pub struct CommandsPathSlice<'l, Endpoint, ControlPoint> {
352 endpoints: &'l [Endpoint],
353 control_points: &'l [ControlPoint],
354 cmds: PathCommandsSlice<'l>,
355}
356
357impl<'l, Endpoint, ControlPoint> CommandsPathSlice<'l, Endpoint, ControlPoint> {
358 /// Returns an iterator over the events of the path using IDs.
359 pub fn iter(&self) -> Iter {
360 self.cmds.iter()
361 }
362
363 /// Returns an iterator over the events of the path using endpoint
364 /// and control point references.
365 pub fn events(&self) -> Events<Endpoint, ControlPoint> {
366 Events {
367 cmds: CmdIter::new(self.cmds.cmds),
368 first_endpoint: 0,
369 prev_endpoint: 0,
370 endpoints: self.endpoints,
371 control_points: self.control_points,
372 }
373 }
374}
375
376impl<'l, Endpoint, ControlPoint> core::ops::Index<EndpointId>
377 for CommandsPathSlice<'l, Endpoint, ControlPoint>
378{
379 type Output = Endpoint;
380 fn index(&self, id: EndpointId) -> &Endpoint {
381 &self.endpoints[id.to_usize()]
382 }
383}
384
385impl<'l, Endpoint, ControlPoint> core::ops::Index<ControlPointId>
386 for CommandsPathSlice<'l, Endpoint, ControlPoint>
387{
388 type Output = ControlPoint;
389 fn index(&self, id: ControlPointId) -> &ControlPoint {
390 &self.control_points[id.to_usize()]
391 }
392}
393
394impl<'l, Endpoint, ControlPoint> fmt::Debug for CommandsPathSlice<'l, Endpoint, ControlPoint>
395where
396 Endpoint: fmt::Debug,
397 ControlPoint: fmt::Debug,
398{
399 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400 write!(f, "{{ ")?;
401 for evt: Event<&Endpoint, &ControlPoint> in self.events() {
402 match evt {
403 Event::Line { to: &Endpoint, .. } => write!(f, "L {to:?}"),
404 Event::Quadratic { ctrl: &ControlPoint, to: &Endpoint, .. } => write!(f, "Q {ctrl:?} {to:?} "),
405 Event::Cubic {
406 ctrl1: &ControlPoint, ctrl2: &ControlPoint, to: &Endpoint, ..
407 } => write!(f, "C {ctrl1:?} {ctrl2:?} {to:?} "),
408 Event::Begin { at: &Endpoint, .. } => write!(f, "M {at:?} "),
409 Event::End { close: true, .. } => write!(f, "Z "),
410 Event::End { close: false, .. } => Ok(()),
411 }?;
412 }
413 write!(f, "}}")
414 }
415}
416
417/// Builds path commands.
418///
419/// See [`PathCommands`](struct.PathCommands.html).
420#[derive(Debug, Default, Clone)]
421pub struct PathCommandsBuilder {
422 cmds: Vec<u32>,
423 first_event_index: u32,
424 validator: DebugValidator,
425}
426
427impl PathCommandsBuilder {
428 /// Creates a builder without allocating memory.
429 pub fn new() -> Self {
430 Self::default()
431 }
432
433 /// Creates a pre-allocated builder.
434 pub fn with_capacity(cap: usize) -> Self {
435 Self {
436 cmds: Vec::with_capacity(cap),
437 ..Self::default()
438 }
439 }
440
441 pub fn begin(&mut self, to: EndpointId) -> EventId {
442 self.validator.begin();
443
444 self.first_event_index = self.cmds.len() as u32;
445 let id = EventId(self.cmds.len() as u32);
446 self.cmds.push(verb::BEGIN);
447 self.cmds.push(to.0);
448
449 id
450 }
451
452 pub fn end(&mut self, close: bool) -> Option<EventId> {
453 self.validator.end();
454
455 let id = EventId(self.cmds.len() as u32);
456 let cmd = if close { verb::CLOSE } else { verb::END };
457 self.cmds.push(cmd);
458 self.cmds.push(self.first_event_index);
459
460 Some(id)
461 }
462
463 pub fn line_to(&mut self, to: EndpointId) -> EventId {
464 self.validator.edge();
465
466 let id = EventId(self.cmds.len() as u32);
467 self.cmds.push(verb::LINE);
468 self.cmds.push(to.0);
469
470 id
471 }
472
473 pub fn quadratic_bezier_to(&mut self, ctrl: ControlPointId, to: EndpointId) -> EventId {
474 self.validator.edge();
475
476 let id = EventId(self.cmds.len() as u32);
477 self.cmds.push(verb::QUADRATIC);
478 self.cmds.push(ctrl.0);
479 self.cmds.push(to.0);
480
481 id
482 }
483
484 pub fn cubic_bezier_to(
485 &mut self,
486 ctrl1: ControlPointId,
487 ctrl2: ControlPointId,
488 to: EndpointId,
489 ) -> EventId {
490 self.validator.edge();
491
492 let id = EventId(self.cmds.len() as u32);
493 self.cmds.push(verb::CUBIC);
494 self.cmds.push(ctrl1.0);
495 self.cmds.push(ctrl2.0);
496 self.cmds.push(to.0);
497
498 id
499 }
500
501 /// Consumes the builder and returns path commands.
502 pub fn build(self) -> PathCommands {
503 self.validator.build();
504
505 PathCommands {
506 cmds: self.cmds.into_boxed_slice(),
507 }
508 }
509}
510
511/// An iterator of `Event<&Endpoint, &ControlPoint>`.
512#[derive(Clone)]
513pub struct Events<'l, Endpoint, ControlPoint> {
514 cmds: CmdIter<'l>,
515 prev_endpoint: usize,
516 first_endpoint: usize,
517 endpoints: &'l [Endpoint],
518 control_points: &'l [ControlPoint],
519}
520
521impl<'l, Endpoint, ControlPoint> Iterator for Events<'l, Endpoint, ControlPoint> {
522 type Item = Event<&'l Endpoint, &'l ControlPoint>;
523
524 #[inline]
525 fn next(&mut self) -> Option<Event<&'l Endpoint, &'l ControlPoint>> {
526 match self.cmds.next() {
527 Some(verb::BEGIN) => {
528 let to = self.cmds.next().unwrap() as usize;
529 self.prev_endpoint = to;
530 self.first_endpoint = to;
531 Some(Event::Begin {
532 at: &self.endpoints[to],
533 })
534 }
535 Some(verb::LINE) => {
536 let to = self.cmds.next().unwrap() as usize;
537 let from = self.prev_endpoint;
538 self.prev_endpoint = to;
539 Some(Event::Line {
540 from: &self.endpoints[from],
541 to: &self.endpoints[to],
542 })
543 }
544 Some(verb::QUADRATIC) => {
545 let ctrl = self.cmds.next().unwrap() as usize;
546 let to = self.cmds.next().unwrap() as usize;
547 let from = self.prev_endpoint;
548 self.prev_endpoint = to;
549 Some(Event::Quadratic {
550 from: &self.endpoints[from],
551 ctrl: &self.control_points[ctrl],
552 to: &self.endpoints[to],
553 })
554 }
555 Some(verb::CUBIC) => {
556 let ctrl1 = self.cmds.next().unwrap() as usize;
557 let ctrl2 = self.cmds.next().unwrap() as usize;
558 let to = self.cmds.next().unwrap() as usize;
559 let from = self.prev_endpoint;
560 self.prev_endpoint = to;
561 Some(Event::Cubic {
562 from: &self.endpoints[from],
563 ctrl1: &self.control_points[ctrl1],
564 ctrl2: &self.control_points[ctrl2],
565 to: &self.endpoints[to],
566 })
567 }
568 Some(verb::END) => {
569 let _first_index = self.cmds.next();
570 let last = self.prev_endpoint;
571 let first = self.first_endpoint;
572 self.prev_endpoint = first;
573 Some(Event::End {
574 last: &self.endpoints[last],
575 first: &self.endpoints[first],
576 close: false,
577 })
578 }
579 Some(_) => {
580 // CLOSE
581 let _first_index = self.cmds.next();
582 let last = self.prev_endpoint;
583 let first = self.first_endpoint;
584 self.prev_endpoint = first;
585 Some(Event::End {
586 last: &self.endpoints[last],
587 first: &self.endpoints[first],
588 close: true,
589 })
590 }
591 None => None,
592 }
593 }
594}
595
596impl<'l, Ep, Cp> Events<'l, Ep, Cp>
597where
598 Ep: Position,
599 Cp: Position,
600{
601 pub fn points(self) -> PointEvents<'l, Ep, Cp> {
602 PointEvents {
603 cmds: self.cmds,
604 prev_endpoint: self.prev_endpoint,
605 first_endpoint: self.first_endpoint,
606 endpoints: self.endpoints,
607 control_points: self.control_points,
608 }
609 }
610}
611/// An iterator of `Event<&Endpoint, &ControlPoint>`.
612#[derive(Clone)]
613pub struct Iter<'l> {
614 cmds: CmdIter<'l>,
615 idx: u32,
616 prev_endpoint: EndpointId,
617 first_endpoint: EndpointId,
618}
619
620impl<'l> Iter<'l> {
621 fn new(cmds: &'l [u32]) -> Self {
622 Iter {
623 cmds: CmdIter::new(slice:cmds),
624 idx: 0,
625 prev_endpoint: EndpointId(0),
626 first_endpoint: EndpointId(0),
627 }
628 }
629}
630
631impl<'l> Iterator for Iter<'l> {
632 type Item = IdEvent;
633
634 #[inline]
635 fn next(&mut self) -> Option<IdEvent> {
636 match self.cmds.next() {
637 Some(verb::BEGIN) => {
638 let to = EndpointId(self.cmds.next().unwrap());
639 self.prev_endpoint = to;
640 self.first_endpoint = to;
641 self.idx += 2;
642 Some(IdEvent::Begin { at: to })
643 }
644 Some(verb::LINE) => {
645 let to = EndpointId(self.cmds.next().unwrap());
646 let from = self.prev_endpoint;
647 self.prev_endpoint = to;
648 self.idx += 2;
649 Some(IdEvent::Line { from, to })
650 }
651 Some(verb::QUADRATIC) => {
652 let ctrl = ControlPointId(self.cmds.next().unwrap());
653 let to = EndpointId(self.cmds.next().unwrap());
654 let from = self.prev_endpoint;
655 self.prev_endpoint = to;
656 self.idx += 3;
657 Some(IdEvent::Quadratic { from, ctrl, to })
658 }
659 Some(verb::CUBIC) => {
660 let ctrl1 = ControlPointId(self.cmds.next().unwrap());
661 let ctrl2 = ControlPointId(self.cmds.next().unwrap());
662 let to = EndpointId(self.cmds.next().unwrap());
663 let from = self.prev_endpoint;
664 self.prev_endpoint = to;
665 self.idx += 4;
666 Some(IdEvent::Cubic {
667 from,
668 ctrl1,
669 ctrl2,
670 to,
671 })
672 }
673 Some(verb::END) => {
674 let _first_index = self.cmds.next();
675 let last = self.prev_endpoint;
676 let first = self.first_endpoint;
677 self.prev_endpoint = first;
678 self.idx += 2;
679 Some(IdEvent::End {
680 last,
681 first,
682 close: false,
683 })
684 }
685 Some(_) => {
686 let _first_index = self.cmds.next();
687 let last = self.prev_endpoint;
688 let first = self.first_endpoint;
689 self.prev_endpoint = first;
690 self.idx += 2;
691 Some(IdEvent::End {
692 last,
693 first,
694 close: true,
695 })
696 }
697 None => None,
698 }
699 }
700}
701
702/// An iterator of `PathEvent`.
703#[derive(Clone)]
704pub struct PointEvents<'l, Endpoint, ControlPoint> {
705 cmds: CmdIter<'l>,
706 prev_endpoint: usize,
707 first_endpoint: usize,
708 endpoints: &'l [Endpoint],
709 control_points: &'l [ControlPoint],
710}
711
712impl<'l, Endpoint, ControlPoint> Iterator for PointEvents<'l, Endpoint, ControlPoint>
713where
714 Endpoint: Position,
715 ControlPoint: Position,
716{
717 type Item = PathEvent;
718
719 #[inline]
720 fn next(&mut self) -> Option<PathEvent> {
721 match self.cmds.next() {
722 Some(verb::BEGIN) => {
723 let to = self.cmds.next().unwrap() as usize;
724 self.prev_endpoint = to;
725 self.first_endpoint = to;
726 Some(Event::Begin {
727 at: self.endpoints[to].position(),
728 })
729 }
730 Some(verb::LINE) => {
731 let to = self.cmds.next().unwrap() as usize;
732 let from = self.prev_endpoint;
733 self.prev_endpoint = to;
734 Some(Event::Line {
735 from: self.endpoints[from].position(),
736 to: self.endpoints[to].position(),
737 })
738 }
739 Some(verb::QUADRATIC) => {
740 let ctrl = self.cmds.next().unwrap() as usize;
741 let to = self.cmds.next().unwrap() as usize;
742 let from = self.prev_endpoint;
743 self.prev_endpoint = to;
744 Some(Event::Quadratic {
745 from: self.endpoints[from].position(),
746 ctrl: self.control_points[ctrl].position(),
747 to: self.endpoints[to].position(),
748 })
749 }
750 Some(verb::CUBIC) => {
751 let ctrl1 = self.cmds.next().unwrap() as usize;
752 let ctrl2 = self.cmds.next().unwrap() as usize;
753 let to = self.cmds.next().unwrap() as usize;
754 let from = self.prev_endpoint;
755 self.prev_endpoint = to;
756 Some(Event::Cubic {
757 from: self.endpoints[from].position(),
758 ctrl1: self.control_points[ctrl1].position(),
759 ctrl2: self.control_points[ctrl2].position(),
760 to: self.endpoints[to].position(),
761 })
762 }
763 Some(verb::END) => {
764 let _first_index = self.cmds.next();
765 let last = self.prev_endpoint;
766 let first = self.first_endpoint;
767 self.prev_endpoint = first;
768 Some(Event::End {
769 last: self.endpoints[last].position(),
770 first: self.endpoints[first].position(),
771 close: false,
772 })
773 }
774 Some(_) => {
775 let _first_index = self.cmds.next();
776 let last = self.prev_endpoint;
777 let first = self.first_endpoint;
778 self.prev_endpoint = first;
779 Some(Event::End {
780 last: self.endpoints[last].position(),
781 first: self.endpoints[first].position(),
782 close: true,
783 })
784 }
785 None => None,
786 }
787 }
788}
789
790impl<'l, Endpoint, ControlPoint> PositionStore for CommandsPathSlice<'l, Endpoint, ControlPoint>
791where
792 Endpoint: Position,
793 ControlPoint: Position,
794{
795 fn get_endpoint(&self, id: EndpointId) -> Point {
796 self[id].position()
797 }
798
799 fn get_control_point(&self, id: ControlPointId) -> Point {
800 self[id].position()
801 }
802}
803
804#[cfg(debug_assertions)]
805#[test]
806#[should_panic]
807fn missing_begin_1() {
808 let mut builder: PathCommandsBuilder = PathCommands::builder();
809 builder.line_to(EndpointId(1));
810 builder.end(close:true);
811
812 builder.build();
813}
814
815#[cfg(debug_assertions)]
816#[test]
817#[should_panic]
818fn missing_begin_2() {
819 let mut builder: PathCommandsBuilder = PathCommands::builder();
820 builder.begin(to:EndpointId(0));
821 builder.line_to(EndpointId(1));
822 builder.end(close:true);
823
824 builder.line_to(EndpointId(1));
825 builder.end(close:true);
826
827 builder.build();
828}
829
830#[cfg(debug_assertions)]
831#[test]
832#[should_panic]
833fn missing_end() {
834 let mut builder: PathCommandsBuilder = PathCommands::builder();
835 builder.begin(to:EndpointId(0));
836 builder.line_to(EndpointId(1));
837
838 builder.build();
839}
840
841#[test]
842fn simple_path() {
843 let mut builder = PathCommands::builder();
844 builder.begin(EndpointId(0));
845 builder.line_to(EndpointId(1));
846 builder.quadratic_bezier_to(ControlPointId(2), EndpointId(3));
847 builder.cubic_bezier_to(ControlPointId(4), ControlPointId(5), EndpointId(6));
848 builder.end(false);
849
850 builder.begin(EndpointId(10));
851 builder.line_to(EndpointId(11));
852 builder.quadratic_bezier_to(ControlPointId(12), EndpointId(13));
853 builder.cubic_bezier_to(ControlPointId(14), ControlPointId(15), EndpointId(16));
854 builder.end(true);
855
856 builder.begin(EndpointId(20));
857 builder.line_to(EndpointId(21));
858 builder.quadratic_bezier_to(ControlPointId(22), EndpointId(23));
859 builder.cubic_bezier_to(ControlPointId(24), ControlPointId(25), EndpointId(26));
860 builder.end(false);
861
862 let path = builder.build();
863 let mut iter = path.iter();
864 assert_eq!(iter.next(), Some(IdEvent::Begin { at: EndpointId(0) }));
865 assert_eq!(
866 iter.next(),
867 Some(IdEvent::Line {
868 from: EndpointId(0),
869 to: EndpointId(1)
870 })
871 );
872 assert_eq!(
873 iter.next(),
874 Some(IdEvent::Quadratic {
875 from: EndpointId(1),
876 ctrl: ControlPointId(2),
877 to: EndpointId(3)
878 })
879 );
880 assert_eq!(
881 iter.next(),
882 Some(IdEvent::Cubic {
883 from: EndpointId(3),
884 ctrl1: ControlPointId(4),
885 ctrl2: ControlPointId(5),
886 to: EndpointId(6)
887 })
888 );
889 assert_eq!(
890 iter.next(),
891 Some(IdEvent::End {
892 last: EndpointId(6),
893 first: EndpointId(0),
894 close: false
895 })
896 );
897
898 assert_eq!(iter.next(), Some(IdEvent::Begin { at: EndpointId(10) }));
899 assert_eq!(
900 iter.next(),
901 Some(IdEvent::Line {
902 from: EndpointId(10),
903 to: EndpointId(11)
904 })
905 );
906 assert_eq!(
907 iter.next(),
908 Some(IdEvent::Quadratic {
909 from: EndpointId(11),
910 ctrl: ControlPointId(12),
911 to: EndpointId(13)
912 })
913 );
914 assert_eq!(
915 iter.next(),
916 Some(IdEvent::Cubic {
917 from: EndpointId(13),
918 ctrl1: ControlPointId(14),
919 ctrl2: ControlPointId(15),
920 to: EndpointId(16)
921 })
922 );
923 assert_eq!(
924 iter.next(),
925 Some(IdEvent::End {
926 last: EndpointId(16),
927 first: EndpointId(10),
928 close: true
929 })
930 );
931
932 assert_eq!(iter.next(), Some(IdEvent::Begin { at: EndpointId(20) }));
933 assert_eq!(
934 iter.next(),
935 Some(IdEvent::Line {
936 from: EndpointId(20),
937 to: EndpointId(21)
938 })
939 );
940 assert_eq!(
941 iter.next(),
942 Some(IdEvent::Quadratic {
943 from: EndpointId(21),
944 ctrl: ControlPointId(22),
945 to: EndpointId(23)
946 })
947 );
948 assert_eq!(
949 iter.next(),
950 Some(IdEvent::Cubic {
951 from: EndpointId(23),
952 ctrl1: ControlPointId(24),
953 ctrl2: ControlPointId(25),
954 to: EndpointId(26)
955 })
956 );
957 assert_eq!(
958 iter.next(),
959 Some(IdEvent::End {
960 last: EndpointId(26),
961 first: EndpointId(20),
962 close: false
963 })
964 );
965
966 assert_eq!(iter.next(), None);
967}
968
969#[test]
970fn next_event() {
971 let mut builder = PathCommands::builder();
972 builder.begin(EndpointId(0));
973 builder.line_to(EndpointId(1));
974 builder.quadratic_bezier_to(ControlPointId(2), EndpointId(3));
975 builder.cubic_bezier_to(ControlPointId(4), ControlPointId(5), EndpointId(6));
976 builder.end(false);
977
978 builder.begin(EndpointId(10));
979 builder.line_to(EndpointId(11));
980 builder.quadratic_bezier_to(ControlPointId(12), EndpointId(13));
981 builder.cubic_bezier_to(ControlPointId(14), ControlPointId(15), EndpointId(16));
982 builder.end(true);
983
984 builder.begin(EndpointId(20));
985 builder.line_to(EndpointId(21));
986 builder.quadratic_bezier_to(ControlPointId(22), EndpointId(23));
987 builder.cubic_bezier_to(ControlPointId(24), ControlPointId(25), EndpointId(26));
988 builder.end(false);
989
990 let path = builder.build();
991
992 let mut id = EventId(0);
993 let first = id;
994 assert_eq!(path.event(id), IdEvent::Begin { at: EndpointId(0) });
995 id = path.next_event_id_in_path(id).unwrap();
996 assert_eq!(
997 path.event(id),
998 IdEvent::Line {
999 from: EndpointId(0),
1000 to: EndpointId(1)
1001 }
1002 );
1003 id = path.next_event_id_in_path(id).unwrap();
1004 assert_eq!(
1005 path.event(id),
1006 IdEvent::Quadratic {
1007 from: EndpointId(1),
1008 ctrl: ControlPointId(2),
1009 to: EndpointId(3)
1010 }
1011 );
1012 id = path.next_event_id_in_path(id).unwrap();
1013 assert_eq!(
1014 path.event(id),
1015 IdEvent::Cubic {
1016 from: EndpointId(3),
1017 ctrl1: ControlPointId(4),
1018 ctrl2: ControlPointId(5),
1019 to: EndpointId(6)
1020 }
1021 );
1022 id = path.next_event_id_in_path(id).unwrap();
1023 assert_eq!(
1024 path.event(id),
1025 IdEvent::End {
1026 last: EndpointId(6),
1027 first: EndpointId(0),
1028 close: false
1029 }
1030 );
1031
1032 assert_eq!(path.next_event_id_in_sub_path(id), first);
1033
1034 id = path.next_event_id_in_path(id).unwrap();
1035 let first = id;
1036 assert_eq!(path.event(id), IdEvent::Begin { at: EndpointId(10) });
1037 id = path.next_event_id_in_path(id).unwrap();
1038 assert_eq!(
1039 path.event(id),
1040 IdEvent::Line {
1041 from: EndpointId(10),
1042 to: EndpointId(11)
1043 }
1044 );
1045 id = path.next_event_id_in_path(id).unwrap();
1046 assert_eq!(
1047 path.event(id),
1048 IdEvent::Quadratic {
1049 from: EndpointId(11),
1050 ctrl: ControlPointId(12),
1051 to: EndpointId(13)
1052 }
1053 );
1054 id = path.next_event_id_in_path(id).unwrap();
1055 assert_eq!(
1056 path.event(id),
1057 IdEvent::Cubic {
1058 from: EndpointId(13),
1059 ctrl1: ControlPointId(14),
1060 ctrl2: ControlPointId(15),
1061 to: EndpointId(16)
1062 }
1063 );
1064 id = path.next_event_id_in_path(id).unwrap();
1065 assert_eq!(
1066 path.event(id),
1067 IdEvent::End {
1068 last: EndpointId(16),
1069 first: EndpointId(10),
1070 close: true
1071 }
1072 );
1073
1074 assert_eq!(path.next_event_id_in_sub_path(id), first);
1075
1076 id = path.next_event_id_in_path(id).unwrap();
1077 let first = id;
1078 assert_eq!(path.event(id), IdEvent::Begin { at: EndpointId(20) });
1079 id = path.next_event_id_in_path(id).unwrap();
1080 assert_eq!(
1081 path.event(id),
1082 IdEvent::Line {
1083 from: EndpointId(20),
1084 to: EndpointId(21)
1085 }
1086 );
1087 id = path.next_event_id_in_path(id).unwrap();
1088 assert_eq!(
1089 path.event(id),
1090 IdEvent::Quadratic {
1091 from: EndpointId(21),
1092 ctrl: ControlPointId(22),
1093 to: EndpointId(23)
1094 }
1095 );
1096 id = path.next_event_id_in_path(id).unwrap();
1097 assert_eq!(
1098 path.event(id),
1099 IdEvent::Cubic {
1100 from: EndpointId(23),
1101 ctrl1: ControlPointId(24),
1102 ctrl2: ControlPointId(25),
1103 to: EndpointId(26)
1104 }
1105 );
1106 id = path.next_event_id_in_path(id).unwrap();
1107 assert_eq!(
1108 path.event(id),
1109 IdEvent::End {
1110 last: EndpointId(26),
1111 first: EndpointId(20),
1112 close: false
1113 }
1114 );
1115
1116 assert_eq!(path.next_event_id_in_path(id), None);
1117 assert_eq!(path.next_event_id_in_sub_path(id), first);
1118}
1119