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 pub left: i32,
21 pub top: i32,
23 pub right: i32,
25 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 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 pub left: f32,
342 pub top: f32,
344 pub right: f32,
346 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 !(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 self.left * 0.5 + self.right * 0.5
473 }
474
475 pub fn center_y(&self) -> f32 {
476 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 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 #[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 #[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 !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 !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
812impl 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}