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