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 | |
59 | use crate::events::{Event, IdEvent, PathEvent}; |
60 | use crate::math::Point; |
61 | use crate::{ControlPointId, EndpointId, EventId, Position, PositionStore}; |
62 | |
63 | use core::fmt; |
64 | |
65 | use crate::private::DebugValidator; |
66 | use alloc::boxed::Box; |
67 | use 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 | |
73 | mod 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)] |
89 | struct CmdIter<'l> { |
90 | ptr: *const u32, |
91 | end: *const u32, |
92 | _marker: core::marker::PhantomData<&'l u32>, |
93 | } |
94 | |
95 | impl<'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))] |
156 | pub struct PathCommands { |
157 | cmds: Box<[u32]>, |
158 | } |
159 | |
160 | impl 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 | |
223 | impl fmt::Debug for PathCommands { |
224 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
225 | self.as_slice().fmt(f) |
226 | } |
227 | } |
228 | |
229 | impl<'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 | |
238 | impl<'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)] |
246 | pub struct PathCommandsSlice<'l> { |
247 | cmds: &'l [u32], |
248 | } |
249 | |
250 | impl<'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 | |
328 | impl<'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)] |
351 | pub struct CommandsPathSlice<'l, Endpoint, ControlPoint> { |
352 | endpoints: &'l [Endpoint], |
353 | control_points: &'l [ControlPoint], |
354 | cmds: PathCommandsSlice<'l>, |
355 | } |
356 | |
357 | impl<'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 | |
376 | impl<'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 | |
385 | impl<'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 | |
394 | impl<'l, Endpoint, ControlPoint> fmt::Debug for CommandsPathSlice<'l, Endpoint, ControlPoint> |
395 | where |
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)] |
421 | pub struct PathCommandsBuilder { |
422 | cmds: Vec<u32>, |
423 | first_event_index: u32, |
424 | validator: DebugValidator, |
425 | } |
426 | |
427 | impl 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)] |
513 | pub 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 | |
521 | impl<'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 | |
596 | impl<'l, Ep, Cp> Events<'l, Ep, Cp> |
597 | where |
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)] |
613 | pub struct Iter<'l> { |
614 | cmds: CmdIter<'l>, |
615 | idx: u32, |
616 | prev_endpoint: EndpointId, |
617 | first_endpoint: EndpointId, |
618 | } |
619 | |
620 | impl<'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 | |
631 | impl<'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)] |
704 | pub 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 | |
712 | impl<'l, Endpoint, ControlPoint> Iterator for PointEvents<'l, Endpoint, ControlPoint> |
713 | where |
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 | |
790 | impl<'l, Endpoint, ControlPoint> PositionStore for CommandsPathSlice<'l, Endpoint, ControlPoint> |
791 | where |
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 ] |
807 | fn 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 ] |
818 | fn 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 ] |
833 | fn 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 ] |
842 | fn 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 ] |
970 | fn 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 | |