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