blob: 5a27b3972ef257f61209f3e48d31614243086e71 [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"
bsalomon9c586542015-11-02 12:33:21 -080014#include "SkUtils.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000015
16#if SK_SUPPORT_GPU
17#include "GrContext.h"
bsalomon4ee6bd82015-05-27 13:23:23 -070018#include "GrContextOptions.h"
bsalomon9c586542015-11-02 12:33:21 -080019#include "SkGr.h"
robertphillips@google.comaaa9b292013-07-25 21:34:00 +000020#endif
21
bsalomon5c1262d2015-11-09 10:06:06 -080022/** Holds either a bitmap or image to be rendered and a rect that indicates what part of the bitmap
23 or image should be tested by the GM. The area outside of the rect is present to check
24 for bleed due to filtering/blurring. */
25struct TestPixels {
26 enum Type {
27 kBitmap,
28 kImage
29 };
reed9ce9d672016-03-17 10:51:11 -070030 Type fType;
31 SkBitmap fBitmap;
32 sk_sp<SkImage> fImage;
33 SkIRect fRect; // The region of the bitmap/image that should be rendered.
bsalomon5c1262d2015-11-09 10:06:06 -080034};
reeda5517e22015-07-14 10:54:12 -070035
bsalomon5c1262d2015-11-09 10:06:06 -080036/** Creates a bitmap with two one-pixel rings around a checkerboard. The checkerboard is 2x2
37 logically where each check has as many pixels as is necessary to fill the interior. The rect
38 to draw is set to the checkerboard portion. */
39template<typename PIXEL_TYPE>
40bool make_ringed_bitmap(GrContext*, TestPixels* result, int width, int height,
41 SkColorType ct, SkAlphaType at,
42 PIXEL_TYPE outerRingColor, PIXEL_TYPE innerRingColor,
43 PIXEL_TYPE checkColor1, PIXEL_TYPE checkColor2) {
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +000044 SkASSERT(0 == width % 2 && 0 == height % 2);
bsalomon5c1262d2015-11-09 10:06:06 -080045 SkASSERT(width >= 6 && height >= 6);
skia.committer@gmail.comed000842013-11-09 07:02:23 +000046
bsalomon5c1262d2015-11-09 10:06:06 -080047 result->fType = TestPixels::kBitmap;
48 SkImageInfo info = SkImageInfo::Make(width, height, ct, at);
49 size_t rowBytes = SkAlign4(info.minRowBytes());
50 result->fBitmap.allocPixels(info, rowBytes);
51
52 PIXEL_TYPE* scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 0);
53 for (int x = 0; x < width; ++x) {
54 scanline[x] = outerRingColor;
55 }
56 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 1);
57 scanline[0] = outerRingColor;
58 for (int x = 1; x < width - 1; ++x) {
59 scanline[x] = innerRingColor;
60 }
61 scanline[width - 1] = outerRingColor;
62
63 for (int y = 2; y < height / 2; ++y) {
64 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
65 scanline[0] = outerRingColor;
66 scanline[1] = innerRingColor;
67 for (int x = 2; x < width / 2; ++x) {
68 scanline[x] = checkColor1;
69 }
70 for (int x = width / 2; x < width - 2; ++x) {
71 scanline[x] = checkColor2;
72 }
73 scanline[width - 2] = innerRingColor;
74 scanline[width - 1] = outerRingColor;
75 }
76
77 for (int y = height / 2; y < height - 2; ++y) {
78 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
79 scanline[0] = outerRingColor;
80 scanline[1] = innerRingColor;
81 for (int x = 2; x < width / 2; ++x) {
82 scanline[x] = checkColor2;
83 }
84 for (int x = width / 2; x < width - 2; ++x) {
85 scanline[x] = checkColor1;
86 }
87 scanline[width - 2] = innerRingColor;
88 scanline[width - 1] = outerRingColor;
89 }
90
91 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 2);
92 scanline[0] = outerRingColor;
93 for (int x = 1; x < width - 1; ++x) {
94 scanline[x] = innerRingColor;
95 }
96 scanline[width - 1] = outerRingColor;
97
98 scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 1);
99 for (int x = 0; x < width; ++x) {
100 scanline[x] = outerRingColor;
101 }
102 result->fBitmap.setImmutable();
103 result->fRect.set(2, 2, width - 2, height - 2);
104 return true;
105}
106
107/** Create a black and white checked texture with 2 1-pixel rings around the outside edge.
108 The inner ring is red and the outer ring is blue. */
109static bool make_ringed_color_bitmap(GrContext* ctx, TestPixels* result, int width, int height) {
110 static const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
111 static const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000112 static const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
113 static const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
bsalomon5c1262d2015-11-09 10:06:06 -0800114 return make_ringed_bitmap<SkPMColor>(ctx, result, width, height, kBGRA_8888_SkColorType,
115 kPremul_SkAlphaType, kBlue, kRed, kBlack, kWhite);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000116}
117
bsalomondf85a722015-11-04 04:23:45 -0800118/** 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 -0700119 checker board of 3/4 and 1/2. The inner checkers are large enough to fill the interior with
120 the 2x2 checker grid. */
bsalomon5c1262d2015-11-09 10:06:06 -0800121static bool make_ringed_alpha_bitmap(GrContext* ctx, TestPixels* result, int width, int height) {
122 static const uint8_t kZero = 0x00;
123 static const uint8_t kHalf = 0x80;
124 static const uint8_t k3Q = 0xC0;
125 static const uint8_t kOne = 0xFF;
126 return make_ringed_bitmap<uint8_t>(ctx, result, width, height, kAlpha_8_SkColorType,
127 kPremul_SkAlphaType, kZero, kOne, k3Q, kHalf);
128}
129
130/** Helper to reuse above functions to produce images rather than bmps */
131static void bmp_to_image(TestPixels* result) {
132 SkASSERT(TestPixels::kBitmap == result->fType);
reed9ce9d672016-03-17 10:51:11 -0700133 result->fImage = SkImage::MakeFromBitmap(result->fBitmap);
bsalomon5c1262d2015-11-09 10:06:06 -0800134 SkASSERT(result->fImage);
135 result->fType = TestPixels::kImage;
136 result->fBitmap.reset();
137}
138
139/** Color image case. */
140bool make_ringed_color_image(GrContext* ctx, TestPixels* result, int width, int height) {
141 if (make_ringed_color_bitmap(ctx, result, width, height)) {
142 bmp_to_image(result);
143 return true;
144 }
145 return false;
146}
147
148/** Alpha image case. */
149bool make_ringed_alpha_image(GrContext* ctx, TestPixels* result, int width, int height) {
150 if (make_ringed_alpha_bitmap(ctx, result, width, height)) {
151 bmp_to_image(result);
152 return true;
153 }
154 return false;
155}
156
157/** Similar to make_ringed_bitmap with these modifications:
158 - The backing store is a texture.
halcanary9d524f22016-03-29 09:03:52 -0700159 - The texture is larger than the bitmap dimensions (it is surrounded by non-content
bsalomon5c1262d2015-11-09 10:06:06 -0800160 padding on the right/bottom of the contents.)
161 - The right/bottom sides of the rings are omitted so that the rect to draw is adjacent to
162 the texture padding.
163 */
164template <typename PIXEL_TYPE>
165bool make_oversized_texture_bitmap(GrContext* ctx, TestPixels* result, int width, int height,
166 GrPixelConfig config, PIXEL_TYPE outerRingColor,
167 PIXEL_TYPE innerRingColor, PIXEL_TYPE checkColor1,
168 PIXEL_TYPE checkColor2, PIXEL_TYPE padColor) {
bsalomon9003d1e2015-10-23 11:13:01 -0700169 SkASSERT(0 == width % 2 && 0 == height % 2);
bsalomon5c1262d2015-11-09 10:06:06 -0800170 SkASSERT(width >= 6 && height >= 6);
171#if SK_SUPPORT_GPU
172 if (!ctx) {
173 return false;
174 }
175 /** Put arbitrary pad to the right and below the bitmap content. */
176 static const int kXPad = 10;
177 static const int kYPad = 17;
178 size_t rowBytes = (width + kXPad) * sizeof(PIXEL_TYPE);
179 SkAutoTMalloc<PIXEL_TYPE> pixels(rowBytes*(height + kYPad));
bsalomon9003d1e2015-10-23 11:13:01 -0700180
bsalomon5c1262d2015-11-09 10:06:06 -0800181 PIXEL_TYPE* scanline = pixels.get();
bsalomon9003d1e2015-10-23 11:13:01 -0700182 for (int x = 0; x < width; ++x) {
bsalomon5c1262d2015-11-09 10:06:06 -0800183 scanline[x] = outerRingColor;
bsalomon9003d1e2015-10-23 11:13:01 -0700184 }
bsalomon5c1262d2015-11-09 10:06:06 -0800185 for (int x = width; x < width + kXPad; ++x) {
186 scanline[x] = padColor;
bsalomon9003d1e2015-10-23 11:13:01 -0700187 }
188
bsalomon5c1262d2015-11-09 10:06:06 -0800189 scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes);
190 scanline[0] = outerRingColor;
191 for (int x = 1; x < width; ++x) {
192 scanline[x] = innerRingColor;
193 }
194 for (int x = width; x < width + kXPad; ++x) {
195 scanline[x] = padColor;
bsalomon9003d1e2015-10-23 11:13:01 -0700196 }
197
bsalomon5c1262d2015-11-09 10:06:06 -0800198 for (int y = 2; y < height / 2 + 1; ++y) {
199 scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes);
200 scanline[0] = outerRingColor;
201 scanline[1] = innerRingColor;
202 for (int x = 2; x < width / 2 + 1; ++x) {
203 scanline[x] = checkColor1;
204 }
205 for (int x = width / 2 + 1; x < width; ++x) {
206 scanline[x] = checkColor2;
207 }
208 for (int x = width; x < width + kXPad; ++x) {
209 scanline[x] = padColor;
210 }
bsalomon9003d1e2015-10-23 11:13:01 -0700211 }
bsalomon9003d1e2015-10-23 11:13:01 -0700212
bsalomon5c1262d2015-11-09 10:06:06 -0800213 for (int y = height / 2 + 1; y < height; ++y) {
214 scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes);
215 scanline[0] = outerRingColor;
216 scanline[1] = innerRingColor;
217 for (int x = 2; x < width / 2 + 1; ++x) {
218 scanline[x] = checkColor2;
219 }
220 for (int x = width / 2 + 1; x < width; ++x) {
221 scanline[x] = checkColor1;
222 }
223 for (int x = width; x < width + kXPad; ++x) {
224 scanline[x] = padColor;
225 }
bsalomon9003d1e2015-10-23 11:13:01 -0700226 }
bsalomon5c1262d2015-11-09 10:06:06 -0800227
228 for (int y = height; y < height + kYPad; ++y) {
229 scanline = (PIXEL_TYPE*)((char*)scanline + rowBytes);
230 for (int x = 0; x < width + kXPad; ++x) {
231 scanline[x] = padColor;
232 }
233 }
234
235 GrSurfaceDesc desc;
236 desc.fConfig = config;
237 desc.fWidth = width + kXPad;
238 desc.fHeight = height + kYPad;
bsalomon5ec26ae2016-02-25 08:33:02 -0800239 SkAutoTUnref<GrTexture> texture(ctx->textureProvider()->createTexture(
240 desc, SkBudgeted::kYes, pixels.get(), rowBytes));
bsalomon5c1262d2015-11-09 10:06:06 -0800241
242 if (!texture) {
243 return false;
244 }
245
246 GrWrapTextureInBitmap(texture, width, height, true, &result->fBitmap);
247 result->fType = TestPixels::kBitmap;
248 result->fBitmap.setImmutable();
249 result->fRect.set(2, 2, width, height);
250 return true;
251#else
252 return false;
253#endif
254}
255
256/** Make the color version of the oversized texture-backed bitmap */
257static bool make_ringed_oversized_color_texture_bitmap(GrContext* ctx, TestPixels* result,
258 int width, int height) {
259 static const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
260 static const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
261 static const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
262 static const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
263 static const SkPMColor kGreen = SkPreMultiplyColor(SK_ColorGREEN);
264 return make_oversized_texture_bitmap<SkPMColor>(
265 ctx, result, width, height, kSkia8888_GrPixelConfig, kBlue, kRed, kBlack, kWhite, kGreen);
266}
267
268/** Make the alpha version of the oversized texture-backed bitmap */
269static bool make_ringed_oversized_alpha_texture_bitmap(GrContext* ctx, TestPixels* result,
270 int width, int height) {
271 static const uint8_t kZero = 0x00;
272 static const uint8_t kHalf = 0x80;
273 static const uint8_t k3Q = 0xC0;
274 static const uint8_t kOne = 0xFF;
275 static const uint8_t k1Q = 0x40;
276 return make_oversized_texture_bitmap<uint8_t>(
277 ctx, result, width, height, kAlpha_8_GrPixelConfig, kZero, kOne, k3Q, kHalf, k1Q);
bsalomon9003d1e2015-10-23 11:13:01 -0700278}
279
reed2ad1aa62016-03-09 09:50:50 -0800280static sk_sp<SkShader> make_shader() {
bsalomon9003d1e2015-10-23 11:13:01 -0700281 static const SkPoint pts[] = { {0, 0}, {20, 20} };
282 static const SkColor colors[] = { SK_ColorGREEN, SK_ColorYELLOW };
reed2ad1aa62016-03-09 09:50:50 -0800283 return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kMirror_TileMode);
bsalomon9003d1e2015-10-23 11:13:01 -0700284}
285
reed2ad1aa62016-03-09 09:50:50 -0800286static sk_sp<SkShader> make_null_shader() { return nullptr; }
bsalomon9003d1e2015-10-23 11:13:01 -0700287
288enum BleedTest {
289 kUseBitmap_BleedTest,
bsalomon9c586542015-11-02 12:33:21 -0800290 kUseTextureBitmap_BleedTest,
bsalomon9003d1e2015-10-23 11:13:01 -0700291 kUseImage_BleedTest,
292 kUseAlphaBitmap_BleedTest,
bsalomon9c586542015-11-02 12:33:21 -0800293 kUseAlphaTextureBitmap_BleedTest,
bsalomon9003d1e2015-10-23 11:13:01 -0700294 kUseAlphaImage_BleedTest,
295 kUseAlphaBitmapShader_BleedTest,
bsalomon9c586542015-11-02 12:33:21 -0800296 kUseAlphaTextureBitmapShader_BleedTest,
bsalomon9003d1e2015-10-23 11:13:01 -0700297 kUseAlphaImageShader_BleedTest,
298};
299
300const struct {
301 const char* fName;
bsalomon5c1262d2015-11-09 10:06:06 -0800302 bool (*fPixelMaker)(GrContext*, TestPixels* result, int width, int height);
reed2ad1aa62016-03-09 09:50:50 -0800303 sk_sp<SkShader> (*fShaderMaker)();
bsalomon9003d1e2015-10-23 11:13:01 -0700304} gBleedRec[] = {
bsalomon5c1262d2015-11-09 10:06:06 -0800305 { "bleed", make_ringed_color_bitmap, make_null_shader },
306 { "bleed_texture_bmp", make_ringed_oversized_color_texture_bitmap, make_null_shader },
307 { "bleed_image", make_ringed_color_image, make_null_shader },
308 { "bleed_alpha_bmp", make_ringed_alpha_bitmap, make_null_shader },
309 { "bleed_alpha_texture_bmp", make_ringed_oversized_alpha_texture_bitmap, make_null_shader },
310 { "bleed_alpha_image", make_ringed_alpha_image, make_null_shader },
311 { "bleed_alpha_bmp_shader", make_ringed_alpha_bitmap, make_shader },
312 { "bleed_alpha_texture_bmp_shader", make_ringed_oversized_alpha_texture_bitmap, make_shader },
313 { "bleed_alpha_image_shader", make_ringed_alpha_image, make_shader },
bsalomon9003d1e2015-10-23 11:13:01 -0700314};
315
bsalomon5c1262d2015-11-09 10:06:06 -0800316/** This GM exercises the behavior of the drawBitmapRect & drawImageRect calls. Specifically their
317 handling of :
318 - SrcRectConstraint(bleed vs.no - bleed)
319 - handling of the sub - region feature(area - of - interest) of drawBitmap*
320 - handling of 8888 vs. A8 (including presence of a shader in the A8 case).
321 - (gpu - only) handling of tiled vs.non - tiled drawing)
322 - (gpu - only) texture's backing a bmp where the texture is larger than the bmp.
323 In particular, we should never see the padding outside of an SkBitmap's sub - region (green for
324 8888, 1/4 for alpha). In some instances we can see the two outer rings outside of the area o
325 interest (i.e., the inner four checks) due to AA or filtering if allowed by the
326 SrcRectConstraint.
327*/
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000328class BleedGM : public skiagm::GM {
329public:
bsalomon5c1262d2015-11-09 10:06:06 -0800330 BleedGM(BleedTest bt) : fCreatedPixels(false), fBT(bt){}
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000331
332protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000333
mtklein36352bf2015-03-25 18:17:31 -0700334 SkString onShortName() override {
reeda5517e22015-07-14 10:54:12 -0700335 return SkString(gBleedRec[fBT].fName);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000336 }
337
mtklein36352bf2015-03-25 18:17:31 -0700338 SkISize onISize() override {
bsalomonf57ef1c2015-11-04 04:36:12 -0800339 return SkISize::Make(1200, 1080);
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000340 }
341
bsalomon5c1262d2015-11-09 10:06:06 -0800342 void drawPixels(SkCanvas* canvas, const TestPixels& pixels, const SkRect& src,
343 const SkRect& dst, const SkPaint* paint,
344 SkCanvas::SrcRectConstraint constraint) {
345 if (TestPixels::kBitmap == pixels.fType) {
346 canvas->drawBitmapRect(pixels.fBitmap, src, dst, paint, constraint);
347 } else {
reed9ce9d672016-03-17 10:51:11 -0700348 canvas->drawImageRect(pixels.fImage.get(), src, dst, paint, constraint);
bsalomon5c1262d2015-11-09 10:06:06 -0800349 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000350 }
351
bsalomon5c1262d2015-11-09 10:06:06 -0800352 // Draw the area of interest of the small image
bsalomon9003d1e2015-10-23 11:13:01 -0700353 void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700354 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800355
356 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700357 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
358 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000359
360 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700361 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700362 paint.setShader(fShader);
363 paint.setColor(SK_ColorBLUE);
364 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000365
bsalomon5c1262d2015-11-09 10:06:06 -0800366 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000367 }
368
bsalomon5c1262d2015-11-09 10:06:06 -0800369 // Draw the area of interest of the large image
bsalomon9003d1e2015-10-23 11:13:01 -0700370 void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700371 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800372 SkRect src = SkRect::Make(fBigTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700373 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
374 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000375
376 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700377 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700378 paint.setShader(fShader);
379 paint.setColor(SK_ColorBLUE);
380 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000381
bsalomon5c1262d2015-11-09 10:06:06 -0800382 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000383 }
384
bsalomon5c1262d2015-11-09 10:06:06 -0800385 // Draw upper-left 1/4 of the area of interest of the large image
bsalomon9003d1e2015-10-23 11:13:01 -0700386 void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700387 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800388 SkRect src = SkRect::MakeXYWH(SkIntToScalar(fBigTestPixels.fRect.fLeft),
389 SkIntToScalar(fBigTestPixels.fRect.fTop),
390 fBigTestPixels.fRect.width()/2.f,
391 fBigTestPixels.fRect.height()/2.f);
reeda5517e22015-07-14 10:54:12 -0700392 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
393 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000394
395 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700396 paint.setFilterQuality(filter);
bsalomon9003d1e2015-10-23 11:13:01 -0700397 paint.setShader(fShader);
398 paint.setColor(SK_ColorBLUE);
399 paint.setAntiAlias(aa);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000400
bsalomon5c1262d2015-11-09 10:06:06 -0800401 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000402 }
403
bsalomon5c1262d2015-11-09 10:06:06 -0800404 // Draw the area of interest of the small image with a normal blur
bsalomon9003d1e2015-10-23 11:13:01 -0700405 void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
reeda5517e22015-07-14 10:54:12 -0700406 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800407 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
reeda5517e22015-07-14 10:54:12 -0700408 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
409 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000410
411 SkPaint paint;
reed93a12152015-03-16 10:08:34 -0700412 paint.setFilterQuality(filter);
reedefdfd512016-04-04 10:02:58 -0700413 paint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
414 SkBlurMask::ConvertRadiusToSigma(3)));
bsalomon9003d1e2015-10-23 11:13:01 -0700415 paint.setShader(fShader);
416 paint.setColor(SK_ColorBLUE);
417 paint.setAntiAlias(aa);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000418
bsalomon5c1262d2015-11-09 10:06:06 -0800419 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000420 }
421
bsalomon5c1262d2015-11-09 10:06:06 -0800422 // Draw the area of interest of the small image with a outer blur
bsalomonf57ef1c2015-11-04 04:36:12 -0800423 void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
424 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800425 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
bsalomonf57ef1c2015-11-04 04:36:12 -0800426 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
427 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
428
429 SkPaint paint;
430 paint.setFilterQuality(filter);
reedefdfd512016-04-04 10:02:58 -0700431 paint.setMaskFilter(SkBlurMaskFilter::Make(kOuter_SkBlurStyle,
432 SkBlurMask::ConvertRadiusToSigma(7)));
bsalomonf57ef1c2015-11-04 04:36:12 -0800433 paint.setShader(fShader);
434 paint.setColor(SK_ColorBLUE);
435 paint.setAntiAlias(aa);
436
bsalomon5c1262d2015-11-09 10:06:06 -0800437 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
bsalomonf57ef1c2015-11-04 04:36:12 -0800438 }
439
mtklein36352bf2015-03-25 18:17:31 -0700440 void onDraw(SkCanvas* canvas) override {
bsalomon5c1262d2015-11-09 10:06:06 -0800441 // We don't create pixels in an onOnceBeforeDraw() override because we want access to
442 // GrContext.
443 GrContext* context = canvas->getGrContext();
444#if SK_SUPPORT_GPU
445 // Workaround for SampleApp.
446 if (GrTexture* tex = fBigTestPixels.fBitmap.getTexture()) {
447 if (tex->wasDestroyed()) {
448 fCreatedPixels = false;
449 }
450 }
451#endif
452 bool madePixels = fCreatedPixels;
453
454 if (!madePixels) {
455 madePixels = gBleedRec[fBT].fPixelMaker(context, &fSmallTestPixels, kSmallTextureSize,
456 kSmallTextureSize);
457 madePixels &= gBleedRec[fBT].fPixelMaker(context, &fBigTestPixels, 2 * kMaxTileSize,
458 2 * kMaxTileSize);
459 fCreatedPixels = madePixels;
460 }
461
462 // Assume that if we coulnd't make the bitmap/image it's because it's a GPU test on a
463 // non-GPU backend.
464 if (!madePixels) {
465 skiagm::GM::DrawGpuOnlyMessage(canvas);
466 return;
467 }
468
reed2ad1aa62016-03-09 09:50:50 -0800469 fShader = gBleedRec[fBT].fShaderMaker();
bsalomon5c1262d2015-11-09 10:06:06 -0800470
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000471 canvas->clear(SK_ColorGRAY);
bsalomon9003d1e2015-10-23 11:13:01 -0700472 SkTDArray<SkMatrix> matrices;
473 // Draw with identity
474 *matrices.append() = SkMatrix::I();
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000475
bsalomon9003d1e2015-10-23 11:13:01 -0700476 // Draw with rotation and scale down in x, up in y.
477 SkMatrix m;
bsalomonf57ef1c2015-11-04 04:36:12 -0800478 static const SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
bsalomon9003d1e2015-10-23 11:13:01 -0700479 m.setTranslate(0, kBottom);
480 m.preRotate(15.f, 0, kBottom + kBlockSpacing);
481 m.preScale(0.71f, 1.22f);
482 *matrices.append() = m;
483
484 // Align the next set with the middle of the previous in y, translated to the right in x.
485 SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} };
486 matrices[matrices.count()-1].mapPoints(corners, 4);
487 SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
488 SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX),
489 SkTMax(corners[2].fX, corners[3].fX));
490 m.setTranslate(x, y);
491 m.preScale(0.2f, 0.2f);
492 *matrices.append() = m;
493
494 SkScalar maxX = 0;
495 for (int antiAlias = 0; antiAlias < 2; ++antiAlias) {
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000496 canvas->save();
bsalomon9003d1e2015-10-23 11:13:01 -0700497 canvas->translate(maxX, 0);
498 for (int m = 0; m < matrices.count(); ++m) {
499 canvas->save();
500 canvas->concat(matrices[m]);
501 bool aa = SkToBool(antiAlias);
502
503 // First draw a column with no bleeding and no filtering
504 this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
505 this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
506 this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
507 this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800508 this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700509
510 // Then draw a column with no bleeding and low filtering
511 this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
512 this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
513 this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
514 this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800515 this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700516
517 // Then draw a column with no bleeding and high filtering
518 this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
519 this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
520 this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
521 this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800522 this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700523
524 // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
525 this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
526 this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
527 this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
528 this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800529 this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700530
531 // Then draw a column with bleeding and low filtering
532 this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
533 this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
534 this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
535 this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800536 this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700537
538 // Finally draw a column with bleeding and high filtering
539 this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
540 this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
541 this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
542 this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800543 this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700544
545 SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } };
546 matrices[m].mapPoints(corners, 4);
547 SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX),
548 SkTMax(corners[2].fX, corners[3].fX));
549 maxX = SkTMax(maxX, x);
550 canvas->restore();
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000551 }
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000552 canvas->restore();
553 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000554 }
555
bsalomon4ee6bd82015-05-27 13:23:23 -0700556#if SK_SUPPORT_GPU
557 void modifyGrContextOptions(GrContextOptions* options) override {
bsalomon8c07b7a2015-11-02 11:36:52 -0800558 options->fMaxTileSizeOverride = kMaxTileSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700559 }
560#endif
561
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000562private:
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000563 static const int kBlockSize = 70;
bsalomonf57ef1c2015-11-04 04:36:12 -0800564 static const int kBlockSpacing = 12;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000565
566 static const int kCol0X = kBlockSpacing;
567 static const int kCol1X = 2*kBlockSpacing + kBlockSize;
568 static const int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
569 static const int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000570 static const int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
571 static const int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700572 static const int kWidth = 7*kBlockSpacing + 6*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000573
574 static const int kRow0Y = kBlockSpacing;
575 static const int kRow1Y = 2*kBlockSpacing + kBlockSize;
576 static const int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000577 static const int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
bsalomonf57ef1c2015-11-04 04:36:12 -0800578 static const int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000579
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000580 static const int kSmallTextureSize = 6;
bsalomon8c07b7a2015-11-02 11:36:52 -0800581 static const int kMaxTileSize = 32;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000582
reed2ad1aa62016-03-09 09:50:50 -0800583 bool fCreatedPixels;
584 TestPixels fBigTestPixels;
585 TestPixels fSmallTestPixels;
bsalomon9003d1e2015-10-23 11:13:01 -0700586
reed2ad1aa62016-03-09 09:50:50 -0800587 sk_sp<SkShader> fShader;
bsalomon9003d1e2015-10-23 11:13:01 -0700588
reed2ad1aa62016-03-09 09:50:50 -0800589 const BleedTest fBT;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000590
591 typedef GM INHERITED;
592};
593
bsalomon9c586542015-11-02 12:33:21 -0800594
reeda5517e22015-07-14 10:54:12 -0700595DEF_GM( return new BleedGM(kUseBitmap_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800596DEF_GM( return new BleedGM(kUseTextureBitmap_BleedTest); )
reeda5517e22015-07-14 10:54:12 -0700597DEF_GM( return new BleedGM(kUseImage_BleedTest); )
bsalomon9003d1e2015-10-23 11:13:01 -0700598DEF_GM( return new BleedGM(kUseAlphaBitmap_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800599DEF_GM( return new BleedGM(kUseAlphaTextureBitmap_BleedTest); )
bsalomon9003d1e2015-10-23 11:13:01 -0700600DEF_GM( return new BleedGM(kUseAlphaImage_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800601DEF_GM( return new BleedGM(kUseAlphaBitmapShader_BleedTest); )
602DEF_GM( return new BleedGM(kUseAlphaTextureBitmapShader_BleedTest); )
603DEF_GM( return new BleedGM(kUseAlphaImageShader_BleedTest); )