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