aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/core/SkMatrix.h13
-rw-r--r--src/core/SkBitmapProcState.cpp38
-rw-r--r--src/core/SkMatrix.cpp22
-rw-r--r--src/core/SkPictureShader.cpp3
-rw-r--r--tests/MatrixTest.cpp30
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) {