| Index: src/core/SkMatrix.cpp
|
| diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
|
| index 3caf51a0cfa89eed47cc7815c21277aaad7a0352..474f272255d284a218e13ee368d53d699c5f281a 100644
|
| --- a/src/core/SkMatrix.cpp
|
| +++ b/src/core/SkMatrix.cpp
|
| @@ -1857,45 +1857,71 @@ bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| -SkScalar SkMatrix::getMaxStretch() const {
|
| - TypeMask mask = this->getType();
|
| +enum MinOrMax {
|
| + kMin_MinOrMax,
|
| + kMax_MinOrMax
|
| +};
|
|
|
| - if (this->hasPerspective()) {
|
| +template <MinOrMax MIN_OR_MAX> SkScalar get_stretch_factor(SkMatrix::TypeMask typeMask,
|
| + const SkScalar m[9]) {
|
| + if (typeMask & SkMatrix::kPerspective_Mask) {
|
| return -SK_Scalar1;
|
| }
|
| - if (this->isIdentity()) {
|
| + if (SkMatrix::kIdentity_Mask == typeMask) {
|
| return SK_Scalar1;
|
| }
|
| - if (!(mask & kAffine_Mask)) {
|
| - return SkMaxScalar(SkScalarAbs(fMat[kMScaleX]),
|
| - SkScalarAbs(fMat[kMScaleY]));
|
| + if (!(typeMask & SkMatrix::kAffine_Mask)) {
|
| + if (kMin_MinOrMax == MIN_OR_MAX) {
|
| + return SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
|
| + SkScalarAbs(m[SkMatrix::kMScaleY]));
|
| + } else {
|
| + return SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
|
| + SkScalarAbs(m[SkMatrix::kMScaleY]));
|
| + }
|
| }
|
| // ignore the translation part of the matrix, just look at 2x2 portion.
|
| - // compute singular values, take largest abs value.
|
| + // compute singular values, take largest or smallest abs value.
|
| // [a b; b c] = A^T*A
|
| - SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) +
|
| - SkScalarMul(fMat[kMSkewY], fMat[kMSkewY]);
|
| - SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) +
|
| - SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]);
|
| - SkScalar c = SkScalarMul(fMat[kMSkewX], fMat[kMSkewX]) +
|
| - SkScalarMul(fMat[kMScaleY], fMat[kMScaleY]);
|
| + SkScalar a = SkScalarMul(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX]) +
|
| + SkScalarMul(m[SkMatrix::kMSkewY], m[SkMatrix::kMSkewY]);
|
| + SkScalar b = SkScalarMul(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX]) +
|
| + SkScalarMul(m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
|
| + SkScalar c = SkScalarMul(m[SkMatrix::kMSkewX], m[SkMatrix::kMSkewX]) +
|
| + SkScalarMul(m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
|
| // eigenvalues of A^T*A are the squared singular values of A.
|
| // characteristic equation is det((A^T*A) - l*I) = 0
|
| // l^2 - (a + c)l + (ac-b^2)
|
| // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
|
| - // and roots are guaraunteed to be pos and real).
|
| - SkScalar largerRoot;
|
| + // and roots are guaranteed to be pos and real).
|
| + SkScalar chosenRoot;
|
| SkScalar bSqd = SkScalarMul(b,b);
|
| // if upper left 2x2 is orthogonal save some math
|
| if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
|
| - largerRoot = SkMaxScalar(a, c);
|
| + if (kMin_MinOrMax == MIN_OR_MAX) {
|
| + chosenRoot = SkMinScalar(a, c);
|
| + } else {
|
| + chosenRoot = SkMaxScalar(a, c);
|
| + }
|
| } else {
|
| SkScalar aminusc = a - c;
|
| SkScalar apluscdiv2 = SkScalarHalf(a + c);
|
| SkScalar x = SkScalarHalf(SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd));
|
| - largerRoot = apluscdiv2 + x;
|
| + if (kMin_MinOrMax == MIN_OR_MAX) {
|
| + chosenRoot = apluscdiv2 - x;
|
| + } else {
|
| + chosenRoot = apluscdiv2 + x;
|
| + }
|
| }
|
| - return SkScalarSqrt(largerRoot);
|
| + SkASSERT(chosenRoot >= 0);
|
| + return SkScalarSqrt(chosenRoot);
|
| +}
|
| +
|
| +SkScalar SkMatrix::getMinStretch() const {
|
| + return get_stretch_factor<kMin_MinOrMax>(this->getType(), fMat);
|
| +}
|
| +
|
| +SkScalar SkMatrix::getMaxStretch() const {
|
| + return get_stretch_factor<kMax_MinOrMax>(this->getType(), fMat);
|
| }
|
|
|
| static void reset_identity_matrix(SkMatrix* identity) {
|
|
|