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