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