2013-07-25 21:34:00 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2013 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gm.h"
|
2013-09-06 14:16:12 +00:00
|
|
|
#include "SkBlurMask.h"
|
2013-08-20 16:51:20 +00:00
|
|
|
#include "SkBlurMaskFilter.h"
|
2013-09-06 14:16:12 +00:00
|
|
|
#include "SkCanvas.h"
|
2015-10-23 18:13:01 +00:00
|
|
|
#include "SkGradientShader.h"
|
2015-07-14 17:54:12 +00:00
|
|
|
#include "SkImage.h"
|
2017-03-22 17:47:51 +00:00
|
|
|
#include "SkTDArray.h"
|
2015-11-02 20:33:21 +00:00
|
|
|
#include "SkUtils.h"
|
2013-07-25 21:34:00 +00:00
|
|
|
|
|
|
|
#if SK_SUPPORT_GPU
|
|
|
|
#include "GrContext.h"
|
2015-05-27 20:23:23 +00:00
|
|
|
#include "GrContextOptions.h"
|
2015-11-02 20:33:21 +00:00
|
|
|
#include "SkGr.h"
|
2013-07-25 21:34:00 +00:00
|
|
|
#endif
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
/** Holds either a bitmap or image to be rendered and a rect that indicates what part of the bitmap
|
|
|
|
or image should be tested by the GM. The area outside of the rect is present to check
|
|
|
|
for bleed due to filtering/blurring. */
|
|
|
|
struct TestPixels {
|
|
|
|
enum Type {
|
|
|
|
kBitmap,
|
|
|
|
kImage
|
|
|
|
};
|
2016-03-17 17:51:11 +00:00
|
|
|
Type fType;
|
|
|
|
SkBitmap fBitmap;
|
|
|
|
sk_sp<SkImage> fImage;
|
|
|
|
SkIRect fRect; // The region of the bitmap/image that should be rendered.
|
2015-11-09 18:06:06 +00:00
|
|
|
};
|
2015-11-02 20:33:21 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
/** Creates a bitmap with two one-pixel rings around a checkerboard. The checkerboard is 2x2
|
|
|
|
logically where each check has as many pixels as is necessary to fill the interior. The rect
|
|
|
|
to draw is set to the checkerboard portion. */
|
|
|
|
template<typename PIXEL_TYPE>
|
2016-07-13 21:50:17 +00:00
|
|
|
bool make_ringed_bitmap(TestPixels* result, int width, int height,
|
2015-11-09 18:06:06 +00:00
|
|
|
SkColorType ct, SkAlphaType at,
|
|
|
|
PIXEL_TYPE outerRingColor, PIXEL_TYPE innerRingColor,
|
|
|
|
PIXEL_TYPE checkColor1, PIXEL_TYPE checkColor2) {
|
2013-11-08 15:09:22 +00:00
|
|
|
SkASSERT(0 == width % 2 && 0 == height % 2);
|
2015-11-09 18:06:06 +00:00
|
|
|
SkASSERT(width >= 6 && height >= 6);
|
2013-11-09 07:02:23 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
result->fType = TestPixels::kBitmap;
|
|
|
|
SkImageInfo info = SkImageInfo::Make(width, height, ct, at);
|
|
|
|
size_t rowBytes = SkAlign4(info.minRowBytes());
|
|
|
|
result->fBitmap.allocPixels(info, rowBytes);
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
PIXEL_TYPE* scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 0);
|
2013-07-25 21:34:00 +00:00
|
|
|
for (int x = 0; x < width; ++x) {
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[x] = outerRingColor;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 1);
|
|
|
|
scanline[0] = outerRingColor;
|
2013-11-08 15:09:22 +00:00
|
|
|
for (int x = 1; x < width - 1; ++x) {
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[x] = innerRingColor;
|
2013-11-08 15:09:22 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[width - 1] = outerRingColor;
|
|
|
|
|
|
|
|
for (int y = 2; y < height / 2; ++y) {
|
|
|
|
scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
|
|
|
|
scanline[0] = outerRingColor;
|
|
|
|
scanline[1] = innerRingColor;
|
|
|
|
for (int x = 2; x < width / 2; ++x) {
|
|
|
|
scanline[x] = checkColor1;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
for (int x = width / 2; x < width - 2; ++x) {
|
|
|
|
scanline[x] = checkColor2;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[width - 2] = innerRingColor;
|
|
|
|
scanline[width - 1] = outerRingColor;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
for (int y = height / 2; y < height - 2; ++y) {
|
|
|
|
scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
|
|
|
|
scanline[0] = outerRingColor;
|
|
|
|
scanline[1] = innerRingColor;
|
|
|
|
for (int x = 2; x < width / 2; ++x) {
|
|
|
|
scanline[x] = checkColor2;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
for (int x = width / 2; x < width - 2; ++x) {
|
|
|
|
scanline[x] = checkColor1;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[width - 2] = innerRingColor;
|
|
|
|
scanline[width - 1] = outerRingColor;
|
2013-11-08 15:09:22 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 2);
|
|
|
|
scanline[0] = outerRingColor;
|
2013-11-08 15:09:22 +00:00
|
|
|
for (int x = 1; x < width - 1; ++x) {
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[x] = innerRingColor;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[width - 1] = outerRingColor;
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 1);
|
2013-07-25 21:34:00 +00:00
|
|
|
for (int x = 0; x < width; ++x) {
|
2015-11-09 18:06:06 +00:00
|
|
|
scanline[x] = outerRingColor;
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
result->fBitmap.setImmutable();
|
|
|
|
result->fRect.set(2, 2, width - 2, height - 2);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-07-13 21:50:17 +00:00
|
|
|
/** Create a black and white checked bitmap with 2 1-pixel rings around the outside edge.
|
2015-11-09 18:06:06 +00:00
|
|
|
The inner ring is red and the outer ring is blue. */
|
2016-07-13 21:50:17 +00:00
|
|
|
static bool make_ringed_color_bitmap(TestPixels* result, int width, int height) {
|
2016-09-01 18:24:54 +00:00
|
|
|
const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
|
|
|
|
const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
|
|
|
|
const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
|
|
|
|
const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
|
2016-08-25 13:45:29 +00:00
|
|
|
return make_ringed_bitmap<SkPMColor>(result, width, height, kN32_SkColorType,
|
2015-11-09 18:06:06 +00:00
|
|
|
kPremul_SkAlphaType, kBlue, kRed, kBlack, kWhite);
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-11-04 12:23:45 +00:00
|
|
|
/** Makes a alpha bitmap with 1 wide rect/ring of 0s, an inset of 1s, and the interior is a 2x2
|
2015-10-23 18:13:01 +00:00
|
|
|
checker board of 3/4 and 1/2. The inner checkers are large enough to fill the interior with
|
|
|
|
the 2x2 checker grid. */
|
2016-07-13 21:50:17 +00:00
|
|
|
static bool make_ringed_alpha_bitmap(TestPixels* result, int width, int height) {
|
2016-09-01 18:24:54 +00:00
|
|
|
constexpr uint8_t kZero = 0x00;
|
|
|
|
constexpr uint8_t kHalf = 0x80;
|
|
|
|
constexpr uint8_t k3Q = 0xC0;
|
|
|
|
constexpr uint8_t kOne = 0xFF;
|
2016-07-13 21:50:17 +00:00
|
|
|
return make_ringed_bitmap<uint8_t>(result, width, height, kAlpha_8_SkColorType,
|
2015-11-09 18:06:06 +00:00
|
|
|
kPremul_SkAlphaType, kZero, kOne, k3Q, kHalf);
|
|
|
|
}
|
2015-10-23 18:13:01 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
/** Helper to reuse above functions to produce images rather than bmps */
|
|
|
|
static void bmp_to_image(TestPixels* result) {
|
|
|
|
SkASSERT(TestPixels::kBitmap == result->fType);
|
2016-03-17 17:51:11 +00:00
|
|
|
result->fImage = SkImage::MakeFromBitmap(result->fBitmap);
|
2015-11-09 18:06:06 +00:00
|
|
|
SkASSERT(result->fImage);
|
|
|
|
result->fType = TestPixels::kImage;
|
|
|
|
result->fBitmap.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Color image case. */
|
2016-07-13 21:50:17 +00:00
|
|
|
bool make_ringed_color_image(TestPixels* result, int width, int height) {
|
|
|
|
if (make_ringed_color_bitmap(result, width, height)) {
|
2015-11-09 18:06:06 +00:00
|
|
|
bmp_to_image(result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Alpha image case. */
|
2016-07-13 21:50:17 +00:00
|
|
|
bool make_ringed_alpha_image(TestPixels* result, int width, int height) {
|
|
|
|
if (make_ringed_alpha_bitmap(result, width, height)) {
|
2015-11-09 18:06:06 +00:00
|
|
|
bmp_to_image(result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-03-09 17:50:50 +00:00
|
|
|
static sk_sp<SkShader> make_shader() {
|
2016-09-01 18:24:54 +00:00
|
|
|
constexpr SkPoint pts[] = { {0, 0}, {20, 20} };
|
|
|
|
constexpr SkColor colors[] = { SK_ColorGREEN, SK_ColorYELLOW };
|
2016-03-09 17:50:50 +00:00
|
|
|
return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kMirror_TileMode);
|
2015-10-23 18:13:01 +00:00
|
|
|
}
|
|
|
|
|
2016-03-09 17:50:50 +00:00
|
|
|
static sk_sp<SkShader> make_null_shader() { return nullptr; }
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
enum BleedTest {
|
|
|
|
kUseBitmap_BleedTest,
|
|
|
|
kUseImage_BleedTest,
|
|
|
|
kUseAlphaBitmap_BleedTest,
|
|
|
|
kUseAlphaImage_BleedTest,
|
|
|
|
kUseAlphaBitmapShader_BleedTest,
|
|
|
|
kUseAlphaImageShader_BleedTest,
|
|
|
|
};
|
|
|
|
|
|
|
|
const struct {
|
|
|
|
const char* fName;
|
2016-07-13 21:50:17 +00:00
|
|
|
bool (*fPixelMaker)(TestPixels* result, int width, int height);
|
2016-03-09 17:50:50 +00:00
|
|
|
sk_sp<SkShader> (*fShaderMaker)();
|
2015-10-23 18:13:01 +00:00
|
|
|
} gBleedRec[] = {
|
2015-11-09 18:06:06 +00:00
|
|
|
{ "bleed", make_ringed_color_bitmap, make_null_shader },
|
|
|
|
{ "bleed_image", make_ringed_color_image, make_null_shader },
|
|
|
|
{ "bleed_alpha_bmp", make_ringed_alpha_bitmap, make_null_shader },
|
|
|
|
{ "bleed_alpha_image", make_ringed_alpha_image, make_null_shader },
|
|
|
|
{ "bleed_alpha_bmp_shader", make_ringed_alpha_bitmap, make_shader },
|
|
|
|
{ "bleed_alpha_image_shader", make_ringed_alpha_image, make_shader },
|
2015-10-23 18:13:01 +00:00
|
|
|
};
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
/** This GM exercises the behavior of the drawBitmapRect & drawImageRect calls. Specifically their
|
|
|
|
handling of :
|
|
|
|
- SrcRectConstraint(bleed vs.no - bleed)
|
|
|
|
- handling of the sub - region feature(area - of - interest) of drawBitmap*
|
|
|
|
- handling of 8888 vs. A8 (including presence of a shader in the A8 case).
|
|
|
|
In particular, we should never see the padding outside of an SkBitmap's sub - region (green for
|
|
|
|
8888, 1/4 for alpha). In some instances we can see the two outer rings outside of the area o
|
|
|
|
interest (i.e., the inner four checks) due to AA or filtering if allowed by the
|
|
|
|
SrcRectConstraint.
|
|
|
|
*/
|
2013-07-25 21:34:00 +00:00
|
|
|
class BleedGM : public skiagm::GM {
|
|
|
|
public:
|
2016-07-13 21:50:17 +00:00
|
|
|
BleedGM(BleedTest bt) : fBT(bt){}
|
2013-07-25 21:34:00 +00:00
|
|
|
|
|
|
|
protected:
|
2014-04-30 13:20:45 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkString onShortName() override {
|
2015-07-14 17:54:12 +00:00
|
|
|
return SkString(gBleedRec[fBT].fName);
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
SkISize onISize() override {
|
2015-11-04 12:36:12 +00:00
|
|
|
return SkISize::Make(1200, 1080);
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
void drawPixels(SkCanvas* canvas, const TestPixels& pixels, const SkRect& src,
|
|
|
|
const SkRect& dst, const SkPaint* paint,
|
|
|
|
SkCanvas::SrcRectConstraint constraint) {
|
|
|
|
if (TestPixels::kBitmap == pixels.fType) {
|
|
|
|
canvas->drawBitmapRect(pixels.fBitmap, src, dst, paint, constraint);
|
|
|
|
} else {
|
2016-03-17 17:51:11 +00:00
|
|
|
canvas->drawImageRect(pixels.fImage.get(), src, dst, paint, constraint);
|
2015-11-09 18:06:06 +00:00
|
|
|
}
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
// Draw the area of interest of the small image
|
2015-10-23 18:13:01 +00:00
|
|
|
void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
|
2015-07-14 17:54:12 +00:00
|
|
|
SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
|
2015-11-09 18:06:06 +00:00
|
|
|
|
|
|
|
SkRect src = SkRect::Make(fSmallTestPixels.fRect);
|
2015-07-14 17:54:12 +00:00
|
|
|
SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
|
|
|
|
SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
|
2013-07-26 07:00:58 +00:00
|
|
|
|
2013-08-20 12:09:32 +00:00
|
|
|
SkPaint paint;
|
2015-03-16 17:08:34 +00:00
|
|
|
paint.setFilterQuality(filter);
|
2015-10-23 18:13:01 +00:00
|
|
|
paint.setShader(fShader);
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
|
|
paint.setAntiAlias(aa);
|
2013-08-20 12:09:32 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
|
2013-08-20 12:09:32 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
// Draw the area of interest of the large image
|
2015-10-23 18:13:01 +00:00
|
|
|
void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
|
2015-07-14 17:54:12 +00:00
|
|
|
SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
|
2015-11-09 18:06:06 +00:00
|
|
|
SkRect src = SkRect::Make(fBigTestPixels.fRect);
|
2015-07-14 17:54:12 +00:00
|
|
|
SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
|
|
|
|
SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
|
2013-07-25 21:34:00 +00:00
|
|
|
|
|
|
|
SkPaint paint;
|
2015-03-16 17:08:34 +00:00
|
|
|
paint.setFilterQuality(filter);
|
2015-10-23 18:13:01 +00:00
|
|
|
paint.setShader(fShader);
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
|
|
paint.setAntiAlias(aa);
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
|
2013-08-20 12:09:32 +00:00
|
|
|
}
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
// Draw upper-left 1/4 of the area of interest of the large image
|
2015-10-23 18:13:01 +00:00
|
|
|
void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
|
2015-07-14 17:54:12 +00:00
|
|
|
SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
|
2015-11-09 18:06:06 +00:00
|
|
|
SkRect src = SkRect::MakeXYWH(SkIntToScalar(fBigTestPixels.fRect.fLeft),
|
|
|
|
SkIntToScalar(fBigTestPixels.fRect.fTop),
|
|
|
|
fBigTestPixels.fRect.width()/2.f,
|
|
|
|
fBigTestPixels.fRect.height()/2.f);
|
2015-07-14 17:54:12 +00:00
|
|
|
SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
|
|
|
|
SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2013-08-20 12:09:32 +00:00
|
|
|
SkPaint paint;
|
2015-03-16 17:08:34 +00:00
|
|
|
paint.setFilterQuality(filter);
|
2015-10-23 18:13:01 +00:00
|
|
|
paint.setShader(fShader);
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
|
|
paint.setAntiAlias(aa);
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
|
2013-08-20 12:09:32 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
// Draw the area of interest of the small image with a normal blur
|
2015-10-23 18:13:01 +00:00
|
|
|
void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
|
2015-07-14 17:54:12 +00:00
|
|
|
SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
|
2015-11-09 18:06:06 +00:00
|
|
|
SkRect src = SkRect::Make(fSmallTestPixels.fRect);
|
2015-07-14 17:54:12 +00:00
|
|
|
SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
|
|
|
|
SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
|
2013-08-20 16:51:20 +00:00
|
|
|
|
|
|
|
SkPaint paint;
|
2015-03-16 17:08:34 +00:00
|
|
|
paint.setFilterQuality(filter);
|
2016-04-04 17:02:58 +00:00
|
|
|
paint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
|
|
|
|
SkBlurMask::ConvertRadiusToSigma(3)));
|
2015-10-23 18:13:01 +00:00
|
|
|
paint.setShader(fShader);
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
|
|
paint.setAntiAlias(aa);
|
2013-08-20 16:51:20 +00:00
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
|
2013-08-20 16:51:20 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
// Draw the area of interest of the small image with a outer blur
|
2015-11-04 12:36:12 +00:00
|
|
|
void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
|
|
|
|
SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
|
2015-11-09 18:06:06 +00:00
|
|
|
SkRect src = SkRect::Make(fSmallTestPixels.fRect);
|
2015-11-04 12:36:12 +00:00
|
|
|
SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
|
|
|
|
SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
|
|
|
|
|
|
|
|
SkPaint paint;
|
|
|
|
paint.setFilterQuality(filter);
|
2016-04-04 17:02:58 +00:00
|
|
|
paint.setMaskFilter(SkBlurMaskFilter::Make(kOuter_SkBlurStyle,
|
|
|
|
SkBlurMask::ConvertRadiusToSigma(7)));
|
2015-11-04 12:36:12 +00:00
|
|
|
paint.setShader(fShader);
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
|
|
paint.setAntiAlias(aa);
|
|
|
|
|
2015-11-09 18:06:06 +00:00
|
|
|
this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
|
2015-11-04 12:36:12 +00:00
|
|
|
}
|
|
|
|
|
2016-07-13 21:50:17 +00:00
|
|
|
void onOnceBeforeDraw() override {
|
|
|
|
SkAssertResult(gBleedRec[fBT].fPixelMaker(&fSmallTestPixels, kSmallSize, kSmallSize));
|
|
|
|
SkAssertResult(gBleedRec[fBT].fPixelMaker(&fBigTestPixels, 2 * kMaxTileSize,
|
|
|
|
2 * kMaxTileSize));
|
|
|
|
}
|
2015-11-09 18:06:06 +00:00
|
|
|
|
2016-07-13 21:50:17 +00:00
|
|
|
void onDraw(SkCanvas* canvas) override {
|
2016-03-09 17:50:50 +00:00
|
|
|
fShader = gBleedRec[fBT].fShaderMaker();
|
2015-11-09 18:06:06 +00:00
|
|
|
|
2013-08-20 12:09:32 +00:00
|
|
|
canvas->clear(SK_ColorGRAY);
|
2015-10-23 18:13:01 +00:00
|
|
|
SkTDArray<SkMatrix> matrices;
|
|
|
|
// Draw with identity
|
|
|
|
*matrices.append() = SkMatrix::I();
|
|
|
|
|
|
|
|
// Draw with rotation and scale down in x, up in y.
|
|
|
|
SkMatrix m;
|
2016-09-01 18:24:54 +00:00
|
|
|
constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
|
2015-10-23 18:13:01 +00:00
|
|
|
m.setTranslate(0, kBottom);
|
|
|
|
m.preRotate(15.f, 0, kBottom + kBlockSpacing);
|
|
|
|
m.preScale(0.71f, 1.22f);
|
|
|
|
*matrices.append() = m;
|
|
|
|
|
|
|
|
// Align the next set with the middle of the previous in y, translated to the right in x.
|
|
|
|
SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} };
|
|
|
|
matrices[matrices.count()-1].mapPoints(corners, 4);
|
|
|
|
SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
|
|
|
|
SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX),
|
|
|
|
SkTMax(corners[2].fX, corners[3].fX));
|
|
|
|
m.setTranslate(x, y);
|
|
|
|
m.preScale(0.2f, 0.2f);
|
|
|
|
*matrices.append() = m;
|
|
|
|
|
|
|
|
SkScalar maxX = 0;
|
|
|
|
for (int antiAlias = 0; antiAlias < 2; ++antiAlias) {
|
2013-11-22 20:34:59 +00:00
|
|
|
canvas->save();
|
2015-10-23 18:13:01 +00:00
|
|
|
canvas->translate(maxX, 0);
|
|
|
|
for (int m = 0; m < matrices.count(); ++m) {
|
|
|
|
canvas->save();
|
|
|
|
canvas->concat(matrices[m]);
|
|
|
|
bool aa = SkToBool(antiAlias);
|
|
|
|
|
|
|
|
// First draw a column with no bleeding and no filtering
|
|
|
|
this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
// Then draw a column with no bleeding and low filtering
|
|
|
|
this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
// Then draw a column with no bleeding and high filtering
|
|
|
|
this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
// Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
|
|
|
|
this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
// Then draw a column with bleeding and low filtering
|
|
|
|
this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
// Finally draw a column with bleeding and high filtering
|
|
|
|
this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
|
|
|
|
this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
|
2015-11-04 12:36:12 +00:00
|
|
|
this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
|
2015-10-23 18:13:01 +00:00
|
|
|
|
|
|
|
SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } };
|
|
|
|
matrices[m].mapPoints(corners, 4);
|
|
|
|
SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX),
|
|
|
|
SkTMax(corners[2].fX, corners[3].fX));
|
|
|
|
maxX = SkTMax(maxX, x);
|
|
|
|
canvas->restore();
|
2013-11-22 20:34:59 +00:00
|
|
|
}
|
|
|
|
canvas->restore();
|
|
|
|
}
|
2013-07-25 21:34:00 +00:00
|
|
|
}
|
|
|
|
|
2015-05-27 20:23:23 +00:00
|
|
|
#if SK_SUPPORT_GPU
|
|
|
|
void modifyGrContextOptions(GrContextOptions* options) override {
|
2015-11-02 19:36:52 +00:00
|
|
|
options->fMaxTileSizeOverride = kMaxTileSize;
|
2015-05-27 20:23:23 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-07-25 21:34:00 +00:00
|
|
|
private:
|
2016-09-01 18:24:54 +00:00
|
|
|
static constexpr int kBlockSize = 70;
|
|
|
|
static constexpr int kBlockSpacing = 12;
|
|
|
|
|
|
|
|
static constexpr int kCol0X = kBlockSpacing;
|
|
|
|
static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
|
|
|
|
static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
|
|
|
|
static constexpr int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
|
|
|
|
static constexpr int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
|
|
|
|
static constexpr int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
|
|
|
|
static constexpr int kWidth = 7*kBlockSpacing + 6*kBlockSize;
|
|
|
|
|
|
|
|
static constexpr int kRow0Y = kBlockSpacing;
|
|
|
|
static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
|
|
|
|
static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
|
|
|
|
static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
|
|
|
|
static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
|
|
|
|
|
|
|
|
static constexpr int kSmallSize = 6;
|
|
|
|
static constexpr int kMaxTileSize = 32;
|
2013-07-25 21:34:00 +00:00
|
|
|
|
2016-03-09 17:50:50 +00:00
|
|
|
TestPixels fBigTestPixels;
|
|
|
|
TestPixels fSmallTestPixels;
|
2015-10-23 18:13:01 +00:00
|
|
|
|
2016-03-09 17:50:50 +00:00
|
|
|
sk_sp<SkShader> fShader;
|
2015-10-23 18:13:01 +00:00
|
|
|
|
2016-03-09 17:50:50 +00:00
|
|
|
const BleedTest fBT;
|
2013-07-25 21:34:00 +00:00
|
|
|
|
|
|
|
typedef GM INHERITED;
|
|
|
|
};
|
|
|
|
|
2015-11-02 20:33:21 +00:00
|
|
|
|
2015-07-14 17:54:12 +00:00
|
|
|
DEF_GM( return new BleedGM(kUseBitmap_BleedTest); )
|
|
|
|
DEF_GM( return new BleedGM(kUseImage_BleedTest); )
|
2015-10-23 18:13:01 +00:00
|
|
|
DEF_GM( return new BleedGM(kUseAlphaBitmap_BleedTest); )
|
|
|
|
DEF_GM( return new BleedGM(kUseAlphaImage_BleedTest); )
|
2015-11-02 20:33:21 +00:00
|
|
|
DEF_GM( return new BleedGM(kUseAlphaBitmapShader_BleedTest); )
|
|
|
|
DEF_GM( return new BleedGM(kUseAlphaImageShader_BleedTest); )
|
2016-07-25 15:11:58 +00:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "SkSurface.h"
|
|
|
|
|
|
|
|
sk_sp<SkSurface> make_surface(SkCanvas* canvas, const SkImageInfo& info) {
|
|
|
|
auto surface = canvas->makeSurface(info);
|
|
|
|
if (!surface) {
|
|
|
|
surface = SkSurface::MakeRaster(info);
|
|
|
|
}
|
|
|
|
return surface;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct an image and return the inner "src" rect. Build the image such that the interior is
|
|
|
|
// blue, with a margin of blue (2px) but then an outer margin of red.
|
|
|
|
//
|
|
|
|
// Show that kFast_SrcRectConstraint sees even the red margin (due to mipmapping) when the image
|
|
|
|
// is scaled down far enough.
|
|
|
|
//
|
|
|
|
static sk_sp<SkImage> make_image(SkCanvas* canvas, SkRect* srcR) {
|
2016-07-26 15:26:46 +00:00
|
|
|
// Intentially making the size a power of 2 to avoid the noise from how different GPUs will
|
|
|
|
// produce different mipmap filtering when we have an odd sized texture.
|
|
|
|
const int N = 10 + 2 + 8 + 2 + 10;
|
2016-07-25 15:11:58 +00:00
|
|
|
SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
|
|
|
|
auto surface = make_surface(canvas, info);
|
|
|
|
SkCanvas* c = surface->getCanvas();
|
|
|
|
SkRect r = SkRect::MakeIWH(info.width(), info.height());
|
|
|
|
SkPaint paint;
|
|
|
|
|
|
|
|
paint.setColor(SK_ColorRED);
|
|
|
|
c->drawRect(r, paint);
|
2016-07-26 15:26:46 +00:00
|
|
|
r.inset(10, 10);
|
2016-07-25 15:11:58 +00:00
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
|
|
c->drawRect(r, paint);
|
|
|
|
|
|
|
|
*srcR = r.makeInset(2, 2);
|
|
|
|
return surface->makeImageSnapshot();
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
|
|
|
|
SkRect src;
|
|
|
|
sk_sp<SkImage> img = make_image(canvas, &src);
|
|
|
|
SkPaint paint;
|
|
|
|
|
|
|
|
canvas->translate(10, 10);
|
|
|
|
|
|
|
|
const SkCanvas::SrcRectConstraint constraints[] = {
|
|
|
|
SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
|
|
|
|
};
|
|
|
|
const SkFilterQuality qualities[] = {
|
|
|
|
kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality
|
|
|
|
};
|
|
|
|
for (auto constraint : constraints) {
|
|
|
|
canvas->save();
|
|
|
|
for (auto quality : qualities) {
|
|
|
|
paint.setFilterQuality(quality);
|
|
|
|
auto surf = make_surface(canvas, SkImageInfo::MakeN32Premul(1, 1));
|
|
|
|
surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), &paint, constraint);
|
|
|
|
// now blow up the 1 pixel result
|
|
|
|
canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100), nullptr);
|
|
|
|
canvas->translate(120, 0);
|
|
|
|
}
|
|
|
|
canvas->restore();
|
|
|
|
canvas->translate(0, 120);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|