add unittest for SkTreatAsSprite
Review URL: https://codereview.appspot.com/7042044 git-svn-id: http://skia.googlecode.com/svn/trunk@6974 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
11f20d6270
commit
ad51430215
@ -1802,3 +1802,52 @@ void SkMatrix::toDumpString(SkString* str) const {
|
|||||||
SkFractToFloat(fMat[6]), SkFractToFloat(fMat[7]), SkFractToFloat(fMat[8]));
|
SkFractToFloat(fMat[6]), SkFractToFloat(fMat[7]), SkFractToFloat(fMat[8]));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "SkMatrixUtils.h"
|
||||||
|
|
||||||
|
bool SkTreatAsSprite(const SkMatrix& mat, const SkRect& src,
|
||||||
|
unsigned subpixelBits) {
|
||||||
|
if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// quick success check
|
||||||
|
if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mapRect supports negative scales, so we eliminate those first
|
||||||
|
if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkRect dst;
|
||||||
|
SkIRect isrc, idst;
|
||||||
|
|
||||||
|
mat.mapRect(&dst, src);
|
||||||
|
|
||||||
|
{
|
||||||
|
SkRect tmp = src;
|
||||||
|
tmp.offset(mat.getTranslateX(), mat.getTranslateY());
|
||||||
|
tmp.round(&isrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subpixelBits) {
|
||||||
|
isrc.fLeft <<= subpixelBits;
|
||||||
|
isrc.fTop <<= subpixelBits;
|
||||||
|
isrc.fRight <<= subpixelBits;
|
||||||
|
isrc.fBottom <<= subpixelBits;
|
||||||
|
|
||||||
|
const float scale = 1 << subpixelBits;
|
||||||
|
dst.fLeft *= scale;
|
||||||
|
dst.fTop *= scale;
|
||||||
|
dst.fRight *= scale;
|
||||||
|
dst.fBottom *= scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.round(&idst);
|
||||||
|
return isrc == idst;
|
||||||
|
}
|
||||||
|
|
||||||
|
32
src/core/SkMatrixUtils.h
Normal file
32
src/core/SkMatrixUtils.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 Google Inc.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SkMatrixUtils_DEFINED
|
||||||
|
#define SkMatrixUtils_DEFINED
|
||||||
|
|
||||||
|
#include "SkMatrix.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of subpixel bits used in skia's bilerp.
|
||||||
|
* See SkBitmapProcState_procs.h and SkBitmapProcState_filter.h
|
||||||
|
*/
|
||||||
|
#define kSkSubPixelBitsForBilerp 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a matrix and a src-rect, 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 "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&, const SkRect& src, unsigned subpixelBits);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -9,6 +9,90 @@
|
|||||||
#include "SkBitmap.h"
|
#include "SkBitmap.h"
|
||||||
#include "SkCanvas.h"
|
#include "SkCanvas.h"
|
||||||
#include "SkShader.h"
|
#include "SkShader.h"
|
||||||
|
#include "SkRandom.h"
|
||||||
|
#include "SkMatrixUtils.h"
|
||||||
|
|
||||||
|
static void rand_matrix(SkMatrix* mat, SkRandom& rand, unsigned mask) {
|
||||||
|
mat->setIdentity();
|
||||||
|
if (mask & SkMatrix::kTranslate_Mask) {
|
||||||
|
mat->postTranslate(rand.nextSScalar1(), rand.nextSScalar1());
|
||||||
|
}
|
||||||
|
if (mask & SkMatrix::kScale_Mask) {
|
||||||
|
mat->postScale(rand.nextSScalar1(), rand.nextSScalar1());
|
||||||
|
}
|
||||||
|
if (mask & SkMatrix::kAffine_Mask) {
|
||||||
|
mat->postRotate(rand.nextSScalar1() * 360);
|
||||||
|
}
|
||||||
|
if (mask & SkMatrix::kPerspective_Mask) {
|
||||||
|
mat->setPerspX(rand.nextSScalar1());
|
||||||
|
mat->setPerspY(rand.nextSScalar1());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rand_rect(SkRect* r, SkRandom& rand) {
|
||||||
|
r->set(rand.nextSScalar1() * 1000, rand.nextSScalar1() * 1000,
|
||||||
|
rand.nextSScalar1() * 1000, rand.nextSScalar1() * 1000);
|
||||||
|
r->sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_treatAsSprite(skiatest::Reporter* reporter) {
|
||||||
|
const unsigned bilerBits = kSkSubPixelBitsForBilerp;
|
||||||
|
|
||||||
|
SkMatrix mat;
|
||||||
|
SkRect r;
|
||||||
|
SkRandom rand;
|
||||||
|
|
||||||
|
// assert: translate-only no-filter 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_rect(&r, rand);
|
||||||
|
REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, r, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert: rotate/perspect is never treated as sprite
|
||||||
|
for (int i = 0; i < 1000; ++i) {
|
||||||
|
rand_matrix(&mat, rand, SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask);
|
||||||
|
for (int j = 0; j < 1000; ++j) {
|
||||||
|
rand_rect(&r, rand);
|
||||||
|
REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, r, 0));
|
||||||
|
REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, r, bilerBits));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.set(10, 10, 500, 600);
|
||||||
|
|
||||||
|
const SkScalar tooMuchSubpixel = SkFloatToScalar(100.1f);
|
||||||
|
mat.setTranslate(tooMuchSubpixel, 0);
|
||||||
|
REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, r, bilerBits));
|
||||||
|
mat.setTranslate(0, tooMuchSubpixel);
|
||||||
|
REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, r, bilerBits));
|
||||||
|
|
||||||
|
const SkScalar tinySubPixel = SkFloatToScalar(100.02f);
|
||||||
|
mat.setTranslate(tinySubPixel, 0);
|
||||||
|
REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, r, bilerBits));
|
||||||
|
mat.setTranslate(0, tinySubPixel);
|
||||||
|
REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, r, bilerBits));
|
||||||
|
|
||||||
|
const SkScalar twoThirds = SK_Scalar1 * 2 / 3;
|
||||||
|
const SkScalar bigScale = SkScalarDiv(r.width() + twoThirds, r.width());
|
||||||
|
mat.setScale(bigScale, bigScale);
|
||||||
|
REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, r, false));
|
||||||
|
REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, r, bilerBits));
|
||||||
|
|
||||||
|
const SkScalar oneThird = SK_Scalar1 / 3;
|
||||||
|
const SkScalar smallScale = SkScalarDiv(r.width() + oneThird, r.width());
|
||||||
|
mat.setScale(smallScale, smallScale);
|
||||||
|
REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, r, false));
|
||||||
|
REPORTER_ASSERT(reporter, !SkTreatAsSprite(mat, r, bilerBits));
|
||||||
|
|
||||||
|
const SkScalar oneFortyth = SK_Scalar1 / 40;
|
||||||
|
const SkScalar tinyScale = SkScalarDiv(r.width() + oneFortyth, r.width());
|
||||||
|
mat.setScale(tinyScale, tinyScale);
|
||||||
|
REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, r, false));
|
||||||
|
REPORTER_ASSERT(reporter, SkTreatAsSprite(mat, r, bilerBits));
|
||||||
|
}
|
||||||
|
|
||||||
static void assert_ifDrawnTo(skiatest::Reporter* reporter,
|
static void assert_ifDrawnTo(skiatest::Reporter* reporter,
|
||||||
const SkBitmap& bm, bool shouldBeDrawn) {
|
const SkBitmap& bm, bool shouldBeDrawn) {
|
||||||
@ -179,6 +263,8 @@ static void TestDrawBitmapRect(skiatest::Reporter* reporter) {
|
|||||||
|
|
||||||
test_nan_antihair(reporter);
|
test_nan_antihair(reporter);
|
||||||
test_giantrepeat_crbug118018(reporter);
|
test_giantrepeat_crbug118018(reporter);
|
||||||
|
|
||||||
|
test_treatAsSprite(reporter);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "TestClassDef.h"
|
#include "TestClassDef.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user