Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Side by Side Diff: src/core/SkMatrix.cpp

Issue 1188433011: Added check for ill-conditioned invert (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address further code review comments (always perform exhaustive check) Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « include/core/SkMatrix.h ('k') | tests/MatrixTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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(SkScalar dst[9], const SkScalar src[9], SkScalar invDe t, bool 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], invDet);
795 dst[kMSkewX] = scross_dscale(src[kMTransX], src[kMPersp1], src[kMSkewX] , src[kMPersp2], invDet);
796 dst[kMTransX] = scross_dscale(src[kMSkewX], src[kMTransY], src[kMTransX ], src[kMScaleY], invDet);
797
798 dst[kMSkewY] = scross_dscale(src[kMTransY], src[kMPersp0], src[kMSkewY] , src[kMPersp2], invDet);
799 dst[kMScaleY] = scross_dscale(src[kMScaleX], src[kMPersp2], src[kMTransX ], src[kMPersp0], invDet);
800 dst[kMTransY] = scross_dscale(src[kMTransX], src[kMSkewY], src[kMScaleX ], src[kMTransY], invDet);
801
802 dst[kMPersp0] = scross_dscale(src[kMSkewY], src[kMPersp1], src[kMScaleY ], src[kMPersp0], invDet);
803 dst[kMPersp1] = scross_dscale(src[kMSkewX], src[kMPersp0], src[kMScaleX ], src[kMPersp1], invDet);
804 dst[kMPersp2] = scross_dscale(src[kMScaleX], src[kMScaleY], src[kMSkewX] , src[kMSkewY], invDet);
805 } else { // not perspective
806 dst[kMScaleX] = SkDoubleToScalar(src[kMScaleY] * invDet);
807 dst[kMSkewX] = SkDoubleToScalar(-src[kMSkewX] * invDet);
808 dst[kMTransX] = dcross_dscale(src[kMSkewX], src[kMTransY], src[kMScaleY] , src[kMTransX], invDet);
809
810 dst[kMSkewY] = SkDoubleToScalar(-src[kMSkewY] * invDet);
811 dst[kMScaleY] = SkDoubleToScalar(src[kMScaleX] * invDet);
812 dst[kMTransY] = dcross_dscale(src[kMSkewY], src[kMTransX], src[kMScaleX] , src[kMTransY], invDet);
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 23 matching lines...) Expand all
812 } 853 }
813 } else { // inv is NULL, just check if we're invertible 854 } else { // inv is NULL, just check if we're invertible
814 if (!fMat[kMScaleX] || !fMat[kMScaleY]) { 855 if (!fMat[kMScaleX] || !fMat[kMScaleY]) {
815 invertible = false; 856 invertible = false;
816 } 857 }
817 } 858 }
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 invDet = sk_inv_determinant(fMat, isPersp);
823 864
824 if (scale == 0) { // underflow 865 if (invDet == 0) { // underflow
825 return false; 866 return false;
826 } 867 }
827 868
828 if (inv) { 869 bool applyingInPlace = (inv == this);
829 SkMatrix tmp;
830 if (inv == this) {
831 inv = &tmp;
832 }
833 870
834 if (isPersp) { 871 SkMatrix* tmp = inv;
835 inv->fMat[kMScaleX] = scross_dscale(fMat[kMScaleY], fMat[kMPersp2], fMat[kMTransY], fMat[kMPersp1], scale);
836 inv->fMat[kMSkewX] = scross_dscale(fMat[kMTransX], fMat[kMPersp1], fMat[kMSkewX], fMat[kMPersp2], scale);
837 inv->fMat[kMTransX] = scross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMTransX], fMat[kMScaleY], scale);
838 872
839 inv->fMat[kMSkewY] = scross_dscale(fMat[kMTransY], fMat[kMPersp0], fMat[kMSkewY], fMat[kMPersp2], scale); 873 SkMatrix storage;
840 inv->fMat[kMScaleY] = scross_dscale(fMat[kMScaleX], fMat[kMPersp2], fMat[kMTransX], fMat[kMPersp0], scale); 874 if (applyingInPlace || NULL == tmp) {
841 inv->fMat[kMTransY] = scross_dscale(fMat[kMTransX], fMat[kMSkewY], fMat[kMScaleX], fMat[kMTransY], scale); 875 tmp = &storage; // we either need to avoid trampling memory or have no memory
876 }
842 877
843 inv->fMat[kMPersp0] = scross_dscale(fMat[kMSkewY], fMat[kMPersp1], fMat[kMScaleY], fMat[kMPersp0], scale); 878 ComputeInv(tmp->fMat, fMat, invDet, isPersp);
844 inv->fMat[kMPersp1] = scross_dscale(fMat[kMSkewX], fMat[kMPersp0], fMat[kMScaleX], fMat[kMPersp1], scale); 879 if (!tmp->isFinite()) {
845 inv->fMat[kMPersp2] = scross_dscale(fMat[kMScaleX], fMat[kMScaleY], fMat[kMSkewX], fMat[kMSkewY], scale); 880 return false;
846 } else { // not perspective 881 }
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 882
851 inv->fMat[kMSkewY] = SkDoubleToScalar(-fMat[kMSkewY] * scale); 883 tmp->setTypeMask(fTypeMask);
852 inv->fMat[kMScaleY] = SkDoubleToScalar(fMat[kMScaleX] * scale);
853 inv->fMat[kMTransY] = dcross_dscale(fMat[kMSkewY], fMat[kMTransX], f Mat[kMScaleX], fMat[kMTransY], scale);
854 884
855 inv->fMat[kMPersp0] = 0; 885 if (applyingInPlace) {
856 inv->fMat[kMPersp1] = 0; 886 *inv = storage; // need to copy answer back
857 inv->fMat[kMPersp2] = 1; 887 }
858 }
859 888
860 inv->setTypeMask(fTypeMask);
861
862 if (inv == &tmp) {
863 *(SkMatrix*)this = tmp;
864 }
865 }
866 return true; 889 return true;
867 } 890 }
868 891
869 /////////////////////////////////////////////////////////////////////////////// 892 ///////////////////////////////////////////////////////////////////////////////
870 893
871 void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[ ], int count) { 894 void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[ ], int count) {
872 SkASSERT(m.getType() == 0); 895 SkASSERT(m.getType() == 0);
873 896
874 if (dst != src && count > 0) { 897 if (dst != src && count > 0) {
875 memcpy(dst, src, count * sizeof(SkPoint)); 898 memcpy(dst, src, count * sizeof(SkPoint));
(...skipping 917 matching lines...) Expand 10 before | Expand all | Expand 10 after
1793 rotation1->fX = cos1; 1816 rotation1->fX = cos1;
1794 rotation1->fY = sin1; 1817 rotation1->fY = sin1;
1795 } 1818 }
1796 if (rotation2) { 1819 if (rotation2) {
1797 rotation2->fX = cos2; 1820 rotation2->fX = cos2;
1798 rotation2->fY = sin2; 1821 rotation2->fY = sin2;
1799 } 1822 }
1800 1823
1801 return true; 1824 return true;
1802 } 1825 }
OLDNEW
« no previous file with comments | « include/core/SkMatrix.h ('k') | tests/MatrixTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698