1 /* 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" 21 #include "SkSize.h" 22 23 /** \struct SkIRect 24 25 SkIRect holds four 32 bit integer coordinates for a rectangle 26 */ 27 struct SkIRect { 28 int32_t fLeft, fTop, fRight, fBottom; 29 30 /** Return true if the rectangle's width or height are <= 0 31 */ isEmptySkIRect32 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } 33 34 /** Returns the rectangle's width. This does not check for a valid rectangle (i.e. left <= right) 35 so the result may be negative. 36 */ widthSkIRect37 int width() const { return fRight - fLeft; } 38 39 /** Returns the rectangle's height. This does not check for a valid rectangle (i.e. top <= bottom) 40 so the result may be negative. 41 */ heightSkIRect42 int height() const { return fBottom - fTop; } 43 44 friend int operator==(const SkIRect& a, const SkIRect& b) { 45 return !memcmp(&a, &b, sizeof(a)); 46 } 47 48 friend int operator!=(const SkIRect& a, const SkIRect& b) { 49 return memcmp(&a, &b, sizeof(a)); 50 } 51 is16BitSkIRect52 bool is16Bit() const { 53 return SkIsS16(fLeft) && SkIsS16(fTop) && 54 SkIsS16(fRight) && SkIsS16(fBottom); 55 } 56 57 /** Set the rectangle to (0,0,0,0) 58 */ setEmptySkIRect59 void setEmpty() { memset(this, 0, sizeof(*this)); } 60 setSkIRect61 void set(int32_t left, int32_t top, int32_t right, int32_t bottom) { 62 fLeft = left; 63 fTop = top; 64 fRight = right; 65 fBottom = bottom; 66 } 67 68 /** Offset set the rectangle by adding dx to its left and right, 69 and adding dy to its top and bottom. 70 */ offsetSkIRect71 void offset(int32_t dx, int32_t dy) { 72 fLeft += dx; 73 fTop += dy; 74 fRight += dx; 75 fBottom += dy; 76 } 77 offsetSkIRect78 void offset(const SkIPoint& delta) { 79 this->offset(delta.fX, delta.fY); 80 } 81 82 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards, 83 making the rectangle narrower. If dx is negative, then the sides are moved outwards, 84 making the rectangle wider. The same hods true for dy and the top and bottom. 85 */ insetSkIRect86 void inset(int32_t dx, int32_t dy) { 87 fLeft += dx; 88 fTop += dy; 89 fRight -= dx; 90 fBottom -= dy; 91 } 92 93 /** Returns true if (x,y) is inside the rectangle and the rectangle is not 94 empty. The left and top are considered to be inside, while the right 95 and bottom are not. Thus for the rectangle (0, 0, 5, 10), the 96 points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not. 97 */ containsSkIRect98 bool contains(int32_t x, int32_t y) const { 99 return (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) && 100 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop); 101 } 102 103 /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle. 104 If either rectangle is empty, contains() returns false. 105 */ containsSkIRect106 bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const { 107 return left < right && top < bottom && !this->isEmpty() && // check for empties 108 fLeft <= left && fTop <= top && 109 fRight >= right && fBottom >= bottom; 110 } 111 112 /** Returns true if the specified rectangle r is inside or equal to this rectangle. 113 */ containsSkIRect114 bool contains(const SkIRect& r) const { 115 return !r.isEmpty() && !this->isEmpty() && // check for empties 116 fLeft <= r.fLeft && fTop <= r.fTop && 117 fRight >= r.fRight && fBottom >= r.fBottom; 118 } 119 120 /** Return true if this rectangle contains the specified rectangle. 121 For speed, this method does not check if either this or the specified 122 rectangles are empty, and if either is, its return value is undefined. 123 In the debugging build however, we assert that both this and the 124 specified rectangles are non-empty. 125 */ containsNoEmptyCheckSkIRect126 bool containsNoEmptyCheck(int32_t left, int32_t top, 127 int32_t right, int32_t bottom) const { 128 SkASSERT(fLeft < fRight && fTop < fBottom); 129 SkASSERT(left < right && top < bottom); 130 131 return fLeft <= left && fTop <= top && 132 fRight >= right && fBottom >= bottom; 133 } 134 135 /** If r intersects this rectangle, return true and set this rectangle to that 136 intersection, otherwise return false and do not change this rectangle. 137 If either rectangle is empty, do nothing and return false. 138 */ intersectSkIRect139 bool intersect(const SkIRect& r) { 140 SkASSERT(&r); 141 return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom); 142 } 143 144 /** If rectangles a and b intersect, return true and set this rectangle to 145 that intersection, otherwise return false and do not change this 146 rectangle. If either rectangle is empty, do nothing and return false. 147 */ intersectSkIRect148 bool intersect(const SkIRect& a, const SkIRect& b) { 149 SkASSERT(&a && &b); 150 151 if (!a.isEmpty() && !b.isEmpty() && 152 a.fLeft < b.fRight && b.fLeft < a.fRight && 153 a.fTop < b.fBottom && b.fTop < a.fBottom) { 154 fLeft = SkMax32(a.fLeft, b.fLeft); 155 fTop = SkMax32(a.fTop, b.fTop); 156 fRight = SkMin32(a.fRight, b.fRight); 157 fBottom = SkMin32(a.fBottom, b.fBottom); 158 return true; 159 } 160 return false; 161 } 162 163 /** If rectangles a and b intersect, return true and set this rectangle to 164 that intersection, otherwise return false and do not change this 165 rectangle. For speed, no check to see if a or b are empty is performed. 166 If either is, then the return result is undefined. In the debug build, 167 we assert that both rectangles are non-empty. 168 */ intersectNoEmptyCheckSkIRect169 bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) { 170 SkASSERT(&a && &b); 171 SkASSERT(!a.isEmpty() && !b.isEmpty()); 172 173 if (a.fLeft < b.fRight && b.fLeft < a.fRight && 174 a.fTop < b.fBottom && b.fTop < a.fBottom) { 175 fLeft = SkMax32(a.fLeft, b.fLeft); 176 fTop = SkMax32(a.fTop, b.fTop); 177 fRight = SkMin32(a.fRight, b.fRight); 178 fBottom = SkMin32(a.fBottom, b.fBottom); 179 return true; 180 } 181 return false; 182 } 183 184 /** If the rectangle specified by left,top,right,bottom intersects this rectangle, 185 return true and set this rectangle to that intersection, 186 otherwise return false and do not change this rectangle. 187 If either rectangle is empty, do nothing and return false. 188 */ intersectSkIRect189 bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) { 190 if (left < right && top < bottom && !this->isEmpty() && 191 fLeft < right && left < fRight && fTop < bottom && top < fBottom) { 192 if (fLeft < left) fLeft = left; 193 if (fTop < top) fTop = top; 194 if (fRight > right) fRight = right; 195 if (fBottom > bottom) fBottom = bottom; 196 return true; 197 } 198 return false; 199 } 200 201 /** Returns true if a and b are not empty, and they intersect 202 */ IntersectsSkIRect203 static bool Intersects(const SkIRect& a, const SkIRect& b) { 204 return !a.isEmpty() && !b.isEmpty() && // check for empties 205 a.fLeft < b.fRight && b.fLeft < a.fRight && 206 a.fTop < b.fBottom && b.fTop < a.fBottom; 207 } 208 209 /** Update this rectangle to enclose itself and the specified rectangle. 210 If this rectangle is empty, just set it to the specified rectangle. If the specified 211 rectangle is empty, do nothing. 212 */ 213 void join(int32_t left, int32_t top, int32_t right, int32_t bottom); 214 215 /** Update this rectangle to enclose itself and the specified rectangle. 216 If this rectangle is empty, just set it to the specified rectangle. If the specified 217 rectangle is empty, do nothing. 218 */ joinSkIRect219 void join(const SkIRect& r) { 220 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); 221 } 222 223 /** Swap top/bottom or left/right if there are flipped. 224 This can be called if the edges are computed separately, 225 and may have crossed over each other. 226 When this returns, left <= right && top <= bottom 227 */ 228 void sort(); 229 }; 230 231 /** \struct SkRect 232 */ 233 struct SkRect { 234 SkScalar fLeft, fTop, fRight, fBottom; 235 MakeSizeSkRect236 static SkRect MakeSize(const SkSize& size) { 237 SkRect r; 238 r.set(0, 0, size.width(), size.height()); 239 return r; 240 } 241 MakeLTRBSkRect242 static SkRect MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) { 243 SkRect rect; 244 rect.set(l, t, r, b); 245 return rect; 246 } 247 MakeXYWHSkRect248 static SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) { 249 SkRect r; 250 r.set(x, y, x + w, y + h); 251 return r; 252 } 253 254 /** Return true if the rectangle's width or height are <= 0 255 */ isEmptySkRect256 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; } widthSkRect257 SkScalar width() const { return fRight - fLeft; } heightSkRect258 SkScalar height() const { return fBottom - fTop; } centerXSkRect259 SkScalar centerX() const { return SkScalarHalf(fLeft + fRight); } centerYSkRect260 SkScalar centerY() const { return SkScalarHalf(fTop + fBottom); } 261 262 friend int operator==(const SkRect& a, const SkRect& b) { 263 return !memcmp(&a, &b, sizeof(a)); 264 } 265 266 friend int operator!=(const SkRect& a, const SkRect& b) { 267 return memcmp(&a, &b, sizeof(a)); 268 } 269 270 /** return the 4 points that enclose the rectangle 271 */ 272 void toQuad(SkPoint quad[4]) const; 273 274 /** Set this rectangle to the empty rectangle (0,0,0,0) 275 */ setEmptySkRect276 void setEmpty() { memset(this, 0, sizeof(*this)); } 277 setSkRect278 void set(const SkIRect& src) { 279 fLeft = SkIntToScalar(src.fLeft); 280 fTop = SkIntToScalar(src.fTop); 281 fRight = SkIntToScalar(src.fRight); 282 fBottom = SkIntToScalar(src.fBottom); 283 } 284 setSkRect285 void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 286 fLeft = left; 287 fTop = top; 288 fRight = right; 289 fBottom = bottom; 290 } 291 292 /** Initialize the rect with the 4 specified integers. The routine handles 293 converting them to scalars (by calling SkIntToScalar) 294 */ isetSkRect295 void iset(int left, int top, int right, int bottom) { 296 fLeft = SkIntToScalar(left); 297 fTop = SkIntToScalar(top); 298 fRight = SkIntToScalar(right); 299 fBottom = SkIntToScalar(bottom); 300 } 301 302 /** Set this rectangle to be the bounds of the array of points. 303 If the array is empty (count == 0), then set this rectangle 304 to the empty rectangle (0,0,0,0) 305 */ 306 void set(const SkPoint pts[], int count); 307 308 /** Offset set the rectangle by adding dx to its left and right, 309 and adding dy to its top and bottom. 310 */ offsetSkRect311 void offset(SkScalar dx, SkScalar dy) { 312 fLeft += dx; 313 fTop += dy; 314 fRight += dx; 315 fBottom += dy; 316 } 317 offsetSkRect318 void offset(const SkPoint& delta) { 319 this->offset(delta.fX, delta.fY); 320 } 321 322 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards, 323 making the rectangle narrower. If dx is negative, then the sides are moved outwards, 324 making the rectangle wider. The same hods true for dy and the top and bottom. 325 */ insetSkRect326 void inset(SkScalar dx, SkScalar dy) { 327 fLeft += dx; 328 fTop += dy; 329 fRight -= dx; 330 fBottom -= dy; 331 } 332 333 /** If this rectangle intersects r, return true and set this rectangle to that 334 intersection, otherwise return false and do not change this rectangle. 335 If either rectangle is empty, do nothing and return false. 336 */ 337 bool intersect(const SkRect& r); 338 339 /** If this rectangle intersects the rectangle specified by left, top, right, bottom, 340 return true and set this rectangle to that intersection, otherwise return false 341 and do not change this rectangle. 342 If either rectangle is empty, do nothing and return false. 343 */ 344 bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 345 346 /** Return true if this rectangle is not empty, and the specified sides of 347 a rectangle are not empty, and they intersect. 348 */ intersectsSkRect349 bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const { 350 return // first check that both are not empty 351 left < right && top < bottom && 352 fLeft < fRight && fTop < fBottom && 353 // now check for intersection 354 fLeft < right && left < fRight && 355 fTop < bottom && top < fBottom; 356 } 357 358 /** Return true if rectangles a and b are not empty and intersect. 359 */ IntersectsSkRect360 static bool Intersects(const SkRect& a, const SkRect& b) { 361 return !a.isEmpty() && !b.isEmpty() && // check for empties 362 a.fLeft < b.fRight && b.fLeft < a.fRight && 363 a.fTop < b.fBottom && b.fTop < a.fBottom; 364 } 365 366 /** Update this rectangle to enclose itself and the specified rectangle. 367 If this rectangle is empty, just set it to the specified rectangle. If the specified 368 rectangle is empty, do nothing. 369 */ 370 void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom); 371 372 /** Update this rectangle to enclose itself and the specified rectangle. 373 If this rectangle is empty, just set it to the specified rectangle. If the specified 374 rectangle is empty, do nothing. 375 */ joinSkRect376 void join(const SkRect& r) { 377 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom); 378 } 379 380 /** Returns true if (p.fX,p.fY) is inside the rectangle. The left and top coordinates of 381 the rectangle are considered to be inside, while the right and bottom coordinates 382 are not. Thus for the rectangle (0, 0, 5, 10), the points (0,0) and (0,9) are inside, 383 while (-1,0) and (5,9) are not. 384 If this rectangle is empty, return false. 385 */ containsSkRect386 bool contains(const SkPoint& p) const { 387 return !this->isEmpty() && 388 fLeft <= p.fX && p.fX < fRight && 389 fTop <= p.fY && p.fY < fBottom; 390 } 391 392 /** Returns true if (x,y) is inside the rectangle. The left and top coordinates of 393 the rectangle are considered to be inside, while the right and bottom coordinates 394 are not. Thus for the rectangle (0, 0, 5, 10), the points (0,0) and (0,9) are inside, 395 while (-1,0) and (5,9) are not. 396 If this rectangle is empty, return false. 397 */ containsSkRect398 bool contains(SkScalar x, SkScalar y) const { 399 return !this->isEmpty() && 400 fLeft <= x && x < fRight && 401 fTop <= y && y < fBottom; 402 } 403 404 /** Return true if this rectangle contains r. 405 If either rectangle is empty, return false. 406 */ containsSkRect407 bool contains(const SkRect& r) const { 408 return !r.isEmpty() && !this->isEmpty() && // check for empties 409 fLeft <= r.fLeft && fTop <= r.fTop && 410 fRight >= r.fRight && fBottom >= r.fBottom; 411 } 412 413 /** Set the dst integer rectangle by rounding this rectangle's coordinates 414 to their nearest integer values. 415 */ roundSkRect416 void round(SkIRect* dst) const { 417 SkASSERT(dst); 418 dst->set(SkScalarRound(fLeft), SkScalarRound(fTop), SkScalarRound(fRight), SkScalarRound(fBottom)); 419 } 420 421 /** Set the dst integer rectangle by rounding "out" this rectangle, choosing the floor of top and left, 422 and the ceiling of right and bototm. 423 */ roundOutSkRect424 void roundOut(SkIRect* dst) const { 425 SkASSERT(dst); 426 dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop), SkScalarCeil(fRight), SkScalarCeil(fBottom)); 427 } 428 429 /** Swap top/bottom or left/right if there are flipped. 430 This can be called if the edges are computed separately, 431 and may have crossed over each other. 432 When this returns, left <= right && top <= bottom 433 */ 434 void sort(); 435 }; 436 437 #endif 438 439