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.builder.begin(at, attributes)
965 }
966
967 fn end(&mut self, close: bool) {
968 self.builder.end(close)
969 }
970
971 fn line_to(&mut self, to: Point, attributes: Attributes) -> EndpointId {
972 let id = self.builder.line_to(to, attributes);
973 self.current_position = to;
974 self.prev_attributes.copy_from_slice(attributes);
975 id
976 }
977
978 fn quadratic_bezier_to(
979 &mut self,
980 ctrl: Point,
981 to: Point,
982 attributes: Attributes,
983 ) -> EndpointId {
984 let id = crate::private::flatten_quadratic_bezier(
985 self.tolerance,
986 self.current_position,
987 ctrl,
988 to,
989 attributes,
990 &self.prev_attributes,
991 &mut self.builder,
992 &mut self.attribute_buffer,
993 );
994 self.current_position = to;
995 self.prev_attributes.copy_from_slice(attributes);
996
997 id
998 }
999
1000 fn cubic_bezier_to(
1001 &mut self,
1002 ctrl1: Point,
1003 ctrl2: Point,
1004 to: Point,
1005 attributes: Attributes,
1006 ) -> EndpointId {
1007 let id = crate::private::flatten_cubic_bezier(
1008 self.tolerance,
1009 self.current_position,
1010 ctrl1,
1011 ctrl2,
1012 to,
1013 attributes,
1014 &self.prev_attributes,
1015 &mut self.builder,
1016 &mut self.attribute_buffer,
1017 );
1018 self.current_position = to;
1019 self.prev_attributes.copy_from_slice(attributes);
1020
1021 id
1022 }
1023
1024 fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
1025 self.builder.reserve(endpoints + ctrl_points * 4, 0);
1026 }
1027}
1028
1029impl<Builder: PathBuilder> Flattened<Builder> {
1030 pub fn new(builder: Builder, tolerance: f32) -> Flattened<Builder> {
1031 let n = builder.num_attributes();
1032 Flattened {
1033 builder,
1034 current_position: point(0.0, 0.0),
1035 tolerance,
1036 prev_attributes: vec![0.0; n],
1037 attribute_buffer: vec![0.0; n],
1038 }
1039 }
1040
1041 pub fn build(self) -> Builder::PathType
1042 where
1043 Builder: Build,
1044 {
1045 self.builder.build()
1046 }
1047
1048 pub fn set_tolerance(&mut self, tolerance: f32) {
1049 self.tolerance = tolerance
1050 }
1051}
1052
1053pub struct Transformed<Builder, Transform> {
1055 builder: Builder,
1056 transform: Transform,
1057}
1058
1059impl<Builder, Transform> Transformed<Builder, Transform> {
1060 #[inline]
1061 pub fn new(builder: Builder, transform: Transform) -> Self {
1062 Transformed { builder, transform }
1063 }
1064
1065 #[inline]
1066 pub fn set_transform(&mut self, transform: Transform) {
1067 self.transform = transform;
1068 }
1069}
1070
1071impl<Builder: Build, Transform> Build for Transformed<Builder, Transform> {
1072 type PathType = Builder::PathType;
1073
1074 #[inline]
1075 fn build(self) -> Builder::PathType {
1076 self.builder.build()
1077 }
1078}
1079
1080impl<Builder, Transform> PathBuilder for Transformed<Builder, Transform>
1081where
1082 Builder: PathBuilder,
1083 Transform: Transformation<f32>,
1084{
1085 fn num_attributes(&self) -> usize {
1086 self.builder.num_attributes()
1087 }
1088
1089 #[inline]
1090 fn begin(&mut self, at: Point, attributes: Attributes) -> EndpointId {
1091 self.builder
1092 .begin(self.transform.transform_point(at), attributes)
1093 }
1094
1095 #[inline]
1096 fn end(&mut self, close: bool) {
1097 self.builder.end(close)
1098 }
1099
1100 #[inline]
1101 fn line_to(&mut self, to: Point, attributes: Attributes) -> EndpointId {
1102 self.builder
1103 .line_to(self.transform.transform_point(to), attributes)
1104 }
1105
1106 #[inline]
1107 fn quadratic_bezier_to(
1108 &mut self,
1109 ctrl: Point,
1110 to: Point,
1111 attributes: Attributes,
1112 ) -> EndpointId {
1113 self.builder.quadratic_bezier_to(
1114 self.transform.transform_point(ctrl),
1115 self.transform.transform_point(to),
1116 attributes,
1117 )
1118 }
1119
1120 #[inline]
1121 fn cubic_bezier_to(
1122 &mut self,
1123 ctrl1: Point,
1124 ctrl2: Point,
1125 to: Point,
1126 attributes: Attributes,
1127 ) -> EndpointId {
1128 self.builder.cubic_bezier_to(
1129 self.transform.transform_point(ctrl1),
1130 self.transform.transform_point(ctrl2),
1131 self.transform.transform_point(to),
1132 attributes,
1133 )
1134 }
1135
1136 #[inline]
1137 fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
1138 self.builder.reserve(endpoints, ctrl_points);
1139 }
1140}
1141
1142pub struct WithSvg<Builder: PathBuilder> {
1144 builder: Builder,
1145
1146 first_position: Point,
1147 current_position: Point,
1148 last_ctrl: Point,
1149 last_cmd: Verb,
1150 need_moveto: bool,
1151 is_empty: bool,
1152 attribute_buffer: Vec<f32>,
1153}
1154
1155impl<Builder: PathBuilder> WithSvg<Builder> {
1156 pub fn new(builder: Builder) -> Self {
1157 let attribute_buffer = vec![0.0; builder.num_attributes()];
1158 WithSvg {
1159 builder,
1160 first_position: point(0.0, 0.0),
1161 current_position: point(0.0, 0.0),
1162 last_ctrl: point(0.0, 0.0),
1163 need_moveto: true,
1164 is_empty: true,
1165 last_cmd: Verb::End,
1166 attribute_buffer,
1167 }
1168 }
1169
1170 pub fn build(mut self) -> Builder::PathType
1171 where
1172 Builder: Build,
1173 {
1174 self.end_if_needed();
1175 self.builder.build()
1176 }
1177
1178 pub fn flattened(self, tolerance: f32) -> WithSvg<Flattened<Builder>> {
1179 WithSvg::new(Flattened::new(self.builder, tolerance))
1180 }
1181
1182 pub fn transformed<Transform>(
1183 self,
1184 transform: Transform,
1185 ) -> WithSvg<Transformed<Builder, Transform>>
1186 where
1187 Transform: Transformation<f32>,
1188 {
1189 WithSvg::new(Transformed::new(self.builder, transform))
1190 }
1191
1192 pub fn move_to(&mut self, to: Point) -> EndpointId {
1193 self.end_if_needed();
1194
1195 let id = self.builder.begin(to, &self.attribute_buffer);
1196
1197 self.is_empty = false;
1198 self.need_moveto = false;
1199 self.first_position = to;
1200 self.current_position = to;
1201 self.last_cmd = Verb::Begin;
1202
1203 id
1204 }
1205
1206 pub fn line_to(&mut self, to: Point) -> EndpointId {
1207 if let Some(id) = self.begin_if_needed(&to) {
1208 return id;
1209 }
1210
1211 self.current_position = to;
1212 self.last_cmd = Verb::LineTo;
1213
1214 self.builder.line_to(to, &self.attribute_buffer)
1215 }
1216
1217 pub fn close(&mut self) {
1218 if self.need_moveto {
1219 return;
1220 }
1221
1222 self.current_position = self.first_position;
1239 self.need_moveto = true;
1240 self.last_cmd = Verb::Close;
1241
1242 self.builder.close();
1243 }
1244
1245 pub fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) -> EndpointId {
1246 if let Some(id) = self.begin_if_needed(&to) {
1247 return id;
1248 }
1249
1250 self.current_position = to;
1251 self.last_cmd = Verb::QuadraticTo;
1252 self.last_ctrl = ctrl;
1253
1254 self.builder
1255 .quadratic_bezier_to(ctrl, to, &self.attribute_buffer)
1256 }
1257
1258 pub fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) -> EndpointId {
1259 if let Some(id) = self.begin_if_needed(&to) {
1260 return id;
1261 }
1262
1263 self.current_position = to;
1264 self.last_cmd = Verb::CubicTo;
1265 self.last_ctrl = ctrl2;
1266
1267 self.builder
1268 .cubic_bezier_to(ctrl1, ctrl2, to, &self.attribute_buffer)
1269 }
1270
1271 pub fn arc(&mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle) {
1272 nan_check(center);
1273 nan_check(radii.to_point());
1274 debug_assert!(!sweep_angle.get().is_nan());
1275 debug_assert!(!x_rotation.get().is_nan());
1276
1277 self.last_ctrl = self.current_position;
1278
1279 use lyon_geom::euclid::approxeq::ApproxEq;
1283 if self.current_position.approx_eq(¢er) {
1284 return;
1285 }
1286
1287 let start_angle = (self.current_position - center).angle_from_x_axis() - x_rotation;
1288
1289 let arc = Arc {
1290 center,
1291 radii,
1292 start_angle,
1293 sweep_angle,
1294 x_rotation,
1295 };
1296
1297 let arc_start = arc.from();
1300 if self.need_moveto {
1301 self.move_to(arc_start);
1302 } else if (arc_start - self.current_position).square_length() < 0.01 {
1303 self.builder.line_to(arc_start, &self.attribute_buffer);
1304 }
1305
1306 arc.for_each_quadratic_bezier(&mut |curve| {
1307 self.builder
1308 .quadratic_bezier_to(curve.ctrl, curve.to, &self.attribute_buffer);
1309 self.current_position = curve.to;
1310 });
1311 }
1312
1313 #[inline(always)]
1317 fn begin_if_needed(&mut self, default: &Point) -> Option<EndpointId> {
1318 if self.need_moveto {
1319 return self.insert_move_to(default);
1320 }
1321
1322 None
1323 }
1324
1325 #[inline(never)]
1326 fn insert_move_to(&mut self, default: &Point) -> Option<EndpointId> {
1327 if self.is_empty {
1328 return Some(self.move_to(*default));
1329 }
1330
1331 self.move_to(self.first_position);
1332
1333 None
1334 }
1335
1336 fn end_if_needed(&mut self) {
1337 if (self.last_cmd as u8) <= (Verb::Begin as u8) {
1338 self.builder.end(false);
1339 }
1340 }
1341
1342 pub fn current_position(&self) -> Point {
1343 self.current_position
1344 }
1345
1346 pub fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
1347 self.builder.reserve(endpoints, ctrl_points);
1348 }
1349
1350 fn get_smooth_cubic_ctrl(&self) -> Point {
1351 match self.last_cmd {
1352 Verb::CubicTo => self.current_position + (self.current_position - self.last_ctrl),
1353 _ => self.current_position,
1354 }
1355 }
1356
1357 fn get_smooth_quadratic_ctrl(&self) -> Point {
1358 match self.last_cmd {
1359 Verb::QuadraticTo => self.current_position + (self.current_position - self.last_ctrl),
1360 _ => self.current_position,
1361 }
1362 }
1363
1364 fn relative_to_absolute(&self, v: Vector) -> Point {
1365 self.current_position + v
1366 }
1367}
1368
1369impl<Builder, Transform> WithSvg<Transformed<Builder, Transform>>
1370where
1371 Builder: PathBuilder,
1372 Transform: Transformation<f32>,
1373{
1374 #[inline]
1375 pub fn set_transform(&mut self, transform: Transform) {
1376 self.builder.set_transform(transform);
1377 }
1378}
1379
1380impl<Builder: PathBuilder + Build> Build for WithSvg<Builder> {
1381 type PathType = Builder::PathType;
1382
1383 fn build(mut self) -> Builder::PathType {
1384 self.end_if_needed();
1385 self.builder.build()
1386 }
1387}
1388
1389impl<Builder: PathBuilder> SvgPathBuilder for WithSvg<Builder> {
1390 fn move_to(&mut self, to: Point) {
1391 self.move_to(to);
1392 }
1393
1394 fn close(&mut self) {
1395 self.close();
1396 }
1397
1398 fn line_to(&mut self, to: Point) {
1399 self.line_to(to);
1400 }
1401
1402 fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) {
1403 self.quadratic_bezier_to(ctrl, to);
1404 }
1405
1406 fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) {
1407 self.cubic_bezier_to(ctrl1, ctrl2, to);
1408 }
1409
1410 fn relative_move_to(&mut self, to: Vector) {
1411 let to = self.relative_to_absolute(to);
1412 self.move_to(to);
1413 }
1414
1415 fn relative_line_to(&mut self, to: Vector) {
1416 let to = self.relative_to_absolute(to);
1417 self.line_to(to);
1418 }
1419
1420 fn relative_quadratic_bezier_to(&mut self, ctrl: Vector, to: Vector) {
1421 let ctrl = self.relative_to_absolute(ctrl);
1422 let to = self.relative_to_absolute(to);
1423 self.quadratic_bezier_to(ctrl, to);
1424 }
1425
1426 fn relative_cubic_bezier_to(&mut self, ctrl1: Vector, ctrl2: Vector, to: Vector) {
1427 let to = self.relative_to_absolute(to);
1428 let ctrl1 = self.relative_to_absolute(ctrl1);
1429 let ctrl2 = self.relative_to_absolute(ctrl2);
1430 self.cubic_bezier_to(ctrl1, ctrl2, to);
1431 }
1432
1433 fn smooth_cubic_bezier_to(&mut self, ctrl2: Point, to: Point) {
1434 let ctrl1 = self.get_smooth_cubic_ctrl();
1435 self.cubic_bezier_to(ctrl1, ctrl2, to);
1436 }
1437
1438 fn smooth_relative_cubic_bezier_to(&mut self, ctrl2: Vector, to: Vector) {
1439 let ctrl1 = self.get_smooth_cubic_ctrl();
1440 let ctrl2 = self.relative_to_absolute(ctrl2);
1441 let to = self.relative_to_absolute(to);
1442 self.cubic_bezier_to(ctrl1, ctrl2, to);
1443 }
1444
1445 fn smooth_quadratic_bezier_to(&mut self, to: Point) {
1446 let ctrl = self.get_smooth_quadratic_ctrl();
1447 self.quadratic_bezier_to(ctrl, to);
1448 }
1449
1450 fn smooth_relative_quadratic_bezier_to(&mut self, to: Vector) {
1451 let ctrl = self.get_smooth_quadratic_ctrl();
1452 let to = self.relative_to_absolute(to);
1453 self.quadratic_bezier_to(ctrl, to);
1454 }
1455
1456 fn horizontal_line_to(&mut self, x: f32) {
1457 let y = self.current_position.y;
1458 self.line_to(point(x, y));
1459 }
1460
1461 fn relative_horizontal_line_to(&mut self, dx: f32) {
1462 let p = self.current_position;
1463 self.line_to(point(p.x + dx, p.y));
1464 }
1465
1466 fn vertical_line_to(&mut self, y: f32) {
1467 let x = self.current_position.x;
1468 self.line_to(point(x, y));
1469 }
1470
1471 fn relative_vertical_line_to(&mut self, dy: f32) {
1472 let p = self.current_position;
1473 self.line_to(point(p.x, p.y + dy));
1474 }
1475
1476 fn arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Point) {
1477 let svg_arc = SvgArc {
1478 from: self.current_position,
1479 to,
1480 radii,
1481 x_rotation,
1482 flags: ArcFlags {
1483 large_arc: flags.large_arc,
1484 sweep: flags.sweep,
1485 },
1486 };
1487
1488 if svg_arc.is_straight_line() {
1489 self.line_to(to);
1490 } else {
1491 let arc = svg_arc.to_arc();
1492 self.arc(arc.center, arc.radii, arc.sweep_angle, arc.x_rotation);
1493 }
1494 }
1495
1496 fn relative_arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Vector) {
1497 let to = self.relative_to_absolute(to);
1498 self.arc_to(radii, x_rotation, flags, to);
1499 }
1500
1501 fn reserve(&mut self, endpoints: usize, ctrl_points: usize) {
1502 self.builder.reserve(endpoints, ctrl_points);
1503 }
1504}
1505
1506fn add_circle<Builder: PathBuilder>(
1508 builder: &mut Builder,
1509 center: Point,
1510 radius: f32,
1511 winding: Winding,
1512 attributes: Attributes,
1513) {
1514 let radius = radius.abs();
1515 let dir = match winding {
1516 Winding::Positive => 1.0,
1517 Winding::Negative => -1.0,
1518 };
1519
1520 const CONSTANT_FACTOR: f32 = 0.55191505;
1522 let d = radius * CONSTANT_FACTOR;
1523
1524 builder.begin(center + vector(-radius, 0.0), attributes);
1525
1526 let ctrl_0 = center + vector(-radius, -d * dir);
1527 let ctrl_1 = center + vector(-d, -radius * dir);
1528 let mid = center + vector(0.0, -radius * dir);
1529 builder.cubic_bezier_to(ctrl_0, ctrl_1, mid, attributes);
1530
1531 let ctrl_0 = center + vector(d, -radius * dir);
1532 let ctrl_1 = center + vector(radius, -d * dir);
1533 let mid = center + vector(radius, 0.0);
1534 builder.cubic_bezier_to(ctrl_0, ctrl_1, mid, attributes);
1535
1536 let ctrl_0 = center + vector(radius, d * dir);
1537 let ctrl_1 = center + vector(d, radius * dir);
1538 let mid = center + vector(0.0, radius * dir);
1539 builder.cubic_bezier_to(ctrl_0, ctrl_1, mid, attributes);
1540
1541 let ctrl_0 = center + vector(-d, radius * dir);
1542 let ctrl_1 = center + vector(-radius, d * dir);
1543 let mid = center + vector(-radius, 0.0);
1544 builder.cubic_bezier_to(ctrl_0, ctrl_1, mid, attributes);
1545
1546 builder.close();
1547}
1548
1549fn add_rounded_rectangle<Builder: PathBuilder>(
1551 builder: &mut Builder,
1552 rect: &Box2D,
1553 radii: &BorderRadii,
1554 winding: Winding,
1555 attributes: Attributes,
1556) {
1557 let w = rect.width();
1558 let h = rect.height();
1559 let x_min = rect.min.x;
1560 let y_min = rect.min.y;
1561 let x_max = rect.max.x;
1562 let y_max = rect.max.y;
1563 let min_wh = w.min(h);
1564 let mut tl = radii.top_left.abs().min(min_wh);
1565 let mut tr = radii.top_right.abs().min(min_wh);
1566 let mut bl = radii.bottom_left.abs().min(min_wh);
1567 let mut br = radii.bottom_right.abs().min(min_wh);
1568
1569 if tl + tr > w {
1571 let x = (tl + tr - w) * 0.5;
1572 tl -= x;
1573 tr -= x;
1574 }
1575 if bl + br > w {
1576 let x = (bl + br - w) * 0.5;
1577 bl -= x;
1578 br -= x;
1579 }
1580 if tr + br > h {
1581 let x = (tr + br - h) * 0.5;
1582 tr -= x;
1583 br -= x;
1584 }
1585 if tl + bl > h {
1586 let x = (tl + bl - h) * 0.5;
1587 tl -= x;
1588 bl -= x;
1589 }
1590
1591 const CONSTANT_FACTOR: f32 = 0.55191505;
1593
1594 let tl_d = tl * CONSTANT_FACTOR;
1595 let tl_corner = point(x_min, y_min);
1596
1597 let tr_d = tr * CONSTANT_FACTOR;
1598 let tr_corner = point(x_max, y_min);
1599
1600 let br_d = br * CONSTANT_FACTOR;
1601 let br_corner = point(x_max, y_max);
1602
1603 let bl_d = bl * CONSTANT_FACTOR;
1604 let bl_corner = point(x_min, y_max);
1605
1606 let points = [
1607 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),
1612 tr_corner + vector(-tr + tr_d, 0.0),
1613 tr_corner + vector(0.0, tr - tr_d),
1614 tr_corner + vector(0.0, tr),
1615 point(x_max, y_max - br),
1616 br_corner + vector(0.0, -br + br_d),
1617 br_corner + vector(-br + br_d, 0.0),
1618 br_corner + vector(-br, 0.0),
1619 point(x_min + bl, y_max),
1620 bl_corner + vector(bl - bl_d, 0.0),
1621 bl_corner + vector(0.0, -bl + bl_d),
1622 bl_corner + vector(0.0, -bl),
1623 ];
1624
1625 if winding == Winding::Positive {
1626 builder.begin(points[0], attributes);
1627 if tl > 0.0 {
1628 builder.cubic_bezier_to(points[1], points[2], points[3], attributes);
1629 }
1630 builder.line_to(points[4], attributes);
1631 if tr > 0.0 {
1632 builder.cubic_bezier_to(points[5], points[6], points[7], attributes);
1633 }
1634 builder.line_to(points[8], attributes);
1635 if br > 0.0 {
1636 builder.cubic_bezier_to(points[9], points[10], points[11], attributes);
1637 }
1638 builder.line_to(points[12], attributes);
1639 if bl > 0.0 {
1640 builder.cubic_bezier_to(points[13], points[14], points[15], attributes);
1641 }
1642 } else {
1643 builder.begin(points[15], attributes);
1644 if bl > 0.0 {
1645 builder.cubic_bezier_to(points[14], points[13], points[12], attributes);
1646 }
1647 builder.line_to(points[11], attributes);
1648 if br > 0.0 {
1649 builder.cubic_bezier_to(points[10], points[9], points[8], attributes);
1650 }
1651 builder.line_to(points[7], attributes);
1652 if tr > 0.0 {
1653 builder.cubic_bezier_to(points[6], points[5], points[4], attributes);
1654 }
1655 builder.line_to(points[3], attributes);
1656 if tl > 0.0 {
1657 builder.cubic_bezier_to(points[2], points[1], points[0], attributes);
1658 }
1659 }
1660 builder.end(true);
1661}
1662
1663#[inline]
1664fn nan_check(p: Point) {
1665 debug_assert!(p.x.is_finite());
1666 debug_assert!(p.y.is_finite());
1667}
1668
1669#[test]
1670fn svg_builder_line_to_after_close() {
1671 use crate::Path;
1672 use crate::PathEvent;
1673
1674 let mut p = Path::svg_builder();
1675 p.line_to(point(1.0, 0.0));
1676 p.close();
1677 p.line_to(point(2.0, 0.0));
1678
1679 let path = p.build();
1680 let mut it = path.iter();
1681 assert_eq!(
1682 it.next(),
1683 Some(PathEvent::Begin {
1684 at: point(1.0, 0.0)
1685 })
1686 );
1687 assert_eq!(
1688 it.next(),
1689 Some(PathEvent::End {
1690 last: point(1.0, 0.0),
1691 first: point(1.0, 0.0),
1692 close: true
1693 })
1694 );
1695 assert_eq!(
1696 it.next(),
1697 Some(PathEvent::Begin {
1698 at: point(1.0, 0.0)
1699 })
1700 );
1701 assert_eq!(
1702 it.next(),
1703 Some(PathEvent::Line {
1704 from: point(1.0, 0.0),
1705 to: point(2.0, 0.0)
1706 })
1707 );
1708 assert_eq!(
1709 it.next(),
1710 Some(PathEvent::End {
1711 last: point(2.0, 0.0),
1712 first: point(1.0, 0.0),
1713 close: false
1714 })
1715 );
1716 assert_eq!(it.next(), None);
1717}
1718
1719#[test]
1720fn svg_builder_relative_curves() {
1721 use crate::Path;
1722 use crate::PathEvent;
1723
1724 let mut p = Path::svg_builder();
1725 p.move_to(point(0.0, 0.0));
1726 p.relative_quadratic_bezier_to(vector(0., 100.), vector(-100., 100.));
1727 p.relative_line_to(vector(-50., 0.));
1728
1729 let path = p.build();
1730 let mut it = path.iter();
1731 assert_eq!(
1732 it.next(),
1733 Some(PathEvent::Begin {
1734 at: point(0.0, 0.0)
1735 })
1736 );
1737 assert_eq!(
1738 it.next(),
1739 Some(PathEvent::Quadratic {
1740 from: point(0.0, 0.0),
1741 ctrl: point(0.0, 100.0),
1742 to: point(-100., 100.),
1743 })
1744 );
1745 assert_eq!(
1746 it.next(),
1747 Some(PathEvent::Line {
1748 from: point(-100.0, 100.0),
1749 to: point(-150., 100.)
1750 })
1751 );
1752 assert_eq!(
1753 it.next(),
1754 Some(PathEvent::End {
1755 first: point(0.0, 0.0),
1756 last: point(-150., 100.),
1757 close: false,
1758 })
1759 );
1760 assert_eq!(it.next(), None);
1761}
1762
1763#[test]
1764fn svg_builder_arc_to_update_position() {
1765 use crate::Path;
1766
1767 let mut p = Path::svg_builder();
1768 p.move_to(point(0.0, 0.0));
1769 assert_eq!(p.current_position(), point(0.0, 0.0));
1770 p.arc_to(
1771 vector(100., 100.),
1772 Angle::degrees(0.),
1773 ArcFlags::default(),
1774 point(0.0, 100.0),
1775 );
1776 assert_ne!(p.current_position(), point(0.0, 0.0));
1777}
1778
1779#[test]
1780fn issue_650() {
1781 let mut builder = crate::path::Path::builder().with_svg();
1782 builder.arc(
1783 point(0.0, 0.0),
1784 vector(50.0, 50.0),
1785 Angle::radians(PI),
1786 Angle::radians(0.0),
1787 );
1788 builder.build();
1789}
1790
1791#[test]
1792fn straight_line_arc() {
1793 use crate::Path;
1794
1795 let mut p = Path::svg_builder();
1796 p.move_to(point(100.0, 0.0));
1797 p.arc_to(
1799 vector(100., 100.),
1800 Angle::degrees(0.),
1801 ArcFlags::default(),
1802 point(100.0, 0.0),
1803 );
1804}
1805
1806#[test]
1807fn top_right_rounded_rect() {
1808 use crate::{math::*, Path};
1809 let mut builder = Path::builder();
1810 builder.add_rounded_rectangle(
1811 &Box2D::new(point(0., 0.), point(100., 100.)),
1812 &BorderRadii {
1813 top_right: 2.,
1814 ..Default::default()
1815 },
1816 Winding::Positive,
1817 );
1818 let path = builder.build();
1819 let tr = path.iter().skip(2).next().unwrap();
1820 assert_eq!(tr.from(), point(98., 0.));
1821 assert_eq!(tr.to(), point(100., 2.));
1822}