diff options
-rw-r--r-- | include/core/SkMatrix.h | 13 | ||||
-rw-r--r-- | src/core/SkBitmapProcState.cpp | 38 | ||||
-rw-r--r-- | src/core/SkMatrix.cpp | 22 | ||||
-rw-r--r-- | src/core/SkPictureShader.cpp | 3 | ||||
-rw-r--r-- | tests/MatrixTest.cpp | 30 |
5 files changed, 78 insertions, 28 deletions
diff --git a/include/core/SkMatrix.h b/include/core/SkMatrix.h index a272051067..b2ee3c61bf 100644 --- a/include/core/SkMatrix.h +++ b/include/core/SkMatrix.h @@ -624,6 +624,19 @@ public: bool getMinMaxScales(SkScalar scaleFactors[2]) const; /** + * Attempt to decompose this matrix into a scale-only component and whatever remains, where + * the scale component is to be applied first. + * + * M -> Remaining * Scale + * + * On success, return true and assign the scale and remaining components (assuming their + * respective parameters are not null). On failure return false and ignore the parameters. + * + * Possible reasons to fail: perspective, one or more scale factors are zero. + */ + bool decomposeScale(SkSize* scale, SkMatrix* remaining = NULL) const; + + /** * Return a reference to a const identity matrix */ static const SkMatrix& I(); diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp index 720a30f05c..0b50fbc32d 100644 --- a/src/core/SkBitmapProcState.cpp +++ b/src/core/SkBitmapProcState.cpp @@ -98,12 +98,6 @@ static bool valid_for_filtering(unsigned dimension) { return (dimension & ~0x3FFF) == 0; } -static SkScalar effective_matrix_scale(const SkMatrix& mat) { - SkScalar dx = SkVector::Length(mat.getScaleX(), mat.getSkewY()); - SkScalar dy = SkVector::Length(mat.getSkewX(), mat.getScaleY()); - return SkScalarSqrt(dx * dy); -} - // Check to see that the size of the bitmap that would be produced by // scaling by the given inverted matrix is less than the maximum allowed. static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) { @@ -119,22 +113,6 @@ static inline bool cache_size_okay(const SkBitmap& bm, const SkMatrix& invMat) { } /* - * Extract the "best" scale factors from a matrix. - */ -static bool extract_scale(const SkMatrix& matrix, SkVector* scale) { - SkASSERT(!matrix.hasPerspective()); - SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]); - SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX], matrix[SkMatrix::kMScaleY]); - if (!SkScalarIsFinite(sx) || !SkScalarIsFinite(sy) || - SkScalarNearlyZero(sx) || SkScalarNearlyZero(sy)) - { - return false; - } - scale->set(sx, sy); - return true; -} - -/* * High quality is implemented by performing up-right scale-only filtering and then * using bilerp for any remaining transformations. */ @@ -154,12 +132,12 @@ void SkBitmapProcState::processHQRequest() { SkScalar invScaleX = fInvMatrix.getScaleX(); SkScalar invScaleY = fInvMatrix.getScaleY(); if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) { - SkVector scale; - if (!extract_scale(fInvMatrix, &scale)) { - return; // can't find suitable scale factors + SkSize scale; + if (!fInvMatrix.decomposeScale(&scale)) { + return; } - invScaleX = scale.x(); - invScaleY = scale.y(); + invScaleX = scale.width(); + invScaleY = scale.height(); } if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) { return; // no need for HQ @@ -204,7 +182,11 @@ void SkBitmapProcState::processMediumRequest() { // to a valid bitmap. fFilterLevel = kLow_SkFilterQuality; - SkScalar invScale = effective_matrix_scale(fInvMatrix); + SkSize invScaleSize; + if (!fInvMatrix.decomposeScale(&invScaleSize, NULL)) { + return; + } + SkScalar invScale = SkScalarSqrt(invScaleSize.width() * invScaleSize.height()); if (invScale > SK_Scalar1) { fCurrMip.reset(SkMipMapCache::FindAndRef(fOrigBitmap)); diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp index 9658177ec9..753c4dc61e 100644 --- a/src/core/SkMatrix.cpp +++ b/src/core/SkMatrix.cpp @@ -1603,6 +1603,28 @@ const SkMatrix& SkMatrix::InvalidMatrix() { return invalid.asSkMatrix(); } +bool SkMatrix::decomposeScale(SkSize* scale, SkMatrix* remaining) const { + if (this->hasPerspective()) { + return false; + } + + const SkScalar sx = SkVector::Length(this->getScaleX(), this->getSkewY()); + const SkScalar sy = SkVector::Length(this->getSkewX(), this->getScaleY()); + if (!SkScalarIsFinite(sx) || !SkScalarIsFinite(sy) || + SkScalarNearlyZero(sx) || SkScalarNearlyZero(sy)) { + return false; + } + + if (scale) { + scale->set(sx, sy); + } + if (remaining) { + *remaining = *this; + remaining->postScale(SkScalarInvert(sx), SkScalarInvert(sy)); + } + return true; +} + /////////////////////////////////////////////////////////////////////////////// size_t SkMatrix::writeToMemory(void* buffer) const { diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp index 776fe5e655..3734791ce4 100644 --- a/src/core/SkPictureShader.cpp +++ b/src/core/SkPictureShader.cpp @@ -152,6 +152,9 @@ SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatri // Use a rotation-invariant scale SkPoint scale; + // + // TODO: replace this with decomposeScale() -- but beware LayoutTest rebaselines! + // if (!SkDecomposeUpper2x2(m, NULL, &scale, NULL)) { // Decomposition failed, use an approximation. scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()), diff --git a/tests/MatrixTest.cpp b/tests/MatrixTest.cpp index 7875d9ea45..95d33acabd 100644 --- a/tests/MatrixTest.cpp +++ b/tests/MatrixTest.cpp @@ -771,6 +771,34 @@ static void test_matrix_homogeneous(skiatest::Reporter* reporter) { } +static bool check_decompScale(const SkMatrix& matrix) { + SkSize scale; + SkMatrix remaining; + + if (!matrix.decomposeScale(&scale, &remaining)) { + return false; + } + if (scale.width() <= 0 || scale.height() <= 0) { + return false; + } + remaining.preScale(scale.width(), scale.height()); + return nearly_equal(matrix, remaining); +} + +static void test_decompScale(skiatest::Reporter* reporter) { + SkMatrix m; + + m.reset(); + REPORTER_ASSERT(reporter, check_decompScale(m)); + m.setScale(2, 3); + REPORTER_ASSERT(reporter, check_decompScale(m)); + m.setRotate(35, 0, 0); + REPORTER_ASSERT(reporter, check_decompScale(m)); + + m.setScale(1, 0); + REPORTER_ASSERT(reporter, !check_decompScale(m)); +} + DEF_TEST(Matrix, reporter) { SkMatrix mat, inverse, iden1, iden2; @@ -889,6 +917,8 @@ DEF_TEST(Matrix, reporter) { test_matrix_decomposition(reporter); test_matrix_homogeneous(reporter); test_set9(reporter); + + test_decompScale(reporter); } DEF_TEST(Matrix_Concat, r) { |