blob: 85ae2f49d10584aa37a3f6c417b8052b25f78bb9 [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 };
30 Type fType;
31 SkBitmap fBitmap;
32 SkAutoTUnref<SkImage> fImage;
33 SkIRect fRect; // The region of the bitmap/image that should be rendered.
34};
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);
133 result->fImage.reset(SkImage::NewFromBitmap(result->fBitmap));
134 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.
159 - The texture is larger than the bitmap dimensions (it is surrounded by non-content
160 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;
239 SkAutoTUnref<GrTexture> texture(ctx->textureProvider()->createTexture(desc, true, pixels.get(),
240 rowBytes));
241
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
280static SkShader* make_shader() {
281 static const SkPoint pts[] = { {0, 0}, {20, 20} };
282 static const SkColor colors[] = { SK_ColorGREEN, SK_ColorYELLOW };
283 return SkGradientShader::CreateLinear(pts, colors, nullptr, 2, SkShader::kMirror_TileMode);
284}
285
286static SkShader* make_null_shader() { return nullptr; }
287
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);
303 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 {
348 canvas->drawImageRect(pixels.fImage, src, dst, paint, constraint);
349 }
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);
commit-bot@chromium.orge3964552014-04-28 16:25:35 +0000413 SkMaskFilter* mf = SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
reeda5517e22015-07-14 10:54:12 -0700414 SkBlurMask::ConvertRadiusToSigma(3));
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000415 paint.setMaskFilter(mf)->unref();
bsalomon9003d1e2015-10-23 11:13:01 -0700416 paint.setShader(fShader);
417 paint.setColor(SK_ColorBLUE);
418 paint.setAntiAlias(aa);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000419
bsalomon5c1262d2015-11-09 10:06:06 -0800420 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000421 }
422
bsalomon5c1262d2015-11-09 10:06:06 -0800423 // Draw the area of interest of the small image with a outer blur
bsalomonf57ef1c2015-11-04 04:36:12 -0800424 void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
425 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
bsalomon5c1262d2015-11-09 10:06:06 -0800426 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
bsalomonf57ef1c2015-11-04 04:36:12 -0800427 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
428 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
429
430 SkPaint paint;
431 paint.setFilterQuality(filter);
432 SkMaskFilter* mf = SkBlurMaskFilter::Create(kOuter_SkBlurStyle,
433 SkBlurMask::ConvertRadiusToSigma(7));
434 paint.setMaskFilter(mf)->unref();
435 paint.setShader(fShader);
436 paint.setColor(SK_ColorBLUE);
437 paint.setAntiAlias(aa);
438
bsalomon5c1262d2015-11-09 10:06:06 -0800439 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
bsalomonf57ef1c2015-11-04 04:36:12 -0800440 }
441
mtklein36352bf2015-03-25 18:17:31 -0700442 void onDraw(SkCanvas* canvas) override {
bsalomon5c1262d2015-11-09 10:06:06 -0800443 // We don't create pixels in an onOnceBeforeDraw() override because we want access to
444 // GrContext.
445 GrContext* context = canvas->getGrContext();
446#if SK_SUPPORT_GPU
447 // Workaround for SampleApp.
448 if (GrTexture* tex = fBigTestPixels.fBitmap.getTexture()) {
449 if (tex->wasDestroyed()) {
450 fCreatedPixels = false;
451 }
452 }
453#endif
454 bool madePixels = fCreatedPixels;
455
456 if (!madePixels) {
457 madePixels = gBleedRec[fBT].fPixelMaker(context, &fSmallTestPixels, kSmallTextureSize,
458 kSmallTextureSize);
459 madePixels &= gBleedRec[fBT].fPixelMaker(context, &fBigTestPixels, 2 * kMaxTileSize,
460 2 * kMaxTileSize);
461 fCreatedPixels = madePixels;
462 }
463
464 // Assume that if we coulnd't make the bitmap/image it's because it's a GPU test on a
465 // non-GPU backend.
466 if (!madePixels) {
467 skiagm::GM::DrawGpuOnlyMessage(canvas);
468 return;
469 }
470
471 fShader.reset(gBleedRec[fBT].fShaderMaker());
472
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000473 canvas->clear(SK_ColorGRAY);
bsalomon9003d1e2015-10-23 11:13:01 -0700474 SkTDArray<SkMatrix> matrices;
475 // Draw with identity
476 *matrices.append() = SkMatrix::I();
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000477
bsalomon9003d1e2015-10-23 11:13:01 -0700478 // Draw with rotation and scale down in x, up in y.
479 SkMatrix m;
bsalomonf57ef1c2015-11-04 04:36:12 -0800480 static const SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
bsalomon9003d1e2015-10-23 11:13:01 -0700481 m.setTranslate(0, kBottom);
482 m.preRotate(15.f, 0, kBottom + kBlockSpacing);
483 m.preScale(0.71f, 1.22f);
484 *matrices.append() = m;
485
486 // Align the next set with the middle of the previous in y, translated to the right in x.
487 SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} };
488 matrices[matrices.count()-1].mapPoints(corners, 4);
489 SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
490 SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX),
491 SkTMax(corners[2].fX, corners[3].fX));
492 m.setTranslate(x, y);
493 m.preScale(0.2f, 0.2f);
494 *matrices.append() = m;
495
496 SkScalar maxX = 0;
497 for (int antiAlias = 0; antiAlias < 2; ++antiAlias) {
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000498 canvas->save();
bsalomon9003d1e2015-10-23 11:13:01 -0700499 canvas->translate(maxX, 0);
500 for (int m = 0; m < matrices.count(); ++m) {
501 canvas->save();
502 canvas->concat(matrices[m]);
503 bool aa = SkToBool(antiAlias);
504
505 // First draw a column with no bleeding and no filtering
506 this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
507 this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
508 this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
509 this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800510 this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700511
512 // Then draw a column with no bleeding and low filtering
513 this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
514 this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
515 this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
516 this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800517 this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700518
519 // Then draw a column with no bleeding and high filtering
520 this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
521 this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
522 this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
523 this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800524 this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700525
526 // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
527 this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
528 this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
529 this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
530 this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800531 this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700532
533 // Then draw a column with bleeding and low filtering
534 this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
535 this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
536 this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
537 this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800538 this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700539
540 // Finally draw a column with bleeding and high filtering
541 this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
542 this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
543 this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
544 this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomonf57ef1c2015-11-04 04:36:12 -0800545 this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
bsalomon9003d1e2015-10-23 11:13:01 -0700546
547 SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } };
548 matrices[m].mapPoints(corners, 4);
549 SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX),
550 SkTMax(corners[2].fX, corners[3].fX));
551 maxX = SkTMax(maxX, x);
552 canvas->restore();
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000553 }
commit-bot@chromium.orgd6ca4ac2013-11-22 20:34:59 +0000554 canvas->restore();
555 }
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000556 }
557
bsalomon4ee6bd82015-05-27 13:23:23 -0700558#if SK_SUPPORT_GPU
559 void modifyGrContextOptions(GrContextOptions* options) override {
bsalomon8c07b7a2015-11-02 11:36:52 -0800560 options->fMaxTileSizeOverride = kMaxTileSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700561 }
562#endif
563
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000564private:
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000565 static const int kBlockSize = 70;
bsalomonf57ef1c2015-11-04 04:36:12 -0800566 static const int kBlockSpacing = 12;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000567
568 static const int kCol0X = kBlockSpacing;
569 static const int kCol1X = 2*kBlockSpacing + kBlockSize;
570 static const int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
571 static const int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000572 static const int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
573 static const int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
bsalomon4ee6bd82015-05-27 13:23:23 -0700574 static const int kWidth = 7*kBlockSpacing + 6*kBlockSize;
robertphillips@google.comd7ca6612013-08-20 12:09:32 +0000575
576 static const int kRow0Y = kBlockSpacing;
577 static const int kRow1Y = 2*kBlockSpacing + kBlockSize;
578 static const int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
robertphillips@google.com2cc0b472013-08-20 16:51:20 +0000579 static const int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
bsalomonf57ef1c2015-11-04 04:36:12 -0800580 static const int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000581
commit-bot@chromium.orgec39b502013-11-08 15:09:22 +0000582 static const int kSmallTextureSize = 6;
bsalomon8c07b7a2015-11-02 11:36:52 -0800583 static const int kMaxTileSize = 32;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000584
bsalomon5c1262d2015-11-09 10:06:06 -0800585 bool fCreatedPixels;
586 TestPixels fBigTestPixels;
587 TestPixels fSmallTestPixels;
bsalomon9003d1e2015-10-23 11:13:01 -0700588
bsalomon5c1262d2015-11-09 10:06:06 -0800589 SkAutoTUnref<SkShader> fShader;
bsalomon9003d1e2015-10-23 11:13:01 -0700590
bsalomon5c1262d2015-11-09 10:06:06 -0800591 const BleedTest fBT;
robertphillips@google.comaaa9b292013-07-25 21:34:00 +0000592
593 typedef GM INHERITED;
594};
595
bsalomon9c586542015-11-02 12:33:21 -0800596
reeda5517e22015-07-14 10:54:12 -0700597DEF_GM( return new BleedGM(kUseBitmap_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800598DEF_GM( return new BleedGM(kUseTextureBitmap_BleedTest); )
reeda5517e22015-07-14 10:54:12 -0700599DEF_GM( return new BleedGM(kUseImage_BleedTest); )
bsalomon9003d1e2015-10-23 11:13:01 -0700600DEF_GM( return new BleedGM(kUseAlphaBitmap_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800601DEF_GM( return new BleedGM(kUseAlphaTextureBitmap_BleedTest); )
bsalomon9003d1e2015-10-23 11:13:01 -0700602DEF_GM( return new BleedGM(kUseAlphaImage_BleedTest); )
bsalomon9c586542015-11-02 12:33:21 -0800603DEF_GM( return new BleedGM(kUseAlphaBitmapShader_BleedTest); )
604DEF_GM( return new BleedGM(kUseAlphaTextureBitmapShader_BleedTest); )
605DEF_GM( return new BleedGM(kUseAlphaImageShader_BleedTest); )