xref: /aosp_15_r20/external/skia/tools/viewer/XferSlide.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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