 Chromium Code Reviews
 Chromium Code Reviews Issue 1188433011:
  Added check for ill-conditioned invert  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master
    
  
    Issue 1188433011:
  Added check for ill-conditioned invert  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master| 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 "SkMatrix.h" | 8 #include "SkMatrix.h" | 
| 9 #include "SkFloatBits.h" | 9 #include "SkFloatBits.h" | 
| 10 #include "SkString.h" | 10 #include "SkString.h" | 
| (...skipping 734 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 745 | 745 | 
| 746 // Since the determinant is on the order of the cube of the matrix members, | 746 // Since the determinant is on the order of the cube of the matrix members, | 
| 747 // compare to the cube of the default nearly-zero constant (although an | 747 // compare to the cube of the default nearly-zero constant (although an | 
| 748 // estimate of the condition number would be better if it wasn't so expensiv e). | 748 // estimate of the condition number would be better if it wasn't so expensiv e). | 
| 749 if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) { | 749 if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) { | 
| 750 return 0; | 750 return 0; | 
| 751 } | 751 } | 
| 752 return 1.0 / det; | 752 return 1.0 / det; | 
| 753 } | 753 } | 
| 754 | 754 | 
| 755 bool SkMatrix::isFinite() const { | |
| 756 for (int i = 0; i < 9; ++i) { | |
| 757 if (!SkScalarIsFinite(fMat[i])) { | |
| 758 return false; | |
| 759 } | |
| 760 } | |
| 761 | |
| 762 return true; | |
| 763 } | |
| 764 | |
| 755 void SkMatrix::SetAffineIdentity(SkScalar affine[6]) { | 765 void SkMatrix::SetAffineIdentity(SkScalar affine[6]) { | 
| 756 affine[kAScaleX] = 1; | 766 affine[kAScaleX] = 1; | 
| 757 affine[kASkewY] = 0; | 767 affine[kASkewY] = 0; | 
| 758 affine[kASkewX] = 0; | 768 affine[kASkewX] = 0; | 
| 759 affine[kAScaleY] = 1; | 769 affine[kAScaleY] = 1; | 
| 760 affine[kATransX] = 0; | 770 affine[kATransX] = 0; | 
| 761 affine[kATransY] = 0; | 771 affine[kATransY] = 0; | 
| 762 } | 772 } | 
| 763 | 773 | 
| 764 bool SkMatrix::asAffine(SkScalar affine[6]) const { | 774 bool SkMatrix::asAffine(SkScalar affine[6]) const { | 
| 765 if (this->hasPerspective()) { | 775 if (this->hasPerspective()) { | 
| 766 return false; | 776 return false; | 
| 767 } | 777 } | 
| 768 if (affine) { | 778 if (affine) { | 
| 769 affine[kAScaleX] = this->fMat[kMScaleX]; | 779 affine[kAScaleX] = this->fMat[kMScaleX]; | 
| 770 affine[kASkewY] = this->fMat[kMSkewY]; | 780 affine[kASkewY] = this->fMat[kMSkewY]; | 
| 771 affine[kASkewX] = this->fMat[kMSkewX]; | 781 affine[kASkewX] = this->fMat[kMSkewX]; | 
| 772 affine[kAScaleY] = this->fMat[kMScaleY]; | 782 affine[kAScaleY] = this->fMat[kMScaleY]; | 
| 773 affine[kATransX] = this->fMat[kMTransX]; | 783 affine[kATransX] = this->fMat[kMTransX]; | 
| 774 affine[kATransY] = this->fMat[kMTransY]; | 784 affine[kATransY] = this->fMat[kMTransY]; | 
| 775 } | 785 } | 
| 776 return true; | 786 return true; | 
| 777 } | 787 } | 
| 778 | 788 | 
| 789 void SkMatrix::ComputeInv(const SkScalar* src, SkScalar* dst, SkScalar scale, bo ol isPersp) { | |
| 790 SkASSERT(src != dst); | |
| 791 SkASSERT(src && dst); | |
| 792 | |
| 793 if (isPersp) { | |
| 794 dst[kMScaleX] = scross_dscale(src[kMScaleY], src[kMPersp2], src[kMTransY ], src[kMPersp1], scale); | |
| 795 dst[kMSkewX] = scross_dscale(src[kMTransX], src[kMPersp1], src[kMSkewX] , src[kMPersp2], scale); | |
| 796 dst[kMTransX] = scross_dscale(src[kMSkewX], src[kMTransY], src[kMTransX ], src[kMScaleY], scale); | |
| 797 | |
| 798 dst[kMSkewY] = scross_dscale(src[kMTransY], src[kMPersp0], src[kMSkewY] , src[kMPersp2], scale); | |
| 799 dst[kMScaleY] = scross_dscale(src[kMScaleX], src[kMPersp2], src[kMTransX ], src[kMPersp0], scale); | |
| 800 dst[kMTransY] = scross_dscale(src[kMTransX], src[kMSkewY], src[kMScaleX ], src[kMTransY], scale); | |
| 801 | |
| 802 dst[kMPersp0] = scross_dscale(src[kMSkewY], src[kMPersp1], src[kMScaleY ], src[kMPersp0], scale); | |
| 803 dst[kMPersp1] = scross_dscale(src[kMSkewX], src[kMPersp0], src[kMScaleX ], src[kMPersp1], scale); | |
| 804 dst[kMPersp2] = scross_dscale(src[kMScaleX], src[kMScaleY], src[kMSkewX] , src[kMSkewY], scale); | |
| 805 } else { // not perspective | |
| 806 dst[kMScaleX] = SkDoubleToScalar(src[kMScaleY] * scale); | |
| 807 dst[kMSkewX] = SkDoubleToScalar(-src[kMSkewX] * scale); | |
| 808 dst[kMTransX] = dcross_dscale(src[kMSkewX], src[kMTransY], src[kMScaleY] , src[kMTransX], scale); | |
| 809 | |
| 810 dst[kMSkewY] = SkDoubleToScalar(-src[kMSkewY] * scale); | |
| 811 dst[kMScaleY] = SkDoubleToScalar(src[kMScaleX] * scale); | |
| 812 dst[kMTransY] = dcross_dscale(src[kMSkewY], src[kMTransX], src[kMScaleX] , src[kMTransY], scale); | |
| 813 | |
| 814 dst[kMPersp0] = 0; | |
| 815 dst[kMPersp1] = 0; | |
| 816 dst[kMPersp2] = 1; | |
| 817 } | |
| 818 } | |
| 819 | |
| 779 bool SkMatrix::invertNonIdentity(SkMatrix* inv) const { | 820 bool SkMatrix::invertNonIdentity(SkMatrix* inv) const { | 
| 780 SkASSERT(!this->isIdentity()); | 821 SkASSERT(!this->isIdentity()); | 
| 781 | 822 | 
| 782 TypeMask mask = this->getType(); | 823 TypeMask mask = this->getType(); | 
| 783 | 824 | 
| 784 if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) { | 825 if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) { | 
| 785 bool invertible = true; | 826 bool invertible = true; | 
| 786 if (inv) { | 827 if (inv) { | 
| 787 if (mask & kScale_Mask) { | 828 if (mask & kScale_Mask) { | 
| 788 SkScalar invX = fMat[kMScaleX]; | 829 SkScalar invX = fMat[kMScaleX]; | 
| (...skipping 29 matching lines...) Expand all Loading... | |
| 818 return invertible; | 859 return invertible; | 
| 819 } | 860 } | 
| 820 | 861 | 
| 821 int isPersp = mask & kPerspective_Mask; | 862 int isPersp = mask & kPerspective_Mask; | 
| 822 double scale = sk_inv_determinant(fMat, isPersp); | 863 double scale = sk_inv_determinant(fMat, isPersp); | 
| 823 | 864 | 
| 824 if (scale == 0) { // underflow | 865 if (scale == 0) { // underflow | 
| 825 return false; | 866 return false; | 
| 826 } | 867 } | 
| 827 | 868 | 
| 828 if (inv) { | 869 // If the scale is close to the float min check the validity of the | 
| 829 SkMatrix tmp; | 870 // inverse result regardless of if the actual result is requested | 
| 830 if (inv == this) { | 871 bool checkInv = abs(scale) <= SK_ScalarSmallest; | 
| 831 inv = &tmp; | |
| 832 } | |
| 833 | 872 | 
| 834 if (isPersp) { | 873 if (!inv && !checkInv) { | 
| 835 inv->fMat[kMScaleX] = scross_dscale(fMat[kMScaleY], fMat[kMPersp2], fMat[kMTransY], fMat[kMPersp1], scale); | 874 return true; // no reason to actually compute the inverse | 
| 836 inv->fMat[kMSkewX] = scross_dscale(fMat[kMTransX], fMat[kMPersp1], fMat[kMSkewX], fMat[kMPersp2], scale); | 875 } | 
| 837 inv->fMat[kMTransX] = scross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMTransX], fMat[kMScaleY], scale); | |
| 838 | 876 | 
| 839 inv->fMat[kMSkewY] = scross_dscale(fMat[kMTransY], fMat[kMPersp0], fMat[kMSkewY], fMat[kMPersp2], scale); | 877 bool applyingInPlace = (inv == this); | 
| 840 inv->fMat[kMScaleY] = scross_dscale(fMat[kMScaleX], fMat[kMPersp2], fMat[kMTransX], fMat[kMPersp0], scale); | |
| 841 inv->fMat[kMTransY] = scross_dscale(fMat[kMTransX], fMat[kMSkewY], fMat[kMScaleX], fMat[kMTransY], scale); | |
| 842 | 878 | 
| 843 inv->fMat[kMPersp0] = scross_dscale(fMat[kMSkewY], fMat[kMPersp1], fMat[kMScaleY], fMat[kMPersp0], scale); | 879 SkMatrix* tmp = inv; | 
| 844 inv->fMat[kMPersp1] = scross_dscale(fMat[kMSkewX], fMat[kMPersp0], fMat[kMScaleX], fMat[kMPersp1], scale); | |
| 845 inv->fMat[kMPersp2] = scross_dscale(fMat[kMScaleX], fMat[kMScaleY], fMat[kMSkewX], fMat[kMSkewY], scale); | |
| 846 } else { // not perspective | |
| 847 inv->fMat[kMScaleX] = SkDoubleToScalar(fMat[kMScaleY] * scale); | |
| 848 inv->fMat[kMSkewX] = SkDoubleToScalar(-fMat[kMSkewX] * scale); | |
| 849 inv->fMat[kMTransX] = dcross_dscale(fMat[kMSkewX], fMat[kMTransY], f Mat[kMScaleY], fMat[kMTransX], scale); | |
| 850 | 880 | 
| 851 inv->fMat[kMSkewY] = SkDoubleToScalar(-fMat[kMSkewY] * scale); | 881 SkMatrix storage; | 
| 852 inv->fMat[kMScaleY] = SkDoubleToScalar(fMat[kMScaleX] * scale); | 882 if (applyingInPlace || NULL == tmp) { | 
| 853 inv->fMat[kMTransY] = dcross_dscale(fMat[kMSkewY], fMat[kMTransX], f Mat[kMScaleX], fMat[kMTransY], scale); | 883 tmp = &storage; // we either need to avoid trampling memory or have no memory | 
| 884 } | |
| 854 | 885 | 
| 855 inv->fMat[kMPersp0] = 0; | 886 ComputeInv(fMat, tmp->fMat, scale, isPersp); | 
| 856 inv->fMat[kMPersp1] = 0; | 887 if (!tmp->isFinite()) { | 
| 857 inv->fMat[kMPersp2] = 1; | 888 return false; | 
| 858 } | 889 } | 
| 859 | 890 | 
| 860 inv->setTypeMask(fTypeMask); | 891 tmp->setTypeMask(fTypeMask); | 
| 861 | 892 | 
| 862 if (inv == &tmp) { | 893 if (applyingInPlace) { | 
| 863 *(SkMatrix*)this = tmp; | 894 *(SkMatrix*)this = storage; // need to copy answer back | 
| 
reed1
2015/06/17 19:27:56
why the cast? why not 
if (applyingInPlace) {
 
robertphillips
2015/06/17 19:44:46
Done. It was left over from the prior code.
 | |
| 864 } | |
| 865 } | 895 } | 
| 896 | |
| 866 return true; | 897 return true; | 
| 867 } | 898 } | 
| 868 | 899 | 
| 869 /////////////////////////////////////////////////////////////////////////////// | 900 /////////////////////////////////////////////////////////////////////////////// | 
| 870 | 901 | 
| 871 void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[ ], int count) { | 902 void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[ ], int count) { | 
| 872 SkASSERT(m.getType() == 0); | 903 SkASSERT(m.getType() == 0); | 
| 873 | 904 | 
| 874 if (dst != src && count > 0) { | 905 if (dst != src && count > 0) { | 
| 875 memcpy(dst, src, count * sizeof(SkPoint)); | 906 memcpy(dst, src, count * sizeof(SkPoint)); | 
| (...skipping 917 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1793 rotation1->fX = cos1; | 1824 rotation1->fX = cos1; | 
| 1794 rotation1->fY = sin1; | 1825 rotation1->fY = sin1; | 
| 1795 } | 1826 } | 
| 1796 if (rotation2) { | 1827 if (rotation2) { | 
| 1797 rotation2->fX = cos2; | 1828 rotation2->fX = cos2; | 
| 1798 rotation2->fY = sin2; | 1829 rotation2->fY = sin2; | 
| 1799 } | 1830 } | 
| 1800 | 1831 | 
| 1801 return true; | 1832 return true; | 
| 1802 } | 1833 } | 
| OLD | NEW |