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