blob: e57130a4581de0f3e08ab3656bebdc54f1a42a21 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef SkRect_DEFINED
18#define SkRect_DEFINED
19
20#include "SkPoint.h"
reed@android.com233481e2010-02-24 01:49:13 +000021#include "SkSize.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000022
23/** \struct SkIRect
24
25 SkIRect holds four 32 bit integer coordinates for a rectangle
26*/
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +000027struct SK_API SkIRect {
reed@android.com8a1c16f2008-12-17 15:59:43 +000028 int32_t fLeft, fTop, fRight, fBottom;
29
reed@android.com097a3512010-07-13 18:35:14 +000030 static SkIRect MakeEmpty() {
31 SkIRect r;
32 r.setEmpty();
33 return r;
34 }
35
36 static SkIRect MakeWH(int32_t w, int32_t h) {
37 SkIRect r;
38 r.set(0, 0, w, h);
39 return r;
40 }
41
42 static SkIRect MakeSize(const SkISize& size) {
43 SkIRect r;
44 r.set(0, 0, size.width(), size.height());
45 return r;
46 }
47
48 static SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) {
49 SkIRect rect;
50 rect.set(l, t, r, b);
51 return rect;
52 }
53
54 static SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) {
55 SkIRect r;
56 r.set(x, y, x + w, y + h);
57 return r;
58 }
59
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 /** Return true if the rectangle's width or height are <= 0
61 */
62 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
63
64 /** Returns the rectangle's width. This does not check for a valid rectangle (i.e. left <= right)
65 so the result may be negative.
66 */
67 int width() const { return fRight - fLeft; }
68
69 /** Returns the rectangle's height. This does not check for a valid rectangle (i.e. top <= bottom)
70 so the result may be negative.
71 */
72 int height() const { return fBottom - fTop; }
73
reed@google.comb530ef52011-07-20 19:55:42 +000074 friend bool operator==(const SkIRect& a, const SkIRect& b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 return !memcmp(&a, &b, sizeof(a));
76 }
reed@android.comda6fb322010-02-19 21:41:30 +000077
reed@google.comb530ef52011-07-20 19:55:42 +000078 friend bool operator!=(const SkIRect& a, const SkIRect& b) {
79 return !(a == b);
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 }
81
reed@android.comd4577752009-11-21 02:48:11 +000082 bool is16Bit() const {
83 return SkIsS16(fLeft) && SkIsS16(fTop) &&
84 SkIsS16(fRight) && SkIsS16(fBottom);
85 }
86
reed@android.com8a1c16f2008-12-17 15:59:43 +000087 /** Set the rectangle to (0,0,0,0)
88 */
89 void setEmpty() { memset(this, 0, sizeof(*this)); }
90
reed@android.comda6fb322010-02-19 21:41:30 +000091 void set(int32_t left, int32_t top, int32_t right, int32_t bottom) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 fLeft = left;
93 fTop = top;
94 fRight = right;
95 fBottom = bottom;
96 }
reed@google.com20efde72011-05-09 17:00:02 +000097 // alias for set(l, t, r, b)
98 void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) {
99 this->set(left, top, right, bottom);
100 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101
reed@google.com1d12b1f2011-03-03 13:23:35 +0000102 void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) {
103 fLeft = x;
104 fTop = y;
105 fRight = x + width;
106 fBottom = y + height;
107 }
reed@google.com20efde72011-05-09 17:00:02 +0000108
109 /**
110 * Make the largest representable rectangle
111 */
112 void setLargest() {
113 fLeft = fTop = SK_MinS32;
114 fRight = fBottom = SK_MaxS32;
115 }
116
117 /**
118 * Make the largest representable rectangle, but inverted (e.g. fLeft will
119 * be max 32bit and right will be min 32bit).
120 */
121 void setLargestInverted() {
122 fLeft = fTop = SK_MaxS32;
123 fRight = fBottom = SK_MinS32;
124 }
reed@google.com1d12b1f2011-03-03 13:23:35 +0000125
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 /** Offset set the rectangle by adding dx to its left and right,
127 and adding dy to its top and bottom.
128 */
reed@android.comda6fb322010-02-19 21:41:30 +0000129 void offset(int32_t dx, int32_t dy) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 fLeft += dx;
131 fTop += dy;
132 fRight += dx;
133 fBottom += dy;
134 }
135
reed@android.comda6fb322010-02-19 21:41:30 +0000136 void offset(const SkIPoint& delta) {
137 this->offset(delta.fX, delta.fY);
138 }
139
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
141 making the rectangle narrower. If dx is negative, then the sides are moved outwards,
142 making the rectangle wider. The same hods true for dy and the top and bottom.
143 */
reed@android.comda6fb322010-02-19 21:41:30 +0000144 void inset(int32_t dx, int32_t dy) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 fLeft += dx;
146 fTop += dy;
147 fRight -= dx;
148 fBottom -= dy;
149 }
reed@android.comda6fb322010-02-19 21:41:30 +0000150
reed@google.com20efde72011-05-09 17:00:02 +0000151 bool quickReject(int l, int t, int r, int b) const {
152 return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b;
153 }
154
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155 /** Returns true if (x,y) is inside the rectangle and the rectangle is not
156 empty. The left and top are considered to be inside, while the right
157 and bottom are not. Thus for the rectangle (0, 0, 5, 10), the
158 points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not.
159 */
reed@android.comda6fb322010-02-19 21:41:30 +0000160 bool contains(int32_t x, int32_t y) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 return (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) &&
162 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop);
163 }
164
165 /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle.
166 If either rectangle is empty, contains() returns false.
167 */
reed@android.comda6fb322010-02-19 21:41:30 +0000168 bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 return left < right && top < bottom && !this->isEmpty() && // check for empties
170 fLeft <= left && fTop <= top &&
171 fRight >= right && fBottom >= bottom;
172 }
173
174 /** Returns true if the specified rectangle r is inside or equal to this rectangle.
175 */
reed@android.comda6fb322010-02-19 21:41:30 +0000176 bool contains(const SkIRect& r) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 return !r.isEmpty() && !this->isEmpty() && // check for empties
178 fLeft <= r.fLeft && fTop <= r.fTop &&
179 fRight >= r.fRight && fBottom >= r.fBottom;
180 }
181
182 /** Return true if this rectangle contains the specified rectangle.
183 For speed, this method does not check if either this or the specified
184 rectangles are empty, and if either is, its return value is undefined.
185 In the debugging build however, we assert that both this and the
186 specified rectangles are non-empty.
187 */
188 bool containsNoEmptyCheck(int32_t left, int32_t top,
reed@android.comda6fb322010-02-19 21:41:30 +0000189 int32_t right, int32_t bottom) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190 SkASSERT(fLeft < fRight && fTop < fBottom);
191 SkASSERT(left < right && top < bottom);
192
193 return fLeft <= left && fTop <= top &&
194 fRight >= right && fBottom >= bottom;
195 }
196
197 /** If r intersects this rectangle, return true and set this rectangle to that
198 intersection, otherwise return false and do not change this rectangle.
199 If either rectangle is empty, do nothing and return false.
200 */
reed@android.comda6fb322010-02-19 21:41:30 +0000201 bool intersect(const SkIRect& r) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 SkASSERT(&r);
203 return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
204 }
205
206 /** If rectangles a and b intersect, return true and set this rectangle to
207 that intersection, otherwise return false and do not change this
208 rectangle. If either rectangle is empty, do nothing and return false.
209 */
reed@android.comda6fb322010-02-19 21:41:30 +0000210 bool intersect(const SkIRect& a, const SkIRect& b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211 SkASSERT(&a && &b);
212
213 if (!a.isEmpty() && !b.isEmpty() &&
reed@android.comda6fb322010-02-19 21:41:30 +0000214 a.fLeft < b.fRight && b.fLeft < a.fRight &&
215 a.fTop < b.fBottom && b.fTop < a.fBottom) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 fLeft = SkMax32(a.fLeft, b.fLeft);
217 fTop = SkMax32(a.fTop, b.fTop);
218 fRight = SkMin32(a.fRight, b.fRight);
219 fBottom = SkMin32(a.fBottom, b.fBottom);
220 return true;
221 }
222 return false;
223 }
224
225 /** If rectangles a and b intersect, return true and set this rectangle to
226 that intersection, otherwise return false and do not change this
227 rectangle. For speed, no check to see if a or b are empty is performed.
228 If either is, then the return result is undefined. In the debug build,
229 we assert that both rectangles are non-empty.
230 */
reed@android.comda6fb322010-02-19 21:41:30 +0000231 bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 SkASSERT(&a && &b);
233 SkASSERT(!a.isEmpty() && !b.isEmpty());
234
235 if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
reed@android.comda6fb322010-02-19 21:41:30 +0000236 a.fTop < b.fBottom && b.fTop < a.fBottom) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237 fLeft = SkMax32(a.fLeft, b.fLeft);
238 fTop = SkMax32(a.fTop, b.fTop);
239 fRight = SkMin32(a.fRight, b.fRight);
240 fBottom = SkMin32(a.fBottom, b.fBottom);
241 return true;
242 }
243 return false;
244 }
245
246 /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
247 return true and set this rectangle to that intersection,
248 otherwise return false and do not change this rectangle.
249 If either rectangle is empty, do nothing and return false.
250 */
reed@android.comda6fb322010-02-19 21:41:30 +0000251 bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 if (left < right && top < bottom && !this->isEmpty() &&
reed@android.comda6fb322010-02-19 21:41:30 +0000253 fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 if (fLeft < left) fLeft = left;
255 if (fTop < top) fTop = top;
256 if (fRight > right) fRight = right;
257 if (fBottom > bottom) fBottom = bottom;
258 return true;
259 }
260 return false;
261 }
262
263 /** Returns true if a and b are not empty, and they intersect
264 */
reed@android.comda6fb322010-02-19 21:41:30 +0000265 static bool Intersects(const SkIRect& a, const SkIRect& b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266 return !a.isEmpty() && !b.isEmpty() && // check for empties
267 a.fLeft < b.fRight && b.fLeft < a.fRight &&
268 a.fTop < b.fBottom && b.fTop < a.fBottom;
269 }
270
271 /** Update this rectangle to enclose itself and the specified rectangle.
272 If this rectangle is empty, just set it to the specified rectangle. If the specified
273 rectangle is empty, do nothing.
274 */
275 void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
276
277 /** Update this rectangle to enclose itself and the specified rectangle.
278 If this rectangle is empty, just set it to the specified rectangle. If the specified
279 rectangle is empty, do nothing.
280 */
reed@android.comda6fb322010-02-19 21:41:30 +0000281 void join(const SkIRect& r) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
283 }
284
285 /** Swap top/bottom or left/right if there are flipped.
286 This can be called if the edges are computed separately,
287 and may have crossed over each other.
288 When this returns, left <= right && top <= bottom
289 */
290 void sort();
reed@google.com20efde72011-05-09 17:00:02 +0000291
292 static const SkIRect& EmptyIRect() {
reed@google.com4b4fb3a2011-05-16 18:24:19 +0000293 static const SkIRect gEmpty = { 0, 0, 0, 0 };
reed@google.com20efde72011-05-09 17:00:02 +0000294 return gEmpty;
295 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296};
297
298/** \struct SkRect
299*/
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +0000300struct SK_API SkRect {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301 SkScalar fLeft, fTop, fRight, fBottom;
302
reed@android.com2687ae02010-04-12 21:21:59 +0000303 static SkRect MakeEmpty() {
304 SkRect r;
305 r.setEmpty();
306 return r;
307 }
308
309 static SkRect MakeWH(SkScalar w, SkScalar h) {
310 SkRect r;
311 r.set(0, 0, w, h);
312 return r;
313 }
314
reed@android.com233481e2010-02-24 01:49:13 +0000315 static SkRect MakeSize(const SkSize& size) {
316 SkRect r;
317 r.set(0, 0, size.width(), size.height());
318 return r;
319 }
320
321 static SkRect MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
322 SkRect rect;
323 rect.set(l, t, r, b);
324 return rect;
325 }
326
327 static SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
328 SkRect r;
329 r.set(x, y, x + w, y + h);
330 return r;
331 }
reed@android.com2687ae02010-04-12 21:21:59 +0000332
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 /** Return true if the rectangle's width or height are <= 0
334 */
335 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
wjmaclean@chromium.org116b2bc2011-02-07 17:48:37 +0000336 bool hasValidCoordinates() const;
reed@google.com20efde72011-05-09 17:00:02 +0000337 SkScalar left() const { return fLeft; }
338 SkScalar top() const { return fTop; }
339 SkScalar right() const { return fRight; }
340 SkScalar bottom() const { return fBottom; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341 SkScalar width() const { return fRight - fLeft; }
342 SkScalar height() const { return fBottom - fTop; }
343 SkScalar centerX() const { return SkScalarHalf(fLeft + fRight); }
344 SkScalar centerY() const { return SkScalarHalf(fTop + fBottom); }
345
reed@android.comda6fb322010-02-19 21:41:30 +0000346 friend int operator==(const SkRect& a, const SkRect& b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347 return !memcmp(&a, &b, sizeof(a));
348 }
reed@android.comda6fb322010-02-19 21:41:30 +0000349
350 friend int operator!=(const SkRect& a, const SkRect& b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 return memcmp(&a, &b, sizeof(a));
352 }
353
354 /** return the 4 points that enclose the rectangle
355 */
356 void toQuad(SkPoint quad[4]) const;
357
358 /** Set this rectangle to the empty rectangle (0,0,0,0)
359 */
360 void setEmpty() { memset(this, 0, sizeof(*this)); }
361
reed@android.comda6fb322010-02-19 21:41:30 +0000362 void set(const SkIRect& src) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 fLeft = SkIntToScalar(src.fLeft);
364 fTop = SkIntToScalar(src.fTop);
365 fRight = SkIntToScalar(src.fRight);
366 fBottom = SkIntToScalar(src.fBottom);
367 }
368
reed@android.comda6fb322010-02-19 21:41:30 +0000369 void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 fLeft = left;
371 fTop = top;
372 fRight = right;
373 fBottom = bottom;
374 }
reed@google.com20efde72011-05-09 17:00:02 +0000375 // alias for set(l, t, r, b)
376 void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
377 this->set(left, top, right, bottom);
378 }
379
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380 /** Initialize the rect with the 4 specified integers. The routine handles
381 converting them to scalars (by calling SkIntToScalar)
382 */
383 void iset(int left, int top, int right, int bottom) {
384 fLeft = SkIntToScalar(left);
385 fTop = SkIntToScalar(top);
386 fRight = SkIntToScalar(right);
387 fBottom = SkIntToScalar(bottom);
388 }
389
390 /** Set this rectangle to be the bounds of the array of points.
391 If the array is empty (count == 0), then set this rectangle
392 to the empty rectangle (0,0,0,0)
393 */
394 void set(const SkPoint pts[], int count);
395
reed@google.com20efde72011-05-09 17:00:02 +0000396 // alias for set(pts, count)
397 void setBounds(const SkPoint pts[], int count) {
398 this->set(pts, count);
399 }
400
reed@google.com1d12b1f2011-03-03 13:23:35 +0000401 void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
402 fLeft = x;
403 fTop = y;
404 fRight = x + width;
405 fBottom = y + height;
406 }
407
reed@google.com20efde72011-05-09 17:00:02 +0000408 /**
409 * Make the largest representable rectangle
410 */
411 void setLargest() {
412 fLeft = fTop = SK_ScalarMin;
413 fRight = fBottom = SK_ScalarMax;
414 }
415
416 /**
417 * Make the largest representable rectangle, but inverted (e.g. fLeft will
418 * be max and right will be min).
419 */
420 void setLargestInverted() {
421 fLeft = fTop = SK_ScalarMax;
422 fRight = fBottom = SK_ScalarMin;
423 }
424
reed@android.com8a1c16f2008-12-17 15:59:43 +0000425 /** Offset set the rectangle by adding dx to its left and right,
426 and adding dy to its top and bottom.
427 */
reed@android.comda6fb322010-02-19 21:41:30 +0000428 void offset(SkScalar dx, SkScalar dy) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429 fLeft += dx;
430 fTop += dy;
431 fRight += dx;
432 fBottom += dy;
433 }
434
reed@android.comda6fb322010-02-19 21:41:30 +0000435 void offset(const SkPoint& delta) {
436 this->offset(delta.fX, delta.fY);
437 }
438
reed@android.com8a1c16f2008-12-17 15:59:43 +0000439 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
440 making the rectangle narrower. If dx is negative, then the sides are moved outwards,
441 making the rectangle wider. The same hods true for dy and the top and bottom.
442 */
reed@android.comda6fb322010-02-19 21:41:30 +0000443 void inset(SkScalar dx, SkScalar dy) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444 fLeft += dx;
445 fTop += dy;
446 fRight -= dx;
447 fBottom -= dy;
448 }
449
450 /** If this rectangle intersects r, return true and set this rectangle to that
451 intersection, otherwise return false and do not change this rectangle.
452 If either rectangle is empty, do nothing and return false.
453 */
454 bool intersect(const SkRect& r);
455
456 /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
457 return true and set this rectangle to that intersection, otherwise return false
458 and do not change this rectangle.
459 If either rectangle is empty, do nothing and return false.
460 */
461 bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
462
reed@google.comaf8edcc2011-05-12 22:31:01 +0000463 /**
464 * Return true if this rectangle is not empty, and the specified sides of
465 * a rectangle are not empty, and they intersect.
466 */
reed@android.comda6fb322010-02-19 21:41:30 +0000467 bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000468 return // first check that both are not empty
469 left < right && top < bottom &&
470 fLeft < fRight && fTop < fBottom &&
471 // now check for intersection
472 fLeft < right && left < fRight &&
473 fTop < bottom && top < fBottom;
474 }
475
reed@google.comaf8edcc2011-05-12 22:31:01 +0000476 /**
477 * Return true if rectangles a and b are not empty and intersect.
478 */
reed@android.comda6fb322010-02-19 21:41:30 +0000479 static bool Intersects(const SkRect& a, const SkRect& b) {
reed@google.comaf8edcc2011-05-12 22:31:01 +0000480 return !a.isEmpty() && !b.isEmpty() &&
481 a.fLeft < b.fRight && b.fLeft < a.fRight &&
482 a.fTop < b.fBottom && b.fTop < a.fBottom;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000483 }
484
reed@google.comaf8edcc2011-05-12 22:31:01 +0000485 /**
486 * Update this rectangle to enclose itself and the specified rectangle.
487 * If this rectangle is empty, just set it to the specified rectangle.
488 * If the specified rectangle is empty, do nothing.
489 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000490 void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
491
492 /** Update this rectangle to enclose itself and the specified rectangle.
493 If this rectangle is empty, just set it to the specified rectangle. If the specified
494 rectangle is empty, do nothing.
495 */
reed@android.comda6fb322010-02-19 21:41:30 +0000496 void join(const SkRect& r) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000497 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
498 }
reed@google.com20efde72011-05-09 17:00:02 +0000499 // alias for join()
500 void growToInclude(const SkRect& r) { this->join(r); }
501
reed@google.comaf8edcc2011-05-12 22:31:01 +0000502 /**
503 * Grow the rect to include the specified (x,y). After this call, the
504 * following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
505 *
506 * This is close, but not quite the same contract as contains(), since
507 * contains() treats the left and top different from the right and bottom.
508 * contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
509 * that contains(x,y) always returns false if the rect is empty.
510 */
reed@google.com20efde72011-05-09 17:00:02 +0000511 void growToInclude(SkScalar x, SkScalar y) {
512 fLeft = SkMinScalar(x, fLeft);
bsalomon@google.comee9aa302011-05-09 22:32:52 +0000513 fRight = SkMaxScalar(x, fRight);
514 fTop = SkMinScalar(y, fTop);
reed@google.com20efde72011-05-09 17:00:02 +0000515 fBottom = SkMaxScalar(y, fBottom);
516 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000517
reed@google.comaf8edcc2011-05-12 22:31:01 +0000518 /**
519 * Returns true if (p.fX,p.fY) is inside the rectangle, and the rectangle
520 * is not empty.
521 *
522 * Contains treats the left and top differently from the right and bottom.
523 * The left and top coordinates of the rectangle are themselves considered
524 * to be inside, while the right and bottom are not. Thus for the rectangle
525 * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not.
526 */
reed@android.comda6fb322010-02-19 21:41:30 +0000527 bool contains(const SkPoint& p) const {
reed@google.comaf8edcc2011-05-12 22:31:01 +0000528 return !this->isEmpty() &&
529 fLeft <= p.fX && p.fX < fRight && fTop <= p.fY && p.fY < fBottom;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530 }
531
reed@google.comaf8edcc2011-05-12 22:31:01 +0000532 /**
533 * Returns true if (x,y) is inside the rectangle, and the rectangle
534 * is not empty.
535 *
536 * Contains treats the left and top differently from the right and bottom.
537 * The left and top coordinates of the rectangle are themselves considered
538 * to be inside, while the right and bottom are not. Thus for the rectangle
539 * {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not.
540 */
reed@android.comda6fb322010-02-19 21:41:30 +0000541 bool contains(SkScalar x, SkScalar y) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000542 return !this->isEmpty() &&
reed@google.comaf8edcc2011-05-12 22:31:01 +0000543 fLeft <= x && x < fRight && fTop <= y && y < fBottom;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544 }
545
reed@google.comaf8edcc2011-05-12 22:31:01 +0000546 /**
547 * Return true if this rectangle contains r, and if both rectangles are
548 * not empty.
549 */
reed@android.comda6fb322010-02-19 21:41:30 +0000550 bool contains(const SkRect& r) const {
reed@google.comaf8edcc2011-05-12 22:31:01 +0000551 return !r.isEmpty() && !this->isEmpty() &&
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552 fLeft <= r.fLeft && fTop <= r.fTop &&
553 fRight >= r.fRight && fBottom >= r.fBottom;
554 }
555
reed@google.comaf8edcc2011-05-12 22:31:01 +0000556 /**
557 * Set the dst rectangle by rounding this rectangle's coordinates to their
558 * nearest integer values using SkScalarRound.
559 */
reed@android.comda6fb322010-02-19 21:41:30 +0000560 void round(SkIRect* dst) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000561 SkASSERT(dst);
reed@google.comaf8edcc2011-05-12 22:31:01 +0000562 dst->set(SkScalarRound(fLeft), SkScalarRound(fTop),
563 SkScalarRound(fRight), SkScalarRound(fBottom));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000564 }
565
reed@google.comaf8edcc2011-05-12 22:31:01 +0000566 /**
567 * Set the dst rectangle by rounding "out" this rectangle, choosing the
568 * SkScalarFloor of top and left, and the SkScalarCeil of right and bottom.
569 */
reed@android.comda6fb322010-02-19 21:41:30 +0000570 void roundOut(SkIRect* dst) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000571 SkASSERT(dst);
reed@google.comaf8edcc2011-05-12 22:31:01 +0000572 dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop),
573 SkScalarCeil(fRight), SkScalarCeil(fBottom));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574 }
575
reed@google.comaf8edcc2011-05-12 22:31:01 +0000576 /**
577 * Swap top/bottom or left/right if there are flipped (i.e. if width()
578 * or height() would have returned a negative value.) This should be called
579 * if the edges are computed separately, and may have crossed over each
580 * other. When this returns, left <= right && top <= bottom
581 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000582 void sort();
583};
584
585#endif
586