OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
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 "SkGeometry.h" | 8 #include "SkGeometry.h" |
9 #include "SkMatrix.h" | 9 #include "SkMatrix.h" |
10 #include "SkNx.h" | 10 #include "SkNx.h" |
(...skipping 957 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
968 dst[3] = SkScalarInterp(ab, bc, t); | 968 dst[3] = SkScalarInterp(ab, bc, t); |
969 dst[6] = bc; | 969 dst[6] = bc; |
970 } | 970 } |
971 | 971 |
972 static void ratquad_mapTo3D(const SkPoint src[3], SkScalar w, SkP3D dst[]) { | 972 static void ratquad_mapTo3D(const SkPoint src[3], SkScalar w, SkP3D dst[]) { |
973 dst[0].set(src[0].fX * 1, src[0].fY * 1, 1); | 973 dst[0].set(src[0].fX * 1, src[0].fY * 1, 1); |
974 dst[1].set(src[1].fX * w, src[1].fY * w, w); | 974 dst[1].set(src[1].fX * w, src[1].fY * w, w); |
975 dst[2].set(src[2].fX * 1, src[2].fY * 1, 1); | 975 dst[2].set(src[2].fX * 1, src[2].fY * 1, 1); |
976 } | 976 } |
977 | 977 |
978 void SkConic::chopAt(SkScalar t, SkConic dst[2]) const { | 978 // return false if infinity or NaN is generated; caller must check |
| 979 bool SkConic::chopAt(SkScalar t, SkConic dst[2]) const { |
979 SkP3D tmp[3], tmp2[3]; | 980 SkP3D tmp[3], tmp2[3]; |
980 | 981 |
981 ratquad_mapTo3D(fPts, fW, tmp); | 982 ratquad_mapTo3D(fPts, fW, tmp); |
982 | 983 |
983 p3d_interp(&tmp[0].fX, &tmp2[0].fX, t); | 984 p3d_interp(&tmp[0].fX, &tmp2[0].fX, t); |
984 p3d_interp(&tmp[0].fY, &tmp2[0].fY, t); | 985 p3d_interp(&tmp[0].fY, &tmp2[0].fY, t); |
985 p3d_interp(&tmp[0].fZ, &tmp2[0].fZ, t); | 986 p3d_interp(&tmp[0].fZ, &tmp2[0].fZ, t); |
986 | 987 |
987 dst[0].fPts[0] = fPts[0]; | 988 dst[0].fPts[0] = fPts[0]; |
988 tmp2[0].projectDown(&dst[0].fPts[1]); | 989 tmp2[0].projectDown(&dst[0].fPts[1]); |
989 tmp2[1].projectDown(&dst[0].fPts[2]); dst[1].fPts[0] = dst[0].fPts[2]; | 990 tmp2[1].projectDown(&dst[0].fPts[2]); dst[1].fPts[0] = dst[0].fPts[2]; |
990 tmp2[2].projectDown(&dst[1].fPts[1]); | 991 tmp2[2].projectDown(&dst[1].fPts[1]); |
991 dst[1].fPts[2] = fPts[2]; | 992 dst[1].fPts[2] = fPts[2]; |
992 | 993 |
993 // to put in "standard form", where w0 and w2 are both 1, we compute the | 994 // to put in "standard form", where w0 and w2 are both 1, we compute the |
994 // new w1 as sqrt(w1*w1/w0*w2) | 995 // new w1 as sqrt(w1*w1/w0*w2) |
995 // or | 996 // or |
996 // w1 /= sqrt(w0*w2) | 997 // w1 /= sqrt(w0*w2) |
997 // | 998 // |
998 // However, in our case, we know that for dst[0]: | 999 // However, in our case, we know that for dst[0]: |
999 // w0 == 1, and for dst[1], w2 == 1 | 1000 // w0 == 1, and for dst[1], w2 == 1 |
1000 // | 1001 // |
1001 SkScalar root = SkScalarSqrt(tmp2[1].fZ); | 1002 SkScalar root = SkScalarSqrt(tmp2[1].fZ); |
1002 dst[0].fW = tmp2[0].fZ / root; | 1003 dst[0].fW = tmp2[0].fZ / root; |
1003 dst[1].fW = tmp2[2].fZ / root; | 1004 dst[1].fW = tmp2[2].fZ / root; |
| 1005 SkASSERT(sizeof(dst[0]) == sizeof(SkScalar) * 7); |
| 1006 SkASSERT(0 == offsetof(SkConic, fPts[0].fX)); |
| 1007 return SkScalarsAreFinite(&dst[0].fPts[0].fX, 7 * 2); |
1004 } | 1008 } |
1005 | 1009 |
1006 void SkConic::chopAt(SkScalar t1, SkScalar t2, SkConic* dst) const { | 1010 void SkConic::chopAt(SkScalar t1, SkScalar t2, SkConic* dst) const { |
1007 if (0 == t1 || 1 == t2) { | 1011 if (0 == t1 || 1 == t2) { |
1008 if (0 == t1 && 1 == t2) { | 1012 if (0 == t1 && 1 == t2) { |
1009 *dst = *this; | 1013 *dst = *this; |
| 1014 return; |
1010 } else { | 1015 } else { |
1011 SkConic pair[2]; | 1016 SkConic pair[2]; |
1012 this->chopAt(t1 ? t1 : t2, pair); | 1017 if (this->chopAt(t1 ? t1 : t2, pair)) { |
1013 *dst = pair[SkToBool(t1)]; | 1018 *dst = pair[SkToBool(t1)]; |
| 1019 return; |
| 1020 } |
1014 } | 1021 } |
1015 return; | |
1016 } | 1022 } |
1017 SkConicCoeff coeff(*this); | 1023 SkConicCoeff coeff(*this); |
1018 Sk2s tt1(t1); | 1024 Sk2s tt1(t1); |
1019 Sk2s aXY = coeff.fNumer.eval(tt1); | 1025 Sk2s aXY = coeff.fNumer.eval(tt1); |
1020 Sk2s aZZ = coeff.fDenom.eval(tt1); | 1026 Sk2s aZZ = coeff.fDenom.eval(tt1); |
1021 Sk2s midTT((t1 + t2) / 2); | 1027 Sk2s midTT((t1 + t2) / 2); |
1022 Sk2s dXY = coeff.fNumer.eval(midTT); | 1028 Sk2s dXY = coeff.fNumer.eval(midTT); |
1023 Sk2s dZZ = coeff.fDenom.eval(midTT); | 1029 Sk2s dZZ = coeff.fDenom.eval(midTT); |
1024 Sk2s tt2(t2); | 1030 Sk2s tt2(t2); |
1025 Sk2s cXY = coeff.fNumer.eval(tt2); | 1031 Sk2s cXY = coeff.fNumer.eval(tt2); |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1236 return conic_find_extrema(&fPts[0].fX, fW, t); | 1242 return conic_find_extrema(&fPts[0].fX, fW, t); |
1237 } | 1243 } |
1238 | 1244 |
1239 bool SkConic::findYExtrema(SkScalar* t) const { | 1245 bool SkConic::findYExtrema(SkScalar* t) const { |
1240 return conic_find_extrema(&fPts[0].fY, fW, t); | 1246 return conic_find_extrema(&fPts[0].fY, fW, t); |
1241 } | 1247 } |
1242 | 1248 |
1243 bool SkConic::chopAtXExtrema(SkConic dst[2]) const { | 1249 bool SkConic::chopAtXExtrema(SkConic dst[2]) const { |
1244 SkScalar t; | 1250 SkScalar t; |
1245 if (this->findXExtrema(&t)) { | 1251 if (this->findXExtrema(&t)) { |
1246 this->chopAt(t, dst); | 1252 if (!this->chopAt(t, dst)) { |
| 1253 // if chop can't return finite values, don't chop |
| 1254 return false; |
| 1255 } |
1247 // now clean-up the middle, since we know t was meant to be at | 1256 // now clean-up the middle, since we know t was meant to be at |
1248 // an X-extrema | 1257 // an X-extrema |
1249 SkScalar value = dst[0].fPts[2].fX; | 1258 SkScalar value = dst[0].fPts[2].fX; |
1250 dst[0].fPts[1].fX = value; | 1259 dst[0].fPts[1].fX = value; |
1251 dst[1].fPts[0].fX = value; | 1260 dst[1].fPts[0].fX = value; |
1252 dst[1].fPts[1].fX = value; | 1261 dst[1].fPts[1].fX = value; |
1253 return true; | 1262 return true; |
1254 } | 1263 } |
1255 return false; | 1264 return false; |
1256 } | 1265 } |
1257 | 1266 |
1258 bool SkConic::chopAtYExtrema(SkConic dst[2]) const { | 1267 bool SkConic::chopAtYExtrema(SkConic dst[2]) const { |
1259 SkScalar t; | 1268 SkScalar t; |
1260 if (this->findYExtrema(&t)) { | 1269 if (this->findYExtrema(&t)) { |
1261 this->chopAt(t, dst); | 1270 if (!this->chopAt(t, dst)) { |
| 1271 // if chop can't return finite values, don't chop |
| 1272 return false; |
| 1273 } |
1262 // now clean-up the middle, since we know t was meant to be at | 1274 // now clean-up the middle, since we know t was meant to be at |
1263 // an Y-extrema | 1275 // an Y-extrema |
1264 SkScalar value = dst[0].fPts[2].fY; | 1276 SkScalar value = dst[0].fPts[2].fY; |
1265 dst[0].fPts[1].fY = value; | 1277 dst[0].fPts[1].fY = value; |
1266 dst[1].fPts[0].fY = value; | 1278 dst[1].fPts[0].fY = value; |
1267 dst[1].fPts[1].fY = value; | 1279 dst[1].fPts[1].fY = value; |
1268 return true; | 1280 return true; |
1269 } | 1281 } |
1270 return false; | 1282 return false; |
1271 } | 1283 } |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1397 matrix.preScale(SK_Scalar1, -SK_Scalar1); | 1409 matrix.preScale(SK_Scalar1, -SK_Scalar1); |
1398 } | 1410 } |
1399 if (userMatrix) { | 1411 if (userMatrix) { |
1400 matrix.postConcat(*userMatrix); | 1412 matrix.postConcat(*userMatrix); |
1401 } | 1413 } |
1402 for (int i = 0; i < conicCount; ++i) { | 1414 for (int i = 0; i < conicCount; ++i) { |
1403 matrix.mapPoints(dst[i].fPts, 3); | 1415 matrix.mapPoints(dst[i].fPts, 3); |
1404 } | 1416 } |
1405 return conicCount; | 1417 return conicCount; |
1406 } | 1418 } |
OLD | NEW |