1 /*
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"
9 #include "SkBlurMask.h"
10 #include "SkBlurMaskFilter.h"
11 #include "SkCanvas.h"
12 #include "SkGradientShader.h"
13 #include "SkImage.h"
14 #include "SkUtils.h"
15
16 #if SK_SUPPORT_GPU
17 #include "GrContext.h"
18 #include "GrContextOptions.h"
19 #include "SkGr.h"
20 #endif
21
22 /** 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. */
25 struct 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 };
35
36 /** 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. */
39 template<typename PIXEL_TYPE>
make_ringed_bitmap(GrContext *,TestPixels * result,int width,int height,SkColorType ct,SkAlphaType at,PIXEL_TYPE outerRingColor,PIXEL_TYPE innerRingColor,PIXEL_TYPE checkColor1,PIXEL_TYPE checkColor2)40 bool 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) {
44 SkASSERT(0 == width % 2 && 0 == height % 2);
45 SkASSERT(width >= 6 && height >= 6);
46
47 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. */
make_ringed_color_bitmap(GrContext * ctx,TestPixels * result,int width,int height)109 static 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);
112 static const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
113 static const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
114 return make_ringed_bitmap<SkPMColor>(ctx, result, width, height, kBGRA_8888_SkColorType,
115 kPremul_SkAlphaType, kBlue, kRed, kBlack, kWhite);
116 }
117
118 /** Makes a alpha bitmap with 1 wide rect/ring of 0s, an inset of 1s, and the interior is a 2x2
119 checker board of 3/4 and 1/2. The inner checkers are large enough to fill the interior with
120 the 2x2 checker grid. */
make_ringed_alpha_bitmap(GrContext * ctx,TestPixels * result,int width,int height)121 static 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 */
bmp_to_image(TestPixels * result)131 static 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. */
make_ringed_color_image(GrContext * ctx,TestPixels * result,int width,int height)140 bool 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. */
make_ringed_alpha_image(GrContext * ctx,TestPixels * result,int width,int height)149 bool 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 */
164 template <typename PIXEL_TYPE>
make_oversized_texture_bitmap(GrContext * ctx,TestPixels * result,int width,int height,GrPixelConfig config,PIXEL_TYPE outerRingColor,PIXEL_TYPE innerRingColor,PIXEL_TYPE checkColor1,PIXEL_TYPE checkColor2,PIXEL_TYPE padColor)165 bool 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) {
169 SkASSERT(0 == width % 2 && 0 == height % 2);
170 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));
180
181 PIXEL_TYPE* scanline = pixels.get();
182 for (int x = 0; x < width; ++x) {
183 scanline[x] = outerRingColor;
184 }
185 for (int x = width; x < width + kXPad; ++x) {
186 scanline[x] = padColor;
187 }
188
189 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;
196 }
197
198 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 }
211 }
212
213 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 }
226 }
227
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(
240 desc, SkBudgeted::kYes, pixels.get(), 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 */
make_ringed_oversized_color_texture_bitmap(GrContext * ctx,TestPixels * result,int width,int height)257 static 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 */
make_ringed_oversized_alpha_texture_bitmap(GrContext * ctx,TestPixels * result,int width,int height)269 static 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);
278 }
279
make_shader()280 static 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
make_null_shader()286 static SkShader* make_null_shader() { return nullptr; }
287
288 enum BleedTest {
289 kUseBitmap_BleedTest,
290 kUseTextureBitmap_BleedTest,
291 kUseImage_BleedTest,
292 kUseAlphaBitmap_BleedTest,
293 kUseAlphaTextureBitmap_BleedTest,
294 kUseAlphaImage_BleedTest,
295 kUseAlphaBitmapShader_BleedTest,
296 kUseAlphaTextureBitmapShader_BleedTest,
297 kUseAlphaImageShader_BleedTest,
298 };
299
300 const struct {
301 const char* fName;
302 bool (*fPixelMaker)(GrContext*, TestPixels* result, int width, int height);
303 SkShader* (*fShaderMaker)();
304 } gBleedRec[] = {
305 { "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 },
314 };
315
316 /** 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 */
328 class BleedGM : public skiagm::GM {
329 public:
BleedGM(BleedTest bt)330 BleedGM(BleedTest bt) : fCreatedPixels(false), fBT(bt){}
331
332 protected:
333
onShortName()334 SkString onShortName() override {
335 return SkString(gBleedRec[fBT].fName);
336 }
337
onISize()338 SkISize onISize() override {
339 return SkISize::Make(1200, 1080);
340 }
341
drawPixels(SkCanvas * canvas,const TestPixels & pixels,const SkRect & src,const SkRect & dst,const SkPaint * paint,SkCanvas::SrcRectConstraint constraint)342 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 }
350 }
351
352 // Draw the area of interest of the small image
drawCase1(SkCanvas * canvas,int transX,int transY,bool aa,SkCanvas::SrcRectConstraint constraint,SkFilterQuality filter)353 void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
354 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
355
356 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
357 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
358 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
359
360 SkPaint paint;
361 paint.setFilterQuality(filter);
362 paint.setShader(fShader);
363 paint.setColor(SK_ColorBLUE);
364 paint.setAntiAlias(aa);
365
366 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
367 }
368
369 // Draw the area of interest of the large image
drawCase2(SkCanvas * canvas,int transX,int transY,bool aa,SkCanvas::SrcRectConstraint constraint,SkFilterQuality filter)370 void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
371 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
372 SkRect src = SkRect::Make(fBigTestPixels.fRect);
373 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
374 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
375
376 SkPaint paint;
377 paint.setFilterQuality(filter);
378 paint.setShader(fShader);
379 paint.setColor(SK_ColorBLUE);
380 paint.setAntiAlias(aa);
381
382 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
383 }
384
385 // Draw upper-left 1/4 of the area of interest of the large image
drawCase3(SkCanvas * canvas,int transX,int transY,bool aa,SkCanvas::SrcRectConstraint constraint,SkFilterQuality filter)386 void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
387 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
388 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);
392 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
393 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
394
395 SkPaint paint;
396 paint.setFilterQuality(filter);
397 paint.setShader(fShader);
398 paint.setColor(SK_ColorBLUE);
399 paint.setAntiAlias(aa);
400
401 this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
402 }
403
404 // Draw the area of interest of the small image with a normal blur
drawCase4(SkCanvas * canvas,int transX,int transY,bool aa,SkCanvas::SrcRectConstraint constraint,SkFilterQuality filter)405 void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
406 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
407 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
408 SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
409 SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
410
411 SkPaint paint;
412 paint.setFilterQuality(filter);
413 SkMaskFilter* mf = SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
414 SkBlurMask::ConvertRadiusToSigma(3));
415 paint.setMaskFilter(mf)->unref();
416 paint.setShader(fShader);
417 paint.setColor(SK_ColorBLUE);
418 paint.setAntiAlias(aa);
419
420 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
421 }
422
423 // Draw the area of interest of the small image with a outer blur
drawCase5(SkCanvas * canvas,int transX,int transY,bool aa,SkCanvas::SrcRectConstraint constraint,SkFilterQuality filter)424 void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
425 SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
426 SkRect src = SkRect::Make(fSmallTestPixels.fRect);
427 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
439 this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
440 }
441
onDraw(SkCanvas * canvas)442 void onDraw(SkCanvas* canvas) override {
443 // 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
473 canvas->clear(SK_ColorGRAY);
474 SkTDArray<SkMatrix> matrices;
475 // Draw with identity
476 *matrices.append() = SkMatrix::I();
477
478 // Draw with rotation and scale down in x, up in y.
479 SkMatrix m;
480 static const SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
481 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) {
498 canvas->save();
499 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);
510 this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
511
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);
517 this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
518
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);
524 this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
525
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);
531 this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
532
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);
538 this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
539
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);
545 this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
546
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();
553 }
554 canvas->restore();
555 }
556 }
557
558 #if SK_SUPPORT_GPU
modifyGrContextOptions(GrContextOptions * options)559 void modifyGrContextOptions(GrContextOptions* options) override {
560 options->fMaxTileSizeOverride = kMaxTileSize;
561 }
562 #endif
563
564 private:
565 static const int kBlockSize = 70;
566 static const int kBlockSpacing = 12;
567
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;
572 static const int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
573 static const int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
574 static const int kWidth = 7*kBlockSpacing + 6*kBlockSize;
575
576 static const int kRow0Y = kBlockSpacing;
577 static const int kRow1Y = 2*kBlockSpacing + kBlockSize;
578 static const int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
579 static const int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
580 static const int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
581
582 static const int kSmallTextureSize = 6;
583 static const int kMaxTileSize = 32;
584
585 bool fCreatedPixels;
586 TestPixels fBigTestPixels;
587 TestPixels fSmallTestPixels;
588
589 SkAutoTUnref<SkShader> fShader;
590
591 const BleedTest fBT;
592
593 typedef GM INHERITED;
594 };
595
596
597 DEF_GM( return new BleedGM(kUseBitmap_BleedTest); )
598 DEF_GM( return new BleedGM(kUseTextureBitmap_BleedTest); )
599 DEF_GM( return new BleedGM(kUseImage_BleedTest); )
600 DEF_GM( return new BleedGM(kUseAlphaBitmap_BleedTest); )
601 DEF_GM( return new BleedGM(kUseAlphaTextureBitmap_BleedTest); )
602 DEF_GM( return new BleedGM(kUseAlphaImage_BleedTest); )
603 DEF_GM( return new BleedGM(kUseAlphaBitmapShader_BleedTest); )
604 DEF_GM( return new BleedGM(kUseAlphaTextureBitmapShader_BleedTest); )
605 DEF_GM( return new BleedGM(kUseAlphaImageShader_BleedTest); )
606