skia_safe/core/
rect.rs

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