diff options
Diffstat (limited to 'chromium/third_party/skia/src/core/SkMatrix.cpp')
-rw-r--r-- | chromium/third_party/skia/src/core/SkMatrix.cpp | 95 |
1 files changed, 59 insertions, 36 deletions
diff --git a/chromium/third_party/skia/src/core/SkMatrix.cpp b/chromium/third_party/skia/src/core/SkMatrix.cpp index 9c9c4375f9e..068902eaace 100644 --- a/chromium/third_party/skia/src/core/SkMatrix.cpp +++ b/chromium/third_party/skia/src/core/SkMatrix.cpp @@ -752,6 +752,16 @@ static double sk_inv_determinant(const float mat[9], int isPerspective) { return 1.0 / det; } +bool SkMatrix::isFinite() const { + for (int i = 0; i < 9; ++i) { + if (!SkScalarIsFinite(fMat[i])) { + return false; + } + } + + return true; +} + void SkMatrix::SetAffineIdentity(SkScalar affine[6]) { affine[kAScaleX] = 1; affine[kASkewY] = 0; @@ -776,6 +786,37 @@ bool SkMatrix::asAffine(SkScalar affine[6]) const { return true; } +void SkMatrix::ComputeInv(SkScalar dst[9], const SkScalar src[9], SkScalar invDet, bool isPersp) { + SkASSERT(src != dst); + SkASSERT(src && dst); + + if (isPersp) { + dst[kMScaleX] = scross_dscale(src[kMScaleY], src[kMPersp2], src[kMTransY], src[kMPersp1], invDet); + dst[kMSkewX] = scross_dscale(src[kMTransX], src[kMPersp1], src[kMSkewX], src[kMPersp2], invDet); + dst[kMTransX] = scross_dscale(src[kMSkewX], src[kMTransY], src[kMTransX], src[kMScaleY], invDet); + + dst[kMSkewY] = scross_dscale(src[kMTransY], src[kMPersp0], src[kMSkewY], src[kMPersp2], invDet); + dst[kMScaleY] = scross_dscale(src[kMScaleX], src[kMPersp2], src[kMTransX], src[kMPersp0], invDet); + dst[kMTransY] = scross_dscale(src[kMTransX], src[kMSkewY], src[kMScaleX], src[kMTransY], invDet); + + dst[kMPersp0] = scross_dscale(src[kMSkewY], src[kMPersp1], src[kMScaleY], src[kMPersp0], invDet); + dst[kMPersp1] = scross_dscale(src[kMSkewX], src[kMPersp0], src[kMScaleX], src[kMPersp1], invDet); + dst[kMPersp2] = scross_dscale(src[kMScaleX], src[kMScaleY], src[kMSkewX], src[kMSkewY], invDet); + } else { // not perspective + dst[kMScaleX] = SkDoubleToScalar(src[kMScaleY] * invDet); + dst[kMSkewX] = SkDoubleToScalar(-src[kMSkewX] * invDet); + dst[kMTransX] = dcross_dscale(src[kMSkewX], src[kMTransY], src[kMScaleY], src[kMTransX], invDet); + + dst[kMSkewY] = SkDoubleToScalar(-src[kMSkewY] * invDet); + dst[kMScaleY] = SkDoubleToScalar(src[kMScaleX] * invDet); + dst[kMTransY] = dcross_dscale(src[kMSkewY], src[kMTransX], src[kMScaleX], src[kMTransY], invDet); + + dst[kMPersp0] = 0; + dst[kMPersp1] = 0; + dst[kMPersp2] = 1; + } +} + bool SkMatrix::invertNonIdentity(SkMatrix* inv) const { SkASSERT(!this->isIdentity()); @@ -819,50 +860,32 @@ bool SkMatrix::invertNonIdentity(SkMatrix* inv) const { } int isPersp = mask & kPerspective_Mask; - double scale = sk_inv_determinant(fMat, isPersp); + double invDet = sk_inv_determinant(fMat, isPersp); - if (scale == 0) { // underflow + if (invDet == 0) { // underflow return false; } - if (inv) { - SkMatrix tmp; - if (inv == this) { - inv = &tmp; - } + bool applyingInPlace = (inv == this); - if (isPersp) { - inv->fMat[kMScaleX] = scross_dscale(fMat[kMScaleY], fMat[kMPersp2], fMat[kMTransY], fMat[kMPersp1], scale); - inv->fMat[kMSkewX] = scross_dscale(fMat[kMTransX], fMat[kMPersp1], fMat[kMSkewX], fMat[kMPersp2], scale); - inv->fMat[kMTransX] = scross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMTransX], fMat[kMScaleY], scale); - - inv->fMat[kMSkewY] = scross_dscale(fMat[kMTransY], fMat[kMPersp0], fMat[kMSkewY], fMat[kMPersp2], scale); - inv->fMat[kMScaleY] = scross_dscale(fMat[kMScaleX], fMat[kMPersp2], fMat[kMTransX], fMat[kMPersp0], scale); - inv->fMat[kMTransY] = scross_dscale(fMat[kMTransX], fMat[kMSkewY], fMat[kMScaleX], fMat[kMTransY], scale); - - inv->fMat[kMPersp0] = scross_dscale(fMat[kMSkewY], fMat[kMPersp1], fMat[kMScaleY], fMat[kMPersp0], scale); - inv->fMat[kMPersp1] = scross_dscale(fMat[kMSkewX], fMat[kMPersp0], fMat[kMScaleX], fMat[kMPersp1], scale); - inv->fMat[kMPersp2] = scross_dscale(fMat[kMScaleX], fMat[kMScaleY], fMat[kMSkewX], fMat[kMSkewY], scale); - } else { // not perspective - inv->fMat[kMScaleX] = SkDoubleToScalar(fMat[kMScaleY] * scale); - inv->fMat[kMSkewX] = SkDoubleToScalar(-fMat[kMSkewX] * scale); - inv->fMat[kMTransX] = dcross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMScaleY], fMat[kMTransX], scale); - - inv->fMat[kMSkewY] = SkDoubleToScalar(-fMat[kMSkewY] * scale); - inv->fMat[kMScaleY] = SkDoubleToScalar(fMat[kMScaleX] * scale); - inv->fMat[kMTransY] = dcross_dscale(fMat[kMSkewY], fMat[kMTransX], fMat[kMScaleX], fMat[kMTransY], scale); - - inv->fMat[kMPersp0] = 0; - inv->fMat[kMPersp1] = 0; - inv->fMat[kMPersp2] = 1; - } + SkMatrix* tmp = inv; + + SkMatrix storage; + if (applyingInPlace || NULL == tmp) { + tmp = &storage; // we either need to avoid trampling memory or have no memory + } + + ComputeInv(tmp->fMat, fMat, invDet, isPersp); + if (!tmp->isFinite()) { + return false; + } - inv->setTypeMask(fTypeMask); + tmp->setTypeMask(fTypeMask); - if (inv == &tmp) { - *(SkMatrix*)this = tmp; - } + if (applyingInPlace) { + *inv = storage; // need to copy answer back } + return true; } |