| 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) {
 | 
| 
 |