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 "SkBlurMaskFilter.h"
     11 #include "SkCanvas.h"
     12 
     13 #if SK_SUPPORT_GPU
     14 #include "GrContext.h"
     15 #endif
     16 
     17 // Create a black&white checked texture with 2 1-pixel rings
     18 // around the outside edge. The inner ring is red and the outer ring is blue.
     19 static void make_ringed_bitmap(SkBitmap* result, int width, int height) {
     20     SkASSERT(0 == width % 2 && 0 == height % 2);
     21 
     22     static const SkPMColor kRed = SkPreMultiplyColor(SK_ColorRED);
     23     static const SkPMColor kBlue = SkPreMultiplyColor(SK_ColorBLUE);
     24     static const SkPMColor kBlack = SkPreMultiplyColor(SK_ColorBLACK);
     25     static const SkPMColor kWhite = SkPreMultiplyColor(SK_ColorWHITE);
     26 
     27     result->allocN32Pixels(width, height, true);
     28 
     29     SkPMColor* scanline = result->getAddr32(0, 0);
     30     for (int x = 0; x < width; ++x) {
     31         scanline[x] = kBlue;
     32     }
     33     scanline = result->getAddr32(0, 1);
     34     scanline[0] = kBlue;
     35     for (int x = 1; x < width - 1; ++x) {
     36         scanline[x] = kRed;
     37     }
     38     scanline[width-1] = kBlue;
     39 
     40     for (int y = 2; y < height/2; ++y) {
     41         scanline = result->getAddr32(0, y);
     42         scanline[0] = kBlue;
     43         scanline[1] = kRed;
     44         for (int x = 2; x < width/2; ++x) {
     45             scanline[x] = kBlack;
     46         }
     47         for (int x = width/2; x < width-2; ++x) {
     48             scanline[x] = kWhite;
     49         }
     50         scanline[width-2] = kRed;
     51         scanline[width-1] = kBlue;
     52     }
     53 
     54     for (int y = height/2; y < height-2; ++y) {
     55         scanline = result->getAddr32(0, y);
     56         scanline[0] = kBlue;
     57         scanline[1] = kRed;
     58         for (int x = 2; x < width/2; ++x) {
     59             scanline[x] = kWhite;
     60         }
     61         for (int x = width/2; x < width-2; ++x) {
     62             scanline[x] = kBlack;
     63         }
     64         scanline[width-2] = kRed;
     65         scanline[width-1] = kBlue;
     66     }
     67 
     68     scanline = result->getAddr32(0, height-2);
     69     scanline[0] = kBlue;
     70     for (int x = 1; x < width - 1; ++x) {
     71         scanline[x] = kRed;
     72     }
     73     scanline[width-1] = kBlue;
     74 
     75     scanline = result->getAddr32(0, height-1);
     76     for (int x = 0; x < width; ++x) {
     77         scanline[x] = kBlue;
     78     }
     79     result->setImmutable();
     80 }
     81 
     82 // This GM exercises the drawBitmapRectToRect "bleed" flag
     83 class BleedGM : public skiagm::GM {
     84 public:
     85     BleedGM() {}
     86 
     87 protected:
     88     virtual uint32_t onGetFlags() const SK_OVERRIDE {
     89         return kSkipTiled_Flag;
     90     }
     91 
     92     virtual SkString onShortName() SK_OVERRIDE {
     93         return SkString("bleed");
     94     }
     95 
     96     virtual SkISize onISize() SK_OVERRIDE {
     97         return SkISize::Make(kWidth, 780);
     98     }
     99 
    100     virtual void onOnceBeforeDraw() SK_OVERRIDE {
    101         make_ringed_bitmap(&fBitmapSmall, kSmallTextureSize, kSmallTextureSize);
    102 
    103         // To exercise the GPU's tiling path we need a texture
    104         // too big for the GPU to handle in one go
    105         make_ringed_bitmap(&fBitmapBig, 2*kMaxTextureSize, 2*kMaxTextureSize);
    106     }
    107 
    108     // Draw only the center of the small bitmap
    109     void drawCase1(SkCanvas* canvas, int transX, int transY,
    110                    SkCanvas::DrawBitmapRectFlags flags, SkPaint::FilterLevel filter) {
    111         SkRect src = SkRect::MakeXYWH(2, 2,
    112                                       SkIntToScalar(kSmallTextureSize-4),
    113                                       SkIntToScalar(kSmallTextureSize-4));
    114         SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
    115 
    116         SkPaint paint;
    117         paint.setFilterLevel(filter);
    118 
    119         canvas->save();
    120         canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
    121         canvas->drawBitmapRectToRect(fBitmapSmall, &src, dst, &paint, flags);
    122         canvas->restore();
    123     }
    124 
    125     // Draw almost all of the large bitmap
    126     void drawCase2(SkCanvas* canvas, int transX, int transY,
    127                    SkCanvas::DrawBitmapRectFlags flags, SkPaint::FilterLevel filter) {
    128         SkRect src = SkRect::MakeXYWH(2, 2,
    129                                       SkIntToScalar(fBitmapBig.width()-4),
    130                                       SkIntToScalar(fBitmapBig.height()-4));
    131         SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
    132 
    133         SkPaint paint;
    134         paint.setFilterLevel(filter);
    135 
    136         canvas->save();
    137         canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
    138         canvas->drawBitmapRectToRect(fBitmapBig, &src, dst, &paint, flags);
    139         canvas->restore();
    140     }
    141 
    142     // Draw ~1/4 of the large bitmap
    143     void drawCase3(SkCanvas* canvas, int transX, int transY,
    144                    SkCanvas::DrawBitmapRectFlags flags, SkPaint::FilterLevel filter) {
    145         SkRect src = SkRect::MakeXYWH(2, 2,
    146                                       SkIntToScalar(fBitmapBig.width()/2-2),
    147                                       SkIntToScalar(fBitmapBig.height()/2-2));
    148         SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
    149 
    150         SkPaint paint;
    151         paint.setFilterLevel(filter);
    152 
    153         canvas->save();
    154         canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
    155         canvas->drawBitmapRectToRect(fBitmapBig, &src, dst, &paint, flags);
    156         canvas->restore();
    157     }
    158 
    159     // Draw the center of the small bitmap with a mask filter
    160     void drawCase4(SkCanvas* canvas, int transX, int transY,
    161                    SkCanvas::DrawBitmapRectFlags flags, SkPaint::FilterLevel filter) {
    162         SkRect src = SkRect::MakeXYWH(2, 2,
    163                                       SkIntToScalar(kSmallTextureSize-4),
    164                                       SkIntToScalar(kSmallTextureSize-4));
    165         SkRect dst = SkRect::MakeXYWH(0, 0, SkIntToScalar(kBlockSize), SkIntToScalar(kBlockSize));
    166 
    167         SkPaint paint;
    168         paint.setFilterLevel(filter);
    169         SkMaskFilter* mf = SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
    170                                          SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(3)));
    171         paint.setMaskFilter(mf)->unref();
    172 
    173         canvas->save();
    174         canvas->translate(SkIntToScalar(transX), SkIntToScalar(transY));
    175         canvas->drawBitmapRectToRect(fBitmapSmall, &src, dst, &paint, flags);
    176         canvas->restore();
    177     }
    178 
    179     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
    180 
    181         canvas->clear(SK_ColorGRAY);
    182 
    183         for (int m = 0; m < 2; ++m) {
    184             canvas->save();
    185             if (m) {
    186                 static const SkScalar kBottom = SkIntToScalar(kRow3Y + kBlockSize + kBlockSpacing);
    187                 canvas->translate(0, kBottom);
    188                 SkMatrix rotate;
    189                 rotate.setRotate(15.f, 0, kBottom + kBlockSpacing);
    190                 canvas->concat(rotate);
    191                 canvas->scale(0.71f, 1.22f);
    192             }
    193 
    194             // First draw a column with no bleeding, tiling, or filtering
    195             this->drawCase1(canvas, kCol0X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kNone_FilterLevel);
    196             this->drawCase2(canvas, kCol0X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kNone_FilterLevel);
    197             this->drawCase3(canvas, kCol0X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kNone_FilterLevel);
    198             this->drawCase4(canvas, kCol0X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kNone_FilterLevel);
    199 
    200             // Then draw a column with no bleeding or tiling but with low filtering
    201             this->drawCase1(canvas, kCol1X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    202             this->drawCase2(canvas, kCol1X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    203             this->drawCase3(canvas, kCol1X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    204             this->drawCase4(canvas, kCol1X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    205 
    206             // Then draw a column with no bleeding or tiling but with high filtering
    207             this->drawCase1(canvas, kCol2X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    208             this->drawCase2(canvas, kCol2X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    209             this->drawCase3(canvas, kCol2X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    210             this->drawCase4(canvas, kCol2X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    211 
    212 #if SK_SUPPORT_GPU
    213             GrContext* ctx = canvas->getGrContext();
    214             int oldMaxTextureSize = 0;
    215             if (ctx) {
    216                 // shrink the max texture size so all our textures can be reasonably sized
    217                 oldMaxTextureSize = ctx->getMaxTextureSize();
    218                 ctx->setMaxTextureSizeOverride(kMaxTextureSize);
    219             }
    220 #endif
    221 
    222             // Then draw a column with no bleeding but with tiling and low filtering
    223             this->drawCase1(canvas, kCol3X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    224             this->drawCase2(canvas, kCol3X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    225             this->drawCase3(canvas, kCol3X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    226             this->drawCase4(canvas, kCol3X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    227 
    228             // Then draw a column with no bleeding but with tiling and high filtering
    229             this->drawCase1(canvas, kCol4X, kRow0Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    230             this->drawCase2(canvas, kCol4X, kRow1Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    231             this->drawCase3(canvas, kCol4X, kRow2Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    232             this->drawCase4(canvas, kCol4X, kRow3Y, SkCanvas::kNone_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    233 
    234             // Then draw a column with bleeding, tiling, and low filtering
    235             this->drawCase1(canvas, kCol5X, kRow0Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    236             this->drawCase2(canvas, kCol5X, kRow1Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    237             this->drawCase3(canvas, kCol5X, kRow2Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    238             this->drawCase4(canvas, kCol5X, kRow3Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kLow_FilterLevel);
    239 
    240             // Finally draw a column with bleeding, tiling, and high filtering
    241             this->drawCase1(canvas, kCol6X, kRow0Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    242             this->drawCase2(canvas, kCol6X, kRow1Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    243             this->drawCase3(canvas, kCol6X, kRow2Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    244             this->drawCase4(canvas, kCol6X, kRow3Y, SkCanvas::kBleed_DrawBitmapRectFlag, SkPaint::kHigh_FilterLevel);
    245 
    246 #if SK_SUPPORT_GPU
    247             if (ctx) {
    248                 ctx->setMaxTextureSizeOverride(oldMaxTextureSize);
    249             }
    250 #endif
    251             canvas->restore();
    252         }
    253     }
    254 
    255 private:
    256     static const int kBlockSize = 70;
    257     static const int kBlockSpacing = 5;
    258 
    259     static const int kCol0X = kBlockSpacing;
    260     static const int kCol1X = 2*kBlockSpacing + kBlockSize;
    261     static const int kCol2X = 3*kBlockSpacing + 2*kBlockSize;
    262     static const int kCol3X = 4*kBlockSpacing + 3*kBlockSize;
    263     static const int kCol4X = 5*kBlockSpacing + 4*kBlockSize;
    264     static const int kCol5X = 6*kBlockSpacing + 5*kBlockSize;
    265     static const int kCol6X = 7*kBlockSpacing + 6*kBlockSize;
    266     static const int kWidth = 8*kBlockSpacing + 7*kBlockSize;
    267 
    268     static const int kRow0Y = kBlockSpacing;
    269     static const int kRow1Y = 2*kBlockSpacing + kBlockSize;
    270     static const int kRow2Y = 3*kBlockSpacing + 2*kBlockSize;
    271     static const int kRow3Y = 4*kBlockSpacing + 3*kBlockSize;
    272 
    273     static const int kSmallTextureSize = 6;
    274     static const int kMaxTextureSize = 32;
    275 
    276     SkBitmap fBitmapSmall;
    277     SkBitmap fBitmapBig;
    278 
    279     typedef GM INHERITED;
    280 };
    281 
    282 DEF_GM( return new BleedGM(); )
    283