1use crate::clip::{self, ContourPolygonClipper, ContourRectClipper};
14use crate::dilation::ContourDilator;
15use crate::orientation::Orientation;
16use crate::segment::{Segment, SegmentFlags, SegmentKind};
17use pathfinder_geometry::line_segment::LineSegment2F;
18use pathfinder_geometry::rect::RectF;
19use pathfinder_geometry::transform2d::Transform2F;
20use pathfinder_geometry::transform3d::Perspective;
21use pathfinder_geometry::unit_vector::UnitVector;
22use pathfinder_geometry::vector::{Vector2F, vec2f};
23use std::f32::consts::PI;
24use std::fmt::{self, Debug, Formatter};
25use std::mem;
26
27#[derive(Clone)]
28pub struct Outline {
29 pub(crate) contours: Vec<Contour>,
30 pub(crate) bounds: RectF,
31}
32
33#[derive(Clone)]
34pub struct Contour {
35 pub(crate) points: Vec<Vector2F>,
36 pub(crate) flags: Vec<PointFlags>,
37 pub(crate) bounds: RectF,
38 pub(crate) closed: bool,
39}
40
41bitflags! {
42 pub struct PointFlags: u8 {
43 const CONTROL_POINT_0 = 0x01;
44 const CONTROL_POINT_1 = 0x02;
45 }
46}
47
48bitflags! {
49 pub struct PushSegmentFlags: u8 {
50 const UPDATE_BOUNDS = 0x01;
51 const INCLUDE_FROM_POINT = 0x02;
52 }
53}
54
55impl Outline {
56 #[inline]
57 pub fn new() -> Outline {
58 Outline {
59 contours: vec![],
60 bounds: RectF::default(),
61 }
62 }
63
64 #[inline]
65 pub fn from_segments<I>(segments: I) -> Outline
66 where
67 I: Iterator<Item = Segment>,
68 {
69 let mut outline = Outline::new();
70 let mut current_contour = Contour::new();
71
72 for segment in segments {
73 if segment.flags.contains(SegmentFlags::FIRST_IN_SUBPATH) {
74 if !current_contour.is_empty() {
75 outline
76 .contours
77 .push(mem::replace(&mut current_contour, Contour::new()));
78 }
79 current_contour.push_point(segment.baseline.from(), PointFlags::empty(), true);
80 }
81
82 if segment.flags.contains(SegmentFlags::CLOSES_SUBPATH) {
83 if !current_contour.is_empty() {
84 current_contour.close();
85 let contour = mem::replace(&mut current_contour, Contour::new());
86 outline.push_contour(contour);
87 }
88 continue;
89 }
90
91 if segment.is_none() {
92 continue;
93 }
94
95 if !segment.is_line() {
96 current_contour.push_point(segment.ctrl.from(), PointFlags::CONTROL_POINT_0, true);
97 if !segment.is_quadratic() {
98 current_contour.push_point(
99 segment.ctrl.to(),
100 PointFlags::CONTROL_POINT_1,
101 true,
102 );
103 }
104 }
105
106 current_contour.push_point(segment.baseline.to(), PointFlags::empty(), true);
107 }
108
109 outline.push_contour(current_contour);
110 outline
111 }
112
113 #[inline]
114 pub fn from_rect(rect: RectF) -> Outline {
115 let mut outline = Outline::new();
116 outline.push_contour(Contour::from_rect(rect));
117 outline
118 }
119
120 #[inline]
121 pub fn bounds(&self) -> RectF {
122 self.bounds
123 }
124
125 #[inline]
126 pub fn contours(&self) -> &[Contour] {
127 &self.contours
128 }
129
130 #[inline]
131 pub fn into_contours(self) -> Vec<Contour> {
132 self.contours
133 }
134
135 #[inline]
137 pub fn clear(&mut self) {
138 self.contours.clear();
139 self.bounds = RectF::default();
140 }
141
142 pub fn push_contour(&mut self, contour: Contour) {
143 if contour.is_empty() {
144 return;
145 }
146
147 if self.contours.is_empty() {
148 self.bounds = contour.bounds;
149 } else {
150 self.bounds = self.bounds.union_rect(contour.bounds);
151 }
152
153 self.contours.push(contour);
154 }
155
156 pub fn pop_contour(&mut self) -> Option<Contour> {
157 let last_contour = self.contours.pop();
158
159 let mut new_bounds = None;
160 for contour in &mut self.contours {
161 contour.update_bounds(&mut new_bounds);
162 }
163 self.bounds = new_bounds.unwrap_or_else(|| RectF::default());
164
165 last_contour
166 }
167
168 pub fn transform(&mut self, transform: &Transform2F) {
169 if transform.is_identity() {
170 return;
171 }
172
173 let mut new_bounds = None;
174 for contour in &mut self.contours {
175 contour.transform(transform);
176 contour.update_bounds(&mut new_bounds);
177 }
178 self.bounds = new_bounds.unwrap_or_else(|| RectF::default());
179 }
180
181 pub fn apply_perspective(&mut self, perspective: &Perspective) {
182 let mut new_bounds = None;
183 for contour in &mut self.contours {
184 contour.apply_perspective(perspective);
185 contour.update_bounds(&mut new_bounds);
186 }
187 self.bounds = new_bounds.unwrap_or_else(|| RectF::default());
188 }
189
190 pub fn dilate(&mut self, amount: Vector2F) {
191 let orientation = Orientation::from_outline(self);
192 self.contours
193 .iter_mut()
194 .for_each(|contour| contour.dilate(amount, orientation));
195 self.bounds = self.bounds.dilate(amount);
196 }
197
198 pub fn prepare_for_tiling(&mut self, view_box: RectF) {
199 self.contours
200 .iter_mut()
201 .for_each(|contour| contour.prepare_for_tiling(view_box));
202 self.bounds = self
203 .bounds
204 .intersection(view_box)
205 .unwrap_or_else(|| RectF::default());
206 }
207
208 pub fn is_outside_polygon(&self, clip_polygon: &[Vector2F]) -> bool {
209 clip::rect_is_outside_polygon(self.bounds, clip_polygon)
210 }
211
212 fn is_inside_polygon(&self, clip_polygon: &[Vector2F]) -> bool {
213 clip::rect_is_inside_polygon(self.bounds, clip_polygon)
214 }
215
216 pub fn clip_against_polygon(&mut self, clip_polygon: &[Vector2F]) {
217 if self.is_inside_polygon(clip_polygon) {
219 return;
220 }
221
222 for contour in mem::replace(&mut self.contours, vec![]) {
223 self.push_contour(ContourPolygonClipper::new(clip_polygon, contour).clip());
224 }
225 }
226
227 pub fn clip_against_rect(&mut self, clip_rect: RectF) {
228 if clip_rect.contains_rect(self.bounds) {
229 return;
230 }
231
232 for contour in mem::replace(&mut self.contours, vec![]) {
233 self.push_contour(ContourRectClipper::new(clip_rect, contour).clip());
234 }
235 }
236
237 #[inline]
238 pub fn close_all_contours(&mut self) {
239 self.contours.iter_mut().for_each(|contour| contour.close());
240 }
241}
242
243impl Debug for Outline {
244 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
245 for (contour_index, contour) in self.contours.iter().enumerate() {
246 if contour_index > 0 {
247 write!(formatter, " ")?;
248 }
249 contour.fmt(formatter)?;
250 }
251 Ok(())
252 }
253}
254
255impl Contour {
256 #[inline]
257 pub fn new() -> Contour {
258 Contour {
259 points: vec![],
260 flags: vec![],
261 bounds: RectF::default(),
262 closed: false,
263 }
264 }
265
266 #[inline]
267 pub fn with_capacity(length: usize) -> Contour {
268 Contour {
269 points: Vec::with_capacity(length),
270 flags: Vec::with_capacity(length),
271 bounds: RectF::default(),
272 closed: false,
273 }
274 }
275
276 #[inline]
277 pub fn from_rect(rect: RectF) -> Contour {
278 let mut contour = Contour::new();
279 contour.push_point(rect.origin(), PointFlags::empty(), false);
280 contour.push_point(rect.upper_right(), PointFlags::empty(), false);
281 contour.push_point(rect.lower_right(), PointFlags::empty(), false);
282 contour.push_point(rect.lower_left(), PointFlags::empty(), false);
283 contour.close();
284 contour.bounds = rect;
285 contour
286 }
287
288 #[inline]
290 pub(crate) fn take(&mut self) -> Contour {
291 let length = self.len() as usize;
292 mem::replace(
293 self,
294 Contour {
295 points: Vec::with_capacity(length),
296 flags: Vec::with_capacity(length),
297 bounds: RectF::default(),
298 closed: false,
299 },
300 )
301 }
302
303 #[inline]
305 pub fn clear(&mut self) {
306 self.points.clear();
307 self.flags.clear();
308 self.bounds = RectF::default();
309 self.closed = false;
310 }
311
312 #[inline]
313 pub fn iter(&self, flags: ContourIterFlags) -> ContourIter {
314 ContourIter {
315 contour: self,
316 index: 1,
317 flags,
318 }
319 }
320
321 #[inline]
322 pub fn is_empty(&self) -> bool {
323 self.points.is_empty()
324 }
325
326 #[inline]
327 pub fn len(&self) -> u32 {
328 self.points.len() as u32
329 }
330
331 #[inline]
332 pub fn bounds(&self) -> RectF {
333 self.bounds
334 }
335
336 #[inline]
337 pub fn is_closed(&self) -> bool {
338 self.closed
339 }
340
341 #[inline]
342 pub fn position_of(&self, index: u32) -> Vector2F {
343 self.points[index as usize]
344 }
345
346 #[inline]
347 pub fn last_position(&self) -> Option<Vector2F> {
348 self.points.last().cloned()
349 }
350
351 #[inline]
352 pub(crate) fn position_of_last(&self, index: u32) -> Vector2F {
353 self.points[self.points.len() - index as usize]
354 }
355
356 #[inline]
357 pub fn push_endpoint(&mut self, point: Vector2F) {
358 self.push_point(point, PointFlags::empty(), true);
359 }
360
361 #[inline]
362 pub fn push_quadratic(&mut self, ctrl: Vector2F, point: Vector2F) {
363 self.push_point(ctrl, PointFlags::CONTROL_POINT_0, true);
364 self.push_point(point, PointFlags::empty(), true);
365 }
366
367 #[inline]
368 pub fn push_cubic(&mut self, ctrl0: Vector2F, ctrl1: Vector2F, point: Vector2F) {
369 self.push_point(ctrl0, PointFlags::CONTROL_POINT_0, true);
370 self.push_point(ctrl1, PointFlags::CONTROL_POINT_1, true);
371 self.push_point(point, PointFlags::empty(), true);
372 }
373
374 #[inline]
375 pub fn close(&mut self) {
376 self.closed = true;
377 }
378
379 #[inline]
380 pub(crate) fn push_point(&mut self,
381 point: Vector2F,
382 flags: PointFlags,
383 update_bounds: bool) {
384 debug_assert!(!point.x().is_nan() && !point.y().is_nan());
385
386 if update_bounds {
387 let first = self.is_empty();
388 union_rect(&mut self.bounds, point, first);
389 }
390
391 self.points.push(point);
392 self.flags.push(flags);
393 }
394
395 #[inline]
396 pub(crate) fn push_segment(&mut self, segment: &Segment, flags: PushSegmentFlags) {
397 if segment.is_none() {
398 return;
399 }
400
401 let update_bounds = flags.contains(PushSegmentFlags::UPDATE_BOUNDS);
402 self.push_point(segment.baseline.from(), PointFlags::empty(), update_bounds);
403
404 if !segment.is_line() {
405 self.push_point(
406 segment.ctrl.from(),
407 PointFlags::CONTROL_POINT_0,
408 update_bounds,
409 );
410 if !segment.is_quadratic() {
411 self.push_point(
412 segment.ctrl.to(),
413 PointFlags::CONTROL_POINT_1,
414 update_bounds,
415 );
416 }
417 }
418
419 self.push_point(segment.baseline.to(), PointFlags::empty(), update_bounds);
420 }
421
422 pub fn push_arc(&mut self,
423 transform: &Transform2F,
424 start_angle: f32,
425 end_angle: f32,
426 direction: ArcDirection) {
427 if end_angle - start_angle >= PI * 2.0 {
428 self.push_ellipse(transform);
429 } else {
430 let start = vec2f(start_angle.cos(), start_angle.sin());
431 let end = vec2f(end_angle.cos(), end_angle.sin());
432 self.push_arc_from_unit_chord(transform, LineSegment2F::new(start, end), direction);
433 }
434 }
435
436 pub fn push_arc_from_unit_chord(&mut self,
437 transform: &Transform2F,
438 mut chord: LineSegment2F,
439 direction: ArcDirection) {
440 let mut direction_transform = Transform2F::default();
441 if direction == ArcDirection::CCW {
442 chord *= vec2f(1.0, -1.0);
443 direction_transform = Transform2F::from_scale(vec2f(1.0, -1.0));
444 }
445
446 let (mut vector, end_vector) = (UnitVector(chord.from()), UnitVector(chord.to()));
447 for segment_index in 0..4 {
448 debug!("push_arc_from_unit_chord(): loop segment index {}", segment_index);
449
450 let mut sweep_vector = end_vector.rev_rotate_by(vector);
451 let last = sweep_vector.0.x() >= -EPSILON && sweep_vector.0.y() >= -EPSILON;
452 debug!("... end_vector={:?} vector={:?} sweep_vector={:?} last={:?}",
453 end_vector,
454 vector,
455 sweep_vector,
456 last);
457
458 let mut segment;
459 if !last {
460 sweep_vector = UnitVector(vec2f(0.0, 1.0));
461 segment = Segment::quarter_circle_arc();
462 } else {
463 segment = Segment::arc_from_cos(sweep_vector.0.x());
464 }
465
466 let half_sweep_vector = sweep_vector.halve_angle();
467 let rotation = Transform2F::from_rotation_vector(half_sweep_vector.rotate_by(vector));
468 segment = segment.transform(&(*transform * direction_transform * rotation));
469
470 let mut push_segment_flags = PushSegmentFlags::UPDATE_BOUNDS;
471 if segment_index == 0 {
472 push_segment_flags.insert(PushSegmentFlags::INCLUDE_FROM_POINT);
473 }
474 self.push_segment(&segment, push_segment_flags);
475
476 if last {
477 break;
478 }
479
480 vector = vector.rotate_by(sweep_vector);
481 }
482
483 const EPSILON: f32 = 0.001;
484 }
485
486 pub fn push_ellipse(&mut self, transform: &Transform2F) {
487 let segment = Segment::quarter_circle_arc();
488 let mut rotation;
489 self.push_segment(&segment.transform(transform),
490 PushSegmentFlags::UPDATE_BOUNDS | PushSegmentFlags::INCLUDE_FROM_POINT);
491 rotation = Transform2F::from_rotation_vector(UnitVector(vec2f( 0.0, 1.0)));
492 self.push_segment(&segment.transform(&(*transform * rotation)),
493 PushSegmentFlags::UPDATE_BOUNDS);
494 rotation = Transform2F::from_rotation_vector(UnitVector(vec2f(-1.0, 0.0)));
495 self.push_segment(&segment.transform(&(*transform * rotation)),
496 PushSegmentFlags::UPDATE_BOUNDS);
497 rotation = Transform2F::from_rotation_vector(UnitVector(vec2f( 0.0, -1.0)));
498 self.push_segment(&segment.transform(&(*transform * rotation)),
499 PushSegmentFlags::UPDATE_BOUNDS);
500 }
501
502 #[inline]
503 pub fn segment_after(&self, point_index: u32) -> Segment {
504 debug_assert!(self.point_is_endpoint(point_index));
505
506 let mut segment = Segment::none();
507 segment.baseline.set_from(self.position_of(point_index));
508
509 let point1_index = self.add_to_point_index(point_index, 1);
510 if self.point_is_endpoint(point1_index) {
511 segment.baseline.set_to(self.position_of(point1_index));
512 segment.kind = SegmentKind::Line;
513 } else {
514 segment.ctrl.set_from(self.position_of(point1_index));
515
516 let point2_index = self.add_to_point_index(point_index, 2);
517 if self.point_is_endpoint(point2_index) {
518 segment.baseline.set_to(self.position_of(point2_index));
519 segment.kind = SegmentKind::Quadratic;
520 } else {
521 segment.ctrl.set_to(self.position_of(point2_index));
522 segment.kind = SegmentKind::Cubic;
523
524 let point3_index = self.add_to_point_index(point_index, 3);
525 segment.baseline.set_to(self.position_of(point3_index));
526 }
527 }
528
529 segment
530 }
531
532 #[inline]
533 pub fn hull_segment_after(&self, prev_point_index: u32) -> LineSegment2F {
534 let next_point_index = self.next_point_index_of(prev_point_index);
535 LineSegment2F::new(
536 self.points[prev_point_index as usize],
537 self.points[next_point_index as usize],
538 )
539 }
540
541 #[inline]
542 pub fn point_is_endpoint(&self, point_index: u32) -> bool {
543 !self.flags[point_index as usize]
544 .intersects(PointFlags::CONTROL_POINT_0 | PointFlags::CONTROL_POINT_1)
545 }
546
547 #[inline]
548 pub fn add_to_point_index(&self, point_index: u32, addend: u32) -> u32 {
549 let (index, limit) = (point_index + addend, self.len());
550 if index >= limit {
551 index - limit
552 } else {
553 index
554 }
555 }
556
557 #[inline]
558 pub fn point_is_logically_above(&self, a: u32, b: u32) -> bool {
559 let (a_y, b_y) = (self.points[a as usize].y(), self.points[b as usize].y());
560 a_y < b_y || (a_y == b_y && a < b)
561 }
562
563 #[inline]
564 pub fn prev_endpoint_index_of(&self, mut point_index: u32) -> u32 {
565 loop {
566 point_index = self.prev_point_index_of(point_index);
567 if self.point_is_endpoint(point_index) {
568 return point_index;
569 }
570 }
571 }
572
573 #[inline]
574 pub fn next_endpoint_index_of(&self, mut point_index: u32) -> u32 {
575 loop {
576 point_index = self.next_point_index_of(point_index);
577 if self.point_is_endpoint(point_index) {
578 return point_index;
579 }
580 }
581 }
582
583 #[inline]
584 pub fn prev_point_index_of(&self, point_index: u32) -> u32 {
585 if point_index == 0 {
586 self.len() - 1
587 } else {
588 point_index - 1
589 }
590 }
591
592 #[inline]
593 pub fn next_point_index_of(&self, point_index: u32) -> u32 {
594 if point_index == self.len() - 1 {
595 0
596 } else {
597 point_index + 1
598 }
599 }
600
601 pub fn transform(&mut self, transform: &Transform2F) {
602 if transform.is_identity() {
603 return;
604 }
605
606 for (point_index, point) in self.points.iter_mut().enumerate() {
607 *point = *transform * *point;
608 union_rect(&mut self.bounds, *point, point_index == 0);
609 }
610 }
611
612 pub fn apply_perspective(&mut self, perspective: &Perspective) {
613 for (point_index, point) in self.points.iter_mut().enumerate() {
614 *point = *perspective * *point;
615 union_rect(&mut self.bounds, *point, point_index == 0);
616 }
617 }
618
619 pub fn dilate(&mut self, amount: Vector2F, orientation: Orientation) {
620 ContourDilator::new(self, amount, orientation).dilate();
621 self.bounds = self.bounds.dilate(amount);
622 }
623
624 fn prepare_for_tiling(&mut self, view_box: RectF) {
625 let (mut last_endpoint_index, mut contour_is_monotonic) = (None, true);
628 for point_index in 0..(self.points.len() as u32) {
629 if contour_is_monotonic {
630 if self.point_is_endpoint(point_index) {
631 if let Some(last_endpoint_index) = last_endpoint_index {
632 if !self.curve_with_endpoints_is_monotonic(last_endpoint_index,
633 point_index) {
634 contour_is_monotonic = false;
635 }
636 }
637 last_endpoint_index = Some(point_index);
638 }
639 }
640 }
641
642 if !contour_is_monotonic {
644 self.make_monotonic();
645 }
646
647 self.bounds = self
649 .bounds
650 .intersection(view_box)
651 .unwrap_or_else(|| RectF::default());
652 }
653
654 fn make_monotonic(&mut self) {
655 debug!("--- make_monotonic() ---");
656
657 let contour = self.take();
658 self.bounds = contour.bounds;
659
660 let mut last_endpoint_index = None;
661 let input_point_count = contour.points.len() as u32;
662 for point_index in 0..(input_point_count + 1) {
663 if point_index < input_point_count && !contour.point_is_endpoint(point_index) {
664 continue;
665 }
666
667 if let Some(last_endpoint_index) = last_endpoint_index {
668 let position_index = if point_index == input_point_count {
669 0
670 } else {
671 point_index
672 };
673 let baseline = LineSegment2F::new(
674 contour.points[last_endpoint_index as usize],
675 contour.points[position_index as usize],
676 );
677 let point_count = point_index - last_endpoint_index + 1;
678 if point_count == 3 {
679 let ctrl_point_index = last_endpoint_index as usize + 1;
680 let ctrl_position = &contour.points[ctrl_point_index];
681 handle_cubic(
682 self,
683 &Segment::quadratic(baseline, *ctrl_position).to_cubic(),
684 );
685 } else if point_count == 4 {
686 let first_ctrl_point_index = last_endpoint_index as usize + 1;
687 let ctrl_position_0 = &contour.points[first_ctrl_point_index + 0];
688 let ctrl_position_1 = &contour.points[first_ctrl_point_index + 1];
689 let ctrl = LineSegment2F::new(*ctrl_position_0, *ctrl_position_1);
690 handle_cubic(self, &Segment::cubic(baseline, ctrl));
691 }
692
693 self.push_point(
694 contour.points[position_index as usize],
695 PointFlags::empty(),
696 false,
697 );
698 }
699
700 last_endpoint_index = Some(point_index);
701 }
702
703 fn handle_cubic(contour: &mut Contour, segment: &Segment) {
704 debug!("handle_cubic({:?})", segment);
705
706 match segment.as_cubic_segment().y_extrema() {
707 (Some(t0), Some(t1)) => {
708 let (segments_01, segment_2) = segment.as_cubic_segment().split(t1);
709 let (segment_0, segment_1) = segments_01.as_cubic_segment().split(t0 / t1);
710 contour.push_segment(&segment_0, PushSegmentFlags::empty());
711 contour.push_segment(&segment_1, PushSegmentFlags::empty());
712 contour.push_segment(&segment_2, PushSegmentFlags::empty());
713 }
714 (Some(t0), None) | (None, Some(t0)) => {
715 let (segment_0, segment_1) = segment.as_cubic_segment().split(t0);
716 contour.push_segment(&segment_0, PushSegmentFlags::empty());
717 contour.push_segment(&segment_1, PushSegmentFlags::empty());
718 }
719 (None, None) => contour.push_segment(segment, PushSegmentFlags::empty()),
720 }
721 }
722 }
723
724 fn curve_with_endpoints_is_monotonic(
725 &self,
726 start_endpoint_index: u32,
727 end_endpoint_index: u32,
728 ) -> bool {
729 let start_position = self.points[start_endpoint_index as usize];
730 let end_position = self.points[end_endpoint_index as usize];
731
732 if start_position.x() <= end_position.x() {
733 for point_index in start_endpoint_index..end_endpoint_index {
734 if self.points[point_index as usize].x() > self.points[point_index as usize + 1].x()
735 {
736 return false;
737 }
738 }
739 } else {
740 for point_index in start_endpoint_index..end_endpoint_index {
741 if self.points[point_index as usize].x() < self.points[point_index as usize + 1].x()
742 {
743 return false;
744 }
745 }
746 }
747
748 if start_position.y() <= end_position.y() {
749 for point_index in start_endpoint_index..end_endpoint_index {
750 if self.points[point_index as usize].y() > self.points[point_index as usize + 1].y()
751 {
752 return false;
753 }
754 }
755 } else {
756 for point_index in start_endpoint_index..end_endpoint_index {
757 if self.points[point_index as usize].y() < self.points[point_index as usize + 1].y()
758 {
759 return false;
760 }
761 }
762 }
763
764 true
765 }
766
767 pub(crate) fn update_bounds(&self, bounds: &mut Option<RectF>) {
770 *bounds = Some(match *bounds {
771 None => self.bounds,
772 Some(bounds) => bounds.union_rect(self.bounds),
773 })
774 }
775}
776
777impl Debug for Contour {
778 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
779 for (segment_index, segment) in self.iter(ContourIterFlags::IGNORE_CLOSE_SEGMENT)
780 .enumerate() {
781 if segment_index == 0 {
782 write!(
783 formatter,
784 "M {} {}",
785 segment.baseline.from_x(),
786 segment.baseline.from_y()
787 )?;
788 }
789
790 match segment.kind {
791 SegmentKind::None => {}
792 SegmentKind::Line => {
793 write!(
794 formatter,
795 " L {} {}",
796 segment.baseline.to_x(),
797 segment.baseline.to_y()
798 )?;
799 }
800 SegmentKind::Quadratic => {
801 write!(
802 formatter,
803 " Q {} {} {} {}",
804 segment.ctrl.from_x(),
805 segment.ctrl.from_y(),
806 segment.baseline.to_x(),
807 segment.baseline.to_y()
808 )?;
809 }
810 SegmentKind::Cubic => {
811 write!(
812 formatter,
813 " C {} {} {} {} {} {}",
814 segment.ctrl.from_x(),
815 segment.ctrl.from_y(),
816 segment.ctrl.to_x(),
817 segment.ctrl.to_y(),
818 segment.baseline.to_x(),
819 segment.baseline.to_y()
820 )?;
821 }
822 }
823 }
824
825 if self.closed {
826 write!(formatter, " z")?;
827 }
828
829 Ok(())
830 }
831}
832
833#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
834pub struct PointIndex(u32);
835
836impl PointIndex {
837 #[inline]
838 pub fn new(contour: u32, point: u32) -> PointIndex {
839 debug_assert!(contour <= 0xfff);
840 debug_assert!(point <= 0x000f_ffff);
841 PointIndex((contour << 20) | point)
842 }
843
844 #[inline]
845 pub fn contour(self) -> u32 {
846 self.0 >> 20
847 }
848
849 #[inline]
850 pub fn point(self) -> u32 {
851 self.0 & 0x000f_ffff
852 }
853}
854
855pub struct ContourIter<'a> {
856 contour: &'a Contour,
857 index: u32,
858 flags: ContourIterFlags,
859}
860
861impl<'a> Iterator for ContourIter<'a> {
862 type Item = Segment;
863
864 #[inline]
865 fn next(&mut self) -> Option<Segment> {
866 let contour = self.contour;
867
868 let include_close_segment = self.contour.closed &&
869 !self.flags.contains(ContourIterFlags::IGNORE_CLOSE_SEGMENT);
870 if (self.index == contour.len() && !include_close_segment) ||
871 self.index == contour.len() + 1 {
872 return None;
873 }
874
875 let point0_index = self.index - 1;
876 let point0 = contour.position_of(point0_index);
877 if self.index == contour.len() {
878 let point1 = contour.position_of(0);
879 self.index += 1;
880 return Some(Segment::line(LineSegment2F::new(point0, point1)));
881 }
882
883 let point1_index = self.index;
884 self.index += 1;
885 let point1 = contour.position_of(point1_index);
886 if contour.point_is_endpoint(point1_index) {
887 return Some(Segment::line(LineSegment2F::new(point0, point1)));
888 }
889
890 let point2_index = self.index;
891 let point2 = contour.position_of(point2_index);
892 self.index += 1;
893 if contour.point_is_endpoint(point2_index) {
894 return Some(Segment::quadratic(LineSegment2F::new(point0, point2), point1));
895 }
896
897 let point3_index = self.index;
898 let point3 = contour.position_of(point3_index);
899 self.index += 1;
900 debug_assert!(contour.point_is_endpoint(point3_index));
901 return Some(Segment::cubic(
902 LineSegment2F::new(point0, point3),
903 LineSegment2F::new(point1, point2),
904 ));
905 }
906}
907
908#[derive(Clone, Copy, Debug, PartialEq)]
909pub enum ArcDirection {
910 CW,
911 CCW,
912}
913
914bitflags! {
915 pub struct ContourIterFlags: u8 {
916 const IGNORE_CLOSE_SEGMENT = 1;
917 }
918}
919
920#[inline]
921pub(crate) fn union_rect(bounds: &mut RectF, new_point: Vector2F, first: bool) {
922 if first {
923 *bounds = RectF::from_points(new_point, new_point);
924 } else {
925 *bounds = bounds.union_point(new_point)
926 }
927}