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 "include/core/SkCanvas.h" 9 #include "include/core/SkDrawable.h" 10 #include "include/core/SkFont.h" 11 #include "include/core/SkPath.h" 12 #include "include/core/SkRSXform.h" 13 #include "include/core/SkSamplingOptions.h" 14 #include "include/core/SkString.h" 15 #include "include/core/SkSurface.h" 16 #include "include/effects/SkGradientShader.h" 17 #include "include/utils/SkTextUtils.h" 18 #include "src/base/SkRandom.h" 19 #include "tools/DecodeUtils.h" 20 #include "tools/fonts/FontToolUtils.h" 21 #include "tools/viewer/ClickHandlerSlide.h" 22 23 const SkBlendMode gModes[] = { 24 SkBlendMode::kSrcOver, 25 SkBlendMode::kSrc, 26 SkBlendMode::kSrcIn, 27 SkBlendMode::kSrcOut, 28 SkBlendMode::kSrcATop, 29 SkBlendMode::kDstOver, 30 SkBlendMode::kDstIn, 31 SkBlendMode::kDstOut, 32 SkBlendMode::kDstATop, 33 }; 34 const int N_Modes = std::size(gModes); 35 36 static SkRandom gRand; 37 38 struct ModeButton { 39 SkString fLabel; 40 SkColor fColor; 41 SkRect fRect; 42 43 public: initModeButton44 void init(const char label[], const SkRect& rect) { 45 fLabel = label; 46 fRect = rect; 47 fColor = (gRand.nextU() & 0x7F7F7F7F) | SkColorSetARGB(0xFF, 0, 0, 0x80); 48 } 49 drawModeButton50 void draw(SkCanvas* canvas) { 51 SkPaint paint; 52 paint.setAntiAlias(true); 53 paint.setColor(fColor); 54 canvas->drawRoundRect(fRect, 8, 8, paint); 55 56 paint.setColor(0xFFFFFFFF); 57 SkFont font = ToolUtils::DefaultFont(); 58 font.setSize(16); 59 font.setEdging(SkFont::Edging::kSubpixelAntiAlias); 60 SkTextUtils::DrawString(canvas, fLabel.c_str(), fRect.centerX(), fRect.fTop + 0.68f * fRect.height(), 61 font, paint, SkTextUtils::kCenter_Align); 62 } 63 hitTestModeButton64 bool hitTest(SkScalar x, SkScalar y) { 65 return fRect.intersects({x - 1, y - 1, x + 1, y + 1}); 66 } 67 }; 68 69 class ModeDrawable : public SkDrawable { 70 public: ModeDrawable()71 ModeDrawable() : fMode(SkBlendMode::kSrcOver), fLoc(SkPoint::Make(0, 0)) {} 72 73 SkBlendMode fMode; 74 SkPoint fLoc; 75 hitTest(SkScalar x,SkScalar y)76 bool hitTest(SkScalar x, SkScalar y) { 77 SkRect target = SkRect::MakeXYWH(x - fLoc.x() - 1, y - fLoc.y() - 1, 3, 3); 78 return this->getBounds().intersects(target); 79 } 80 }; 81 82 class CircDrawable : public ModeDrawable { 83 SkPaint fPaint; 84 SkRect fBounds; 85 86 public: CircDrawable(SkScalar size,SkColor c)87 CircDrawable(SkScalar size, SkColor c) { 88 const SkColor colors[] = { 0, c }; 89 fPaint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(size/2, size/2), size/2, 90 colors, nullptr, 2, 91 SkTileMode::kClamp)); 92 fBounds = SkRect::MakeWH(size, size); 93 } 94 95 protected: onGetBounds()96 SkRect onGetBounds() override { 97 return fBounds; 98 } 99 onDraw(SkCanvas * canvas)100 void onDraw(SkCanvas* canvas) override { 101 fPaint.setBlendMode(fMode); 102 canvas->save(); 103 canvas->translate(fLoc.x(), fLoc.y()); 104 canvas->drawOval(fBounds, fPaint); 105 canvas->restore(); 106 } 107 }; 108 109 class XferSlide : public ClickHandlerSlide { 110 public: XferSlide()111 XferSlide() { 112 const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK }; 113 for (int i = 0; i < N; ++i) { 114 fDrs[i].reset(new CircDrawable(200, colors[i])); 115 fDrs[i]->fLoc.set(100.f + i * 100, 100.f + i * 100); 116 fDrs[i]->fMode = SkBlendMode::kSrcOver; 117 } 118 fSelected = nullptr; 119 120 this->addButtons(); 121 fName = "XferDemo"; 122 } 123 draw(SkCanvas * canvas)124 void draw(SkCanvas* canvas) override { 125 for (int i = 0; i < N_Modes; ++i) { 126 fModeButtons[i].draw(canvas); 127 } 128 129 SkPaint paint; 130 if (fSelected) { 131 for (int i = 0; i < N_Modes; ++i) { 132 if (fSelected->fMode == gModes[i]) { 133 canvas->drawRect(fModeRect[i], paint); 134 break; 135 } 136 } 137 } 138 139 canvas->saveLayer(nullptr, nullptr); 140 for (int i = 0; i < N; ++i) { 141 fDrs[i]->draw(canvas); 142 } 143 canvas->restore(); 144 } 145 146 protected: onFindClickHandler(SkScalar x,SkScalar y,skui::ModifierKey)147 Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override { 148 // Check mode buttons first 149 for (int i = 0; i < N_Modes; ++i) { 150 if (fModeButtons[i].hitTest(x, y)) { 151 Click* click = new Click(); 152 click->fMeta.setS32("mode", i); 153 return click; 154 } 155 } 156 fSelected = nullptr; 157 for (int i = N - 1; i >= 0; --i) { 158 if (fDrs[i]->hitTest(x, y)) { 159 fSelected = fDrs[i].get(); 160 break; 161 } 162 } 163 return fSelected ? new Click() : nullptr; 164 } 165 onClick(Click * click)166 bool onClick(Click* click) override { 167 int32_t mode; 168 if (click->fMeta.findS32("mode", &mode)) { 169 if (fSelected && skui::InputState::kUp == click->fState) { 170 fSelected->fMode = gModes[mode]; 171 } 172 } else { 173 fSelected->fLoc.fX += click->fCurr.fX - click->fPrev.fX; 174 fSelected->fLoc.fY += click->fCurr.fY - click->fPrev.fY; 175 } 176 return true; 177 } 178 179 private: 180 enum { 181 N = 4 182 }; 183 184 SkRect fModeRect[N_Modes]; 185 ModeButton fModeButtons[N_Modes]; 186 sk_sp<CircDrawable> fDrs[N]; 187 CircDrawable* fSelected; 188 addButtons()189 void addButtons() { 190 SkScalar x = 10; 191 SkScalar y = 10; 192 for (int i = 0; i < N_Modes; ++i) { 193 fModeButtons[i].init(SkBlendMode_Name(gModes[i]), SkRect::MakeXYWH(x, y, 70, 25)); 194 fModeRect[i] = SkRect::MakeXYWH(x, y + 28, 70, 2); 195 x += 80; 196 } 197 } 198 }; 199 200 DEF_SLIDE( return new XferSlide; ) 201 202 ////////////////////////////////////////////////////////////////////////////// 203 204 #include "tools/Resources.h" 205 206 class CubicResamplerSlide : public ClickHandlerSlide { 207 public: CubicResamplerSlide()208 CubicResamplerSlide() { 209 fName = "CubicResampler"; 210 } 211 212 protected: load(SkScalar,SkScalar)213 void load(SkScalar, SkScalar) override { 214 SkRect r = {10, 10, 200, 200}; 215 for (const char* name : {"images/mandrill_128.png", 216 "images/rle.bmp", 217 "images/example_4.png"}) { 218 fRecs.push_back({ToolUtils::GetResourceAsImage(name), r}); 219 r.offset(0, r.height() + 10); 220 } 221 fDomain.setXYWH(r.fLeft + 3 * r.width() + 40, 50, 200, 200); 222 fCubic = {.3f, .5f}; 223 } 224 draw(SkCanvas * canvas)225 void draw(SkCanvas* canvas) override { 226 for (const auto& rec : fRecs) { 227 rec.draw(canvas, fCubic); 228 } 229 230 SkPaint paint; 231 paint.setAntiAlias(true); 232 paint.setStroke(true); 233 canvas->drawRect(fDomain, paint); 234 235 paint.setColor(SK_ColorRED); 236 paint.setStroke(false); 237 SkPoint loc = SkMatrix::RectToRect({0,0,1,1}, fDomain).mapXY(fCubic.B, fCubic.C); 238 canvas->drawCircle(loc.fX, loc.fY, 8, paint); 239 240 SkString str; 241 str.printf("B=%4.2f C=%4.2f", fCubic.B, fCubic.C); 242 SkFont font = ToolUtils::DefaultFont(); 243 font.setSize(25); 244 font.setEdging(SkFont::Edging::kAntiAlias); 245 paint.setColor(SK_ColorBLACK); 246 canvas->drawSimpleText(str.c_str(), str.size(), SkTextEncoding::kUTF8, 247 fDomain.fLeft + 10, fDomain.fBottom + 40, font, paint); 248 } 249 pin_unitize(float min,float max,float value)250 static float pin_unitize(float min, float max, float value) { 251 return (std::min(std::max(value, min), max) - min) / (max - min); 252 } pin_unitize(const SkRect & r,SkPoint p)253 static SkPoint pin_unitize(const SkRect& r, SkPoint p) { 254 return { 255 pin_unitize(r.fLeft, r.fRight, p.fX), 256 pin_unitize(r.fTop, r.fBottom, p.fY), 257 }; 258 } 259 260 protected: onFindClickHandler(SkScalar x,SkScalar y,skui::ModifierKey)261 Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey) override { 262 if (fDomain.contains(x, y)) { 263 return new Click([this](Click* click) { 264 auto [B, C] = pin_unitize(fDomain, click->fCurr); 265 fCubic = {B, C}; 266 return true; 267 }); 268 } 269 return nullptr; 270 } 271 onClick(ClickHandlerSlide::Click *)272 bool onClick(ClickHandlerSlide::Click *) override { return false; } 273 274 private: 275 struct Rec { 276 sk_sp<SkImage> fImage; 277 SkRect fBounds; 278 drawCubicResamplerSlide::Rec279 void draw(SkCanvas* canvas, SkCubicResampler cubic) const { 280 SkRect r = fBounds; 281 SkPaint paint; 282 283 SkMatrix lm = SkMatrix::Translate(r.x(), r.y()) 284 * SkMatrix::Scale(10, 10); 285 paint.setShader(fImage->makeShader(SkSamplingOptions(), lm)); 286 canvas->drawRect(r, paint); 287 288 r.offset(r.width() + 10, 0); 289 lm.postTranslate(r.width() + 10, 0); 290 291 paint.setShader(fImage->makeShader(SkSamplingOptions(SkFilterMode::kLinear), lm)); 292 canvas->drawRect(r, paint); 293 294 r.offset(r.width() + 10, 0); 295 lm.postTranslate(r.width() + 10, 0); 296 297 paint.setShader(fImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, 298 SkSamplingOptions(cubic), &lm)); 299 canvas->drawRect(r, paint); 300 } 301 }; 302 303 std::vector<Rec> fRecs; 304 SkRect fDomain; 305 SkCubicResampler fCubic; 306 }; 307 308 DEF_SLIDE( return new CubicResamplerSlide; ) 309