Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2014 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 "sk_tool_utils.h"
     10 #include "SkBlurImageFilter.h"
     11 #include "SkDropShadowImageFilter.h"
     12 #include "SkImageSource.h"
     13 #include "SkOffsetImageFilter.h"
     14 #include "SkPath.h"
     15 #include "SkPictureImageFilter.h"
     16 #include "SkPictureRecorder.h"
     17 #include "SkRandom.h"
     18 #include "SkSurface.h"
     19 #include "SkTileImageFilter.h"
     20 
     21 namespace skiagm {
     22 
     23 // Each method of this type must draw its geometry inside 'r' using 'p'
     24 typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p);
     25 
     26 static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
     27     canvas->drawRect(r, p);
     28 }
     29 
     30 static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
     31     canvas->drawOval(r, p);
     32 }
     33 
     34 static void draw_rrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
     35     SkScalar xRad = r.width() / 4.0f;
     36     SkScalar yRad = r.height() / 4.0f;
     37 
     38     SkRRect rr;
     39     rr.setRectXY(r, xRad, yRad);
     40     canvas->drawRRect(rr, p);
     41 }
     42 
     43 static void draw_drrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
     44     SkScalar xRad = r.width() / 4.0f;
     45     SkScalar yRad = r.height() / 4.0f;
     46 
     47     SkRRect outer;
     48     outer.setRectXY(r, xRad, yRad);
     49     SkRRect inner = outer;
     50     inner.inset(xRad, yRad);
     51     canvas->drawDRRect(outer, inner, p);
     52 }
     53 
     54 static void draw_path(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
     55     SkPath path;
     56 
     57     path.moveTo(r.fLeft, r.fTop);
     58     path.lineTo(r.fLeft, r.fBottom);
     59     path.lineTo(r.fRight, r.fBottom);
     60     path.close();
     61 
     62     canvas->drawPath(path, p);
     63 }
     64 
     65 static void draw_points(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
     66     SkPoint pts0[2] = { { r.fLeft, r.fTop }, { r.fRight, r.fBottom } };
     67     SkPoint pts1[2] = { { r.fLeft, r.fBottom }, { r.fRight, r.fTop } };
     68 
     69     canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts0, p);
     70     canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts1, p);
     71 }
     72 
     73 static void draw_bitmap(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
     74     SkBitmap bm;
     75 
     76     bm.allocN32Pixels(64, 64);
     77     SkCanvas temp(bm);
     78     temp.clear(SK_ColorMAGENTA);
     79 
     80     canvas->drawBitmapRect(bm, r, &p);
     81 }
     82 
     83 constexpr drawMth gDrawMthds[] = {
     84     draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
     85 };
     86 
     87 static void add_paint(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> filter) {
     88     SkPaint& p = paints->push_back();
     89     p.setImageFilter(std::move(filter));
     90     SkASSERT(p.canComputeFastBounds());
     91 }
     92 
     93 // Create a selection of imagefilter-based paints to test
     94 static void create_paints(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> source) {
     95     {
     96         SkMatrix scale;
     97         scale.setScale(2.0f, 2.0f);
     98 
     99         sk_sp<SkImageFilter> scaleMIF(
    100             SkImageFilter::MakeMatrixFilter(scale, kLow_SkFilterQuality, source));
    101 
    102         add_paint(paints, std::move(scaleMIF));
    103     }
    104 
    105     {
    106         SkMatrix rot;
    107         rot.setRotate(-33.3f);
    108 
    109         sk_sp<SkImageFilter> rotMIF(
    110             SkImageFilter::MakeMatrixFilter(rot, kLow_SkFilterQuality, source));
    111 
    112         add_paint(paints, std::move(rotMIF));
    113     }
    114 
    115     {
    116         SkRect src = SkRect::MakeXYWH(20, 20, 10, 10);
    117         SkRect dst = SkRect::MakeXYWH(30, 30, 30, 30);
    118         sk_sp<SkImageFilter> tileIF(SkTileImageFilter::Make(src, dst, nullptr));
    119 
    120         add_paint(paints, std::move(tileIF));
    121     }
    122 
    123     {
    124         constexpr SkDropShadowImageFilter::ShadowMode kBoth =
    125                     SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode;
    126 
    127         sk_sp<SkImageFilter> dsif(SkDropShadowImageFilter::Make(10.0f, 10.0f,
    128                                                                 3.0f, 3.0f,
    129                                                                 SK_ColorRED, kBoth,
    130                                                                 source));
    131 
    132         add_paint(paints, std::move(dsif));
    133     }
    134 
    135     {
    136         sk_sp<SkImageFilter> dsif(
    137             SkDropShadowImageFilter::Make(27.0f, 27.0f,
    138                                             3.0f, 3.0f,
    139                                             SK_ColorRED,
    140                                             SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
    141                                             source));
    142 
    143         add_paint(paints, std::move(dsif));
    144     }
    145 
    146     add_paint(paints, SkBlurImageFilter::Make(3, 3, source));
    147     add_paint(paints, SkOffsetImageFilter::Make(15, 15, source));
    148 }
    149 
    150 // This GM visualizes the fast bounds for various combinations of geometry
    151 // and image filter
    152 class ImageFilterFastBoundGM : public GM {
    153 public:
    154     ImageFilterFastBoundGM() {
    155         this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
    156     }
    157 
    158 protected:
    159     static constexpr int kTileWidth = 100;
    160     static constexpr int kTileHeight = 100;
    161     static constexpr int kNumVertTiles = 7;
    162     static constexpr int kNumXtraCols = 2;
    163 
    164     SkString onShortName() override{ return SkString("filterfastbounds"); }
    165 
    166     SkISize onISize() override{
    167         return SkISize::Make((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols) * kTileWidth,
    168                              kNumVertTiles * kTileHeight);
    169     }
    170 
    171     static void draw_geom_with_paint(drawMth draw, const SkIPoint& off,
    172                                      SkCanvas* canvas, const SkPaint& p) {
    173         SkPaint redStroked;
    174         redStroked.setColor(SK_ColorRED);
    175         redStroked.setStyle(SkPaint::kStroke_Style);
    176 
    177         SkPaint blueStroked;
    178         blueStroked.setColor(SK_ColorBLUE);
    179         blueStroked.setStyle(SkPaint::kStroke_Style);
    180 
    181         const SkRect r = SkRect::MakeLTRB(20, 20, 30, 30);
    182         SkRect storage;
    183 
    184         canvas->save();
    185             canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
    186             canvas->scale(1.5f, 1.5f);
    187 
    188             const SkRect& fastBound = p.computeFastBounds(r, &storage);
    189 
    190             canvas->save();
    191                 canvas->clipRect(fastBound);
    192                 (*draw)(canvas, r, p);
    193             canvas->restore();
    194 
    195             canvas->drawRect(r, redStroked);
    196             canvas->drawRect(fastBound, blueStroked);
    197         canvas->restore();
    198     }
    199 
    200     static void draw_savelayer_with_paint(const SkIPoint& off,
    201                                           SkCanvas* canvas,
    202                                           const SkPaint& p) {
    203         SkPaint redStroked;
    204         redStroked.setColor(SK_ColorRED);
    205         redStroked.setStyle(SkPaint::kStroke_Style);
    206 
    207         SkPaint blueStroked;
    208         blueStroked.setColor(SK_ColorBLUE);
    209         blueStroked.setStyle(SkPaint::kStroke_Style);
    210 
    211         const SkRect bounds = SkRect::MakeWH(10, 10);
    212         SkRect storage;
    213 
    214         canvas->save();
    215             canvas->translate(30, 30);
    216             canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
    217             canvas->scale(1.5f, 1.5f);
    218 
    219             const SkRect& fastBound = p.computeFastBounds(bounds, &storage);
    220 
    221             canvas->saveLayer(&fastBound, &p);
    222             canvas->restore();
    223 
    224             canvas->drawRect(bounds, redStroked);
    225             canvas->drawRect(fastBound, blueStroked);
    226         canvas->restore();
    227     }
    228 
    229     void onDraw(SkCanvas* canvas) override{
    230 
    231         SkPaint blackFill;
    232 
    233         //-----------
    234         // Normal paints (no source)
    235         SkTArray<SkPaint> paints;
    236         create_paints(&paints, nullptr);
    237 
    238         //-----------
    239         // Paints with a PictureImageFilter as a source
    240         sk_sp<SkPicture> pic;
    241 
    242         {
    243             SkPictureRecorder rec;
    244 
    245             SkCanvas* c = rec.beginRecording(10, 10);
    246             c->drawRect(SkRect::MakeWH(10, 10), blackFill);
    247             pic = rec.finishRecordingAsPicture();
    248         }
    249 
    250         SkTArray<SkPaint> pifPaints;
    251         create_paints(&pifPaints, SkPictureImageFilter::Make(pic));
    252 
    253         //-----------
    254         // Paints with a SkImageSource as a source
    255 
    256         auto surface(SkSurface::MakeRasterN32Premul(10, 10));
    257         {
    258             SkPaint p;
    259             SkCanvas* temp = surface->getCanvas();
    260             temp->clear(SK_ColorYELLOW);
    261             p.setColor(SK_ColorBLUE);
    262             temp->drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
    263             p.setColor(SK_ColorGREEN);
    264             temp->drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
    265         }
    266 
    267         sk_sp<SkImage> image(surface->makeImageSnapshot());
    268         sk_sp<SkImageFilter> imageSource(SkImageSource::Make(std::move(image)));
    269         SkTArray<SkPaint> bmsPaints;
    270         create_paints(&bmsPaints, std::move(imageSource));
    271 
    272         //-----------
    273         SkASSERT(paints.count() == kNumVertTiles);
    274         SkASSERT(paints.count() == pifPaints.count());
    275         SkASSERT(paints.count() == bmsPaints.count());
    276 
    277         // horizontal separators
    278         for (int i = 1; i < paints.count(); ++i) {
    279             canvas->drawLine(0,
    280                              i*SkIntToScalar(kTileHeight),
    281                              SkIntToScalar((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols)*kTileWidth),
    282                              i*SkIntToScalar(kTileHeight),
    283                              blackFill);
    284         }
    285         // vertical separators
    286         for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols; ++i) {
    287             canvas->drawLine(SkIntToScalar(i * kTileWidth),
    288                              0,
    289                              SkIntToScalar(i * kTileWidth),
    290                              SkIntToScalar(paints.count() * kTileWidth),
    291                              blackFill);
    292         }
    293 
    294         // A column of saveLayers with PictureImageFilters
    295         for (int i = 0; i < pifPaints.count(); ++i) {
    296             draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
    297                                       canvas, pifPaints[i]);
    298         }
    299 
    300         // A column of saveLayers with BitmapSources
    301         for (int i = 0; i < pifPaints.count(); ++i) {
    302             draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight),
    303                                       canvas, bmsPaints[i]);
    304         }
    305 
    306         // Multiple columns with different geometry
    307         for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds); ++i) {
    308             for (int j = 0; j < paints.count(); ++j) {
    309                 draw_geom_with_paint(*gDrawMthds[i],
    310                                      SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight),
    311                                      canvas, paints[j]);
    312             }
    313         }
    314 
    315     }
    316 
    317 private:
    318     typedef GM INHERITED;
    319 };
    320 
    321 //////////////////////////////////////////////////////////////////////////////
    322 
    323 DEF_GM(return new ImageFilterFastBoundGM;)
    324 }
    325