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

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

Issue 1568063002: Revert of Fix handling of radii scaling to force the result to always be less (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 11 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/DrawPathTest.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 <cmath>
9 #include "SkRRect.h" 8 #include "SkRRect.h"
10 #include "SkMatrix.h" 9 #include "SkMatrix.h"
11 10
12 /////////////////////////////////////////////////////////////////////////////// 11 ///////////////////////////////////////////////////////////////////////////////
13 12
14 void SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { 13 void SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) {
15 fRect = rect; 14 fRect = rect;
16 fRect.sort(); 15 fRect.sort();
17 16
18 if (fRect.isEmpty() || !fRect.isFinite()) { 17 if (fRect.isEmpty() || !fRect.isFinite()) {
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 } 102 }
104 103
105 fRadii[kUpperLeft_Corner].set(leftRad, topRad); 104 fRadii[kUpperLeft_Corner].set(leftRad, topRad);
106 fRadii[kUpperRight_Corner].set(rightRad, topRad); 105 fRadii[kUpperRight_Corner].set(rightRad, topRad);
107 fRadii[kLowerRight_Corner].set(rightRad, bottomRad); 106 fRadii[kLowerRight_Corner].set(rightRad, bottomRad);
108 fRadii[kLowerLeft_Corner].set(leftRad, bottomRad); 107 fRadii[kLowerLeft_Corner].set(leftRad, bottomRad);
109 108
110 SkDEBUGCODE(this->validate();) 109 SkDEBUGCODE(this->validate();)
111 } 110 }
112 111
112 /*
113 * TODO: clean this guy up and possibly add to SkScalar.h
114 */
115 static inline SkScalar SkScalarDecULP(SkScalar value) {
116 #if SK_SCALAR_IS_FLOAT
117 return SkBits2Float(SkFloat2Bits(value) - 1);
118 #else
119 #error "need impl for doubles"
120 #endif
121 }
122
123 /**
124 * We need all combinations of predicates to be true to have a "safe" radius va lue.
125 */
126 static SkScalar clamp_radius_check_predicates(SkScalar rad, SkScalar min, SkScal ar max) {
127 SkASSERT(min < max);
128 if (rad > max - min || min + rad > max || max - rad < min) {
129 rad = SkScalarDecULP(rad);
130 }
131 return rad;
132 }
133
113 // These parameters intentionally double. Apropos crbug.com/463920, if one of th e 134 // These parameters intentionally double. Apropos crbug.com/463920, if one of th e
114 // radii is huge while the other is small, single precision math can completely 135 // radii is huge while the other is small, single precision math can completely
115 // miss the fact that a scale is required. 136 // miss the fact that a scale is required.
116 static double compute_min_scale(double rad1, double rad2, double limit, double c urMin) { 137 static double compute_min_scale(double rad1, double rad2, double limit, double c urMin) {
117 if ((rad1 + rad2) > limit) { 138 if ((rad1 + rad2) > limit) {
118 return SkTMin(curMin, limit / (rad1 + rad2)); 139 return SkTMin(curMin, limit / (rad1 + rad2));
119 } 140 }
120 return curMin; 141 return curMin;
121 } 142 }
122 143
123 // This code assumes that a and b fit in in a float, and therefore the resulting smaller value of
124 // a and b will fit in a float. The side of the rectangle may be larger than a f loat.
125 // Scale must be less than or equal to the ratio limit / (*a + *b).
126 static void adjust_radii(double limit, double scale, float* a, float* b) {
127 SkASSERT(scale < 1.0 && scale > 0.0);
128 // This check is conservative. (double)*a + (double)*b >= (double)(*a + *b)
129 if ((double)*a + (double)*b > limit) {
130 float* minRadius = a;
131 float* maxRadius = b;
132 // Force minRadius to be the smaller of the two.
133 if (*minRadius > *maxRadius) {
134 SkTSwap(minRadius, maxRadius);
135 }
136 // newMinRadius must be float in order to give the actual value of the r adius.
137 // The newMinRadius will always be smaller than limit. The largest that minRadius can be
138 // is 1/2 the ratio of minRadius : (minRadius + maxRadius), therefore in the resulting
139 // division, minRadius can be no larger than 1/2 limit + ULP.
140 float newMinRadius = *minRadius * scale;
141 *minRadius = newMinRadius;
142 // Because newMaxRadius is the result of a double to float conversion, i t can be larger
143 // than limit, but only by one ULP.
144 float newMaxRadius = (float)(limit - newMinRadius);
145 // If newMaxRadius is larger than the same value as a double, then it ne eds to be
146 // reduced by one ULP to be less than limit - newMinRadius.
147 // Note: nexttowardf is a c99 call and should be std::nexttoward, but th is is not
148 // implemented in the ARM compiler.
149 if (newMaxRadius > limit - newMinRadius) {
150 newMaxRadius = nexttowardf(newMaxRadius, limit - newMinRadius);
151 }
152 // This handles the case where both sets of radii are larger than a side by differing
153 // scale factors. The one that needs the larger scale factor (the radii with less
154 // overlap) will produce radii that are short enough just using the smal ler scale factor
155 // from the side where the radii overlap is larger.
156 *maxRadius = SkMinScalar(scale * *maxRadius, newMaxRadius);
157 } else {
158 *a *= scale;
159 *b *= scale;
160 }
161 SkASSERT(*a >= 0.0f && *b >= 0.0f);
162 SkASSERT((*a + *b) <= limit);
163 }
164
165 void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { 144 void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) {
166 fRect = rect; 145 fRect = rect;
167 fRect.sort(); 146 fRect.sort();
168 147
169 if (fRect.isEmpty() || !fRect.isFinite()) { 148 if (fRect.isEmpty() || !fRect.isFinite()) {
170 this->setEmpty(); 149 this->setEmpty();
171 return; 150 return;
172 } 151 }
173 152
174 if (!SkScalarsAreFinite(&radii[0].fX, 8)) { 153 if (!SkScalarsAreFinite(&radii[0].fX, 8)) {
(...skipping 29 matching lines...) Expand all
204 // that to scale down _all_ the radii. This algorithm is from the 183 // that to scale down _all_ the radii. This algorithm is from the
205 // W3 spec (http://www.w3.org/TR/css3-background/) section 5.5 - Overlapping 184 // W3 spec (http://www.w3.org/TR/css3-background/) section 5.5 - Overlapping
206 // Curves: 185 // Curves:
207 // "Let f = min(Li/Si), where i is one of { top, right, bottom, left }, 186 // "Let f = min(Li/Si), where i is one of { top, right, bottom, left },
208 // Si is the sum of the two corresponding radii of the corners on side i, 187 // Si is the sum of the two corresponding radii of the corners on side i,
209 // and Ltop = Lbottom = the width of the box, 188 // and Ltop = Lbottom = the width of the box,
210 // and Lleft = Lright = the height of the box. 189 // and Lleft = Lright = the height of the box.
211 // If f < 1, then all corner radii are reduced by multiplying them by f." 190 // If f < 1, then all corner radii are reduced by multiplying them by f."
212 double scale = 1.0; 191 double scale = 1.0;
213 192
214 // The sides of the rectangle may be larger than a float. 193 scale = compute_min_scale(fRadii[0].fX, fRadii[1].fX, fRect.width(), scale) ;
215 double width = (double)fRect.fRight - (double)fRect.fLeft; 194 scale = compute_min_scale(fRadii[1].fY, fRadii[2].fY, fRect.height(), scale) ;
216 double height = (double)fRect.fBottom - (double)fRect.fTop; 195 scale = compute_min_scale(fRadii[2].fX, fRadii[3].fX, fRect.width(), scale) ;
217 scale = compute_min_scale(fRadii[0].fX, fRadii[1].fX, width, scale); 196 scale = compute_min_scale(fRadii[3].fY, fRadii[0].fY, fRect.height(), scale) ;
218 scale = compute_min_scale(fRadii[1].fY, fRadii[2].fY, height, scale);
219 scale = compute_min_scale(fRadii[2].fX, fRadii[3].fX, width, scale);
220 scale = compute_min_scale(fRadii[3].fY, fRadii[0].fY, height, scale);
221 197
222 if (scale < 1.0) { 198 if (scale < 1.0) {
223 adjust_radii(width, scale, &fRadii[0].fX, &fRadii[1].fX); 199 for (int i = 0; i < 4; ++i) {
224 adjust_radii(height, scale, &fRadii[1].fY, &fRadii[2].fY); 200 fRadii[i].fX *= scale;
225 adjust_radii(width, scale, &fRadii[2].fX, &fRadii[3].fX); 201 fRadii[i].fY *= scale;
226 adjust_radii(height, scale, &fRadii[3].fY, &fRadii[0].fY); 202 }
227 } 203 }
228 204
205 // https://bug.skia.org/3239 -- its possible that we can hit the following i nconsistency:
206 // rad == bounds.bottom - bounds.top
207 // bounds.bottom - radius < bounds.top
208 // YIKES
209 // We need to detect and "fix" this now, otherwise we can have the following wackiness:
210 // path.addRRect(rrect);
211 // rrect.rect() != path.getBounds()
212 for (int i = 0; i < 4; ++i) {
213 fRadii[i].fX = clamp_radius_check_predicates(fRadii[i].fX, fRect.fLeft, fRect.fRight);
214 fRadii[i].fY = clamp_radius_check_predicates(fRadii[i].fY, fRect.fTop, f Rect.fBottom);
215 }
229 // At this point we're either oval, simple, or complex (not empty or rect). 216 // At this point we're either oval, simple, or complex (not empty or rect).
230 this->computeType(); 217 this->computeType();
231 218
232 SkDEBUGCODE(this->validate();) 219 SkDEBUGCODE(this->validate();)
233 } 220 }
234 221
235 // This method determines if a point known to be inside the RRect's bounds is 222 // This method determines if a point known to be inside the RRect's bounds is
236 // inside all the corners. 223 // inside all the corners.
237 bool SkRRect::checkCornerContainment(SkScalar x, SkScalar y) const { 224 bool SkRRect::checkCornerContainment(SkScalar x, SkScalar y) const {
238 SkPoint canonicalPt; // (x,y) translated to one of the quadrants 225 SkPoint canonicalPt; // (x,y) translated to one of the quadrants
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after
605 } 592 }
606 593
607 for (int i = 0; i < 4; ++i) { 594 for (int i = 0; i < 4; ++i) {
608 validate_radius_check_predicates(fRadii[i].fX, fRect.fLeft, fRect.fRight ); 595 validate_radius_check_predicates(fRadii[i].fX, fRect.fLeft, fRect.fRight );
609 validate_radius_check_predicates(fRadii[i].fY, fRect.fTop, fRect.fBottom ); 596 validate_radius_check_predicates(fRadii[i].fY, fRect.fTop, fRect.fBottom );
610 } 597 }
611 } 598 }
612 #endif // SK_DEBUG 599 #endif // SK_DEBUG
613 600
614 /////////////////////////////////////////////////////////////////////////////// 601 ///////////////////////////////////////////////////////////////////////////////
OLDNEW
« no previous file with comments | « no previous file | tests/DrawPathTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698