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