blob: b6ee10b555421951822e6f7189e756d5eef45dfb [file] [log] [blame]
robertphillips@google.comaaa9b292013-07-25 21:34:00 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm.h"
robertphillips@google.comb7061172013-09-06 14:16:12 +00009#include "SkBlurMask.h"
robertphillips@google.com2cc0b472013-08-20 16:51:20 +000010#include "SkBlurMaskFilter.h"
robertphillips@google.comb7061172013-09-06 14:16:12 +000011#include "SkCanvas.h"
bsalomon9003d1e2015-10-23 11:13:01 -070012#include "SkGradientShader.h"
reeda5517e22015-07-14 10:54:12 -070013#include "SkImage.h"
Mike Klein33d20552017-03-22 13:47:51 -040014#include "SkTDArray.h"
bsalomon9c586542015-11-02 12:33:21 -080015#include "SkUtils.h"
Mike Reed46596ae2018-01-02 15:40:29 -050016#include "sk_tool_utils.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000017
18#if SK_SUPPORT_GPU
19#include "GrContext.h"
bsalomon4ee6bd82015-05-27 13:23:23 -070020#include "GrContextOptions.h"
bsalomon9c586542015-11-02 12:33:21 -080021#include "SkGr.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000022#endif
23
bsalomon5c1262d2015-11-09 10:06:06 -080024/** Holds either a bitmap or image to be rendered and a rect that indicates what part of the bitmap
25 or image should be tested by the GM. The area outside of the rect is present to check
26 for bleed due to filtering/blurring. */
27struct TestPixels {
28 enum Type {
29 kBitmap,
30 kImage
31 };
reed9ce9d672016-03-17 10:51:11 -070032 Type fType;
33 SkBitmap fBitmap;
34 sk_sp<SkImage> fImage;
35 SkIRect fRect; // The region of the bitmap/image that should be rendered.
bsalomon5c1262d2015-11-09 10:06:06 -080036};
reeda5517e22015-07-14 10:54:12 -070037
bsalomon5c1262d2015-11-09 10:06:06 -080038/** Creates a bitmap with two one-pixel rings around a checkerboard. The checkerboard is 2x2
39 logically where each check has as many pixels as is necessary to fill the interior. The rect
40 to draw is set to the checkerboard portion. */
41template<typename PIXEL_TYPE>
bsalomona2e08372016-07-13 14:50:17 -070042bool make_ringed_bitmap(TestPixels* result, int width, int height,
bsalomon5c1262d2015-11-09 10:06:06 -080043 SkColorType ct, SkAlphaType at,
44 PIXEL_TYPE outerRingColor, PIXEL_TYPE innerRingColor,
45 PIXEL_TYPE checkColor1, PIXEL_TYPE checkColor2) {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000046 SkASSERT(0 == width % 2 && 0 == height % 2);
bsalomon5c1262d2015-11-09 10:06:06 -080047 SkASSERT(width >= 6 && height >= 6);
skia.committer@gmail.comed000842013-11-09 07:02:23 +000048
bsalomon5c1262d2015-11-09 10:06:06 -080049 result->fType = TestPixels::kBitmap;
50 SkImageInfo info = SkImageInfo::Make(width, height, ct, at);
51 size_t rowBytes = SkAlign4(info.minRowBytes());
52 result->fBitmap.allocPixels(info, rowBytes);
53
54 PIXEL_TYPE* scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 0);
55 for (int x = 0; x < width; ++x) {
56 scanline[x] = outerRingColor;
57 }
58 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 1);
59 scanline[0] = outerRingColor;
60 for (int x = 1; x < width - 1; ++x) {
61 scanline[x] = innerRingColor;
62 }
63 scanline[width - 1] = outerRingColor;
64
65 for (int y = 2; y < height / 2; ++y) {
66 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
67 scanline[0] = outerRingColor;
68 scanline[1] = innerRingColor;
69 for (int x = 2; x < width / 2; ++x) {
70 scanline[x] = checkColor1;
71 }
72 for (int x = width / 2; x < width - 2; ++x) {
73 scanline[x] = checkColor2;
74 }
75 scanline[width - 2] = innerRingColor;
76 scanline[width - 1] = outerRingColor;
77 }
78
79 for (int y = height / 2; y < height - 2; ++y) {
80 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
81 scanline[0] = outerRingColor;
82 scanline[1] = innerRingColor;
83 for (int x = 2; x < width / 2; ++x) {
84 scanline[x] = checkColor2;
85 }
86 for (int x = width / 2; x < width - 2; ++x) {
87 scanline[x] = checkColor1;
88 }
89 scanline[width - 2] = innerRingColor;
90 scanline[width - 1] = outerRingColor;
91 }
92
93 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 2);
94 scanline[0] = outerRingColor;
95 for (int x = 1; x < width - 1; ++x) {
96 scanline[x] = innerRingColor;
97 }
98 scanline[width - 1] = outerRingColor;
99
100 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 1);
101 for (int x = 0; x < width; ++x) {
102 scanline[x] = outerRingColor;
103 }
104 result->fBitmap.setImmutable();
105 result->fRect.set(2, 2, width - 2, height - 2);
106 return true;
107}
108
bsalomona2e08372016-07-13 14:50:17 -0700109/** Create a black and white checked bitmap with 2 1-pixel rings around the outside edge.
bsalomon5c1262d2015-11-09 10:06:06 -0800110 The inner ring is red and the outer ring is blue. */
bsalomona2e08372016-07-13 14:50:17 -0700111static bool make_ringed_color_bitmap(TestPixels* result, int width, int height) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700112 const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
113 const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
114 const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
115 const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
bsalomon48b24612016-08-25 06:45:29 -0700116 return make_ringed_bitmap<SkPMColor>(result, width, height, kN32_SkColorType,
bsalomon5c1262d2015-11-09 10:06:06 -0800117 kPremul_SkAlphaType, kBlue, kRed, kBlack, kWhite);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000118}
119
bsalomondf85a722015-11-04 04:23:45 -0800120/** Makes a alpha bitmap with 1 wide rect/ring of 0s, an inset of 1s, and the interior is a 2x2
bsalomon9003d1e2015-10-23 11:13:01 -0700121 checker board of 3/4 and 1/2. The inner checkers are large enough to fill the interior with
122 the 2x2 checker grid. */
bsalomona2e08372016-07-13 14:50:17 -0700123static bool make_ringed_alpha_bitmap(TestPixels* result, int width, int height) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700124 constexpr uint8_t kZero = 0x00;
125 constexpr uint8_t kHalf = 0x80;
126 constexpr uint8_t k3Q = 0xC0;
127 constexpr uint8_t kOne = 0xFF;
bsalomona2e08372016-07-13 14:50:17 -0700128 return make_ringed_bitmap<uint8_t>(result, width, height, kAlpha_8_SkColorType,
bsalomon5c1262d2015-11-09 10:06:06 -0800129 kPremul_SkAlphaType, kZero, kOne, k3Q, kHalf);
130}
131
132/** Helper to reuse above functions to produce images rather than bmps */
133static void bmp_to_image(TestPixels* result) {
134 SkASSERT(TestPixels::kBitmap == result->fType);
reed9ce9d672016-03-17 10:51:11 -0700135 result->fImage = SkImage::MakeFromBitmap(result->fBitmap);
bsalomon5c1262d2015-11-09 10:06:06 -0800136 SkASSERT(result->fImage);
137 result->fType = TestPixels::kImage;
138 result->fBitmap.reset();
139}
140
141/** Color image case. */
bsalomona2e08372016-07-13 14:50:17 -0700142bool make_ringed_color_image(TestPixels* result, int width, int height) {
143 if (make_ringed_color_bitmap(result, width, height)) {
bsalomon5c1262d2015-11-09 10:06:06 -0800144 bmp_to_image(result);
145 return true;
146 }
147 return false;
148}
149
150/** Alpha image case. */
bsalomona2e08372016-07-13 14:50:17 -0700151bool make_ringed_alpha_image(TestPixels* result, int width, int height) {
152 if (make_ringed_alpha_bitmap(result, width, height)) {
bsalomon5c1262d2015-11-09 10:06:06 -0800153 bmp_to_image(result);
154 return true;
155 }
156 return false;
157}
158
reed2ad1aa62016-03-09 09:50:50 -0800159static sk_sp<SkShader> make_shader() {
mtkleindbfd7ab2016-09-01 11:24:54 -0700160 constexpr SkPoint pts[] = { {0, 0}, {20, 20} };
161 constexpr SkColor colors[] = { SK_ColorGREEN, SK_ColorYELLOW };
reed2ad1aa62016-03-09 09:50:50 -0800162 return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kMirror_TileMode);
bsalomon9003d1e2015-10-23 11:13:01 -0700163}
164
reed2ad1aa62016-03-09 09:50:50 -0800165static sk_sp<SkShader> make_null_shader() { return nullptr; }
bsalomon9003d1e2015-10-23 11:13:01 -0700166
167enum BleedTest {
168 kUseBitmap_BleedTest,
169 kUseImage_BleedTest,
170 kUseAlphaBitmap_BleedTest,
171 kUseAlphaImage_BleedTest,
172 kUseAlphaBitmapShader_BleedTest,
173 kUseAlphaImageShader_BleedTest,
174};
175
176const struct {
177 const char* fName;
bsalomona2e08372016-07-13 14:50:17 -0700178 bool (*fPixelMaker)(TestPixels* result, int width, int height);
reed2ad1aa62016-03-09 09:50:50 -0800179 sk_sp<SkShader> (*fShaderMaker)();
bsalomon9003d1e2015-10-23 11:13:01 -0700180} gBleedRec[] = {
bsalomon5c1262d2015-11-09 10:06:06 -0800181 { "bleed", make_ringed_color_bitmap, make_null_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800182 { "bleed_image", make_ringed_color_image, make_null_shader },
183 { "bleed_alpha_bmp", make_ringed_alpha_bitmap, make_null_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800184 { "bleed_alpha_image", make_ringed_alpha_image, make_null_shader },
185 { "bleed_alpha_bmp_shader", make_ringed_alpha_bitmap, make_shader },
bsalomon5c1262d2015-11-09 10:06:06 -0800186 { "bleed_alpha_image_shader", make_ringed_alpha_image, make_shader },
bsalomon9003d1e2015-10-23 11:13:01 -0700187};
188
bsalomon5c1262d2015-11-09 10:06:06 -0800189/** This GM exercises the behavior of the drawBitmapRect & drawImageRect calls. Specifically their
190 handling of :
191 - SrcRectConstraint(bleed vs.no - bleed)
192 - handling of the sub - region feature(area - of - interest) of drawBitmap*
193 - handling of 8888 vs. A8 (including presence of a shader in the A8 case).
bsalomon5c1262d2015-11-09 10:06:06 -0800194 In particular, we should never see the padding outside of an SkBitmap's sub - region (green for
195 8888, 1/4 for alpha). In some instances we can see the two outer rings outside of the area o
196 interest (i.e., the inner four checks) due to AA or filtering if allowed by the
197 SrcRectConstraint.
198*/
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000199class BleedGM : public skiagm::GM {
200public:
bsalomona2e08372016-07-13 14:50:17 -0700201 BleedGM(BleedTest bt) : fBT(bt){}
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000202
203protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000204
mtklein36352bf2015-03-25 18:17:31 -0700205 SkString onShortName() override {
reeda5517e22015-07-14 10:54:12 -0700206 return SkString(gBleedRec[fBT].fName);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000207 }
208
mtklein36352bf2015-03-25 18:17:31 -0700209 SkISize onISize() override {
bsalomonf57ef1c2015-11-04 04:36:12 -0800210 return SkISize::Make(1200, 1080);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000211 }
212
bsalomon5c1262d2015-11-09 10:06:06 -0800213 void drawPixels(SkCanvas* canvas, const TestPixels& pixels, const SkRect& src,
214 const SkRect& dst, const SkPaint* paint,
215 SkCanvas::SrcRectConstraint constraint) {
216 if (TestPixels::kBitmap == pixels.fType) {
217 canvas->drawBitmapRect(pixels.fBitmap, src, dst, paint, constraint);
218 } else {
reed9ce9d672016-03-17 10:51:11 -0700219 canvas->drawImageRect(pixels.fImage.get(), src, dst, paint, constraint);
bsalomon5c1262d2015-11-09 10:06:06 -0800220 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000221 }
222
bsalomon5c1262d2015-11-09 10:06:06 -0800223 // Draw the area of interest of the small image
bsalomon9003d1e2015-10-23 11:13:01 -0700224 void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700225 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800226
227 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700228 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
229 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000230
231 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700232 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700233 paint.setShader(fShader);
234 paint.setColor(SK_ColorBLUE);
235 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000236
bsalomon5c1262d2015-11-09 10:06:06 -0800237 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000238 }
239
bsalomon5c1262d2015-11-09 10:06:06 -0800240 // Draw the area of interest of the large image
bsalomon9003d1e2015-10-23 11:13:01 -0700241 void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700242 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800243 SkRect src = SkRect::Make(fBigTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700244 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
245 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000246
247 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700248 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700249 paint.setShader(fShader);
250 paint.setColor(SK_ColorBLUE);
251 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000252
bsalomon5c1262d2015-11-09 10:06:06 -0800253 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000254 }
255
bsalomon5c1262d2015-11-09 10:06:06 -0800256 // Draw upper-left 1/4 of the area of interest of the large image
bsalomon9003d1e2015-10-23 11:13:01 -0700257 void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700258 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800259 SkRect src = SkRect::MakeXYWH(SkIntToScalar(fBigTestPixels.fRect.fLeft),
260 SkIntToScalar(fBigTestPixels.fRect.fTop),
261 fBigTestPixels.fRect.width()/2.f,
262 fBigTestPixels.fRect.height()/2.f);
reeda5517e22015-07-14 10:54:12 -0700263 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
264 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000265
266 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700267 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700268 paint.setShader(fShader);
269 paint.setColor(SK_ColorBLUE);
270 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000271
bsalomon5c1262d2015-11-09 10:06:06 -0800272 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000273 }
274
bsalomon5c1262d2015-11-09 10:06:06 -0800275 // Draw the area of interest of the small image with a normal blur
bsalomon9003d1e2015-10-23 11:13:01 -0700276 void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700277 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800278 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700279 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
280 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000281
282 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700283 paint.setFilterQuality(filter);
reedefdfd512016-04-04 10:02:58 -0700284 paint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
285 SkBlurMask::ConvertRadiusToSigma(3)));
bsalomon9003d1e2015-10-23 11:13:01 -0700286 paint.setShader(fShader);
287 paint.setColor(SK_ColorBLUE);
288 paint.setAntiAlias(aa);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000289
bsalomon5c1262d2015-11-09 10:06:06 -0800290 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000291 }
292
bsalomon5c1262d2015-11-09 10:06:06 -0800293 // Draw the area of interest of the small image with a outer blur
bsalomonf57ef1c2015-11-04 04:36:12 -0800294 void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
295 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800296 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
bsalomonf57ef1c2015-11-04 04:36:12 -0800297 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
298 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
299
300 SkPaint paint;
301 paint.setFilterQuality(filter);
reedefdfd512016-04-04 10:02:58 -0700302 paint.setMaskFilter(SkBlurMaskFilter::Make(kOuter_SkBlurStyle,
303 SkBlurMask::ConvertRadiusToSigma(7)));
bsalomonf57ef1c2015-11-04 04:36:12 -0800304 paint.setShader(fShader);
305 paint.setColor(SK_ColorBLUE);
306 paint.setAntiAlias(aa);
307
bsalomon5c1262d2015-11-09 10:06:06 -0800308 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
bsalomonf57ef1c2015-11-04 04:36:12 -0800309 }
310
bsalomona2e08372016-07-13 14:50:17 -0700311 void onOnceBeforeDraw() override {
312 SkAssertResult(gBleedRec[fBT].fPixelMaker(&fSmallTestPixels, kSmallSize, kSmallSize));
313 SkAssertResult(gBleedRec[fBT].fPixelMaker(&fBigTestPixels, 2 * kMaxTileSize,
314 2 * kMaxTileSize));
315 }
316
mtklein36352bf2015-03-25 18:17:31 -0700317 void onDraw(SkCanvas* canvas) override {
reed2ad1aa62016-03-09 09:50:50 -0800318 fShader = gBleedRec[fBT].fShaderMaker();
bsalomon5c1262d2015-11-09 10:06:06 -0800319
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000320 canvas->clear(SK_ColorGRAY);
bsalomon9003d1e2015-10-23 11:13:01 -0700321 SkTDArray<SkMatrix> matrices;
322 // Draw with identity
323 *matrices.append() = SkMatrix::I();
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000324
bsalomon9003d1e2015-10-23 11:13:01 -0700325 // Draw with rotation and scale down in x, up in y.
326 SkMatrix m;
mtkleindbfd7ab2016-09-01 11:24:54 -0700327 constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
bsalomon9003d1e2015-10-23 11:13:01 -0700328 m.setTranslate(0, kBottom);
329 m.preRotate(15.f, 0, kBottom + kBlockSpacing);
330 m.preScale(0.71f, 1.22f);
331 *matrices.append() = m;
332
333 // Align the next set with the middle of the previous in y, translated to the right in x.
334 SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} };
335 matrices[matrices.count()-1].mapPoints(corners, 4);
336 SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
337 SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX),
338 SkTMax(corners[2].fX, corners[3].fX));
339 m.setTranslate(x, y);
340 m.preScale(0.2f, 0.2f);
341 *matrices.append() = m;
342
343 SkScalar maxX = 0;
344 for (int antiAlias = 0; antiAlias < 2; ++antiAlias) {
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000345 canvas->save();
bsalomon9003d1e2015-10-23 11:13:01 -0700346 canvas->translate(maxX, 0);
347 for (int m = 0; m < matrices.count(); ++m) {
348 canvas->save();
349 canvas->concat(matrices[m]);
350 bool aa = SkToBool(antiAlias);
351
352 // First draw a column with no bleeding and no filtering
353 this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
354 this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
355 this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
356 this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800357 this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700358
359 // Then draw a column with no bleeding and low filtering
360 this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
361 this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
362 this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
363 this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800364 this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700365
366 // Then draw a column with no bleeding and high filtering
367 this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
368 this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
369 this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
370 this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800371 this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700372
373 // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
374 this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
375 this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
376 this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
377 this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800378 this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700379
380 // Then draw a column with bleeding and low filtering
381 this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
382 this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
383 this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
384 this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800385 this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700386
387 // Finally draw a column with bleeding and high filtering
388 this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
389 this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
390 this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
391 this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800392 this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700393
394 SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } };
395 matrices[m].mapPoints(corners, 4);
396 SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX),
397 SkTMax(corners[2].fX, corners[3].fX));
398 maxX = SkTMax(maxX, x);
399 canvas->restore();
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000400 }
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000401 canvas->restore();
402 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000403 }
404
bsalomon4ee6bd82015-05-27 13:23:23 -0700405#if SK_SUPPORT_GPU
406 void modifyGrContextOptions(GrContextOptions* options) override {
bsalomon8c07b7a2015-11-02 11:36:52 -0800407 options->fMaxTileSizeOverride = kMaxTileSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700408 }
409#endif
410
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000411private:
mtkleindbfd7ab2016-09-01 11:24:54 -0700412 static constexpr int kBlockSize = 70;
413 static constexpr int kBlockSpacing = 12;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000414
mtkleindbfd7ab2016-09-01 11:24:54 -0700415 static constexpr int kCol0X = kBlockSpacing;
416 static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
417 static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
418 static constexpr int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
419 static constexpr int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
420 static constexpr int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
421 static constexpr int kWidth = 7*kBlockSpacing + 6*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000422
mtkleindbfd7ab2016-09-01 11:24:54 -0700423 static constexpr int kRow0Y = kBlockSpacing;
424 static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
425 static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
426 static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
427 static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000428
mtkleindbfd7ab2016-09-01 11:24:54 -0700429 static constexpr int kSmallSize = 6;
430 static constexpr int kMaxTileSize = 32;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000431
reed2ad1aa62016-03-09 09:50:50 -0800432 TestPixels fBigTestPixels;
433 TestPixels fSmallTestPixels;
bsalomon9003d1e2015-10-23 11:13:01 -0700434
reed2ad1aa62016-03-09 09:50:50 -0800435 sk_sp<SkShader> fShader;
bsalomon9003d1e2015-10-23 11:13:01 -0700436
reed2ad1aa62016-03-09 09:50:50 -0800437 const BleedTest fBT;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000438
439 typedef GM INHERITED;
440};
441
bsalomon9c586542015-11-02 12:33:21 -0800442
reeda5517e22015-07-14 10:54:12 -0700443DEF_GM( return new BleedGM(kUseBitmap_BleedTest); )
444DEF_GM( return new BleedGM(kUseImage_BleedTest); )
bsalomon9003d1e2015-10-23 11:13:01 -0700445DEF_GM( return new BleedGM(kUseAlphaBitmap_BleedTest); )
446DEF_GM( return new BleedGM(kUseAlphaImage_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800447DEF_GM( return new BleedGM(kUseAlphaBitmapShader_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800448DEF_GM( return new BleedGM(kUseAlphaImageShader_BleedTest); )
reed2adecda2016-07-25 08:11:58 -0700449
450///////////////////////////////////////////////////////////////////////////////////////////////////
451#include "SkSurface.h"
452
reed2adecda2016-07-25 08:11:58 -0700453// Construct an image and return the inner "src" rect. Build the image such that the interior is
454// blue, with a margin of blue (2px) but then an outer margin of red.
455//
456// Show that kFast_SrcRectConstraint sees even the red margin (due to mipmapping) when the image
457// is scaled down far enough.
458//
459static sk_sp<SkImage> make_image(SkCanvas* canvas, SkRect* srcR) {
egdaniel26318c92016-07-26 08:26:46 -0700460 // Intentially making the size a power of 2 to avoid the noise from how different GPUs will
461 // produce different mipmap filtering when we have an odd sized texture.
462 const int N = 10 + 2 + 8 + 2 + 10;
reed2adecda2016-07-25 08:11:58 -0700463 SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
Mike Reed46596ae2018-01-02 15:40:29 -0500464 auto surface = sk_tool_utils::makeSurface(canvas, info);
reed2adecda2016-07-25 08:11:58 -0700465 SkCanvas* c = surface->getCanvas();
466 SkRect r = SkRect::MakeIWH(info.width(), info.height());
467 SkPaint paint;
468
469 paint.setColor(SK_ColorRED);
470 c->drawRect(r, paint);
egdaniel26318c92016-07-26 08:26:46 -0700471 r.inset(10, 10);
reed2adecda2016-07-25 08:11:58 -0700472 paint.setColor(SK_ColorBLUE);
473 c->drawRect(r, paint);
474
475 *srcR = r.makeInset(2, 2);
476 return surface->makeImageSnapshot();
477}
478
479DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
480 SkRect src;
481 sk_sp<SkImage> img = make_image(canvas, &src);
482 SkPaint paint;
483
484 canvas->translate(10, 10);
485
486 const SkCanvas::SrcRectConstraint constraints[] = {
487 SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
488 };
489 const SkFilterQuality qualities[] = {
490 kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality
491 };
492 for (auto constraint : constraints) {
493 canvas->save();
494 for (auto quality : qualities) {
495 paint.setFilterQuality(quality);
Mike Reed46596ae2018-01-02 15:40:29 -0500496 auto surf = sk_tool_utils::makeSurface(canvas, SkImageInfo::MakeN32Premul(1, 1));
reed2adecda2016-07-25 08:11:58 -0700497 surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), &paint, constraint);
498 // now blow up the 1 pixel result
499 canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100), nullptr);
500 canvas->translate(120, 0);
501 }
502 canvas->restore();
503 canvas->translate(0, 120);
504 }
505}
506
507