| Index: src/core/SkMatrix.cpp
|
| diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
|
| index 9c9c4375f9e33e36ae2810b379b1c4cd48e632bd..068902eaace552bfce0e57247ef0de64776db052 100644
|
| --- a/src/core/SkMatrix.cpp
|
| +++ b/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;
|
| }
|
|
|
|
|