1use std::{ops::AddAssign, rc::Rc};
4
5use crate::{
6 ArcRecordArgs, Brush, Color, ColorFilter, CommandRecorder, CommandRecording, DrawGroup,
7 DrawTransform, GroupMarker, ImageBitmap, ImageSampling, PathFillRule, Trapezoid,
8 normalized_band,
9 path::{DrawStyle, Path},
10 stroke::{LineGeometry, Stroke},
11 text_primitive::{TextBlockAt, TextPrimitive, measured_text, text_primitive},
12 typography::{DrawTextMeasurer, DrawTextStyle, TextMeasurement},
13 vector_path_mask::{
14 PathSide, VECTOR_PATH_SUPERSAMPLE, rasterize_vector_path, vector_path_mask_cache_get,
15 vector_path_mask_cache_put, vector_path_mask_key,
16 },
17};
18
19#[derive(Clone, Copy, Debug, PartialEq, Default)]
21pub struct Point {
22 pub x: f32,
24 pub y: f32,
26}
27
28impl Point {
29 pub const fn new(x: f32, y: f32) -> Self {
31 Self { x, y }
32 }
33
34 pub const ZERO: Self = Self { x: 0.0, y: 0.0 };
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, Default)]
40pub struct Size {
41 pub width: f32,
43 pub height: f32,
45}
46
47impl Size {
48 pub const fn new(width: f32, height: f32) -> Self {
50 Self { width, height }
51 }
52
53 pub const ZERO: Self = Self {
55 width: 0.0,
56 height: 0.0,
57 };
58}
59
60#[derive(Clone, Copy, Debug, Default, PartialEq)]
62pub struct Rect {
63 pub x: f32,
65 pub y: f32,
67 pub width: f32,
69 pub height: f32,
71}
72
73impl Rect {
74 pub const EMPTY: Self = Self {
78 x: 0.0,
79 y: 0.0,
80 width: 0.0,
81 height: 0.0,
82 };
83
84 pub fn from_origin_size(origin: Point, size: Size) -> Self {
86 Self {
87 x: origin.x,
88 y: origin.y,
89 width: size.width,
90 height: size.height,
91 }
92 }
93
94 pub fn from_size(size: Size) -> Self {
96 Self {
97 x: 0.0,
98 y: 0.0,
99 width: size.width,
100 height: size.height,
101 }
102 }
103
104 pub fn translate(&self, dx: f32, dy: f32) -> Self {
106 Self {
107 x: self.x + dx,
108 y: self.y + dy,
109 width: self.width,
110 height: self.height,
111 }
112 }
113
114 pub fn contains(&self, x: f32, y: f32) -> bool {
116 x >= self.x && y >= self.y && x <= self.x + self.width && y <= self.y + self.height
117 }
118
119 pub fn is_empty(&self) -> bool {
121 self.width <= 0.0 || self.height <= 0.0
122 }
123
124 pub fn intersect(&self, other: Self) -> Option<Self> {
126 let left = self.x.max(other.x);
127 let top = self.y.max(other.y);
128 let right = (self.x + self.width).min(other.x + other.width);
129 let bottom = (self.y + self.height).min(other.y + other.height);
130 let width = right - left;
131 let height = bottom - top;
132 if width <= 0.0 || height <= 0.0 {
133 None
134 } else {
135 Some(Self {
136 x: left,
137 y: top,
138 width,
139 height,
140 })
141 }
142 }
143
144 pub fn union(&self, other: Self) -> Self {
146 let left = self.x.min(other.x);
147 let top = self.y.min(other.y);
148 let right = (self.x + self.width).max(other.x + other.width);
149 let bottom = (self.y + self.height).max(other.y + other.height);
150 Self {
151 x: left,
152 y: top,
153 width: (right - left).max(0.0),
154 height: (bottom - top).max(0.0),
155 }
156 }
157}
158
159#[derive(Clone, Copy, Debug, Default, PartialEq)]
161pub struct EdgeInsets {
162 pub left: f32,
164 pub top: f32,
166 pub right: f32,
168 pub bottom: f32,
170}
171
172impl EdgeInsets {
173 pub fn uniform(all: f32) -> Self {
175 Self {
176 left: all,
177 top: all,
178 right: all,
179 bottom: all,
180 }
181 }
182
183 pub fn horizontal(horizontal: f32) -> Self {
185 Self {
186 left: horizontal,
187 right: horizontal,
188 ..Self::default()
189 }
190 }
191
192 pub fn vertical(vertical: f32) -> Self {
194 Self {
195 top: vertical,
196 bottom: vertical,
197 ..Self::default()
198 }
199 }
200
201 pub fn symmetric(horizontal: f32, vertical: f32) -> Self {
203 Self {
204 left: horizontal,
205 right: horizontal,
206 top: vertical,
207 bottom: vertical,
208 }
209 }
210
211 pub fn from_components(left: f32, top: f32, right: f32, bottom: f32) -> Self {
213 Self {
214 left,
215 top,
216 right,
217 bottom,
218 }
219 }
220
221 pub fn is_zero(&self) -> bool {
223 self.left == 0.0 && self.top == 0.0 && self.right == 0.0 && self.bottom == 0.0
224 }
225
226 pub fn horizontal_sum(&self) -> f32 {
228 self.left + self.right
229 }
230
231 pub fn vertical_sum(&self) -> f32 {
233 self.top + self.bottom
234 }
235
236 pub fn inset_rect(&self, size: Size) -> Rect {
239 Rect {
240 x: self.left,
241 y: self.top,
242 width: (size.width - self.horizontal_sum()).max(0.0),
243 height: (size.height - self.vertical_sum()).max(0.0),
244 }
245 }
246}
247
248impl AddAssign for EdgeInsets {
249 fn add_assign(&mut self, rhs: Self) {
250 self.left += rhs.left;
251 self.top += rhs.top;
252 self.right += rhs.right;
253 self.bottom += rhs.bottom;
254 }
255}
256
257#[derive(Clone, Copy, Debug, Default, PartialEq)]
259pub struct CornerRadii {
260 pub top_left: f32,
262 pub top_right: f32,
264 pub bottom_right: f32,
266 pub bottom_left: f32,
268}
269
270impl CornerRadii {
271 pub fn uniform(radius: f32) -> Self {
273 Self {
274 top_left: radius,
275 top_right: radius,
276 bottom_right: radius,
277 bottom_left: radius,
278 }
279 }
280}
281
282#[derive(Clone, Copy, Debug, PartialEq)]
284pub struct RoundedCornerShape {
285 radii: CornerRadii,
286}
287
288impl RoundedCornerShape {
289 pub fn new(top_left: f32, top_right: f32, bottom_right: f32, bottom_left: f32) -> Self {
291 Self {
292 radii: CornerRadii {
293 top_left,
294 top_right,
295 bottom_right,
296 bottom_left,
297 },
298 }
299 }
300
301 pub fn uniform(radius: f32) -> Self {
303 Self {
304 radii: CornerRadii::uniform(radius),
305 }
306 }
307
308 pub fn with_radii(radii: CornerRadii) -> Self {
310 Self { radii }
311 }
312
313 pub fn resolve(&self, width: f32, height: f32) -> CornerRadii {
316 let mut resolved = self.radii;
317 let max_width = (width / 2.0).max(0.0);
318 let max_height = (height / 2.0).max(0.0);
319 resolved.top_left = resolved.top_left.clamp(0.0, max_width).min(max_height);
320 resolved.top_right = resolved.top_right.clamp(0.0, max_width).min(max_height);
321 resolved.bottom_right = resolved.bottom_right.clamp(0.0, max_width).min(max_height);
322 resolved.bottom_left = resolved.bottom_left.clamp(0.0, max_width).min(max_height);
323 resolved
324 }
325
326 pub fn radii(&self) -> CornerRadii {
328 self.radii
329 }
330}
331
332#[derive(Clone, Copy, Debug, PartialEq)]
335pub struct TransformOrigin {
336 pub pivot_fraction_x: f32,
338 pub pivot_fraction_y: f32,
340}
341
342impl TransformOrigin {
343 pub const fn new(pivot_fraction_x: f32, pivot_fraction_y: f32) -> Self {
345 Self {
346 pivot_fraction_x,
347 pivot_fraction_y,
348 }
349 }
350
351 pub const CENTER: Self = Self::new(0.5, 0.5);
353}
354
355impl Default for TransformOrigin {
356 fn default() -> Self {
357 Self::CENTER
358 }
359}
360
361#[derive(Clone, Copy, Debug, Default, PartialEq)]
363pub enum LayerShape {
364 #[default]
366 Rectangle,
367 Rounded(RoundedCornerShape),
369}
370
371#[derive(Clone, Debug, PartialEq)]
374pub struct GraphicsLayer {
375 pub alpha: f32,
377 pub scale: f32,
379 pub scale_x: f32,
381 pub scale_y: f32,
383 pub rotation_x: f32,
385 pub rotation_y: f32,
387 pub rotation_z: f32,
389 pub camera_distance: f32,
392 pub transform_origin: TransformOrigin,
394 pub translation_x: f32,
396 pub translation_y: f32,
398 pub space: Option<std::sync::Arc<crate::space::LayerSpace>>,
403 pub shadow_elevation: f32,
405 pub ambient_shadow_color: Color,
407 pub spot_shadow_color: Color,
409 pub shape: LayerShape,
411 pub clip: bool,
413 pub compositing_strategy: CompositingStrategy,
415 pub blend_mode: BlendMode,
417 pub color_filter: Option<ColorFilter>,
419 pub render_effect: Option<crate::render_effect::RenderEffect>,
422 pub backdrop_effect: Option<crate::render_effect::RenderEffect>,
426}
427
428impl GraphicsLayer {
429 pub const DEFAULT: Self = Self {
431 alpha: 1.0,
432 scale: 1.0,
433 scale_x: 1.0,
434 scale_y: 1.0,
435 rotation_x: 0.0,
436 rotation_y: 0.0,
437 rotation_z: 0.0,
438 camera_distance: 8.0,
439 transform_origin: TransformOrigin::CENTER,
440 translation_x: 0.0,
441 translation_y: 0.0,
442 space: None,
443 shadow_elevation: 0.0,
444 ambient_shadow_color: Color::BLACK,
445 spot_shadow_color: Color::BLACK,
446 shape: LayerShape::Rectangle,
447 clip: false,
448 compositing_strategy: CompositingStrategy::Auto,
449 blend_mode: BlendMode::SrcOver,
450 color_filter: None,
451 render_effect: None,
452 backdrop_effect: None,
453 };
454
455 pub fn composite_alpha_8bit(alpha: f32) -> f32 {
479 (alpha.clamp(0.0, 1.0) * 255.0).floor() / 255.0
480 }
481}
482
483impl Default for GraphicsLayer {
484 fn default() -> Self {
485 Self::DEFAULT
486 }
487}
488
489#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
494pub enum BlendMode {
495 Clear,
497 Src,
499 Dst,
501 #[default]
503 SrcOver,
504 DstOver,
506 SrcIn,
508 DstIn,
510 SrcOut,
512 DstOut,
514 SrcAtop,
516 DstAtop,
518 Xor,
520 Plus,
522 Modulate,
524 Screen,
526 Overlay,
528 Darken,
530 Lighten,
532 ColorDodge,
534 ColorBurn,
536 HardLight,
538 SoftLight,
540 Difference,
542 Exclusion,
544 Multiply,
546 Hue,
548 Saturation,
550 Color,
552 Luminosity,
554}
555
556impl BlendMode {
557 pub const ALL: [Self; 29] = [
559 Self::Clear,
560 Self::Src,
561 Self::Dst,
562 Self::SrcOver,
563 Self::DstOver,
564 Self::SrcIn,
565 Self::DstIn,
566 Self::SrcOut,
567 Self::DstOut,
568 Self::SrcAtop,
569 Self::DstAtop,
570 Self::Xor,
571 Self::Plus,
572 Self::Modulate,
573 Self::Screen,
574 Self::Overlay,
575 Self::Darken,
576 Self::Lighten,
577 Self::ColorDodge,
578 Self::ColorBurn,
579 Self::HardLight,
580 Self::SoftLight,
581 Self::Difference,
582 Self::Exclusion,
583 Self::Multiply,
584 Self::Hue,
585 Self::Saturation,
586 Self::Color,
587 Self::Luminosity,
588 ];
589}
590
591#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
593pub enum CompositingStrategy {
594 #[default]
596 Auto,
597 Offscreen,
599 ModulateAlpha,
601}
602
603#[derive(Clone, Debug, PartialEq)]
605pub enum DrawPrimitive {
606 Content,
609 Blend {
611 primitive: Box<Self>,
613 blend_mode: BlendMode,
615 },
616 Rect {
618 rect: Rect,
620 brush: Brush,
622 stroke: Option<Stroke>,
625 },
626 RoundRect {
628 rect: Rect,
630 brush: Brush,
632 radii: CornerRadii,
634 stroke: Option<Stroke>,
637 },
638 Arc {
648 rect: Rect,
652 brush: Brush,
654 center: Point,
656 radius: f32,
659 start_angle: f32,
662 sweep_angle: f32,
664 stroke: Option<Stroke>,
666 inner_radius: f32,
668 },
669 Line {
672 rect: Rect,
675 brush: Brush,
677 start: Point,
679 end: Point,
681 stroke: Stroke,
683 },
684 Trapezoid {
687 rect: Rect,
690 brush: Brush,
692 trapezoid: Trapezoid,
694 },
695 Image {
697 rect: Rect,
699 image: ImageBitmap,
701 alpha: f32,
703 color_filter: Option<ColorFilter>,
705 sampling: ImageSampling,
707 src_rect: Option<Rect>,
711 },
712 Text(Box<TextPrimitive>),
714 Shadow(ShadowPrimitive),
717 Group(GroupMarker),
720}
721
722impl DrawPrimitive {
723 pub fn translate(self, dx: f32, dy: f32) -> Self {
726 match self {
727 Self::Content => Self::Content,
728 Self::Blend {
729 primitive,
730 blend_mode,
731 } => Self::Blend {
732 primitive: Box::new(primitive.translate(dx, dy)),
733 blend_mode,
734 },
735 Self::Rect {
736 rect,
737 brush,
738 stroke,
739 } => Self::Rect {
740 rect: rect.translate(dx, dy),
741 brush,
742 stroke,
743 },
744 Self::RoundRect {
745 rect,
746 brush,
747 radii,
748 stroke,
749 } => Self::RoundRect {
750 rect: rect.translate(dx, dy),
751 brush,
752 radii,
753 stroke,
754 },
755 Self::Arc {
756 rect,
757 brush,
758 center,
759 radius,
760 start_angle,
761 sweep_angle,
762 stroke,
763 inner_radius,
764 } => Self::Arc {
765 rect: rect.translate(dx, dy),
766 brush,
767 center: Point::new(center.x + dx, center.y + dy),
768 radius,
769 start_angle,
770 sweep_angle,
771 stroke,
772 inner_radius,
773 },
774 Self::Line {
775 rect,
776 brush,
777 start,
778 end,
779 stroke,
780 } => Self::Line {
781 rect: rect.translate(dx, dy),
782 brush,
783 start: Point::new(start.x + dx, start.y + dy),
784 end: Point::new(end.x + dx, end.y + dy),
785 stroke,
786 },
787 Self::Trapezoid {
788 rect,
789 brush,
790 trapezoid,
791 } => Self::Trapezoid {
792 rect: rect.translate(dx, dy),
793 brush,
794 trapezoid: trapezoid.translate(dx, dy),
795 },
796 Self::Image {
797 rect,
798 image,
799 alpha,
800 color_filter,
801 sampling,
802 src_rect,
803 } => Self::Image {
804 rect: rect.translate(dx, dy),
805 image,
806 alpha,
807 color_filter,
808 sampling,
809 src_rect,
810 },
811 Self::Text(mut text) => {
812 text.rect = text.rect.translate(dx, dy);
813 Self::Text(text)
814 }
815 Self::Shadow(ShadowPrimitive::Drop {
816 shape,
817 cutout,
818 blur_radius,
819 blend_mode,
820 }) => Self::Shadow(ShadowPrimitive::Drop {
821 shape: Box::new(shape.translate(dx, dy)),
822 cutout: cutout.map(|cutout| Box::new(cutout.translate(dx, dy))),
823 blur_radius,
824 blend_mode,
825 }),
826 Self::Shadow(ShadowPrimitive::Inner {
827 fill,
828 cutout,
829 blur_radius,
830 blend_mode,
831 clip_rect,
832 }) => Self::Shadow(ShadowPrimitive::Inner {
833 fill: Box::new(fill.translate(dx, dy)),
834 cutout: Box::new(cutout.translate(dx, dy)),
835 blur_radius,
836 blend_mode,
837 clip_rect: clip_rect.translate(dx, dy),
838 }),
839 Self::Group(GroupMarker::Start(group)) => {
840 Self::Group(GroupMarker::Start(group.translate(dx, dy)))
841 }
842 Self::Group(GroupMarker::End) => Self::Group(GroupMarker::End),
843 }
844 }
845}
846
847#[derive(Clone, Debug, PartialEq)]
850pub enum ShadowPrimitive {
851 Drop {
855 shape: Box<DrawPrimitive>,
857 cutout: Option<Box<DrawPrimitive>>,
859 blur_radius: f32,
861 blend_mode: BlendMode,
863 },
864 Inner {
866 fill: Box<DrawPrimitive>,
868 cutout: Box<DrawPrimitive>,
870 blur_radius: f32,
872 blend_mode: BlendMode,
874 clip_rect: Rect,
876 },
877}
878
879pub trait DrawScope {
883 fn size(&self) -> Size;
885 fn draw_content(&mut self);
889 fn draw_rect(&mut self, brush: Brush);
891 fn draw_rect_blend(&mut self, brush: Brush, blend_mode: BlendMode);
893 fn draw_rect_at(&mut self, rect: Rect, brush: Brush);
895 fn draw_rect_at_blend(&mut self, rect: Rect, brush: Brush, blend_mode: BlendMode);
897 fn draw_round_rect(&mut self, brush: Brush, radii: CornerRadii);
899 fn draw_round_rect_blend(&mut self, brush: Brush, radii: CornerRadii, blend_mode: BlendMode);
901 fn draw_round_rect_at(&mut self, rect: Rect, brush: Brush, radii: CornerRadii);
903 fn draw_circle(&mut self, brush: Brush, center: Point, radius: f32);
905 fn draw_circle_blend(
907 &mut self,
908 brush: Brush,
909 center: Point,
910 radius: f32,
911 blend_mode: BlendMode,
912 );
913
914 fn draw_rect_stroked(&mut self, brush: Brush, stroke: Stroke);
916 fn draw_rect_stroked_blend(&mut self, brush: Brush, stroke: Stroke, blend_mode: BlendMode);
918 fn draw_rect_at_stroked(&mut self, rect: Rect, brush: Brush, stroke: Stroke);
920 fn draw_rect_at_stroked_blend(
922 &mut self,
923 rect: Rect,
924 brush: Brush,
925 stroke: Stroke,
926 blend_mode: BlendMode,
927 );
928 fn draw_round_rect_stroked(&mut self, brush: Brush, radii: CornerRadii, stroke: Stroke);
930 fn draw_round_rect_stroked_blend(
932 &mut self,
933 brush: Brush,
934 radii: CornerRadii,
935 stroke: Stroke,
936 blend_mode: BlendMode,
937 );
938 fn draw_round_rect_at_stroked(
940 &mut self,
941 rect: Rect,
942 brush: Brush,
943 radii: CornerRadii,
944 stroke: Stroke,
945 );
946 fn draw_round_rect_at_stroked_blend(
948 &mut self,
949 rect: Rect,
950 brush: Brush,
951 radii: CornerRadii,
952 stroke: Stroke,
953 blend_mode: BlendMode,
954 );
955 fn draw_circle_stroked(&mut self, brush: Brush, center: Point, radius: f32, stroke: Stroke);
958 fn draw_circle_stroked_blend(
960 &mut self,
961 brush: Brush,
962 center: Point,
963 radius: f32,
964 stroke: Stroke,
965 blend_mode: BlendMode,
966 );
967
968 fn draw_arc(
981 &mut self,
982 brush: Brush,
983 center: Point,
984 radius: f32,
985 start_angle: f32,
986 sweep_angle: f32,
987 stroke: Stroke,
988 );
989 #[expect(clippy::too_many_arguments, reason = "Compose's parameters")]
991 fn draw_arc_blend(
992 &mut self,
993 brush: Brush,
994 center: Point,
995 radius: f32,
996 start_angle: f32,
997 sweep_angle: f32,
998 stroke: Stroke,
999 blend_mode: BlendMode,
1000 );
1001
1002 fn draw_line(&mut self, brush: Brush, start: Point, end: Point, stroke: Stroke);
1008 fn draw_line_blend(
1010 &mut self,
1011 brush: Brush,
1012 start: Point,
1013 end: Point,
1014 stroke: Stroke,
1015 blend_mode: BlendMode,
1016 );
1017
1018 fn draw_path(&mut self, path: &Path, brush: Brush, style: DrawStyle);
1027 fn draw_path_blend(
1029 &mut self,
1030 path: &Path,
1031 brush: Brush,
1032 style: DrawStyle,
1033 blend_mode: BlendMode,
1034 );
1035
1036 fn draw_annular_sector(
1045 &mut self,
1046 brush: Brush,
1047 center: Point,
1048 inner_radius: f32,
1049 outer_radius: f32,
1050 start_angle: f32,
1051 sweep_angle: f32,
1052 );
1053 #[expect(clippy::too_many_arguments, reason = "Compose's parameters")]
1055 fn draw_annular_sector_blend(
1056 &mut self,
1057 brush: Brush,
1058 center: Point,
1059 inner_radius: f32,
1060 outer_radius: f32,
1061 start_angle: f32,
1062 sweep_angle: f32,
1063 blend_mode: BlendMode,
1064 );
1065
1066 fn draw_image(&mut self, image: ImageBitmap);
1068 fn draw_image_blend(&mut self, image: ImageBitmap, blend_mode: BlendMode);
1070 fn draw_image_at(
1073 &mut self,
1074 rect: Rect,
1075 image: ImageBitmap,
1076 alpha: f32,
1077 color_filter: Option<ColorFilter>,
1078 );
1079 fn draw_image_at_sampled(
1081 &mut self,
1082 rect: Rect,
1083 image: ImageBitmap,
1084 alpha: f32,
1085 color_filter: Option<ColorFilter>,
1086 sampling: ImageSampling,
1087 );
1088 fn draw_image_at_blend(
1090 &mut self,
1091 rect: Rect,
1092 image: ImageBitmap,
1093 alpha: f32,
1094 color_filter: Option<ColorFilter>,
1095 blend_mode: BlendMode,
1096 );
1097 fn draw_image_src(
1100 &mut self,
1101 image: ImageBitmap,
1102 src_rect: Rect,
1103 dst_rect: Rect,
1104 alpha: f32,
1105 color_filter: Option<ColorFilter>,
1106 );
1107 fn draw_image_src_sampled(
1109 &mut self,
1110 image: ImageBitmap,
1111 src_rect: Rect,
1112 dst_rect: Rect,
1113 alpha: f32,
1114 color_filter: Option<ColorFilter>,
1115 sampling: ImageSampling,
1116 );
1117 fn draw_image_src_blend(
1119 &mut self,
1120 image: ImageBitmap,
1121 src_rect: Rect,
1122 dst_rect: Rect,
1123 alpha: f32,
1124 color_filter: Option<ColorFilter>,
1125 blend_mode: BlendMode,
1126 );
1127 fn draw_vector_path(&mut self, path: &crate::VectorPath, brush: Brush);
1135 fn draw_svg_path(&mut self, d: &str, brush: Brush) {
1141 if let Ok(path) = crate::VectorPath::parse(d) {
1142 self.draw_vector_path(&path, brush);
1143 }
1144 }
1145
1146 fn measure_text(&self, text: &str, style: &DrawTextStyle) -> TextMeasurement;
1153
1154 fn draw_text(&mut self, brush: Brush, text: &str, style: &DrawTextStyle) {
1157 self.draw_text_at(Rect::from_size(self.size()), brush, text, style);
1158 }
1159
1160 fn draw_text_at(&mut self, rect: Rect, brush: Brush, text: &str, style: &DrawTextStyle);
1167
1168 fn draw_text_from(&mut self, top_left: Point, brush: Brush, text: &str, style: &DrawTextStyle);
1174
1175 fn with_transform(
1181 &mut self,
1182 transform: &[DrawTransform<'_>],
1183 block: &mut dyn FnMut(&mut dyn DrawScope),
1184 );
1185
1186 fn translate(&mut self, dx: f32, dy: f32, block: &mut dyn FnMut(&mut dyn DrawScope)) {
1188 self.with_transform(&[DrawTransform::Translate { dx, dy }], block);
1189 }
1190
1191 fn scale(
1194 &mut self,
1195 scale_x: f32,
1196 scale_y: f32,
1197 pivot: Point,
1198 block: &mut dyn FnMut(&mut dyn DrawScope),
1199 ) {
1200 self.with_transform(
1201 &[DrawTransform::Scale {
1202 scale_x,
1203 scale_y,
1204 pivot,
1205 }],
1206 block,
1207 );
1208 }
1209
1210 fn rotate(&mut self, degrees: f32, pivot: Point, block: &mut dyn FnMut(&mut dyn DrawScope)) {
1213 self.with_transform(&[DrawTransform::Rotate { degrees, pivot }], block);
1214 }
1215
1216 fn inset(
1219 &mut self,
1220 left: f32,
1221 top: f32,
1222 right: f32,
1223 bottom: f32,
1224 block: &mut dyn FnMut(&mut dyn DrawScope),
1225 ) {
1226 self.with_transform(
1227 &[DrawTransform::Inset {
1228 left,
1229 top,
1230 right,
1231 bottom,
1232 }],
1233 block,
1234 );
1235 }
1236
1237 fn clip_rect(&mut self, rect: Rect, block: &mut dyn FnMut(&mut dyn DrawScope)) {
1239 self.with_transform(&[DrawTransform::ClipRect(rect)], block);
1240 }
1241
1242 fn clip_path(&mut self, path: &Path, block: &mut dyn FnMut(&mut dyn DrawScope)) {
1245 self.with_transform(&[DrawTransform::ClipPath(path)], block);
1246 }
1247
1248 fn into_primitives(self) -> Vec<DrawPrimitive>;
1251}
1252
1253fn vector_mask_rect(bounds: Rect) -> Rect {
1256 let x = bounds.x.floor() - 1.0;
1257 let y = bounds.y.floor() - 1.0;
1258 Rect {
1259 x,
1260 y,
1261 width: (bounds.x + bounds.width).ceil() - x + 1.0,
1262 height: (bounds.y + bounds.height).ceil() - y + 1.0,
1263 }
1264}
1265
1266pub struct DrawScopeDefault<'a> {
1270 size: Size,
1271 recording: CommandRecorder<'a>,
1272 text_measurer: Option<Rc<dyn DrawTextMeasurer>>,
1273}
1274
1275impl<'a> DrawScopeDefault<'a> {
1276 pub fn new(size: Size, recording: &'a mut CommandRecording) -> Self {
1279 Self::with_storage(size, None, recording)
1280 }
1281
1282 pub fn with_text_measurer(
1287 size: Size,
1288 text_measurer: Rc<dyn DrawTextMeasurer>,
1289 recording: &'a mut CommandRecording,
1290 ) -> Self {
1291 Self::with_storage(size, Some(text_measurer), recording)
1292 }
1293
1294 fn with_storage(
1295 size: Size,
1296 text_measurer: Option<Rc<dyn DrawTextMeasurer>>,
1297 recording: &'a mut CommandRecording,
1298 ) -> Self {
1299 Self {
1300 size,
1301 recording: recording.record(),
1302 text_measurer,
1303 }
1304 }
1305
1306 pub fn content_marker_count(&self) -> u32 {
1308 self.recording.content_markers()
1309 }
1310
1311 pub fn draw_inset(&mut self, insets: EdgeInsets, draw: impl FnOnce(&mut DrawScopeDefault<'_>)) {
1315 let inner = insets.inset_rect(self.size);
1316 let mut recording = CommandRecording::default();
1317 let mut scope = DrawScopeDefault::with_storage(
1318 Size {
1319 width: inner.width,
1320 height: inner.height,
1321 },
1322 self.text_measurer.clone(),
1323 &mut recording,
1324 );
1325 draw(&mut scope);
1326 scope.finish();
1327 self.push_recorded(crate::translate_recorded(
1328 recording.primitives_with_markers(),
1329 inner.x,
1330 inner.y,
1331 ));
1332 }
1333
1334 pub fn push_recorded(&mut self, primitives: impl IntoIterator<Item = DrawPrimitive>) {
1336 for primitive in primitives {
1337 self.recording.push_primitive(primitive);
1338 }
1339 }
1340
1341 pub fn finish(self) {
1343 self.recording.finish();
1344 }
1345
1346 fn push_blended_primitive(&mut self, primitive: DrawPrimitive, blend_mode: BlendMode) {
1347 if blend_mode != BlendMode::SrcOver {
1348 self.recording.push_other(DrawPrimitive::Blend {
1349 primitive: Box::new(primitive),
1350 blend_mode,
1351 });
1352 return;
1353 }
1354 self.recording.push_other(primitive);
1355 }
1356
1357 #[inline]
1358 fn push_arc(&mut self, args: &ArcRecordArgs<'_>) {
1359 let geometry = normalized_band(args);
1360 if geometry.is_degenerate() {
1361 return;
1362 }
1363 self.recording.push_scope_arc(args, &geometry);
1364 }
1365
1366 fn push_path_fill(&mut self, path: &Path, brush: &Brush, blend_mode: BlendMode) {
1370 let brush_rect = Rect::from_size(self.size);
1371 let recording = &mut self.recording;
1372 let sliced = crate::thread_state::with(|state| {
1373 let mut slicer = state.path_slicer.borrow_mut();
1374 let contours = path
1375 .contours()
1376 .iter()
1377 .map(|contour| contour.points.as_slice());
1378 slicer
1379 .slice(contours, PathFillRule::NonZero)
1380 .map(|slices| recording.push_trapezoids(brush_rect, slices, brush, blend_mode))
1381 .is_some()
1382 });
1383 if !sliced {
1384 self.push_vector_path(
1385 &path.to_vector_path(PathFillRule::NonZero),
1386 brush,
1387 brush_rect,
1388 blend_mode,
1389 PathSide::Inside,
1390 );
1391 }
1392 }
1393
1394 fn with_path_mask(
1399 &mut self,
1400 mask: &crate::VectorPath,
1401 rest: &[DrawTransform<'_>],
1402 block: &mut dyn FnMut(&mut dyn DrawScope),
1403 ) {
1404 let rect = vector_mask_rect(mask.bounds());
1405 self.recording.push_group_start(DrawGroup::masked(rect));
1406 self.with_transform(rest, block);
1407 self.push_vector_path(
1408 mask,
1409 &Brush::solid(Color::BLACK),
1410 rect,
1411 BlendMode::DstOut,
1412 PathSide::Outside,
1413 );
1414 self.recording.push_group_end();
1415 }
1416
1417 fn push_vector_path(
1421 &mut self,
1422 path: &crate::VectorPath,
1423 brush: &Brush,
1424 brush_rect: Rect,
1425 blend_mode: BlendMode,
1426 side: PathSide,
1427 ) {
1428 const MAX_MASK_PIXELS: f32 = 4096.0;
1429
1430 if path.is_empty() || !brush.paints() {
1431 return;
1432 }
1433 let bounds = path.bounds();
1434 if bounds.width <= 0.0 || bounds.height <= 0.0 {
1435 return;
1436 }
1437
1438 let rect = vector_mask_rect(bounds);
1439 let origin = Point::new(rect.x, rect.y);
1440 let mask_width = (rect.width * VECTOR_PATH_SUPERSAMPLE)
1441 .ceil()
1442 .clamp(1.0, MAX_MASK_PIXELS) as usize;
1443 let mask_height = (rect.height * VECTOR_PATH_SUPERSAMPLE)
1444 .ceil()
1445 .clamp(1.0, MAX_MASK_PIXELS) as usize;
1446 let mask_size = (mask_width, mask_height);
1447
1448 let key = vector_path_mask_key(path, origin, mask_size, brush, brush_rect, side);
1449 let image = match vector_path_mask_cache_get(key) {
1450 Some(image) => image,
1451 None => {
1452 let Some(image) =
1453 rasterize_vector_path(path, brush, brush_rect, origin, mask_size, side)
1454 else {
1455 return;
1456 };
1457 vector_path_mask_cache_put(key, image.clone());
1458 image
1459 }
1460 };
1461
1462 let image = DrawPrimitive::Image {
1463 rect,
1464 image,
1465 alpha: 1.0,
1466 color_filter: None,
1467 sampling: ImageSampling::Linear,
1468 src_rect: None,
1469 };
1470 self.recording
1471 .push_other(if blend_mode == BlendMode::SrcOver {
1472 image
1473 } else {
1474 DrawPrimitive::Blend {
1475 primitive: Box::new(image),
1476 blend_mode,
1477 }
1478 });
1479 }
1480}
1481
1482impl DrawScope for DrawScopeDefault<'_> {
1483 fn size(&self) -> Size {
1484 self.size
1485 }
1486
1487 fn with_transform(
1488 &mut self,
1489 transform: &[DrawTransform<'_>],
1490 block: &mut dyn FnMut(&mut dyn DrawScope),
1491 ) {
1492 let Some((step, rest)) = transform.split_first() else {
1493 block(self);
1494 return;
1495 };
1496 let outer = self.size;
1497 let (group, size) = match *step {
1498 DrawTransform::Translate { dx, dy } => (DrawGroup::moved(dx, dy, outer), outer),
1499 DrawTransform::Scale {
1500 scale_x,
1501 scale_y,
1502 pivot,
1503 } => (DrawGroup::about(pivot, scale_x, scale_y, 0.0, outer), outer),
1504 DrawTransform::Rotate { degrees, pivot } => {
1505 (DrawGroup::about(pivot, 1.0, 1.0, degrees, outer), outer)
1506 }
1507 DrawTransform::Inset {
1508 left,
1509 top,
1510 right,
1511 bottom,
1512 } => {
1513 let inner = Size::new(
1514 (outer.width - left - right).max(0.0),
1515 (outer.height - top - bottom).max(0.0),
1516 );
1517 (DrawGroup::moved(left, top, inner), inner)
1518 }
1519 DrawTransform::ClipRect(rect) => (DrawGroup::clipped(rect), outer),
1520 DrawTransform::ClipPath(path) => {
1521 let mask = path.to_vector_path(PathFillRule::NonZero);
1522 if !mask.is_empty() {
1523 self.with_path_mask(&mask, rest, block);
1524 return;
1525 }
1526 (DrawGroup::clipped(Rect::EMPTY), outer)
1528 }
1529 };
1530 self.recording.push_group_start(group);
1531 self.size = size;
1532 self.with_transform(rest, block);
1533 self.size = outer;
1534 self.recording.push_group_end();
1535 }
1536
1537 fn draw_content(&mut self) {
1538 self.recording.push_content();
1539 }
1540
1541 fn draw_rect(&mut self, brush: Brush) {
1542 self.draw_rect_blend(brush, BlendMode::SrcOver);
1543 }
1544
1545 fn draw_rect_blend(&mut self, brush: Brush, blend_mode: BlendMode) {
1546 self.recording
1547 .push_rect(Rect::from_size(self.size), &brush, None, blend_mode);
1548 }
1549
1550 fn draw_rect_at(&mut self, rect: Rect, brush: Brush) {
1551 self.draw_rect_at_blend(rect, brush, BlendMode::SrcOver);
1552 }
1553
1554 fn draw_rect_at_blend(&mut self, rect: Rect, brush: Brush, blend_mode: BlendMode) {
1555 self.recording.push_rect(rect, &brush, None, blend_mode);
1556 }
1557
1558 fn draw_round_rect(&mut self, brush: Brush, radii: CornerRadii) {
1559 self.draw_round_rect_blend(brush, radii, BlendMode::SrcOver);
1560 }
1561
1562 fn draw_round_rect_blend(&mut self, brush: Brush, radii: CornerRadii, blend_mode: BlendMode) {
1563 self.recording
1564 .push_round_rect(Rect::from_size(self.size), &brush, radii, None, blend_mode);
1565 }
1566
1567 fn draw_round_rect_at(&mut self, rect: Rect, brush: Brush, radii: CornerRadii) {
1568 self.recording
1569 .push_round_rect(rect, &brush, radii, None, BlendMode::SrcOver);
1570 }
1571
1572 fn draw_rect_stroked(&mut self, brush: Brush, stroke: Stroke) {
1573 self.draw_rect_stroked_blend(brush, stroke, BlendMode::SrcOver);
1574 }
1575
1576 fn draw_rect_stroked_blend(&mut self, brush: Brush, stroke: Stroke, blend_mode: BlendMode) {
1577 self.draw_rect_at_stroked_blend(Rect::from_size(self.size), brush, stroke, blend_mode);
1578 }
1579
1580 fn draw_rect_at_stroked(&mut self, rect: Rect, brush: Brush, stroke: Stroke) {
1581 self.draw_rect_at_stroked_blend(rect, brush, stroke, BlendMode::SrcOver);
1582 }
1583
1584 fn draw_rect_at_stroked_blend(
1585 &mut self,
1586 rect: Rect,
1587 brush: Brush,
1588 stroke: Stroke,
1589 blend_mode: BlendMode,
1590 ) {
1591 if !stroke.is_visible() {
1592 return;
1593 }
1594 self.recording
1595 .push_rect(rect, &brush, Some(stroke), blend_mode);
1596 }
1597
1598 fn draw_round_rect_stroked(&mut self, brush: Brush, radii: CornerRadii, stroke: Stroke) {
1599 self.draw_round_rect_stroked_blend(brush, radii, stroke, BlendMode::SrcOver);
1600 }
1601
1602 fn draw_round_rect_stroked_blend(
1603 &mut self,
1604 brush: Brush,
1605 radii: CornerRadii,
1606 stroke: Stroke,
1607 blend_mode: BlendMode,
1608 ) {
1609 self.draw_round_rect_at_stroked_blend(
1610 Rect::from_size(self.size),
1611 brush,
1612 radii,
1613 stroke,
1614 blend_mode,
1615 );
1616 }
1617
1618 fn draw_round_rect_at_stroked(
1619 &mut self,
1620 rect: Rect,
1621 brush: Brush,
1622 radii: CornerRadii,
1623 stroke: Stroke,
1624 ) {
1625 self.draw_round_rect_at_stroked_blend(rect, brush, radii, stroke, BlendMode::SrcOver);
1626 }
1627
1628 fn draw_round_rect_at_stroked_blend(
1629 &mut self,
1630 rect: Rect,
1631 brush: Brush,
1632 radii: CornerRadii,
1633 stroke: Stroke,
1634 blend_mode: BlendMode,
1635 ) {
1636 if !stroke.is_visible() {
1637 return;
1638 }
1639 self.recording
1640 .push_round_rect(rect, &brush, radii, Some(stroke), blend_mode);
1641 }
1642
1643 fn draw_circle_stroked(&mut self, brush: Brush, center: Point, radius: f32, stroke: Stroke) {
1644 self.draw_circle_stroked_blend(brush, center, radius, stroke, BlendMode::SrcOver);
1645 }
1646
1647 fn draw_circle_stroked_blend(
1648 &mut self,
1649 brush: Brush,
1650 center: Point,
1651 radius: f32,
1652 stroke: Stroke,
1653 blend_mode: BlendMode,
1654 ) {
1655 if !stroke.is_visible() || !radius.is_finite() {
1656 return;
1657 }
1658 let radius = radius.max(0.0);
1659 let diameter = radius * 2.0;
1660 self.draw_round_rect_at_stroked_blend(
1661 Rect {
1662 x: center.x - radius,
1663 y: center.y - radius,
1664 width: diameter,
1665 height: diameter,
1666 },
1667 brush,
1668 CornerRadii::uniform(radius),
1669 stroke,
1670 blend_mode,
1671 );
1672 }
1673
1674 fn draw_arc(
1675 &mut self,
1676 brush: Brush,
1677 center: Point,
1678 radius: f32,
1679 start_angle: f32,
1680 sweep_angle: f32,
1681 stroke: Stroke,
1682 ) {
1683 self.draw_arc_blend(
1684 brush,
1685 center,
1686 radius,
1687 start_angle,
1688 sweep_angle,
1689 stroke,
1690 BlendMode::SrcOver,
1691 );
1692 }
1693
1694 fn draw_arc_blend(
1695 &mut self,
1696 brush: Brush,
1697 center: Point,
1698 radius: f32,
1699 start_angle: f32,
1700 sweep_angle: f32,
1701 stroke: Stroke,
1702 blend_mode: BlendMode,
1703 ) {
1704 if !stroke.is_visible() {
1705 return;
1706 }
1707 self.push_arc(&ArcRecordArgs {
1708 brush: &brush,
1709 center,
1710 radius,
1711 start_angle,
1712 sweep_angle,
1713 stroke: Some(stroke),
1714 inner_radius: 0.0,
1715 blend_mode,
1716 });
1717 }
1718
1719 fn draw_line(&mut self, brush: Brush, start: Point, end: Point, stroke: Stroke) {
1720 self.draw_line_blend(brush, start, end, stroke, BlendMode::SrcOver);
1721 }
1722
1723 fn draw_line_blend(
1724 &mut self,
1725 brush: Brush,
1726 start: Point,
1727 end: Point,
1728 stroke: Stroke,
1729 blend_mode: BlendMode,
1730 ) {
1731 self.recording
1732 .line_run(&brush, stroke, blend_mode)
1733 .push(start, end, stroke.cap);
1734 }
1735
1736 fn draw_path(&mut self, path: &Path, brush: Brush, style: DrawStyle) {
1737 self.draw_path_blend(path, brush, style, BlendMode::SrcOver);
1738 }
1739
1740 fn draw_path_blend(
1741 &mut self,
1742 path: &Path,
1743 brush: Brush,
1744 style: DrawStyle,
1745 blend_mode: BlendMode,
1746 ) {
1747 let (stroke, dash) = match style {
1748 DrawStyle::Fill => {
1749 self.push_path_fill(path, &brush, blend_mode);
1750 return;
1751 }
1752 DrawStyle::Stroke(stroke) => (stroke, None),
1753 DrawStyle::DashedStroke(stroke, dash) => (stroke, Some(dash)),
1754 };
1755 if !stroke.is_visible() {
1756 return;
1757 }
1758 let mut run = self.recording.line_run(&brush, stroke, blend_mode);
1759 let mut push = |line: LineGeometry| run.push(line.start, line.end, line.cap);
1760 for contour in path.contours() {
1761 let Some(dash) = dash else {
1762 crate::for_each_stroke_line(&contour.points, contour.closed, stroke, &mut push);
1763 continue;
1764 };
1765 let closing = contour
1766 .closed
1767 .then(|| contour.points.first().copied())
1768 .flatten();
1769 let points: std::borrow::Cow<'_, [Point]> = match closing {
1770 Some(first) => {
1771 std::borrow::Cow::Owned(contour.points.iter().copied().chain([first]).collect())
1772 }
1773 None => std::borrow::Cow::Borrowed(&contour.points),
1774 };
1775 dash.for_each_dash(&points, |piece| {
1776 crate::for_each_stroke_line(piece, false, stroke, &mut push);
1777 });
1778 }
1779 }
1780
1781 fn draw_annular_sector(
1782 &mut self,
1783 brush: Brush,
1784 center: Point,
1785 inner_radius: f32,
1786 outer_radius: f32,
1787 start_angle: f32,
1788 sweep_angle: f32,
1789 ) {
1790 self.draw_annular_sector_blend(
1791 brush,
1792 center,
1793 inner_radius,
1794 outer_radius,
1795 start_angle,
1796 sweep_angle,
1797 BlendMode::SrcOver,
1798 );
1799 }
1800
1801 fn draw_annular_sector_blend(
1802 &mut self,
1803 brush: Brush,
1804 center: Point,
1805 inner_radius: f32,
1806 outer_radius: f32,
1807 start_angle: f32,
1808 sweep_angle: f32,
1809 blend_mode: BlendMode,
1810 ) {
1811 self.push_arc(&ArcRecordArgs {
1812 brush: &brush,
1813 center,
1814 radius: outer_radius,
1815 start_angle,
1816 sweep_angle,
1817 stroke: None,
1818 inner_radius,
1819 blend_mode,
1820 });
1821 }
1822
1823 fn draw_circle(&mut self, brush: Brush, center: Point, radius: f32) {
1824 self.draw_circle_blend(brush, center, radius, BlendMode::SrcOver);
1825 }
1826
1827 fn draw_circle_blend(
1828 &mut self,
1829 brush: Brush,
1830 center: Point,
1831 radius: f32,
1832 blend_mode: BlendMode,
1833 ) {
1834 let radius = radius.max(0.0);
1835 let diameter = radius * 2.0;
1836 self.recording.push_round_rect(
1837 Rect {
1838 x: center.x - radius,
1839 y: center.y - radius,
1840 width: diameter,
1841 height: diameter,
1842 },
1843 &brush,
1844 CornerRadii::uniform(radius),
1845 None,
1846 blend_mode,
1847 );
1848 }
1849
1850 fn draw_image(&mut self, image: ImageBitmap) {
1851 self.draw_image_blend(image, BlendMode::SrcOver);
1852 }
1853
1854 fn draw_image_blend(&mut self, image: ImageBitmap, blend_mode: BlendMode) {
1855 self.push_blended_primitive(
1856 DrawPrimitive::Image {
1857 rect: Rect::from_size(self.size),
1858 image,
1859 alpha: 1.0,
1860 color_filter: None,
1861 sampling: ImageSampling::Nearest,
1862 src_rect: None,
1863 },
1864 blend_mode,
1865 );
1866 }
1867
1868 fn draw_image_at(
1869 &mut self,
1870 rect: Rect,
1871 image: ImageBitmap,
1872 alpha: f32,
1873 color_filter: Option<ColorFilter>,
1874 ) {
1875 self.draw_image_at_sampled(rect, image, alpha, color_filter, ImageSampling::Nearest);
1876 }
1877
1878 fn draw_image_at_sampled(
1879 &mut self,
1880 rect: Rect,
1881 image: ImageBitmap,
1882 alpha: f32,
1883 color_filter: Option<ColorFilter>,
1884 sampling: ImageSampling,
1885 ) {
1886 self.push_blended_primitive(
1887 DrawPrimitive::Image {
1888 rect,
1889 image,
1890 alpha: alpha.clamp(0.0, 1.0),
1891 color_filter,
1892 sampling,
1893 src_rect: None,
1894 },
1895 BlendMode::SrcOver,
1896 );
1897 }
1898
1899 fn draw_image_at_blend(
1900 &mut self,
1901 rect: Rect,
1902 image: ImageBitmap,
1903 alpha: f32,
1904 color_filter: Option<ColorFilter>,
1905 blend_mode: BlendMode,
1906 ) {
1907 self.push_blended_primitive(
1908 DrawPrimitive::Image {
1909 rect,
1910 image,
1911 alpha: alpha.clamp(0.0, 1.0),
1912 color_filter,
1913 sampling: ImageSampling::Nearest,
1914 src_rect: None,
1915 },
1916 blend_mode,
1917 );
1918 }
1919
1920 fn draw_image_src(
1921 &mut self,
1922 image: ImageBitmap,
1923 src_rect: Rect,
1924 dst_rect: Rect,
1925 alpha: f32,
1926 color_filter: Option<ColorFilter>,
1927 ) {
1928 self.draw_image_src_blend(
1929 image,
1930 src_rect,
1931 dst_rect,
1932 alpha,
1933 color_filter,
1934 BlendMode::SrcOver,
1935 );
1936 }
1937
1938 fn draw_image_src_sampled(
1939 &mut self,
1940 image: ImageBitmap,
1941 src_rect: Rect,
1942 dst_rect: Rect,
1943 alpha: f32,
1944 color_filter: Option<ColorFilter>,
1945 sampling: ImageSampling,
1946 ) {
1947 self.push_blended_primitive(
1948 DrawPrimitive::Image {
1949 rect: dst_rect,
1950 image,
1951 alpha: alpha.clamp(0.0, 1.0),
1952 color_filter,
1953 sampling,
1954 src_rect: Some(src_rect),
1955 },
1956 BlendMode::SrcOver,
1957 );
1958 }
1959
1960 fn draw_image_src_blend(
1961 &mut self,
1962 image: ImageBitmap,
1963 src_rect: Rect,
1964 dst_rect: Rect,
1965 alpha: f32,
1966 color_filter: Option<ColorFilter>,
1967 blend_mode: BlendMode,
1968 ) {
1969 self.push_blended_primitive(
1970 DrawPrimitive::Image {
1971 rect: dst_rect,
1972 image,
1973 alpha: alpha.clamp(0.0, 1.0),
1974 color_filter,
1975 sampling: ImageSampling::Nearest,
1976 src_rect: Some(src_rect),
1977 },
1978 blend_mode,
1979 );
1980 }
1981
1982 fn draw_vector_path(&mut self, path: &crate::VectorPath, brush: Brush) {
1983 self.push_vector_path(
1984 path,
1985 &brush,
1986 Rect::from_size(self.size),
1987 BlendMode::SrcOver,
1988 PathSide::Inside,
1989 );
1990 }
1991
1992 fn measure_text(&self, text: &str, style: &DrawTextStyle) -> TextMeasurement {
1993 measured_text(self.text_measurer.as_deref(), text, style).measurement
1994 }
1995
1996 fn draw_text_at(&mut self, rect: Rect, brush: Brush, text: &str, style: &DrawTextStyle) {
1997 let at = TextBlockAt::Aligned(rect);
1998 let measurer = self.text_measurer.as_deref();
1999 if let Some(text) = text_primitive(measurer, at, brush, text, style) {
2000 self.recording.push_other(text);
2001 }
2002 }
2003
2004 fn draw_text_from(&mut self, top_left: Point, brush: Brush, text: &str, style: &DrawTextStyle) {
2005 let at = TextBlockAt::From(top_left);
2006 let measurer = self.text_measurer.as_deref();
2007 if let Some(text) = text_primitive(measurer, at, brush, text, style) {
2008 self.recording.push_other(text);
2009 }
2010 }
2011
2012 fn into_primitives(self) -> Vec<DrawPrimitive> {
2013 self.recording.into_primitives()
2014 }
2015}
2016
2017#[cfg(test)]
2018#[path = "tests/geometry_tests.rs"]
2019mod tests;