Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkRRect.h" | 8 #include "SkRRect.h" |
| 9 #include "SkMatrix.h" | 9 #include "SkMatrix.h" |
| 10 | 10 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 110 * TODO: clean this guy up and possibly add to SkScalar.h | 110 * TODO: clean this guy up and possibly add to SkScalar.h |
| 111 */ | 111 */ |
| 112 static inline SkScalar SkScalarDecULP(SkScalar value) { | 112 static inline SkScalar SkScalarDecULP(SkScalar value) { |
| 113 #if SK_SCALAR_IS_FLOAT | 113 #if SK_SCALAR_IS_FLOAT |
| 114 return SkBits2Float(SkFloat2Bits(value) - 1); | 114 return SkBits2Float(SkFloat2Bits(value) - 1); |
| 115 #else | 115 #else |
| 116 #error "need impl for doubles" | 116 #error "need impl for doubles" |
| 117 #endif | 117 #endif |
| 118 } | 118 } |
| 119 | 119 |
| 120 static SkScalar clamp_radius_add(SkScalar rad, SkScalar min, SkScalar max) { | 120 /** |
|
robertphillips
2015/02/13 22:31:03
missing spaces here ?
| |
| 121 SkASSERT(rad <= max - min); | 121 * We need all combinations of predicates to be true to have a "safe" radius va lue. |
| 122 if (min + rad > max) { | 122 */ |
| 123 static SkScalar clamp_radius_check_predicates(SkScalar rad, SkScalar min, SkScal ar max) { | |
| 124 SkASSERT(min < max); | |
| 125 if (rad > max - min || min + rad > max || max - rad < min) { | |
| 123 rad = SkScalarDecULP(rad); | 126 rad = SkScalarDecULP(rad); |
| 124 } | 127 } |
| 125 return rad; | 128 return rad; |
| 126 } | |
| 127 | |
| 128 static SkScalar clamp_radius_sub(SkScalar rad, SkScalar min, SkScalar max) { | |
| 129 SkASSERT(rad <= max - min); | |
| 130 if (max - rad < min) { | |
| 131 rad = SkScalarDecULP(rad); | |
| 132 } | |
| 133 return rad; | |
| 134 } | 129 } |
| 135 | 130 |
| 136 void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { | 131 void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { |
| 137 if (rect.isEmpty() || !rect.isFinite()) { | 132 if (rect.isEmpty() || !rect.isFinite()) { |
| 138 this->setEmpty(); | 133 this->setEmpty(); |
| 139 return; | 134 return; |
| 140 } | 135 } |
| 141 | 136 |
| 142 if (!SkScalarsAreFinite(&radii[0].fX, 8)) { | 137 if (!SkScalarsAreFinite(&radii[0].fX, 8)) { |
| 143 this->setRect(rect); // devolve into a simple rect | 138 this->setRect(rect); // devolve into a simple rect |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 204 } | 199 } |
| 205 } | 200 } |
| 206 | 201 |
| 207 // skbug.com/3239 -- its possible that we can hit the following inconsistenc y: | 202 // skbug.com/3239 -- its possible that we can hit the following inconsistenc y: |
| 208 // rad == bounds.bottom - bounds.top | 203 // rad == bounds.bottom - bounds.top |
| 209 // bounds.bottom - radius < bounds.top | 204 // bounds.bottom - radius < bounds.top |
| 210 // YIKES | 205 // YIKES |
| 211 // We need to detect and "fix" this now, otherwise we can have the following wackiness: | 206 // We need to detect and "fix" this now, otherwise we can have the following wackiness: |
| 212 // path.addRRect(rrect); | 207 // path.addRRect(rrect); |
| 213 // rrect.rect() != path.getBounds() | 208 // rrect.rect() != path.getBounds() |
| 214 fRadii[0].fX = clamp_radius_add(fRadii[0].fX, rect.fLeft, rect.fRight); | 209 for (int i = 0; i < 4; ++i) { |
| 215 fRadii[0].fY = clamp_radius_add(fRadii[0].fY, rect.fTop, rect.fBottom); | 210 fRadii[i].fX = clamp_radius_check_predicates(fRadii[i].fX, rect.fLeft, r ect.fRight); |
| 216 fRadii[1].fX = clamp_radius_sub(fRadii[1].fX, rect.fLeft, rect.fRight); | 211 fRadii[i].fY = clamp_radius_check_predicates(fRadii[i].fY, rect.fTop, re ct.fBottom); |
| 217 fRadii[1].fY = clamp_radius_add(fRadii[1].fY, rect.fTop, rect.fBottom); | 212 } |
| 218 fRadii[2].fX = clamp_radius_sub(fRadii[2].fX, rect.fLeft, rect.fRight); | |
| 219 fRadii[2].fY = clamp_radius_sub(fRadii[2].fY, rect.fTop, rect.fBottom); | |
| 220 fRadii[3].fX = clamp_radius_add(fRadii[3].fX, rect.fLeft, rect.fRight); | |
| 221 fRadii[3].fY = clamp_radius_sub(fRadii[3].fY, rect.fTop, rect.fBottom); | |
| 222 | |
| 223 // At this point we're either oval, simple, or complex (not empty or rect). | 213 // At this point we're either oval, simple, or complex (not empty or rect). |
| 224 this->computeType(); | 214 this->computeType(); |
| 225 | 215 |
| 226 SkDEBUGCODE(this->validate();) | 216 SkDEBUGCODE(this->validate();) |
| 227 } | 217 } |
| 228 | 218 |
| 229 // This method determines if a point known to be inside the RRect's bounds is | 219 // This method determines if a point known to be inside the RRect's bounds is |
| 230 // inside all the corners. | 220 // inside all the corners. |
| 231 bool SkRRect::checkCornerContainment(SkScalar x, SkScalar y) const { | 221 bool SkRRect::checkCornerContainment(SkScalar x, SkScalar y) const { |
| 232 SkPoint canonicalPt; // (x,y) translated to one of the quadrants | 222 SkPoint canonicalPt; // (x,y) translated to one of the quadrants |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 390 // use SkMatrix::rectStaysRect() to check for a valid transformation. | 380 // use SkMatrix::rectStaysRect() to check for a valid transformation. |
| 391 if (!matrix_only_scale_and_translate(matrix)) { | 381 if (!matrix_only_scale_and_translate(matrix)) { |
| 392 return false; | 382 return false; |
| 393 } | 383 } |
| 394 | 384 |
| 395 SkRect newRect; | 385 SkRect newRect; |
| 396 if (!matrix.mapRect(&newRect, fRect)) { | 386 if (!matrix.mapRect(&newRect, fRect)) { |
| 397 return false; | 387 return false; |
| 398 } | 388 } |
| 399 | 389 |
| 390 // The matrix may have scaled us to zero (or due to float madness, we now ha ve collapsed | |
|
robertphillips
2015/02/13 22:31:03
',' -> ')' ?
| |
| 391 // some dimension of the rect, so we need to check for that. | |
| 392 if (newRect.isEmpty()) { | |
| 393 dst->setEmpty(); | |
| 394 return true; | |
| 395 } | |
| 396 | |
| 400 // At this point, this is guaranteed to succeed, so we can modify dst. | 397 // At this point, this is guaranteed to succeed, so we can modify dst. |
| 401 dst->fRect = newRect; | 398 dst->fRect = newRect; |
| 402 | 399 |
| 403 // Since the only transforms that were allowed are scale and translate, the type | 400 // Since the only transforms that were allowed are scale and translate, the type |
| 404 // remains unchanged. | 401 // remains unchanged. |
| 405 dst->fType = fType; | 402 dst->fType = fType; |
| 406 | 403 |
| 407 if (kOval_Type == fType) { | 404 if (kOval_Type == fType) { |
| 408 for (int i = 0; i < 4; ++i) { | 405 for (int i = 0; i < 4; ++i) { |
| 409 dst->fRadii[i].fX = SkScalarHalf(newRect.width()); | 406 dst->fRadii[i].fX = SkScalarHalf(newRect.width()); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 521 } | 518 } |
| 522 line.append("\n"); | 519 line.append("\n"); |
| 523 } | 520 } |
| 524 line.append("};"); | 521 line.append("};"); |
| 525 SkDebugf("%s\n", line.c_str()); | 522 SkDebugf("%s\n", line.c_str()); |
| 526 } | 523 } |
| 527 | 524 |
| 528 /////////////////////////////////////////////////////////////////////////////// | 525 /////////////////////////////////////////////////////////////////////////////// |
| 529 | 526 |
| 530 #ifdef SK_DEBUG | 527 #ifdef SK_DEBUG |
| 528 /** | |
| 529 * We need all combinations of predicates to be true to have a "safe" radius va lue. | |
| 530 */ | |
| 531 static void validate_radius_check_predicates(SkScalar rad, SkScalar min, SkScala r max) { | |
| 532 SkASSERT(min <= max); | |
| 533 SkASSERT(rad <= max - min); | |
| 534 SkASSERT(min + rad <= max); | |
| 535 SkASSERT(max - rad >= min); | |
| 536 } | |
| 537 | |
| 531 void SkRRect::validate() const { | 538 void SkRRect::validate() const { |
| 532 bool allRadiiZero = (0 == fRadii[0].fX && 0 == fRadii[0].fY); | 539 bool allRadiiZero = (0 == fRadii[0].fX && 0 == fRadii[0].fY); |
| 533 bool allCornersSquare = (0 == fRadii[0].fX || 0 == fRadii[0].fY); | 540 bool allCornersSquare = (0 == fRadii[0].fX || 0 == fRadii[0].fY); |
| 534 bool allRadiiSame = true; | 541 bool allRadiiSame = true; |
| 535 | 542 |
| 536 for (int i = 1; i < 4; ++i) { | 543 for (int i = 1; i < 4; ++i) { |
| 537 if (0 != fRadii[i].fX || 0 != fRadii[i].fY) { | 544 if (0 != fRadii[i].fX || 0 != fRadii[i].fY) { |
| 538 allRadiiZero = false; | 545 allRadiiZero = false; |
| 539 } | 546 } |
| 540 | 547 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 574 SkASSERT(!fRect.isEmpty()); | 581 SkASSERT(!fRect.isEmpty()); |
| 575 SkASSERT(!allRadiiZero && !allRadiiSame && !allCornersSquare); | 582 SkASSERT(!allRadiiZero && !allRadiiSame && !allCornersSquare); |
| 576 SkASSERT(patchesOfNine); | 583 SkASSERT(patchesOfNine); |
| 577 break; | 584 break; |
| 578 case kComplex_Type: | 585 case kComplex_Type: |
| 579 SkASSERT(!fRect.isEmpty()); | 586 SkASSERT(!fRect.isEmpty()); |
| 580 SkASSERT(!allRadiiZero && !allRadiiSame && !allCornersSquare); | 587 SkASSERT(!allRadiiZero && !allRadiiSame && !allCornersSquare); |
| 581 SkASSERT(!patchesOfNine); | 588 SkASSERT(!patchesOfNine); |
| 582 break; | 589 break; |
| 583 } | 590 } |
| 591 | |
| 592 for (int i = 0; i < 4; ++i) { | |
| 593 validate_radius_check_predicates(fRadii[i].fX, fRect.fLeft, fRect.fRight ); | |
| 594 validate_radius_check_predicates(fRadii[i].fY, fRect.fTop, fRect.fBottom ); | |
| 595 } | |
| 584 } | 596 } |
| 585 #endif // SK_DEBUG | 597 #endif // SK_DEBUG |
| 586 | 598 |
| 587 /////////////////////////////////////////////////////////////////////////////// | 599 /////////////////////////////////////////////////////////////////////////////// |
| OLD | NEW |