| 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 |
| 11 /////////////////////////////////////////////////////////////////////////////// | 11 /////////////////////////////////////////////////////////////////////////////// |
| 12 | 12 |
| 13 void SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { | 13 void SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) { |
| 14 if (rect.isEmpty() || !rect.isFinite()) { | 14 fRect = rect; |
| 15 fRect.sort(); |
| 16 |
| 17 if (fRect.isEmpty() || !fRect.isFinite()) { |
| 15 this->setEmpty(); | 18 this->setEmpty(); |
| 16 return; | 19 return; |
| 17 } | 20 } |
| 18 | 21 |
| 19 if (!SkScalarsAreFinite(xRad, yRad)) { | 22 if (!SkScalarsAreFinite(xRad, yRad)) { |
| 20 xRad = yRad = 0; // devolve into a simple rect | 23 xRad = yRad = 0; // devolve into a simple rect |
| 21 } | 24 } |
| 22 if (xRad <= 0 || yRad <= 0) { | 25 if (xRad <= 0 || yRad <= 0) { |
| 23 // all corners are square in this case | 26 // all corners are square in this case |
| 24 this->setRect(rect); | 27 this->setRect(rect); |
| 25 return; | 28 return; |
| 26 } | 29 } |
| 27 | 30 |
| 28 if (rect.width() < xRad+xRad || rect.height() < yRad+yRad) { | 31 if (fRect.width() < xRad+xRad || fRect.height() < yRad+yRad) { |
| 29 SkScalar scale = SkMinScalar(rect.width() / (xRad + xRad), rect.height()
/ (yRad + yRad)); | 32 SkScalar scale = SkMinScalar(fRect.width() / (xRad + xRad), fRect.height
() / (yRad + yRad)); |
| 30 SkASSERT(scale < SK_Scalar1); | 33 SkASSERT(scale < SK_Scalar1); |
| 31 xRad = SkScalarMul(xRad, scale); | 34 xRad = SkScalarMul(xRad, scale); |
| 32 yRad = SkScalarMul(yRad, scale); | 35 yRad = SkScalarMul(yRad, scale); |
| 33 } | 36 } |
| 34 | 37 |
| 35 fRect = rect; | |
| 36 for (int i = 0; i < 4; ++i) { | 38 for (int i = 0; i < 4; ++i) { |
| 37 fRadii[i].set(xRad, yRad); | 39 fRadii[i].set(xRad, yRad); |
| 38 } | 40 } |
| 39 fType = kSimple_Type; | 41 fType = kSimple_Type; |
| 40 if (xRad >= SkScalarHalf(fRect.width()) && yRad >= SkScalarHalf(fRect.height
())) { | 42 if (xRad >= SkScalarHalf(fRect.width()) && yRad >= SkScalarHalf(fRect.height
())) { |
| 41 fType = kOval_Type; | 43 fType = kOval_Type; |
| 42 // TODO: assert that all the x&y radii are already W/2 & H/2 | 44 // TODO: assert that all the x&y radii are already W/2 & H/2 |
| 43 } | 45 } |
| 44 | 46 |
| 45 SkDEBUGCODE(this->validate();) | 47 SkDEBUGCODE(this->validate();) |
| 46 } | 48 } |
| 47 | 49 |
| 48 void SkRRect::setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad
, | 50 void SkRRect::setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad
, |
| 49 SkScalar rightRad, SkScalar bottomRad) { | 51 SkScalar rightRad, SkScalar bottomRad) { |
| 50 if (rect.isEmpty() || !rect.isFinite()) { | 52 fRect = rect; |
| 53 fRect.sort(); |
| 54 |
| 55 if (fRect.isEmpty() || !fRect.isFinite()) { |
| 51 this->setEmpty(); | 56 this->setEmpty(); |
| 52 return; | 57 return; |
| 53 } | 58 } |
| 54 | 59 |
| 55 const SkScalar array[4] = { leftRad, topRad, rightRad, bottomRad }; | 60 const SkScalar array[4] = { leftRad, topRad, rightRad, bottomRad }; |
| 56 if (!SkScalarsAreFinite(array, 4)) { | 61 if (!SkScalarsAreFinite(array, 4)) { |
| 57 this->setRect(rect); // devolve into a simple rect | 62 this->setRect(rect); // devolve into a simple rect |
| 58 return; | 63 return; |
| 59 } | 64 } |
| 60 | 65 |
| 61 leftRad = SkMaxScalar(leftRad, 0); | 66 leftRad = SkMaxScalar(leftRad, 0); |
| 62 topRad = SkMaxScalar(topRad, 0); | 67 topRad = SkMaxScalar(topRad, 0); |
| 63 rightRad = SkMaxScalar(rightRad, 0); | 68 rightRad = SkMaxScalar(rightRad, 0); |
| 64 bottomRad = SkMaxScalar(bottomRad, 0); | 69 bottomRad = SkMaxScalar(bottomRad, 0); |
| 65 | 70 |
| 66 SkScalar scale = SK_Scalar1; | 71 SkScalar scale = SK_Scalar1; |
| 67 if (leftRad + rightRad > rect.width()) { | 72 if (leftRad + rightRad > fRect.width()) { |
| 68 scale = rect.width() / (leftRad + rightRad); | 73 scale = fRect.width() / (leftRad + rightRad); |
| 69 } | 74 } |
| 70 if (topRad + bottomRad > rect.height()) { | 75 if (topRad + bottomRad > fRect.height()) { |
| 71 scale = SkMinScalar(scale, rect.height() / (topRad + bottomRad)); | 76 scale = SkMinScalar(scale, fRect.height() / (topRad + bottomRad)); |
| 72 } | 77 } |
| 73 | 78 |
| 74 if (scale < SK_Scalar1) { | 79 if (scale < SK_Scalar1) { |
| 75 leftRad = SkScalarMul(leftRad, scale); | 80 leftRad = SkScalarMul(leftRad, scale); |
| 76 topRad = SkScalarMul(topRad, scale); | 81 topRad = SkScalarMul(topRad, scale); |
| 77 rightRad = SkScalarMul(rightRad, scale); | 82 rightRad = SkScalarMul(rightRad, scale); |
| 78 bottomRad = SkScalarMul(bottomRad, scale); | 83 bottomRad = SkScalarMul(bottomRad, scale); |
| 79 } | 84 } |
| 80 | 85 |
| 81 if (leftRad == rightRad && topRad == bottomRad) { | 86 if (leftRad == rightRad && topRad == bottomRad) { |
| 82 if (leftRad >= SkScalarHalf(rect.width()) && topRad >= SkScalarHalf(rect
.height())) { | 87 if (leftRad >= SkScalarHalf(fRect.width()) && topRad >= SkScalarHalf(fRe
ct.height())) { |
| 83 fType = kOval_Type; | 88 fType = kOval_Type; |
| 84 } else if (0 == leftRad || 0 == topRad) { | 89 } else if (0 == leftRad || 0 == topRad) { |
| 85 // If the left and (by equality check above) right radii are zero th
en it is a rect. | 90 // If the left and (by equality check above) right radii are zero th
en it is a rect. |
| 86 // Same goes for top/bottom. | 91 // Same goes for top/bottom. |
| 87 fType = kRect_Type; | 92 fType = kRect_Type; |
| 88 leftRad = 0; | 93 leftRad = 0; |
| 89 topRad = 0; | 94 topRad = 0; |
| 90 rightRad = 0; | 95 rightRad = 0; |
| 91 bottomRad = 0; | 96 bottomRad = 0; |
| 92 } else { | 97 } else { |
| 93 fType = kSimple_Type; | 98 fType = kSimple_Type; |
| 94 } | 99 } |
| 95 } else { | 100 } else { |
| 96 fType = kNinePatch_Type; | 101 fType = kNinePatch_Type; |
| 97 } | 102 } |
| 98 | 103 |
| 99 fRect = rect; | |
| 100 fRadii[kUpperLeft_Corner].set(leftRad, topRad); | 104 fRadii[kUpperLeft_Corner].set(leftRad, topRad); |
| 101 fRadii[kUpperRight_Corner].set(rightRad, topRad); | 105 fRadii[kUpperRight_Corner].set(rightRad, topRad); |
| 102 fRadii[kLowerRight_Corner].set(rightRad, bottomRad); | 106 fRadii[kLowerRight_Corner].set(rightRad, bottomRad); |
| 103 fRadii[kLowerLeft_Corner].set(leftRad, bottomRad); | 107 fRadii[kLowerLeft_Corner].set(leftRad, bottomRad); |
| 104 | 108 |
| 105 SkDEBUGCODE(this->validate();) | 109 SkDEBUGCODE(this->validate();) |
| 106 } | 110 } |
| 107 | 111 |
| 108 /* | 112 /* |
| 109 * TODO: clean this guy up and possibly add to SkScalar.h | 113 * TODO: clean this guy up and possibly add to SkScalar.h |
| (...skipping 21 matching lines...) Expand all Loading... |
| 131 // 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 |
| 132 // miss the fact that a scale is required. | 136 // miss the fact that a scale is required. |
| 133 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) { |
| 134 if ((rad1 + rad2) > limit) { | 138 if ((rad1 + rad2) > limit) { |
| 135 return SkTMin(curMin, limit / (rad1 + rad2)); | 139 return SkTMin(curMin, limit / (rad1 + rad2)); |
| 136 } | 140 } |
| 137 return curMin; | 141 return curMin; |
| 138 } | 142 } |
| 139 | 143 |
| 140 void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { | 144 void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) { |
| 141 if (rect.isEmpty() || !rect.isFinite()) { | 145 fRect = rect; |
| 146 fRect.sort(); |
| 147 |
| 148 if (fRect.isEmpty() || !fRect.isFinite()) { |
| 142 this->setEmpty(); | 149 this->setEmpty(); |
| 143 return; | 150 return; |
| 144 } | 151 } |
| 145 | 152 |
| 146 if (!SkScalarsAreFinite(&radii[0].fX, 8)) { | 153 if (!SkScalarsAreFinite(&radii[0].fX, 8)) { |
| 147 this->setRect(rect); // devolve into a simple rect | 154 this->setRect(rect); // devolve into a simple rect |
| 148 return; | 155 return; |
| 149 } | 156 } |
| 150 | 157 |
| 151 fRect = rect; | |
| 152 memcpy(fRadii, radii, sizeof(fRadii)); | 158 memcpy(fRadii, radii, sizeof(fRadii)); |
| 153 | 159 |
| 154 bool allCornersSquare = true; | 160 bool allCornersSquare = true; |
| 155 | 161 |
| 156 // Clamp negative radii to zero | 162 // Clamp negative radii to zero |
| 157 for (int i = 0; i < 4; ++i) { | 163 for (int i = 0; i < 4; ++i) { |
| 158 if (fRadii[i].fX <= 0 || fRadii[i].fY <= 0) { | 164 if (fRadii[i].fX <= 0 || fRadii[i].fY <= 0) { |
| 159 // In this case we are being a little fast & loose. Since one of | 165 // In this case we are being a little fast & loose. Since one of |
| 160 // the radii is 0 the corner is square. However, the other radii | 166 // the radii is 0 the corner is square. However, the other radii |
| 161 // could still be non-zero and play in the global scale factor | 167 // could still be non-zero and play in the global scale factor |
| (...skipping 15 matching lines...) Expand all Loading... |
| 177 // 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 |
| 178 // 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 |
| 179 // Curves: | 185 // Curves: |
| 180 // "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 }, |
| 181 // 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, |
| 182 // and Ltop = Lbottom = the width of the box, | 188 // and Ltop = Lbottom = the width of the box, |
| 183 // and Lleft = Lright = the height of the box. | 189 // and Lleft = Lright = the height of the box. |
| 184 // 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." |
| 185 double scale = 1.0; | 191 double scale = 1.0; |
| 186 | 192 |
| 187 scale = compute_min_scale(fRadii[0].fX, fRadii[1].fX, rect.width(), scale); | 193 scale = compute_min_scale(fRadii[0].fX, fRadii[1].fX, fRect.width(), scale)
; |
| 188 scale = compute_min_scale(fRadii[1].fY, fRadii[2].fY, rect.height(), scale); | 194 scale = compute_min_scale(fRadii[1].fY, fRadii[2].fY, fRect.height(), scale)
; |
| 189 scale = compute_min_scale(fRadii[2].fX, fRadii[3].fX, rect.width(), scale); | 195 scale = compute_min_scale(fRadii[2].fX, fRadii[3].fX, fRect.width(), scale)
; |
| 190 scale = compute_min_scale(fRadii[3].fY, fRadii[0].fY, rect.height(), scale); | 196 scale = compute_min_scale(fRadii[3].fY, fRadii[0].fY, fRect.height(), scale)
; |
| 191 | 197 |
| 192 if (scale < 1.0) { | 198 if (scale < 1.0) { |
| 193 for (int i = 0; i < 4; ++i) { | 199 for (int i = 0; i < 4; ++i) { |
| 194 fRadii[i].fX *= scale; | 200 fRadii[i].fX *= scale; |
| 195 fRadii[i].fY *= scale; | 201 fRadii[i].fY *= scale; |
| 196 } | 202 } |
| 197 } | 203 } |
| 198 | 204 |
| 199 // skbug.com/3239 -- its possible that we can hit the following inconsistenc
y: | 205 // skbug.com/3239 -- its possible that we can hit the following inconsistenc
y: |
| 200 // rad == bounds.bottom - bounds.top | 206 // rad == bounds.bottom - bounds.top |
| 201 // bounds.bottom - radius < bounds.top | 207 // bounds.bottom - radius < bounds.top |
| 202 // YIKES | 208 // YIKES |
| 203 // We need to detect and "fix" this now, otherwise we can have the following
wackiness: | 209 // We need to detect and "fix" this now, otherwise we can have the following
wackiness: |
| 204 // path.addRRect(rrect); | 210 // path.addRRect(rrect); |
| 205 // rrect.rect() != path.getBounds() | 211 // rrect.rect() != path.getBounds() |
| 206 for (int i = 0; i < 4; ++i) { | 212 for (int i = 0; i < 4; ++i) { |
| 207 fRadii[i].fX = clamp_radius_check_predicates(fRadii[i].fX, rect.fLeft, r
ect.fRight); | 213 fRadii[i].fX = clamp_radius_check_predicates(fRadii[i].fX, fRect.fLeft,
fRect.fRight); |
| 208 fRadii[i].fY = clamp_radius_check_predicates(fRadii[i].fY, rect.fTop, re
ct.fBottom); | 214 fRadii[i].fY = clamp_radius_check_predicates(fRadii[i].fY, fRect.fTop, f
Rect.fBottom); |
| 209 } | 215 } |
| 210 // 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). |
| 211 this->computeType(); | 217 this->computeType(); |
| 212 | 218 |
| 213 SkDEBUGCODE(this->validate();) | 219 SkDEBUGCODE(this->validate();) |
| 214 } | 220 } |
| 215 | 221 |
| 216 // 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 |
| 217 // inside all the corners. | 223 // inside all the corners. |
| 218 bool SkRRect::checkCornerContainment(SkScalar x, SkScalar y) const { | 224 bool SkRRect::checkCornerContainment(SkScalar x, SkScalar y) const { |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 586 } | 592 } |
| 587 | 593 |
| 588 for (int i = 0; i < 4; ++i) { | 594 for (int i = 0; i < 4; ++i) { |
| 589 validate_radius_check_predicates(fRadii[i].fX, fRect.fLeft, fRect.fRight
); | 595 validate_radius_check_predicates(fRadii[i].fX, fRect.fLeft, fRect.fRight
); |
| 590 validate_radius_check_predicates(fRadii[i].fY, fRect.fTop, fRect.fBottom
); | 596 validate_radius_check_predicates(fRadii[i].fY, fRect.fTop, fRect.fBottom
); |
| 591 } | 597 } |
| 592 } | 598 } |
| 593 #endif // SK_DEBUG | 599 #endif // SK_DEBUG |
| 594 | 600 |
| 595 /////////////////////////////////////////////////////////////////////////////// | 601 /////////////////////////////////////////////////////////////////////////////// |
| OLD | NEW |