1 | /* |
2 | * Copyright 2006 The Android Open Source Project |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #ifndef SkRect_DEFINED |
9 | #define SkRect_DEFINED |
10 | |
11 | #include "include/core/SkPoint.h" |
12 | #include "include/core/SkSize.h" |
13 | #include "include/core/SkTypes.h" |
14 | #include "include/private/base/SkFloatingPoint.h" |
15 | #include "include/private/base/SkSafe32.h" |
16 | #include "include/private/base/SkTFitsIn.h" |
17 | |
18 | #include <algorithm> |
19 | #include <cmath> |
20 | #include <cstdint> |
21 | #include <string> |
22 | |
23 | struct SkRect; |
24 | |
25 | /** \struct SkIRect |
26 | SkIRect holds four 32-bit integer coordinates describing the upper and |
27 | lower bounds of a rectangle. SkIRect may be created from outer bounds or |
28 | from position, width, and height. SkIRect describes an area; if its right |
29 | is less than or equal to its left, or if its bottom is less than or equal to |
30 | its top, it is considered empty. |
31 | */ |
32 | struct SK_API SkIRect { |
33 | int32_t fLeft = 0; //!< smaller x-axis bounds |
34 | int32_t fTop = 0; //!< smaller y-axis bounds |
35 | int32_t fRight = 0; //!< larger x-axis bounds |
36 | int32_t fBottom = 0; //!< larger y-axis bounds |
37 | |
38 | /** Returns constructed SkIRect set to (0, 0, 0, 0). |
39 | Many other rectangles are empty; if left is equal to or greater than right, |
40 | or if top is equal to or greater than bottom. Setting all members to zero |
41 | is a convenience, but does not designate a special empty rectangle. |
42 | |
43 | @return bounds (0, 0, 0, 0) |
44 | */ |
45 | [[nodiscard]] static constexpr SkIRect MakeEmpty() { |
46 | return SkIRect{.fLeft: 0, .fTop: 0, .fRight: 0, .fBottom: 0}; |
47 | } |
48 | |
49 | /** Returns constructed SkIRect set to (0, 0, w, h). Does not validate input; w or h |
50 | may be negative. |
51 | |
52 | @param w width of constructed SkIRect |
53 | @param h height of constructed SkIRect |
54 | @return bounds (0, 0, w, h) |
55 | */ |
56 | [[nodiscard]] static constexpr SkIRect MakeWH(int32_t w, int32_t h) { |
57 | return SkIRect{.fLeft: 0, .fTop: 0, .fRight: w, .fBottom: h}; |
58 | } |
59 | |
60 | /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). |
61 | Does not validate input; size.width() or size.height() may be negative. |
62 | |
63 | @param size values for SkIRect width and height |
64 | @return bounds (0, 0, size.width(), size.height()) |
65 | */ |
66 | [[nodiscard]] static constexpr SkIRect MakeSize(const SkISize& size) { |
67 | return SkIRect{.fLeft: 0, .fTop: 0, .fRight: size.fWidth, .fBottom: size.fHeight}; |
68 | } |
69 | |
70 | /** Returns constructed SkIRect set to (pt.x(), pt.y(), pt.x() + size.width(), |
71 | pt.y() + size.height()). Does not validate input; size.width() or size.height() may be |
72 | negative. |
73 | |
74 | @param pt values for SkIRect fLeft and fTop |
75 | @param size values for SkIRect width and height |
76 | @return bounds at pt with width and height of size |
77 | */ |
78 | [[nodiscard]] static constexpr SkIRect MakePtSize(SkIPoint pt, SkISize size) { |
79 | return MakeXYWH(x: pt.x(), y: pt.y(), w: size.width(), h: size.height()); |
80 | } |
81 | |
82 | /** Returns constructed SkIRect set to (l, t, r, b). Does not sort input; SkIRect may |
83 | result in fLeft greater than fRight, or fTop greater than fBottom. |
84 | |
85 | @param l integer stored in fLeft |
86 | @param t integer stored in fTop |
87 | @param r integer stored in fRight |
88 | @param b integer stored in fBottom |
89 | @return bounds (l, t, r, b) |
90 | */ |
91 | [[nodiscard]] static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) { |
92 | return SkIRect{.fLeft: l, .fTop: t, .fRight: r, .fBottom: b}; |
93 | } |
94 | |
95 | /** Returns constructed SkIRect set to: (x, y, x + w, y + h). |
96 | Does not validate input; w or h may be negative. |
97 | |
98 | @param x stored in fLeft |
99 | @param y stored in fTop |
100 | @param w added to x and stored in fRight |
101 | @param h added to y and stored in fBottom |
102 | @return bounds at (x, y) with width w and height h |
103 | */ |
104 | [[nodiscard]] static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) { |
105 | return { .fLeft: x, .fTop: y, .fRight: Sk32_sat_add(a: x, b: w), .fBottom: Sk32_sat_add(a: y, b: h) }; |
106 | } |
107 | |
108 | /** Returns left edge of SkIRect, if sorted. |
109 | Call sort() to reverse fLeft and fRight if needed. |
110 | |
111 | @return fLeft |
112 | */ |
113 | constexpr int32_t left() const { return fLeft; } |
114 | |
115 | /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, |
116 | and sort() to reverse fTop and fBottom if needed. |
117 | |
118 | @return fTop |
119 | */ |
120 | constexpr int32_t top() const { return fTop; } |
121 | |
122 | /** Returns right edge of SkIRect, if sorted. |
123 | Call sort() to reverse fLeft and fRight if needed. |
124 | |
125 | @return fRight |
126 | */ |
127 | constexpr int32_t right() const { return fRight; } |
128 | |
129 | /** Returns bottom edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, |
130 | and sort() to reverse fTop and fBottom if needed. |
131 | |
132 | @return fBottom |
133 | */ |
134 | constexpr int32_t bottom() const { return fBottom; } |
135 | |
136 | /** Returns left edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, |
137 | and sort() to reverse fLeft and fRight if needed. |
138 | |
139 | @return fLeft |
140 | */ |
141 | constexpr int32_t x() const { return fLeft; } |
142 | |
143 | /** Returns top edge of SkIRect, if sorted. Call isEmpty() to see if SkIRect may be invalid, |
144 | and sort() to reverse fTop and fBottom if needed. |
145 | |
146 | @return fTop |
147 | */ |
148 | constexpr int32_t y() const { return fTop; } |
149 | |
150 | // Experimental |
151 | constexpr SkIPoint topLeft() const { return {.fX: fLeft, .fY: fTop}; } |
152 | |
153 | /** Returns span on the x-axis. This does not check if SkIRect is sorted, or if |
154 | result fits in 32-bit signed integer; result may be negative. |
155 | |
156 | @return fRight minus fLeft |
157 | */ |
158 | constexpr int32_t width() const { return Sk32_can_overflow_sub(a: fRight, b: fLeft); } |
159 | |
160 | /** Returns span on the y-axis. This does not check if SkIRect is sorted, or if |
161 | result fits in 32-bit signed integer; result may be negative. |
162 | |
163 | @return fBottom minus fTop |
164 | */ |
165 | constexpr int32_t height() const { return Sk32_can_overflow_sub(a: fBottom, b: fTop); } |
166 | |
167 | /** Returns spans on the x-axis and y-axis. This does not check if SkIRect is sorted, |
168 | or if result fits in 32-bit signed integer; result may be negative. |
169 | |
170 | @return SkISize (width, height) |
171 | */ |
172 | constexpr SkISize size() const { return SkISize::Make(w: this->width(), h: this->height()); } |
173 | |
174 | /** Returns span on the x-axis. This does not check if SkIRect is sorted, so the |
175 | result may be negative. This is safer than calling width() since width() might |
176 | overflow in its calculation. |
177 | |
178 | @return fRight minus fLeft cast to int64_t |
179 | */ |
180 | constexpr int64_t width64() const { return (int64_t)fRight - (int64_t)fLeft; } |
181 | |
182 | /** Returns span on the y-axis. This does not check if SkIRect is sorted, so the |
183 | result may be negative. This is safer than calling height() since height() might |
184 | overflow in its calculation. |
185 | |
186 | @return fBottom minus fTop cast to int64_t |
187 | */ |
188 | constexpr int64_t height64() const { return (int64_t)fBottom - (int64_t)fTop; } |
189 | |
190 | /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal |
191 | to or greater than fBottom. Call sort() to reverse rectangles with negative |
192 | width64() or height64(). |
193 | |
194 | @return true if width64() or height64() are zero or negative |
195 | */ |
196 | bool isEmpty64() const { return fRight <= fLeft || fBottom <= fTop; } |
197 | |
198 | /** Returns true if width() or height() are zero or negative. |
199 | |
200 | @return true if width() or height() are zero or negative |
201 | */ |
202 | bool isEmpty() const { |
203 | int64_t w = this->width64(); |
204 | int64_t h = this->height64(); |
205 | if (w <= 0 || h <= 0) { |
206 | return true; |
207 | } |
208 | // Return true if either exceeds int32_t |
209 | return !SkTFitsIn<int32_t>(src: w | h); |
210 | } |
211 | |
212 | /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are |
213 | identical to corresponding members in b. |
214 | |
215 | @param a SkIRect to compare |
216 | @param b SkIRect to compare |
217 | @return true if members are equal |
218 | */ |
219 | friend bool operator==(const SkIRect& a, const SkIRect& b) { |
220 | return a.fLeft == b.fLeft && a.fTop == b.fTop && |
221 | a.fRight == b.fRight && a.fBottom == b.fBottom; |
222 | } |
223 | |
224 | /** Returns true if any member in a: fLeft, fTop, fRight, and fBottom; is not |
225 | identical to the corresponding member in b. |
226 | |
227 | @param a SkIRect to compare |
228 | @param b SkIRect to compare |
229 | @return true if members are not equal |
230 | */ |
231 | friend bool operator!=(const SkIRect& a, const SkIRect& b) { |
232 | return a.fLeft != b.fLeft || a.fTop != b.fTop || |
233 | a.fRight != b.fRight || a.fBottom != b.fBottom; |
234 | } |
235 | |
236 | /** Sets SkIRect to (0, 0, 0, 0). |
237 | |
238 | Many other rectangles are empty; if left is equal to or greater than right, |
239 | or if top is equal to or greater than bottom. Setting all members to zero |
240 | is a convenience, but does not designate a special empty rectangle. |
241 | */ |
242 | void setEmpty() { memset(s: this, c: 0, n: sizeof(*this)); } |
243 | |
244 | /** Sets SkIRect to (left, top, right, bottom). |
245 | left and right are not sorted; left is not necessarily less than right. |
246 | top and bottom are not sorted; top is not necessarily less than bottom. |
247 | |
248 | @param left stored in fLeft |
249 | @param top stored in fTop |
250 | @param right stored in fRight |
251 | @param bottom stored in fBottom |
252 | */ |
253 | void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) { |
254 | fLeft = left; |
255 | fTop = top; |
256 | fRight = right; |
257 | fBottom = bottom; |
258 | } |
259 | |
260 | /** Sets SkIRect to: (x, y, x + width, y + height). |
261 | Does not validate input; width or height may be negative. |
262 | |
263 | @param x stored in fLeft |
264 | @param y stored in fTop |
265 | @param width added to x and stored in fRight |
266 | @param height added to y and stored in fBottom |
267 | */ |
268 | void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) { |
269 | fLeft = x; |
270 | fTop = y; |
271 | fRight = Sk32_sat_add(a: x, b: width); |
272 | fBottom = Sk32_sat_add(a: y, b: height); |
273 | } |
274 | |
275 | void setWH(int32_t width, int32_t height) { |
276 | fLeft = 0; |
277 | fTop = 0; |
278 | fRight = width; |
279 | fBottom = height; |
280 | } |
281 | |
282 | void setSize(SkISize size) { |
283 | fLeft = 0; |
284 | fTop = 0; |
285 | fRight = size.width(); |
286 | fBottom = size.height(); |
287 | } |
288 | |
289 | /** Returns SkIRect offset by (dx, dy). |
290 | |
291 | If dx is negative, SkIRect returned is moved to the left. |
292 | If dx is positive, SkIRect returned is moved to the right. |
293 | If dy is negative, SkIRect returned is moved upward. |
294 | If dy is positive, SkIRect returned is moved downward. |
295 | |
296 | @param dx offset added to fLeft and fRight |
297 | @param dy offset added to fTop and fBottom |
298 | @return SkIRect offset by dx and dy, with original width and height |
299 | */ |
300 | constexpr SkIRect makeOffset(int32_t dx, int32_t dy) const { |
301 | return { |
302 | .fLeft: Sk32_sat_add(a: fLeft, b: dx), .fTop: Sk32_sat_add(a: fTop, b: dy), |
303 | .fRight: Sk32_sat_add(a: fRight, b: dx), .fBottom: Sk32_sat_add(a: fBottom, b: dy), |
304 | }; |
305 | } |
306 | |
307 | /** Returns SkIRect offset by (offset.x(), offset.y()). |
308 | |
309 | If offset.x() is negative, SkIRect returned is moved to the left. |
310 | If offset.x() is positive, SkIRect returned is moved to the right. |
311 | If offset.y() is negative, SkIRect returned is moved upward. |
312 | If offset.y() is positive, SkIRect returned is moved downward. |
313 | |
314 | @param offset translation vector |
315 | @return SkIRect translated by offset, with original width and height |
316 | */ |
317 | constexpr SkIRect makeOffset(SkIVector offset) const { |
318 | return this->makeOffset(dx: offset.x(), dy: offset.y()); |
319 | } |
320 | |
321 | /** Returns SkIRect, inset by (dx, dy). |
322 | |
323 | If dx is negative, SkIRect returned is wider. |
324 | If dx is positive, SkIRect returned is narrower. |
325 | If dy is negative, SkIRect returned is taller. |
326 | If dy is positive, SkIRect returned is shorter. |
327 | |
328 | @param dx offset added to fLeft and subtracted from fRight |
329 | @param dy offset added to fTop and subtracted from fBottom |
330 | @return SkIRect inset symmetrically left and right, top and bottom |
331 | */ |
332 | SkIRect makeInset(int32_t dx, int32_t dy) const { |
333 | return { |
334 | .fLeft: Sk32_sat_add(a: fLeft, b: dx), .fTop: Sk32_sat_add(a: fTop, b: dy), |
335 | .fRight: Sk32_sat_sub(a: fRight, b: dx), .fBottom: Sk32_sat_sub(a: fBottom, b: dy), |
336 | }; |
337 | } |
338 | |
339 | /** Returns SkIRect, outset by (dx, dy). |
340 | |
341 | If dx is negative, SkIRect returned is narrower. |
342 | If dx is positive, SkIRect returned is wider. |
343 | If dy is negative, SkIRect returned is shorter. |
344 | If dy is positive, SkIRect returned is taller. |
345 | |
346 | @param dx offset subtracted to fLeft and added from fRight |
347 | @param dy offset subtracted to fTop and added from fBottom |
348 | @return SkIRect outset symmetrically left and right, top and bottom |
349 | */ |
350 | SkIRect makeOutset(int32_t dx, int32_t dy) const { |
351 | return { |
352 | .fLeft: Sk32_sat_sub(a: fLeft, b: dx), .fTop: Sk32_sat_sub(a: fTop, b: dy), |
353 | .fRight: Sk32_sat_add(a: fRight, b: dx), .fBottom: Sk32_sat_add(a: fBottom, b: dy), |
354 | }; |
355 | } |
356 | |
357 | /** Offsets SkIRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. |
358 | |
359 | If dx is negative, moves SkIRect returned to the left. |
360 | If dx is positive, moves SkIRect returned to the right. |
361 | If dy is negative, moves SkIRect returned upward. |
362 | If dy is positive, moves SkIRect returned downward. |
363 | |
364 | @param dx offset added to fLeft and fRight |
365 | @param dy offset added to fTop and fBottom |
366 | */ |
367 | void offset(int32_t dx, int32_t dy) { |
368 | fLeft = Sk32_sat_add(a: fLeft, b: dx); |
369 | fTop = Sk32_sat_add(a: fTop, b: dy); |
370 | fRight = Sk32_sat_add(a: fRight, b: dx); |
371 | fBottom = Sk32_sat_add(a: fBottom, b: dy); |
372 | } |
373 | |
374 | /** Offsets SkIRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to |
375 | fTop, fBottom. |
376 | |
377 | If delta.fX is negative, moves SkIRect returned to the left. |
378 | If delta.fX is positive, moves SkIRect returned to the right. |
379 | If delta.fY is negative, moves SkIRect returned upward. |
380 | If delta.fY is positive, moves SkIRect returned downward. |
381 | |
382 | @param delta offset added to SkIRect |
383 | */ |
384 | void offset(const SkIPoint& delta) { |
385 | this->offset(dx: delta.fX, dy: delta.fY); |
386 | } |
387 | |
388 | /** Offsets SkIRect so that fLeft equals newX, and fTop equals newY. width and height |
389 | are unchanged. |
390 | |
391 | @param newX stored in fLeft, preserving width() |
392 | @param newY stored in fTop, preserving height() |
393 | */ |
394 | void offsetTo(int32_t newX, int32_t newY) { |
395 | fRight = Sk64_pin_to_s32(x: (int64_t)fRight + newX - fLeft); |
396 | fBottom = Sk64_pin_to_s32(x: (int64_t)fBottom + newY - fTop); |
397 | fLeft = newX; |
398 | fTop = newY; |
399 | } |
400 | |
401 | /** Insets SkIRect by (dx,dy). |
402 | |
403 | If dx is positive, makes SkIRect narrower. |
404 | If dx is negative, makes SkIRect wider. |
405 | If dy is positive, makes SkIRect shorter. |
406 | If dy is negative, makes SkIRect taller. |
407 | |
408 | @param dx offset added to fLeft and subtracted from fRight |
409 | @param dy offset added to fTop and subtracted from fBottom |
410 | */ |
411 | void inset(int32_t dx, int32_t dy) { |
412 | fLeft = Sk32_sat_add(a: fLeft, b: dx); |
413 | fTop = Sk32_sat_add(a: fTop, b: dy); |
414 | fRight = Sk32_sat_sub(a: fRight, b: dx); |
415 | fBottom = Sk32_sat_sub(a: fBottom, b: dy); |
416 | } |
417 | |
418 | /** Outsets SkIRect by (dx, dy). |
419 | |
420 | If dx is positive, makes SkIRect wider. |
421 | If dx is negative, makes SkIRect narrower. |
422 | If dy is positive, makes SkIRect taller. |
423 | If dy is negative, makes SkIRect shorter. |
424 | |
425 | @param dx subtracted to fLeft and added from fRight |
426 | @param dy subtracted to fTop and added from fBottom |
427 | */ |
428 | void outset(int32_t dx, int32_t dy) { this->inset(dx: -dx, dy: -dy); } |
429 | |
430 | /** Adjusts SkIRect by adding dL to fLeft, dT to fTop, dR to fRight, and dB to fBottom. |
431 | |
432 | If dL is positive, narrows SkIRect on the left. If negative, widens it on the left. |
433 | If dT is positive, shrinks SkIRect on the top. If negative, lengthens it on the top. |
434 | If dR is positive, narrows SkIRect on the right. If negative, widens it on the right. |
435 | If dB is positive, shrinks SkIRect on the bottom. If negative, lengthens it on the bottom. |
436 | |
437 | The resulting SkIRect is not checked for validity. Thus, if the resulting SkIRect left is |
438 | greater than right, the SkIRect will be considered empty. Call sort() after this call |
439 | if that is not the desired behavior. |
440 | |
441 | @param dL offset added to fLeft |
442 | @param dT offset added to fTop |
443 | @param dR offset added to fRight |
444 | @param dB offset added to fBottom |
445 | */ |
446 | void adjust(int32_t dL, int32_t dT, int32_t dR, int32_t dB) { |
447 | fLeft = Sk32_sat_add(a: fLeft, b: dL); |
448 | fTop = Sk32_sat_add(a: fTop, b: dT); |
449 | fRight = Sk32_sat_add(a: fRight, b: dR); |
450 | fBottom = Sk32_sat_add(a: fBottom, b: dB); |
451 | } |
452 | |
453 | /** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. |
454 | Returns false if SkIRect is empty. |
455 | |
456 | Considers input to describe constructed SkIRect: (x, y, x + 1, y + 1) and |
457 | returns true if constructed area is completely enclosed by SkIRect area. |
458 | |
459 | @param x test SkIPoint x-coordinate |
460 | @param y test SkIPoint y-coordinate |
461 | @return true if (x, y) is inside SkIRect |
462 | */ |
463 | bool contains(int32_t x, int32_t y) const { |
464 | return x >= fLeft && x < fRight && y >= fTop && y < fBottom; |
465 | } |
466 | |
467 | /** Returns true if SkIRect contains r. |
468 | Returns false if SkIRect is empty or r is empty. |
469 | |
470 | SkIRect contains r when SkIRect area completely includes r area. |
471 | |
472 | @param r SkIRect contained |
473 | @return true if all sides of SkIRect are outside r |
474 | */ |
475 | bool contains(const SkIRect& r) const { |
476 | return !r.isEmpty() && !this->isEmpty() && // check for empties |
477 | fLeft <= r.fLeft && fTop <= r.fTop && |
478 | fRight >= r.fRight && fBottom >= r.fBottom; |
479 | } |
480 | |
481 | /** Returns true if SkIRect contains r. |
482 | Returns false if SkIRect is empty or r is empty. |
483 | |
484 | SkIRect contains r when SkIRect area completely includes r area. |
485 | |
486 | @param r SkRect contained |
487 | @return true if all sides of SkIRect are outside r |
488 | */ |
489 | inline bool contains(const SkRect& r) const; |
490 | |
491 | /** Returns true if SkIRect contains construction. |
492 | Asserts if SkIRect is empty or construction is empty, and if SK_DEBUG is defined. |
493 | |
494 | Return is undefined if SkIRect is empty or construction is empty. |
495 | |
496 | @param r SkIRect contained |
497 | @return true if all sides of SkIRect are outside r |
498 | */ |
499 | bool containsNoEmptyCheck(const SkIRect& r) const { |
500 | SkASSERT(fLeft < fRight && fTop < fBottom); |
501 | SkASSERT(r.fLeft < r.fRight && r.fTop < r.fBottom); |
502 | return fLeft <= r.fLeft && fTop <= r.fTop && fRight >= r.fRight && fBottom >= r.fBottom; |
503 | } |
504 | |
505 | /** Returns true if SkIRect intersects r, and sets SkIRect to intersection. |
506 | Returns false if SkIRect does not intersect r, and leaves SkIRect unchanged. |
507 | |
508 | Returns false if either r or SkIRect is empty, leaving SkIRect unchanged. |
509 | |
510 | @param r limit of result |
511 | @return true if r and SkIRect have area in common |
512 | */ |
513 | bool intersect(const SkIRect& r) { |
514 | return this->intersect(a: *this, b: r); |
515 | } |
516 | |
517 | /** Returns true if a intersects b, and sets SkIRect to intersection. |
518 | Returns false if a does not intersect b, and leaves SkIRect unchanged. |
519 | |
520 | Returns false if either a or b is empty, leaving SkIRect unchanged. |
521 | |
522 | @param a SkIRect to intersect |
523 | @param b SkIRect to intersect |
524 | @return true if a and b have area in common |
525 | */ |
526 | [[nodiscard]] bool intersect(const SkIRect& a, const SkIRect& b); |
527 | |
528 | /** Returns true if a intersects b. |
529 | Returns false if either a or b is empty, or do not intersect. |
530 | |
531 | @param a SkIRect to intersect |
532 | @param b SkIRect to intersect |
533 | @return true if a and b have area in common |
534 | */ |
535 | static bool Intersects(const SkIRect& a, const SkIRect& b) { |
536 | return SkIRect{}.intersect(a, b); |
537 | } |
538 | |
539 | /** Sets SkIRect to the union of itself and r. |
540 | |
541 | Has no effect if r is empty. Otherwise, if SkIRect is empty, sets SkIRect to r. |
542 | |
543 | @param r expansion SkIRect |
544 | |
545 | example: https://fiddle.skia.org/c/@IRect_join_2 |
546 | */ |
547 | void join(const SkIRect& r); |
548 | |
549 | /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps |
550 | fTop and fBottom if fTop is greater than fBottom. Result may be empty, |
551 | and width() and height() will be zero or positive. |
552 | */ |
553 | void sort() { |
554 | using std::swap; |
555 | if (fLeft > fRight) { |
556 | swap(x&: fLeft, y&: fRight); |
557 | } |
558 | if (fTop > fBottom) { |
559 | swap(x&: fTop, y&: fBottom); |
560 | } |
561 | } |
562 | |
563 | /** Returns SkIRect with fLeft and fRight swapped if fLeft is greater than fRight; and |
564 | with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; |
565 | and width() and height() will be zero or positive. |
566 | |
567 | @return sorted SkIRect |
568 | */ |
569 | SkIRect makeSorted() const { |
570 | return MakeLTRB(l: std::min(a: fLeft, b: fRight), t: std::min(a: fTop, b: fBottom), |
571 | r: std::max(a: fLeft, b: fRight), b: std::max(a: fTop, b: fBottom)); |
572 | } |
573 | }; |
574 | |
575 | /** \struct SkRect |
576 | SkRect holds four float coordinates describing the upper and |
577 | lower bounds of a rectangle. SkRect may be created from outer bounds or |
578 | from position, width, and height. SkRect describes an area; if its right |
579 | is less than or equal to its left, or if its bottom is less than or equal to |
580 | its top, it is considered empty. |
581 | */ |
582 | struct SK_API SkRect { |
583 | float fLeft = 0; //!< smaller x-axis bounds |
584 | float fTop = 0; //!< smaller y-axis bounds |
585 | float fRight = 0; //!< larger x-axis bounds |
586 | float fBottom = 0; //!< larger y-axis bounds |
587 | |
588 | /** Returns constructed SkRect set to (0, 0, 0, 0). |
589 | Many other rectangles are empty; if left is equal to or greater than right, |
590 | or if top is equal to or greater than bottom. Setting all members to zero |
591 | is a convenience, but does not designate a special empty rectangle. |
592 | |
593 | @return bounds (0, 0, 0, 0) |
594 | */ |
595 | [[nodiscard]] static constexpr SkRect MakeEmpty() { |
596 | return SkRect{.fLeft: 0, .fTop: 0, .fRight: 0, .fBottom: 0}; |
597 | } |
598 | |
599 | /** Returns constructed SkRect set to float values (0, 0, w, h). Does not |
600 | validate input; w or h may be negative. |
601 | |
602 | Passing integer values may generate a compiler warning since SkRect cannot |
603 | represent 32-bit integers exactly. Use SkIRect for an exact integer rectangle. |
604 | |
605 | @param w float width of constructed SkRect |
606 | @param h float height of constructed SkRect |
607 | @return bounds (0, 0, w, h) |
608 | */ |
609 | [[nodiscard]] static constexpr SkRect MakeWH(float w, float h) { |
610 | return SkRect{.fLeft: 0, .fTop: 0, .fRight: w, .fBottom: h}; |
611 | } |
612 | |
613 | /** Returns constructed SkRect set to integer values (0, 0, w, h). Does not validate |
614 | input; w or h may be negative. |
615 | |
616 | Use to avoid a compiler warning that input may lose precision when stored. |
617 | Use SkIRect for an exact integer rectangle. |
618 | |
619 | @param w integer width of constructed SkRect |
620 | @param h integer height of constructed SkRect |
621 | @return bounds (0, 0, w, h) |
622 | */ |
623 | [[nodiscard]] static SkRect MakeIWH(int w, int h) { |
624 | return {.fLeft: 0, .fTop: 0, .fRight: static_cast<float>(w), .fBottom: static_cast<float>(h)}; |
625 | } |
626 | |
627 | /** Returns constructed SkRect set to (0, 0, size.width(), size.height()). Does not |
628 | validate input; size.width() or size.height() may be negative. |
629 | |
630 | @param size float values for SkRect width and height |
631 | @return bounds (0, 0, size.width(), size.height()) |
632 | */ |
633 | [[nodiscard]] static constexpr SkRect MakeSize(const SkSize& size) { |
634 | return SkRect{.fLeft: 0, .fTop: 0, .fRight: size.fWidth, .fBottom: size.fHeight}; |
635 | } |
636 | |
637 | /** Returns constructed SkRect set to (l, t, r, b). Does not sort input; SkRect may |
638 | result in fLeft greater than fRight, or fTop greater than fBottom. |
639 | |
640 | @param l float stored in fLeft |
641 | @param t float stored in fTop |
642 | @param r float stored in fRight |
643 | @param b float stored in fBottom |
644 | @return bounds (l, t, r, b) |
645 | */ |
646 | [[nodiscard]] static constexpr SkRect MakeLTRB(float l, float t, float r, float b) { |
647 | return SkRect {.fLeft: l, .fTop: t, .fRight: r, .fBottom: b}; |
648 | } |
649 | |
650 | /** Returns constructed SkRect set to (x, y, x + w, y + h). |
651 | Does not validate input; w or h may be negative. |
652 | |
653 | @param x stored in fLeft |
654 | @param y stored in fTop |
655 | @param w added to x and stored in fRight |
656 | @param h added to y and stored in fBottom |
657 | @return bounds at (x, y) with width w and height h |
658 | */ |
659 | [[nodiscard]] static constexpr SkRect MakeXYWH(float x, float y, float w, float h) { |
660 | return SkRect {.fLeft: x, .fTop: y, .fRight: x + w, .fBottom: y + h}; |
661 | } |
662 | |
663 | /** Returns constructed SkIRect set to (0, 0, size.width(), size.height()). |
664 | Does not validate input; size.width() or size.height() may be negative. |
665 | |
666 | @param size integer values for SkRect width and height |
667 | @return bounds (0, 0, size.width(), size.height()) |
668 | */ |
669 | static SkRect Make(const SkISize& size) { |
670 | return MakeIWH(w: size.width(), h: size.height()); |
671 | } |
672 | |
673 | /** Returns constructed SkIRect set to irect, promoting integers to float. |
674 | Does not validate input; fLeft may be greater than fRight, fTop may be greater |
675 | than fBottom. |
676 | |
677 | @param irect integer unsorted bounds |
678 | @return irect members converted to float |
679 | */ |
680 | [[nodiscard]] static SkRect Make(const SkIRect& irect) { |
681 | return { |
682 | .fLeft: static_cast<float>(irect.fLeft), .fTop: static_cast<float>(irect.fTop), |
683 | .fRight: static_cast<float>(irect.fRight), .fBottom: static_cast<float>(irect.fBottom) |
684 | }; |
685 | } |
686 | |
687 | /** Returns true if fLeft is equal to or greater than fRight, or if fTop is equal |
688 | to or greater than fBottom. Call sort() to reverse rectangles with negative |
689 | width() or height(). |
690 | |
691 | @return true if width() or height() are zero or negative |
692 | */ |
693 | bool isEmpty() const { |
694 | // We write it as the NOT of a non-empty rect, so we will return true if any values |
695 | // are NaN. |
696 | return !(fLeft < fRight && fTop < fBottom); |
697 | } |
698 | |
699 | /** Returns true if fLeft is equal to or less than fRight, or if fTop is equal |
700 | to or less than fBottom. Call sort() to reverse rectangles with negative |
701 | width() or height(). |
702 | |
703 | @return true if width() or height() are zero or positive |
704 | */ |
705 | bool isSorted() const { return fLeft <= fRight && fTop <= fBottom; } |
706 | |
707 | /** Returns true if all values in the rectangle are finite. |
708 | |
709 | @return true if no member is infinite or NaN |
710 | */ |
711 | bool isFinite() const { |
712 | float accum = 0; |
713 | accum *= fLeft; |
714 | accum *= fTop; |
715 | accum *= fRight; |
716 | accum *= fBottom; |
717 | |
718 | // accum is either NaN or it is finite (zero). |
719 | SkASSERT(0 == accum || std::isnan(accum)); |
720 | |
721 | // value==value will be true iff value is not NaN |
722 | // TODO: is it faster to say !accum or accum==accum? |
723 | return !std::isnan(lcpp_x: accum); |
724 | } |
725 | |
726 | /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. |
727 | Call sort() to reverse fLeft and fRight if needed. |
728 | |
729 | @return fLeft |
730 | */ |
731 | constexpr float x() const { return fLeft; } |
732 | |
733 | /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, |
734 | and sort() to reverse fTop and fBottom if needed. |
735 | |
736 | @return fTop |
737 | */ |
738 | constexpr float y() const { return fTop; } |
739 | |
740 | /** Returns left edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. |
741 | Call sort() to reverse fLeft and fRight if needed. |
742 | |
743 | @return fLeft |
744 | */ |
745 | constexpr float left() const { return fLeft; } |
746 | |
747 | /** Returns top edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, |
748 | and sort() to reverse fTop and fBottom if needed. |
749 | |
750 | @return fTop |
751 | */ |
752 | constexpr float top() const { return fTop; } |
753 | |
754 | /** Returns right edge of SkRect, if sorted. Call isSorted() to see if SkRect is valid. |
755 | Call sort() to reverse fLeft and fRight if needed. |
756 | |
757 | @return fRight |
758 | */ |
759 | constexpr float right() const { return fRight; } |
760 | |
761 | /** Returns bottom edge of SkRect, if sorted. Call isEmpty() to see if SkRect may be invalid, |
762 | and sort() to reverse fTop and fBottom if needed. |
763 | |
764 | @return fBottom |
765 | */ |
766 | constexpr float bottom() const { return fBottom; } |
767 | |
768 | /** Returns span on the x-axis. This does not check if SkRect is sorted, or if |
769 | result fits in 32-bit float; result may be negative or infinity. |
770 | |
771 | @return fRight minus fLeft |
772 | */ |
773 | constexpr float width() const { return fRight - fLeft; } |
774 | |
775 | /** Returns span on the y-axis. This does not check if SkRect is sorted, or if |
776 | result fits in 32-bit float; result may be negative or infinity. |
777 | |
778 | @return fBottom minus fTop |
779 | */ |
780 | constexpr float height() const { return fBottom - fTop; } |
781 | |
782 | /** Returns average of left edge and right edge. Result does not change if SkRect |
783 | is sorted. Result may overflow to infinity if SkRect is far from the origin. |
784 | |
785 | @return midpoint on x-axis |
786 | */ |
787 | constexpr float centerX() const { |
788 | return sk_float_midpoint(a: fLeft, b: fRight); |
789 | } |
790 | |
791 | /** Returns average of top edge and bottom edge. Result does not change if SkRect |
792 | is sorted. |
793 | |
794 | @return midpoint on y-axis |
795 | */ |
796 | constexpr float centerY() const { |
797 | return sk_float_midpoint(a: fTop, b: fBottom); |
798 | } |
799 | |
800 | /** Returns the point this->centerX(), this->centerY(). |
801 | @return rectangle center |
802 | */ |
803 | constexpr SkPoint center() const { return {.fX: this->centerX(), .fY: this->centerY()}; } |
804 | |
805 | /** Returns true if all members in a: fLeft, fTop, fRight, and fBottom; are |
806 | equal to the corresponding members in b. |
807 | |
808 | a and b are not equal if either contain NaN. a and b are equal if members |
809 | contain zeroes with different signs. |
810 | |
811 | @param a SkRect to compare |
812 | @param b SkRect to compare |
813 | @return true if members are equal |
814 | */ |
815 | friend bool operator==(const SkRect& a, const SkRect& b) { |
816 | return a.fLeft == b.fLeft && |
817 | a.fTop == b.fTop && |
818 | a.fRight == b.fRight && |
819 | a.fBottom == b.fBottom; |
820 | } |
821 | |
822 | /** Returns true if any in a: fLeft, fTop, fRight, and fBottom; does not |
823 | equal the corresponding members in b. |
824 | |
825 | a and b are not equal if either contain NaN. a and b are equal if members |
826 | contain zeroes with different signs. |
827 | |
828 | @param a SkRect to compare |
829 | @param b SkRect to compare |
830 | @return true if members are not equal |
831 | */ |
832 | friend bool operator!=(const SkRect& a, const SkRect& b) { |
833 | return !(a == b); |
834 | } |
835 | |
836 | /** Returns four points in quad that enclose SkRect ordered as: top-left, top-right, |
837 | bottom-right, bottom-left. |
838 | |
839 | TODO: Consider adding parameter to control whether quad is clockwise or counterclockwise. |
840 | |
841 | @param quad storage for corners of SkRect |
842 | |
843 | example: https://fiddle.skia.org/c/@Rect_toQuad |
844 | */ |
845 | void toQuad(SkPoint quad[4]) const; |
846 | |
847 | /** Sets SkRect to (0, 0, 0, 0). |
848 | |
849 | Many other rectangles are empty; if left is equal to or greater than right, |
850 | or if top is equal to or greater than bottom. Setting all members to zero |
851 | is a convenience, but does not designate a special empty rectangle. |
852 | */ |
853 | void setEmpty() { *this = MakeEmpty(); } |
854 | |
855 | /** Sets SkRect to src, promoting src members from integer to float. |
856 | Very large values in src may lose precision. |
857 | |
858 | @param src integer SkRect |
859 | */ |
860 | void set(const SkIRect& src) { |
861 | fLeft = src.fLeft; |
862 | fTop = src.fTop; |
863 | fRight = src.fRight; |
864 | fBottom = src.fBottom; |
865 | } |
866 | |
867 | /** Sets SkRect to (left, top, right, bottom). |
868 | left and right are not sorted; left is not necessarily less than right. |
869 | top and bottom are not sorted; top is not necessarily less than bottom. |
870 | |
871 | @param left stored in fLeft |
872 | @param top stored in fTop |
873 | @param right stored in fRight |
874 | @param bottom stored in fBottom |
875 | */ |
876 | void setLTRB(float left, float top, float right, float bottom) { |
877 | fLeft = left; |
878 | fTop = top; |
879 | fRight = right; |
880 | fBottom = bottom; |
881 | } |
882 | |
883 | /** Sets to bounds of SkPoint array with count entries. If count is zero or smaller, |
884 | or if SkPoint array contains an infinity or NaN, sets to (0, 0, 0, 0). |
885 | |
886 | Result is either empty or sorted: fLeft is less than or equal to fRight, and |
887 | fTop is less than or equal to fBottom. |
888 | |
889 | @param pts SkPoint array |
890 | @param count entries in array |
891 | */ |
892 | void setBounds(const SkPoint pts[], int count) { |
893 | (void)this->setBoundsCheck(pts, count); |
894 | } |
895 | |
896 | /** Sets to bounds of SkPoint array with count entries. Returns false if count is |
897 | zero or smaller, or if SkPoint array contains an infinity or NaN; in these cases |
898 | sets SkRect to (0, 0, 0, 0). |
899 | |
900 | Result is either empty or sorted: fLeft is less than or equal to fRight, and |
901 | fTop is less than or equal to fBottom. |
902 | |
903 | @param pts SkPoint array |
904 | @param count entries in array |
905 | @return true if all SkPoint values are finite |
906 | |
907 | example: https://fiddle.skia.org/c/@Rect_setBoundsCheck |
908 | */ |
909 | bool setBoundsCheck(const SkPoint pts[], int count); |
910 | |
911 | /** Sets to bounds of SkPoint pts array with count entries. If any SkPoint in pts |
912 | contains infinity or NaN, all SkRect dimensions are set to NaN. |
913 | |
914 | @param pts SkPoint array |
915 | @param count entries in array |
916 | |
917 | example: https://fiddle.skia.org/c/@Rect_setBoundsNoCheck |
918 | */ |
919 | void setBoundsNoCheck(const SkPoint pts[], int count); |
920 | |
921 | /** Sets bounds to the smallest SkRect enclosing SkPoint p0 and p1. The result is |
922 | sorted and may be empty. Does not check to see if values are finite. |
923 | |
924 | @param p0 corner to include |
925 | @param p1 corner to include |
926 | */ |
927 | void set(const SkPoint& p0, const SkPoint& p1) { |
928 | fLeft = std::min(a: p0.fX, b: p1.fX); |
929 | fRight = std::max(a: p0.fX, b: p1.fX); |
930 | fTop = std::min(a: p0.fY, b: p1.fY); |
931 | fBottom = std::max(a: p0.fY, b: p1.fY); |
932 | } |
933 | |
934 | /** Sets SkRect to (x, y, x + width, y + height). |
935 | Does not validate input; width or height may be negative. |
936 | |
937 | @param x stored in fLeft |
938 | @param y stored in fTop |
939 | @param width added to x and stored in fRight |
940 | @param height added to y and stored in fBottom |
941 | */ |
942 | void setXYWH(float x, float y, float width, float height) { |
943 | fLeft = x; |
944 | fTop = y; |
945 | fRight = x + width; |
946 | fBottom = y + height; |
947 | } |
948 | |
949 | /** Sets SkRect to (0, 0, width, height). Does not validate input; |
950 | width or height may be negative. |
951 | |
952 | @param width stored in fRight |
953 | @param height stored in fBottom |
954 | */ |
955 | void setWH(float width, float height) { |
956 | fLeft = 0; |
957 | fTop = 0; |
958 | fRight = width; |
959 | fBottom = height; |
960 | } |
961 | void setIWH(int32_t width, int32_t height) { |
962 | this->setWH(width, height); |
963 | } |
964 | |
965 | /** Returns SkRect offset by (dx, dy). |
966 | |
967 | If dx is negative, SkRect returned is moved to the left. |
968 | If dx is positive, SkRect returned is moved to the right. |
969 | If dy is negative, SkRect returned is moved upward. |
970 | If dy is positive, SkRect returned is moved downward. |
971 | |
972 | @param dx added to fLeft and fRight |
973 | @param dy added to fTop and fBottom |
974 | @return SkRect offset on axes, with original width and height |
975 | */ |
976 | constexpr SkRect makeOffset(float dx, float dy) const { |
977 | return MakeLTRB(l: fLeft + dx, t: fTop + dy, r: fRight + dx, b: fBottom + dy); |
978 | } |
979 | |
980 | /** Returns SkRect offset by v. |
981 | |
982 | @param v added to rect |
983 | @return SkRect offset on axes, with original width and height |
984 | */ |
985 | constexpr SkRect makeOffset(SkVector v) const { return this->makeOffset(dx: v.x(), dy: v.y()); } |
986 | |
987 | /** Returns SkRect, inset by (dx, dy). |
988 | |
989 | If dx is negative, SkRect returned is wider. |
990 | If dx is positive, SkRect returned is narrower. |
991 | If dy is negative, SkRect returned is taller. |
992 | If dy is positive, SkRect returned is shorter. |
993 | |
994 | @param dx added to fLeft and subtracted from fRight |
995 | @param dy added to fTop and subtracted from fBottom |
996 | @return SkRect inset symmetrically left and right, top and bottom |
997 | */ |
998 | SkRect makeInset(float dx, float dy) const { |
999 | return MakeLTRB(l: fLeft + dx, t: fTop + dy, r: fRight - dx, b: fBottom - dy); |
1000 | } |
1001 | |
1002 | /** Returns SkRect, outset by (dx, dy). |
1003 | |
1004 | If dx is negative, SkRect returned is narrower. |
1005 | If dx is positive, SkRect returned is wider. |
1006 | If dy is negative, SkRect returned is shorter. |
1007 | If dy is positive, SkRect returned is taller. |
1008 | |
1009 | @param dx subtracted to fLeft and added from fRight |
1010 | @param dy subtracted to fTop and added from fBottom |
1011 | @return SkRect outset symmetrically left and right, top and bottom |
1012 | */ |
1013 | SkRect makeOutset(float dx, float dy) const { |
1014 | return MakeLTRB(l: fLeft - dx, t: fTop - dy, r: fRight + dx, b: fBottom + dy); |
1015 | } |
1016 | |
1017 | /** Offsets SkRect by adding dx to fLeft, fRight; and by adding dy to fTop, fBottom. |
1018 | |
1019 | If dx is negative, moves SkRect to the left. |
1020 | If dx is positive, moves SkRect to the right. |
1021 | If dy is negative, moves SkRect upward. |
1022 | If dy is positive, moves SkRect downward. |
1023 | |
1024 | @param dx offset added to fLeft and fRight |
1025 | @param dy offset added to fTop and fBottom |
1026 | */ |
1027 | void offset(float dx, float dy) { |
1028 | fLeft += dx; |
1029 | fTop += dy; |
1030 | fRight += dx; |
1031 | fBottom += dy; |
1032 | } |
1033 | |
1034 | /** Offsets SkRect by adding delta.fX to fLeft, fRight; and by adding delta.fY to |
1035 | fTop, fBottom. |
1036 | |
1037 | If delta.fX is negative, moves SkRect to the left. |
1038 | If delta.fX is positive, moves SkRect to the right. |
1039 | If delta.fY is negative, moves SkRect upward. |
1040 | If delta.fY is positive, moves SkRect downward. |
1041 | |
1042 | @param delta added to SkRect |
1043 | */ |
1044 | void offset(const SkPoint& delta) { |
1045 | this->offset(dx: delta.fX, dy: delta.fY); |
1046 | } |
1047 | |
1048 | /** Offsets SkRect so that fLeft equals newX, and fTop equals newY. width and height |
1049 | are unchanged. |
1050 | |
1051 | @param newX stored in fLeft, preserving width() |
1052 | @param newY stored in fTop, preserving height() |
1053 | */ |
1054 | void offsetTo(float newX, float newY) { |
1055 | fRight += newX - fLeft; |
1056 | fBottom += newY - fTop; |
1057 | fLeft = newX; |
1058 | fTop = newY; |
1059 | } |
1060 | |
1061 | /** Insets SkRect by (dx, dy). |
1062 | |
1063 | If dx is positive, makes SkRect narrower. |
1064 | If dx is negative, makes SkRect wider. |
1065 | If dy is positive, makes SkRect shorter. |
1066 | If dy is negative, makes SkRect taller. |
1067 | |
1068 | @param dx added to fLeft and subtracted from fRight |
1069 | @param dy added to fTop and subtracted from fBottom |
1070 | */ |
1071 | void inset(float dx, float dy) { |
1072 | fLeft += dx; |
1073 | fTop += dy; |
1074 | fRight -= dx; |
1075 | fBottom -= dy; |
1076 | } |
1077 | |
1078 | /** Outsets SkRect by (dx, dy). |
1079 | |
1080 | If dx is positive, makes SkRect wider. |
1081 | If dx is negative, makes SkRect narrower. |
1082 | If dy is positive, makes SkRect taller. |
1083 | If dy is negative, makes SkRect shorter. |
1084 | |
1085 | @param dx subtracted to fLeft and added from fRight |
1086 | @param dy subtracted to fTop and added from fBottom |
1087 | */ |
1088 | void outset(float dx, float dy) { this->inset(dx: -dx, dy: -dy); } |
1089 | |
1090 | /** Returns true if SkRect intersects r, and sets SkRect to intersection. |
1091 | Returns false if SkRect does not intersect r, and leaves SkRect unchanged. |
1092 | |
1093 | Returns false if either r or SkRect is empty, leaving SkRect unchanged. |
1094 | |
1095 | @param r limit of result |
1096 | @return true if r and SkRect have area in common |
1097 | |
1098 | example: https://fiddle.skia.org/c/@Rect_intersect |
1099 | */ |
1100 | bool intersect(const SkRect& r); |
1101 | |
1102 | /** Returns true if a intersects b, and sets SkRect to intersection. |
1103 | Returns false if a does not intersect b, and leaves SkRect unchanged. |
1104 | |
1105 | Returns false if either a or b is empty, leaving SkRect unchanged. |
1106 | |
1107 | @param a SkRect to intersect |
1108 | @param b SkRect to intersect |
1109 | @return true if a and b have area in common |
1110 | */ |
1111 | [[nodiscard]] bool intersect(const SkRect& a, const SkRect& b); |
1112 | |
1113 | |
1114 | private: |
1115 | static bool Intersects(float al, float at, float ar, float ab, |
1116 | float bl, float bt, float br, float bb) { |
1117 | float L = std::max(a: al, b: bl); |
1118 | float R = std::min(a: ar, b: br); |
1119 | float T = std::max(a: at, b: bt); |
1120 | float B = std::min(a: ab, b: bb); |
1121 | return L < R && T < B; |
1122 | } |
1123 | |
1124 | public: |
1125 | |
1126 | /** Returns true if SkRect intersects r. |
1127 | Returns false if either r or SkRect is empty, or do not intersect. |
1128 | |
1129 | @param r SkRect to intersect |
1130 | @return true if r and SkRect have area in common |
1131 | */ |
1132 | bool intersects(const SkRect& r) const { |
1133 | return Intersects(al: fLeft, at: fTop, ar: fRight, ab: fBottom, |
1134 | bl: r.fLeft, bt: r.fTop, br: r.fRight, bb: r.fBottom); |
1135 | } |
1136 | |
1137 | /** Returns true if a intersects b. |
1138 | Returns false if either a or b is empty, or do not intersect. |
1139 | |
1140 | @param a SkRect to intersect |
1141 | @param b SkRect to intersect |
1142 | @return true if a and b have area in common |
1143 | */ |
1144 | static bool Intersects(const SkRect& a, const SkRect& b) { |
1145 | return Intersects(al: a.fLeft, at: a.fTop, ar: a.fRight, ab: a.fBottom, |
1146 | bl: b.fLeft, bt: b.fTop, br: b.fRight, bb: b.fBottom); |
1147 | } |
1148 | |
1149 | /** Sets SkRect to the union of itself and r. |
1150 | |
1151 | Has no effect if r is empty. Otherwise, if SkRect is empty, sets |
1152 | SkRect to r. |
1153 | |
1154 | @param r expansion SkRect |
1155 | |
1156 | example: https://fiddle.skia.org/c/@Rect_join_2 |
1157 | */ |
1158 | void join(const SkRect& r); |
1159 | |
1160 | /** Sets SkRect to the union of itself and r. |
1161 | |
1162 | Asserts if r is empty and SK_DEBUG is defined. |
1163 | If SkRect is empty, sets SkRect to r. |
1164 | |
1165 | May produce incorrect results if r is empty. |
1166 | |
1167 | @param r expansion SkRect |
1168 | */ |
1169 | void joinNonEmptyArg(const SkRect& r) { |
1170 | SkASSERT(!r.isEmpty()); |
1171 | // if we are empty, just assign |
1172 | if (fLeft >= fRight || fTop >= fBottom) { |
1173 | *this = r; |
1174 | } else { |
1175 | this->joinPossiblyEmptyRect(r); |
1176 | } |
1177 | } |
1178 | |
1179 | /** Sets SkRect to the union of itself and the construction. |
1180 | |
1181 | May produce incorrect results if SkRect or r is empty. |
1182 | |
1183 | @param r expansion SkRect |
1184 | */ |
1185 | void joinPossiblyEmptyRect(const SkRect& r) { |
1186 | fLeft = std::min(a: fLeft, b: r.left()); |
1187 | fTop = std::min(a: fTop, b: r.top()); |
1188 | fRight = std::max(a: fRight, b: r.right()); |
1189 | fBottom = std::max(a: fBottom, b: r.bottom()); |
1190 | } |
1191 | |
1192 | /** Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. |
1193 | Returns false if SkRect is empty. |
1194 | |
1195 | @param x test SkPoint x-coordinate |
1196 | @param y test SkPoint y-coordinate |
1197 | @return true if (x, y) is inside SkRect |
1198 | */ |
1199 | bool contains(float x, float y) const { |
1200 | return x >= fLeft && x < fRight && y >= fTop && y < fBottom; |
1201 | } |
1202 | |
1203 | /** Returns true if SkRect contains r. |
1204 | Returns false if SkRect is empty or r is empty. |
1205 | |
1206 | SkRect contains r when SkRect area completely includes r area. |
1207 | |
1208 | @param r SkRect contained |
1209 | @return true if all sides of SkRect are outside r |
1210 | */ |
1211 | bool contains(const SkRect& r) const { |
1212 | // todo: can we eliminate the this->isEmpty check? |
1213 | return !r.isEmpty() && !this->isEmpty() && |
1214 | fLeft <= r.fLeft && fTop <= r.fTop && |
1215 | fRight >= r.fRight && fBottom >= r.fBottom; |
1216 | } |
1217 | |
1218 | /** Returns true if SkRect contains r. |
1219 | Returns false if SkRect is empty or r is empty. |
1220 | |
1221 | SkRect contains r when SkRect area completely includes r area. |
1222 | |
1223 | @param r SkIRect contained |
1224 | @return true if all sides of SkRect are outside r |
1225 | */ |
1226 | bool contains(const SkIRect& r) const { |
1227 | // todo: can we eliminate the this->isEmpty check? |
1228 | return !r.isEmpty() && !this->isEmpty() && |
1229 | fLeft <= r.fLeft && fTop <= r.fTop && |
1230 | fRight >= r.fRight && fBottom >= r.fBottom; |
1231 | } |
1232 | |
1233 | /** Sets SkIRect by adding 0.5 and discarding the fractional portion of SkRect |
1234 | members, using (sk_float_round2int(fLeft), sk_float_round2int(fTop), |
1235 | sk_float_round2int(fRight), sk_float_round2int(fBottom)). |
1236 | |
1237 | @param dst storage for SkIRect |
1238 | */ |
1239 | void round(SkIRect* dst) const { |
1240 | SkASSERT(dst); |
1241 | dst->setLTRB(sk_float_round2int(fLeft), sk_float_round2int(fTop), |
1242 | sk_float_round2int(fRight), sk_float_round2int(fBottom)); |
1243 | } |
1244 | |
1245 | /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and rounding |
1246 | up fRight and fBottom, using |
1247 | (sk_float_floor2int(fLeft), sk_float_floor2int(fTop), |
1248 | sk_float_ceil2int(fRight), sk_float_ceil2int(fBottom)). |
1249 | |
1250 | @param dst storage for SkIRect |
1251 | */ |
1252 | void roundOut(SkIRect* dst) const { |
1253 | SkASSERT(dst); |
1254 | dst->setLTRB(sk_float_floor2int(fLeft), sk_float_floor2int(fTop), |
1255 | sk_float_ceil2int(fRight), sk_float_ceil2int(fBottom)); |
1256 | } |
1257 | |
1258 | /** Sets SkRect by discarding the fractional portion of fLeft and fTop; and rounding |
1259 | up fRight and fBottom, using |
1260 | (sk_float_floor(fLeft), sk_float_floor(fTop), |
1261 | sk_float_ceil(fRight), sk_float_ceil(fBottom)). |
1262 | |
1263 | @param dst storage for SkRect |
1264 | */ |
1265 | void roundOut(SkRect* dst) const { |
1266 | dst->setLTRB(left: sk_float_floor(x: fLeft), top: sk_float_floor(x: fTop), |
1267 | right: sk_float_ceil(x: fRight), bottom: sk_float_ceil(x: fBottom)); |
1268 | } |
1269 | |
1270 | /** Sets SkRect by rounding up fLeft and fTop; and discarding the fractional portion |
1271 | of fRight and fBottom, using |
1272 | (sk_float_ceil2int(fLeft), sk_float_ceil2int(fTop), |
1273 | sk_float_floor2int(fRight), sk_float_floor2int(fBottom)). |
1274 | |
1275 | @param dst storage for SkIRect |
1276 | */ |
1277 | void roundIn(SkIRect* dst) const { |
1278 | SkASSERT(dst); |
1279 | dst->setLTRB(sk_float_ceil2int(fLeft), sk_float_ceil2int(fTop), |
1280 | sk_float_floor2int(fRight), sk_float_floor2int(fBottom)); |
1281 | } |
1282 | |
1283 | /** Returns SkIRect by adding 0.5 and discarding the fractional portion of SkRect |
1284 | members, using (sk_float_round2int(fLeft), sk_float_round2int(fTop), |
1285 | sk_float_round2int(fRight), sk_float_round2int(fBottom)). |
1286 | |
1287 | @return rounded SkIRect |
1288 | */ |
1289 | SkIRect round() const { |
1290 | SkIRect ir; |
1291 | this->round(dst: &ir); |
1292 | return ir; |
1293 | } |
1294 | |
1295 | /** Sets SkIRect by discarding the fractional portion of fLeft and fTop; and rounding |
1296 | up fRight and fBottom, using |
1297 | (sk_float_floor2int(fLeft), sk_float_floor2int(fTop), |
1298 | sk_float_ceil2int(fRight), sk_float_ceil2int(fBottom)). |
1299 | |
1300 | @return rounded SkIRect |
1301 | */ |
1302 | SkIRect roundOut() const { |
1303 | SkIRect ir; |
1304 | this->roundOut(dst: &ir); |
1305 | return ir; |
1306 | } |
1307 | /** Sets SkIRect by rounding up fLeft and fTop; and discarding the fractional portion |
1308 | of fRight and fBottom, using |
1309 | (sk_float_ceil2int(fLeft), sk_float_ceil2int(fTop), |
1310 | sk_float_floor2int(fRight), sk_float_floor2int(fBottom)). |
1311 | |
1312 | @return rounded SkIRect |
1313 | */ |
1314 | SkIRect roundIn() const { |
1315 | SkIRect ir; |
1316 | this->roundIn(dst: &ir); |
1317 | return ir; |
1318 | } |
1319 | |
1320 | /** Swaps fLeft and fRight if fLeft is greater than fRight; and swaps |
1321 | fTop and fBottom if fTop is greater than fBottom. Result may be empty; |
1322 | and width() and height() will be zero or positive. |
1323 | */ |
1324 | void sort() { |
1325 | using std::swap; |
1326 | if (fLeft > fRight) { |
1327 | swap(x&: fLeft, y&: fRight); |
1328 | } |
1329 | |
1330 | if (fTop > fBottom) { |
1331 | swap(x&: fTop, y&: fBottom); |
1332 | } |
1333 | } |
1334 | |
1335 | /** Returns SkRect with fLeft and fRight swapped if fLeft is greater than fRight; and |
1336 | with fTop and fBottom swapped if fTop is greater than fBottom. Result may be empty; |
1337 | and width() and height() will be zero or positive. |
1338 | |
1339 | @return sorted SkRect |
1340 | */ |
1341 | SkRect makeSorted() const { |
1342 | return MakeLTRB(l: std::min(a: fLeft, b: fRight), t: std::min(a: fTop, b: fBottom), |
1343 | r: std::max(a: fLeft, b: fRight), b: std::max(a: fTop, b: fBottom)); |
1344 | } |
1345 | |
1346 | /** Returns pointer to first float in SkRect, to treat it as an array with four |
1347 | entries. |
1348 | |
1349 | @return pointer to fLeft |
1350 | */ |
1351 | const float* asScalars() const { return &fLeft; } |
1352 | |
1353 | /** Writes text representation of SkRect to standard output. Set asHex to true to |
1354 | generate exact binary representations of floating point numbers. |
1355 | |
1356 | @param asHex true if SkScalar values are written as hexadecimal |
1357 | |
1358 | example: https://fiddle.skia.org/c/@Rect_dump |
1359 | */ |
1360 | void dump(bool asHex) const; |
1361 | |
1362 | /** Writes text representation of SkRect to standard output. The representation may be |
1363 | directly compiled as C++ code. Floating point values are written |
1364 | with limited precision; it may not be possible to reconstruct original SkRect |
1365 | from output. |
1366 | */ |
1367 | void dump() const { this->dump(asHex: false); } |
1368 | |
1369 | /** Writes text representation of SkRect to standard output. The representation may be |
1370 | directly compiled as C++ code. Floating point values are written |
1371 | in hexadecimal to preserve their exact bit pattern. The output reconstructs the |
1372 | original SkRect. |
1373 | |
1374 | Use instead of dump() when submitting |
1375 | */ |
1376 | void dumpHex() const { this->dump(asHex: true); } |
1377 | }; |
1378 | |
1379 | inline bool SkIRect::contains(const SkRect& r) const { |
1380 | return !r.isEmpty() && !this->isEmpty() && // check for empties |
1381 | fLeft <= r.fLeft && fTop <= r.fTop && |
1382 | fRight >= r.fRight && fBottom >= r.fBottom; |
1383 | } |
1384 | |
1385 | #endif |
1386 | |