xref: /aosp_15_r20/external/skia/tools/viewer/QuadStrokerSlide.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2012 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBlendMode.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathMeasure.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathUtils.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/utils/SkTextUtils.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkGeometry.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPathPriv.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkPointPriv.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkStroke.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "tools/viewer/ClickHandlerSlide.h"
37*c8dee2aaSAndroid Build Coastguard Worker 
38*c8dee2aaSAndroid Build Coastguard Worker #include <cfloat>
39*c8dee2aaSAndroid Build Coastguard Worker 
40*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
41*c8dee2aaSAndroid Build Coastguard Worker 
42*c8dee2aaSAndroid Build Coastguard Worker class SkEvent;
43*c8dee2aaSAndroid Build Coastguard Worker 
hittest(const SkPoint & target,SkScalar x,SkScalar y)44*c8dee2aaSAndroid Build Coastguard Worker static bool hittest(const SkPoint& target, SkScalar x, SkScalar y) {
45*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar TOL = 7;
46*c8dee2aaSAndroid Build Coastguard Worker     return SkPoint::Distance(target, SkPoint::Make(x, y)) <= TOL;
47*c8dee2aaSAndroid Build Coastguard Worker }
48*c8dee2aaSAndroid Build Coastguard Worker 
getOnCurvePoints(const SkPath & path,SkPoint storage[])49*c8dee2aaSAndroid Build Coastguard Worker static int getOnCurvePoints(const SkPath& path, SkPoint storage[]) {
50*c8dee2aaSAndroid Build Coastguard Worker     int count = 0;
51*c8dee2aaSAndroid Build Coastguard Worker     for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
52*c8dee2aaSAndroid Build Coastguard Worker         switch (verb) {
53*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kMove:
54*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kLine:
55*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kQuad:
56*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kConic:
57*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kCubic:
58*c8dee2aaSAndroid Build Coastguard Worker                 storage[count++] = pts[0];
59*c8dee2aaSAndroid Build Coastguard Worker                 break;
60*c8dee2aaSAndroid Build Coastguard Worker             default:
61*c8dee2aaSAndroid Build Coastguard Worker                 break;
62*c8dee2aaSAndroid Build Coastguard Worker         }
63*c8dee2aaSAndroid Build Coastguard Worker     }
64*c8dee2aaSAndroid Build Coastguard Worker     return count;
65*c8dee2aaSAndroid Build Coastguard Worker }
66*c8dee2aaSAndroid Build Coastguard Worker 
getContourCounts(const SkPath & path,TArray<int> * contourCounts)67*c8dee2aaSAndroid Build Coastguard Worker static void getContourCounts(const SkPath& path, TArray<int>* contourCounts) {
68*c8dee2aaSAndroid Build Coastguard Worker     int count = 0;
69*c8dee2aaSAndroid Build Coastguard Worker     for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
70*c8dee2aaSAndroid Build Coastguard Worker         switch (verb) {
71*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kMove:
72*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kLine:
73*c8dee2aaSAndroid Build Coastguard Worker                 count += 1;
74*c8dee2aaSAndroid Build Coastguard Worker                 break;
75*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kQuad:
76*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kConic:
77*c8dee2aaSAndroid Build Coastguard Worker                 count += 2;
78*c8dee2aaSAndroid Build Coastguard Worker                 break;
79*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kCubic:
80*c8dee2aaSAndroid Build Coastguard Worker                 count += 3;
81*c8dee2aaSAndroid Build Coastguard Worker                 break;
82*c8dee2aaSAndroid Build Coastguard Worker             case SkPathVerb::kClose:
83*c8dee2aaSAndroid Build Coastguard Worker                 contourCounts->push_back(count);
84*c8dee2aaSAndroid Build Coastguard Worker                 count = 0;
85*c8dee2aaSAndroid Build Coastguard Worker                 break;
86*c8dee2aaSAndroid Build Coastguard Worker             default:
87*c8dee2aaSAndroid Build Coastguard Worker                 break;
88*c8dee2aaSAndroid Build Coastguard Worker         }
89*c8dee2aaSAndroid Build Coastguard Worker     }
90*c8dee2aaSAndroid Build Coastguard Worker     if (count > 0) {
91*c8dee2aaSAndroid Build Coastguard Worker         contourCounts->push_back(count);
92*c8dee2aaSAndroid Build Coastguard Worker     }
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker 
erase(const sk_sp<SkSurface> & surface)95*c8dee2aaSAndroid Build Coastguard Worker static void erase(const sk_sp<SkSurface>& surface) {
96*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = surface->getCanvas();
97*c8dee2aaSAndroid Build Coastguard Worker     if (canvas) {
98*c8dee2aaSAndroid Build Coastguard Worker         canvas->clear(SK_ColorTRANSPARENT);
99*c8dee2aaSAndroid Build Coastguard Worker     }
100*c8dee2aaSAndroid Build Coastguard Worker }
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker struct StrokeTypeButton {
103*c8dee2aaSAndroid Build Coastguard Worker     SkRect fBounds;
104*c8dee2aaSAndroid Build Coastguard Worker     char fLabel;
105*c8dee2aaSAndroid Build Coastguard Worker     bool fEnabled;
106*c8dee2aaSAndroid Build Coastguard Worker };
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker struct CircleTypeButton : public StrokeTypeButton {
109*c8dee2aaSAndroid Build Coastguard Worker     bool fFill;
110*c8dee2aaSAndroid Build Coastguard Worker };
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker class QuadStrokerSlide : public ClickHandlerSlide {
113*c8dee2aaSAndroid Build Coastguard Worker     enum {
114*c8dee2aaSAndroid Build Coastguard Worker         SKELETON_COLOR = 0xFF0000FF,
115*c8dee2aaSAndroid Build Coastguard Worker         WIREFRAME_COLOR = 0x80FF0000
116*c8dee2aaSAndroid Build Coastguard Worker     };
117*c8dee2aaSAndroid Build Coastguard Worker 
118*c8dee2aaSAndroid Build Coastguard Worker     enum {
119*c8dee2aaSAndroid Build Coastguard Worker         kCount = 18
120*c8dee2aaSAndroid Build Coastguard Worker     };
121*c8dee2aaSAndroid Build Coastguard Worker     SkPoint fPts[kCount];
122*c8dee2aaSAndroid Build Coastguard Worker     SkRect fWeightControl;
123*c8dee2aaSAndroid Build Coastguard Worker     SkRect fRadiusControl;
124*c8dee2aaSAndroid Build Coastguard Worker     SkRect fErrorControl;
125*c8dee2aaSAndroid Build Coastguard Worker     SkRect fWidthControl;
126*c8dee2aaSAndroid Build Coastguard Worker     SkRect fBounds;
127*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix fMatrix, fInverse;
128*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkShader> fShader;
129*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkSurface> fMinSurface;
130*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkSurface> fMaxSurface;
131*c8dee2aaSAndroid Build Coastguard Worker     StrokeTypeButton fCubicButton;
132*c8dee2aaSAndroid Build Coastguard Worker     StrokeTypeButton fConicButton;
133*c8dee2aaSAndroid Build Coastguard Worker     StrokeTypeButton fQuadButton;
134*c8dee2aaSAndroid Build Coastguard Worker     StrokeTypeButton fArcButton;
135*c8dee2aaSAndroid Build Coastguard Worker     StrokeTypeButton fRRectButton;
136*c8dee2aaSAndroid Build Coastguard Worker     CircleTypeButton fCircleButton;
137*c8dee2aaSAndroid Build Coastguard Worker     StrokeTypeButton fTextButton;
138*c8dee2aaSAndroid Build Coastguard Worker     SkString fText;
139*c8dee2aaSAndroid Build Coastguard Worker     SkScalar fTextSize;
140*c8dee2aaSAndroid Build Coastguard Worker     SkScalar fWeight;
141*c8dee2aaSAndroid Build Coastguard Worker     SkScalar fRadius;
142*c8dee2aaSAndroid Build Coastguard Worker     SkScalar fWidth, fDWidth;
143*c8dee2aaSAndroid Build Coastguard Worker     SkScalar fWidthScale;
144*c8dee2aaSAndroid Build Coastguard Worker     int fW, fH, fZoom;
145*c8dee2aaSAndroid Build Coastguard Worker     bool fAnimate;
146*c8dee2aaSAndroid Build Coastguard Worker     bool fDrawRibs;
147*c8dee2aaSAndroid Build Coastguard Worker     bool fDrawTangents;
148*c8dee2aaSAndroid Build Coastguard Worker     bool fDrawTDivs;
149*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
150*c8dee2aaSAndroid Build Coastguard Worker     #define kStrokerErrorMin 0.001f
151*c8dee2aaSAndroid Build Coastguard Worker     #define kStrokerErrorMax 5
152*c8dee2aaSAndroid Build Coastguard Worker #endif
153*c8dee2aaSAndroid Build Coastguard Worker     #define kWidthMin 1
154*c8dee2aaSAndroid Build Coastguard Worker     #define kWidthMax 100
155*c8dee2aaSAndroid Build Coastguard Worker public:
QuadStrokerSlide()156*c8dee2aaSAndroid Build Coastguard Worker     QuadStrokerSlide() {
157*c8dee2aaSAndroid Build Coastguard Worker         fPts[0].set(50, 200);  // cubic
158*c8dee2aaSAndroid Build Coastguard Worker         fPts[1].set(50, 100);
159*c8dee2aaSAndroid Build Coastguard Worker         fPts[2].set(150, 50);
160*c8dee2aaSAndroid Build Coastguard Worker         fPts[3].set(300, 50);
161*c8dee2aaSAndroid Build Coastguard Worker 
162*c8dee2aaSAndroid Build Coastguard Worker         fPts[4].set(350, 200);  // conic
163*c8dee2aaSAndroid Build Coastguard Worker         fPts[5].set(350, 100);
164*c8dee2aaSAndroid Build Coastguard Worker         fPts[6].set(450, 50);
165*c8dee2aaSAndroid Build Coastguard Worker 
166*c8dee2aaSAndroid Build Coastguard Worker         fPts[7].set(150, 300);  // quad
167*c8dee2aaSAndroid Build Coastguard Worker         fPts[8].set(150, 200);
168*c8dee2aaSAndroid Build Coastguard Worker         fPts[9].set(250, 150);
169*c8dee2aaSAndroid Build Coastguard Worker 
170*c8dee2aaSAndroid Build Coastguard Worker         fPts[10].set(250, 200);  // arc
171*c8dee2aaSAndroid Build Coastguard Worker         fPts[11].set(250, 300);
172*c8dee2aaSAndroid Build Coastguard Worker         fPts[12].set(150, 350);
173*c8dee2aaSAndroid Build Coastguard Worker 
174*c8dee2aaSAndroid Build Coastguard Worker         fPts[13].set(200, 200); // rrect
175*c8dee2aaSAndroid Build Coastguard Worker         fPts[14].set(400, 400);
176*c8dee2aaSAndroid Build Coastguard Worker 
177*c8dee2aaSAndroid Build Coastguard Worker         fPts[15].set(250, 250);  // oval
178*c8dee2aaSAndroid Build Coastguard Worker         fPts[16].set(450, 450);
179*c8dee2aaSAndroid Build Coastguard Worker 
180*c8dee2aaSAndroid Build Coastguard Worker         fText = "a";
181*c8dee2aaSAndroid Build Coastguard Worker         fTextSize = 12;
182*c8dee2aaSAndroid Build Coastguard Worker         fWidth = 50;
183*c8dee2aaSAndroid Build Coastguard Worker         fDWidth = 0.25f;
184*c8dee2aaSAndroid Build Coastguard Worker         fWeight = 1;
185*c8dee2aaSAndroid Build Coastguard Worker         fRadius = 150;
186*c8dee2aaSAndroid Build Coastguard Worker 
187*c8dee2aaSAndroid Build Coastguard Worker         fCubicButton.fLabel = 'C';
188*c8dee2aaSAndroid Build Coastguard Worker         fCubicButton.fEnabled = false;
189*c8dee2aaSAndroid Build Coastguard Worker         fConicButton.fLabel = 'K';
190*c8dee2aaSAndroid Build Coastguard Worker         fConicButton.fEnabled = false;
191*c8dee2aaSAndroid Build Coastguard Worker         fQuadButton.fLabel = 'Q';
192*c8dee2aaSAndroid Build Coastguard Worker         fQuadButton.fEnabled = false;
193*c8dee2aaSAndroid Build Coastguard Worker         fArcButton.fLabel = 'A';
194*c8dee2aaSAndroid Build Coastguard Worker         fArcButton.fEnabled = true;
195*c8dee2aaSAndroid Build Coastguard Worker         fRRectButton.fLabel = 'R';
196*c8dee2aaSAndroid Build Coastguard Worker         fRRectButton.fEnabled = false;
197*c8dee2aaSAndroid Build Coastguard Worker         fCircleButton.fLabel = 'O';
198*c8dee2aaSAndroid Build Coastguard Worker         fCircleButton.fEnabled = true;
199*c8dee2aaSAndroid Build Coastguard Worker         fCircleButton.fFill = true;
200*c8dee2aaSAndroid Build Coastguard Worker         fTextButton.fLabel = 'T';
201*c8dee2aaSAndroid Build Coastguard Worker         fTextButton.fEnabled = false;
202*c8dee2aaSAndroid Build Coastguard Worker         fAnimate = false;
203*c8dee2aaSAndroid Build Coastguard Worker         setAsNeeded();
204*c8dee2aaSAndroid Build Coastguard Worker         fName = "QuadStroker";
205*c8dee2aaSAndroid Build Coastguard Worker     }
206*c8dee2aaSAndroid Build Coastguard Worker 
onChar(SkUnichar uni)207*c8dee2aaSAndroid Build Coastguard Worker     bool onChar(SkUnichar uni) override {
208*c8dee2aaSAndroid Build Coastguard Worker         if (fTextButton.fEnabled) {
209*c8dee2aaSAndroid Build Coastguard Worker             switch (uni) {
210*c8dee2aaSAndroid Build Coastguard Worker                 case ' ':
211*c8dee2aaSAndroid Build Coastguard Worker                     fText = "";
212*c8dee2aaSAndroid Build Coastguard Worker                     break;
213*c8dee2aaSAndroid Build Coastguard Worker                 case '-':
214*c8dee2aaSAndroid Build Coastguard Worker                     fTextSize = std::max(1.0f, fTextSize - 1);
215*c8dee2aaSAndroid Build Coastguard Worker                     break;
216*c8dee2aaSAndroid Build Coastguard Worker                 case '+':
217*c8dee2aaSAndroid Build Coastguard Worker                 case '=':
218*c8dee2aaSAndroid Build Coastguard Worker                     fTextSize += 1;
219*c8dee2aaSAndroid Build Coastguard Worker                     break;
220*c8dee2aaSAndroid Build Coastguard Worker                 default:
221*c8dee2aaSAndroid Build Coastguard Worker                     fText.appendUnichar(uni);
222*c8dee2aaSAndroid Build Coastguard Worker             }
223*c8dee2aaSAndroid Build Coastguard Worker             return true;
224*c8dee2aaSAndroid Build Coastguard Worker         }
225*c8dee2aaSAndroid Build Coastguard Worker         return false;
226*c8dee2aaSAndroid Build Coastguard Worker     }
227*c8dee2aaSAndroid Build Coastguard Worker 
load(SkScalar w,SkScalar h)228*c8dee2aaSAndroid Build Coastguard Worker     void load(SkScalar w, SkScalar h) override { this->layout(w, h); }
229*c8dee2aaSAndroid Build Coastguard Worker 
resize(SkScalar w,SkScalar h)230*c8dee2aaSAndroid Build Coastguard Worker     void resize(SkScalar w, SkScalar h) override { this->layout(w, h); }
231*c8dee2aaSAndroid Build Coastguard Worker 
draw(SkCanvas * canvas)232*c8dee2aaSAndroid Build Coastguard Worker     void draw(SkCanvas* canvas) override {
233*c8dee2aaSAndroid Build Coastguard Worker         canvas->clear(SK_ColorLTGRAY);
234*c8dee2aaSAndroid Build Coastguard Worker 
235*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
236*c8dee2aaSAndroid Build Coastguard Worker         SkScalar width = fWidth;
237*c8dee2aaSAndroid Build Coastguard Worker 
238*c8dee2aaSAndroid Build Coastguard Worker         if (fCubicButton.fEnabled) {
239*c8dee2aaSAndroid Build Coastguard Worker             path.moveTo(fPts[0]);
240*c8dee2aaSAndroid Build Coastguard Worker             path.cubicTo(fPts[1], fPts[2], fPts[3]);
241*c8dee2aaSAndroid Build Coastguard Worker             setForSingles();
242*c8dee2aaSAndroid Build Coastguard Worker             draw_stroke(canvas, path, width, 950, false);
243*c8dee2aaSAndroid Build Coastguard Worker         }
244*c8dee2aaSAndroid Build Coastguard Worker 
245*c8dee2aaSAndroid Build Coastguard Worker         if (fConicButton.fEnabled) {
246*c8dee2aaSAndroid Build Coastguard Worker             path.reset();
247*c8dee2aaSAndroid Build Coastguard Worker             path.moveTo(fPts[4]);
248*c8dee2aaSAndroid Build Coastguard Worker             path.conicTo(fPts[5], fPts[6], fWeight);
249*c8dee2aaSAndroid Build Coastguard Worker             setForSingles();
250*c8dee2aaSAndroid Build Coastguard Worker             draw_stroke(canvas, path, width, 950, false);
251*c8dee2aaSAndroid Build Coastguard Worker         }
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker         if (fQuadButton.fEnabled) {
254*c8dee2aaSAndroid Build Coastguard Worker             path.reset();
255*c8dee2aaSAndroid Build Coastguard Worker             path.moveTo(fPts[7]);
256*c8dee2aaSAndroid Build Coastguard Worker             path.quadTo(fPts[8], fPts[9]);
257*c8dee2aaSAndroid Build Coastguard Worker             setForSingles();
258*c8dee2aaSAndroid Build Coastguard Worker             draw_stroke(canvas, path, width, 950, false);
259*c8dee2aaSAndroid Build Coastguard Worker         }
260*c8dee2aaSAndroid Build Coastguard Worker 
261*c8dee2aaSAndroid Build Coastguard Worker         if (fArcButton.fEnabled) {
262*c8dee2aaSAndroid Build Coastguard Worker             path.reset();
263*c8dee2aaSAndroid Build Coastguard Worker             path.moveTo(fPts[10]);
264*c8dee2aaSAndroid Build Coastguard Worker             path.arcTo(fPts[11], fPts[12], fRadius);
265*c8dee2aaSAndroid Build Coastguard Worker             setForGeometry();
266*c8dee2aaSAndroid Build Coastguard Worker             draw_stroke(canvas, path, width, 950, false);
267*c8dee2aaSAndroid Build Coastguard Worker             SkPath pathPts;
268*c8dee2aaSAndroid Build Coastguard Worker             pathPts.moveTo(fPts[10]);
269*c8dee2aaSAndroid Build Coastguard Worker             pathPts.lineTo(fPts[11]);
270*c8dee2aaSAndroid Build Coastguard Worker             pathPts.lineTo(fPts[12]);
271*c8dee2aaSAndroid Build Coastguard Worker             draw_points(canvas, pathPts, SK_ColorDKGRAY, true);
272*c8dee2aaSAndroid Build Coastguard Worker         }
273*c8dee2aaSAndroid Build Coastguard Worker 
274*c8dee2aaSAndroid Build Coastguard Worker         if (fRRectButton.fEnabled) {
275*c8dee2aaSAndroid Build Coastguard Worker             SkScalar rad = 32;
276*c8dee2aaSAndroid Build Coastguard Worker             SkRect r;
277*c8dee2aaSAndroid Build Coastguard Worker             r.setBounds(&fPts[13], 2);
278*c8dee2aaSAndroid Build Coastguard Worker             path.reset();
279*c8dee2aaSAndroid Build Coastguard Worker             SkRRect rr;
280*c8dee2aaSAndroid Build Coastguard Worker             rr.setRectXY(r, rad, rad);
281*c8dee2aaSAndroid Build Coastguard Worker             path.addRRect(rr);
282*c8dee2aaSAndroid Build Coastguard Worker             setForGeometry();
283*c8dee2aaSAndroid Build Coastguard Worker             draw_stroke(canvas, path, width, 950, false);
284*c8dee2aaSAndroid Build Coastguard Worker 
285*c8dee2aaSAndroid Build Coastguard Worker             path.reset();
286*c8dee2aaSAndroid Build Coastguard Worker             SkRRect rr2;
287*c8dee2aaSAndroid Build Coastguard Worker             rr.inset(width/2, width/2, &rr2);
288*c8dee2aaSAndroid Build Coastguard Worker             path.addRRect(rr2, SkPathDirection::kCCW);
289*c8dee2aaSAndroid Build Coastguard Worker             rr.inset(-width/2, -width/2, &rr2);
290*c8dee2aaSAndroid Build Coastguard Worker             path.addRRect(rr2, SkPathDirection::kCW);
291*c8dee2aaSAndroid Build Coastguard Worker             SkPaint paint;
292*c8dee2aaSAndroid Build Coastguard Worker             paint.setAntiAlias(true);
293*c8dee2aaSAndroid Build Coastguard Worker             paint.setColor(0x40FF8844);
294*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawPath(path, paint);
295*c8dee2aaSAndroid Build Coastguard Worker         }
296*c8dee2aaSAndroid Build Coastguard Worker 
297*c8dee2aaSAndroid Build Coastguard Worker         if (fCircleButton.fEnabled) {
298*c8dee2aaSAndroid Build Coastguard Worker             path.reset();
299*c8dee2aaSAndroid Build Coastguard Worker             SkRect r;
300*c8dee2aaSAndroid Build Coastguard Worker             r.setBounds(&fPts[15], 2);
301*c8dee2aaSAndroid Build Coastguard Worker             path.addOval(r);
302*c8dee2aaSAndroid Build Coastguard Worker             setForGeometry();
303*c8dee2aaSAndroid Build Coastguard Worker             if (fCircleButton.fFill) {
304*c8dee2aaSAndroid Build Coastguard Worker                 if (fArcButton.fEnabled) {
305*c8dee2aaSAndroid Build Coastguard Worker                     SkPoint center;
306*c8dee2aaSAndroid Build Coastguard Worker                     if (arcCenter(&center)) {
307*c8dee2aaSAndroid Build Coastguard Worker                         r.setLTRB(center.fX - fRadius, center.fY - fRadius,
308*c8dee2aaSAndroid Build Coastguard Worker                                   center.fX + fRadius, center.fY + fRadius);
309*c8dee2aaSAndroid Build Coastguard Worker                     }
310*c8dee2aaSAndroid Build Coastguard Worker                 }
311*c8dee2aaSAndroid Build Coastguard Worker                 draw_fill(canvas, r, width);
312*c8dee2aaSAndroid Build Coastguard Worker             } else {
313*c8dee2aaSAndroid Build Coastguard Worker                 draw_stroke(canvas, path, width, 950, false);
314*c8dee2aaSAndroid Build Coastguard Worker             }
315*c8dee2aaSAndroid Build Coastguard Worker         }
316*c8dee2aaSAndroid Build Coastguard Worker 
317*c8dee2aaSAndroid Build Coastguard Worker         if (fTextButton.fEnabled) {
318*c8dee2aaSAndroid Build Coastguard Worker             path.reset();
319*c8dee2aaSAndroid Build Coastguard Worker             SkFont font = ToolUtils::DefaultFont();
320*c8dee2aaSAndroid Build Coastguard Worker             font.setSize(fTextSize);
321*c8dee2aaSAndroid Build Coastguard Worker             SkTextUtils::GetPath(fText.c_str(), fText.size(), SkTextEncoding::kUTF8,
322*c8dee2aaSAndroid Build Coastguard Worker                                  0, fTextSize, font, &path);
323*c8dee2aaSAndroid Build Coastguard Worker             setForText();
324*c8dee2aaSAndroid Build Coastguard Worker             draw_stroke(canvas, path, width * fWidthScale / fTextSize, fTextSize, true);
325*c8dee2aaSAndroid Build Coastguard Worker         }
326*c8dee2aaSAndroid Build Coastguard Worker 
327*c8dee2aaSAndroid Build Coastguard Worker         if (fAnimate) {
328*c8dee2aaSAndroid Build Coastguard Worker             fWidth += fDWidth;
329*c8dee2aaSAndroid Build Coastguard Worker             if (fDWidth > 0 && fWidth > kWidthMax) {
330*c8dee2aaSAndroid Build Coastguard Worker                 fDWidth = -fDWidth;
331*c8dee2aaSAndroid Build Coastguard Worker             } else if (fDWidth < 0 && fWidth < kWidthMin) {
332*c8dee2aaSAndroid Build Coastguard Worker                 fDWidth = -fDWidth;
333*c8dee2aaSAndroid Build Coastguard Worker             }
334*c8dee2aaSAndroid Build Coastguard Worker         }
335*c8dee2aaSAndroid Build Coastguard Worker         setAsNeeded();
336*c8dee2aaSAndroid Build Coastguard Worker         if (fConicButton.fEnabled) {
337*c8dee2aaSAndroid Build Coastguard Worker             draw_control(canvas, fWeightControl, fWeight, 0, 5, "weight");
338*c8dee2aaSAndroid Build Coastguard Worker         }
339*c8dee2aaSAndroid Build Coastguard Worker         if (fArcButton.fEnabled) {
340*c8dee2aaSAndroid Build Coastguard Worker             draw_control(canvas, fRadiusControl, fRadius, 0, 500, "radius");
341*c8dee2aaSAndroid Build Coastguard Worker         }
342*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
343*c8dee2aaSAndroid Build Coastguard Worker         draw_control(canvas, fErrorControl, gDebugStrokerError, kStrokerErrorMin, kStrokerErrorMax,
344*c8dee2aaSAndroid Build Coastguard Worker                      "error");
345*c8dee2aaSAndroid Build Coastguard Worker #endif
346*c8dee2aaSAndroid Build Coastguard Worker         draw_control(canvas, fWidthControl, fWidth * fWidthScale, kWidthMin * fWidthScale,
347*c8dee2aaSAndroid Build Coastguard Worker                      kWidthMax * fWidthScale, "width");
348*c8dee2aaSAndroid Build Coastguard Worker         draw_button(canvas, fQuadButton);
349*c8dee2aaSAndroid Build Coastguard Worker         draw_button(canvas, fCubicButton);
350*c8dee2aaSAndroid Build Coastguard Worker         draw_button(canvas, fConicButton);
351*c8dee2aaSAndroid Build Coastguard Worker         draw_button(canvas, fArcButton);
352*c8dee2aaSAndroid Build Coastguard Worker         draw_button(canvas, fRRectButton);
353*c8dee2aaSAndroid Build Coastguard Worker         draw_button(canvas, fCircleButton);
354*c8dee2aaSAndroid Build Coastguard Worker         draw_button(canvas, fTextButton);
355*c8dee2aaSAndroid Build Coastguard Worker     }
356*c8dee2aaSAndroid Build Coastguard Worker protected:
357*c8dee2aaSAndroid Build Coastguard Worker     class MyClick : public Click {
358*c8dee2aaSAndroid Build Coastguard Worker     public:
359*c8dee2aaSAndroid Build Coastguard Worker         int fIndex;
MyClick(int index)360*c8dee2aaSAndroid Build Coastguard Worker         MyClick(int index) : fIndex(index) {}
361*c8dee2aaSAndroid Build Coastguard Worker     };
362*c8dee2aaSAndroid Build Coastguard Worker 
onFindClickHandler(SkScalar x,SkScalar y,skui::ModifierKey modi)363*c8dee2aaSAndroid Build Coastguard Worker     Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
364*c8dee2aaSAndroid Build Coastguard Worker         for (size_t i = 0; i < std::size(fPts); ++i) {
365*c8dee2aaSAndroid Build Coastguard Worker             if (hittest(fPts[i], x, y)) {
366*c8dee2aaSAndroid Build Coastguard Worker                 return new MyClick((int)i);
367*c8dee2aaSAndroid Build Coastguard Worker             }
368*c8dee2aaSAndroid Build Coastguard Worker         }
369*c8dee2aaSAndroid Build Coastguard Worker         const SkRect& rectPt = SkRect::MakeXYWH(x, y, 1, 1);
370*c8dee2aaSAndroid Build Coastguard Worker         if (fWeightControl.contains(rectPt)) {
371*c8dee2aaSAndroid Build Coastguard Worker             return new MyClick((int) std::size(fPts) + 1);
372*c8dee2aaSAndroid Build Coastguard Worker         }
373*c8dee2aaSAndroid Build Coastguard Worker         if (fRadiusControl.contains(rectPt)) {
374*c8dee2aaSAndroid Build Coastguard Worker             return new MyClick((int) std::size(fPts) + 2);
375*c8dee2aaSAndroid Build Coastguard Worker         }
376*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
377*c8dee2aaSAndroid Build Coastguard Worker         if (fErrorControl.contains(rectPt)) {
378*c8dee2aaSAndroid Build Coastguard Worker             return new MyClick((int) std::size(fPts) + 3);
379*c8dee2aaSAndroid Build Coastguard Worker         }
380*c8dee2aaSAndroid Build Coastguard Worker #endif
381*c8dee2aaSAndroid Build Coastguard Worker         if (fWidthControl.contains(rectPt)) {
382*c8dee2aaSAndroid Build Coastguard Worker             return new MyClick((int) std::size(fPts) + 4);
383*c8dee2aaSAndroid Build Coastguard Worker         }
384*c8dee2aaSAndroid Build Coastguard Worker         if (fCubicButton.fBounds.contains(rectPt)) {
385*c8dee2aaSAndroid Build Coastguard Worker             fCubicButton.fEnabled ^= true;
386*c8dee2aaSAndroid Build Coastguard Worker             return new MyClick((int) std::size(fPts) + 5);
387*c8dee2aaSAndroid Build Coastguard Worker         }
388*c8dee2aaSAndroid Build Coastguard Worker         if (fConicButton.fBounds.contains(rectPt)) {
389*c8dee2aaSAndroid Build Coastguard Worker             fConicButton.fEnabled ^= true;
390*c8dee2aaSAndroid Build Coastguard Worker             return new MyClick((int) std::size(fPts) + 6);
391*c8dee2aaSAndroid Build Coastguard Worker         }
392*c8dee2aaSAndroid Build Coastguard Worker         if (fQuadButton.fBounds.contains(rectPt)) {
393*c8dee2aaSAndroid Build Coastguard Worker             fQuadButton.fEnabled ^= true;
394*c8dee2aaSAndroid Build Coastguard Worker             return new MyClick((int) std::size(fPts) + 7);
395*c8dee2aaSAndroid Build Coastguard Worker         }
396*c8dee2aaSAndroid Build Coastguard Worker         if (fArcButton.fBounds.contains(rectPt)) {
397*c8dee2aaSAndroid Build Coastguard Worker             fArcButton.fEnabled ^= true;
398*c8dee2aaSAndroid Build Coastguard Worker             return new MyClick((int) std::size(fPts) + 8);
399*c8dee2aaSAndroid Build Coastguard Worker         }
400*c8dee2aaSAndroid Build Coastguard Worker         if (fRRectButton.fBounds.contains(rectPt)) {
401*c8dee2aaSAndroid Build Coastguard Worker             fRRectButton.fEnabled ^= true;
402*c8dee2aaSAndroid Build Coastguard Worker             return new MyClick((int) std::size(fPts) + 9);
403*c8dee2aaSAndroid Build Coastguard Worker         }
404*c8dee2aaSAndroid Build Coastguard Worker         if (fCircleButton.fBounds.contains(rectPt)) {
405*c8dee2aaSAndroid Build Coastguard Worker             bool wasEnabled = fCircleButton.fEnabled;
406*c8dee2aaSAndroid Build Coastguard Worker             fCircleButton.fEnabled = !fCircleButton.fFill;
407*c8dee2aaSAndroid Build Coastguard Worker             fCircleButton.fFill = wasEnabled && !fCircleButton.fFill;
408*c8dee2aaSAndroid Build Coastguard Worker             return new MyClick((int) std::size(fPts) + 10);
409*c8dee2aaSAndroid Build Coastguard Worker         }
410*c8dee2aaSAndroid Build Coastguard Worker         if (fTextButton.fBounds.contains(rectPt)) {
411*c8dee2aaSAndroid Build Coastguard Worker             fTextButton.fEnabled ^= true;
412*c8dee2aaSAndroid Build Coastguard Worker             return new MyClick((int) std::size(fPts) + 11);
413*c8dee2aaSAndroid Build Coastguard Worker         }
414*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
415*c8dee2aaSAndroid Build Coastguard Worker     }
416*c8dee2aaSAndroid Build Coastguard Worker 
onClick(Click * click)417*c8dee2aaSAndroid Build Coastguard Worker     bool onClick(Click* click) override {
418*c8dee2aaSAndroid Build Coastguard Worker         int index = ((MyClick*)click)->fIndex;
419*c8dee2aaSAndroid Build Coastguard Worker         if (index < (int) std::size(fPts)) {
420*c8dee2aaSAndroid Build Coastguard Worker             fPts[index].offset(click->fCurr.fX - click->fPrev.fX,
421*c8dee2aaSAndroid Build Coastguard Worker                                click->fCurr.fY - click->fPrev.fY);
422*c8dee2aaSAndroid Build Coastguard Worker         } else if (index == (int) std::size(fPts) + 1) {
423*c8dee2aaSAndroid Build Coastguard Worker             fWeight = MapScreenYtoValue(click->fCurr.fY, fWeightControl, 0, 5);
424*c8dee2aaSAndroid Build Coastguard Worker         } else if (index == (int) std::size(fPts) + 2) {
425*c8dee2aaSAndroid Build Coastguard Worker             fRadius = MapScreenYtoValue(click->fCurr.fY, fRadiusControl, 0, 500);
426*c8dee2aaSAndroid Build Coastguard Worker         }
427*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
428*c8dee2aaSAndroid Build Coastguard Worker         else if (index == (int) std::size(fPts) + 3) {
429*c8dee2aaSAndroid Build Coastguard Worker             gDebugStrokerError = std::max(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY,
430*c8dee2aaSAndroid Build Coastguard Worker                                                                          fErrorControl, kStrokerErrorMin, kStrokerErrorMax));
431*c8dee2aaSAndroid Build Coastguard Worker             gDebugStrokerErrorSet = true;
432*c8dee2aaSAndroid Build Coastguard Worker         }
433*c8dee2aaSAndroid Build Coastguard Worker #endif
434*c8dee2aaSAndroid Build Coastguard Worker         else if (index == (int) std::size(fPts) + 4) {
435*c8dee2aaSAndroid Build Coastguard Worker             fWidth = std::max(FLT_EPSILON, MapScreenYtoValue(click->fCurr.fY, fWidthControl,
436*c8dee2aaSAndroid Build Coastguard Worker                                                              kWidthMin, kWidthMax));
437*c8dee2aaSAndroid Build Coastguard Worker             fAnimate = fWidth <= kWidthMin;
438*c8dee2aaSAndroid Build Coastguard Worker         }
439*c8dee2aaSAndroid Build Coastguard Worker         return true;
440*c8dee2aaSAndroid Build Coastguard Worker     }
441*c8dee2aaSAndroid Build Coastguard Worker 
442*c8dee2aaSAndroid Build Coastguard Worker private:
layout(SkScalar w,SkScalar h)443*c8dee2aaSAndroid Build Coastguard Worker     void layout(SkScalar w, SkScalar h) {
444*c8dee2aaSAndroid Build Coastguard Worker         fRadiusControl.setXYWH(w - 200, 30, 30, 400);
445*c8dee2aaSAndroid Build Coastguard Worker         fWeightControl.setXYWH(w - 150, 30, 30, 400);
446*c8dee2aaSAndroid Build Coastguard Worker         fErrorControl.setXYWH(w - 100, 30, 30, 400);
447*c8dee2aaSAndroid Build Coastguard Worker         fWidthControl.setXYWH(w -  50, 30, 30, 400);
448*c8dee2aaSAndroid Build Coastguard Worker         int buttonOffset = 450;
449*c8dee2aaSAndroid Build Coastguard Worker         fCubicButton.fBounds.setXYWH(w - 50, SkIntToScalar(buttonOffset), 30, 30);
450*c8dee2aaSAndroid Build Coastguard Worker         buttonOffset += 50;
451*c8dee2aaSAndroid Build Coastguard Worker         fConicButton.fBounds.setXYWH(w - 50, SkIntToScalar(buttonOffset), 30, 30);
452*c8dee2aaSAndroid Build Coastguard Worker         buttonOffset += 50;
453*c8dee2aaSAndroid Build Coastguard Worker         fQuadButton.fBounds.setXYWH(w - 50, SkIntToScalar(buttonOffset), 30, 30);
454*c8dee2aaSAndroid Build Coastguard Worker         buttonOffset += 50;
455*c8dee2aaSAndroid Build Coastguard Worker         fArcButton.fBounds.setXYWH(w - 50, SkIntToScalar(buttonOffset), 30, 30);
456*c8dee2aaSAndroid Build Coastguard Worker         buttonOffset += 50;
457*c8dee2aaSAndroid Build Coastguard Worker         fRRectButton.fBounds.setXYWH(w - 50, SkIntToScalar(buttonOffset), 30, 30);
458*c8dee2aaSAndroid Build Coastguard Worker         buttonOffset += 50;
459*c8dee2aaSAndroid Build Coastguard Worker         fCircleButton.fBounds.setXYWH(w - 50, SkIntToScalar(buttonOffset), 30, 30);
460*c8dee2aaSAndroid Build Coastguard Worker         buttonOffset += 50;
461*c8dee2aaSAndroid Build Coastguard Worker         fTextButton.fBounds.setXYWH(w - 50, SkIntToScalar(buttonOffset), 30, 30);
462*c8dee2aaSAndroid Build Coastguard Worker     }
463*c8dee2aaSAndroid Build Coastguard Worker 
copyMinToMax()464*c8dee2aaSAndroid Build Coastguard Worker     void copyMinToMax() {
465*c8dee2aaSAndroid Build Coastguard Worker         erase(fMaxSurface);
466*c8dee2aaSAndroid Build Coastguard Worker         SkCanvas* canvas = fMaxSurface->getCanvas();
467*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
468*c8dee2aaSAndroid Build Coastguard Worker         canvas->concat(fMatrix);
469*c8dee2aaSAndroid Build Coastguard Worker         fMinSurface->draw(canvas, 0, 0);
470*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
471*c8dee2aaSAndroid Build Coastguard Worker 
472*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
473*c8dee2aaSAndroid Build Coastguard Worker         paint.setBlendMode(SkBlendMode::kClear);
474*c8dee2aaSAndroid Build Coastguard Worker         for (int iy = 1; iy < fH; ++iy) {
475*c8dee2aaSAndroid Build Coastguard Worker             SkScalar y = SkIntToScalar(iy * fZoom);
476*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint);
477*c8dee2aaSAndroid Build Coastguard Worker         }
478*c8dee2aaSAndroid Build Coastguard Worker         for (int ix = 1; ix < fW; ++ix) {
479*c8dee2aaSAndroid Build Coastguard Worker             SkScalar x = SkIntToScalar(ix * fZoom);
480*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint);
481*c8dee2aaSAndroid Build Coastguard Worker         }
482*c8dee2aaSAndroid Build Coastguard Worker     }
483*c8dee2aaSAndroid Build Coastguard Worker 
setWHZ(int width,int height,int zoom)484*c8dee2aaSAndroid Build Coastguard Worker     void setWHZ(int width, int height, int zoom) {
485*c8dee2aaSAndroid Build Coastguard Worker         fZoom = zoom;
486*c8dee2aaSAndroid Build Coastguard Worker         fBounds.setIWH(width * zoom, height * zoom);
487*c8dee2aaSAndroid Build Coastguard Worker         fMatrix.setScale(SkIntToScalar(zoom), SkIntToScalar(zoom));
488*c8dee2aaSAndroid Build Coastguard Worker         fInverse.setScale(SK_Scalar1 / zoom, SK_Scalar1 / zoom);
489*c8dee2aaSAndroid Build Coastguard Worker         fShader = ToolUtils::create_checkerboard_shader(0xFFCCCCCC, 0xFFFFFFFF, zoom);
490*c8dee2aaSAndroid Build Coastguard Worker 
491*c8dee2aaSAndroid Build Coastguard Worker         SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
492*c8dee2aaSAndroid Build Coastguard Worker         fMinSurface = SkSurfaces::Raster(info);
493*c8dee2aaSAndroid Build Coastguard Worker         info = info.makeWH(width * zoom, height * zoom);
494*c8dee2aaSAndroid Build Coastguard Worker         fMaxSurface = SkSurfaces::Raster(info);
495*c8dee2aaSAndroid Build Coastguard Worker     }
496*c8dee2aaSAndroid Build Coastguard Worker 
draw_points(SkCanvas * canvas,const SkPath & path,SkColor color,bool show_lines)497*c8dee2aaSAndroid Build Coastguard Worker     void draw_points(SkCanvas* canvas, const SkPath& path, SkColor color,
498*c8dee2aaSAndroid Build Coastguard Worker                      bool show_lines) {
499*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
500*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(color);
501*c8dee2aaSAndroid Build Coastguard Worker         paint.setAlpha(0x80);
502*c8dee2aaSAndroid Build Coastguard Worker         paint.setAntiAlias(true);
503*c8dee2aaSAndroid Build Coastguard Worker         int n = path.countPoints();
504*c8dee2aaSAndroid Build Coastguard Worker         std::unique_ptr<SkPoint[]> pts{new SkPoint[n]};
505*c8dee2aaSAndroid Build Coastguard Worker         if (show_lines && fDrawTangents) {
506*c8dee2aaSAndroid Build Coastguard Worker             TArray<int> contourCounts;
507*c8dee2aaSAndroid Build Coastguard Worker             getContourCounts(path, &contourCounts);
508*c8dee2aaSAndroid Build Coastguard Worker             SkPoint* ptPtr = pts.get();
509*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < contourCounts.size(); ++i) {
510*c8dee2aaSAndroid Build Coastguard Worker                 int count = contourCounts[i];
511*c8dee2aaSAndroid Build Coastguard Worker                 path.getPoints(ptPtr, count);
512*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawPoints(SkCanvas::kPolygon_PointMode, count, ptPtr, paint);
513*c8dee2aaSAndroid Build Coastguard Worker                 ptPtr += count;
514*c8dee2aaSAndroid Build Coastguard Worker             }
515*c8dee2aaSAndroid Build Coastguard Worker         } else {
516*c8dee2aaSAndroid Build Coastguard Worker             n = getOnCurvePoints(path, pts.get());
517*c8dee2aaSAndroid Build Coastguard Worker         }
518*c8dee2aaSAndroid Build Coastguard Worker         paint.setStrokeWidth(5);
519*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPoints(SkCanvas::kPoints_PointMode, n, pts.get(), paint);
520*c8dee2aaSAndroid Build Coastguard Worker     }
521*c8dee2aaSAndroid Build Coastguard Worker 
draw_ribs(SkCanvas * canvas,const SkPath & path,SkScalar width,SkColor color)522*c8dee2aaSAndroid Build Coastguard Worker     void draw_ribs(SkCanvas* canvas, const SkPath& path, SkScalar width,
523*c8dee2aaSAndroid Build Coastguard Worker                    SkColor color) {
524*c8dee2aaSAndroid Build Coastguard Worker         const SkScalar radius = width / 2;
525*c8dee2aaSAndroid Build Coastguard Worker 
526*c8dee2aaSAndroid Build Coastguard Worker         SkPathMeasure meas(path, false);
527*c8dee2aaSAndroid Build Coastguard Worker         SkScalar total = meas.getLength();
528*c8dee2aaSAndroid Build Coastguard Worker 
529*c8dee2aaSAndroid Build Coastguard Worker         SkScalar delta = 8;
530*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint, labelP;
531*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(color);
532*c8dee2aaSAndroid Build Coastguard Worker         labelP.setColor(color & 0xff5f9f5f);
533*c8dee2aaSAndroid Build Coastguard Worker         SkFont font = ToolUtils::DefaultFont();
534*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pos, tan;
535*c8dee2aaSAndroid Build Coastguard Worker         int index = 0;
536*c8dee2aaSAndroid Build Coastguard Worker         for (SkScalar dist = 0; dist <= total; dist += delta) {
537*c8dee2aaSAndroid Build Coastguard Worker             if (meas.getPosTan(dist, &pos, &tan)) {
538*c8dee2aaSAndroid Build Coastguard Worker                 tan.scale(radius);
539*c8dee2aaSAndroid Build Coastguard Worker                 SkPointPriv::RotateCCW(&tan);
540*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(),
541*c8dee2aaSAndroid Build Coastguard Worker                                  pos.x() - tan.x(), pos.y() - tan.y(), paint);
542*c8dee2aaSAndroid Build Coastguard Worker                 if (0 == index % 10) {
543*c8dee2aaSAndroid Build Coastguard Worker                     SkString label;
544*c8dee2aaSAndroid Build Coastguard Worker                     label.appendS32(index);
545*c8dee2aaSAndroid Build Coastguard Worker                     SkRect dot = SkRect::MakeXYWH(pos.x() - 2, pos.y() - 2, 4, 4);
546*c8dee2aaSAndroid Build Coastguard Worker                     canvas->drawRect(dot, labelP);
547*c8dee2aaSAndroid Build Coastguard Worker                     canvas->drawString(label,
548*c8dee2aaSAndroid Build Coastguard Worker                         pos.x() - tan.x() * 1.25f, pos.y() - tan.y() * 1.25f, font, labelP);
549*c8dee2aaSAndroid Build Coastguard Worker                 }
550*c8dee2aaSAndroid Build Coastguard Worker             }
551*c8dee2aaSAndroid Build Coastguard Worker             ++index;
552*c8dee2aaSAndroid Build Coastguard Worker         }
553*c8dee2aaSAndroid Build Coastguard Worker     }
554*c8dee2aaSAndroid Build Coastguard Worker 
draw_t_divs(SkCanvas * canvas,const SkPath & path,SkScalar width,SkColor color)555*c8dee2aaSAndroid Build Coastguard Worker     void draw_t_divs(SkCanvas* canvas, const SkPath& path, SkScalar width, SkColor color) {
556*c8dee2aaSAndroid Build Coastguard Worker         const SkScalar radius = width / 2;
557*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
558*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(color);
559*c8dee2aaSAndroid Build Coastguard Worker         SkPathMeasure meas(path, false);
560*c8dee2aaSAndroid Build Coastguard Worker         SkScalar total = meas.getLength();
561*c8dee2aaSAndroid Build Coastguard Worker         SkScalar delta = 8;
562*c8dee2aaSAndroid Build Coastguard Worker         int ribs = 0;
563*c8dee2aaSAndroid Build Coastguard Worker         for (SkScalar dist = 0; dist <= total; dist += delta) {
564*c8dee2aaSAndroid Build Coastguard Worker             ++ribs;
565*c8dee2aaSAndroid Build Coastguard Worker         }
566*c8dee2aaSAndroid Build Coastguard Worker         const uint8_t* verbs = SkPathPriv::VerbData(path);
567*c8dee2aaSAndroid Build Coastguard Worker         if (path.countVerbs() < 2 || SkPath::kMove_Verb != verbs[0]) {
568*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(0);
569*c8dee2aaSAndroid Build Coastguard Worker             return;
570*c8dee2aaSAndroid Build Coastguard Worker         }
571*c8dee2aaSAndroid Build Coastguard Worker         auto verb = static_cast<SkPath::Verb>(verbs[1]);
572*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(SkPath::kLine_Verb <= verb && verb <= SkPath::kCubic_Verb);
573*c8dee2aaSAndroid Build Coastguard Worker         const SkPoint* pts = SkPathPriv::PointData(path);
574*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pos, tan;
575*c8dee2aaSAndroid Build Coastguard Worker         for (int index = 0; index < ribs; ++index) {
576*c8dee2aaSAndroid Build Coastguard Worker             SkScalar t = (SkScalar) index / ribs;
577*c8dee2aaSAndroid Build Coastguard Worker             switch (verb) {
578*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kLine_Verb:
579*c8dee2aaSAndroid Build Coastguard Worker                     tan = pts[1] - pts[0];
580*c8dee2aaSAndroid Build Coastguard Worker                     pos = pts[0];
581*c8dee2aaSAndroid Build Coastguard Worker                     pos.fX += tan.fX * t;
582*c8dee2aaSAndroid Build Coastguard Worker                     pos.fY += tan.fY * t;
583*c8dee2aaSAndroid Build Coastguard Worker                     break;
584*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kQuad_Verb:
585*c8dee2aaSAndroid Build Coastguard Worker                     pos = SkEvalQuadAt(pts, t);
586*c8dee2aaSAndroid Build Coastguard Worker                     tan = SkEvalQuadTangentAt(pts, t);
587*c8dee2aaSAndroid Build Coastguard Worker                     break;
588*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kConic_Verb: {
589*c8dee2aaSAndroid Build Coastguard Worker                     SkConic conic(pts, SkPathPriv::ConicWeightData(path)[0]);
590*c8dee2aaSAndroid Build Coastguard Worker                     pos = conic.evalAt(t);
591*c8dee2aaSAndroid Build Coastguard Worker                     tan = conic.evalTangentAt(t);
592*c8dee2aaSAndroid Build Coastguard Worker                     } break;
593*c8dee2aaSAndroid Build Coastguard Worker                 case SkPath::kCubic_Verb:
594*c8dee2aaSAndroid Build Coastguard Worker                     SkEvalCubicAt(pts, t, &pos, &tan, nullptr);
595*c8dee2aaSAndroid Build Coastguard Worker                     break;
596*c8dee2aaSAndroid Build Coastguard Worker                 default:
597*c8dee2aaSAndroid Build Coastguard Worker                     SkASSERT(0);
598*c8dee2aaSAndroid Build Coastguard Worker                     return;
599*c8dee2aaSAndroid Build Coastguard Worker             }
600*c8dee2aaSAndroid Build Coastguard Worker             tan.setLength(radius);
601*c8dee2aaSAndroid Build Coastguard Worker             SkPointPriv::RotateCCW(&tan);
602*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawLine(pos.x() + tan.x(), pos.y() + tan.y(),
603*c8dee2aaSAndroid Build Coastguard Worker                                 pos.x() - tan.x(), pos.y() - tan.y(), paint);
604*c8dee2aaSAndroid Build Coastguard Worker             if (0 == index % 10) {
605*c8dee2aaSAndroid Build Coastguard Worker                 SkString label;
606*c8dee2aaSAndroid Build Coastguard Worker                 label.appendS32(index);
607*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawString(label,
608*c8dee2aaSAndroid Build Coastguard Worker                                    pos.x() + tan.x() * 1.25f,
609*c8dee2aaSAndroid Build Coastguard Worker                                    pos.y() + tan.y() * 1.25f,
610*c8dee2aaSAndroid Build Coastguard Worker                                    ToolUtils::DefaultFont(),
611*c8dee2aaSAndroid Build Coastguard Worker                                    paint);
612*c8dee2aaSAndroid Build Coastguard Worker             }
613*c8dee2aaSAndroid Build Coastguard Worker         }
614*c8dee2aaSAndroid Build Coastguard Worker     }
615*c8dee2aaSAndroid Build Coastguard Worker 
draw_stroke(SkCanvas * canvas,const SkPath & path,SkScalar width,SkScalar scale,bool drawText)616*c8dee2aaSAndroid Build Coastguard Worker     void draw_stroke(SkCanvas* canvas, const SkPath& path, SkScalar width, SkScalar scale,
617*c8dee2aaSAndroid Build Coastguard Worker             bool drawText) {
618*c8dee2aaSAndroid Build Coastguard Worker         if (path.isEmpty()) {
619*c8dee2aaSAndroid Build Coastguard Worker             return;
620*c8dee2aaSAndroid Build Coastguard Worker         }
621*c8dee2aaSAndroid Build Coastguard Worker         SkRect bounds = path.getBounds();
622*c8dee2aaSAndroid Build Coastguard Worker         this->setWHZ(SkScalarCeilToInt(bounds.right()), drawText
623*c8dee2aaSAndroid Build Coastguard Worker                 ? SkScalarRoundToInt(scale * 3 / 2) : SkScalarRoundToInt(scale),
624*c8dee2aaSAndroid Build Coastguard Worker                 SkScalarRoundToInt(950.0f / scale));
625*c8dee2aaSAndroid Build Coastguard Worker         erase(fMinSurface);
626*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
627*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0x1f1f0f0f);
628*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kStroke_Style);
629*c8dee2aaSAndroid Build Coastguard Worker         paint.setStrokeWidth(width * scale * scale);
630*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0x3f0f1f3f);
631*c8dee2aaSAndroid Build Coastguard Worker         if (drawText) {
632*c8dee2aaSAndroid Build Coastguard Worker             fMinSurface->getCanvas()->drawPath(path, paint);
633*c8dee2aaSAndroid Build Coastguard Worker             this->copyMinToMax();
634*c8dee2aaSAndroid Build Coastguard Worker             fMaxSurface->draw(canvas, 0, 0);
635*c8dee2aaSAndroid Build Coastguard Worker         }
636*c8dee2aaSAndroid Build Coastguard Worker         paint.setAntiAlias(true);
637*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kStroke_Style);
638*c8dee2aaSAndroid Build Coastguard Worker         paint.setStrokeWidth(1);
639*c8dee2aaSAndroid Build Coastguard Worker 
640*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(SKELETON_COLOR);
641*c8dee2aaSAndroid Build Coastguard Worker         SkPath scaled;
642*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix matrix;
643*c8dee2aaSAndroid Build Coastguard Worker         matrix.reset();
644*c8dee2aaSAndroid Build Coastguard Worker         matrix.setScale(950 / scale, 950 / scale);
645*c8dee2aaSAndroid Build Coastguard Worker         if (drawText) {
646*c8dee2aaSAndroid Build Coastguard Worker             path.transform(matrix, &scaled);
647*c8dee2aaSAndroid Build Coastguard Worker         } else {
648*c8dee2aaSAndroid Build Coastguard Worker             scaled = path;
649*c8dee2aaSAndroid Build Coastguard Worker         }
650*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(scaled, paint);
651*c8dee2aaSAndroid Build Coastguard Worker         draw_points(canvas, scaled, SKELETON_COLOR, true);
652*c8dee2aaSAndroid Build Coastguard Worker 
653*c8dee2aaSAndroid Build Coastguard Worker         if (fDrawRibs) {
654*c8dee2aaSAndroid Build Coastguard Worker             draw_ribs(canvas, scaled, width, 0xFF00FF00);
655*c8dee2aaSAndroid Build Coastguard Worker         }
656*c8dee2aaSAndroid Build Coastguard Worker 
657*c8dee2aaSAndroid Build Coastguard Worker         if (fDrawTDivs) {
658*c8dee2aaSAndroid Build Coastguard Worker             draw_t_divs(canvas, scaled, width, 0xFF3F3F00);
659*c8dee2aaSAndroid Build Coastguard Worker         }
660*c8dee2aaSAndroid Build Coastguard Worker 
661*c8dee2aaSAndroid Build Coastguard Worker         SkPath fill;
662*c8dee2aaSAndroid Build Coastguard Worker 
663*c8dee2aaSAndroid Build Coastguard Worker         SkPaint p;
664*c8dee2aaSAndroid Build Coastguard Worker         p.setStyle(SkPaint::kStroke_Style);
665*c8dee2aaSAndroid Build Coastguard Worker         if (drawText) {
666*c8dee2aaSAndroid Build Coastguard Worker             p.setStrokeWidth(width * scale * scale);
667*c8dee2aaSAndroid Build Coastguard Worker         } else {
668*c8dee2aaSAndroid Build Coastguard Worker             p.setStrokeWidth(width);
669*c8dee2aaSAndroid Build Coastguard Worker         }
670*c8dee2aaSAndroid Build Coastguard Worker         skpathutils::FillPathWithPaint(path, p, &fill);
671*c8dee2aaSAndroid Build Coastguard Worker         SkPath scaledFill;
672*c8dee2aaSAndroid Build Coastguard Worker         if (drawText) {
673*c8dee2aaSAndroid Build Coastguard Worker             fill.transform(matrix, &scaledFill);
674*c8dee2aaSAndroid Build Coastguard Worker         } else {
675*c8dee2aaSAndroid Build Coastguard Worker             scaledFill = fill;
676*c8dee2aaSAndroid Build Coastguard Worker         }
677*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(WIREFRAME_COLOR);
678*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(scaledFill, paint);
679*c8dee2aaSAndroid Build Coastguard Worker         draw_points(canvas, scaledFill, WIREFRAME_COLOR, false);
680*c8dee2aaSAndroid Build Coastguard Worker     }
681*c8dee2aaSAndroid Build Coastguard Worker 
draw_fill(SkCanvas * canvas,const SkRect & rect,SkScalar width)682*c8dee2aaSAndroid Build Coastguard Worker     void draw_fill(SkCanvas* canvas, const SkRect& rect, SkScalar width) {
683*c8dee2aaSAndroid Build Coastguard Worker         if (rect.isEmpty()) {
684*c8dee2aaSAndroid Build Coastguard Worker             return;
685*c8dee2aaSAndroid Build Coastguard Worker         }
686*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
687*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0x1f1f0f0f);
688*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kStroke_Style);
689*c8dee2aaSAndroid Build Coastguard Worker         paint.setStrokeWidth(width);
690*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
691*c8dee2aaSAndroid Build Coastguard Worker         SkScalar maxSide = std::max(rect.width(), rect.height()) / 2;
692*c8dee2aaSAndroid Build Coastguard Worker         SkPoint center = { rect.fLeft + maxSide, rect.fTop + maxSide };
693*c8dee2aaSAndroid Build Coastguard Worker         path.addCircle(center.fX, center.fY, maxSide);
694*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(path, paint);
695*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kFill_Style);
696*c8dee2aaSAndroid Build Coastguard Worker         path.reset();
697*c8dee2aaSAndroid Build Coastguard Worker         path.addCircle(center.fX, center.fY, maxSide - width / 2);
698*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0x3f0f1f3f);
699*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(path, paint);
700*c8dee2aaSAndroid Build Coastguard Worker         path.reset();
701*c8dee2aaSAndroid Build Coastguard Worker         path.setFillType(SkPathFillType::kEvenOdd);
702*c8dee2aaSAndroid Build Coastguard Worker         path.addCircle(center.fX, center.fY, maxSide + width / 2);
703*c8dee2aaSAndroid Build Coastguard Worker         SkRect outside = SkRect::MakeXYWH(center.fX - maxSide - width, center.fY - maxSide - width,
704*c8dee2aaSAndroid Build Coastguard Worker                 (maxSide + width) * 2, (maxSide + width) * 2);
705*c8dee2aaSAndroid Build Coastguard Worker         path.addRect(outside);
706*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawPath(path, paint);
707*c8dee2aaSAndroid Build Coastguard Worker     }
708*c8dee2aaSAndroid Build Coastguard Worker 
draw_button(SkCanvas * canvas,const StrokeTypeButton & button)709*c8dee2aaSAndroid Build Coastguard Worker     void draw_button(SkCanvas* canvas, const StrokeTypeButton& button) {
710*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
711*c8dee2aaSAndroid Build Coastguard Worker         paint.setAntiAlias(true);
712*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kStroke_Style);
713*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(button.fEnabled ? 0xFF3F0000 : 0x6F3F0000);
714*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawRect(button.fBounds, paint);
715*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(button.fEnabled ? 0xFF3F0000 : 0x6F3F0000);
716*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kFill_Style);
717*c8dee2aaSAndroid Build Coastguard Worker         SkFont font = ToolUtils::DefaultFont();
718*c8dee2aaSAndroid Build Coastguard Worker         font.setSize(25.0f);
719*c8dee2aaSAndroid Build Coastguard Worker         SkTextUtils::Draw(canvas, &button.fLabel, 1, SkTextEncoding::kUTF8,
720*c8dee2aaSAndroid Build Coastguard Worker                 button.fBounds.centerX(), button.fBounds.fBottom - 5,
721*c8dee2aaSAndroid Build Coastguard Worker                 font, paint, SkTextUtils::kCenter_Align);
722*c8dee2aaSAndroid Build Coastguard Worker     }
723*c8dee2aaSAndroid Build Coastguard Worker 
draw_control(SkCanvas * canvas,const SkRect & bounds,SkScalar value,SkScalar min,SkScalar max,const char * name)724*c8dee2aaSAndroid Build Coastguard Worker     void draw_control(SkCanvas* canvas, const SkRect& bounds, SkScalar value,
725*c8dee2aaSAndroid Build Coastguard Worker             SkScalar min, SkScalar max, const char* name) {
726*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
727*c8dee2aaSAndroid Build Coastguard Worker         paint.setAntiAlias(true);
728*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kStroke_Style);
729*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawRect(bounds, paint);
730*c8dee2aaSAndroid Build Coastguard Worker         SkScalar scale = max - min;
731*c8dee2aaSAndroid Build Coastguard Worker         SkScalar yPos = bounds.fTop + (value - min) * bounds.height() / scale;
732*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0xFFFF0000);
733*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawLine(bounds.fLeft - 5, yPos, bounds.fRight + 5, yPos, paint);
734*c8dee2aaSAndroid Build Coastguard Worker         SkString label;
735*c8dee2aaSAndroid Build Coastguard Worker         label.printf("%0.3g", value);
736*c8dee2aaSAndroid Build Coastguard Worker         paint.setColor(0xFF000000);
737*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kFill_Style);
738*c8dee2aaSAndroid Build Coastguard Worker         SkFont font(ToolUtils::DefaultTypeface(), 11.0f);
739*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawString(label, bounds.fLeft + 5, yPos - 5, font, paint);
740*c8dee2aaSAndroid Build Coastguard Worker         font.setSize(13.0f);
741*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawString(name, bounds.fLeft, bounds.bottom() + 11, font, paint);
742*c8dee2aaSAndroid Build Coastguard Worker     }
743*c8dee2aaSAndroid Build Coastguard Worker 
setForGeometry()744*c8dee2aaSAndroid Build Coastguard Worker     void setForGeometry() {
745*c8dee2aaSAndroid Build Coastguard Worker         fDrawRibs = true;
746*c8dee2aaSAndroid Build Coastguard Worker         fDrawTangents = true;
747*c8dee2aaSAndroid Build Coastguard Worker         fDrawTDivs = false;
748*c8dee2aaSAndroid Build Coastguard Worker         fWidthScale = 1;
749*c8dee2aaSAndroid Build Coastguard Worker     }
750*c8dee2aaSAndroid Build Coastguard Worker 
setForText()751*c8dee2aaSAndroid Build Coastguard Worker     void setForText() {
752*c8dee2aaSAndroid Build Coastguard Worker         fDrawRibs = fDrawTangents = fDrawTDivs = false;
753*c8dee2aaSAndroid Build Coastguard Worker         fWidthScale = 0.002f;
754*c8dee2aaSAndroid Build Coastguard Worker     }
755*c8dee2aaSAndroid Build Coastguard Worker 
setForSingles()756*c8dee2aaSAndroid Build Coastguard Worker     void setForSingles() {
757*c8dee2aaSAndroid Build Coastguard Worker         setForGeometry();
758*c8dee2aaSAndroid Build Coastguard Worker         fDrawTDivs = true;
759*c8dee2aaSAndroid Build Coastguard Worker     }
760*c8dee2aaSAndroid Build Coastguard Worker 
setAsNeeded()761*c8dee2aaSAndroid Build Coastguard Worker     void setAsNeeded() {
762*c8dee2aaSAndroid Build Coastguard Worker         if (fConicButton.fEnabled || fCubicButton.fEnabled || fQuadButton.fEnabled) {
763*c8dee2aaSAndroid Build Coastguard Worker             setForSingles();
764*c8dee2aaSAndroid Build Coastguard Worker         } else if (fRRectButton.fEnabled || fCircleButton.fEnabled || fArcButton.fEnabled) {
765*c8dee2aaSAndroid Build Coastguard Worker             setForGeometry();
766*c8dee2aaSAndroid Build Coastguard Worker         } else {
767*c8dee2aaSAndroid Build Coastguard Worker             setForText();
768*c8dee2aaSAndroid Build Coastguard Worker         }
769*c8dee2aaSAndroid Build Coastguard Worker     }
770*c8dee2aaSAndroid Build Coastguard Worker 
arcCenter(SkPoint * center)771*c8dee2aaSAndroid Build Coastguard Worker     bool arcCenter(SkPoint* center) {
772*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
773*c8dee2aaSAndroid Build Coastguard Worker         path.moveTo(fPts[10]);
774*c8dee2aaSAndroid Build Coastguard Worker         path.arcTo(fPts[11], fPts[12], fRadius);
775*c8dee2aaSAndroid Build Coastguard Worker         SkPath::Iter iter(path, false);
776*c8dee2aaSAndroid Build Coastguard Worker         SkPoint pts[4];
777*c8dee2aaSAndroid Build Coastguard Worker         iter.next(pts);
778*c8dee2aaSAndroid Build Coastguard Worker         if (SkPath::kLine_Verb == iter.next(pts)) {
779*c8dee2aaSAndroid Build Coastguard Worker             iter.next(pts);
780*c8dee2aaSAndroid Build Coastguard Worker         }
781*c8dee2aaSAndroid Build Coastguard Worker         SkVector before = pts[0] - pts[1];
782*c8dee2aaSAndroid Build Coastguard Worker         SkVector after = pts[1] - pts[2];
783*c8dee2aaSAndroid Build Coastguard Worker         before.setLength(fRadius);
784*c8dee2aaSAndroid Build Coastguard Worker         after.setLength(fRadius);
785*c8dee2aaSAndroid Build Coastguard Worker         SkVector beforeCCW, afterCCW;
786*c8dee2aaSAndroid Build Coastguard Worker         SkPointPriv::RotateCCW(before, &beforeCCW);
787*c8dee2aaSAndroid Build Coastguard Worker         SkPointPriv::RotateCCW(after, &afterCCW);
788*c8dee2aaSAndroid Build Coastguard Worker         beforeCCW += pts[0];
789*c8dee2aaSAndroid Build Coastguard Worker         afterCCW += pts[2];
790*c8dee2aaSAndroid Build Coastguard Worker         *center = beforeCCW;
791*c8dee2aaSAndroid Build Coastguard Worker         if (SkScalarNearlyEqual(beforeCCW.fX, afterCCW.fX)
792*c8dee2aaSAndroid Build Coastguard Worker                 && SkScalarNearlyEqual(beforeCCW.fY, afterCCW.fY)) {
793*c8dee2aaSAndroid Build Coastguard Worker             return true;
794*c8dee2aaSAndroid Build Coastguard Worker         }
795*c8dee2aaSAndroid Build Coastguard Worker         SkVector beforeCW, afterCW;
796*c8dee2aaSAndroid Build Coastguard Worker         SkPointPriv::RotateCW(before, &beforeCW);
797*c8dee2aaSAndroid Build Coastguard Worker         SkPointPriv::RotateCW(after, &afterCW);
798*c8dee2aaSAndroid Build Coastguard Worker         beforeCW += pts[0];
799*c8dee2aaSAndroid Build Coastguard Worker         afterCW += pts[2];
800*c8dee2aaSAndroid Build Coastguard Worker         *center = beforeCW;
801*c8dee2aaSAndroid Build Coastguard Worker         return SkScalarNearlyEqual(beforeCW.fX, afterCW.fX)
802*c8dee2aaSAndroid Build Coastguard Worker                 && SkScalarNearlyEqual(beforeCCW.fY, afterCW.fY);
803*c8dee2aaSAndroid Build Coastguard Worker     }
804*c8dee2aaSAndroid Build Coastguard Worker 
MapScreenYtoValue(SkScalar y,const SkRect & control,SkScalar min,SkScalar max)805*c8dee2aaSAndroid Build Coastguard Worker     static SkScalar MapScreenYtoValue(SkScalar y, const SkRect& control, SkScalar min,
806*c8dee2aaSAndroid Build Coastguard Worker             SkScalar max) {
807*c8dee2aaSAndroid Build Coastguard Worker         return (y - control.fTop) / control.height() * (max - min) + min;
808*c8dee2aaSAndroid Build Coastguard Worker     }
809*c8dee2aaSAndroid Build Coastguard Worker };
810*c8dee2aaSAndroid Build Coastguard Worker 
811*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
812*c8dee2aaSAndroid Build Coastguard Worker 
813*c8dee2aaSAndroid Build Coastguard Worker DEF_SLIDE( return new QuadStrokerSlide(); )
814