• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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