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