Home | History | Annotate | Download | only in samplecode
      1 /*
      2  * Copyright 2015 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 
     10 #include "Resources.h"
     11 #include "SampleCode.h"
     12 #include "SkAnimTimer.h"
     13 #include "SkCanvas.h"
     14 #include "SkInterpolator.h"
     15 #include "SkSurface.h"
     16 #include "SkRandom.h"
     17 #include "SkTime.h"
     18 
     19 static SkSurface* make_surface(SkCanvas* canvas, const SkImageInfo& info) {
     20     SkSurface* surface = canvas->newSurface(info);
     21     if (!surface) {
     22         surface = SkSurface::NewRaster(info);
     23     }
     24     return surface;
     25 }
     26 
     27 #define N   128
     28 #define ANGLE_DELTA 3
     29 #define SCALE_DELTA (SK_Scalar1 / 32)
     30 
     31 static SkImage* make_image() {
     32     SkImageInfo info = SkImageInfo::MakeN32(N, N, kOpaque_SkAlphaType);
     33     SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(info));
     34     SkCanvas* canvas = surface->getCanvas();
     35     canvas->drawColor(SK_ColorWHITE);
     36 
     37     SkPath path;
     38     path.setFillType(SkPath::kEvenOdd_FillType);
     39 
     40     path.addRect(SkRect::MakeWH(N/2, N));
     41     path.addRect(SkRect::MakeWH(N, N/2));
     42     path.moveTo(0, 0); path.lineTo(N, 0); path.lineTo(0, N); path.close();
     43 
     44     canvas->drawPath(path, SkPaint());
     45     return surface->newImageSnapshot();
     46 }
     47 
     48 static SkImage* zoom_up(SkImage* orig) {
     49     const SkScalar S = 8;    // amount to scale up
     50     const int D = 2;    // dimension scaling for the offscreen
     51     // since we only view the center, don't need to produce the entire thing
     52 
     53     SkImageInfo info = SkImageInfo::MakeN32(orig->width() * D, orig->height() * D,
     54                                             kOpaque_SkAlphaType);
     55     SkAutoTUnref<SkSurface> surface(orig->newSurface(info));
     56     SkCanvas* canvas = surface->getCanvas();
     57     canvas->drawColor(SK_ColorWHITE);
     58     canvas->scale(S, S);
     59     canvas->translate(-SkScalarHalf(orig->width()) * (S - D) / S,
     60                       -SkScalarHalf(orig->height()) * (S - D) / S);
     61     canvas->drawImage(orig, 0, 0, NULL);
     62 
     63     if (S > 3) {
     64         SkPaint paint;
     65         paint.setColor(SK_ColorWHITE);
     66         for (int i = 1; i < orig->height(); ++i) {
     67             SkScalar y = SkIntToScalar(i);
     68             canvas->drawLine(0, y, SkIntToScalar(orig->width()), y, paint);
     69         }
     70         for (int i = 1; i < orig->width(); ++i) {
     71             SkScalar x = SkIntToScalar(i);
     72             canvas->drawLine(x, 0, x, SkIntToScalar(orig->height()), paint);
     73         }
     74     }
     75     return surface->newImageSnapshot();
     76 }
     77 
     78 struct AnimValue {
     79     SkScalar fValue;
     80     SkScalar fMin;
     81     SkScalar fMax;
     82     SkScalar fMod;
     83 
     84     operator SkScalar() const { return fValue; }
     85 
     86     void set(SkScalar value, SkScalar min, SkScalar max) {
     87         fValue = value;
     88         fMin = min;
     89         fMax = max;
     90         fMod = 0;
     91     }
     92 
     93     void setMod(SkScalar value, SkScalar mod) {
     94         fValue = value;
     95         fMin = 0;
     96         fMax = 0;
     97         fMod = mod;
     98     }
     99 
    100     SkScalar inc(SkScalar delta) {
    101         fValue += delta;
    102         return this->fixUp();
    103     }
    104 
    105     SkScalar fixUp() {
    106         if (fMod) {
    107             fValue = SkScalarMod(fValue, fMod);
    108         } else {
    109             if (fValue > fMax) {
    110                 fValue = fMax;
    111             } else if (fValue < fMin) {
    112                 fValue = fMin;
    113             }
    114         }
    115         return fValue;
    116     }
    117 };
    118 
    119 static void draw_box_frame(SkCanvas* canvas, int width, int height) {
    120     SkPaint p;
    121     p.setStyle(SkPaint::kStroke_Style);
    122     p.setColor(SK_ColorRED);
    123     SkRect r = SkRect::MakeIWH(width, height);
    124     r.inset(0.5f, 0.5f);
    125     canvas->drawRect(r, p);
    126     canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), p);
    127     canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), p);
    128 }
    129 
    130 class FilterQualityView : public SampleView {
    131     SkAutoTUnref<SkImage> fImage;
    132     AnimValue             fScale, fAngle;
    133     SkSize              fCell;
    134     SkInterpolator      fTrans;
    135     SkMSec              fCurrTime;
    136     bool                fShowFatBits;
    137 
    138 public:
    139     FilterQualityView() : fImage(make_image()), fTrans(2, 2), fShowFatBits(true) {
    140         fCell.set(256, 256);
    141 
    142         fScale.set(1, SK_Scalar1 / 8, 1);
    143         fAngle.setMod(0, 360);
    144 
    145         SkScalar values[2];
    146         fTrans.setMirror(true);
    147         fTrans.setReset(true);
    148 
    149         fCurrTime = 0;
    150 
    151         fTrans.setRepeatCount(999);
    152         values[0] = values[1] = 0;
    153         fTrans.setKeyFrame(0, fCurrTime, values);
    154         values[0] = values[1] = 1;
    155         fTrans.setKeyFrame(1, fCurrTime + 2000, values);
    156     }
    157 
    158 protected:
    159     bool onQuery(SkEvent* evt) override {
    160         if (SampleCode::TitleQ(*evt)) {
    161             SampleCode::TitleR(evt, "FilterQuality");
    162             return true;
    163         }
    164         SkUnichar uni;
    165         if (SampleCode::CharQ(*evt, &uni)) {
    166             switch (uni) {
    167                 case '1': fAngle.inc(-ANGLE_DELTA); this->inval(NULL); return true;
    168                 case '2': fAngle.inc( ANGLE_DELTA); this->inval(NULL); return true;
    169                 case '3': fScale.inc(-SCALE_DELTA); this->inval(NULL); return true;
    170                 case '4': fScale.inc( SCALE_DELTA); this->inval(NULL); return true;
    171                 case '5': fShowFatBits = !fShowFatBits; this->inval(NULL); return true;
    172                 default: break;
    173             }
    174         }
    175         return this->INHERITED::onQuery(evt);
    176     }
    177 
    178     void drawTheImage(SkCanvas* canvas, const SkISize& size, SkFilterQuality filter,
    179                       SkScalar dx, SkScalar dy) {
    180         SkPaint paint;
    181         paint.setAntiAlias(true);
    182         paint.setFilterQuality(filter);
    183 
    184         SkAutoCanvasRestore acr(canvas, true);
    185 
    186         canvas->translate(dx, dy);
    187 
    188         canvas->translate(SkScalarHalf(size.width()), SkScalarHalf(size.height()));
    189         canvas->scale(fScale, fScale);
    190         canvas->rotate(fAngle);
    191         canvas->drawImage(fImage, -SkScalarHalf(fImage->width()), -SkScalarHalf(fImage->height()),
    192                           &paint);
    193 
    194         if (false) {
    195             acr.restore();
    196             draw_box_frame(canvas, size.width(), size.height());
    197         }
    198     }
    199 
    200     void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) {
    201         SkCanvas* origCanvas = canvas;
    202         SkAutoCanvasRestore acr(canvas, true);
    203 
    204         SkISize size = SkISize::Make(fImage->width(), fImage->height());
    205 
    206         SkAutoTUnref<SkSurface> surface;
    207         if (fShowFatBits) {
    208             // scale up so we don't clip rotations
    209             SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2,
    210                                                     kOpaque_SkAlphaType);
    211             surface.reset(make_surface(canvas, info));
    212             canvas = surface->getCanvas();
    213             canvas->drawColor(SK_ColorWHITE);
    214             size.set(info.width(), info.height());
    215         } else {
    216             canvas->translate(SkScalarHalf(fCell.width() - fImage->width()),
    217                               SkScalarHalf(fCell.height() - fImage->height()));
    218         }
    219         this->drawTheImage(canvas, size, filter, dx, dy);
    220 
    221         if (surface) {
    222             SkAutoTUnref<SkImage> orig(surface->newImageSnapshot());
    223             SkAutoTUnref<SkImage> zoomed(zoom_up(orig));
    224             origCanvas->drawImage(zoomed,
    225                                   SkScalarHalf(fCell.width() - zoomed->width()),
    226                                   SkScalarHalf(fCell.height() - zoomed->height()));
    227         }
    228     }
    229 
    230     void drawBorders(SkCanvas* canvas) {
    231         SkPaint p;
    232         p.setStyle(SkPaint::kStroke_Style);
    233         p.setColor(SK_ColorBLUE);
    234 
    235         SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
    236         r.inset(SK_ScalarHalf, SK_ScalarHalf);
    237         canvas->drawRect(r, p);
    238         canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
    239         canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
    240     }
    241 
    242     void onDrawContent(SkCanvas* canvas) override {
    243         fCell.set(this->height() / 2, this->height() / 2);
    244 
    245         SkScalar trans[2];
    246         fTrans.timeToValues(fCurrTime, trans);
    247 
    248         for (int y = 0; y < 2; ++y) {
    249             for (int x = 0; x < 2; ++x) {
    250                 int index = y * 2 + x;
    251                 SkAutoCanvasRestore acr(canvas, true);
    252                 canvas->translate(fCell.width() * x, fCell.height() * y);
    253                 SkRect r = SkRect::MakeWH(fCell.width(), fCell.height());
    254                 r.inset(4, 4);
    255                 canvas->clipRect(r);
    256                 this->drawHere(canvas, SkFilterQuality(index), trans[0], trans[1]);
    257             }
    258         }
    259 
    260         this->drawBorders(canvas);
    261 
    262         const SkScalar textX = fCell.width() * 2 + 30;
    263 
    264         SkPaint paint;
    265         paint.setAntiAlias(true);
    266         paint.setTextSize(36);
    267         SkString str;
    268         str.appendScalar(fScale);
    269         canvas->drawText(str.c_str(), str.size(), textX, 100, paint);
    270         str.reset(); str.appendScalar(fAngle);
    271         canvas->drawText(str.c_str(), str.size(), textX, 150, paint);
    272 
    273         str.reset(); str.appendScalar(trans[0]);
    274         canvas->drawText(str.c_str(), str.size(), textX, 200, paint);
    275         str.reset(); str.appendScalar(trans[1]);
    276         canvas->drawText(str.c_str(), str.size(), textX, 250, paint);
    277     }
    278 
    279     bool onAnimate(const SkAnimTimer& timer) override {
    280         fCurrTime = timer.msec();
    281         return true;
    282     }
    283 
    284     virtual bool handleKey(SkKey key) {
    285         this->inval(NULL);
    286         return true;
    287     }
    288 
    289 private:
    290     typedef SampleView INHERITED;
    291 };
    292 
    293 //////////////////////////////////////////////////////////////////////////////
    294 
    295 static SkView* MyFactory() { return new FilterQualityView; }
    296 static SkViewRegister reg(MyFactory);
    297