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

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: Update 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
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(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
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
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 }
OLDNEW
« include/core/SkMatrix.h ('K') | « include/core/SkScalar.h ('k') | tests/MatrixTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698