1 | //! A container to store multiple paths contiguously. |
2 | |
3 | use crate::builder::*; |
4 | use crate::math::*; |
5 | use crate::path; |
6 | use crate::{Attributes, EndpointId, PathSlice, NO_ATTRIBUTES}; |
7 | |
8 | use core::fmt; |
9 | use core::iter::{FromIterator, FusedIterator, IntoIterator}; |
10 | use core::ops::Range; |
11 | |
12 | use alloc::vec::Vec; |
13 | |
14 | #[derive (Clone, Debug)] |
15 | struct PathDescriptor { |
16 | points: (u32, u32), |
17 | verbs: (u32, u32), |
18 | num_attributes: u32, |
19 | } |
20 | |
21 | /// An object that stores multiple paths contiguously. |
22 | #[derive (Clone, Default)] |
23 | pub struct PathBuffer { |
24 | points: Vec<Point>, |
25 | verbs: Vec<path::Verb>, |
26 | paths: Vec<PathDescriptor>, |
27 | } |
28 | |
29 | impl PathBuffer { |
30 | #[inline ] |
31 | pub fn new() -> Self { |
32 | PathBuffer { |
33 | points: Vec::new(), |
34 | verbs: Vec::new(), |
35 | paths: Vec::new(), |
36 | } |
37 | } |
38 | |
39 | #[inline ] |
40 | pub fn with_capacity(endpoints: usize, ctrl_points: usize, paths: usize) -> Self { |
41 | let mut buffer = PathBuffer::new(); |
42 | buffer.reserve(endpoints, ctrl_points, paths); |
43 | |
44 | buffer |
45 | } |
46 | |
47 | #[inline ] |
48 | pub fn as_slice(&self) -> PathBufferSlice { |
49 | PathBufferSlice { |
50 | points: &self.points, |
51 | verbs: &self.verbs, |
52 | paths: &self.paths, |
53 | } |
54 | } |
55 | |
56 | #[inline ] |
57 | pub fn get(&self, index: usize) -> PathSlice { |
58 | let desc = &self.paths[index]; |
59 | PathSlice { |
60 | points: &self.points[desc.points.0 as usize..desc.points.1 as usize], |
61 | verbs: &self.verbs[desc.verbs.0 as usize..desc.verbs.1 as usize], |
62 | num_attributes: desc.num_attributes as usize, |
63 | } |
64 | } |
65 | |
66 | #[inline ] |
67 | pub fn indices(&self) -> Range<usize> { |
68 | 0..self.paths.len() |
69 | } |
70 | |
71 | #[inline ] |
72 | pub fn iter(&self) -> Iter<'_> { |
73 | Iter::new(&self.points, &self.verbs, &self.paths) |
74 | } |
75 | |
76 | #[inline ] |
77 | /// Returns the number of paths in the path buffer. |
78 | pub fn len(&self) -> usize { |
79 | self.paths.len() |
80 | } |
81 | |
82 | /// Returns whether the path buffer is empty. |
83 | #[inline ] |
84 | pub fn is_empty(&self) -> bool { |
85 | self.paths.is_empty() |
86 | } |
87 | |
88 | #[inline ] |
89 | pub fn builder(&mut self) -> Builder { |
90 | Builder::new(self) |
91 | } |
92 | |
93 | #[inline ] |
94 | pub fn clear(&mut self) { |
95 | self.points.clear(); |
96 | self.verbs.clear(); |
97 | self.paths.clear(); |
98 | } |
99 | |
100 | #[inline ] |
101 | pub fn reserve(&mut self, endpoints: usize, ctrl_points: usize, paths: usize) { |
102 | self.points.reserve(endpoints + ctrl_points); |
103 | self.verbs.reserve(endpoints); |
104 | self.paths.reserve(paths); |
105 | } |
106 | } |
107 | |
108 | impl fmt::Debug for PathBuffer { |
109 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
110 | self.as_slice().fmt(formatter) |
111 | } |
112 | } |
113 | |
114 | impl<'l> FromIterator<PathSlice<'l>> for PathBuffer { |
115 | fn from_iter<T: IntoIterator<Item = PathSlice<'l>>>(iter: T) -> PathBuffer { |
116 | iter.into_iter() |
117 | .fold(init:PathBuffer::new(), |mut buffer: PathBuffer, path: PathSlice<'l>| { |
118 | let builder: Builder<'_> = buffer.builder(); |
119 | pathBuilder<'_>.iter() |
120 | .fold(init:builder, |mut builder: Builder<'_>, event: Event, …>| { |
121 | builder.path_event(event, NO_ATTRIBUTES); |
122 | builder |
123 | }) |
124 | .build(); |
125 | buffer |
126 | }) |
127 | } |
128 | } |
129 | |
130 | /// A view on a `PathBuffer`. |
131 | #[derive (Clone)] |
132 | pub struct PathBufferSlice<'l> { |
133 | points: &'l [Point], |
134 | verbs: &'l [path::Verb], |
135 | paths: &'l [PathDescriptor], |
136 | } |
137 | |
138 | impl<'l> PathBufferSlice<'l> { |
139 | #[inline ] |
140 | pub fn get(&self, index: usize) -> PathSlice { |
141 | let desc = &self.paths[index]; |
142 | PathSlice { |
143 | points: &self.points[desc.points.0 as usize..desc.points.1 as usize], |
144 | verbs: &self.verbs[desc.verbs.0 as usize..desc.verbs.1 as usize], |
145 | num_attributes: desc.num_attributes as usize, |
146 | } |
147 | } |
148 | |
149 | #[inline ] |
150 | pub fn indices(&self) -> Range<usize> { |
151 | 0..self.paths.len() |
152 | } |
153 | |
154 | #[inline ] |
155 | pub fn iter(&self) -> Iter<'_> { |
156 | Iter::new(self.points, self.verbs, self.paths) |
157 | } |
158 | |
159 | /// Returns the number of paths in the path buffer. |
160 | #[inline ] |
161 | pub fn len(&self) -> usize { |
162 | self.paths.len() |
163 | } |
164 | |
165 | /// Returns whether the path buffer is empty. |
166 | #[inline ] |
167 | pub fn is_empty(&self) -> bool { |
168 | self.paths.is_empty() |
169 | } |
170 | } |
171 | |
172 | impl<'l> fmt::Debug for PathBufferSlice<'l> { |
173 | fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
174 | write!( |
175 | formatter, |
176 | "PathBuffer {{ paths: {:?}, points: {:?}, verbs: {:?}, " , |
177 | self.paths.len(), |
178 | self.points.len(), |
179 | self.verbs.len(), |
180 | )?; |
181 | for idx: usize in self.indices() { |
182 | write!(formatter, "# {idx:?}: " )?; |
183 | self.get(index:idx).fmt(formatter)?; |
184 | write!(formatter, ", " )?; |
185 | } |
186 | write!(formatter, " }}" ) |
187 | } |
188 | } |
189 | |
190 | /// A Builder that appends a path to an existing PathBuffer. |
191 | /// |
192 | /// Implements the `PathBuilder` trait. |
193 | pub struct Builder<'l> { |
194 | buffer: &'l mut PathBuffer, |
195 | builder: path::Builder, |
196 | points_start: u32, |
197 | verbs_start: u32, |
198 | } |
199 | |
200 | impl<'l> Builder<'l> { |
201 | #[inline ] |
202 | fn new(buffer: &'l mut PathBuffer) -> Self { |
203 | let mut builder = path::Path::builder(); |
204 | core::mem::swap(&mut buffer.points, &mut builder.inner_mut().points); |
205 | core::mem::swap(&mut buffer.verbs, &mut builder.inner_mut().verbs); |
206 | let points_start = builder.inner().points.len() as u32; |
207 | let verbs_start = builder.inner().verbs.len() as u32; |
208 | Builder { |
209 | buffer, |
210 | builder, |
211 | points_start, |
212 | verbs_start, |
213 | } |
214 | } |
215 | |
216 | #[inline ] |
217 | pub fn with_attributes(self, num_attributes: usize) -> BuilderWithAttributes<'l> { |
218 | assert_eq!(self.builder.inner().verbs.len(), self.verbs_start as usize); |
219 | |
220 | BuilderWithAttributes { |
221 | buffer: self.buffer, |
222 | builder: path::BuilderWithAttributes { |
223 | builder: self.builder.into_inner(), |
224 | num_attributes, |
225 | first_attributes: alloc::vec![0.0; num_attributes], |
226 | }, |
227 | points_start: self.points_start, |
228 | verbs_start: self.verbs_start, |
229 | } |
230 | } |
231 | |
232 | #[inline ] |
233 | pub fn build(mut self) -> usize { |
234 | let points_end = self.builder.inner().points.len() as u32; |
235 | let verbs_end = self.builder.inner().verbs.len() as u32; |
236 | core::mem::swap( |
237 | &mut self.builder.inner_mut().points, |
238 | &mut self.buffer.points, |
239 | ); |
240 | core::mem::swap(&mut self.builder.inner_mut().verbs, &mut self.buffer.verbs); |
241 | |
242 | let index = self.buffer.paths.len(); |
243 | self.buffer.paths.push(PathDescriptor { |
244 | points: (self.points_start, points_end), |
245 | verbs: (self.verbs_start, verbs_end), |
246 | num_attributes: 0, |
247 | }); |
248 | |
249 | index |
250 | } |
251 | |
252 | #[inline ] |
253 | fn adjust_id(&self, mut id: EndpointId) -> EndpointId { |
254 | id.0 -= self.points_start; |
255 | |
256 | id |
257 | } |
258 | |
259 | #[inline ] |
260 | pub fn begin(&mut self, at: Point) -> EndpointId { |
261 | let id = self.builder.begin(at); |
262 | self.adjust_id(id) |
263 | } |
264 | |
265 | #[inline ] |
266 | pub fn end(&mut self, close: bool) { |
267 | self.builder.end(close) |
268 | } |
269 | |
270 | #[inline ] |
271 | pub fn line_to(&mut self, to: Point) -> EndpointId { |
272 | let id = self.builder.line_to(to); |
273 | self.adjust_id(id) |
274 | } |
275 | |
276 | #[inline ] |
277 | pub fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) -> EndpointId { |
278 | let id = self.builder.quadratic_bezier_to(ctrl, to); |
279 | self.adjust_id(id) |
280 | } |
281 | |
282 | #[inline ] |
283 | pub fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) -> EndpointId { |
284 | let id = self.builder.cubic_bezier_to(ctrl1, ctrl2, to); |
285 | self.adjust_id(id) |
286 | } |
287 | |
288 | #[inline ] |
289 | pub fn reserve(&mut self, endpoints: usize, ctrl_points: usize) { |
290 | self.builder.reserve(endpoints, ctrl_points); |
291 | } |
292 | } |
293 | |
294 | impl<'l> PathBuilder for Builder<'l> { |
295 | #[inline ] |
296 | fn num_attributes(&self) -> usize { |
297 | 0 |
298 | } |
299 | |
300 | #[inline ] |
301 | fn begin(&mut self, at: Point, _attributes: Attributes) -> EndpointId { |
302 | self.begin(at) |
303 | } |
304 | |
305 | #[inline ] |
306 | fn end(&mut self, close: bool) { |
307 | self.end(close); |
308 | } |
309 | |
310 | #[inline ] |
311 | fn line_to(&mut self, to: Point, _attributes: Attributes) -> EndpointId { |
312 | self.line_to(to) |
313 | } |
314 | |
315 | #[inline ] |
316 | fn quadratic_bezier_to( |
317 | &mut self, |
318 | ctrl: Point, |
319 | to: Point, |
320 | _attributes: Attributes, |
321 | ) -> EndpointId { |
322 | self.quadratic_bezier_to(ctrl, to) |
323 | } |
324 | |
325 | #[inline ] |
326 | fn cubic_bezier_to( |
327 | &mut self, |
328 | ctrl1: Point, |
329 | ctrl2: Point, |
330 | to: Point, |
331 | _attributes: Attributes, |
332 | ) -> EndpointId { |
333 | self.cubic_bezier_to(ctrl1, ctrl2, to) |
334 | } |
335 | |
336 | #[inline ] |
337 | fn reserve(&mut self, endpoints: usize, ctrl_points: usize) { |
338 | self.reserve(endpoints, ctrl_points); |
339 | } |
340 | } |
341 | |
342 | impl<'l> Build for Builder<'l> { |
343 | type PathType = usize; |
344 | fn build(self) -> usize { |
345 | self.build() |
346 | } |
347 | } |
348 | |
349 | /// A Builder that appends a path to an existing PathBuffer, with custom attributes. |
350 | pub struct BuilderWithAttributes<'l> { |
351 | buffer: &'l mut PathBuffer, |
352 | builder: path::BuilderWithAttributes, |
353 | points_start: u32, |
354 | verbs_start: u32, |
355 | } |
356 | |
357 | impl<'l> BuilderWithAttributes<'l> { |
358 | #[inline ] |
359 | pub fn new(buffer: &'l mut PathBuffer, num_attributes: usize) -> Self { |
360 | let mut builder = path::Path::builder().into_inner(); |
361 | core::mem::swap(&mut buffer.points, &mut builder.points); |
362 | core::mem::swap(&mut buffer.verbs, &mut builder.verbs); |
363 | let points_start = builder.points.len() as u32; |
364 | let verbs_start = builder.verbs.len() as u32; |
365 | BuilderWithAttributes { |
366 | buffer, |
367 | builder: path::BuilderWithAttributes { |
368 | builder, |
369 | num_attributes, |
370 | first_attributes: alloc::vec![0.0; num_attributes], |
371 | }, |
372 | points_start, |
373 | verbs_start, |
374 | } |
375 | } |
376 | |
377 | #[inline ] |
378 | pub fn build(mut self) -> usize { |
379 | let points_end = self.builder.builder.points.len() as u32; |
380 | let verbs_end = self.builder.builder.verbs.len() as u32; |
381 | core::mem::swap(&mut self.builder.builder.points, &mut self.buffer.points); |
382 | core::mem::swap(&mut self.builder.builder.verbs, &mut self.buffer.verbs); |
383 | |
384 | let index = self.buffer.paths.len(); |
385 | self.buffer.paths.push(PathDescriptor { |
386 | points: (self.points_start, points_end), |
387 | verbs: (self.verbs_start, verbs_end), |
388 | num_attributes: 0, |
389 | }); |
390 | |
391 | index |
392 | } |
393 | |
394 | #[inline ] |
395 | fn adjust_id(&self, mut id: EndpointId) -> EndpointId { |
396 | id.0 -= self.points_start; |
397 | |
398 | id |
399 | } |
400 | |
401 | #[inline ] |
402 | pub fn begin(&mut self, at: Point, attributes: Attributes) -> EndpointId { |
403 | let id = self.builder.begin(at, attributes); |
404 | self.adjust_id(id) |
405 | } |
406 | |
407 | #[inline ] |
408 | pub fn end(&mut self, close: bool) { |
409 | self.builder.end(close) |
410 | } |
411 | |
412 | #[inline ] |
413 | pub fn line_to(&mut self, to: Point, attributes: Attributes) -> EndpointId { |
414 | let id = self.builder.line_to(to, attributes); |
415 | self.adjust_id(id) |
416 | } |
417 | |
418 | #[inline ] |
419 | pub fn quadratic_bezier_to( |
420 | &mut self, |
421 | ctrl: Point, |
422 | to: Point, |
423 | attributes: Attributes, |
424 | ) -> EndpointId { |
425 | let id = self.builder.quadratic_bezier_to(ctrl, to, attributes); |
426 | self.adjust_id(id) |
427 | } |
428 | |
429 | #[inline ] |
430 | pub fn cubic_bezier_to( |
431 | &mut self, |
432 | ctrl1: Point, |
433 | ctrl2: Point, |
434 | to: Point, |
435 | attributes: Attributes, |
436 | ) -> EndpointId { |
437 | let id = self.builder.cubic_bezier_to(ctrl1, ctrl2, to, attributes); |
438 | self.adjust_id(id) |
439 | } |
440 | |
441 | #[inline ] |
442 | pub fn reserve(&mut self, endpoints: usize, ctrl_points: usize) { |
443 | self.builder.reserve(endpoints, ctrl_points); |
444 | } |
445 | } |
446 | |
447 | impl<'l> PathBuilder for BuilderWithAttributes<'l> { |
448 | #[inline ] |
449 | fn num_attributes(&self) -> usize { |
450 | self.builder.num_attributes() |
451 | } |
452 | |
453 | #[inline ] |
454 | fn begin(&mut self, at: Point, attributes: Attributes) -> EndpointId { |
455 | self.begin(at, attributes) |
456 | } |
457 | |
458 | #[inline ] |
459 | fn end(&mut self, close: bool) { |
460 | self.end(close); |
461 | } |
462 | |
463 | #[inline ] |
464 | fn line_to(&mut self, to: Point, attributes: Attributes) -> EndpointId { |
465 | self.line_to(to, attributes) |
466 | } |
467 | |
468 | #[inline ] |
469 | fn quadratic_bezier_to( |
470 | &mut self, |
471 | ctrl: Point, |
472 | to: Point, |
473 | attributes: Attributes, |
474 | ) -> EndpointId { |
475 | self.quadratic_bezier_to(ctrl, to, attributes) |
476 | } |
477 | |
478 | #[inline ] |
479 | fn cubic_bezier_to( |
480 | &mut self, |
481 | ctrl1: Point, |
482 | ctrl2: Point, |
483 | to: Point, |
484 | attributes: Attributes, |
485 | ) -> EndpointId { |
486 | self.cubic_bezier_to(ctrl1, ctrl2, to, attributes) |
487 | } |
488 | |
489 | #[inline ] |
490 | fn reserve(&mut self, endpoints: usize, ctrl_points: usize) { |
491 | self.reserve(endpoints, ctrl_points); |
492 | } |
493 | } |
494 | |
495 | impl<'l> Build for BuilderWithAttributes<'l> { |
496 | type PathType = usize; |
497 | fn build(self) -> usize { |
498 | self.build() |
499 | } |
500 | } |
501 | |
502 | /// Iterator over the paths in a [`PathBufferSlice`]. |
503 | #[derive (Clone)] |
504 | pub struct Iter<'l> { |
505 | points: &'l [Point], |
506 | verbs: &'l [path::Verb], |
507 | paths: ::core::slice::Iter<'l, PathDescriptor>, |
508 | } |
509 | |
510 | impl<'l> Iter<'l> { |
511 | fn new(points: &'l [Point], verbs: &'l [path::Verb], paths: &'l [PathDescriptor]) -> Iter<'l> { |
512 | Iter { |
513 | points, |
514 | verbs, |
515 | paths: paths.iter(), |
516 | } |
517 | } |
518 | } |
519 | |
520 | impl<'l> Iterator for Iter<'l> { |
521 | type Item = PathSlice<'l>; |
522 | |
523 | fn next(&mut self) -> Option<PathSlice<'l>> { |
524 | let path: &'l PathDescriptor = self.paths.next()?; |
525 | Some(PathSlice { |
526 | points: &self.points[path.points.0 as usize..path.points.1 as usize], |
527 | verbs: &self.verbs[path.verbs.0 as usize..path.verbs.1 as usize], |
528 | num_attributes: path.num_attributes as usize, |
529 | }) |
530 | } |
531 | |
532 | fn size_hint(&self) -> (usize, Option<usize>) { |
533 | self.paths.size_hint() |
534 | } |
535 | } |
536 | |
537 | // slice::Iter is Fused and ExactSize |
538 | impl<'l> FusedIterator for Iter<'l> {} |
539 | impl<'l> ExactSizeIterator for Iter<'l> {} |
540 | |
541 | impl<'l> DoubleEndedIterator for Iter<'l> { |
542 | fn next_back(&mut self) -> Option<PathSlice<'l>> { |
543 | let path: &'l PathDescriptor = self.paths.next_back()?; |
544 | Some(PathSlice { |
545 | points: &self.points[path.points.0 as usize..path.points.1 as usize], |
546 | verbs: &self.verbs[path.verbs.0 as usize..path.verbs.1 as usize], |
547 | num_attributes: path.num_attributes as usize, |
548 | }) |
549 | } |
550 | } |
551 | |
552 | #[test ] |
553 | fn simple() { |
554 | use crate::PathEvent; |
555 | |
556 | let mut buffer = PathBuffer::new(); |
557 | |
558 | let mut builder = buffer.builder(); |
559 | builder.begin(point(0.0, 0.0)); |
560 | builder.line_to(point(10.0, 0.0)); |
561 | builder.line_to(point(10.0, 10.0)); |
562 | let a = builder.line_to(point(0.0, 10.0)); |
563 | builder.end(true); |
564 | |
565 | let p1 = builder.build(); |
566 | |
567 | let mut builder = buffer.builder(); |
568 | builder.begin(point(0.0, 0.0)); |
569 | builder.line_to(point(20.0, 0.0)); |
570 | builder.line_to(point(20.0, 20.0)); |
571 | let b = builder.line_to(point(0.0, 20.0)); |
572 | builder.end(false); |
573 | |
574 | let p2 = builder.build(); |
575 | |
576 | let mut iter = buffer.get(p1).iter(); |
577 | assert_eq!( |
578 | iter.next(), |
579 | Some(PathEvent::Begin { |
580 | at: point(0.0, 0.0) |
581 | }) |
582 | ); |
583 | assert_eq!( |
584 | iter.next(), |
585 | Some(PathEvent::Line { |
586 | from: point(0.0, 0.0), |
587 | to: point(10.0, 0.0) |
588 | }) |
589 | ); |
590 | assert_eq!( |
591 | iter.next(), |
592 | Some(PathEvent::Line { |
593 | from: point(10.0, 0.0), |
594 | to: point(10.0, 10.0) |
595 | }) |
596 | ); |
597 | assert_eq!( |
598 | iter.next(), |
599 | Some(PathEvent::Line { |
600 | from: point(10.0, 10.0), |
601 | to: point(0.0, 10.0) |
602 | }) |
603 | ); |
604 | assert_eq!( |
605 | iter.next(), |
606 | Some(PathEvent::End { |
607 | last: point(0.0, 10.0), |
608 | first: point(0.0, 0.0), |
609 | close: true |
610 | }) |
611 | ); |
612 | assert_eq!(iter.next(), None); |
613 | |
614 | let mut iter = buffer.get(p2).iter(); |
615 | assert_eq!( |
616 | iter.next(), |
617 | Some(PathEvent::Begin { |
618 | at: point(0.0, 0.0) |
619 | }) |
620 | ); |
621 | assert_eq!( |
622 | iter.next(), |
623 | Some(PathEvent::Line { |
624 | from: point(0.0, 0.0), |
625 | to: point(20.0, 0.0) |
626 | }) |
627 | ); |
628 | assert_eq!( |
629 | iter.next(), |
630 | Some(PathEvent::Line { |
631 | from: point(20.0, 0.0), |
632 | to: point(20.0, 20.0) |
633 | }) |
634 | ); |
635 | assert_eq!( |
636 | iter.next(), |
637 | Some(PathEvent::Line { |
638 | from: point(20.0, 20.0), |
639 | to: point(0.0, 20.0) |
640 | }) |
641 | ); |
642 | assert_eq!( |
643 | iter.next(), |
644 | Some(PathEvent::End { |
645 | last: point(0.0, 20.0), |
646 | first: point(0.0, 0.0), |
647 | close: false |
648 | }) |
649 | ); |
650 | assert_eq!(iter.next(), None); |
651 | |
652 | assert_eq!(buffer.get(p1)[a], point(0.0, 10.0)); |
653 | assert_eq!(buffer.get(p2)[b], point(0.0, 20.0)); |
654 | } |
655 | |