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