• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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