gfx/skia/trunk/include/core/SkRect.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2006 The Android Open Source Project
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9
michael@0 10 #ifndef SkRect_DEFINED
michael@0 11 #define SkRect_DEFINED
michael@0 12
michael@0 13 #include "SkPoint.h"
michael@0 14 #include "SkSize.h"
michael@0 15
michael@0 16 /** \struct SkIRect
michael@0 17
michael@0 18 SkIRect holds four 32 bit integer coordinates for a rectangle
michael@0 19 */
michael@0 20 struct SK_API SkIRect {
michael@0 21 int32_t fLeft, fTop, fRight, fBottom;
michael@0 22
michael@0 23 static SkIRect SK_WARN_UNUSED_RESULT MakeEmpty() {
michael@0 24 SkIRect r;
michael@0 25 r.setEmpty();
michael@0 26 return r;
michael@0 27 }
michael@0 28
michael@0 29 static SkIRect SK_WARN_UNUSED_RESULT MakeLargest() {
michael@0 30 SkIRect r;
michael@0 31 r.setLargest();
michael@0 32 return r;
michael@0 33 }
michael@0 34
michael@0 35 static SkIRect SK_WARN_UNUSED_RESULT MakeWH(int32_t w, int32_t h) {
michael@0 36 SkIRect r;
michael@0 37 r.set(0, 0, w, h);
michael@0 38 return r;
michael@0 39 }
michael@0 40
michael@0 41 static SkIRect SK_WARN_UNUSED_RESULT MakeSize(const SkISize& size) {
michael@0 42 SkIRect r;
michael@0 43 r.set(0, 0, size.width(), size.height());
michael@0 44 return r;
michael@0 45 }
michael@0 46
michael@0 47 static SkIRect SK_WARN_UNUSED_RESULT MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) {
michael@0 48 SkIRect rect;
michael@0 49 rect.set(l, t, r, b);
michael@0 50 return rect;
michael@0 51 }
michael@0 52
michael@0 53 static SkIRect SK_WARN_UNUSED_RESULT MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) {
michael@0 54 SkIRect r;
michael@0 55 r.set(x, y, x + w, y + h);
michael@0 56 return r;
michael@0 57 }
michael@0 58
michael@0 59 int left() const { return fLeft; }
michael@0 60 int top() const { return fTop; }
michael@0 61 int right() const { return fRight; }
michael@0 62 int bottom() const { return fBottom; }
michael@0 63
michael@0 64 /** return the left edge of the rect */
michael@0 65 int x() const { return fLeft; }
michael@0 66 /** return the top edge of the rect */
michael@0 67 int y() const { return fTop; }
michael@0 68 /**
michael@0 69 * Returns the rectangle's width. This does not check for a valid rect
michael@0 70 * (i.e. left <= right) so the result may be negative.
michael@0 71 */
michael@0 72 int width() const { return fRight - fLeft; }
michael@0 73
michael@0 74 /**
michael@0 75 * Returns the rectangle's height. This does not check for a valid rect
michael@0 76 * (i.e. top <= bottom) so the result may be negative.
michael@0 77 */
michael@0 78 int height() const { return fBottom - fTop; }
michael@0 79
michael@0 80 /**
michael@0 81 * Since the center of an integer rect may fall on a factional value, this
michael@0 82 * method is defined to return (right + left) >> 1.
michael@0 83 *
michael@0 84 * This is a specific "truncation" of the average, which is different than
michael@0 85 * (right + left) / 2 when the sum is negative.
michael@0 86 */
michael@0 87 int centerX() const { return (fRight + fLeft) >> 1; }
michael@0 88
michael@0 89 /**
michael@0 90 * Since the center of an integer rect may fall on a factional value, this
michael@0 91 * method is defined to return (bottom + top) >> 1
michael@0 92 *
michael@0 93 * This is a specific "truncation" of the average, which is different than
michael@0 94 * (bottom + top) / 2 when the sum is negative.
michael@0 95 */
michael@0 96 int centerY() const { return (fBottom + fTop) >> 1; }
michael@0 97
michael@0 98 /**
michael@0 99 * Return true if the rectangle's width or height are <= 0
michael@0 100 */
michael@0 101 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
michael@0 102
michael@0 103 bool isLargest() const { return SK_MinS32 == fLeft &&
michael@0 104 SK_MinS32 == fTop &&
michael@0 105 SK_MaxS32 == fRight &&
michael@0 106 SK_MaxS32 == fBottom; }
michael@0 107
michael@0 108 friend bool operator==(const SkIRect& a, const SkIRect& b) {
michael@0 109 return !memcmp(&a, &b, sizeof(a));
michael@0 110 }
michael@0 111
michael@0 112 friend bool operator!=(const SkIRect& a, const SkIRect& b) {
michael@0 113 return !(a == b);
michael@0 114 }
michael@0 115
michael@0 116 bool is16Bit() const {
michael@0 117 return SkIsS16(fLeft) && SkIsS16(fTop) &&
michael@0 118 SkIsS16(fRight) && SkIsS16(fBottom);
michael@0 119 }
michael@0 120
michael@0 121 /** Set the rectangle to (0,0,0,0)
michael@0 122 */
michael@0 123 void setEmpty() { memset(this, 0, sizeof(*this)); }
michael@0 124
michael@0 125 void set(int32_t left, int32_t top, int32_t right, int32_t bottom) {
michael@0 126 fLeft = left;
michael@0 127 fTop = top;
michael@0 128 fRight = right;
michael@0 129 fBottom = bottom;
michael@0 130 }
michael@0 131 // alias for set(l, t, r, b)
michael@0 132 void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) {
michael@0 133 this->set(left, top, right, bottom);
michael@0 134 }
michael@0 135
michael@0 136 void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) {
michael@0 137 fLeft = x;
michael@0 138 fTop = y;
michael@0 139 fRight = x + width;
michael@0 140 fBottom = y + height;
michael@0 141 }
michael@0 142
michael@0 143 /**
michael@0 144 * Make the largest representable rectangle
michael@0 145 */
michael@0 146 void setLargest() {
michael@0 147 fLeft = fTop = SK_MinS32;
michael@0 148 fRight = fBottom = SK_MaxS32;
michael@0 149 }
michael@0 150
michael@0 151 /**
michael@0 152 * Make the largest representable rectangle, but inverted (e.g. fLeft will
michael@0 153 * be max 32bit and right will be min 32bit).
michael@0 154 */
michael@0 155 void setLargestInverted() {
michael@0 156 fLeft = fTop = SK_MaxS32;
michael@0 157 fRight = fBottom = SK_MinS32;
michael@0 158 }
michael@0 159
michael@0 160 /** Offset set the rectangle by adding dx to its left and right,
michael@0 161 and adding dy to its top and bottom.
michael@0 162 */
michael@0 163 void offset(int32_t dx, int32_t dy) {
michael@0 164 fLeft += dx;
michael@0 165 fTop += dy;
michael@0 166 fRight += dx;
michael@0 167 fBottom += dy;
michael@0 168 }
michael@0 169
michael@0 170 void offset(const SkIPoint& delta) {
michael@0 171 this->offset(delta.fX, delta.fY);
michael@0 172 }
michael@0 173
michael@0 174 /**
michael@0 175 * Offset this rect such its new x() and y() will equal newX and newY.
michael@0 176 */
michael@0 177 void offsetTo(int32_t newX, int32_t newY) {
michael@0 178 fRight += newX - fLeft;
michael@0 179 fBottom += newY - fTop;
michael@0 180 fLeft = newX;
michael@0 181 fTop = newY;
michael@0 182 }
michael@0 183
michael@0 184 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
michael@0 185 making the rectangle narrower. If dx is negative, then the sides are moved outwards,
michael@0 186 making the rectangle wider. The same holds true for dy and the top and bottom.
michael@0 187 */
michael@0 188 void inset(int32_t dx, int32_t dy) {
michael@0 189 fLeft += dx;
michael@0 190 fTop += dy;
michael@0 191 fRight -= dx;
michael@0 192 fBottom -= dy;
michael@0 193 }
michael@0 194
michael@0 195 /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
michael@0 196 moved outwards, making the rectangle wider. If dx is negative, then the
michael@0 197 sides are moved inwards, making the rectangle narrower. The same holds
michael@0 198 true for dy and the top and bottom.
michael@0 199 */
michael@0 200 void outset(int32_t dx, int32_t dy) { this->inset(-dx, -dy); }
michael@0 201
michael@0 202 bool quickReject(int l, int t, int r, int b) const {
michael@0 203 return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b;
michael@0 204 }
michael@0 205
michael@0 206 /** Returns true if (x,y) is inside the rectangle and the rectangle is not
michael@0 207 empty. The left and top are considered to be inside, while the right
michael@0 208 and bottom are not. Thus for the rectangle (0, 0, 5, 10), the
michael@0 209 points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not.
michael@0 210 */
michael@0 211 bool contains(int32_t x, int32_t y) const {
michael@0 212 return (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) &&
michael@0 213 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop);
michael@0 214 }
michael@0 215
michael@0 216 /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle.
michael@0 217 If either rectangle is empty, contains() returns false.
michael@0 218 */
michael@0 219 bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const {
michael@0 220 return left < right && top < bottom && !this->isEmpty() && // check for empties
michael@0 221 fLeft <= left && fTop <= top &&
michael@0 222 fRight >= right && fBottom >= bottom;
michael@0 223 }
michael@0 224
michael@0 225 /** Returns true if the specified rectangle r is inside or equal to this rectangle.
michael@0 226 */
michael@0 227 bool contains(const SkIRect& r) const {
michael@0 228 return !r.isEmpty() && !this->isEmpty() && // check for empties
michael@0 229 fLeft <= r.fLeft && fTop <= r.fTop &&
michael@0 230 fRight >= r.fRight && fBottom >= r.fBottom;
michael@0 231 }
michael@0 232
michael@0 233 /** Return true if this rectangle contains the specified rectangle.
michael@0 234 For speed, this method does not check if either this or the specified
michael@0 235 rectangles are empty, and if either is, its return value is undefined.
michael@0 236 In the debugging build however, we assert that both this and the
michael@0 237 specified rectangles are non-empty.
michael@0 238 */
michael@0 239 bool containsNoEmptyCheck(int32_t left, int32_t top,
michael@0 240 int32_t right, int32_t bottom) const {
michael@0 241 SkASSERT(fLeft < fRight && fTop < fBottom);
michael@0 242 SkASSERT(left < right && top < bottom);
michael@0 243
michael@0 244 return fLeft <= left && fTop <= top &&
michael@0 245 fRight >= right && fBottom >= bottom;
michael@0 246 }
michael@0 247
michael@0 248 bool containsNoEmptyCheck(const SkIRect& r) const {
michael@0 249 return containsNoEmptyCheck(r.fLeft, r.fTop, r.fRight, r.fBottom);
michael@0 250 }
michael@0 251
michael@0 252 /** If r intersects this rectangle, return true and set this rectangle to that
michael@0 253 intersection, otherwise return false and do not change this rectangle.
michael@0 254 If either rectangle is empty, do nothing and return false.
michael@0 255 */
michael@0 256 bool intersect(const SkIRect& r) {
michael@0 257 SkASSERT(&r);
michael@0 258 return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
michael@0 259 }
michael@0 260
michael@0 261 /** If rectangles a and b intersect, return true and set this rectangle to
michael@0 262 that intersection, otherwise return false and do not change this
michael@0 263 rectangle. If either rectangle is empty, do nothing and return false.
michael@0 264 */
michael@0 265 bool intersect(const SkIRect& a, const SkIRect& b) {
michael@0 266 SkASSERT(&a && &b);
michael@0 267
michael@0 268 if (!a.isEmpty() && !b.isEmpty() &&
michael@0 269 a.fLeft < b.fRight && b.fLeft < a.fRight &&
michael@0 270 a.fTop < b.fBottom && b.fTop < a.fBottom) {
michael@0 271 fLeft = SkMax32(a.fLeft, b.fLeft);
michael@0 272 fTop = SkMax32(a.fTop, b.fTop);
michael@0 273 fRight = SkMin32(a.fRight, b.fRight);
michael@0 274 fBottom = SkMin32(a.fBottom, b.fBottom);
michael@0 275 return true;
michael@0 276 }
michael@0 277 return false;
michael@0 278 }
michael@0 279
michael@0 280 /** If rectangles a and b intersect, return true and set this rectangle to
michael@0 281 that intersection, otherwise return false and do not change this
michael@0 282 rectangle. For speed, no check to see if a or b are empty is performed.
michael@0 283 If either is, then the return result is undefined. In the debug build,
michael@0 284 we assert that both rectangles are non-empty.
michael@0 285 */
michael@0 286 bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
michael@0 287 SkASSERT(&a && &b);
michael@0 288 SkASSERT(!a.isEmpty() && !b.isEmpty());
michael@0 289
michael@0 290 if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
michael@0 291 a.fTop < b.fBottom && b.fTop < a.fBottom) {
michael@0 292 fLeft = SkMax32(a.fLeft, b.fLeft);
michael@0 293 fTop = SkMax32(a.fTop, b.fTop);
michael@0 294 fRight = SkMin32(a.fRight, b.fRight);
michael@0 295 fBottom = SkMin32(a.fBottom, b.fBottom);
michael@0 296 return true;
michael@0 297 }
michael@0 298 return false;
michael@0 299 }
michael@0 300
michael@0 301 /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
michael@0 302 return true and set this rectangle to that intersection,
michael@0 303 otherwise return false and do not change this rectangle.
michael@0 304 If either rectangle is empty, do nothing and return false.
michael@0 305 */
michael@0 306 bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
michael@0 307 if (left < right && top < bottom && !this->isEmpty() &&
michael@0 308 fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
michael@0 309 if (fLeft < left) fLeft = left;
michael@0 310 if (fTop < top) fTop = top;
michael@0 311 if (fRight > right) fRight = right;
michael@0 312 if (fBottom > bottom) fBottom = bottom;
michael@0 313 return true;
michael@0 314 }
michael@0 315 return false;
michael@0 316 }
michael@0 317
michael@0 318 /** Returns true if a and b are not empty, and they intersect
michael@0 319 */
michael@0 320 static bool Intersects(const SkIRect& a, const SkIRect& b) {
michael@0 321 return !a.isEmpty() && !b.isEmpty() && // check for empties
michael@0 322 a.fLeft < b.fRight && b.fLeft < a.fRight &&
michael@0 323 a.fTop < b.fBottom && b.fTop < a.fBottom;
michael@0 324 }
michael@0 325
michael@0 326 /**
michael@0 327 * Returns true if a and b intersect. debug-asserts that neither are empty.
michael@0 328 */
michael@0 329 static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
michael@0 330 SkASSERT(!a.isEmpty());
michael@0 331 SkASSERT(!b.isEmpty());
michael@0 332 return a.fLeft < b.fRight && b.fLeft < a.fRight &&
michael@0 333 a.fTop < b.fBottom && b.fTop < a.fBottom;
michael@0 334 }
michael@0 335
michael@0 336 /** Update this rectangle to enclose itself and the specified rectangle.
michael@0 337 If this rectangle is empty, just set it to the specified rectangle. If the specified
michael@0 338 rectangle is empty, do nothing.
michael@0 339 */
michael@0 340 void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
michael@0 341
michael@0 342 /** Update this rectangle to enclose itself and the specified rectangle.
michael@0 343 If this rectangle is empty, just set it to the specified rectangle. If the specified
michael@0 344 rectangle is empty, do nothing.
michael@0 345 */
michael@0 346 void join(const SkIRect& r) {
michael@0 347 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
michael@0 348 }
michael@0 349
michael@0 350 /** Swap top/bottom or left/right if there are flipped.
michael@0 351 This can be called if the edges are computed separately,
michael@0 352 and may have crossed over each other.
michael@0 353 When this returns, left <= right && top <= bottom
michael@0 354 */
michael@0 355 void sort();
michael@0 356
michael@0 357 static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() {
michael@0 358 static const SkIRect gEmpty = { 0, 0, 0, 0 };
michael@0 359 return gEmpty;
michael@0 360 }
michael@0 361 };
michael@0 362
michael@0 363 /** \struct SkRect
michael@0 364 */
michael@0 365 struct SK_API SkRect {
michael@0 366 SkScalar fLeft, fTop, fRight, fBottom;
michael@0 367
michael@0 368 static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() {
michael@0 369 SkRect r;
michael@0 370 r.setEmpty();
michael@0 371 return r;
michael@0 372 }
michael@0 373
michael@0 374 static SkRect SK_WARN_UNUSED_RESULT MakeLargest() {
michael@0 375 SkRect r;
michael@0 376 r.setLargest();
michael@0 377 return r;
michael@0 378 }
michael@0 379
michael@0 380 static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) {
michael@0 381 SkRect r;
michael@0 382 r.set(0, 0, w, h);
michael@0 383 return r;
michael@0 384 }
michael@0 385
michael@0 386 static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) {
michael@0 387 SkRect r;
michael@0 388 r.set(0, 0, size.width(), size.height());
michael@0 389 return r;
michael@0 390 }
michael@0 391
michael@0 392 static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
michael@0 393 SkRect rect;
michael@0 394 rect.set(l, t, r, b);
michael@0 395 return rect;
michael@0 396 }
michael@0 397
michael@0 398 static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
michael@0 399 SkRect r;
michael@0 400 r.set(x, y, x + w, y + h);
michael@0 401 return r;
michael@0 402 }
michael@0 403
michael@0 404 SK_ATTR_DEPRECATED("use Make()")
michael@0 405 static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) {
michael@0 406 SkRect r;
michael@0 407 r.set(SkIntToScalar(irect.fLeft),
michael@0 408 SkIntToScalar(irect.fTop),
michael@0 409 SkIntToScalar(irect.fRight),
michael@0 410 SkIntToScalar(irect.fBottom));
michael@0 411 return r;
michael@0 412 }
michael@0 413
michael@0 414 static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) {
michael@0 415 SkRect r;
michael@0 416 r.set(SkIntToScalar(irect.fLeft),
michael@0 417 SkIntToScalar(irect.fTop),
michael@0 418 SkIntToScalar(irect.fRight),
michael@0 419 SkIntToScalar(irect.fBottom));
michael@0 420 return r;
michael@0 421 }
michael@0 422
michael@0 423 /**
michael@0 424 * Return true if the rectangle's width or height are <= 0
michael@0 425 */
michael@0 426 bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
michael@0 427
michael@0 428 bool isLargest() const { return SK_ScalarMin == fLeft &&
michael@0 429 SK_ScalarMin == fTop &&
michael@0 430 SK_ScalarMax == fRight &&
michael@0 431 SK_ScalarMax == fBottom; }
michael@0 432
michael@0 433 /**
michael@0 434 * Returns true iff all values in the rect are finite. If any are
michael@0 435 * infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
michael@0 436 * returns false.
michael@0 437 */
michael@0 438 bool isFinite() const {
michael@0 439 float accum = 0;
michael@0 440 accum *= fLeft;
michael@0 441 accum *= fTop;
michael@0 442 accum *= fRight;
michael@0 443 accum *= fBottom;
michael@0 444
michael@0 445 // accum is either NaN or it is finite (zero).
michael@0 446 SkASSERT(0 == accum || !(accum == accum));
michael@0 447
michael@0 448 // value==value will be true iff value is not NaN
michael@0 449 // TODO: is it faster to say !accum or accum==accum?
michael@0 450 return accum == accum;
michael@0 451 }
michael@0 452
michael@0 453 SkScalar x() const { return fLeft; }
michael@0 454 SkScalar y() const { return fTop; }
michael@0 455 SkScalar left() const { return fLeft; }
michael@0 456 SkScalar top() const { return fTop; }
michael@0 457 SkScalar right() const { return fRight; }
michael@0 458 SkScalar bottom() const { return fBottom; }
michael@0 459 SkScalar width() const { return fRight - fLeft; }
michael@0 460 SkScalar height() const { return fBottom - fTop; }
michael@0 461 SkScalar centerX() const { return SkScalarHalf(fLeft + fRight); }
michael@0 462 SkScalar centerY() const { return SkScalarHalf(fTop + fBottom); }
michael@0 463
michael@0 464 friend bool operator==(const SkRect& a, const SkRect& b) {
michael@0 465 return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
michael@0 466 }
michael@0 467
michael@0 468 friend bool operator!=(const SkRect& a, const SkRect& b) {
michael@0 469 return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
michael@0 470 }
michael@0 471
michael@0 472 /** return the 4 points that enclose the rectangle (top-left, top-right, bottom-right,
michael@0 473 bottom-left). TODO: Consider adding param to control whether quad is CW or CCW.
michael@0 474 */
michael@0 475 void toQuad(SkPoint quad[4]) const;
michael@0 476
michael@0 477 /** Set this rectangle to the empty rectangle (0,0,0,0)
michael@0 478 */
michael@0 479 void setEmpty() { memset(this, 0, sizeof(*this)); }
michael@0 480
michael@0 481 void set(const SkIRect& src) {
michael@0 482 fLeft = SkIntToScalar(src.fLeft);
michael@0 483 fTop = SkIntToScalar(src.fTop);
michael@0 484 fRight = SkIntToScalar(src.fRight);
michael@0 485 fBottom = SkIntToScalar(src.fBottom);
michael@0 486 }
michael@0 487
michael@0 488 void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
michael@0 489 fLeft = left;
michael@0 490 fTop = top;
michael@0 491 fRight = right;
michael@0 492 fBottom = bottom;
michael@0 493 }
michael@0 494 // alias for set(l, t, r, b)
michael@0 495 void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
michael@0 496 this->set(left, top, right, bottom);
michael@0 497 }
michael@0 498
michael@0 499 /** Initialize the rect with the 4 specified integers. The routine handles
michael@0 500 converting them to scalars (by calling SkIntToScalar)
michael@0 501 */
michael@0 502 void iset(int left, int top, int right, int bottom) {
michael@0 503 fLeft = SkIntToScalar(left);
michael@0 504 fTop = SkIntToScalar(top);
michael@0 505 fRight = SkIntToScalar(right);
michael@0 506 fBottom = SkIntToScalar(bottom);
michael@0 507 }
michael@0 508
michael@0 509 /**
michael@0 510 * Set this rectangle to be left/top at 0,0, and have the specified width
michael@0 511 * and height (automatically converted to SkScalar).
michael@0 512 */
michael@0 513 void isetWH(int width, int height) {
michael@0 514 fLeft = fTop = 0;
michael@0 515 fRight = SkIntToScalar(width);
michael@0 516 fBottom = SkIntToScalar(height);
michael@0 517 }
michael@0 518
michael@0 519 /** Set this rectangle to be the bounds of the array of points.
michael@0 520 If the array is empty (count == 0), then set this rectangle
michael@0 521 to the empty rectangle (0,0,0,0)
michael@0 522 */
michael@0 523 void set(const SkPoint pts[], int count) {
michael@0 524 // set() had been checking for non-finite values, so keep that behavior
michael@0 525 // for now. Now that we have setBoundsCheck(), we may decide to make
michael@0 526 // set() be simpler/faster, and not check for those.
michael@0 527 (void)this->setBoundsCheck(pts, count);
michael@0 528 }
michael@0 529
michael@0 530 // alias for set(pts, count)
michael@0 531 void setBounds(const SkPoint pts[], int count) {
michael@0 532 (void)this->setBoundsCheck(pts, count);
michael@0 533 }
michael@0 534
michael@0 535 /**
michael@0 536 * Compute the bounds of the array of points, and set this rect to that
michael@0 537 * bounds and return true... unless a non-finite value is encountered,
michael@0 538 * in which case this rect is set to empty and false is returned.
michael@0 539 */
michael@0 540 bool setBoundsCheck(const SkPoint pts[], int count);
michael@0 541
michael@0 542 void set(const SkPoint& p0, const SkPoint& p1) {
michael@0 543 fLeft = SkMinScalar(p0.fX, p1.fX);
michael@0 544 fRight = SkMaxScalar(p0.fX, p1.fX);
michael@0 545 fTop = SkMinScalar(p0.fY, p1.fY);
michael@0 546 fBottom = SkMaxScalar(p0.fY, p1.fY);
michael@0 547 }
michael@0 548
michael@0 549 void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
michael@0 550 fLeft = x;
michael@0 551 fTop = y;
michael@0 552 fRight = x + width;
michael@0 553 fBottom = y + height;
michael@0 554 }
michael@0 555
michael@0 556 void setWH(SkScalar width, SkScalar height) {
michael@0 557 fLeft = 0;
michael@0 558 fTop = 0;
michael@0 559 fRight = width;
michael@0 560 fBottom = height;
michael@0 561 }
michael@0 562
michael@0 563 /**
michael@0 564 * Make the largest representable rectangle
michael@0 565 */
michael@0 566 void setLargest() {
michael@0 567 fLeft = fTop = SK_ScalarMin;
michael@0 568 fRight = fBottom = SK_ScalarMax;
michael@0 569 }
michael@0 570
michael@0 571 /**
michael@0 572 * Make the largest representable rectangle, but inverted (e.g. fLeft will
michael@0 573 * be max and right will be min).
michael@0 574 */
michael@0 575 void setLargestInverted() {
michael@0 576 fLeft = fTop = SK_ScalarMax;
michael@0 577 fRight = fBottom = SK_ScalarMin;
michael@0 578 }
michael@0 579
michael@0 580 /** Offset set the rectangle by adding dx to its left and right,
michael@0 581 and adding dy to its top and bottom.
michael@0 582 */
michael@0 583 void offset(SkScalar dx, SkScalar dy) {
michael@0 584 fLeft += dx;
michael@0 585 fTop += dy;
michael@0 586 fRight += dx;
michael@0 587 fBottom += dy;
michael@0 588 }
michael@0 589
michael@0 590 void offset(const SkPoint& delta) {
michael@0 591 this->offset(delta.fX, delta.fY);
michael@0 592 }
michael@0 593
michael@0 594 /**
michael@0 595 * Offset this rect such its new x() and y() will equal newX and newY.
michael@0 596 */
michael@0 597 void offsetTo(SkScalar newX, SkScalar newY) {
michael@0 598 fRight += newX - fLeft;
michael@0 599 fBottom += newY - fTop;
michael@0 600 fLeft = newX;
michael@0 601 fTop = newY;
michael@0 602 }
michael@0 603
michael@0 604 /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are
michael@0 605 moved inwards, making the rectangle narrower. If dx is negative, then
michael@0 606 the sides are moved outwards, making the rectangle wider. The same holds
michael@0 607 true for dy and the top and bottom.
michael@0 608 */
michael@0 609 void inset(SkScalar dx, SkScalar dy) {
michael@0 610 fLeft += dx;
michael@0 611 fTop += dy;
michael@0 612 fRight -= dx;
michael@0 613 fBottom -= dy;
michael@0 614 }
michael@0 615
michael@0 616 /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
michael@0 617 moved outwards, making the rectangle wider. If dx is negative, then the
michael@0 618 sides are moved inwards, making the rectangle narrower. The same holds
michael@0 619 true for dy and the top and bottom.
michael@0 620 */
michael@0 621 void outset(SkScalar dx, SkScalar dy) { this->inset(-dx, -dy); }
michael@0 622
michael@0 623 /** If this rectangle intersects r, return true and set this rectangle to that
michael@0 624 intersection, otherwise return false and do not change this rectangle.
michael@0 625 If either rectangle is empty, do nothing and return false.
michael@0 626 */
michael@0 627 bool intersect(const SkRect& r);
michael@0 628 bool intersect2(const SkRect& r);
michael@0 629
michael@0 630 /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
michael@0 631 return true and set this rectangle to that intersection, otherwise return false
michael@0 632 and do not change this rectangle.
michael@0 633 If either rectangle is empty, do nothing and return false.
michael@0 634 */
michael@0 635 bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
michael@0 636
michael@0 637 /**
michael@0 638 * Return true if this rectangle is not empty, and the specified sides of
michael@0 639 * a rectangle are not empty, and they intersect.
michael@0 640 */
michael@0 641 bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
michael@0 642 return // first check that both are not empty
michael@0 643 left < right && top < bottom &&
michael@0 644 fLeft < fRight && fTop < fBottom &&
michael@0 645 // now check for intersection
michael@0 646 fLeft < right && left < fRight &&
michael@0 647 fTop < bottom && top < fBottom;
michael@0 648 }
michael@0 649
michael@0 650 /** If rectangles a and b intersect, return true and set this rectangle to
michael@0 651 * that intersection, otherwise return false and do not change this
michael@0 652 * rectangle. If either rectangle is empty, do nothing and return false.
michael@0 653 */
michael@0 654 bool intersect(const SkRect& a, const SkRect& b);
michael@0 655
michael@0 656 /**
michael@0 657 * Return true if rectangles a and b are not empty and intersect.
michael@0 658 */
michael@0 659 static bool Intersects(const SkRect& a, const SkRect& b) {
michael@0 660 return !a.isEmpty() && !b.isEmpty() &&
michael@0 661 a.fLeft < b.fRight && b.fLeft < a.fRight &&
michael@0 662 a.fTop < b.fBottom && b.fTop < a.fBottom;
michael@0 663 }
michael@0 664
michael@0 665 /**
michael@0 666 * Update this rectangle to enclose itself and the specified rectangle.
michael@0 667 * If this rectangle is empty, just set it to the specified rectangle.
michael@0 668 * If the specified rectangle is empty, do nothing.
michael@0 669 */
michael@0 670 void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
michael@0 671
michael@0 672 /** Update this rectangle to enclose itself and the specified rectangle.
michael@0 673 If this rectangle is empty, just set it to the specified rectangle. If the specified
michael@0 674 rectangle is empty, do nothing.
michael@0 675 */
michael@0 676 void join(const SkRect& r) {
michael@0 677 this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
michael@0 678 }
michael@0 679 // alias for join()
michael@0 680 void growToInclude(const SkRect& r) { this->join(r); }
michael@0 681
michael@0 682 /**
michael@0 683 * Grow the rect to include the specified (x,y). After this call, the
michael@0 684 * following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
michael@0 685 *
michael@0 686 * This is close, but not quite the same contract as contains(), since
michael@0 687 * contains() treats the left and top different from the right and bottom.
michael@0 688 * contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
michael@0 689 * that contains(x,y) always returns false if the rect is empty.
michael@0 690 */
michael@0 691 void growToInclude(SkScalar x, SkScalar y) {
michael@0 692 fLeft = SkMinScalar(x, fLeft);
michael@0 693 fRight = SkMaxScalar(x, fRight);
michael@0 694 fTop = SkMinScalar(y, fTop);
michael@0 695 fBottom = SkMaxScalar(y, fBottom);
michael@0 696 }
michael@0 697
michael@0 698 /** Bulk version of growToInclude */
michael@0 699 void growToInclude(const SkPoint pts[], int count) {
michael@0 700 this->growToInclude(pts, sizeof(SkPoint), count);
michael@0 701 }
michael@0 702
michael@0 703 /** Bulk version of growToInclude with stride. */
michael@0 704 void growToInclude(const SkPoint pts[], size_t stride, int count) {
michael@0 705 SkASSERT(count >= 0);
michael@0 706 SkASSERT(stride >= sizeof(SkPoint));
michael@0 707 const SkPoint* end = (const SkPoint*)((intptr_t)pts + count * stride);
michael@0 708 for (; pts < end; pts = (const SkPoint*)((intptr_t)pts + stride)) {
michael@0 709 this->growToInclude(pts->fX, pts->fY);
michael@0 710 }
michael@0 711 }
michael@0 712
michael@0 713 /**
michael@0 714 * Return true if this rectangle contains r, and if both rectangles are
michael@0 715 * not empty.
michael@0 716 */
michael@0 717 bool contains(const SkRect& r) const {
michael@0 718 // todo: can we eliminate the this->isEmpty check?
michael@0 719 return !r.isEmpty() && !this->isEmpty() &&
michael@0 720 fLeft <= r.fLeft && fTop <= r.fTop &&
michael@0 721 fRight >= r.fRight && fBottom >= r.fBottom;
michael@0 722 }
michael@0 723
michael@0 724 /**
michael@0 725 * Set the dst rectangle by rounding this rectangle's coordinates to their
michael@0 726 * nearest integer values using SkScalarRoundToInt.
michael@0 727 */
michael@0 728 void round(SkIRect* dst) const {
michael@0 729 SkASSERT(dst);
michael@0 730 dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop),
michael@0 731 SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom));
michael@0 732 }
michael@0 733
michael@0 734 /**
michael@0 735 * Set the dst rectangle by rounding "out" this rectangle, choosing the
michael@0 736 * SkScalarFloor of top and left, and the SkScalarCeil of right and bottom.
michael@0 737 */
michael@0 738 void roundOut(SkIRect* dst) const {
michael@0 739 SkASSERT(dst);
michael@0 740 dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop),
michael@0 741 SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom));
michael@0 742 }
michael@0 743
michael@0 744 /**
michael@0 745 * Expand this rectangle by rounding its coordinates "out", choosing the
michael@0 746 * floor of top and left, and the ceil of right and bottom. If this rect
michael@0 747 * is already on integer coordinates, then it will be unchanged.
michael@0 748 */
michael@0 749 void roundOut() {
michael@0 750 this->set(SkScalarFloorToScalar(fLeft),
michael@0 751 SkScalarFloorToScalar(fTop),
michael@0 752 SkScalarCeilToScalar(fRight),
michael@0 753 SkScalarCeilToScalar(fBottom));
michael@0 754 }
michael@0 755
michael@0 756 /**
michael@0 757 * Set the dst rectangle by rounding "in" this rectangle, choosing the
michael@0 758 * ceil of top and left, and the floor of right and bottom. This does *not*
michael@0 759 * call sort(), so it is possible that the resulting rect is inverted...
michael@0 760 * e.g. left >= right or top >= bottom. Call isEmpty() to detect that.
michael@0 761 */
michael@0 762 void roundIn(SkIRect* dst) const {
michael@0 763 SkASSERT(dst);
michael@0 764 dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop),
michael@0 765 SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom));
michael@0 766 }
michael@0 767
michael@0 768 /**
michael@0 769 * Return a new SkIRect which is contains the rounded coordinates of this
michael@0 770 * rect using SkScalarRoundToInt.
michael@0 771 */
michael@0 772 SkIRect round() const {
michael@0 773 SkIRect ir;
michael@0 774 this->round(&ir);
michael@0 775 return ir;
michael@0 776 }
michael@0 777
michael@0 778 /**
michael@0 779 * Swap top/bottom or left/right if there are flipped (i.e. if width()
michael@0 780 * or height() would have returned a negative value.) This should be called
michael@0 781 * if the edges are computed separately, and may have crossed over each
michael@0 782 * other. When this returns, left <= right && top <= bottom
michael@0 783 */
michael@0 784 void sort();
michael@0 785
michael@0 786 /**
michael@0 787 * cast-safe way to treat the rect as an array of (4) SkScalars.
michael@0 788 */
michael@0 789 const SkScalar* asScalars() const { return &fLeft; }
michael@0 790 };
michael@0 791
michael@0 792 #endif

mercurial