Skip to main content

simple_render/ui/render/
rect.rs

1use super::*;
2
3#[derive(Clone)]
4pub struct Rect {
5    pub(super) layer_options: LayerOptions,
6    pub(super) width: Length,
7    pub(super) height: Length,
8    pub(super) min_width: u32,
9    pub(super) min_height: u32,
10    pub(super) max_width: Option<u32>,
11    pub(super) max_height: Option<u32>,
12    pub(super) fill: u32,
13    pub(super) direction: Direction,
14    pub(super) align: Align,
15    pub(super) justify: Align,
16    pub(super) overflow: Overflow,
17    pub(super) position: Position,
18    pub(super) inset: Inset,
19    pub(super) padding: Spacing,
20    pub(super) gap: u32,
21    pub(super) style: Style,
22    pub(super) content: Option<Content>,
23    pub(super) children: Vec<Rect>,
24}
25
26pub type Ui = Rect;
27
28impl Default for Rect {
29    fn default() -> Self {
30        Self {
31            layer_options: LayerOptions::default(),
32            width: Length::Fit,
33            height: Length::Fit,
34            min_width: 0,
35            min_height: 0,
36            max_width: None,
37            max_height: None,
38            fill: 1,
39            direction: Direction::Row,
40            align: Align::Start,
41            justify: Align::Start,
42            overflow: Overflow::Clip,
43            position: Position::Flow,
44            inset: Inset::ZERO,
45            padding: Spacing::ZERO,
46            gap: 0,
47            style: Style::default(),
48            content: None,
49            children: Vec::new(),
50        }
51    }
52}
53
54impl Rect {
55    pub fn new(layout: RectLayout) -> Self {
56        Self::default().with_layout(layout)
57    }
58
59    pub fn empty() -> Self {
60        Self::default()
61    }
62
63    pub fn layout(layout: RectLayout) -> Self {
64        Self::new(layout)
65    }
66
67    pub fn styled(style: RectStyle) -> Self {
68        Self::empty().style(style)
69    }
70
71    pub fn with_layout(mut self, layout: RectLayout) -> Self {
72        if let Some(surface) = layout.surface {
73            self.layer_options = surface.into();
74        }
75        self.width = layout.width;
76        self.height = layout.height;
77        self.min_width = layout.min_width;
78        self.min_height = layout.min_height;
79        self.max_width = layout.max_width;
80        self.max_height = layout.max_height;
81        self.fill = layout.fill;
82        self.direction = layout.direction;
83        self.align = layout.align;
84        self.justify = layout.justify;
85        self.overflow = layout.overflow;
86        self.position = layout.position;
87        self.inset = layout.inset;
88        self.padding = layout.padding;
89        self.gap = layout.gap;
90        self.style = layout.style;
91        self.content = layout.content;
92        self
93    }
94
95    pub fn style(mut self, style: RectStyle) -> Self {
96        self.style = style;
97        self
98    }
99
100    pub fn width(mut self, width: Length) -> Self {
101        self.width = width;
102        self
103    }
104
105    pub fn height(mut self, height: Length) -> Self {
106        self.height = height;
107        self
108    }
109
110    pub fn size(mut self, width: Length, height: Length) -> Self {
111        self.width = width;
112        self.height = height;
113        self
114    }
115
116    pub fn min_width(mut self, min_width: u32) -> Self {
117        self.min_width = min_width;
118        self
119    }
120
121    pub fn min_height(mut self, min_height: u32) -> Self {
122        self.min_height = min_height;
123        self
124    }
125
126    pub fn max_width(mut self, max_width: impl Into<Option<u32>>) -> Self {
127        self.max_width = max_width.into();
128        self
129    }
130
131    pub fn max_height(mut self, max_height: impl Into<Option<u32>>) -> Self {
132        self.max_height = max_height.into();
133        self
134    }
135
136    pub fn fill(mut self, fill: u32) -> Self {
137        self.fill = fill;
138        self
139    }
140
141    pub fn direction(mut self, direction: Direction) -> Self {
142        self.direction = direction;
143        self
144    }
145
146    pub fn align(mut self, align: Align) -> Self {
147        self.align = align;
148        self
149    }
150
151    pub fn justify(mut self, justify: Align) -> Self {
152        self.justify = justify;
153        self
154    }
155
156    pub fn overflow(mut self, overflow: Overflow) -> Self {
157        self.overflow = overflow;
158        self
159    }
160
161    pub fn position(mut self, position: Position) -> Self {
162        self.position = position;
163        self
164    }
165
166    pub fn inset(mut self, inset: Inset) -> Self {
167        self.inset = inset;
168        self
169    }
170
171    pub fn absolute(mut self, inset: Inset) -> Self {
172        self.position = Position::Absolute;
173        self.inset = inset;
174        self
175    }
176
177    pub fn padding(mut self, padding: Spacing) -> Self {
178        self.padding = padding;
179        self
180    }
181
182    pub fn gap(mut self, gap: u32) -> Self {
183        self.gap = gap;
184        self
185    }
186
187    pub fn background(mut self, background: impl Into<Paint>) -> Self {
188        self.style.background = Some(background.into());
189        self
190    }
191
192    pub fn border(mut self, border: Border) -> Self {
193        self.style.border = Some(border);
194        self
195    }
196
197    pub fn corner_radius(mut self, radius: u32) -> Self {
198        self.style.corner_radius = radius;
199        self
200    }
201
202    pub fn corner_radii(mut self, radii: CornerRadius) -> Self {
203        self.style.corner_radii = radii;
204        self
205    }
206
207    pub fn gradient(mut self, gradient: GradientDirection) -> Self {
208        self.style.gradient = gradient;
209        self
210    }
211
212    pub fn opacity(mut self, opacity: f32) -> Self {
213        self.style.opacity = opacity;
214        self
215    }
216
217    pub fn content(mut self, content: impl Into<Content>) -> Self {
218        self.content = Some(content.into());
219        self
220    }
221
222    pub fn with_surface(mut self, surface: Surface) -> Self {
223        self.layer_options = surface.into();
224        self
225    }
226
227    pub fn begin(_: Bounds) -> Self {
228        Self::default()
229    }
230
231    pub fn build(bounds: Bounds, content: impl FnOnce(&mut Self)) -> Self {
232        let mut ui = Self::begin(bounds);
233        content(&mut ui);
234        ui
235    }
236
237    pub fn child(mut self, child: Rect) -> Self {
238        self.children.push(child);
239        self
240    }
241
242    pub fn children(mut self, children: impl IntoIterator<Item = Rect>) -> Self {
243        self.children.extend(children);
244        self
245    }
246
247    pub fn draw(self) -> wayland::Result<()> {
248        let options = self.layer_options.clone();
249        options.show(UiRenderer {
250            root: self,
251            fonts: LazyFontCtx::new(),
252        })
253    }
254
255    pub fn draw_with_commands(self, receiver: wayland::RenderReceiver) -> wayland::Result<()> {
256        let options = self.layer_options.clone();
257        options.show_with_commands(
258            UiRenderer {
259                root: self,
260                fonts: LazyFontCtx::new(),
261            },
262            receiver,
263        )
264    }
265
266    pub fn commands(&self, bounds: Bounds) -> Vec<DrawCommand> {
267        let mut fonts = FontCtx::new();
268        self.commands_with_fonts(bounds, &mut fonts)
269    }
270
271    pub fn commands_with_fonts(&self, bounds: Bounds, fonts: &mut FontCtx) -> Vec<DrawCommand> {
272        let mut commands = Vec::new();
273        Self::visit_layout(
274            self,
275            bounds,
276            Clip::rect(bounds),
277            1.0,
278            None,
279            fonts,
280            &mut |command, _| {
281                commands.push(command.to_owned());
282            },
283        );
284        fonts.trim_scratch();
285        commands
286    }
287
288    pub fn measure(&self, available_width: u32, available_height: u32) -> MeasuredSize {
289        let mut fonts = FontCtx::new();
290        self.measure_with_fonts(available_width, available_height, &mut fonts)
291    }
292
293    pub fn measure_with_fonts(
294        &self,
295        available_width: u32,
296        available_height: u32,
297        fonts: &mut FontCtx,
298    ) -> MeasuredSize {
299        let measured = measure_element(self, fonts, available_width, available_height);
300        fonts.trim_scratch();
301        measured.into()
302    }
303
304    pub fn hit_test(&self, bounds: Bounds, x: f64, y: f64) -> Option<Hit> {
305        let mut fonts = FontCtx::new();
306        self.hit_test_with_fonts(bounds, x, y, &mut fonts)
307    }
308
309    pub fn hit_test_with_fonts(
310        &self,
311        bounds: Bounds,
312        x: f64,
313        y: f64,
314        fonts: &mut FontCtx,
315    ) -> Option<Hit> {
316        let mut path = Vec::new();
317        self.hit_test_path_with_fonts(bounds, x, y, fonts, &mut path)
318            .map(|bounds| Hit { path, bounds })
319    }
320
321    pub fn hit_test_path(
322        &self,
323        bounds: Bounds,
324        x: f64,
325        y: f64,
326        path: &mut Vec<usize>,
327    ) -> Option<Bounds> {
328        let mut fonts = FontCtx::new();
329        self.hit_test_path_with_fonts(bounds, x, y, &mut fonts, path)
330    }
331
332    pub fn hit_test_path_with_fonts(
333        &self,
334        bounds: Bounds,
335        x: f64,
336        y: f64,
337        fonts: &mut FontCtx,
338        path: &mut Vec<usize>,
339    ) -> Option<Bounds> {
340        path.clear();
341        let Some((x, y)) = hit_point(x, y) else {
342            fonts.trim_scratch();
343            return None;
344        };
345
346        let mut current_path = Vec::new();
347        let bounds = Self::hit_test_layout(
348            self,
349            bounds,
350            Clip::rect(bounds),
351            None,
352            fonts,
353            x,
354            y,
355            &mut current_path,
356            path,
357        );
358        fonts.trim_scratch();
359        bounds
360    }
361
362    pub fn paint(&mut self, canvas: &mut Canvas<'_>) {
363        let mut fonts = FontCtx::new();
364        self.paint_with_fonts(canvas, &mut fonts);
365    }
366
367    pub fn paint_with_fonts(&mut self, canvas: &mut Canvas<'_>, fonts: &mut FontCtx) {
368        self.paint_scaled_with_fonts(canvas, fonts, canvas.width(), canvas.height(), 1);
369    }
370
371    #[allow(clippy::too_many_arguments)]
372    pub fn paint_bgra_with_fonts(
373        &mut self,
374        pixels: &mut [u8],
375        buffer_width: u32,
376        buffer_height: u32,
377        stride: u32,
378        logical_width: u32,
379        logical_height: u32,
380        scale: u32,
381        fonts: &mut FontCtx,
382    ) -> Option<DamageRect> {
383        self.paint_bgra_viewport_with_fonts(
384            pixels,
385            buffer_width,
386            buffer_height,
387            stride,
388            logical_width,
389            logical_height,
390            0,
391            0,
392            scale,
393            fonts,
394        )
395    }
396
397    #[allow(clippy::too_many_arguments)]
398    pub fn paint_bgra_viewport_with_fonts(
399        &mut self,
400        pixels: &mut [u8],
401        buffer_width: u32,
402        buffer_height: u32,
403        stride: u32,
404        logical_width: u32,
405        logical_height: u32,
406        viewport_x: i32,
407        viewport_y: i32,
408        scale: u32,
409        fonts: &mut FontCtx,
410    ) -> Option<DamageRect> {
411        let mut canvas =
412            Canvas::from_bgra_pixels(pixels, buffer_width, buffer_height, stride, scale)?;
413        self.paint_viewport_with_fonts(
414            &mut canvas,
415            fonts,
416            logical_width,
417            logical_height,
418            viewport_x,
419            viewport_y,
420            scale,
421        );
422        canvas.damage()
423    }
424
425    #[allow(clippy::too_many_arguments)]
426    pub fn paint_bgra_transformed_with_fonts(
427        &mut self,
428        pixels: &mut [u8],
429        buffer_width: u32,
430        buffer_height: u32,
431        stride: u32,
432        logical_width: u32,
433        logical_height: u32,
434        scale: u32,
435        transform: PaintTransform,
436        fonts: &mut FontCtx,
437    ) -> Option<DamageRect> {
438        self.paint_bgra_transformed_viewport_with_fonts(
439            pixels,
440            buffer_width,
441            buffer_height,
442            stride,
443            logical_width,
444            logical_height,
445            0,
446            0,
447            scale,
448            transform,
449            fonts,
450        )
451    }
452
453    #[allow(clippy::too_many_arguments)]
454    pub fn paint_bgra_transformed_viewport_with_fonts(
455        &mut self,
456        pixels: &mut [u8],
457        buffer_width: u32,
458        buffer_height: u32,
459        stride: u32,
460        logical_width: u32,
461        logical_height: u32,
462        viewport_x: i32,
463        viewport_y: i32,
464        scale: u32,
465        transform: PaintTransform,
466        fonts: &mut FontCtx,
467    ) -> Option<DamageRect> {
468        let mut canvas =
469            Canvas::from_bgra_pixels(pixels, buffer_width, buffer_height, stride, scale)?;
470        self.paint_transformed_viewport_with_fonts(
471            &mut canvas,
472            fonts,
473            logical_width,
474            logical_height,
475            viewport_x,
476            viewport_y,
477            scale,
478            transform,
479        );
480        canvas.damage()
481    }
482
483    #[allow(clippy::too_many_arguments)]
484    pub fn paint_bgra(
485        &mut self,
486        pixels: &mut [u8],
487        buffer_width: u32,
488        buffer_height: u32,
489        stride: u32,
490        logical_width: u32,
491        logical_height: u32,
492        scale: u32,
493    ) -> Option<DamageRect> {
494        let mut fonts = FontCtx::new();
495        self.paint_bgra_with_fonts(
496            pixels,
497            buffer_width,
498            buffer_height,
499            stride,
500            logical_width,
501            logical_height,
502            scale,
503            &mut fonts,
504        )
505    }
506
507    #[allow(clippy::too_many_arguments)]
508    pub fn paint_bgra_transformed(
509        &mut self,
510        pixels: &mut [u8],
511        buffer_width: u32,
512        buffer_height: u32,
513        stride: u32,
514        logical_width: u32,
515        logical_height: u32,
516        scale: u32,
517        transform: PaintTransform,
518    ) -> Option<DamageRect> {
519        let mut fonts = FontCtx::new();
520        self.paint_bgra_transformed_with_fonts(
521            pixels,
522            buffer_width,
523            buffer_height,
524            stride,
525            logical_width,
526            logical_height,
527            scale,
528            transform,
529            &mut fonts,
530        )
531    }
532
533    #[allow(clippy::too_many_arguments)]
534    pub fn paint_bgra_transformed_viewport(
535        &mut self,
536        pixels: &mut [u8],
537        buffer_width: u32,
538        buffer_height: u32,
539        stride: u32,
540        logical_width: u32,
541        logical_height: u32,
542        viewport_x: i32,
543        viewport_y: i32,
544        scale: u32,
545        transform: PaintTransform,
546    ) -> Option<DamageRect> {
547        let mut fonts = FontCtx::new();
548        self.paint_bgra_transformed_viewport_with_fonts(
549            pixels,
550            buffer_width,
551            buffer_height,
552            stride,
553            logical_width,
554            logical_height,
555            viewport_x,
556            viewport_y,
557            scale,
558            transform,
559            &mut fonts,
560        )
561    }
562
563    #[allow(clippy::too_many_arguments)]
564    pub fn paint_bgra_viewport(
565        &mut self,
566        pixels: &mut [u8],
567        buffer_width: u32,
568        buffer_height: u32,
569        stride: u32,
570        logical_width: u32,
571        logical_height: u32,
572        viewport_x: i32,
573        viewport_y: i32,
574        scale: u32,
575    ) -> Option<DamageRect> {
576        let mut fonts = FontCtx::new();
577        self.paint_bgra_viewport_with_fonts(
578            pixels,
579            buffer_width,
580            buffer_height,
581            stride,
582            logical_width,
583            logical_height,
584            viewport_x,
585            viewport_y,
586            scale,
587            &mut fonts,
588        )
589    }
590
591    pub fn paint_scaled_with_fonts(
592        &mut self,
593        canvas: &mut Canvas<'_>,
594        fonts: &mut FontCtx,
595        width: u32,
596        height: u32,
597        scale: u32,
598    ) {
599        self.paint_viewport_with_fonts(canvas, fonts, width, height, 0, 0, scale);
600    }
601
602    #[allow(clippy::too_many_arguments)]
603    pub fn paint_transformed_with_fonts(
604        &mut self,
605        canvas: &mut Canvas<'_>,
606        fonts: &mut FontCtx,
607        width: u32,
608        height: u32,
609        scale: u32,
610        transform: PaintTransform,
611    ) {
612        self.paint_transformed_viewport_with_fonts(
613            canvas, fonts, width, height, 0, 0, scale, transform,
614        );
615    }
616
617    #[allow(clippy::too_many_arguments)]
618    pub fn paint_viewport_with_fonts(
619        &mut self,
620        canvas: &mut Canvas<'_>,
621        fonts: &mut FontCtx,
622        width: u32,
623        height: u32,
624        viewport_x: i32,
625        viewport_y: i32,
626        scale: u32,
627    ) {
628        let scale = scale.max(1);
629        let offset = PaintOffset {
630            x: scale_i32(viewport_x, scale),
631            y: scale_i32(viewport_y, scale),
632        };
633        let bounds = Bounds::new(0, 0, width, height);
634        Self::visit_layout(
635            self,
636            bounds,
637            Clip::rect(bounds),
638            1.0,
639            None,
640            fonts,
641            &mut |command, fonts| {
642                paint_scaled_command_with_offset(canvas, fonts, command, scale, offset);
643            },
644        );
645        fonts.trim_scratch();
646    }
647
648    #[allow(clippy::too_many_arguments)]
649    pub fn paint_transformed_viewport_with_fonts(
650        &mut self,
651        canvas: &mut Canvas<'_>,
652        fonts: &mut FontCtx,
653        width: u32,
654        height: u32,
655        viewport_x: i32,
656        viewport_y: i32,
657        scale: u32,
658        transform: PaintTransform,
659    ) {
660        let scale = scale.max(1);
661        let visual_scale = if transform.scale.is_finite() {
662            transform.scale.max(0.0)
663        } else {
664            0.0
665        };
666        if visual_scale <= 0.0 {
667            fonts.trim_scratch();
668            return;
669        }
670        if transform.is_identity() {
671            self.paint_viewport_with_fonts(
672                canvas, fonts, width, height, viewport_x, viewport_y, scale,
673            );
674            return;
675        }
676
677        let total_scale = scale as f32 * visual_scale;
678        let offset = PaintOffset {
679            x: scale_i32_f32(viewport_x, total_scale).saturating_sub(transform.translate_x),
680            y: scale_i32_f32(viewport_y, total_scale).saturating_sub(transform.translate_y),
681        };
682        let bounds = Bounds::new(0, 0, width, height);
683        Self::visit_layout(
684            self,
685            bounds,
686            Clip::rect(bounds),
687            1.0,
688            None,
689            fonts,
690            &mut |command, fonts| {
691                paint_scaled_f32_command_with_offset(canvas, fonts, command, total_scale, offset);
692            },
693        );
694        fonts.trim_scratch();
695    }
696
697    pub fn render(&mut self, canvas: &mut Canvas<'_>) {
698        self.paint(canvas);
699    }
700
701    fn visit_layout(
702        element: &Rect,
703        bounds: Bounds,
704        clip: Clip,
705        opacity: f32,
706        premeasured: Option<Size>,
707        fonts: &mut FontCtx,
708        visit: &mut dyn FnMut(PaintCommand<'_>, &mut FontCtx),
709    ) {
710        let measured = if element_needs_measure(element) {
711            premeasured
712                .unwrap_or_else(|| measure_element(element, fonts, bounds.width, bounds.height))
713        } else {
714            Size::default()
715        };
716        let width = resolve_length(
717            element.width,
718            bounds.width,
719            measured.width,
720            element.min_width,
721            element.max_width,
722        );
723        let height = resolve_length(
724            element.height,
725            bounds.height,
726            measured.height,
727            element.min_height,
728            element.max_height,
729        );
730        let rect = Bounds {
731            x: bounds.x,
732            y: bounds.y,
733            width,
734            height,
735        };
736        let Some(clip) = clip.intersect_bounds(rect) else {
737            return;
738        };
739        let opacity = multiply_opacity(opacity, element.style.opacity);
740        let radii = element_corner_radii(element);
741
742        if let Some(paint) = &element.style.background {
743            visit(
744                PaintCommand::Rect {
745                    rect,
746                    clip,
747                    opacity,
748                    paint,
749                    gradient: element.style.gradient,
750                    radii,
751                },
752                fonts,
753            );
754        }
755        if let Some(border) = &element.style.border {
756            visit(
757                PaintCommand::Border {
758                    rect,
759                    clip,
760                    opacity,
761                    paint: &border.color,
762                    gradient: border.gradient,
763                    widths: border_widths(border),
764                    radii,
765                },
766                fonts,
767            );
768        }
769        let content_rect = rect.inset(element.padding);
770        if let Some(content) = &element.content {
771            match content {
772                Content::Text(text) => visit(
773                    PaintCommand::Text {
774                        rect: content_rect,
775                        clip,
776                        opacity,
777                        text,
778                    },
779                    fonts,
780                ),
781                Content::RichText(text) => visit(
782                    PaintCommand::RichText {
783                        rect: content_rect,
784                        clip,
785                        opacity,
786                        text,
787                    },
788                    fonts,
789                ),
790                Content::Image(image) => visit(
791                    PaintCommand::Image {
792                        rect: content_rect,
793                        clip,
794                        opacity,
795                        image,
796                    },
797                    fonts,
798                ),
799            }
800        }
801
802        if element.children.is_empty() {
803            return;
804        }
805
806        let child_clip = match element.overflow {
807            Overflow::Clip => {
808                let Some(child_clip) =
809                    clip.with_rounded_rect(content_rect, content_clip_radii(element))
810                else {
811                    return;
812                };
813                child_clip
814            }
815            Overflow::Visible => clip,
816        };
817        layout_children(
818            element,
819            content_rect,
820            fonts,
821            |_, child, rect, measured, fonts| {
822                Self::visit_layout(
823                    child,
824                    rect,
825                    child_clip,
826                    opacity,
827                    Some(measured),
828                    fonts,
829                    visit,
830                );
831            },
832        );
833    }
834
835    #[allow(clippy::too_many_arguments)]
836    fn hit_test_layout(
837        element: &Rect,
838        bounds: Bounds,
839        clip: Clip,
840        premeasured: Option<Size>,
841        fonts: &mut FontCtx,
842        x: u32,
843        y: u32,
844        current_path: &mut Vec<usize>,
845        hit_path: &mut Vec<usize>,
846    ) -> Option<Bounds> {
847        let measured = if element_needs_measure(element) {
848            premeasured
849                .unwrap_or_else(|| measure_element(element, fonts, bounds.width, bounds.height))
850        } else {
851            Size::default()
852        };
853        let width = resolve_length(
854            element.width,
855            bounds.width,
856            measured.width,
857            element.min_width,
858            element.max_width,
859        );
860        let height = resolve_length(
861            element.height,
862            bounds.height,
863            measured.height,
864            element.min_height,
865            element.max_height,
866        );
867        let rect = Bounds {
868            x: bounds.x,
869            y: bounds.y,
870            width,
871            height,
872        };
873        let clip = clip.intersect_bounds(rect)?;
874        let content_rect = rect.inset(element.padding);
875        let child_clip = match element.overflow {
876            Overflow::Clip => clip.with_rounded_rect(content_rect, content_clip_radii(element))?,
877            Overflow::Visible => clip,
878        };
879
880        let mut hit = None;
881        layout_children(
882            element,
883            content_rect,
884            fonts,
885            |index, child, rect, measured, fonts| {
886                current_path.push(index);
887                if let Some(bounds) = Self::hit_test_layout(
888                    child,
889                    rect,
890                    child_clip,
891                    Some(measured),
892                    fonts,
893                    x,
894                    y,
895                    current_path,
896                    hit_path,
897                ) {
898                    hit = Some(bounds);
899                }
900                current_path.pop();
901            },
902        );
903
904        if let Some(bounds) = hit {
905            return Some(bounds);
906        }
907
908        let hit_clip = clip.with_rounded_rect(rect, element_corner_radii(element))?;
909        if hit_clip.contains(x, y) {
910            hit_path.clear();
911            hit_path.extend_from_slice(current_path);
912            Some(rect)
913        } else {
914            None
915        }
916    }
917}
918
919fn hit_point(x: f64, y: f64) -> Option<(u32, u32)> {
920    if !x.is_finite() || !y.is_finite() || x < 0.0 || y < 0.0 {
921        return None;
922    }
923    let x = x.floor();
924    let y = y.floor();
925    if x > u32::MAX as f64 || y > u32::MAX as f64 {
926        return None;
927    }
928    Some((x as u32, y as u32))
929}