• 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/gm.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkBlurTypes.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkFilterQuality.h"
14 #include "include/core/SkImage.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkMaskFilter.h"
17 #include "include/core/SkMatrix.h"
18 #include "include/core/SkPaint.h"
19 #include "include/core/SkPoint.h"
20 #include "include/core/SkRect.h"
21 #include "include/core/SkRefCnt.h"
22 #include "include/core/SkScalar.h"
23 #include "include/core/SkShader.h"
24 #include "include/core/SkSize.h"
25 #include "include/core/SkString.h"
26 #include "include/core/SkSurface.h"
27 #include "include/core/SkTileMode.h"
28 #include "include/core/SkTypes.h"
29 #include "include/effects/SkGradientShader.h"
30 #include "include/gpu/GrContextOptions.h"
31 #include "include/private/SkTDArray.h"
32 #include "src/core/SkBlurMask.h"
33 #include "tools/ToolUtils.h"
34 
35 /** Holds either a bitmap or image to be rendered and a rect that indicates what part of the bitmap
36     or image should be tested by the GM. The area outside of the rect is present to check
37     for bleed due to filtering/blurring. */
38 struct TestPixels {
39     enum Type {
40         kBitmap,
41         kImage
42     };
43     Type            fType;
44     SkBitmap        fBitmap;
45     sk_sp<SkImage>  fImage;
46     SkIRect         fRect;  // The region of the bitmap/image that should be rendered.
47 };
48 
49 /** Creates a bitmap with two one-pixel rings around a checkerboard. The checkerboard is 2x2
50     logically where each check has as many pixels as is necessary to fill the interior. The rect
51     to draw is set to the checkerboard portion. */
52 template<typename PIXEL_TYPE>
make_ringed_bitmap(TestPixels * result,int width,int height,SkColorType ct,SkAlphaType at,PIXEL_TYPE outerRingColor,PIXEL_TYPE innerRingColor,PIXEL_TYPE checkColor1,PIXEL_TYPE checkColor2)53 bool make_ringed_bitmap(TestPixels* result, int width, int height,
54                         SkColorType ct, SkAlphaType at,
55                         PIXEL_TYPE outerRingColor, PIXEL_TYPE innerRingColor,
56                         PIXEL_TYPE checkColor1, PIXEL_TYPE checkColor2) {
57     SkASSERT(0 == width % 2 && 0 == height % 2);
58     SkASSERT(width >= 6 && height >= 6);
59 
60     result->fType = TestPixels::kBitmap;
61     SkImageInfo info = SkImageInfo::Make(width, height, ct, at);
62     size_t rowBytes = SkAlign4(info.minRowBytes());
63     result->fBitmap.allocPixels(info, rowBytes);
64 
65     PIXEL_TYPE* scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 0);
66     for (int x = 0; x < width; ++x) {
67         scanline[x] = outerRingColor;
68     }
69     scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, 1);
70     scanline[0] = outerRingColor;
71     for (int x = 1; x < width - 1; ++x) {
72         scanline[x] = innerRingColor;
73     }
74     scanline[width - 1] = outerRingColor;
75 
76     for (int y = 2; y < height / 2; ++y) {
77         scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
78         scanline[0] = outerRingColor;
79         scanline[1] = innerRingColor;
80         for (int x = 2; x < width / 2; ++x) {
81             scanline[x] = checkColor1;
82         }
83         for (int x = width / 2; x < width - 2; ++x) {
84             scanline[x] = checkColor2;
85         }
86         scanline[width - 2] = innerRingColor;
87         scanline[width - 1] = outerRingColor;
88     }
89 
90     for (int y = height / 2; y < height - 2; ++y) {
91         scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, y);
92         scanline[0] = outerRingColor;
93         scanline[1] = innerRingColor;
94         for (int x = 2; x < width / 2; ++x) {
95             scanline[x] = checkColor2;
96         }
97         for (int x = width / 2; x < width - 2; ++x) {
98             scanline[x] = checkColor1;
99         }
100         scanline[width - 2] = innerRingColor;
101         scanline[width - 1] = outerRingColor;
102     }
103 
104     scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 2);
105     scanline[0] = outerRingColor;
106     for (int x = 1; x < width - 1; ++x) {
107         scanline[x] = innerRingColor;
108     }
109     scanline[width - 1] = outerRingColor;
110 
111     scanline = (PIXEL_TYPE*)result->fBitmap.getAddr(0, height - 1);
112     for (int x = 0; x < width; ++x) {
113         scanline[x] = outerRingColor;
114     }
115     result->fBitmap.setImmutable();
116     result->fRect.set(2, 2, width - 2, height - 2);
117     return true;
118 }
119 
120 /** Create a black and white checked bitmap with 2 1-pixel rings around the outside edge.
121     The inner ring is red and the outer ring is blue. */
make_ringed_color_bitmap(TestPixels * result,int width,int height)122 static bool make_ringed_color_bitmap(TestPixels* result, int width, int height) {
123     const SkPMColor kBlue  = SkPreMultiplyColor(SK_ColorBLUE);
124     const SkPMColor kRed   = SkPreMultiplyColor(SK_ColorRED);
125     const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
126     const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
127     return make_ringed_bitmap<SkPMColor>(result, width, height, kN32_SkColorType,
128                                          kPremul_SkAlphaType, kBlue, kRed, kBlack, kWhite);
129 }
130 
131 /** Makes a alpha bitmap with 1 wide rect/ring of 0s, an inset of 1s, and the interior is a 2x2
132     checker board of 3/4 and 1/2. The inner checkers are large enough to fill the interior with
133     the 2x2 checker grid. */
make_ringed_alpha_bitmap(TestPixels * result,int width,int height)134 static bool make_ringed_alpha_bitmap(TestPixels* result, int width, int height) {
135     constexpr uint8_t kZero = 0x00;
136     constexpr uint8_t kHalf = 0x80;
137     constexpr uint8_t k3Q   = 0xC0;
138     constexpr uint8_t kOne  = 0xFF;
139     return make_ringed_bitmap<uint8_t>(result, width, height, kAlpha_8_SkColorType,
140                                        kPremul_SkAlphaType, kZero, kOne, k3Q, kHalf);
141 }
142 
143 /** Helper to reuse above functions to produce images rather than bmps */
bmp_to_image(TestPixels * result)144 static void bmp_to_image(TestPixels* result) {
145     SkASSERT(TestPixels::kBitmap == result->fType);
146     result->fImage = SkImage::MakeFromBitmap(result->fBitmap);
147     SkASSERT(result->fImage);
148     result->fType = TestPixels::kImage;
149     result->fBitmap.reset();
150 }
151 
152 /** Color image case. */
make_ringed_color_image(TestPixels * result,int width,int height)153 bool make_ringed_color_image(TestPixels* result, int width, int height) {
154     if (make_ringed_color_bitmap(result, width, height)) {
155         bmp_to_image(result);
156         return true;
157     }
158     return false;
159 }
160 
161 /** Alpha image case. */
make_ringed_alpha_image(TestPixels * result,int width,int height)162 bool make_ringed_alpha_image(TestPixels* result, int width, int height) {
163     if (make_ringed_alpha_bitmap(result, width, height)) {
164         bmp_to_image(result);
165         return true;
166     }
167     return false;
168 }
169 
make_shader()170 static sk_sp<SkShader> make_shader() {
171     constexpr SkPoint pts[] = { {0, 0}, {20, 20} };
172     constexpr SkColor colors[] = { SK_ColorGREEN, SK_ColorYELLOW };
173     return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kMirror);
174 }
175 
make_null_shader()176 static sk_sp<SkShader> make_null_shader() { return nullptr; }
177 
178 enum BleedTest {
179     kUseBitmap_BleedTest,
180     kUseImage_BleedTest,
181     kUseAlphaBitmap_BleedTest,
182     kUseAlphaImage_BleedTest,
183     kUseAlphaBitmapShader_BleedTest,
184     kUseAlphaImageShader_BleedTest,
185 };
186 
187 const struct {
188     const char* fName;
189     bool (*fPixelMaker)(TestPixels* result, int width, int height);
190     sk_sp<SkShader> (*fShaderMaker)();
191 } gBleedRec[] = {
192     { "bleed",                          make_ringed_color_bitmap,                   make_null_shader },
193     { "bleed_image",                    make_ringed_color_image,                    make_null_shader },
194     { "bleed_alpha_bmp",                make_ringed_alpha_bitmap,                   make_null_shader },
195     { "bleed_alpha_image",              make_ringed_alpha_image,                    make_null_shader },
196     { "bleed_alpha_bmp_shader",         make_ringed_alpha_bitmap,                   make_shader      },
197     { "bleed_alpha_image_shader",       make_ringed_alpha_image,                    make_shader      },
198 };
199 
200 /** This GM exercises the behavior of the drawBitmapRect & drawImageRect calls. Specifically their
201     handling of :
202      - SrcRectConstraint(bleed vs.no - bleed)
203      - handling of the sub - region feature(area - of - interest) of drawBitmap*
204      - handling of 8888 vs. A8 (including presence of a shader in the A8 case).
205     In particular, we should never see the padding outside of an SkBitmap's sub - region (green for
206     8888, 1/4 for alpha). In some instances we can see the two outer rings outside of the area o
207     interest (i.e., the inner four checks) due to AA or filtering if allowed by the
208     SrcRectConstraint.
209 */
210 class BleedGM : public skiagm::GM {
211 public:
BleedGM(BleedTest bt)212     BleedGM(BleedTest bt) : fBT(bt){}
213 
214 protected:
215 
onShortName()216     SkString onShortName() override {
217         return SkString(gBleedRec[fBT].fName);
218     }
219 
onISize()220     SkISize onISize() override {
221         return SkISize::Make(1200, 1080);
222     }
223 
drawPixels(SkCanvas * canvas,const TestPixels & pixels,const SkRect & src,const SkRect & dst,const SkPaint * paint,SkCanvas::SrcRectConstraint constraint)224     void drawPixels(SkCanvas* canvas, const TestPixels& pixels, const SkRect& src,
225                     const SkRect& dst, const SkPaint* paint,
226                     SkCanvas::SrcRectConstraint constraint) {
227         if (TestPixels::kBitmap == pixels.fType) {
228             canvas->drawBitmapRect(pixels.fBitmap, src, dst, paint, constraint);
229         } else {
230             canvas->drawImageRect(pixels.fImage.get(), src, dst, paint, constraint);
231         }
232     }
233 
234     // Draw the area of interest of the small image
drawCase1(SkCanvas * canvas,int transX,int transY,bool aa,SkCanvas::SrcRectConstraint constraint,SkFilterQuality filter)235     void drawCase1(SkCanvas* canvas, int transX, int transY, bool aa,
236                    SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
237 
238         SkRect src = SkRect::Make(fSmallTestPixels.fRect);
239         SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
240                                       SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
241 
242         SkPaint paint;
243         paint.setFilterQuality(filter);
244         paint.setShader(fShader);
245         paint.setColor(SK_ColorBLUE);
246         paint.setAntiAlias(aa);
247 
248         this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
249     }
250 
251     // Draw the area of interest of the large image
drawCase2(SkCanvas * canvas,int transX,int transY,bool aa,SkCanvas::SrcRectConstraint constraint,SkFilterQuality filter)252     void drawCase2(SkCanvas* canvas, int transX, int transY, bool aa,
253                    SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
254         SkRect src = SkRect::Make(fBigTestPixels.fRect);
255         SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
256                                       SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
257 
258         SkPaint paint;
259         paint.setFilterQuality(filter);
260         paint.setShader(fShader);
261         paint.setColor(SK_ColorBLUE);
262         paint.setAntiAlias(aa);
263 
264         this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
265     }
266 
267     // 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)268     void drawCase3(SkCanvas* canvas, int transX, int transY, bool aa,
269                    SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
270         SkRect src = SkRect::MakeXYWH(SkIntToScalar(fBigTestPixels.fRect.fLeft),
271                                       SkIntToScalar(fBigTestPixels.fRect.fTop),
272                                       fBigTestPixels.fRect.width()/2.f,
273                                       fBigTestPixels.fRect.height()/2.f);
274         SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
275                                       SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
276 
277         SkPaint paint;
278         paint.setFilterQuality(filter);
279         paint.setShader(fShader);
280         paint.setColor(SK_ColorBLUE);
281         paint.setAntiAlias(aa);
282 
283         this->drawPixels(canvas, fBigTestPixels, src, dst, &paint, constraint);
284     }
285 
286     // 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)287     void drawCase4(SkCanvas* canvas, int transX, int transY, bool aa,
288                    SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
289         SkRect src = SkRect::Make(fSmallTestPixels.fRect);
290         SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
291                                       SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
292 
293         SkPaint paint;
294         paint.setFilterQuality(filter);
295         paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle,
296                                                    SkBlurMask::ConvertRadiusToSigma(3)));
297         paint.setShader(fShader);
298         paint.setColor(SK_ColorBLUE);
299         paint.setAntiAlias(aa);
300 
301         this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
302     }
303 
304     // 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)305     void drawCase5(SkCanvas* canvas, int transX, int transY, bool aa,
306                    SkCanvas::SrcRectConstraint constraint, SkFilterQuality filter) {
307         SkRect src = SkRect::Make(fSmallTestPixels.fRect);
308         SkRect dst = SkRect::MakeXYWH(SkIntToScalar(transX), SkIntToScalar(transY),
309                                       SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
310 
311         SkPaint paint;
312         paint.setFilterQuality(filter);
313         paint.setMaskFilter(SkMaskFilter::MakeBlur(kOuter_SkBlurStyle,
314                                                    SkBlurMask::ConvertRadiusToSigma(7)));
315         paint.setShader(fShader);
316         paint.setColor(SK_ColorBLUE);
317         paint.setAntiAlias(aa);
318 
319         this->drawPixels(canvas, fSmallTestPixels, src, dst, &paint, constraint);
320     }
321 
onOnceBeforeDraw()322     void onOnceBeforeDraw() override {
323         SkAssertResult(gBleedRec[fBT].fPixelMaker(&fSmallTestPixels, kSmallSize, kSmallSize));
324         SkAssertResult(gBleedRec[fBT].fPixelMaker(&fBigTestPixels, 2 * kMaxTileSize,
325                                                  2 * kMaxTileSize));
326     }
327 
onDraw(SkCanvas * canvas)328     void onDraw(SkCanvas* canvas) override {
329         fShader = gBleedRec[fBT].fShaderMaker();
330 
331         canvas->clear(SK_ColorGRAY);
332         SkTDArray<SkMatrix> matrices;
333         // Draw with identity
334         *matrices.append() = SkMatrix::I();
335 
336         // Draw with rotation and scale down in x, up in y.
337         SkMatrix m;
338         constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
339         m.setTranslate(0, kBottom);
340         m.preRotate(15.f, 0, kBottom + kBlockSpacing);
341         m.preScale(0.71f, 1.22f);
342         *matrices.append() = m;
343 
344         // Align the next set with the middle of the previous in y, translated to the right in x.
345         SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} };
346         matrices[matrices.count()-1].mapPoints(corners, 4);
347         SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
348         SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX),
349                             SkTMax(corners[2].fX, corners[3].fX));
350         m.setTranslate(x, y);
351         m.preScale(0.2f, 0.2f);
352         *matrices.append() = m;
353 
354         SkScalar maxX = 0;
355         for (int antiAlias = 0; antiAlias < 2; ++antiAlias) {
356             canvas->save();
357             canvas->translate(maxX, 0);
358             for (int m = 0; m < matrices.count(); ++m) {
359                 canvas->save();
360                 canvas->concat(matrices[m]);
361                 bool aa = SkToBool(antiAlias);
362 
363                 // First draw a column with no bleeding and no filtering
364                 this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
365                 this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
366                 this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
367                 this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
368                 this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
369 
370                 // Then draw a column with no bleeding and low filtering
371                 this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
372                 this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
373                 this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
374                 this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
375                 this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
376 
377                 // Then draw a column with no bleeding and high filtering
378                 this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
379                 this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
380                 this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
381                 this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
382                 this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
383 
384                 // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
385                 this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
386                 this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
387                 this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
388                 this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
389                 this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
390 
391                 // Then draw a column with bleeding and low filtering
392                 this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
393                 this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
394                 this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
395                 this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
396                 this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
397 
398                 // Finally draw a column with bleeding and high filtering
399                 this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
400                 this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
401                 this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
402                 this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
403                 this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
404 
405                 SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } };
406                 matrices[m].mapPoints(corners, 4);
407                 SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX),
408                                                  SkTMax(corners[2].fX, corners[3].fX));
409                 maxX = SkTMax(maxX, x);
410                 canvas->restore();
411             }
412             canvas->restore();
413         }
414     }
415 
modifyGrContextOptions(GrContextOptions * options)416     void modifyGrContextOptions(GrContextOptions* options) override {
417         options->fMaxTileSizeOverride = kMaxTileSize;
418     }
419 
420 private:
421     static constexpr int kBlockSize = 70;
422     static constexpr int kBlockSpacing = 12;
423 
424     static constexpr int kCol0X = kBlockSpacing;
425     static constexpr int kCol1X = 2*kBlockSpacing + kBlockSize;
426     static constexpr int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
427     static constexpr int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
428     static constexpr int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
429     static constexpr int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
430     static constexpr int kWidth = 7*kBlockSpacing + 6*kBlockSize;
431 
432     static constexpr int kRow0Y = kBlockSpacing;
433     static constexpr int kRow1Y = 2*kBlockSpacing + kBlockSize;
434     static constexpr int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
435     static constexpr int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
436     static constexpr int kRow4Y = 5*kBlockSpacing + 4*kBlockSize;
437 
438     static constexpr int kSmallSize = 6;
439     static constexpr int kMaxTileSize = 32;
440 
441     TestPixels      fBigTestPixels;
442     TestPixels      fSmallTestPixels;
443 
444     sk_sp<SkShader> fShader;
445 
446     const BleedTest fBT;
447 
448     typedef GM INHERITED;
449 };
450 
451 
452 DEF_GM( return new BleedGM(kUseBitmap_BleedTest); )
DEF_GM(return new BleedGM (kUseImage_BleedTest);)453 DEF_GM( return new BleedGM(kUseImage_BleedTest); )
454 DEF_GM( return new BleedGM(kUseAlphaBitmap_BleedTest); )
455 DEF_GM( return new BleedGM(kUseAlphaImage_BleedTest); )
456 DEF_GM( return new BleedGM(kUseAlphaBitmapShader_BleedTest); )
457 DEF_GM( return new BleedGM(kUseAlphaImageShader_BleedTest); )
458 
459 ///////////////////////////////////////////////////////////////////////////////////////////////////
460 
461 // Construct an image and return the inner "src" rect. Build the image such that the interior is
462 // blue, with a margin of blue (2px) but then an outer margin of red.
463 //
464 // Show that kFast_SrcRectConstraint sees even the red margin (due to mipmapping) when the image
465 // is scaled down far enough.
466 //
467 static sk_sp<SkImage> make_image(SkCanvas* canvas, SkRect* srcR) {
468     // Intentially making the size a power of 2 to avoid the noise from how different GPUs will
469     // produce different mipmap filtering when we have an odd sized texture.
470     const int N = 10 + 2 + 8 + 2 + 10;
471     SkImageInfo info = SkImageInfo::MakeN32Premul(N, N);
472     auto        surface = ToolUtils::makeSurface(canvas, info);
473     SkCanvas* c = surface->getCanvas();
474     SkRect r = SkRect::MakeIWH(info.width(), info.height());
475     SkPaint paint;
476 
477     paint.setColor(SK_ColorRED);
478     c->drawRect(r, paint);
479     r.inset(10, 10);
480     paint.setColor(SK_ColorBLUE);
481     c->drawRect(r, paint);
482 
483     *srcR = r.makeInset(2, 2);
484     return surface->makeImageSnapshot();
485 }
486 
487 DEF_SIMPLE_GM(bleed_downscale, canvas, 360, 240) {
488     SkRect src;
489     sk_sp<SkImage> img = make_image(canvas, &src);
490     SkPaint paint;
491 
492     canvas->translate(10, 10);
493 
494     const SkCanvas::SrcRectConstraint constraints[] = {
495         SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint
496     };
497     const SkFilterQuality qualities[] = {
498         kNone_SkFilterQuality, kLow_SkFilterQuality, kMedium_SkFilterQuality
499     };
500     for (auto constraint : constraints) {
501         canvas->save();
502         for (auto quality : qualities) {
503             paint.setFilterQuality(quality);
504             auto surf = ToolUtils::makeSurface(canvas, SkImageInfo::MakeN32Premul(1, 1));
505             surf->getCanvas()->drawImageRect(img, src, SkRect::MakeWH(1, 1), &paint, constraint);
506             // now blow up the 1 pixel result
507             canvas->drawImageRect(surf->makeImageSnapshot(), SkRect::MakeWH(100, 100), nullptr);
508             canvas->translate(120, 0);
509         }
510         canvas->restore();
511         canvas->translate(0, 120);
512     }
513 }
514 
515 
516