skia_safe/core/
rect.rs

1use crate::{
2    interop,
3    prelude::*,
4    private::{
5        is_finite,
6        safe32::{sk32, sk64},
7    },
8    Contains, IPoint, ISize, IVector, Point, Size, Vector,
9};
10use skia_bindings::{self as sb, SkIRect, SkRect};
11use std::{
12    cmp::{max, min},
13    mem,
14};
15
16#[repr(C)]
17#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
18pub struct IRect {
19    /// The x coordinate of the rectangle's left edge.
20    pub left: i32,
21    /// The y coordinate of the rectangle's top edge.
22    pub top: i32,
23    /// The x coordinate of the rectangle's right edge.
24    pub right: i32,
25    /// The y coordinate of the rectangle's bottom edge.
26    pub bottom: i32,
27}
28
29native_transmutable!(SkIRect, IRect, irect_layout);
30
31impl AsRef<IRect> for IRect {
32    fn as_ref(&self) -> &IRect {
33        self
34    }
35}
36
37impl IRect {
38    pub const fn new(left: i32, top: i32, right: i32, bottom: i32) -> Self {
39        Self {
40            left,
41            top,
42            right,
43            bottom,
44        }
45    }
46
47    #[must_use]
48    pub const fn new_empty() -> Self {
49        Self::new(0, 0, 0, 0)
50    }
51
52    #[must_use]
53    pub fn from_wh(w: i32, h: i32) -> Self {
54        Self::from_size((w, h))
55    }
56
57    #[must_use]
58    pub fn from_size(size: impl Into<ISize>) -> Self {
59        let size = size.into();
60        Self::new(0, 0, size.width, size.height)
61    }
62
63    #[must_use]
64    pub fn from_pt_size(pt: impl Into<IPoint>, size: impl Into<ISize>) -> Self {
65        let pt = pt.into();
66        let size = size.into();
67        Self::from_xywh(pt.x, pt.y, size.width, size.height)
68    }
69
70    #[must_use]
71    pub const fn from_ltrb(l: i32, t: i32, r: i32, b: i32) -> Self {
72        Self::new(l, t, r, b)
73    }
74
75    #[must_use]
76    pub fn from_xywh(x: i32, y: i32, w: i32, h: i32) -> Self {
77        IRect {
78            left: x,
79            top: y,
80            right: sk32::sat_add(x, w),
81            bottom: sk32::sat_add(y, h),
82        }
83    }
84
85    pub const fn left(&self) -> i32 {
86        self.left
87    }
88
89    pub const fn top(&self) -> i32 {
90        self.top
91    }
92
93    pub const fn right(&self) -> i32 {
94        self.right
95    }
96
97    pub const fn bottom(&self) -> i32 {
98        self.bottom
99    }
100
101    pub const fn x(&self) -> i32 {
102        self.left
103    }
104
105    pub const fn y(&self) -> i32 {
106        self.top
107    }
108
109    pub const fn width(&self) -> i32 {
110        sk32::can_overflow_sub(self.right, self.left)
111    }
112
113    pub const fn height(&self) -> i32 {
114        sk32::can_overflow_sub(self.bottom, self.top)
115    }
116
117    pub const fn size(&self) -> ISize {
118        ISize::new(self.width(), self.height())
119    }
120
121    pub const fn width_64(&self) -> i64 {
122        self.right as i64 - self.left as i64
123    }
124
125    pub const fn height_64(&self) -> i64 {
126        self.bottom as i64 - self.top as i64
127    }
128
129    pub fn is_empty_64(&self) -> bool {
130        self.right <= self.left || self.bottom <= self.top
131    }
132
133    pub fn is_empty(&self) -> bool {
134        unsafe { sb::C_SkIRect_isEmpty(self.native()) }
135    }
136
137    pub fn set_empty(&mut self) {
138        *self = Self::new_empty()
139    }
140
141    pub fn set_ltrb(&mut self, left: i32, top: i32, right: i32, bottom: i32) {
142        *self = Self::new(left, top, right, bottom);
143    }
144
145    pub fn set_xywh(&mut self, x: i32, y: i32, w: i32, h: i32) {
146        *self = Self::from_xywh(x, y, w, h);
147    }
148
149    pub fn set_wh(&mut self, width: i32, height: i32) {
150        self.left = 0;
151        self.top = 0;
152        self.right = width;
153        self.bottom = height;
154    }
155
156    pub fn set_size(&mut self, size: impl Into<ISize>) {
157        let size = size.into();
158        self.left = 0;
159        self.top = 0;
160        self.right = size.width;
161        self.bottom = size.height;
162    }
163
164    #[must_use]
165    pub fn with_offset(&self, delta: impl Into<IVector>) -> Self {
166        let mut copied = *self;
167        copied.offset(delta);
168        copied
169    }
170
171    #[must_use]
172    pub fn with_inset(&self, delta: impl Into<IVector>) -> Self {
173        self.with_outset(-delta.into())
174    }
175
176    #[must_use]
177    pub fn with_outset(&self, delta: impl Into<IVector>) -> Self {
178        let delta = delta.into();
179        let (dx, dy) = (delta.x, delta.y);
180        IRect::new(
181            sk32::sat_sub(self.left, dx),
182            sk32::sat_sub(self.top, dy),
183            sk32::sat_add(self.right, dx),
184            sk32::sat_add(self.bottom, dy),
185        )
186    }
187
188    pub fn offset(&mut self, delta: impl Into<IPoint>) {
189        let delta = delta.into();
190        let (dx, dy) = (delta.x, delta.y);
191
192        self.left = sk32::sat_add(self.left, dx);
193        self.top = sk32::sat_add(self.top, dy);
194        self.right = sk32::sat_add(self.right, dx);
195        self.bottom = sk32::sat_add(self.bottom, dy);
196    }
197
198    pub fn offset_to(&mut self, new_p: impl Into<IPoint>) {
199        *self = self.with_offset_to(new_p)
200    }
201
202    #[must_use]
203    pub fn with_offset_to(&self, new_p: impl Into<IPoint>) -> Self {
204        let new_p = new_p.into();
205        let (new_x, new_y) = (new_p.x, new_p.y);
206
207        IRect::new(
208            sk64::pin_to_s32(i64::from(self.right) + i64::from(new_x) - i64::from(self.left)),
209            sk64::pin_to_s32(i64::from(self.bottom) + i64::from(new_y) - i64::from(self.top)),
210            new_x,
211            new_y,
212        )
213    }
214
215    pub fn inset(&mut self, delta: impl Into<IVector>) {
216        *self = self.with_inset(delta)
217    }
218
219    pub fn outset(&mut self, delta: impl Into<IVector>) {
220        *self = self.with_outset(delta)
221    }
222
223    #[must_use]
224    pub fn with_adjustment(&self, d_l: i32, d_t: i32, d_r: i32, d_b: i32) -> Self {
225        IRect::new(
226            sk32::sat_add(self.left, d_l),
227            sk32::sat_add(self.top, d_t),
228            sk32::sat_add(self.right, d_r),
229            sk32::sat_add(self.bottom, d_b),
230        )
231    }
232
233    pub fn adjust(&mut self, d_l: i32, d_t: i32, d_r: i32, d_b: i32) {
234        *self = self.with_adjustment(d_l, d_t, d_r, d_b)
235    }
236
237    // contains() is implemented through a trait below.
238
239    pub fn contains_no_empty_check(&self, r: &Self) -> bool {
240        debug_assert!(self.left < self.right && self.top < self.bottom);
241        debug_assert!(r.left < r.right && r.top < r.bottom);
242
243        self.left <= r.left && self.top <= r.top && self.right >= r.right && self.bottom >= r.bottom
244    }
245
246    #[must_use]
247    pub fn intersect(a: &Self, b: &Self) -> Option<Self> {
248        let mut r = Self::default();
249        unsafe { r.native_mut().intersect(a.native(), b.native()) }.if_true_some(r)
250    }
251
252    pub fn intersects(a: &Self, b: &Self) -> bool {
253        Self::intersect(a, b).is_some()
254    }
255
256    pub fn intersect_no_empty_check_(a: &Self, b: &Self) -> Option<Self> {
257        debug_assert!(!a.is_empty_64() && !b.is_empty_64());
258        let r = IRect::new(
259            max(a.left, b.left),
260            max(a.top, b.top),
261            min(a.right, b.right),
262            min(a.bottom, b.bottom),
263        );
264        r.is_empty().if_false_some(r)
265    }
266
267    pub fn join(a: &Self, b: &Self) -> Self {
268        let mut copied = *a;
269        unsafe { copied.native_mut().join(b.native()) }
270        copied
271    }
272
273    pub fn sort(&mut self) {
274        *self = self.sorted()
275    }
276
277    #[must_use]
278    pub fn sorted(&self) -> Self {
279        Self::new(
280            min(self.left, self.right),
281            min(self.top, self.bottom),
282            max(self.left, self.right),
283            max(self.top, self.bottom),
284        )
285    }
286
287    #[deprecated(since = "0.27.0", note = "removed without replacement")]
288    #[must_use]
289    pub fn empty() -> &'static Self {
290        &EMPTY_IRECT
291    }
292}
293
294pub const EMPTY_IRECT: IRect = IRect {
295    left: 0,
296    top: 0,
297    right: 0,
298    bottom: 0,
299};
300
301impl Contains<IPoint> for IRect {
302    fn contains(&self, other: IPoint) -> bool {
303        let (x, y) = (other.x, other.y);
304        x >= self.left && x < self.right && y >= self.top && y < self.bottom
305    }
306}
307
308impl Contains<&IRect> for IRect {
309    fn contains(&self, r: &IRect) -> bool {
310        !r.is_empty()
311            && !self.is_empty()
312            && self.left <= r.left
313            && self.top <= r.top
314            && self.right >= r.right
315            && self.bottom >= r.bottom
316    }
317}
318
319impl Contains<&Rect> for IRect {
320    fn contains(&self, other: &Rect) -> bool {
321        unsafe { sb::C_SkIRect_contains(self.native(), other.native()) }
322    }
323}
324
325impl Contains<IRect> for IRect {
326    fn contains(&self, other: IRect) -> bool {
327        self.contains(&other)
328    }
329}
330
331impl Contains<Rect> for IRect {
332    fn contains(&self, other: Rect) -> bool {
333        self.contains(&other)
334    }
335}
336
337#[repr(C)]
338#[derive(Copy, Clone, PartialEq, Default, Debug)]
339pub struct Rect {
340    /// The x coordinate of the rectangle's left edge.
341    pub left: f32,
342    /// The y coordinate of the rectangle's top edge.
343    pub top: f32,
344    /// The x coordinate of the rectangle's right edge.
345    pub right: f32,
346    /// The y coordinate of the rectangle's bottom edge.
347    pub bottom: f32,
348}
349
350native_transmutable!(SkRect, Rect, rect_layout);
351
352impl AsRef<Rect> for Rect {
353    fn as_ref(&self) -> &Rect {
354        self
355    }
356}
357
358impl Rect {
359    #[must_use]
360    pub fn new(left: f32, top: f32, right: f32, bottom: f32) -> Self {
361        Self {
362            left,
363            top,
364            right,
365            bottom,
366        }
367    }
368
369    pub fn new_empty() -> Self {
370        Self::new(0.0, 0.0, 0.0, 0.0)
371    }
372
373    #[must_use]
374    pub fn from_wh(w: f32, h: f32) -> Self {
375        Self::new(0.0, 0.0, w, h)
376    }
377
378    #[must_use]
379    pub fn from_iwh(w: i32, h: i32) -> Self {
380        Self::from_wh(w as f32, h as f32)
381    }
382
383    #[must_use]
384    pub fn from_size(size: impl Into<Size>) -> Self {
385        (Point::default(), size.into()).into()
386    }
387
388    #[must_use]
389    pub fn from_ltrb(l: f32, t: f32, b: f32, r: f32) -> Self {
390        Self::new(l, t, b, r)
391    }
392
393    #[must_use]
394    pub fn from_xywh(x: f32, y: f32, w: f32, h: f32) -> Self {
395        Self::new(x, y, x + w, y + h)
396    }
397
398    #[must_use]
399    pub fn from_point_and_size(p: impl Into<Point>, sz: impl Into<Size>) -> Self {
400        (p.into(), sz.into()).into()
401    }
402
403    #[must_use]
404    pub fn from_isize(isize: impl Into<ISize>) -> Self {
405        let isize = isize.into();
406        Self::from_iwh(isize.width, isize.height)
407    }
408
409    #[must_use]
410    pub fn from_irect(irect: impl AsRef<IRect>) -> Self {
411        let irect = irect.as_ref();
412        Self::new(
413            irect.left as f32,
414            irect.top as f32,
415            irect.right as f32,
416            irect.bottom as f32,
417        )
418    }
419
420    pub fn is_empty(&self) -> bool {
421        // We write it as the NOT of a non-empty rect, so we will return true if any values
422        // are NaN.
423        !(self.left < self.right && self.top < self.bottom)
424    }
425
426    pub fn is_sorted(&self) -> bool {
427        self.left <= self.right && self.top <= self.bottom
428    }
429
430    pub fn is_finite(&self) -> bool {
431        is_finite(&[self.left, self.top, self.right, self.bottom])
432    }
433
434    pub const fn x(&self) -> f32 {
435        self.left
436    }
437
438    pub const fn y(&self) -> f32 {
439        self.top
440    }
441
442    pub const fn left(&self) -> f32 {
443        self.left
444    }
445
446    pub const fn top(&self) -> f32 {
447        self.top
448    }
449
450    pub const fn right(&self) -> f32 {
451        self.right
452    }
453
454    pub const fn bottom(&self) -> f32 {
455        self.bottom
456    }
457
458    pub fn size(&self) -> Size {
459        (self.width(), self.height()).into()
460    }
461
462    pub fn width(&self) -> f32 {
463        self.native().fRight - self.native().fLeft
464    }
465
466    pub fn height(&self) -> f32 {
467        self.native().fBottom - self.native().fTop
468    }
469
470    pub fn center_x(&self) -> f32 {
471        // don't use (fLeft + fBottom) * 0.5 as that might overflow before the 0.5
472        self.left * 0.5 + self.right * 0.5
473    }
474
475    pub fn center_y(&self) -> f32 {
476        // don't use (fTop + fBottom) * 0.5 as that might overflow before the 0.5
477        self.top * 0.5 + self.bottom * 0.5
478    }
479
480    pub fn center(&self) -> Point {
481        Point::from((self.center_x(), self.center_y()))
482    }
483
484    pub fn to_quad(self) -> [Point; 4] {
485        let mut quad = [Point::default(); 4];
486        unsafe { self.native().toQuad(quad.native_mut().as_mut_ptr()) }
487        quad
488    }
489
490    pub fn set_empty(&mut self) {
491        *self = Self::new_empty()
492    }
493
494    // TODO: deprecate and rename to set() as soon the other set() variant is removed.
495    pub fn set_irect(&mut self, irect: impl AsRef<IRect>) {
496        *self = Self::from_irect(irect)
497    }
498
499    pub fn set_ltrb(&mut self, left: f32, top: f32, right: f32, bottom: f32) {
500        *self = Self::new(left, top, right, bottom)
501    }
502
503    pub fn set_bounds(&mut self, points: &[Point]) {
504        unsafe {
505            self.native_mut()
506                .setBoundsCheck(points.native().as_ptr(), points.len().try_into().unwrap());
507        }
508    }
509
510    pub fn set_bounds_check(&mut self, points: &[Point]) -> bool {
511        unsafe {
512            self.native_mut()
513                .setBoundsCheck(points.native().as_ptr(), points.len().try_into().unwrap())
514        }
515    }
516
517    pub fn set_bounds_no_check(&mut self, points: &[Point]) {
518        unsafe {
519            self.native_mut()
520                .setBoundsNoCheck(points.native().as_ptr(), points.len().try_into().unwrap())
521        }
522    }
523
524    pub fn set_bounds2(&mut self, p0: impl Into<Point>, p1: impl Into<Point>) {
525        let (p0, p1) = (p0.into(), p1.into());
526        self.left = p0.x.min(p1.x);
527        self.right = p0.x.max(p1.x);
528        self.top = p0.y.min(p1.y);
529        self.bottom = p0.y.max(p1.y);
530    }
531
532    pub fn from_bounds(points: &[Point]) -> Option<Self> {
533        let mut r = Self::default();
534        unsafe {
535            r.native_mut()
536                .setBoundsCheck(points.native().as_ptr(), points.len().try_into().unwrap())
537        }
538        .if_true_some(r)
539    }
540
541    pub fn set_xywh(&mut self, x: f32, y: f32, width: f32, height: f32) {
542        *self = Self::from_xywh(x, y, width, height)
543    }
544
545    pub fn set_wh(&mut self, w: f32, h: f32) {
546        *self = Self::from_wh(w, h)
547    }
548
549    pub fn set_iwh(&mut self, width: i32, height: i32) {
550        *self = Self::from_iwh(width, height)
551    }
552
553    #[must_use]
554    pub fn with_offset(&self, d: impl Into<Vector>) -> Self {
555        let d = d.into();
556        Self::new(
557            self.left + d.x,
558            self.top + d.y,
559            self.right + d.x,
560            self.bottom + d.y,
561        )
562    }
563
564    #[must_use]
565    pub fn with_inset(&self, d: impl Into<Vector>) -> Self {
566        let d = d.into();
567        Self::new(
568            self.left + d.x,
569            self.top + d.y,
570            self.right - d.x,
571            self.bottom - d.y,
572        )
573    }
574
575    #[must_use]
576    pub fn with_outset(&self, d: impl Into<Vector>) -> Self {
577        let d = d.into();
578        Self::new(
579            self.left - d.x,
580            self.top - d.y,
581            self.right + d.x,
582            self.bottom + d.y,
583        )
584    }
585
586    pub fn offset(&mut self, d: impl Into<Vector>) {
587        *self = self.with_offset(d)
588    }
589
590    pub fn offset_to(&mut self, new_p: impl Into<Point>) {
591        *self = self.with_offset_to(new_p)
592    }
593
594    #[must_use]
595    pub fn with_offset_to(&self, new_p: impl Into<Point>) -> Self {
596        let new_p = new_p.into();
597        Self::new(new_p.x, new_p.y, new_p.x - self.left, new_p.y - self.top)
598    }
599
600    pub fn inset(&mut self, d: impl Into<Vector>) {
601        *self = self.with_inset(d)
602    }
603
604    pub fn outset(&mut self, d: impl Into<Vector>) {
605        *self = self.with_outset(d)
606    }
607
608    pub fn intersect(&mut self, r: impl AsRef<Rect>) -> bool {
609        unsafe { self.native_mut().intersect(r.as_ref().native()) }
610    }
611
612    #[must_use]
613    pub fn intersect2(&mut self, a: impl AsRef<Rect>, b: impl AsRef<Rect>) -> bool {
614        unsafe {
615            self.native_mut()
616                .intersect1(a.as_ref().native(), b.as_ref().native())
617        }
618    }
619
620    pub fn intersects(&self, r: impl AsRef<Rect>) -> bool {
621        let r = r.as_ref();
622        Self::intersects_(
623            self.left,
624            self.top,
625            self.right,
626            self.bottom,
627            r.left,
628            r.top,
629            r.right,
630            r.bottom,
631        )
632    }
633
634    pub fn intersects2(a: impl AsRef<Rect>, b: impl AsRef<Rect>) -> bool {
635        a.as_ref().intersects(b)
636    }
637
638    #[allow(clippy::too_many_arguments)]
639    fn intersects_(al: f32, at: f32, ar: f32, ab: f32, bl: f32, bt: f32, br: f32, bb: f32) -> bool {
640        let l = al.max(bl);
641        let r = ar.min(br);
642        let t = at.max(bt);
643        let b = ab.min(bb);
644        l < r && t < b
645    }
646
647    pub fn join(&mut self, r: impl AsRef<Rect>) {
648        let r = r.as_ref();
649        unsafe { self.native_mut().join(r.native()) }
650    }
651
652    pub fn join2(a: impl AsRef<Rect>, b: impl AsRef<Rect>) -> Rect {
653        let mut result = *a.as_ref();
654        result.join(b);
655        result
656    }
657
658    pub fn join_non_empty_arg(&mut self, r: impl AsRef<Rect>) {
659        let r = r.as_ref();
660        debug_assert!(!r.is_empty());
661        if self.left >= self.right || self.top >= self.bottom {
662            *self = *r;
663        } else {
664            self.join_possibly_empty_rect(r);
665        }
666    }
667
668    pub fn join_possibly_empty_rect(&mut self, r: impl AsRef<Rect>) {
669        let r = r.as_ref();
670        self.left = self.left.min(r.left);
671        self.top = self.top.min(r.top);
672        self.right = self.right.max(r.right);
673        self.bottom = self.bottom.max(r.bottom);
674    }
675
676    // The set of contains() functions are defined as a trait below.
677
678    #[must_use]
679    pub fn round(&self) -> IRect {
680        let mut r = IRect::default();
681        unsafe { sb::C_SkRect_round(self.native(), r.native_mut()) };
682        r
683    }
684
685    // The functions round_out() are defined as a trait below.
686
687    #[must_use]
688    pub fn round_in(&self) -> IRect {
689        let mut r = IRect::default();
690        unsafe { sb::C_SkRect_roundIn(self.native(), r.native_mut()) };
691        r
692    }
693
694    pub fn sort(&mut self) {
695        if self.left > self.right {
696            mem::swap(&mut self.left, &mut self.right);
697        }
698
699        if self.top > self.bottom {
700            mem::swap(&mut self.top, &mut self.bottom);
701        }
702    }
703
704    #[must_use]
705    pub fn sorted(&self) -> Rect {
706        Rect::new(
707            self.left.min(self.right),
708            self.top.min(self.bottom),
709            self.left.max(self.right),
710            self.top.max(self.bottom),
711        )
712    }
713
714    pub fn as_scalars(&self) -> &[f32; 4] {
715        unsafe { transmute_ref(&self.left) }
716    }
717
718    pub fn dump(&self, as_hex: impl Into<Option<bool>>) {
719        unsafe { self.native().dump(as_hex.into().unwrap_or_default()) }
720    }
721
722    pub fn dump_to_string(&self, as_hex: bool) -> String {
723        let mut str = interop::String::default();
724        unsafe { sb::C_SkRect_dumpToString(self.native(), as_hex, str.native_mut()) }
725        str.to_string()
726    }
727
728    pub fn dump_hex(&self) {
729        self.dump(true)
730    }
731}
732
733impl Contains<Point> for Rect {
734    fn contains(&self, p: Point) -> bool {
735        self.contains(&p)
736    }
737}
738
739impl Contains<&Point> for Rect {
740    fn contains(&self, p: &Point) -> bool {
741        p.x >= self.left && p.x < self.right && p.y >= self.top && p.y < self.bottom
742    }
743}
744
745impl Contains<Rect> for Rect {
746    fn contains(&self, r: Rect) -> bool {
747        self.contains(&r)
748    }
749}
750
751impl Contains<&Rect> for Rect {
752    fn contains(&self, r: &Rect) -> bool {
753        // TODO: can we eliminate the this->is_empty check?
754        !r.is_empty()
755            && !self.is_empty()
756            && self.left <= r.left
757            && self.top <= r.top
758            && self.right >= r.right
759            && self.bottom >= r.bottom
760    }
761}
762
763impl Contains<IRect> for Rect {
764    fn contains(&self, r: IRect) -> bool {
765        self.contains(&r)
766    }
767}
768
769impl Contains<&IRect> for Rect {
770    fn contains(&self, r: &IRect) -> bool {
771        // TODO: can we eliminate the this->isEmpty check?
772        !r.is_empty()
773            && !self.is_empty()
774            && self.left <= r.left as f32
775            && self.top <= r.top as f32
776            && self.right >= r.right as f32
777            && self.bottom >= r.bottom as f32
778    }
779}
780
781#[test]
782fn contains_overloads_compile() {
783    let r = Rect::default();
784    r.contains(Point::default());
785    r.contains(Rect::default());
786    r.contains(IRect::default());
787}
788
789pub trait RoundOut<R> {
790    fn round_out(&self) -> R;
791}
792
793impl RoundOut<IRect> for Rect {
794    fn round_out(&self) -> IRect {
795        let mut r = IRect::default();
796        unsafe { sb::C_SkRect_roundOut(self.native(), r.native_mut()) };
797        r
798    }
799}
800
801impl RoundOut<Rect> for Rect {
802    fn round_out(&self) -> Rect {
803        Rect::new(
804            self.left.floor(),
805            self.top.floor(),
806            self.right.ceil(),
807            self.bottom.ceil(),
808        )
809    }
810}
811
812//
813// From
814//
815
816impl From<(IPoint, ISize)> for IRect {
817    fn from((point, size): (IPoint, ISize)) -> Self {
818        IRect::new(
819            point.x,
820            point.y,
821            point.x + size.width,
822            point.y + size.height,
823        )
824    }
825}
826
827impl From<(Point, Size)> for Rect {
828    fn from((point, size): (Point, Size)) -> Self {
829        Rect::new(
830            point.x,
831            point.y,
832            point.x + size.width,
833            point.y + size.height,
834        )
835    }
836}
837
838impl From<ISize> for Rect {
839    fn from(isize: ISize) -> Self {
840        Self::from_isize(isize)
841    }
842}
843impl From<IRect> for Rect {
844    fn from(irect: IRect) -> Self {
845        Self::from_irect(irect)
846    }
847}