1use core::convert::TryFrom;
8
9use tiny_skia_path::{IntRect, IntSize, Rect};
10
11use crate::LengthU32;
12
13#[allow(missing_docs)]
21#[derive(Copy, Clone, PartialEq, Debug)]
22pub struct ScreenIntRect {
23 x: u32,
24 y: u32,
25 width: LengthU32,
26 height: LengthU32,
27}
28
29impl ScreenIntRect {
30 pub fn from_xywh(x: u32, y: u32, width: u32, height: u32) -> Option<Self> {
32 i32::try_from(x).ok()?;
33 i32::try_from(y).ok()?;
34 i32::try_from(width).ok()?;
35 i32::try_from(height).ok()?;
36
37 x.checked_add(width)?;
38 y.checked_add(height)?;
39
40 let width = LengthU32::new(width)?;
41 let height = LengthU32::new(height)?;
42
43 Some(ScreenIntRect {
44 x,
45 y,
46 width,
47 height,
48 })
49 }
50
51 pub const fn from_xywh_safe(x: u32, y: u32, width: LengthU32, height: LengthU32) -> Self {
53 ScreenIntRect {
54 x,
55 y,
56 width,
57 height,
58 }
59 }
60
61 pub fn x(&self) -> u32 {
63 self.x
64 }
65
66 pub fn y(&self) -> u32 {
68 self.y
69 }
70
71 pub fn width(&self) -> u32 {
73 self.width.get()
74 }
75
76 pub fn height(&self) -> u32 {
78 self.height.get()
79 }
80
81 pub fn width_safe(&self) -> LengthU32 {
83 self.width
84 }
85
86 pub fn left(&self) -> u32 {
88 self.x
89 }
90
91 pub fn top(&self) -> u32 {
93 self.y
94 }
95
96 pub fn right(&self) -> u32 {
100 self.x + self.width.get()
102 }
103
104 pub fn bottom(&self) -> u32 {
108 self.y + self.height.get()
110 }
111
112 pub fn size(&self) -> IntSize {
114 IntSize::from_wh(self.width(), self.height()).unwrap()
115 }
116
117 pub fn contains(&self, other: &Self) -> bool {
119 self.x <= other.x
120 && self.y <= other.y
121 && self.right() >= other.right()
122 && self.bottom() >= other.bottom()
123 }
124
125 pub fn to_int_rect(&self) -> IntRect {
127 IntRect::from_xywh(
129 self.x as i32,
130 self.y as i32,
131 self.width.get(),
132 self.height.get(),
133 )
134 .unwrap()
135 }
136
137 pub fn to_rect(&self) -> Rect {
139 Rect::from_ltrb(
142 self.x as f32,
143 self.y as f32,
144 self.x as f32 + self.width.get() as f32,
145 self.y as f32 + self.height.get() as f32,
146 )
147 .unwrap()
148 }
149}
150
151#[cfg(test)]
152mod screen_int_rect_tests {
153 use super::*;
154
155 #[test]
156 fn tests() {
157 assert_eq!(ScreenIntRect::from_xywh(0, 0, 0, 0), None);
158 assert_eq!(ScreenIntRect::from_xywh(0, 0, 1, 0), None);
159 assert_eq!(ScreenIntRect::from_xywh(0, 0, 0, 1), None);
160
161 assert_eq!(ScreenIntRect::from_xywh(0, 0, u32::MAX, u32::MAX), None);
162 assert_eq!(ScreenIntRect::from_xywh(0, 0, 1, u32::MAX), None);
163 assert_eq!(ScreenIntRect::from_xywh(0, 0, u32::MAX, 1), None);
164
165 assert_eq!(ScreenIntRect::from_xywh(u32::MAX, 0, 1, 1), None);
166 assert_eq!(ScreenIntRect::from_xywh(0, u32::MAX, 1, 1), None);
167
168 assert_eq!(
169 ScreenIntRect::from_xywh(u32::MAX, u32::MAX, u32::MAX, u32::MAX),
170 None
171 );
172
173 let r = ScreenIntRect::from_xywh(1, 2, 3, 4).unwrap();
174 assert_eq!(r.x(), 1);
175 assert_eq!(r.y(), 2);
176 assert_eq!(r.width(), 3);
177 assert_eq!(r.height(), 4);
178 assert_eq!(r.right(), 4);
179 assert_eq!(r.bottom(), 6);
180 }
181}
182
183pub trait IntSizeExt {
184 fn to_screen_int_rect(&self, x: u32, y: u32) -> ScreenIntRect;
186}
187
188impl IntSizeExt for IntSize {
189 fn to_screen_int_rect(&self, x: u32, y: u32) -> ScreenIntRect {
190 ScreenIntRect::from_xywh(x, y, self.width(), self.height()).unwrap()
191 }
192}
193
194pub trait IntRectExt {
195 fn to_screen_int_rect(&self) -> Option<ScreenIntRect>;
202}
203
204impl IntRectExt for IntRect {
205 fn to_screen_int_rect(&self) -> Option<ScreenIntRect> {
206 let x = u32::try_from(self.x()).ok()?;
207 let y = u32::try_from(self.y()).ok()?;
208 ScreenIntRect::from_xywh(x, y, self.width(), self.height())
209 }
210}