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 Review URL: https://codereview.chromium.org/1566943002
This commit is contained in:
parent
c070d1514a
commit
983dc2541a
@ -2222,8 +2222,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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -8,37 +8,20 @@
|
||||
#ifndef SkMatrixUtils_DEFINED
|
||||
#define SkMatrixUtils_DEFINED
|
||||
|
||||
#include "SkMatrix.h"
|
||||
#include "SkSize.h"
|
||||
|
||||
class SkMatrix;
|
||||
class SkPaint;
|
||||
|
||||
/**
|
||||
* Number of subpixel bits used in skia's bilerp.
|
||||
* See SkBitmapProcState_procs.h and SkBitmapProcState_filter.h
|
||||
*/
|
||||
#define kSkSubPixelBitsForBilerp 4
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* The src-rect is defined to be { 0, 0, size.width(), size.height() }
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
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,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user