1use crate::events::{Event, PathEvent};
83use crate::geom::{traits::Transformation, Arc, ArcFlags, LineSegment, SvgArc};
84use crate::math::*;
85use crate::path::Verb;
86use crate::polygon::Polygon;
87use crate::{Attributes, EndpointId, Winding, NO_ATTRIBUTES};
88
89use core::f32::consts::PI;
90use core::marker::Sized;
91
92use alloc::vec;
93use alloc::vec::Vec;
94
95#[cfg(not(feature = "std"))]
96use num_traits::Float;
97
98#[derive(Copy, Clone, PartialEq, PartialOrd, Debug, Default)]
100pub struct BorderRadii {
101 pub top_left: f32,
102 pub top_right: f32,
103 pub bottom_left: f32,
104 pub bottom_right: f32,
105}
106
107impl BorderRadii {
108 pub fn new(radius: f32) -> Self {
109 let r = radius.abs();
110 BorderRadii {
111 top_left: r,
112 top_right: r,
113 bottom_left: r,
114 bottom_right: r,
115 }
116 }
117}
118
119impl core::fmt::Display for BorderRadii {
120 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
121 write!(
123 f,
124 "BorderRadii({}, {}, {}, {})",
125 self.top_left, self.top_right, self.bottom_left, self.bottom_right
126 )
127 }
128}
129
130#[derive(Clone, Debug, PartialEq, Hash)]
137#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
138pub struct NoAttributes<B: PathBuilder> {
139 pub(crate) inner: B,
140}
141
142impl<B: PathBuilder> NoAttributes<B> {
143 #[inline]
144 pub fn wrap(inner: B) -> Self {
145 assert_eq!(inner.num_attributes(), 0);
146 NoAttributes { inner }
147 }
148
149 pub fn new() -> Self
150 where
151 B: Default,
152 {
153 NoAttributes::wrap(B::default())
154 }
155
156 pub fn with_capacity(endpoints: usize, ctrl_points: usize) -> Self
157 where
158 B: Default,
159 {
160 let mut builder = B::default();
161 builder.reserve(endpoints, ctrl_points);
162 NoAttributes::wrap(builder)
163 }
164
165 #[inline]
170 pub fn begin(&mut self, at: Point) -> EndpointId {
171 self.inner.begin(at, NO_ATTRIBUTES)
172 }
173
174 #[inline]
180 pub fn end(&mut self, close: bool) {
181 self.inner.end(close);
182 }
183
184 #[inline]
188 pub fn close(&mut self) {
189 self.inner.close();
190 }
191
192 #[inline]
196 pub fn line_to(&mut self, to: Point) -> EndpointId {
197 self.inner.line_to(to, NO_ATTRIBUTES)
198 }
199
200 #[inline]
204 pub fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) -> EndpointId {
205 self.inner.quadratic_bezier_to(ctrl, to, NO_ATTRIBUTES)
206 }
207
208 #[inline]
212 pub fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) -> EndpointId {
213 self.inner.cubic_bezier_to(ctrl1, ctrl2, to, NO_ATTRIBUTES)
214 }
215
216 #[inline]
222 pub fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
223 self.inner.reserve(endpoints, ctrl_points);
224 }
225
226 #[inline]
233 pub fn path_event(&mut self, event: PathEvent) {
234 self.inner.path_event(event, NO_ATTRIBUTES);
235 }
236
237 #[inline]
242 pub fn add_polygon(&mut self, polygon: Polygon<Point>) {
243 self.inner.add_polygon(polygon, NO_ATTRIBUTES);
244 }
245
246 #[inline]
251 pub fn add_point(&mut self, at: Point) -> EndpointId {
252 self.inner.add_point(at, NO_ATTRIBUTES)
253 }
254
255 #[inline]
260 pub fn add_line_segment(&mut self, line: &LineSegment<f32>) -> (EndpointId, EndpointId) {
261 self.inner.add_line_segment(line, NO_ATTRIBUTES)
262 }
263
264 #[inline]
269 pub fn add_ellipse(
270 &mut self,
271 center: Point,
272 radii: Vector,
273 x_rotation: Angle,
274 winding: Winding,
275 ) {
276 self.inner
277 .add_ellipse(center, radii, x_rotation, winding, NO_ATTRIBUTES);
278 }
279
280 #[inline]
285 pub fn add_circle(&mut self, center: Point, radius: f32, winding: Winding)
286 where
287 B: Sized,
288 {
289 self.inner
290 .add_circle(center, radius, winding, NO_ATTRIBUTES);
291 }
292
293 #[inline]
298 pub fn add_rectangle(&mut self, rect: &Box2D, winding: Winding) {
299 self.inner.add_rectangle(rect, winding, NO_ATTRIBUTES);
300 }
301
302 #[inline]
307 pub fn add_rounded_rectangle(&mut self, rect: &Box2D, radii: &BorderRadii, winding: Winding)
308 where
309 B: Sized,
310 {
311 self.inner
312 .add_rounded_rectangle(rect, radii, winding, NO_ATTRIBUTES);
313 }
314
315 #[inline]
317 pub fn flattened(self, tolerance: f32) -> NoAttributes<Flattened<B>>
318 where
319 B: Sized,
320 {
321 NoAttributes {
322 inner: Flattened::new(self.inner, tolerance),
323 }
324 }
325
326 #[inline]
328 pub fn transformed<Transform>(
329 self,
330 transform: Transform,
331 ) -> NoAttributes<Transformed<B, Transform>>
332 where
333 B: Sized,
334 Transform: Transformation<f32>,
335 {
336 NoAttributes {
337 inner: Transformed::new(self.inner, transform),
338 }
339 }
340
341 #[inline]
345 pub fn with_svg(self) -> WithSvg<B>
346 where
347 B: Sized,
348 {
349 WithSvg::new(self.inner)
350 }
351
352 #[inline]
354 pub fn build<P>(self) -> P
355 where
356 B: Build<PathType = P>,
357 {
358 self.inner.build()
359 }
360
361 #[inline]
362 pub fn inner(&self) -> &B {
363 &self.inner
364 }
365
366 #[inline]
367 pub fn inner_mut(&mut self) -> &mut B {
368 &mut self.inner
369 }
370
371 #[inline]
372 pub fn into_inner(self) -> B {
373 self.inner
374 }
375}
376
377impl<B: PathBuilder> PathBuilder for NoAttributes<B> {
378 #[inline]
379 fn num_attributes(&self) -> usize {
380 0
381 }
382
383 #[inline]
384 fn begin(&mut self, at: Point, _attributes: Attributes) -> EndpointId {
385 self.inner.begin(at, NO_ATTRIBUTES)
386 }
387
388 #[inline]
389 fn end(&mut self, close: bool) {
390 self.inner.end(close);
391 }
392
393 #[inline]
394 fn line_to(&mut self, to: Point, _attributes: Attributes) -> EndpointId {
395 self.inner.line_to(to, NO_ATTRIBUTES)
396 }
397
398 #[inline]
399 fn quadratic_bezier_to(
400 &mut self,
401 ctrl: Point,
402 to: Point,
403 _attributes: Attributes,
404 ) -> EndpointId {
405 self.inner.quadratic_bezier_to(ctrl, to, NO_ATTRIBUTES)
406 }
407
408 #[inline]
409 fn cubic_bezier_to(
410 &mut self,
411 ctrl1: Point,
412 ctrl2: Point,
413 to: Point,
414 _attributes: Attributes,
415 ) -> EndpointId {
416 self.inner.cubic_bezier_to(ctrl1, ctrl2, to, NO_ATTRIBUTES)
417 }
418
419 #[inline]
420 fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
421 self.inner.reserve(endpoints, ctrl_points)
422 }
423}
424
425impl<B: PathBuilder + Build> Build for NoAttributes<B> {
426 type PathType = B::PathType;
427
428 fn build(self) -> B::PathType {
429 self.inner.build()
430 }
431}
432
433impl<B: PathBuilder + Default> Default for NoAttributes<B> {
434 fn default() -> Self {
435 Self::new()
436 }
437}
438
439pub trait PathBuilder {
452 fn num_attributes(&self) -> usize;
453 fn begin(&mut self, at: Point, custom_attributes: Attributes) -> EndpointId;
458
459 fn end(&mut self, close: bool);
465
466 fn close(&mut self) {
470 self.end(true)
471 }
472
473 fn line_to(&mut self, to: Point, custom_attributes: Attributes) -> EndpointId;
477
478 fn quadratic_bezier_to(
482 &mut self,
483 ctrl: Point,
484 to: Point,
485 custom_attributes: Attributes,
486 ) -> EndpointId;
487
488 fn cubic_bezier_to(
492 &mut self,
493 ctrl1: Point,
494 ctrl2: Point,
495 to: Point,
496 custom_attributes: Attributes,
497 ) -> EndpointId;
498
499 fn reserve(&mut self, _endpoints: usize, _ctrl_points: usize) {}
505
506 fn path_event(&mut self, event: PathEvent, attributes: Attributes) {
513 match event {
514 PathEvent::Begin { at } => {
515 self.begin(at, attributes);
516 }
517 PathEvent::Line { to, .. } => {
518 self.line_to(to, attributes);
519 }
520 PathEvent::Quadratic { ctrl, to, .. } => {
521 self.quadratic_bezier_to(ctrl, to, attributes);
522 }
523 PathEvent::Cubic {
524 ctrl1, ctrl2, to, ..
525 } => {
526 self.cubic_bezier_to(ctrl1, ctrl2, to, attributes);
527 }
528 PathEvent::End { close, .. } => {
529 self.end(close);
530 }
531 }
532 }
533
534 fn event(&mut self, event: Event<(Point, Attributes), Point>) {
535 match event {
536 Event::Begin { at } => {
537 self.begin(at.0, at.1);
538 }
539 Event::Line { to, .. } => {
540 self.line_to(to.0, to.1);
541 }
542 Event::Quadratic { ctrl, to, .. } => {
543 self.quadratic_bezier_to(ctrl, to.0, to.1);
544 }
545 Event::Cubic {
546 ctrl1, ctrl2, to, ..
547 } => {
548 self.cubic_bezier_to(ctrl1, ctrl2, to.0, to.1);
549 }
550 Event::End { close, .. } => {
551 self.end(close);
552 }
553 }
554 }
555
556 fn add_polygon(&mut self, polygon: Polygon<Point>, attributes: Attributes) {
561 if polygon.points.is_empty() {
562 return;
563 }
564
565 self.reserve(polygon.points.len(), 0);
566
567 self.begin(polygon.points[0], attributes);
568 for p in &polygon.points[1..] {
569 self.line_to(*p, attributes);
570 }
571
572 self.end(polygon.closed);
573 }
574
575 fn add_point(&mut self, at: Point, attributes: Attributes) -> EndpointId {
580 let id = self.begin(at, attributes);
581 self.end(false);
582
583 id
584 }
585
586 fn add_line_segment(
591 &mut self,
592 line: &LineSegment<f32>,
593 attributes: Attributes,
594 ) -> (EndpointId, EndpointId) {
595 let a = self.begin(line.from, attributes);
596 let b = self.line_to(line.to, attributes);
597 self.end(false);
598
599 (a, b)
600 }
601
602 fn add_ellipse(
607 &mut self,
608 center: Point,
609 radii: Vector,
610 x_rotation: Angle,
611 winding: Winding,
612 attributes: Attributes,
613 ) {
614 let dir = match winding {
615 Winding::Positive => 1.0,
616 Winding::Negative => -1.0,
617 };
618
619 let arc = Arc {
620 center,
621 radii,
622 x_rotation,
623 start_angle: Angle::radians(0.0),
624 sweep_angle: Angle::radians(2.0 * PI) * dir,
625 };
626
627 self.begin(arc.sample(0.0), attributes);
628 arc.for_each_quadratic_bezier(&mut |curve| {
629 self.quadratic_bezier_to(curve.ctrl, curve.to, attributes);
630 });
631 self.end(true);
632 }
633
634 fn add_circle(&mut self, center: Point, radius: f32, winding: Winding, attributes: Attributes)
639 where
640 Self: Sized,
641 {
642 add_circle(self, center, radius, winding, attributes);
643 }
644
645 fn add_rectangle(&mut self, rect: &Box2D, winding: Winding, attributes: Attributes) {
650 match winding {
651 Winding::Positive => self.add_polygon(
652 Polygon {
653 points: &[
654 rect.min,
655 point(rect.max.x, rect.min.y),
656 rect.max,
657 point(rect.min.x, rect.max.y),
658 ],
659 closed: true,
660 },
661 attributes,
662 ),
663 Winding::Negative => self.add_polygon(
664 Polygon {
665 points: &[
666 rect.min,
667 point(rect.min.x, rect.max.y),
668 rect.max,
669 point(rect.max.x, rect.min.y),
670 ],
671 closed: true,
672 },
673 attributes,
674 ),
675 };
676 }
677
678 fn add_rounded_rectangle(
683 &mut self,
684 rect: &Box2D,
685 radii: &BorderRadii,
686 winding: Winding,
687 custom_attributes: Attributes,
688 ) where
689 Self: Sized,
690 {
691 add_rounded_rectangle(self, rect, radii, winding, custom_attributes);
692 }
693
694 fn flattened(self, tolerance: f32) -> Flattened<Self>
696 where
697 Self: Sized,
698 {
699 Flattened::new(self, tolerance)
700 }
701
702 fn transformed<Transform>(self, transform: Transform) -> Transformed<Self, Transform>
704 where
705 Self: Sized,
706 Transform: Transformation<f32>,
707 {
708 Transformed::new(self, transform)
709 }
710
711 fn with_svg(self) -> WithSvg<Self>
715 where
716 Self: Sized,
717 {
718 WithSvg::new(self)
719 }
720}
721
722pub trait SvgPathBuilder {
731 fn move_to(&mut self, to: Point);
739
740 fn close(&mut self);
749
750 fn line_to(&mut self, to: Point);
758
759 fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point);
768
769 fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point);
778
779 fn relative_move_to(&mut self, to: Vector);
786
787 fn relative_line_to(&mut self, to: Vector);
794
795 fn relative_quadratic_bezier_to(&mut self, ctrl: Vector, to: Vector);
802
803 fn relative_cubic_bezier_to(&mut self, ctrl1: Vector, ctrl2: Vector, to: Vector);
810
811 fn smooth_cubic_bezier_to(&mut self, ctrl2: Point, to: Point);
821
822 fn smooth_relative_cubic_bezier_to(&mut self, ctrl2: Vector, to: Vector);
829
830 fn smooth_quadratic_bezier_to(&mut self, to: Point);
839
840 fn smooth_relative_quadratic_bezier_to(&mut self, to: Vector);
847
848 fn horizontal_line_to(&mut self, x: f32);
854
855 fn relative_horizontal_line_to(&mut self, dx: f32);
862
863 fn vertical_line_to(&mut self, y: f32);
869
870 fn relative_vertical_line_to(&mut self, dy: f32);
877
878 fn arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Point);
889
890 fn relative_arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Vector);
897
898 fn reserve(&mut self, _endpoints: usize, _ctrl_points: usize) {}
904
905 fn add_polygon(&mut self, polygon: Polygon<Point>) {
910 if polygon.points.is_empty() {
911 return;
912 }
913
914 self.reserve(polygon.points.len(), 0);
915
916 self.move_to(polygon.points[0]);
917 for p in &polygon.points[1..] {
918 self.line_to(*p);
919 }
920
921 if polygon.closed {
922 self.close();
923 }
924 }
925}
926
927pub trait Build {
933 type PathType;
935
936 fn build(self) -> Self::PathType;
938}
939
940pub struct Flattened<Builder> {
942 builder: Builder,
943 current_position: Point,
944 tolerance: f32,
945 prev_attributes: Vec<f32>,
946 attribute_buffer: Vec<f32>,
947}
948
949impl<Builder: Build> Build for Flattened<Builder> {
950 type PathType = Builder::PathType;
951
952 fn build(self) -> Builder::PathType {
953 self.builder.build()
954 }
955}
956
957impl<Builder: PathBuilder> PathBuilder for Flattened<Builder> {
958 fn num_attributes(&self) -> usize {
959 self.builder.num_attributes()
960 }
961
962 fn begin(&mut self, at: Point, attributes: Attributes) -> EndpointId {
963 self.current_position = at;
964 self.prev_attributes.copy_from_slice(attributes);
965 self.builder.begin(at, attributes)
966 }
967
968 fn end(&mut self, close: bool) {
969 self.builder.end(close)
970 }
971
972 fn line_to(&mut self, to: Point, attributes: Attributes) -> EndpointId {
973 let id = self.builder.line_to(to, attributes);
974 self.current_position = to;
975 self.prev_attributes.copy_from_slice(attributes);
976 id
977 }
978
979 fn quadratic_bezier_to(
980 &mut self,
981 ctrl: Point,
982 to: Point,
983 attributes: Attributes,
984 ) -> EndpointId {
985 let id = crate::private::flatten_quadratic_bezier(
986 self.tolerance,
987 self.current_position,
988 ctrl,
989 to,
990 attributes,
991 &self.prev_attributes,
992 &mut self.builder,
993 &mut self.attribute_buffer,
994 );
995 self.current_position = to;
996 self.prev_attributes.copy_from_slice(attributes);
997
998 id
999 }
1000
1001 fn cubic_bezier_to(
1002 &mut self,
1003 ctrl1: Point,
1004 ctrl2: Point,
1005 to: Point,
1006 attributes: Attributes,
1007 ) -> EndpointId {
1008 let id = crate::private::flatten_cubic_bezier(
1009 self.tolerance,
1010 self.current_position,
1011 ctrl1,
1012 ctrl2,
1013 to,
1014 attributes,
1015 &self.prev_attributes,
1016 &mut self.builder,
1017 &mut self.attribute_buffer,
1018 );
1019 self.current_position = to;
1020 self.prev_attributes.copy_from_slice(attributes);
1021
1022 id
1023 }
1024
1025 fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
1026 self.builder.reserve(endpoints + ctrl_points * 4, 0);
1027 }
1028}
1029
1030impl<Builder: PathBuilder> Flattened<Builder> {
1031 pub fn new(builder: Builder, tolerance: f32) -> Flattened<Builder> {
1032 let n = builder.num_attributes();
1033 Flattened {
1034 builder,
1035 current_position: point(0.0, 0.0),
1036 tolerance,
1037 prev_attributes: vec![0.0; n],
1038 attribute_buffer: vec![0.0; n],
1039 }
1040 }
1041
1042 pub fn build(self) -> Builder::PathType
1043 where
1044 Builder: Build,
1045 {
1046 self.builder.build()
1047 }
1048
1049 pub fn set_tolerance(&mut self, tolerance: f32) {
1050 self.tolerance = tolerance
1051 }
1052}
1053
1054pub struct Transformed<Builder, Transform> {
1056 builder: Builder,
1057 transform: Transform,
1058}
1059
1060impl<Builder, Transform> Transformed<Builder, Transform> {
1061 #[inline]
1062 pub fn new(builder: Builder, transform: Transform) -> Self {
1063 Transformed { builder, transform }
1064 }
1065
1066 #[inline]
1067 pub fn set_transform(&mut self, transform: Transform) {
1068 self.transform = transform;
1069 }
1070}
1071
1072impl<Builder: Build, Transform> Build for Transformed<Builder, Transform> {
1073 type PathType = Builder::PathType;
1074
1075 #[inline]
1076 fn build(self) -> Builder::PathType {
1077 self.builder.build()
1078 }
1079}
1080
1081impl<Builder, Transform> PathBuilder for Transformed<Builder, Transform>
1082where
1083 Builder: PathBuilder,
1084 Transform: Transformation<f32>,
1085{
1086 fn num_attributes(&self) -> usize {
1087 self.builder.num_attributes()
1088 }
1089
1090 #[inline]
1091 fn begin(&mut self, at: Point, attributes: Attributes) -> EndpointId {
1092 self.builder
1093 .begin(self.transform.transform_point(at), attributes)
1094 }
1095
1096 #[inline]
1097 fn end(&mut self, close: bool) {
1098 self.builder.end(close)
1099 }
1100
1101 #[inline]
1102 fn line_to(&mut self, to: Point, attributes: Attributes) -> EndpointId {
1103 self.builder
1104 .line_to(self.transform.transform_point(to), attributes)
1105 }
1106
1107 #[inline]
1108 fn quadratic_bezier_to(
1109 &mut self,
1110 ctrl: Point,
1111 to: Point,
1112 attributes: Attributes,
1113 ) -> EndpointId {
1114 self.builder.quadratic_bezier_to(
1115 self.transform.transform_point(ctrl),
1116 self.transform.transform_point(to),
1117 attributes,
1118 )
1119 }
1120
1121 #[inline]
1122 fn cubic_bezier_to(
1123 &mut self,
1124 ctrl1: Point,
1125 ctrl2: Point,
1126 to: Point,
1127 attributes: Attributes,
1128 ) -> EndpointId {
1129 self.builder.cubic_bezier_to(
1130 self.transform.transform_point(ctrl1),
1131 self.transform.transform_point(ctrl2),
1132 self.transform.transform_point(to),
1133 attributes,
1134 )
1135 }
1136
1137 #[inline]
1138 fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
1139 self.builder.reserve(endpoints, ctrl_points);
1140 }
1141}
1142
1143pub struct WithSvg<Builder: PathBuilder> {
1145 builder: Builder,
1146
1147 first_position: Point,
1148 current_position: Point,
1149 last_ctrl: Point,
1150 last_cmd: Verb,
1151 need_moveto: bool,
1152 is_empty: bool,
1153 attribute_buffer: Vec<f32>,
1154}
1155
1156impl<Builder: PathBuilder> WithSvg<Builder> {
1157 pub fn new(builder: Builder) -> Self {
1158 let attribute_buffer = vec![0.0; builder.num_attributes()];
1159 WithSvg {
1160 builder,
1161 first_position: point(0.0, 0.0),
1162 current_position: point(0.0, 0.0),
1163 last_ctrl: point(0.0, 0.0),
1164 need_moveto: true,
1165 is_empty: true,
1166 last_cmd: Verb::End,
1167 attribute_buffer,
1168 }
1169 }
1170
1171 pub fn build(mut self) -> Builder::PathType
1172 where
1173 Builder: Build,
1174 {
1175 self.end_if_needed();
1176 self.builder.build()
1177 }
1178
1179 pub fn flattened(self, tolerance: f32) -> WithSvg<Flattened<Builder>> {
1180 WithSvg::new(Flattened::new(self.builder, tolerance))
1181 }
1182
1183 pub fn transformed<Transform>(
1184 self,
1185 transform: Transform,
1186 ) -> WithSvg<Transformed<Builder, Transform>>
1187 where
1188 Transform: Transformation<f32>,
1189 {
1190 WithSvg::new(Transformed::new(self.builder, transform))
1191 }
1192
1193 pub fn move_to(&mut self, to: Point) -> EndpointId {
1194 self.end_if_needed();
1195
1196 let id = self.builder.begin(to, &self.attribute_buffer);
1197
1198 self.is_empty = false;
1199 self.need_moveto = false;
1200 self.first_position = to;
1201 self.current_position = to;
1202 self.last_cmd = Verb::Begin;
1203
1204 id
1205 }
1206
1207 pub fn line_to(&mut self, to: Point) -> EndpointId {
1208 if let Some(id) = self.begin_if_needed(&to) {
1209 return id;
1210 }
1211
1212 self.current_position = to;
1213 self.last_cmd = Verb::LineTo;
1214
1215 self.builder.line_to(to, &self.attribute_buffer)
1216 }
1217
1218 pub fn close(&mut self) {
1219 if self.need_moveto {
1220 return;
1221 }
1222
1223 self.current_position = self.first_position;
1240 self.need_moveto = true;
1241 self.last_cmd = Verb::Close;
1242
1243 self.builder.close();
1244 }
1245
1246 pub fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) -> EndpointId {
1247 if let Some(id) = self.begin_if_needed(&to) {
1248 return id;
1249 }
1250
1251 self.current_position = to;
1252 self.last_cmd = Verb::QuadraticTo;
1253 self.last_ctrl = ctrl;
1254
1255 self.builder
1256 .quadratic_bezier_to(ctrl, to, &self.attribute_buffer)
1257 }
1258
1259 pub fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) -> EndpointId {
1260 if let Some(id) = self.begin_if_needed(&to) {
1261 return id;
1262 }
1263
1264 self.current_position = to;
1265 self.last_cmd = Verb::CubicTo;
1266 self.last_ctrl = ctrl2;
1267
1268 self.builder
1269 .cubic_bezier_to(ctrl1, ctrl2, to, &self.attribute_buffer)
1270 }
1271
1272 pub fn arc(&mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle) {
1273 nan_check(center);
1274 nan_check(radii.to_point());
1275 debug_assert!(!sweep_angle.get().is_nan());
1276 debug_assert!(!x_rotation.get().is_nan());
1277
1278 self.last_ctrl = self.current_position;
1279
1280 use lyon_geom::euclid::approxeq::ApproxEq;
1284 if self.current_position.approx_eq(¢er) {
1285 return;
1286 }
1287
1288 let start_angle = (self.current_position - center).angle_from_x_axis() - x_rotation;
1289
1290 let arc = Arc {
1291 center,
1292 radii,
1293 start_angle,
1294 sweep_angle,
1295 x_rotation,
1296 };
1297
1298 let arc_start = arc.from();
1301 if self.need_moveto {
1302 self.move_to(arc_start);
1303 } else if (arc_start - self.current_position).square_length() > 0.01 {
1304 self.builder.line_to(arc_start, &self.attribute_buffer);
1305 }
1306
1307 arc.for_each_quadratic_bezier(&mut |curve| {
1308 self.builder
1309 .quadratic_bezier_to(curve.ctrl, curve.to, &self.attribute_buffer);
1310 self.current_position = curve.to;
1311 });
1312 }
1313
1314 #[inline(always)]
1318 fn begin_if_needed(&mut self, default: &Point) -> Option<EndpointId> {
1319 if self.need_moveto {
1320 return self.insert_move_to(default);
1321 }
1322
1323 None
1324 }
1325
1326 #[inline(never)]
1327 fn insert_move_to(&mut self, default: &Point) -> Option<EndpointId> {
1328 if self.is_empty {
1329 return Some(self.move_to(*default));
1330 }
1331
1332 self.move_to(self.first_position);
1333
1334 None
1335 }
1336
1337 fn end_if_needed(&mut self) {
1338 if (self.last_cmd as u8) <= (Verb::Begin as u8) {
1339 self.builder.end(false);
1340 }
1341 }
1342
1343 pub fn current_position(&self) -> Point {
1344 self.current_position
1345 }
1346
1347 pub fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
1348 self.builder.reserve(endpoints, ctrl_points);
1349 }
1350
1351 fn get_smooth_cubic_ctrl(&self) -> Point {
1352 match self.last_cmd {
1353 Verb::CubicTo => self.current_position + (self.current_position - self.last_ctrl),
1354 _ => self.current_position,
1355 }
1356 }
1357
1358 fn get_smooth_quadratic_ctrl(&self) -> Point {
1359 match self.last_cmd {
1360 Verb::QuadraticTo => self.current_position + (self.current_position - self.last_ctrl),
1361 _ => self.current_position,
1362 }
1363 }
1364
1365 fn relative_to_absolute(&self, v: Vector) -> Point {
1366 self.current_position + v
1367 }
1368}
1369
1370impl<Builder, Transform> WithSvg<Transformed<Builder, Transform>>
1371where
1372 Builder: PathBuilder,
1373 Transform: Transformation<f32>,
1374{
1375 #[inline]
1376 pub fn set_transform(&mut self, transform: Transform) {
1377 self.builder.set_transform(transform);
1378 }
1379}
1380
1381impl<Builder: PathBuilder + Build> Build for WithSvg<Builder> {
1382 type PathType = Builder::PathType;
1383
1384 fn build(mut self) -> Builder::PathType {
1385 self.end_if_needed();
1386 self.builder.build()
1387 }
1388}
1389
1390impl<Builder: PathBuilder> SvgPathBuilder for WithSvg<Builder> {
1391 fn move_to(&mut self, to: Point) {
1392 self.move_to(to);
1393 }
1394
1395 fn close(&mut self) {
1396 self.close();
1397 }
1398
1399 fn line_to(&mut self, to: Point) {
1400 self.line_to(to);
1401 }
1402
1403 fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) {
1404 self.quadratic_bezier_to(ctrl, to);
1405 }
1406
1407 fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) {
1408 self.cubic_bezier_to(ctrl1, ctrl2, to);
1409 }
1410
1411 fn relative_move_to(&mut self, to: Vector) {
1412 let to = self.relative_to_absolute(to);
1413 self.move_to(to);
1414 }
1415
1416 fn relative_line_to(&mut self, to: Vector) {
1417 let to = self.relative_to_absolute(to);
1418 self.line_to(to);
1419 }
1420
1421 fn relative_quadratic_bezier_to(&mut self, ctrl: Vector, to: Vector) {
1422 let ctrl = self.relative_to_absolute(ctrl);
1423 let to = self.relative_to_absolute(to);
1424 self.quadratic_bezier_to(ctrl, to);
1425 }
1426
1427 fn relative_cubic_bezier_to(&mut self, ctrl1: Vector, ctrl2: Vector, to: Vector) {
1428 let to = self.relative_to_absolute(to);
1429 let ctrl1 = self.relative_to_absolute(ctrl1);
1430 let ctrl2 = self.relative_to_absolute(ctrl2);
1431 self.cubic_bezier_to(ctrl1, ctrl2, to);
1432 }
1433
1434 fn smooth_cubic_bezier_to(&mut self, ctrl2: Point, to: Point) {
1435 let ctrl1 = self.get_smooth_cubic_ctrl();
1436 self.cubic_bezier_to(ctrl1, ctrl2, to);
1437 }
1438
1439 fn smooth_relative_cubic_bezier_to(&mut self, ctrl2: Vector, to: Vector) {
1440 let ctrl1 = self.get_smooth_cubic_ctrl();
1441 let ctrl2 = self.relative_to_absolute(ctrl2);
1442 let to = self.relative_to_absolute(to);
1443 self.cubic_bezier_to(ctrl1, ctrl2, to);
1444 }
1445
1446 fn smooth_quadratic_bezier_to(&mut self, to: Point) {
1447 let ctrl = self.get_smooth_quadratic_ctrl();
1448 self.quadratic_bezier_to(ctrl, to);
1449 }
1450
1451 fn smooth_relative_quadratic_bezier_to(&mut self, to: Vector) {
1452 let ctrl = self.get_smooth_quadratic_ctrl();
1453 let to = self.relative_to_absolute(to);
1454 self.quadratic_bezier_to(ctrl, to);
1455 }
1456
1457 fn horizontal_line_to(&mut self, x: f32) {
1458 let y = self.current_position.y;
1459 self.line_to(point(x, y));
1460 }
1461
1462 fn relative_horizontal_line_to(&mut self, dx: f32) {
1463 let p = self.current_position;
1464 self.line_to(point(p.x + dx, p.y));
1465 }
1466
1467 fn vertical_line_to(&mut self, y: f32) {
1468 let x = self.current_position.x;
1469 self.line_to(point(x, y));
1470 }
1471
1472 fn relative_vertical_line_to(&mut self, dy: f32) {
1473 let p = self.current_position;
1474 self.line_to(point(p.x, p.y + dy));
1475 }
1476
1477 fn arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Point) {
1478 let svg_arc = SvgArc {
1479 from: self.current_position,
1480 to,
1481 radii,
1482 x_rotation,
1483 flags: ArcFlags {
1484 large_arc: flags.large_arc,
1485 sweep: flags.sweep,
1486 },
1487 };
1488
1489 if svg_arc.is_straight_line() {
1490 self.line_to(to);
1491 } else {
1492 let arc = svg_arc.to_arc();
1493 self.arc(arc.center, arc.radii, arc.sweep_angle, arc.x_rotation);
1494 }
1495 }
1496
1497 fn relative_arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Vector) {
1498 let to = self.relative_to_absolute(to);
1499 self.arc_to(radii, x_rotation, flags, to);
1500 }
1501
1502 fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
1503 self.builder.reserve(endpoints, ctrl_points);
1504 }
1505}
1506
1507fn add_circle<Builder: PathBuilder>(
1509 builder: &mut Builder,
1510 center: Point,
1511 radius: f32,
1512 winding: Winding,
1513 attributes: Attributes,
1514) {
1515 let radius = radius.abs();
1516 let dir = match winding {
1517 Winding::Positive => 1.0,
1518 Winding::Negative => -1.0,
1519 };
1520
1521 const CONSTANT_FACTOR: f32 = 0.55191505;
1523 let d = radius * CONSTANT_FACTOR;
1524
1525 builder.begin(center + vector(-radius, 0.0), attributes);
1526
1527 let ctrl_0 = center + vector(-radius, -d * dir);
1528 let ctrl_1 = center + vector(-d, -radius * dir);
1529 let mid = center + vector(0.0, -radius * dir);
1530 builder.cubic_bezier_to(ctrl_0, ctrl_1, mid, attributes);
1531
1532 let ctrl_0 = center + vector(d, -radius * dir);
1533 let ctrl_1 = center + vector(radius, -d * dir);
1534 let mid = center + vector(radius, 0.0);
1535 builder.cubic_bezier_to(ctrl_0, ctrl_1, mid, attributes);
1536
1537 let ctrl_0 = center + vector(radius, d * dir);
1538 let ctrl_1 = center + vector(d, radius * dir);
1539 let mid = center + vector(0.0, radius * dir);
1540 builder.cubic_bezier_to(ctrl_0, ctrl_1, mid, attributes);
1541
1542 let ctrl_0 = center + vector(-d, radius * dir);
1543 let ctrl_1 = center + vector(-radius, d * dir);
1544 let mid = center + vector(-radius, 0.0);
1545 builder.cubic_bezier_to(ctrl_0, ctrl_1, mid, attributes);
1546
1547 builder.close();
1548}
1549
1550fn add_rounded_rectangle<Builder: PathBuilder>(
1552 builder: &mut Builder,
1553 rect: &Box2D,
1554 radii: &BorderRadii,
1555 winding: Winding,
1556 attributes: Attributes,
1557) {
1558 let w = rect.width();
1559 let h = rect.height();
1560 let x_min = rect.min.x;
1561 let y_min = rect.min.y;
1562 let x_max = rect.max.x;
1563 let y_max = rect.max.y;
1564 let min_wh = w.min(h);
1565 let mut tl = radii.top_left.abs().min(min_wh);
1566 let mut tr = radii.top_right.abs().min(min_wh);
1567 let mut bl = radii.bottom_left.abs().min(min_wh);
1568 let mut br = radii.bottom_right.abs().min(min_wh);
1569
1570 if tl + tr > w {
1572 let x = (tl + tr - w) * 0.5;
1573 tl -= x;
1574 tr -= x;
1575 }
1576 if bl + br > w {
1577 let x = (bl + br - w) * 0.5;
1578 bl -= x;
1579 br -= x;
1580 }
1581 if tr + br > h {
1582 let x = (tr + br - h) * 0.5;
1583 tr -= x;
1584 br -= x;
1585 }
1586 if tl + bl > h {
1587 let x = (tl + bl - h) * 0.5;
1588 tl -= x;
1589 bl -= x;
1590 }
1591
1592 const CONSTANT_FACTOR: f32 = 0.55191505;
1594
1595 let tl_d = tl * CONSTANT_FACTOR;
1596 let tl_corner = point(x_min, y_min);
1597
1598 let tr_d = tr * CONSTANT_FACTOR;
1599 let tr_corner = point(x_max, y_min);
1600
1601 let br_d = br * CONSTANT_FACTOR;
1602 let br_corner = point(x_max, y_max);
1603
1604 let bl_d = bl * CONSTANT_FACTOR;
1605 let bl_corner = point(x_min, y_max);
1606
1607 let points = [
1608 point(x_min, y_min + tl), tl_corner + vector(0.0, tl - tl_d), tl_corner + vector(tl - tl_d, 0.0), tl_corner + vector(tl, 0.0), point(x_max - tr, y_min),
1613 tr_corner + vector(-tr + tr_d, 0.0),
1614 tr_corner + vector(0.0, tr - tr_d),
1615 tr_corner + vector(0.0, tr),
1616 point(x_max, y_max - br),
1617 br_corner + vector(0.0, -br + br_d),
1618 br_corner + vector(-br + br_d, 0.0),
1619 br_corner + vector(-br, 0.0),
1620 point(x_min + bl, y_max),
1621 bl_corner + vector(bl - bl_d, 0.0),
1622 bl_corner + vector(0.0, -bl + bl_d),
1623 bl_corner + vector(0.0, -bl),
1624 ];
1625
1626 if winding == Winding::Positive {
1627 builder.begin(points[0], attributes);
1628 if tl > 0.0 {
1629 builder.cubic_bezier_to(points[1], points[2], points[3], attributes);
1630 }
1631 builder.line_to(points[4], attributes);
1632 if tr > 0.0 {
1633 builder.cubic_bezier_to(points[5], points[6], points[7], attributes);
1634 }
1635 builder.line_to(points[8], attributes);
1636 if br > 0.0 {
1637 builder.cubic_bezier_to(points[9], points[10], points[11], attributes);
1638 }
1639 builder.line_to(points[12], attributes);
1640 if bl > 0.0 {
1641 builder.cubic_bezier_to(points[13], points[14], points[15], attributes);
1642 }
1643 } else {
1644 builder.begin(points[15], attributes);
1645 if bl > 0.0 {
1646 builder.cubic_bezier_to(points[14], points[13], points[12], attributes);
1647 }
1648 builder.line_to(points[11], attributes);
1649 if br > 0.0 {
1650 builder.cubic_bezier_to(points[10], points[9], points[8], attributes);
1651 }
1652 builder.line_to(points[7], attributes);
1653 if tr > 0.0 {
1654 builder.cubic_bezier_to(points[6], points[5], points[4], attributes);
1655 }
1656 builder.line_to(points[3], attributes);
1657 if tl > 0.0 {
1658 builder.cubic_bezier_to(points[2], points[1], points[0], attributes);
1659 }
1660 }
1661 builder.end(true);
1662}
1663
1664#[inline]
1665fn nan_check(p: Point) {
1666 debug_assert!(p.x.is_finite());
1667 debug_assert!(p.y.is_finite());
1668}
1669
1670#[test]
1671fn svg_builder_line_to_after_close() {
1672 use crate::Path;
1673 use crate::PathEvent;
1674
1675 let mut p = Path::svg_builder();
1676 p.line_to(point(1.0, 0.0));
1677 p.close();
1678 p.line_to(point(2.0, 0.0));
1679
1680 let path = p.build();
1681 let mut it = path.iter();
1682 assert_eq!(
1683 it.next(),
1684 Some(PathEvent::Begin {
1685 at: point(1.0, 0.0)
1686 })
1687 );
1688 assert_eq!(
1689 it.next(),
1690 Some(PathEvent::End {
1691 last: point(1.0, 0.0),
1692 first: point(1.0, 0.0),
1693 close: true
1694 })
1695 );
1696 assert_eq!(
1697 it.next(),
1698 Some(PathEvent::Begin {
1699 at: point(1.0, 0.0)
1700 })
1701 );
1702 assert_eq!(
1703 it.next(),
1704 Some(PathEvent::Line {
1705 from: point(1.0, 0.0),
1706 to: point(2.0, 0.0)
1707 })
1708 );
1709 assert_eq!(
1710 it.next(),
1711 Some(PathEvent::End {
1712 last: point(2.0, 0.0),
1713 first: point(1.0, 0.0),
1714 close: false
1715 })
1716 );
1717 assert_eq!(it.next(), None);
1718}
1719
1720#[test]
1721fn svg_builder_relative_curves() {
1722 use crate::Path;
1723 use crate::PathEvent;
1724
1725 let mut p = Path::svg_builder();
1726 p.move_to(point(0.0, 0.0));
1727 p.relative_quadratic_bezier_to(vector(0., 100.), vector(-100., 100.));
1728 p.relative_line_to(vector(-50., 0.));
1729
1730 let path = p.build();
1731 let mut it = path.iter();
1732 assert_eq!(
1733 it.next(),
1734 Some(PathEvent::Begin {
1735 at: point(0.0, 0.0)
1736 })
1737 );
1738 assert_eq!(
1739 it.next(),
1740 Some(PathEvent::Quadratic {
1741 from: point(0.0, 0.0),
1742 ctrl: point(0.0, 100.0),
1743 to: point(-100., 100.),
1744 })
1745 );
1746 assert_eq!(
1747 it.next(),
1748 Some(PathEvent::Line {
1749 from: point(-100.0, 100.0),
1750 to: point(-150., 100.)
1751 })
1752 );
1753 assert_eq!(
1754 it.next(),
1755 Some(PathEvent::End {
1756 first: point(0.0, 0.0),
1757 last: point(-150., 100.),
1758 close: false,
1759 })
1760 );
1761 assert_eq!(it.next(), None);
1762}
1763
1764#[test]
1765fn svg_builder_arc_to_update_position() {
1766 use crate::Path;
1767
1768 let mut p = Path::svg_builder();
1769 p.move_to(point(0.0, 0.0));
1770 assert_eq!(p.current_position(), point(0.0, 0.0));
1771 p.arc_to(
1772 vector(100., 100.),
1773 Angle::degrees(0.),
1774 ArcFlags::default(),
1775 point(0.0, 100.0),
1776 );
1777 assert_ne!(p.current_position(), point(0.0, 0.0));
1778}
1779
1780#[test]
1781fn issue_650() {
1782 let mut builder = crate::path::Path::builder().with_svg();
1783 builder.arc(
1784 point(0.0, 0.0),
1785 vector(50.0, 50.0),
1786 Angle::radians(PI),
1787 Angle::radians(0.0),
1788 );
1789 builder.build();
1790}
1791
1792#[test]
1793fn straight_line_arc() {
1794 use crate::Path;
1795
1796 let mut p = Path::svg_builder();
1797 p.move_to(point(100.0, 0.0));
1798 p.arc_to(
1800 vector(100., 100.),
1801 Angle::degrees(0.),
1802 ArcFlags::default(),
1803 point(100.0, 0.0),
1804 );
1805}
1806
1807#[test]
1808fn top_right_rounded_rect() {
1809 use crate::{math::*, Path};
1810 let mut builder = Path::builder();
1811 builder.add_rounded_rectangle(
1812 &Box2D::new(point(0., 0.), point(100., 100.)),
1813 &BorderRadii {
1814 top_right: 2.,
1815 ..Default::default()
1816 },
1817 Winding::Positive,
1818 );
1819 let path = builder.build();
1820 let tr = path.iter().skip(2).next().unwrap();
1821 assert_eq!(tr.from(), point(98., 0.));
1822 assert_eq!(tr.to(), point(100., 2.));
1823}