Skip to main content

skia_safe/core/
rect.rs

1use std::{
2    cmp::{max, min},
3    mem,
4};
5
6use crate::{
7    Contains, IPoint, ISize, IVector, PathDirection, Point, Size, Vector, interop,
8    prelude::*,
9    private::{
10        is_finite,
11        safe32::{sk32, sk64},
12    },
13};
14use skia_bindings::{self as sb, SkIRect, SkRect};
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);
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()) }.then_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()).then_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    pub fn as_i32s(&self) -> &[i32] {
288        unsafe { safer::from_raw_parts(&self.left, 4) }
289    }
290
291    #[deprecated(since = "0.27.0", note = "removed without replacement")]
292    #[must_use]
293    pub fn empty() -> &'static Self {
294        &EMPTY_IRECT
295    }
296}
297
298pub const EMPTY_IRECT: IRect = IRect {
299    left: 0,
300    top: 0,
301    right: 0,
302    bottom: 0,
303};
304
305impl Contains<IPoint> for IRect {
306    fn contains(&self, other: IPoint) -> bool {
307        let (x, y) = (other.x, other.y);
308        x >= self.left && x < self.right && y >= self.top && y < self.bottom
309    }
310}
311
312impl Contains<&IRect> for IRect {
313    fn contains(&self, r: &IRect) -> bool {
314        !r.is_empty()
315            && !self.is_empty()
316            && self.left <= r.left
317            && self.top <= r.top
318            && self.right >= r.right
319            && self.bottom >= r.bottom
320    }
321}
322
323impl Contains<&Rect> for IRect {
324    fn contains(&self, other: &Rect) -> bool {
325        unsafe { sb::C_SkIRect_contains(self.native(), other.native()) }
326    }
327}
328
329impl Contains<IRect> for IRect {
330    fn contains(&self, other: IRect) -> bool {
331        self.contains(&other)
332    }
333}
334
335impl Contains<Rect> for IRect {
336    fn contains(&self, other: Rect) -> bool {
337        self.contains(&other)
338    }
339}
340
341#[repr(C)]
342#[derive(Copy, Clone, PartialEq, Default, Debug)]
343pub struct Rect {
344    /// The x coordinate of the rectangle's left edge.
345    pub left: f32,
346    /// The y coordinate of the rectangle's top edge.
347    pub top: f32,
348    /// The x coordinate of the rectangle's right edge.
349    pub right: f32,
350    /// The y coordinate of the rectangle's bottom edge.
351    pub bottom: f32,
352}
353
354native_transmutable!(SkRect, Rect);
355
356impl AsRef<Rect> for Rect {
357    fn as_ref(&self) -> &Rect {
358        self
359    }
360}
361
362impl Rect {
363    #[must_use]
364    pub fn new(left: f32, top: f32, right: f32, bottom: f32) -> Self {
365        Self {
366            left,
367            top,
368            right,
369            bottom,
370        }
371    }
372
373    pub fn new_empty() -> Self {
374        Self::new(0.0, 0.0, 0.0, 0.0)
375    }
376
377    #[must_use]
378    pub fn from_wh(w: f32, h: f32) -> Self {
379        Self::new(0.0, 0.0, w, h)
380    }
381
382    #[must_use]
383    pub fn from_iwh(w: i32, h: i32) -> Self {
384        Self::from_wh(w as f32, h as f32)
385    }
386
387    #[must_use]
388    pub fn from_size(size: impl Into<Size>) -> Self {
389        (Point::default(), size.into()).into()
390    }
391
392    #[must_use]
393    pub fn from_ltrb(l: f32, t: f32, r: f32, b: f32) -> Self {
394        Self::new(l, t, r, b)
395    }
396
397    #[must_use]
398    pub fn from_xywh(x: f32, y: f32, w: f32, h: f32) -> Self {
399        Self::new(x, y, x + w, y + h)
400    }
401
402    #[must_use]
403    pub fn from_point_and_size(p: impl Into<Point>, sz: impl Into<Size>) -> Self {
404        (p.into(), sz.into()).into()
405    }
406
407    #[must_use]
408    pub fn from_isize(isize: impl Into<ISize>) -> Self {
409        let isize = isize.into();
410        Self::from_iwh(isize.width, isize.height)
411    }
412
413    #[must_use]
414    pub fn from_irect(irect: impl AsRef<IRect>) -> Self {
415        let irect = irect.as_ref();
416        Self::new(
417            irect.left as f32,
418            irect.top as f32,
419            irect.right as f32,
420            irect.bottom as f32,
421        )
422    }
423
424    pub fn is_empty(&self) -> bool {
425        // We write it as the NOT of a non-empty rect, so we will return true if any values
426        // are NaN.
427        !(self.left < self.right && self.top < self.bottom)
428    }
429
430    pub fn is_sorted(&self) -> bool {
431        self.left <= self.right && self.top <= self.bottom
432    }
433
434    pub fn is_finite(&self) -> bool {
435        is_finite(&[self.left, self.top, self.right, self.bottom])
436    }
437
438    pub const fn x(&self) -> f32 {
439        self.left
440    }
441
442    pub const fn y(&self) -> f32 {
443        self.top
444    }
445
446    pub const fn left(&self) -> f32 {
447        self.left
448    }
449
450    pub const fn top(&self) -> f32 {
451        self.top
452    }
453
454    pub const fn right(&self) -> f32 {
455        self.right
456    }
457
458    pub const fn bottom(&self) -> f32 {
459        self.bottom
460    }
461
462    pub fn size(&self) -> Size {
463        (self.width(), self.height()).into()
464    }
465
466    pub fn width(&self) -> f32 {
467        self.native().fRight - self.native().fLeft
468    }
469
470    pub fn height(&self) -> f32 {
471        self.native().fBottom - self.native().fTop
472    }
473
474    pub fn center_x(&self) -> f32 {
475        // don't use (fLeft + fBottom) * 0.5 as that might overflow before the 0.5
476        self.left * 0.5 + self.right * 0.5
477    }
478
479    pub fn center_y(&self) -> f32 {
480        // don't use (fTop + fBottom) * 0.5 as that might overflow before the 0.5
481        self.top * 0.5 + self.bottom * 0.5
482    }
483
484    pub fn center(&self) -> Point {
485        Point::from((self.center_x(), self.center_y()))
486    }
487
488    pub fn tl(&self) -> Point {
489        Point::from((self.left, self.top))
490    }
491
492    pub fn tr(&self) -> Point {
493        Point::from((self.right, self.top))
494    }
495
496    pub fn bl(&self) -> Point {
497        Point::from((self.left, self.bottom))
498    }
499
500    pub fn br(&self) -> Point {
501        Point::from((self.right, self.bottom))
502    }
503
504    pub fn to_quad(&self, dir: impl Into<Option<PathDirection>>) -> [Point; 4] {
505        let mut pts = [Point::default(); 4];
506        self.copy_to_quad(&mut pts, dir);
507        pts
508    }
509
510    pub fn copy_to_quad(&self, pts: &mut [Point], dir: impl Into<Option<PathDirection>>) {
511        debug_assert!(pts.len() >= 4);
512        pts[0] = self.tl();
513        pts[2] = self.br();
514        match dir.into().unwrap_or(PathDirection::CW) {
515            PathDirection::CW => {
516                pts[1] = self.tr();
517                pts[3] = self.bl();
518            }
519            PathDirection::CCW => {
520                pts[1] = self.bl();
521                pts[3] = self.tr();
522            }
523        }
524    }
525
526    pub fn set_empty(&mut self) {
527        *self = Self::new_empty()
528    }
529
530    // TODO: deprecate and rename to set() as soon the other set() variant is removed.
531    pub fn set_irect(&mut self, irect: impl AsRef<IRect>) {
532        *self = Self::from_irect(irect)
533    }
534
535    pub fn set_ltrb(&mut self, left: f32, top: f32, right: f32, bottom: f32) {
536        *self = Self::new(left, top, right, bottom)
537    }
538
539    pub fn bounds(pts: &[Point]) -> Option<Rect> {
540        let mut bounds = Rect::default();
541        unsafe { sb::C_SkRect_Bounds(pts.native().as_ptr(), pts.len(), bounds.native_mut()) }
542            .then_some(bounds)
543    }
544
545    pub fn bounds_or_empty(pts: &[Point]) -> Rect {
546        Self::bounds(pts).unwrap_or_else(Self::new_empty)
547    }
548
549    pub fn set_bounds(&mut self, points: &[Point]) {
550        self.set_bounds_check(points);
551    }
552
553    pub fn set_bounds_check(&mut self, points: &[Point]) -> bool {
554        unsafe {
555            sb::C_SkRect_setBoundsCheck(self.native_mut(), points.native().as_ptr(), points.len())
556        }
557    }
558
559    pub fn set_bounds_no_check(&mut self, points: &[Point]) {
560        unsafe {
561            sb::C_SkRect_setBoundsNoCheck(self.native_mut(), points.native().as_ptr(), points.len())
562        }
563    }
564
565    pub fn set_bounds2(&mut self, p0: impl Into<Point>, p1: impl Into<Point>) {
566        let (p0, p1) = (p0.into(), p1.into());
567        self.left = p0.x.min(p1.x);
568        self.right = p0.x.max(p1.x);
569        self.top = p0.y.min(p1.y);
570        self.bottom = p0.y.max(p1.y);
571    }
572
573    pub fn from_bounds(points: &[Point]) -> Option<Self> {
574        let mut r = Self::default();
575        r.set_bounds_check(points).then_some(r)
576    }
577
578    pub fn set_xywh(&mut self, x: f32, y: f32, width: f32, height: f32) {
579        *self = Self::from_xywh(x, y, width, height)
580    }
581
582    pub fn set_wh(&mut self, w: f32, h: f32) {
583        *self = Self::from_wh(w, h)
584    }
585
586    pub fn set_iwh(&mut self, width: i32, height: i32) {
587        *self = Self::from_iwh(width, height)
588    }
589
590    #[must_use]
591    pub fn with_offset(&self, d: impl Into<Vector>) -> Self {
592        let d = d.into();
593        Self::new(
594            self.left + d.x,
595            self.top + d.y,
596            self.right + d.x,
597            self.bottom + d.y,
598        )
599    }
600
601    #[must_use]
602    pub fn with_inset(&self, d: impl Into<Vector>) -> Self {
603        let d = d.into();
604        Self::new(
605            self.left + d.x,
606            self.top + d.y,
607            self.right - d.x,
608            self.bottom - d.y,
609        )
610    }
611
612    #[must_use]
613    pub fn with_outset(&self, d: impl Into<Vector>) -> Self {
614        let d = d.into();
615        Self::new(
616            self.left - d.x,
617            self.top - d.y,
618            self.right + d.x,
619            self.bottom + d.y,
620        )
621    }
622
623    pub fn offset(&mut self, d: impl Into<Vector>) {
624        *self = self.with_offset(d)
625    }
626
627    pub fn offset_to(&mut self, new_p: impl Into<Point>) {
628        *self = self.with_offset_to(new_p)
629    }
630
631    #[must_use]
632    pub fn with_offset_to(&self, new_p: impl Into<Point>) -> Self {
633        let new_p = new_p.into();
634        Self::new(new_p.x, new_p.y, new_p.x - self.left, new_p.y - self.top)
635    }
636
637    pub fn inset(&mut self, d: impl Into<Vector>) {
638        *self = self.with_inset(d)
639    }
640
641    pub fn outset(&mut self, d: impl Into<Vector>) {
642        *self = self.with_outset(d)
643    }
644
645    pub fn intersect(&mut self, r: impl AsRef<Rect>) -> bool {
646        unsafe { self.native_mut().intersect(r.as_ref().native()) }
647    }
648
649    #[must_use]
650    pub fn intersect2(&mut self, a: impl AsRef<Rect>, b: impl AsRef<Rect>) -> bool {
651        unsafe {
652            self.native_mut()
653                .intersect1(a.as_ref().native(), b.as_ref().native())
654        }
655    }
656
657    pub fn intersects(&self, r: impl AsRef<Rect>) -> bool {
658        let r = r.as_ref();
659        Self::intersects_(
660            self.left,
661            self.top,
662            self.right,
663            self.bottom,
664            r.left,
665            r.top,
666            r.right,
667            r.bottom,
668        )
669    }
670
671    pub fn intersects2(a: impl AsRef<Rect>, b: impl AsRef<Rect>) -> bool {
672        a.as_ref().intersects(b)
673    }
674
675    #[allow(clippy::too_many_arguments)]
676    fn intersects_(al: f32, at: f32, ar: f32, ab: f32, bl: f32, bt: f32, br: f32, bb: f32) -> bool {
677        let l = al.max(bl);
678        let r = ar.min(br);
679        let t = at.max(bt);
680        let b = ab.min(bb);
681        l < r && t < b
682    }
683
684    pub fn join(&mut self, r: impl AsRef<Rect>) {
685        let r = r.as_ref();
686        unsafe { self.native_mut().join(r.native()) }
687    }
688
689    pub fn join2(a: impl AsRef<Rect>, b: impl AsRef<Rect>) -> Rect {
690        let mut result = *a.as_ref();
691        result.join(b);
692        result
693    }
694
695    pub fn join_non_empty_arg(&mut self, r: impl AsRef<Rect>) {
696        let r = r.as_ref();
697        debug_assert!(!r.is_empty());
698        if self.left >= self.right || self.top >= self.bottom {
699            *self = *r;
700        } else {
701            self.join_possibly_empty_rect(r);
702        }
703    }
704
705    pub fn join_possibly_empty_rect(&mut self, r: impl AsRef<Rect>) {
706        let r = r.as_ref();
707        self.left = self.left.min(r.left);
708        self.top = self.top.min(r.top);
709        self.right = self.right.max(r.right);
710        self.bottom = self.bottom.max(r.bottom);
711    }
712
713    // The set of contains() functions are defined as a trait below.
714
715    #[must_use]
716    pub fn round(&self) -> IRect {
717        let mut r = IRect::default();
718        unsafe { sb::C_SkRect_round(self.native(), r.native_mut()) };
719        r
720    }
721
722    // The functions round_out() are defined as a trait below.
723
724    #[must_use]
725    pub fn round_in(&self) -> IRect {
726        let mut r = IRect::default();
727        unsafe { sb::C_SkRect_roundIn(self.native(), r.native_mut()) };
728        r
729    }
730
731    pub fn sort(&mut self) {
732        if self.left > self.right {
733            mem::swap(&mut self.left, &mut self.right);
734        }
735
736        if self.top > self.bottom {
737            mem::swap(&mut self.top, &mut self.bottom);
738        }
739    }
740
741    #[must_use]
742    pub fn sorted(&self) -> Rect {
743        Rect::new(
744            self.left.min(self.right),
745            self.top.min(self.bottom),
746            self.left.max(self.right),
747            self.top.max(self.bottom),
748        )
749    }
750
751    pub fn as_scalars(&self) -> &[f32; 4] {
752        unsafe { transmute_ref(&self.left) }
753    }
754
755    pub fn dump(&self, as_hex: impl Into<Option<bool>>) {
756        unsafe { self.native().dump(as_hex.into().unwrap_or_default()) }
757    }
758
759    pub fn dump_to_string(&self, as_hex: bool) -> String {
760        let mut str = interop::String::default();
761        unsafe { sb::C_SkRect_dumpToString(self.native(), as_hex, str.native_mut()) }
762        str.to_string()
763    }
764
765    pub fn dump_hex(&self) {
766        self.dump(true)
767    }
768}
769
770impl Contains<Point> for Rect {
771    fn contains(&self, p: Point) -> bool {
772        self.contains(&p)
773    }
774}
775
776impl Contains<&Point> for Rect {
777    fn contains(&self, p: &Point) -> bool {
778        p.x >= self.left && p.x < self.right && p.y >= self.top && p.y < self.bottom
779    }
780}
781
782impl Contains<Rect> for Rect {
783    fn contains(&self, r: Rect) -> bool {
784        self.contains(&r)
785    }
786}
787
788impl Contains<&Rect> for Rect {
789    fn contains(&self, r: &Rect) -> bool {
790        // TODO: can we eliminate the this->is_empty check?
791        !r.is_empty()
792            && !self.is_empty()
793            && self.left <= r.left
794            && self.top <= r.top
795            && self.right >= r.right
796            && self.bottom >= r.bottom
797    }
798}
799
800impl Contains<IRect> for Rect {
801    fn contains(&self, r: IRect) -> bool {
802        self.contains(&r)
803    }
804}
805
806impl Contains<&IRect> for Rect {
807    fn contains(&self, r: &IRect) -> bool {
808        // TODO: can we eliminate the this->isEmpty check?
809        !r.is_empty()
810            && !self.is_empty()
811            && self.left <= r.left as f32
812            && self.top <= r.top as f32
813            && self.right >= r.right as f32
814            && self.bottom >= r.bottom as f32
815    }
816}
817
818#[test]
819fn contains_overloads_compile() {
820    let r = Rect::default();
821    r.contains(Point::default());
822    r.contains(Rect::default());
823    r.contains(IRect::default());
824}
825
826pub trait RoundOut<R> {
827    fn round_out(&self) -> R;
828}
829
830impl RoundOut<IRect> for Rect {
831    fn round_out(&self) -> IRect {
832        let mut r = IRect::default();
833        unsafe { sb::C_SkRect_roundOut(self.native(), r.native_mut()) };
834        r
835    }
836}
837
838impl RoundOut<Rect> for Rect {
839    fn round_out(&self) -> Rect {
840        Rect::new(
841            self.left.floor(),
842            self.top.floor(),
843            self.right.ceil(),
844            self.bottom.ceil(),
845        )
846    }
847}
848
849//
850// From
851//
852
853impl From<(IPoint, ISize)> for IRect {
854    fn from((point, size): (IPoint, ISize)) -> Self {
855        IRect::new(
856            point.x,
857            point.y,
858            point.x + size.width,
859            point.y + size.height,
860        )
861    }
862}
863
864impl From<(Point, Size)> for Rect {
865    fn from((point, size): (Point, Size)) -> Self {
866        Rect::new(
867            point.x,
868            point.y,
869            point.x + size.width,
870            point.y + size.height,
871        )
872    }
873}
874
875impl From<ISize> for Rect {
876    fn from(isize: ISize) -> Self {
877        Self::from_isize(isize)
878    }
879}
880impl From<IRect> for Rect {
881    fn from(irect: IRect) -> Self {
882        Self::from_irect(irect)
883    }
884}