xref: /aosp_15_r20/external/skia/tools/viewer/StrokeVerbSlide.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2017 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/SkTypes.h"
9 
10 #if defined(SK_GANESH)
11 
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkFont.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPath.h"
16 #include "src/core/SkGeometry.h"
17 #include "tools/fonts/FontToolUtils.h"
18 #include "tools/viewer/ClickHandlerSlide.h"
19 
20 enum class VerbType {
21     kTriangles,
22     kQuadratics,
23     kCubics,
24     kConics
25 };
26 
verb_type_name(VerbType verbType)27 static const char* verb_type_name(VerbType verbType) {
28     switch (verbType) {
29         case VerbType::kTriangles: return "kTriangles";
30         case VerbType::kQuadratics: return "kQuadratics";
31         case VerbType::kCubics: return "kCubics";
32         case VerbType::kConics: return "kConics";
33     }
34     SkUNREACHABLE;
35 };
36 
37 /**
38  * This sample visualizes simple strokes.
39  */
40 class StrokeVerbSlide : public ClickHandlerSlide {
41 public:
StrokeVerbSlide()42     StrokeVerbSlide() { fName = "StrokeVerb"; }
43 
load(SkScalar w,SkScalar h)44     void load(SkScalar w, SkScalar h) override { this->updatePath(); }
45 
46     void draw(SkCanvas*) override;
47 
48     bool onChar(SkUnichar) override;
49 
50 protected:
51     class Click;
52 
53     ClickHandlerSlide::Click* onFindClickHandler(SkScalar x, SkScalar y,
54                                                  skui::ModifierKey) override;
55     bool onClick(ClickHandlerSlide::Click*) override;
56 
57 
58 private:
updateAndInval()59     void updateAndInval() { this->updatePath(); }
60 
61     void updatePath();
62 
63     VerbType fVerbType = VerbType::kCubics;
64 
65     SkPoint fPoints[4] = {
66             {100.05f, 100.05f}, {400.75f, 100.05f}, {400.75f, 300.95f}, {100.05f, 300.95f}};
67 
68     float fConicWeight = .5;
69     float fStrokeWidth = 40;
70     SkPaint::Join fStrokeJoin = SkPaint::kMiter_Join;
71     SkPaint::Cap fStrokeCap = SkPaint::kButt_Cap;
72 
73     SkPath fPath;
74 };
75 
draw(SkCanvas * canvas)76 void StrokeVerbSlide::draw(SkCanvas* canvas) {
77     canvas->clear(SK_ColorBLACK);
78 
79     SkPaint outlinePaint;
80     outlinePaint.setColor(0xff808080);
81     outlinePaint.setStyle(SkPaint::kStroke_Style);
82     outlinePaint.setStrokeWidth(fStrokeWidth);
83     outlinePaint.setStrokeJoin(fStrokeJoin);
84     outlinePaint.setStrokeCap(fStrokeCap);
85     outlinePaint.setAntiAlias(true);
86     canvas->drawPath(fPath, outlinePaint);
87 
88     SkString caption;
89     caption.appendf("VerbType_%s", verb_type_name(fVerbType));
90     if (VerbType::kCubics == fVerbType) {
91         caption.appendf(" (%s)", SkCubicTypeName(SkClassifyCubic(fPoints)));
92     } else if (VerbType::kConics == fVerbType) {
93         caption.appendf(" (w=%f)", fConicWeight);
94     }
95 
96     caption.appendf(" (stroke_width=%f)", fStrokeWidth);
97 
98     SkPaint pointsPaint;
99     pointsPaint.setColor(SK_ColorBLUE);
100     pointsPaint.setStrokeWidth(8);
101     pointsPaint.setAntiAlias(true);
102 
103     if (VerbType::kCubics == fVerbType) {
104         canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, fPoints, pointsPaint);
105     } else {
106         canvas->drawPoints(SkCanvas::kPoints_PointMode, 2, fPoints, pointsPaint);
107         canvas->drawPoints(SkCanvas::kPoints_PointMode, 1, fPoints + 3, pointsPaint);
108     }
109 
110     SkFont font(ToolUtils::DefaultTypeface(), 20);
111     SkPaint captionPaint;
112     captionPaint.setColor(SK_ColorWHITE);
113     canvas->drawString(caption, 10, 30, font, captionPaint);
114 }
115 
updatePath()116 void StrokeVerbSlide::updatePath() {
117     fPath.reset();
118     fPath.moveTo(fPoints[0]);
119     switch (fVerbType) {
120         case VerbType::kCubics:
121             fPath.cubicTo(fPoints[1], fPoints[2], fPoints[3]);
122             break;
123         case VerbType::kQuadratics:
124             fPath.quadTo(fPoints[1], fPoints[3]);
125             break;
126         case VerbType::kConics:
127             fPath.conicTo(fPoints[1], fPoints[3], fConicWeight);
128             break;
129         case VerbType::kTriangles:
130             fPath.lineTo(fPoints[1]);
131             fPath.lineTo(fPoints[3]);
132             fPath.close();
133             break;
134     }
135 }
136 
137 class StrokeVerbSlide::Click : public ClickHandlerSlide::Click {
138 public:
Click(int ptIdx)139     Click(int ptIdx) : fPtIdx(ptIdx) {}
140 
doClick(SkPoint points[])141     void doClick(SkPoint points[]) {
142         if (fPtIdx >= 0) {
143             points[fPtIdx] += fCurr - fPrev;
144         } else {
145             for (int i = 0; i < 4; ++i) {
146                 points[i] += fCurr - fPrev;
147             }
148         }
149     }
150 
151 private:
152     int fPtIdx;
153 };
154 
onFindClickHandler(SkScalar x,SkScalar y,skui::ModifierKey)155 ClickHandlerSlide::Click* StrokeVerbSlide::onFindClickHandler(SkScalar x, SkScalar y,
156                                                               skui::ModifierKey) {
157     for (int i = 0; i < 4; ++i) {
158         if (VerbType::kCubics != fVerbType && 2 == i) {
159             continue;
160         }
161         if (fabs(x - fPoints[i].x()) < 20 && fabsf(y - fPoints[i].y()) < 20) {
162             return new Click(i);
163         }
164     }
165     return new Click(-1);
166 }
167 
onClick(ClickHandlerSlide::Click * click)168 bool StrokeVerbSlide::onClick(ClickHandlerSlide::Click* click) {
169     Click* myClick = (Click*)click;
170     myClick->doClick(fPoints);
171     this->updateAndInval();
172     return true;
173 }
174 
onChar(SkUnichar unichar)175 bool StrokeVerbSlide::onChar(SkUnichar unichar) {
176         if (unichar >= '1' && unichar <= '4') {
177             fVerbType = VerbType(unichar - '1');
178             this->updateAndInval();
179             return true;
180         }
181         float* valueToScale = nullptr;
182         if (VerbType::kConics == fVerbType) {
183             valueToScale = &fConicWeight;
184         } else {
185             valueToScale = &fStrokeWidth;
186         }
187         if (valueToScale) {
188             if (unichar == '+') {
189                 *valueToScale *= 2;
190                 this->updateAndInval();
191                 return true;
192             }
193             if (unichar == '=') {
194                 *valueToScale *= 5/4.f;
195                 this->updateAndInval();
196                 return true;
197             }
198             if (unichar == '-') {
199                 *valueToScale *= 4/5.f;
200                 this->updateAndInval();
201                 return true;
202             }
203             if (unichar == '_') {
204                 *valueToScale *= .5f;
205                 this->updateAndInval();
206                 return true;
207             }
208         }
209         if (unichar == 'D') {
210             SkDebugf("    SkPoint fPoints[4] = {\n");
211             SkDebugf("        {%ff, %ff},\n", fPoints[0].x(), fPoints[0].y());
212             SkDebugf("        {%ff, %ff},\n", fPoints[1].x(), fPoints[1].y());
213             SkDebugf("        {%ff, %ff},\n", fPoints[2].x(), fPoints[2].y());
214             SkDebugf("        {%ff, %ff}\n", fPoints[3].x(), fPoints[3].y());
215             SkDebugf("    };\n");
216             return true;
217         }
218         if (unichar == 'J') {
219             fStrokeJoin = (SkPaint::Join)((fStrokeJoin + 1) % 3);
220             this->updateAndInval();
221             return true;
222         }
223         if (unichar == 'C') {
224             fStrokeCap = (SkPaint::Cap)((fStrokeCap + 1) % 3);
225             this->updateAndInval();
226             return true;
227         }
228         return false;
229 }
230 
231 DEF_SLIDE(return new StrokeVerbSlide;)
232 
233 #endif  // defined(SK_GANESH)
234