Home | History | Annotate | Download | only in gm
      1 /*
      2 * Copyright 2012 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 "SkPath.h"
     13 
     14 #define STROKE_WIDTH    SkIntToScalar(10)
     15 
     16 typedef void (*Proc)(SkCanvas*, const SkRect&, const SkPaint&);
     17 
     18 static void fill_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
     19     canvas->drawRect(r, p);
     20 }
     21 
     22 static void draw_donut(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
     23     SkRect  rect;
     24     SkPath  path;
     25 
     26     rect = r;
     27     rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
     28     path.addRect(rect);
     29     rect = r;
     30     rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
     31 
     32     path.addRect(rect);
     33     path.setFillType(SkPath::kEvenOdd_FillType);
     34 
     35     canvas->drawPath(path, p);
     36 }
     37 
     38 static void draw_donut_skewed(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
     39     SkRect  rect;
     40     SkPath  path;
     41 
     42     rect = r;
     43     rect.outset(STROKE_WIDTH/2, STROKE_WIDTH/2);
     44     path.addRect(rect);
     45     rect = r;
     46     rect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
     47 
     48     rect.offset(7, -7);
     49 
     50     path.addRect(rect);
     51     path.setFillType(SkPath::kEvenOdd_FillType);
     52 
     53     canvas->drawPath(path, p);
     54 }
     55 
     56 #include "SkGradientShader.h"
     57 
     58 typedef void (*PaintProc)(SkPaint*, SkScalar width);
     59 
     60 class BlurRectGM : public skiagm::GM {
     61       SkAutoTUnref<SkMaskFilter> fMaskFilters[kLastEnum_SkBlurStyle + 1];
     62       SkString  fName;
     63       SkAlpha   fAlpha;
     64 public:
     65     BlurRectGM(const char name[], U8CPU alpha)
     66         : fName(name)
     67         , fAlpha(SkToU8(alpha)) {
     68     }
     69 
     70 protected:
     71     virtual void onOnceBeforeDraw() SK_OVERRIDE {
     72         for (int i = 0; i <= kLastEnum_SkBlurStyle; ++i) {
     73             fMaskFilters[i].reset(SkBlurMaskFilter::Create((SkBlurStyle)i,
     74                                   SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(STROKE_WIDTH/2)),
     75                                   SkBlurMaskFilter::kHighQuality_BlurFlag));
     76         }
     77     }
     78 
     79     virtual SkString onShortName() {
     80         return fName;
     81     }
     82 
     83     virtual SkISize onISize() {
     84         return SkISize::Make(440, 820);
     85     }
     86 
     87     virtual void onDraw(SkCanvas* canvas) {
     88         canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2);
     89 
     90         SkRect  r = { 0, 0, 100, 50 };
     91         SkScalar scales[] = { SK_Scalar1, 0.6f };
     92 
     93         for (size_t s = 0; s < SK_ARRAY_COUNT(scales); ++s) {
     94             canvas->save();
     95             for (size_t f = 0; f < SK_ARRAY_COUNT(fMaskFilters); ++f) {
     96                 SkPaint paint;
     97                 paint.setMaskFilter(fMaskFilters[f]);
     98                 paint.setAlpha(fAlpha);
     99 
    100                 static const Proc procs[] = {
    101                     fill_rect, draw_donut, draw_donut_skewed
    102                 };
    103 
    104                 canvas->save();
    105                 canvas->scale(scales[s], scales[s]);
    106                 this->drawProcs(canvas, r, paint, false, procs, SK_ARRAY_COUNT(procs));
    107                 canvas->translate(r.width() * 4/3, 0);
    108                 this->drawProcs(canvas, r, paint, true, procs, SK_ARRAY_COUNT(procs));
    109                 canvas->restore();
    110 
    111                 canvas->translate(0, SK_ARRAY_COUNT(procs) * r.height() * 4/3 * scales[s]);
    112             }
    113             canvas->restore();
    114             canvas->translate(2 * r.width() * 4/3 * scales[s], 0);
    115         }
    116     }
    117 
    118     virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }
    119 
    120 private:
    121     void drawProcs(SkCanvas* canvas, const SkRect& r, const SkPaint& paint,
    122                    bool doClip, const Proc procs[], size_t procsCount) {
    123         SkAutoCanvasRestore acr(canvas, true);
    124         for (size_t i = 0; i < procsCount; ++i) {
    125             if (doClip) {
    126                 SkRect clipRect(r);
    127                 clipRect.inset(STROKE_WIDTH/2, STROKE_WIDTH/2);
    128                 canvas->save();
    129                 canvas->clipRect(r);
    130             }
    131             procs[i](canvas, r, paint);
    132             if (doClip) {
    133                 canvas->restore();
    134             }
    135             canvas->translate(0, r.height() * 4/3);
    136         }
    137     }
    138 private:
    139     typedef GM INHERITED;
    140 };
    141 
    142 
    143 class BlurRectDirectGM : public skiagm::GM {
    144     SkString  fName;
    145     int fGMWidth, fGMHeight;
    146     int fPadding, fMargin;
    147 public:
    148     BlurRectDirectGM(const char name[])
    149         : fName(name),
    150           fGMWidth(1200),
    151           fGMHeight(1024),
    152           fPadding(10),
    153           fMargin(100)
    154     {
    155     }
    156 
    157 protected:
    158     virtual SkString onShortName() {
    159         return fName;
    160     }
    161 
    162     virtual SkISize onISize() {
    163         return SkISize::Make(fGMWidth, fGMHeight);
    164     }
    165 
    166     virtual void onDraw(SkCanvas* canvas) {
    167         const int widths[] = {25, 5, 5, 100, 150, 25};
    168         const int heights[] = {100, 100, 5, 25, 150, 25};
    169         const SkBlurStyle styles[] = {kNormal_SkBlurStyle, kInner_SkBlurStyle, kOuter_SkBlurStyle};
    170         const float radii[] = {20, 5, 10};
    171 
    172         canvas->translate(50,20);
    173 
    174         int cur_x = 0;
    175         int cur_y = 0;
    176 
    177         int max_height = 0;
    178 
    179         for (size_t i = 0 ; i < SK_ARRAY_COUNT(widths) ; i++) {
    180             int width = widths[i];
    181             int height = heights[i];
    182             SkRect r;
    183             r.setWH(SkIntToScalar(width), SkIntToScalar(height));
    184             SkAutoCanvasRestore autoRestore(canvas, true);
    185 
    186             for (size_t j = 0 ; j < SK_ARRAY_COUNT(radii) ; j++) {
    187                 float radius = radii[j];
    188                 for (size_t k = 0 ; k < SK_ARRAY_COUNT(styles) ; k++) {
    189                     SkBlurStyle style = styles[k];
    190 
    191                     SkMask mask;
    192                     SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius), &mask, r, style);
    193 
    194                     SkAutoMaskFreeImage amfi(mask.fImage);
    195 
    196                     SkBitmap bm;
    197                     bm.installMaskPixels(mask);
    198 
    199                     if (cur_x + bm.width() >= fGMWidth - fMargin) {
    200                         cur_x = 0;
    201                         cur_y += max_height + fPadding;
    202                         max_height = 0;
    203                     }
    204 
    205                     canvas->save();
    206                     canvas->translate((SkScalar)cur_x, (SkScalar)cur_y);
    207                     canvas->translate(-(bm.width() - r.width())/2, -(bm.height()-r.height())/2);
    208                     canvas->drawBitmap(bm, 0.f, 0.f, NULL);
    209                     canvas->restore();
    210 
    211                     cur_x += bm.width() + fPadding;
    212                     if (bm.height() > max_height)
    213                         max_height = bm.height();
    214                 }
    215             }
    216         }
    217     }
    218 
    219     virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }
    220 
    221 private:
    222     typedef GM INHERITED;
    223 };
    224 
    225 class BlurRectCompareGM : public skiagm::GM {
    226     SkString  fName;
    227     unsigned int fRectWidth, fRectHeight;
    228     SkScalar fRadius;
    229     SkBlurStyle fStyle;
    230 public:
    231     BlurRectCompareGM(const char name[], unsigned int rectWidth,
    232                       unsigned int rectHeight, float radius,
    233                       SkBlurStyle style)
    234         : fName(name)
    235         , fRectWidth(rectWidth)
    236         , fRectHeight(rectHeight)
    237         , fRadius(radius)
    238         , fStyle(style) {
    239     }
    240     int width() const {
    241         return fRectWidth;
    242     }
    243     int height() const {
    244         return fRectHeight;
    245     }
    246     SkScalar radius() const {
    247         return fRadius;
    248     }
    249     SkBlurStyle style() const {
    250         return fStyle;
    251     }
    252 
    253 protected:
    254     virtual SkString onShortName() {
    255         return fName;
    256     }
    257 
    258     virtual SkISize onISize() {
    259         return SkISize::Make(640, 480);
    260     }
    261 
    262     virtual bool makeMask(SkMask *m, const SkRect&) = 0;
    263 
    264     virtual void onDraw(SkCanvas* canvas) {
    265         SkRect r;
    266         r.setWH(SkIntToScalar(fRectWidth), SkIntToScalar(fRectHeight));
    267 
    268         SkISize canvas_size = canvas->getDeviceSize();
    269         int center_x = (canvas_size.fWidth - (int)(r.width()))/2;
    270         int center_y = (canvas_size.fHeight - (int)(r.height()))/2;
    271 
    272         SkMask mask;
    273 
    274         if (!this->makeMask(&mask, r)) {
    275             SkPaint paint;
    276             r.offset( SkIntToScalar(center_x), SkIntToScalar(center_y) );
    277             canvas->drawRect(r,paint);
    278             return;
    279         }
    280         SkAutoMaskFreeImage amfi(mask.fImage);
    281 
    282         SkBitmap bm;
    283         bm.installMaskPixels(mask);
    284 
    285         center_x = (canvas_size.fWidth - mask.fBounds.width())/2;
    286         center_y = (canvas_size.fHeight - mask.fBounds.height())/2;
    287 
    288         canvas->drawBitmap(bm, SkIntToScalar(center_x), SkIntToScalar(center_y), NULL);
    289     }
    290 
    291     virtual uint32_t onGetFlags() const { return kSkipPipe_Flag; }
    292 
    293 private:
    294     typedef GM INHERITED;
    295 };
    296 
    297 class BlurRectFastGM: public BlurRectCompareGM {
    298 public:
    299     BlurRectFastGM(const char name[], unsigned int rectWidth,
    300                    unsigned int rectHeight, float blurRadius,
    301                    SkBlurStyle style) :
    302         INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
    303         }
    304 
    305 protected:
    306     virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
    307         return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(this->radius()),
    308                                     m, r, this->style());
    309     }
    310 private:
    311     typedef BlurRectCompareGM INHERITED;
    312 };
    313 
    314 class BlurRectSlowGM: public BlurRectCompareGM {
    315 public:
    316     BlurRectSlowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
    317                    float blurRadius, SkBlurStyle style)
    318         : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
    319         }
    320 
    321 protected:
    322     virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
    323         SkMask src;
    324         r.roundOut(&src.fBounds);
    325         src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
    326         src.fFormat = SkMask::kA8_Format;
    327         src.fRowBytes = src.fBounds.width();
    328         src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
    329         SkAutoMaskFreeImage amfi(src.fImage);
    330 
    331         memset(src.fImage, 0xff, src.computeTotalImageSize());
    332 
    333         return SkBlurMask::BoxBlur(m, src,
    334                                    SkBlurMask::ConvertRadiusToSigma(this->radius()),
    335                                    this->style(), this->getQuality());
    336     }
    337 
    338     virtual SkBlurQuality getQuality() {
    339         return kHigh_SkBlurQuality;
    340     }
    341 private:
    342     typedef BlurRectCompareGM INHERITED;
    343 };
    344 
    345 class BlurRectSlowLowGM: public BlurRectSlowGM {
    346 public:
    347     BlurRectSlowLowGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
    348                       float blurRadius, SkBlurStyle style)
    349         : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
    350         }
    351 
    352 protected:
    353     virtual SkBlurQuality getQuality() SK_OVERRIDE {
    354         return kLow_SkBlurQuality;
    355     }
    356 private:
    357     typedef BlurRectSlowGM INHERITED;
    358 };
    359 
    360 class BlurRectGroundTruthGM: public BlurRectCompareGM {
    361 public:
    362     BlurRectGroundTruthGM(const char name[], unsigned int rectWidth, unsigned int rectHeight,
    363                           float blurRadius, SkBlurStyle style)
    364         : INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
    365         }
    366 
    367 protected:
    368     virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
    369         SkMask src;
    370         r.roundOut(&src.fBounds);
    371         src.fBounds.offset(-src.fBounds.fLeft, -src.fBounds.fTop);  // move to origin
    372         src.fFormat = SkMask::kA8_Format;
    373         src.fRowBytes = src.fBounds.width();
    374         src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
    375         SkAutoMaskFreeImage amfi(src.fImage);
    376 
    377         memset(src.fImage, 0xff, src.computeTotalImageSize());
    378 
    379         return SkBlurMask::BlurGroundTruth(SkBlurMask::ConvertRadiusToSigma(this->radius()),
    380                                            m, src, this->style());
    381     }
    382 
    383     virtual SkBlurQuality getQuality() {
    384         return kHigh_SkBlurQuality;
    385     }
    386 private:
    387     typedef BlurRectCompareGM INHERITED;
    388 };
    389 
    390 
    391 //////////////////////////////////////////////////////////////////////////////
    392 
    393 DEF_GM(return new BlurRectGM("blurrects", 0xFF);)
    394 DEF_GM(return new BlurRectDirectGM("blurrect_gallery");)
    395