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