Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: src/core/SkRRect.cpp

Issue 921163003: fix more tricky-float cases in SkRRect validate (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/RoundRectTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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 ///////////////////////////////////////////////////////////////////////////////
OLDNEW
« no previous file with comments | « no previous file | tests/RoundRectTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698