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