diff options
author | fmalita <fmalita@chromium.org> | 2016-01-07 10:34:46 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-07 10:34:46 -0800 |
commit | c7e211acd0c9201688de7ff0c9a2271c67440adf (patch) | |
tree | c21a3f91ab7e063f9874f90ad62d6a970340ad87 | |
parent | b7f4b8e94e2414d17eb68a9ceae42b2eea38e604 (diff) |
SkTreatAsSprite should take AA into account
Currently we always call SkTreatAsSprite with 0 subpixel bits, which means
subpixel translations are ignored. This is incorrect for the anti-aliased
case (drawSprite always pixel-snaps, so we lose edge AA).
The CL updates SkTreatAsSprite to take an SkPaint argument and use 8 subpixel
bits when AA is requested.
Also remove unused SkTreatAsSpriteFilter.
BUG=skia:4761
R=reed@google.com
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1566943002
Committed: https://skia.googlesource.com/skia/+/983dc2541a729609037a05eba731b3eb9788c517
Review URL: https://codereview.chromium.org/1566943002
-rw-r--r-- | src/core/SkCanvas.cpp | 3 | ||||
-rw-r--r-- | src/core/SkDraw.cpp | 14 | ||||
-rw-r--r-- | src/core/SkMatrix.cpp | 20 | ||||
-rw-r--r-- | src/core/SkMatrixUtils.h | 29 | ||||
-rw-r--r-- | tests/DrawBitmapRectTest.cpp | 38 |
5 files changed, 41 insertions, 63 deletions
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index e5ca9ce6c1..a4acbdc94d 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -2220,8 +2220,7 @@ bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const } const SkMatrix& ctm = this->getTotalMatrix(); - const unsigned kSubpixelBits = 0; // matching SkDraw::drawBitmap() - if (!SkTreatAsSprite(ctm, w, h, kSubpixelBits)) { + if (!SkTreatAsSprite(ctm, SkISize::Make(w, h), paint)) { return false; } diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 249795d0d1..246c31ba51 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -1172,20 +1172,11 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint, proc(*devPathPtr, *fRC, blitter); } -/** For the purposes of drawing bitmaps, if a matrix is "almost" translate - go ahead and treat it as if it were, so that subsequent code can go fast. - */ -static bool just_translate(const SkMatrix& matrix, const SkBitmap& bitmap) { - unsigned bits = 0; // TODO: find a way to allow the caller to tell us to - // respect filtering. - return SkTreatAsSprite(matrix, bitmap.width(), bitmap.height(), bits); -} - void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const { SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType); - if (just_translate(*fMatrix, bitmap)) { + if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) { int ix = SkScalarRoundToInt(fMatrix->getTranslateX()); int iy = SkScalarRoundToInt(fMatrix->getTranslateY()); @@ -1300,7 +1291,8 @@ void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix, return; } - if (bitmap.colorType() != kAlpha_8_SkColorType && just_translate(matrix, bitmap)) { + if (bitmap.colorType() != kAlpha_8_SkColorType + && SkTreatAsSprite(matrix, bitmap.dimensions(), paint)) { // // It is safe to call lock pixels now, since we know the matrix is // (more or less) identity. diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp index dfeb721d45..4b11fdf331 100644 --- a/src/core/SkMatrix.cpp +++ b/src/core/SkMatrix.cpp @@ -1623,8 +1623,14 @@ void SkMatrix::toString(SkString* str) const { #include "SkMatrixUtils.h" -bool SkTreatAsSprite(const SkMatrix& mat, int width, int height, - unsigned subpixelBits) { +bool SkTreatAsSprite(const SkMatrix& mat, const SkISize& size, const SkPaint& paint) { + // Our path aa is 2-bits, and our rect aa is 8, so we could use 8, + // but in practice 4 seems enough (still looks smooth) and allows + // more slightly fractional cases to fall into the fast (sprite) case. + static const unsigned kAntiAliasSubpixelBits = 4; + + const unsigned subpixelBits = paint.isAntiAlias() ? kAntiAliasSubpixelBits : 0; + // quick reject on affine or perspective if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) { return false; @@ -1641,7 +1647,7 @@ bool SkTreatAsSprite(const SkMatrix& mat, int width, int height, } SkRect dst; - SkIRect isrc = { 0, 0, width, height }; + SkIRect isrc = SkIRect::MakeSize(size); { SkRect src; @@ -1654,10 +1660,10 @@ bool SkTreatAsSprite(const SkMatrix& mat, int width, int height, SkScalarRoundToInt(mat.getTranslateY())); if (subpixelBits) { - isrc.fLeft <<= subpixelBits; - isrc.fTop <<= subpixelBits; - isrc.fRight <<= subpixelBits; - isrc.fBottom <<= subpixelBits; + isrc.fLeft = SkLeftShift(isrc.fLeft, subpixelBits); + isrc.fTop = SkLeftShift(isrc.fTop, subpixelBits); + isrc.fRight = SkLeftShift(isrc.fRight, subpixelBits); + isrc.fBottom = SkLeftShift(isrc.fBottom, subpixelBits); const float scale = 1 << subpixelBits; dst.fLeft *= scale; diff --git a/src/core/SkMatrixUtils.h b/src/core/SkMatrixUtils.h index d1b6658d07..0e01fbe953 100644 --- a/src/core/SkMatrixUtils.h +++ b/src/core/SkMatrixUtils.h @@ -8,37 +8,20 @@ #ifndef SkMatrixUtils_DEFINED #define SkMatrixUtils_DEFINED -#include "SkMatrix.h" +#include "SkSize.h" -/** - * Number of subpixel bits used in skia's bilerp. - * See SkBitmapProcState_procs.h and SkBitmapProcState_filter.h - */ -#define kSkSubPixelBitsForBilerp 4 +class SkMatrix; +class SkPaint; /** - * Given a matrix and width/height, return true if the computed dst-rect would + * Given a matrix, size and paint, return true if the computed dst-rect would * align such that there is a 1-to-1 coorspondence between src and dst pixels. * This can be called by drawing code to see if drawBitmap can be turned into * drawSprite (which is faster). * - * The src-rect is defined to be { 0, 0, width, height } - * - * The "closeness" test is based on the subpixelBits parameter. Pass 0 for - * round-to-nearest behavior (e.g. nearest neighbor sampling). Pass the number - * of subpixel-bits to simulate filtering. - */ -bool SkTreatAsSprite(const SkMatrix&, int width, int height, - unsigned subpixelBits); - -/** - * Calls SkTreatAsSprite() with default subpixelBits value to match Skia's - * filter-bitmap implementation (i.e. kSkSubPixelBitsForBilerp). + * The src-rect is defined to be { 0, 0, size.width(), size.height() } */ -static inline bool SkTreatAsSpriteFilter(const SkMatrix& matrix, - int width, int height) { - return SkTreatAsSprite(matrix, width, height, kSkSubPixelBitsForBilerp); -} +bool SkTreatAsSprite(const SkMatrix&, const SkISize& size, const SkPaint& paint); /** Decomposes the upper-left 2x2 of the matrix into a rotation (represented by the cosine and sine of the rotation angle), followed by a non-uniform scale, diff --git a/tests/DrawBitmapRectTest.cpp b/tests/DrawBitmapRectTest.cpp index 2eb181960b..88b9437935 100644 --- a/tests/DrawBitmapRectTest.cpp +++ b/tests/DrawBitmapRectTest.cpp @@ -82,24 +82,22 @@ static void rand_size(SkISize* size, SkRandom& rand) { size->set(rand.nextU() & 0xFFFF, rand.nextU() & 0xFFFF); } -static bool treat_as_sprite(const SkMatrix& mat, const SkISize& size, - unsigned bits) { - return SkTreatAsSprite(mat, size.width(), size.height(), bits); -} - static void test_treatAsSprite(skiatest::Reporter* reporter) { - const unsigned bilerBits = kSkSubPixelBitsForBilerp; SkMatrix mat; SkISize size; SkRandom rand; - // assert: translate-only no-filter can always be treated as sprite + SkPaint noaaPaint; + SkPaint aaPaint; + aaPaint.setAntiAlias(true); + + // assert: translate-only no-aa can always be treated as sprite for (int i = 0; i < 1000; ++i) { rand_matrix(&mat, rand, SkMatrix::kTranslate_Mask); for (int j = 0; j < 1000; ++j) { rand_size(&size, rand); - REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, 0)); + REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, noaaPaint)); } } @@ -108,8 +106,8 @@ static void test_treatAsSprite(skiatest::Reporter* reporter) { rand_matrix(&mat, rand, SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask); for (int j = 0; j < 1000; ++j) { rand_size(&size, rand); - REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, 0)); - REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits)); + REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, noaaPaint)); + REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint)); } } @@ -117,33 +115,33 @@ static void test_treatAsSprite(skiatest::Reporter* reporter) { const SkScalar tooMuchSubpixel = 100.1f; mat.setTranslate(tooMuchSubpixel, 0); - REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits)); + REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint)); mat.setTranslate(0, tooMuchSubpixel); - REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits)); + REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint)); const SkScalar tinySubPixel = 100.02f; mat.setTranslate(tinySubPixel, 0); - REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, bilerBits)); + REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, aaPaint)); mat.setTranslate(0, tinySubPixel); - REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, bilerBits)); + REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, aaPaint)); const SkScalar twoThirds = SK_Scalar1 * 2 / 3; const SkScalar bigScale = (size.width() + twoThirds) / size.width(); mat.setScale(bigScale, bigScale); - REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, false)); - REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits)); + REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, noaaPaint)); + REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint)); const SkScalar oneThird = SK_Scalar1 / 3; const SkScalar smallScale = (size.width() + oneThird) / size.width(); mat.setScale(smallScale, smallScale); - REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, false)); - REPORTER_ASSERT(reporter, !treat_as_sprite(mat, size, bilerBits)); + REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, noaaPaint)); + REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, size, aaPaint)); const SkScalar oneFortyth = SK_Scalar1 / 40; const SkScalar tinyScale = (size.width() + oneFortyth) / size.width(); mat.setScale(tinyScale, tinyScale); - REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, false)); - REPORTER_ASSERT(reporter, treat_as_sprite(mat, size, bilerBits)); + REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, noaaPaint)); + REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, size, aaPaint)); } static void assert_ifDrawnTo(skiatest::Reporter* reporter, |