1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h"
9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
10cb93a386Sopenharmony_ci#include "include/core/SkColorFilter.h"
11cb93a386Sopenharmony_ci#include "include/core/SkColorPriv.h"
12cb93a386Sopenharmony_ci#include "include/core/SkFont.h"
13cb93a386Sopenharmony_ci#include "include/core/SkGraphics.h"
14cb93a386Sopenharmony_ci#include "include/core/SkPathBuilder.h"
15cb93a386Sopenharmony_ci#include "include/core/SkRegion.h"
16cb93a386Sopenharmony_ci#include "include/core/SkShader.h"
17cb93a386Sopenharmony_ci#include "include/core/SkTime.h"
18cb93a386Sopenharmony_ci#include "include/core/SkTypeface.h"
19cb93a386Sopenharmony_ci#include "include/effects/SkGradientShader.h"
20cb93a386Sopenharmony_ci#include "include/utils/SkParsePath.h"
21cb93a386Sopenharmony_ci#include "samplecode/Sample.h"
22cb93a386Sopenharmony_ci#include "src/utils/SkUTF.h"
23cb93a386Sopenharmony_ci#include "tools/timer/TimeUtils.h"
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h"
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ci#include <stdlib.h>
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci// http://code.google.com/p/skia/issues/detail?id=32
30cb93a386Sopenharmony_cistatic void test_cubic() {
31cb93a386Sopenharmony_ci    SkPoint src[4] = {
32cb93a386Sopenharmony_ci        { 556.25000f, 523.03003f },
33cb93a386Sopenharmony_ci        { 556.23999f, 522.96002f },
34cb93a386Sopenharmony_ci        { 556.21997f, 522.89001f },
35cb93a386Sopenharmony_ci        { 556.21997f, 522.82001f }
36cb93a386Sopenharmony_ci    };
37cb93a386Sopenharmony_ci    SkPoint dst[11];
38cb93a386Sopenharmony_ci    dst[10].set(42, -42);   // one past the end, that we don't clobber these
39cb93a386Sopenharmony_ci    SkScalar tval[] = { 0.33333334f, 0.99999994f };
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ci    SkChopCubicAt(src, dst, tval, 2);
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci#if 0
44cb93a386Sopenharmony_ci    for (int i = 0; i < 11; i++) {
45cb93a386Sopenharmony_ci        SkDebugf("--- %d [%g %g]\n", i, dst[i].fX, dst[i].fY);
46cb93a386Sopenharmony_ci    }
47cb93a386Sopenharmony_ci#endif
48cb93a386Sopenharmony_ci}
49cb93a386Sopenharmony_ci
50cb93a386Sopenharmony_cistatic void test_cubic2() {
51cb93a386Sopenharmony_ci    const char* str = "M2242 -590088L-377758 9.94099e+07L-377758 9.94099e+07L2242 -590088Z";
52cb93a386Sopenharmony_ci    SkPath path;
53cb93a386Sopenharmony_ci    SkParsePath::FromSVGString(str, &path);
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci    {
56cb93a386Sopenharmony_ci        SkRect r = path.getBounds();
57cb93a386Sopenharmony_ci        SkIRect ir;
58cb93a386Sopenharmony_ci        r.round(&ir);
59cb93a386Sopenharmony_ci        SkDebugf("[%g %g %g %g] [%x %x %x %x]\n",
60cb93a386Sopenharmony_ci                SkScalarToDouble(r.fLeft), SkScalarToDouble(r.fTop),
61cb93a386Sopenharmony_ci                SkScalarToDouble(r.fRight), SkScalarToDouble(r.fBottom),
62cb93a386Sopenharmony_ci                ir.fLeft, ir.fTop, ir.fRight, ir.fBottom);
63cb93a386Sopenharmony_ci    }
64cb93a386Sopenharmony_ci
65cb93a386Sopenharmony_ci    SkBitmap bitmap;
66cb93a386Sopenharmony_ci    bitmap.allocN32Pixels(300, 200);
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci    SkCanvas canvas(bitmap);
69cb93a386Sopenharmony_ci    SkPaint paint;
70cb93a386Sopenharmony_ci    paint.setAntiAlias(true);
71cb93a386Sopenharmony_ci    canvas.drawPath(path, paint);
72cb93a386Sopenharmony_ci}
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ciclass PathView : public Sample {
75cb93a386Sopenharmony_ci    SkScalar fPrevSecs;
76cb93a386Sopenharmony_cipublic:
77cb93a386Sopenharmony_ci    SkScalar fDStroke, fStroke, fMinStroke, fMaxStroke;
78cb93a386Sopenharmony_ci    SkPath fPath[6];
79cb93a386Sopenharmony_ci    bool fShowHairline;
80cb93a386Sopenharmony_ci    bool fOnce;
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_ci    PathView() {
83cb93a386Sopenharmony_ci        fPrevSecs = 0;
84cb93a386Sopenharmony_ci        fOnce = false;
85cb93a386Sopenharmony_ci    }
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ci    void init() {
88cb93a386Sopenharmony_ci        if (fOnce) {
89cb93a386Sopenharmony_ci            return;
90cb93a386Sopenharmony_ci        }
91cb93a386Sopenharmony_ci        fOnce = true;
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci        test_cubic();
94cb93a386Sopenharmony_ci        test_cubic2();
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ci        fShowHairline = false;
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci        fDStroke = 1;
99cb93a386Sopenharmony_ci        fStroke = 10;
100cb93a386Sopenharmony_ci        fMinStroke = 10;
101cb93a386Sopenharmony_ci        fMaxStroke = 180;
102cb93a386Sopenharmony_ci
103cb93a386Sopenharmony_ci        const SkScalar V = 85;
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci        fPath[0].moveTo(40, 70);
106cb93a386Sopenharmony_ci        fPath[0].lineTo(70, 70 + SK_ScalarHalf);
107cb93a386Sopenharmony_ci        fPath[0].lineTo(110, 70);
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_ci        fPath[1].moveTo(40, 70);
110cb93a386Sopenharmony_ci        fPath[1].lineTo(70, 70 - SK_ScalarHalf);
111cb93a386Sopenharmony_ci        fPath[1].lineTo(110, 70);
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci        fPath[2].moveTo(V, V);
114cb93a386Sopenharmony_ci        fPath[2].lineTo(50, V);
115cb93a386Sopenharmony_ci        fPath[2].lineTo(50, 50);
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci        fPath[3].moveTo(50, 50);
118cb93a386Sopenharmony_ci        fPath[3].lineTo(50, V);
119cb93a386Sopenharmony_ci        fPath[3].lineTo(V, V);
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ci        fPath[4].moveTo(50, 50);
122cb93a386Sopenharmony_ci        fPath[4].lineTo(50, V);
123cb93a386Sopenharmony_ci        fPath[4].lineTo(52, 50);
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci        fPath[5].moveTo(52, 50);
126cb93a386Sopenharmony_ci        fPath[5].lineTo(50, V);
127cb93a386Sopenharmony_ci        fPath[5].lineTo(50, 50);
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci        this->setBGColor(0xFFDDDDDD);
130cb93a386Sopenharmony_ci    }
131cb93a386Sopenharmony_ci
132cb93a386Sopenharmony_ciprotected:
133cb93a386Sopenharmony_ci    SkString name() override { return SkString("Paths"); }
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    void drawPath(SkCanvas* canvas, const SkPath& path, SkPaint::Join j) {
136cb93a386Sopenharmony_ci        SkPaint paint;
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci        paint.setAntiAlias(true);
139cb93a386Sopenharmony_ci        paint.setStyle(SkPaint::kStroke_Style);
140cb93a386Sopenharmony_ci        paint.setStrokeJoin(j);
141cb93a386Sopenharmony_ci        paint.setStrokeWidth(fStroke);
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci        if (fShowHairline) {
144cb93a386Sopenharmony_ci            SkPath  fill;
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_ci            paint.getFillPath(path, &fill);
147cb93a386Sopenharmony_ci            paint.setStrokeWidth(0);
148cb93a386Sopenharmony_ci            canvas->drawPath(fill, paint);
149cb93a386Sopenharmony_ci        } else {
150cb93a386Sopenharmony_ci            canvas->drawPath(path, paint);
151cb93a386Sopenharmony_ci        }
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ci        paint.setColor(SK_ColorRED);
154cb93a386Sopenharmony_ci        paint.setStrokeWidth(0);
155cb93a386Sopenharmony_ci        canvas->drawPath(path, paint);
156cb93a386Sopenharmony_ci    }
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci    void onDrawContent(SkCanvas* canvas) override {
159cb93a386Sopenharmony_ci        this->init();
160cb93a386Sopenharmony_ci        canvas->translate(50, 50);
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ci        static const SkPaint::Join gJoins[] = {
163cb93a386Sopenharmony_ci            SkPaint::kBevel_Join,
164cb93a386Sopenharmony_ci            SkPaint::kMiter_Join,
165cb93a386Sopenharmony_ci            SkPaint::kRound_Join
166cb93a386Sopenharmony_ci        };
167cb93a386Sopenharmony_ci
168cb93a386Sopenharmony_ci        for (size_t i = 0; i < SK_ARRAY_COUNT(gJoins); i++) {
169cb93a386Sopenharmony_ci            canvas->save();
170cb93a386Sopenharmony_ci            for (size_t j = 0; j < SK_ARRAY_COUNT(fPath); j++) {
171cb93a386Sopenharmony_ci                this->drawPath(canvas, fPath[j], gJoins[i]);
172cb93a386Sopenharmony_ci                canvas->translate(200, 0);
173cb93a386Sopenharmony_ci            }
174cb93a386Sopenharmony_ci            canvas->restore();
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci            canvas->translate(0, 200);
177cb93a386Sopenharmony_ci        }
178cb93a386Sopenharmony_ci    }
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_ci    bool onAnimate(double nanos) override {
181cb93a386Sopenharmony_ci        SkScalar currSecs = TimeUtils::Scaled(1e-9 * nanos, 100);
182cb93a386Sopenharmony_ci        SkScalar delta = currSecs - fPrevSecs;
183cb93a386Sopenharmony_ci        fPrevSecs = currSecs;
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci        fStroke += fDStroke * delta;
186cb93a386Sopenharmony_ci        if (fStroke > fMaxStroke || fStroke < fMinStroke) {
187cb93a386Sopenharmony_ci            fDStroke = -fDStroke;
188cb93a386Sopenharmony_ci        }
189cb93a386Sopenharmony_ci        return true;
190cb93a386Sopenharmony_ci    }
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci    Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
193cb93a386Sopenharmony_ci        fShowHairline = !fShowHairline;
194cb93a386Sopenharmony_ci        return nullptr;
195cb93a386Sopenharmony_ci    }
196cb93a386Sopenharmony_ci
197cb93a386Sopenharmony_ciprivate:
198cb93a386Sopenharmony_ci    using INHERITED = Sample;
199cb93a386Sopenharmony_ci};
200cb93a386Sopenharmony_ciDEF_SAMPLE( return new PathView; )
201cb93a386Sopenharmony_ci
202cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
203cb93a386Sopenharmony_ci
204cb93a386Sopenharmony_ci#include "include/effects/SkCornerPathEffect.h"
205cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h"
206cb93a386Sopenharmony_ci
207cb93a386Sopenharmony_ciclass ArcToView : public Sample {
208cb93a386Sopenharmony_ci    bool fDoFrame, fDoCorner, fDoConic;
209cb93a386Sopenharmony_ci    SkPaint fPtsPaint, fSkeletonPaint, fCornerPaint;
210cb93a386Sopenharmony_cipublic:
211cb93a386Sopenharmony_ci    enum {
212cb93a386Sopenharmony_ci        N = 4
213cb93a386Sopenharmony_ci    };
214cb93a386Sopenharmony_ci    SkPoint fPts[N];
215cb93a386Sopenharmony_ci
216cb93a386Sopenharmony_ci    ArcToView()
217cb93a386Sopenharmony_ci        : fDoFrame(false), fDoCorner(false), fDoConic(false)
218cb93a386Sopenharmony_ci    {
219cb93a386Sopenharmony_ci        SkRandom rand;
220cb93a386Sopenharmony_ci        for (int i = 0; i < N; ++i) {
221cb93a386Sopenharmony_ci            fPts[i].fX = 20 + rand.nextUScalar1() * 640;
222cb93a386Sopenharmony_ci            fPts[i].fY = 20 + rand.nextUScalar1() * 480;
223cb93a386Sopenharmony_ci        }
224cb93a386Sopenharmony_ci
225cb93a386Sopenharmony_ci        const SkScalar rad = 50;
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci        fPtsPaint.setAntiAlias(true);
228cb93a386Sopenharmony_ci        fPtsPaint.setStrokeWidth(15);
229cb93a386Sopenharmony_ci        fPtsPaint.setStrokeCap(SkPaint::kRound_Cap);
230cb93a386Sopenharmony_ci
231cb93a386Sopenharmony_ci        fCornerPaint.setAntiAlias(true);
232cb93a386Sopenharmony_ci        fCornerPaint.setStyle(SkPaint::kStroke_Style);
233cb93a386Sopenharmony_ci        fCornerPaint.setStrokeWidth(13);
234cb93a386Sopenharmony_ci        fCornerPaint.setColor(SK_ColorGREEN);
235cb93a386Sopenharmony_ci        fCornerPaint.setPathEffect(SkCornerPathEffect::Make(rad*2));
236cb93a386Sopenharmony_ci
237cb93a386Sopenharmony_ci        fSkeletonPaint.setAntiAlias(true);
238cb93a386Sopenharmony_ci        fSkeletonPaint.setStyle(SkPaint::kStroke_Style);
239cb93a386Sopenharmony_ci        fSkeletonPaint.setColor(SK_ColorRED);
240cb93a386Sopenharmony_ci    }
241cb93a386Sopenharmony_ci
242cb93a386Sopenharmony_ci    void toggle(bool& value) {
243cb93a386Sopenharmony_ci        value = !value;
244cb93a386Sopenharmony_ci    }
245cb93a386Sopenharmony_ci
246cb93a386Sopenharmony_ciprotected:
247cb93a386Sopenharmony_ci    SkString name() override { return SkString("ArcTo"); }
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_ci    bool onChar(SkUnichar uni) override {
250cb93a386Sopenharmony_ci            switch (uni) {
251cb93a386Sopenharmony_ci                case '1': this->toggle(fDoFrame); return true;
252cb93a386Sopenharmony_ci                case '2': this->toggle(fDoCorner); return true;
253cb93a386Sopenharmony_ci                case '3': this->toggle(fDoConic); return true;
254cb93a386Sopenharmony_ci                default: break;
255cb93a386Sopenharmony_ci            }
256cb93a386Sopenharmony_ci            return false;
257cb93a386Sopenharmony_ci    }
258cb93a386Sopenharmony_ci
259cb93a386Sopenharmony_ci    void makePath(SkPath* path) {
260cb93a386Sopenharmony_ci        path->moveTo(fPts[0]);
261cb93a386Sopenharmony_ci        for (int i = 1; i < N; ++i) {
262cb93a386Sopenharmony_ci            path->lineTo(fPts[i]);
263cb93a386Sopenharmony_ci        }
264cb93a386Sopenharmony_ci        if (!fDoFrame) {
265cb93a386Sopenharmony_ci            path->close();
266cb93a386Sopenharmony_ci        }
267cb93a386Sopenharmony_ci    }
268cb93a386Sopenharmony_ci
269cb93a386Sopenharmony_ci    void onDrawContent(SkCanvas* canvas) override {
270cb93a386Sopenharmony_ci        canvas->drawPoints(SkCanvas::kPoints_PointMode, N, fPts, fPtsPaint);
271cb93a386Sopenharmony_ci
272cb93a386Sopenharmony_ci        SkPath path;
273cb93a386Sopenharmony_ci        this->makePath(&path);
274cb93a386Sopenharmony_ci
275cb93a386Sopenharmony_ci        if (fDoCorner) {
276cb93a386Sopenharmony_ci            canvas->drawPath(path, fCornerPaint);
277cb93a386Sopenharmony_ci        }
278cb93a386Sopenharmony_ci
279cb93a386Sopenharmony_ci        canvas->drawPath(path, fSkeletonPaint);
280cb93a386Sopenharmony_ci    }
281cb93a386Sopenharmony_ci
282cb93a386Sopenharmony_ci    Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
283cb93a386Sopenharmony_ci        const SkScalar tol = 4;
284cb93a386Sopenharmony_ci        const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
285cb93a386Sopenharmony_ci        for (int i = 0; i < N; ++i) {
286cb93a386Sopenharmony_ci            if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
287cb93a386Sopenharmony_ci                return new Click([this, i](Click* c) {
288cb93a386Sopenharmony_ci                    fPts[i] = c->fCurr;
289cb93a386Sopenharmony_ci                    return true;
290cb93a386Sopenharmony_ci                });
291cb93a386Sopenharmony_ci            }
292cb93a386Sopenharmony_ci        }
293cb93a386Sopenharmony_ci        return nullptr;
294cb93a386Sopenharmony_ci    }
295cb93a386Sopenharmony_ci
296cb93a386Sopenharmony_ciprivate:
297cb93a386Sopenharmony_ci    using INHERITED = Sample;
298cb93a386Sopenharmony_ci};
299cb93a386Sopenharmony_ciDEF_SAMPLE( return new ArcToView; )
300cb93a386Sopenharmony_ci
301cb93a386Sopenharmony_ci/////////////
302cb93a386Sopenharmony_ci
303cb93a386Sopenharmony_ciclass FatStroke : public Sample {
304cb93a386Sopenharmony_ci    bool fClosed, fShowStroke, fShowHidden, fShowSkeleton, fAsCurves = false;
305cb93a386Sopenharmony_ci    int  fJoinType, fCapType;
306cb93a386Sopenharmony_ci    float fWidth = 30;
307cb93a386Sopenharmony_ci    SkPaint fPtsPaint, fHiddenPaint, fSkeletonPaint, fStrokePaint;
308cb93a386Sopenharmony_cipublic:
309cb93a386Sopenharmony_ci    enum {
310cb93a386Sopenharmony_ci        N = 4
311cb93a386Sopenharmony_ci    };
312cb93a386Sopenharmony_ci    SkPoint fPts[N];
313cb93a386Sopenharmony_ci
314cb93a386Sopenharmony_ci    FatStroke() : fClosed(false), fShowStroke(true), fShowHidden(false), fShowSkeleton(true),
315cb93a386Sopenharmony_ci                  fJoinType(0), fCapType(0)
316cb93a386Sopenharmony_ci    {
317cb93a386Sopenharmony_ci        SkRandom rand;
318cb93a386Sopenharmony_ci        for (int i = 0; i < N; ++i) {
319cb93a386Sopenharmony_ci            fPts[i].fX = 20 + rand.nextUScalar1() * 640;
320cb93a386Sopenharmony_ci            fPts[i].fY = 20 + rand.nextUScalar1() * 480;
321cb93a386Sopenharmony_ci        }
322cb93a386Sopenharmony_ci
323cb93a386Sopenharmony_ci        fPtsPaint.setAntiAlias(true);
324cb93a386Sopenharmony_ci        fPtsPaint.setStrokeWidth(10);
325cb93a386Sopenharmony_ci        fPtsPaint.setStrokeCap(SkPaint::kRound_Cap);
326cb93a386Sopenharmony_ci
327cb93a386Sopenharmony_ci        fHiddenPaint.setAntiAlias(true);
328cb93a386Sopenharmony_ci        fHiddenPaint.setStyle(SkPaint::kStroke_Style);
329cb93a386Sopenharmony_ci        fHiddenPaint.setColor(0xFF0000FF);
330cb93a386Sopenharmony_ci
331cb93a386Sopenharmony_ci        fStrokePaint.setAntiAlias(true);
332cb93a386Sopenharmony_ci        fStrokePaint.setStyle(SkPaint::kStroke_Style);
333cb93a386Sopenharmony_ci        fStrokePaint.setStrokeWidth(50);
334cb93a386Sopenharmony_ci        fStrokePaint.setColor(0x8000FF00);
335cb93a386Sopenharmony_ci
336cb93a386Sopenharmony_ci        fSkeletonPaint.setAntiAlias(true);
337cb93a386Sopenharmony_ci        fSkeletonPaint.setStyle(SkPaint::kStroke_Style);
338cb93a386Sopenharmony_ci        fSkeletonPaint.setColor(SK_ColorRED);
339cb93a386Sopenharmony_ci    }
340cb93a386Sopenharmony_ci
341cb93a386Sopenharmony_ci    void toggle(bool& value) {
342cb93a386Sopenharmony_ci        value = !value;
343cb93a386Sopenharmony_ci    }
344cb93a386Sopenharmony_ci
345cb93a386Sopenharmony_ci    void toggle3(int& value) {
346cb93a386Sopenharmony_ci        value = (value + 1) % 3;
347cb93a386Sopenharmony_ci    }
348cb93a386Sopenharmony_ci
349cb93a386Sopenharmony_ciprotected:
350cb93a386Sopenharmony_ci    SkString name() override { return SkString("FatStroke"); }
351cb93a386Sopenharmony_ci
352cb93a386Sopenharmony_ci    bool onChar(SkUnichar uni) override {
353cb93a386Sopenharmony_ci            switch (uni) {
354cb93a386Sopenharmony_ci                case '1': this->toggle(fShowSkeleton); return true;
355cb93a386Sopenharmony_ci                case '2': this->toggle(fShowStroke); return true;
356cb93a386Sopenharmony_ci                case '3': this->toggle(fShowHidden); return true;
357cb93a386Sopenharmony_ci                case '4': this->toggle3(fJoinType); return true;
358cb93a386Sopenharmony_ci                case '5': this->toggle3(fCapType); return true;
359cb93a386Sopenharmony_ci                case '6': this->toggle(fClosed); return true;
360cb93a386Sopenharmony_ci                case 'c': this->toggle(fAsCurves); return true;
361cb93a386Sopenharmony_ci                case '-': fWidth -= 5; return true;
362cb93a386Sopenharmony_ci                case '=': fWidth += 5; return true;
363cb93a386Sopenharmony_ci                default: break;
364cb93a386Sopenharmony_ci            }
365cb93a386Sopenharmony_ci            return false;
366cb93a386Sopenharmony_ci    }
367cb93a386Sopenharmony_ci
368cb93a386Sopenharmony_ci    void makePath(SkPath* path) {
369cb93a386Sopenharmony_ci        path->moveTo(fPts[0]);
370cb93a386Sopenharmony_ci        if (fAsCurves) {
371cb93a386Sopenharmony_ci            for (int i = 1; i < N-2; ++i) {
372cb93a386Sopenharmony_ci                path->quadTo(fPts[i], (fPts[i+1] + fPts[i]) * 0.5f);
373cb93a386Sopenharmony_ci            }
374cb93a386Sopenharmony_ci            path->quadTo(fPts[N-2], fPts[N-1]);
375cb93a386Sopenharmony_ci        } else {
376cb93a386Sopenharmony_ci            for (int i = 1; i < N; ++i) {
377cb93a386Sopenharmony_ci                path->lineTo(fPts[i]);
378cb93a386Sopenharmony_ci            }
379cb93a386Sopenharmony_ci        }
380cb93a386Sopenharmony_ci        if (fClosed) {
381cb93a386Sopenharmony_ci            path->close();
382cb93a386Sopenharmony_ci        }
383cb93a386Sopenharmony_ci    }
384cb93a386Sopenharmony_ci
385cb93a386Sopenharmony_ci    void onDrawContent(SkCanvas* canvas) override {
386cb93a386Sopenharmony_ci        canvas->drawColor(0xFFEEEEEE);
387cb93a386Sopenharmony_ci
388cb93a386Sopenharmony_ci        SkPath path;
389cb93a386Sopenharmony_ci        this->makePath(&path);
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_ci        fStrokePaint.setStrokeWidth(fWidth);
392cb93a386Sopenharmony_ci        fStrokePaint.setStrokeJoin((SkPaint::Join)fJoinType);
393cb93a386Sopenharmony_ci        fStrokePaint.setStrokeCap((SkPaint::Cap)fCapType);
394cb93a386Sopenharmony_ci
395cb93a386Sopenharmony_ci        if (fShowStroke) {
396cb93a386Sopenharmony_ci            canvas->drawPath(path, fStrokePaint);
397cb93a386Sopenharmony_ci        }
398cb93a386Sopenharmony_ci        if (fShowHidden) {
399cb93a386Sopenharmony_ci            SkPath hidden;
400cb93a386Sopenharmony_ci            fStrokePaint.getFillPath(path, &hidden);
401cb93a386Sopenharmony_ci            canvas->drawPath(hidden, fHiddenPaint);
402cb93a386Sopenharmony_ci        }
403cb93a386Sopenharmony_ci        if (fShowSkeleton) {
404cb93a386Sopenharmony_ci            canvas->drawPath(path, fSkeletonPaint);
405cb93a386Sopenharmony_ci        }
406cb93a386Sopenharmony_ci        canvas->drawPoints(SkCanvas::kPoints_PointMode, N, fPts, fPtsPaint);
407cb93a386Sopenharmony_ci    }
408cb93a386Sopenharmony_ci
409cb93a386Sopenharmony_ci    Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
410cb93a386Sopenharmony_ci        const SkScalar tol = 4;
411cb93a386Sopenharmony_ci        const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
412cb93a386Sopenharmony_ci        for (int i = 0; i < N; ++i) {
413cb93a386Sopenharmony_ci            if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
414cb93a386Sopenharmony_ci                return new Click([this, i](Click* c) {
415cb93a386Sopenharmony_ci                    fPts[i] = c->fCurr;
416cb93a386Sopenharmony_ci                    return true;
417cb93a386Sopenharmony_ci                });
418cb93a386Sopenharmony_ci            }
419cb93a386Sopenharmony_ci        }
420cb93a386Sopenharmony_ci        return nullptr;
421cb93a386Sopenharmony_ci    }
422cb93a386Sopenharmony_ci
423cb93a386Sopenharmony_ciprivate:
424cb93a386Sopenharmony_ci    using INHERITED = Sample;
425cb93a386Sopenharmony_ci};
426cb93a386Sopenharmony_ciDEF_SAMPLE( return new FatStroke; )
427cb93a386Sopenharmony_ci
428cb93a386Sopenharmony_cistatic int compute_parallel_to_base(const SkPoint pts[4], SkScalar t[2]) {
429cb93a386Sopenharmony_ci    // F = At^3 + Bt^2 + Ct + D
430cb93a386Sopenharmony_ci    SkVector A = pts[3] - pts[0] + (pts[1] - pts[2]) * 3.0f;
431cb93a386Sopenharmony_ci    SkVector B = (pts[0] - pts[1] - pts[1] + pts[2]) * 3.0f;
432cb93a386Sopenharmony_ci    SkVector C = (pts[1] - pts[0]) * 3.0f;
433cb93a386Sopenharmony_ci    SkVector DA = pts[3] - pts[0];
434cb93a386Sopenharmony_ci
435cb93a386Sopenharmony_ci    // F' = 3At^2 + 2Bt + C
436cb93a386Sopenharmony_ci    SkScalar a = 3 * A.cross(DA);
437cb93a386Sopenharmony_ci    SkScalar b = 2 * B.cross(DA);
438cb93a386Sopenharmony_ci    SkScalar c = C.cross(DA);
439cb93a386Sopenharmony_ci
440cb93a386Sopenharmony_ci    int n = SkFindUnitQuadRoots(a, b, c, t);
441cb93a386Sopenharmony_ci    SkString str;
442cb93a386Sopenharmony_ci    for (int i = 0; i < n; ++i) {
443cb93a386Sopenharmony_ci        str.appendf(" %g", t[i]);
444cb93a386Sopenharmony_ci    }
445cb93a386Sopenharmony_ci    SkDebugf("roots %s\n", str.c_str());
446cb93a386Sopenharmony_ci    return n;
447cb93a386Sopenharmony_ci}
448cb93a386Sopenharmony_ci
449cb93a386Sopenharmony_ciclass CubicCurve : public Sample {
450cb93a386Sopenharmony_cipublic:
451cb93a386Sopenharmony_ci    enum {
452cb93a386Sopenharmony_ci        N = 4
453cb93a386Sopenharmony_ci    };
454cb93a386Sopenharmony_ci    SkPoint fPts[N];
455cb93a386Sopenharmony_ci
456cb93a386Sopenharmony_ci    CubicCurve() {
457cb93a386Sopenharmony_ci        SkRandom rand;
458cb93a386Sopenharmony_ci        for (int i = 0; i < N; ++i) {
459cb93a386Sopenharmony_ci            fPts[i].fX = 20 + rand.nextUScalar1() * 640;
460cb93a386Sopenharmony_ci            fPts[i].fY = 20 + rand.nextUScalar1() * 480;
461cb93a386Sopenharmony_ci        }
462cb93a386Sopenharmony_ci    }
463cb93a386Sopenharmony_ci
464cb93a386Sopenharmony_ciprotected:
465cb93a386Sopenharmony_ci    SkString name() override { return SkString("CubicCurve"); }
466cb93a386Sopenharmony_ci
467cb93a386Sopenharmony_ci    void onDrawContent(SkCanvas* canvas) override {
468cb93a386Sopenharmony_ci        SkPaint paint;
469cb93a386Sopenharmony_ci        paint.setAntiAlias(true);
470cb93a386Sopenharmony_ci
471cb93a386Sopenharmony_ci        {
472cb93a386Sopenharmony_ci            SkPath path;
473cb93a386Sopenharmony_ci            path.moveTo(fPts[0]);
474cb93a386Sopenharmony_ci            path.cubicTo(fPts[1], fPts[2], fPts[3]);
475cb93a386Sopenharmony_ci            paint.setStyle(SkPaint::kStroke_Style);
476cb93a386Sopenharmony_ci            canvas->drawPath(path, paint);
477cb93a386Sopenharmony_ci        }
478cb93a386Sopenharmony_ci
479cb93a386Sopenharmony_ci        {
480cb93a386Sopenharmony_ci            paint.setColor(SK_ColorRED);
481cb93a386Sopenharmony_ci            SkScalar t[2];
482cb93a386Sopenharmony_ci            int n = compute_parallel_to_base(fPts, t);
483cb93a386Sopenharmony_ci            SkPoint loc;
484cb93a386Sopenharmony_ci            SkVector tan;
485cb93a386Sopenharmony_ci            for (int i = 0; i < n; ++i) {
486cb93a386Sopenharmony_ci                SkEvalCubicAt(fPts, t[i], &loc, &tan, nullptr);
487cb93a386Sopenharmony_ci                tan.setLength(30);
488cb93a386Sopenharmony_ci                canvas->drawLine(loc - tan, loc + tan, paint);
489cb93a386Sopenharmony_ci            }
490cb93a386Sopenharmony_ci            paint.setStrokeWidth(0.5f);
491cb93a386Sopenharmony_ci            canvas->drawLine(fPts[0], fPts[3], paint);
492cb93a386Sopenharmony_ci
493cb93a386Sopenharmony_ci            paint.setColor(SK_ColorBLUE);
494cb93a386Sopenharmony_ci            paint.setStrokeWidth(6);
495cb93a386Sopenharmony_ci            SkEvalCubicAt(fPts, 0.5f, &loc, nullptr, nullptr);
496cb93a386Sopenharmony_ci            canvas->drawPoint(loc, paint);
497cb93a386Sopenharmony_ci
498cb93a386Sopenharmony_ci            paint.setColor(0xFF008800);
499cb93a386Sopenharmony_ci            SkEvalCubicAt(fPts, 1.0f/3, &loc, nullptr, nullptr);
500cb93a386Sopenharmony_ci            canvas->drawPoint(loc, paint);
501cb93a386Sopenharmony_ci            SkEvalCubicAt(fPts, 2.0f/3, &loc, nullptr, nullptr);
502cb93a386Sopenharmony_ci            canvas->drawPoint(loc, paint);
503cb93a386Sopenharmony_ci
504cb93a386Sopenharmony_ci       //     n = SkFindCubicInflections(fPts, t);
505cb93a386Sopenharmony_ci       //     printf("inflections %d %g %g\n", n, t[0], t[1]);
506cb93a386Sopenharmony_ci        }
507cb93a386Sopenharmony_ci
508cb93a386Sopenharmony_ci        {
509cb93a386Sopenharmony_ci            paint.setStyle(SkPaint::kFill_Style);
510cb93a386Sopenharmony_ci            paint.setColor(SK_ColorRED);
511cb93a386Sopenharmony_ci            for (SkPoint p : fPts) {
512cb93a386Sopenharmony_ci                canvas->drawCircle(p.fX, p.fY, 8, paint);
513cb93a386Sopenharmony_ci            }
514cb93a386Sopenharmony_ci        }
515cb93a386Sopenharmony_ci    }
516cb93a386Sopenharmony_ci
517cb93a386Sopenharmony_ci    Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
518cb93a386Sopenharmony_ci        const SkScalar tol = 8;
519cb93a386Sopenharmony_ci        const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
520cb93a386Sopenharmony_ci        for (int i = 0; i < N; ++i) {
521cb93a386Sopenharmony_ci            if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
522cb93a386Sopenharmony_ci                return new Click([this, i](Click* c) {
523cb93a386Sopenharmony_ci                    fPts[i] = c->fCurr;
524cb93a386Sopenharmony_ci                    return true;
525cb93a386Sopenharmony_ci                });
526cb93a386Sopenharmony_ci            }
527cb93a386Sopenharmony_ci        }
528cb93a386Sopenharmony_ci        return this->INHERITED::onFindClickHandler(x, y, modi);
529cb93a386Sopenharmony_ci    }
530cb93a386Sopenharmony_ci
531cb93a386Sopenharmony_ciprivate:
532cb93a386Sopenharmony_ci    using INHERITED = Sample;
533cb93a386Sopenharmony_ci};
534cb93a386Sopenharmony_ciDEF_SAMPLE( return new CubicCurve; )
535cb93a386Sopenharmony_ci
536cb93a386Sopenharmony_cistatic SkPoint lerp(SkPoint a, SkPoint b, float t) {
537cb93a386Sopenharmony_ci    return a * (1 - t) + b * t;
538cb93a386Sopenharmony_ci}
539cb93a386Sopenharmony_ci
540cb93a386Sopenharmony_cistatic int find_max_deviation_cubic(const SkPoint src[4], SkScalar ts[2]) {
541cb93a386Sopenharmony_ci    // deviation = F' x (d - a) == 0, solve for t(s)
542cb93a386Sopenharmony_ci    // F = At^3 + Bt^2 + Ct + D
543cb93a386Sopenharmony_ci    // F' = 3At^2 + 2Bt + C
544cb93a386Sopenharmony_ci    // Z = d - a
545cb93a386Sopenharmony_ci    // F' x Z = 3(A x Z)t^2 + 2(B x Z)t + (C x Z)
546cb93a386Sopenharmony_ci    //
547cb93a386Sopenharmony_ci    SkVector A = src[3] + (src[1] - src[2]) * 3 - src[0];
548cb93a386Sopenharmony_ci    SkVector B = (src[2] - src[1] - src[1] + src[0]) * 3;
549cb93a386Sopenharmony_ci    SkVector C = (src[1] - src[0]) * 3;
550cb93a386Sopenharmony_ci    SkVector Z = src[3] - src[0];
551cb93a386Sopenharmony_ci    // now forumlate the quadratic coefficients we need to solve for t : F' x Z
552cb93a386Sopenharmony_ci    return SkFindUnitQuadRoots(3 * A.cross(Z), 2 * B.cross(Z), C.cross(Z), ts);
553cb93a386Sopenharmony_ci}
554cb93a386Sopenharmony_ci
555cb93a386Sopenharmony_ciclass CubicCurve2 : public Sample {
556cb93a386Sopenharmony_cipublic:
557cb93a386Sopenharmony_ci    enum {
558cb93a386Sopenharmony_ci        N = 7
559cb93a386Sopenharmony_ci    };
560cb93a386Sopenharmony_ci    SkPoint fPts[N];
561cb93a386Sopenharmony_ci    SkPoint* fQuad = fPts + 4;
562cb93a386Sopenharmony_ci    SkScalar fT = 0.5f;
563cb93a386Sopenharmony_ci    bool fShowSub = false;
564cb93a386Sopenharmony_ci    bool fShowFlatness = false;
565cb93a386Sopenharmony_ci    bool fShowInnerQuads = false;
566cb93a386Sopenharmony_ci    SkScalar fScale = 0.75;
567cb93a386Sopenharmony_ci
568cb93a386Sopenharmony_ci    CubicCurve2() {
569cb93a386Sopenharmony_ci        fPts[0] = { 90, 300 };
570cb93a386Sopenharmony_ci        fPts[1] = { 30, 60 };
571cb93a386Sopenharmony_ci        fPts[2] = { 250, 30 };
572cb93a386Sopenharmony_ci        fPts[3] = { 350, 200 };
573cb93a386Sopenharmony_ci
574cb93a386Sopenharmony_ci        fQuad[0] = fPts[0] + SkVector{ 300, 0};
575cb93a386Sopenharmony_ci        fQuad[1] = fPts[1] + SkVector{ 300, 0};
576cb93a386Sopenharmony_ci        fQuad[2] = fPts[2] + SkVector{ 300, 0};
577cb93a386Sopenharmony_ci    }
578cb93a386Sopenharmony_ci
579cb93a386Sopenharmony_ciprotected:
580cb93a386Sopenharmony_ci    SkString name() override { return SkString("CubicCurve2"); }
581cb93a386Sopenharmony_ci
582cb93a386Sopenharmony_ci    bool onChar(SkUnichar uni) override {
583cb93a386Sopenharmony_ci            switch (uni) {
584cb93a386Sopenharmony_ci                case 's': fShowSub = !fShowSub; break;
585cb93a386Sopenharmony_ci                case 'f': fShowFlatness = !fShowFlatness; break;
586cb93a386Sopenharmony_ci                case '-': fT -= 1.0f / 32; break;
587cb93a386Sopenharmony_ci                case '=': fT += 1.0f / 32; break;
588cb93a386Sopenharmony_ci                case 'q': fShowInnerQuads = !fShowInnerQuads; break;
589cb93a386Sopenharmony_ci                default: return false;
590cb93a386Sopenharmony_ci            }
591cb93a386Sopenharmony_ci            fT = std::min(1.0f, std::max(0.0f, fT));
592cb93a386Sopenharmony_ci            return true;
593cb93a386Sopenharmony_ci    }
594cb93a386Sopenharmony_ci
595cb93a386Sopenharmony_ci    static void Dot(SkCanvas* canvas, SkPoint p, SkScalar radius, SkColor c) {
596cb93a386Sopenharmony_ci        SkPaint paint;
597cb93a386Sopenharmony_ci        paint.setAntiAlias(true);
598cb93a386Sopenharmony_ci        paint.setColor(c);
599cb93a386Sopenharmony_ci        canvas->drawCircle(p.fX, p.fY, radius, paint);
600cb93a386Sopenharmony_ci    }
601cb93a386Sopenharmony_ci
602cb93a386Sopenharmony_ci    void showFrame(SkCanvas* canvas, const SkPoint pts[], int count, const SkPaint& p) {
603cb93a386Sopenharmony_ci        SkPaint paint(p);
604cb93a386Sopenharmony_ci        SkPoint storage[3 + 2 + 1];
605cb93a386Sopenharmony_ci        SkPoint* tmp = storage;
606cb93a386Sopenharmony_ci        const SkPoint* prev = pts;
607cb93a386Sopenharmony_ci        for (int n = count; n > 0; --n) {
608cb93a386Sopenharmony_ci            for (int i = 0; i < n; ++i) {
609cb93a386Sopenharmony_ci                canvas->drawLine(prev[i], prev[i+1], paint);
610cb93a386Sopenharmony_ci                tmp[i] = lerp(prev[i], prev[i+1], fT);
611cb93a386Sopenharmony_ci            }
612cb93a386Sopenharmony_ci            prev = tmp;
613cb93a386Sopenharmony_ci            tmp += n;
614cb93a386Sopenharmony_ci        }
615cb93a386Sopenharmony_ci
616cb93a386Sopenharmony_ci        paint.setColor(SK_ColorBLUE);
617cb93a386Sopenharmony_ci        paint.setStyle(SkPaint::kFill_Style);
618cb93a386Sopenharmony_ci        int n = tmp - storage;
619cb93a386Sopenharmony_ci        for (int i = 0; i < n; ++i) {
620cb93a386Sopenharmony_ci            Dot(canvas, storage[i], 4, SK_ColorBLUE);
621cb93a386Sopenharmony_ci        }
622cb93a386Sopenharmony_ci    }
623cb93a386Sopenharmony_ci
624cb93a386Sopenharmony_ci    void showFlattness(SkCanvas* canvas) {
625cb93a386Sopenharmony_ci        SkPaint paint;
626cb93a386Sopenharmony_ci        paint.setStyle(SkPaint::kStroke_Style);
627cb93a386Sopenharmony_ci        paint.setAntiAlias(true);
628cb93a386Sopenharmony_ci
629cb93a386Sopenharmony_ci        SkPaint paint2(paint);
630cb93a386Sopenharmony_ci        paint2.setColor(0xFF008800);
631cb93a386Sopenharmony_ci
632cb93a386Sopenharmony_ci        paint.setColor(0xFF888888);
633cb93a386Sopenharmony_ci        canvas->drawLine(fPts[0], fPts[3], paint);
634cb93a386Sopenharmony_ci        canvas->drawLine(fQuad[0], fQuad[2], paint);
635cb93a386Sopenharmony_ci
636cb93a386Sopenharmony_ci        paint.setColor(0xFF0000FF);
637cb93a386Sopenharmony_ci        SkPoint pts[2];
638cb93a386Sopenharmony_ci        pts[0] = (fQuad[0] + fQuad[1] + fQuad[1] + fQuad[2])*0.25;
639cb93a386Sopenharmony_ci        pts[1] = (fQuad[0] + fQuad[2]) * 0.5;
640cb93a386Sopenharmony_ci        canvas->drawLine(pts[0], pts[1], paint);
641cb93a386Sopenharmony_ci
642cb93a386Sopenharmony_ci        // cubic
643cb93a386Sopenharmony_ci
644cb93a386Sopenharmony_ci        SkVector v0 = (fPts[0] - fPts[1] - fPts[1] + fPts[2]) * fScale;
645cb93a386Sopenharmony_ci        SkVector v1 = (fPts[1] - fPts[2] - fPts[2] + fPts[3]) * fScale;
646cb93a386Sopenharmony_ci        SkVector v = (v0 + v1) * 0.5f;
647cb93a386Sopenharmony_ci
648cb93a386Sopenharmony_ci        SkPoint anchor;
649cb93a386Sopenharmony_ci        SkScalar ts[2];
650cb93a386Sopenharmony_ci        int n = find_max_deviation_cubic(fPts, ts);
651cb93a386Sopenharmony_ci        if (n > 0) {
652cb93a386Sopenharmony_ci            SkEvalCubicAt(fPts, ts[0], &anchor, nullptr, nullptr);
653cb93a386Sopenharmony_ci            canvas->drawLine(anchor, anchor + v, paint2);
654cb93a386Sopenharmony_ci            canvas->drawLine(anchor, anchor + v0, paint);
655cb93a386Sopenharmony_ci            if (n == 2) {
656cb93a386Sopenharmony_ci                SkEvalCubicAt(fPts, ts[1], &anchor, nullptr, nullptr);
657cb93a386Sopenharmony_ci                canvas->drawLine(anchor, anchor + v, paint2);
658cb93a386Sopenharmony_ci            }
659cb93a386Sopenharmony_ci            canvas->drawLine(anchor, anchor + v1, paint);
660cb93a386Sopenharmony_ci        }
661cb93a386Sopenharmony_ci        // not sure we can get here
662cb93a386Sopenharmony_ci    }
663cb93a386Sopenharmony_ci
664cb93a386Sopenharmony_ci    void showInnerQuads(SkCanvas* canvas) {
665cb93a386Sopenharmony_ci        auto draw_quad = [canvas](SkPoint a, SkPoint b, SkPoint c, SkColor color) {
666cb93a386Sopenharmony_ci            SkPaint paint;
667cb93a386Sopenharmony_ci            paint.setAntiAlias(true);
668cb93a386Sopenharmony_ci            paint.setStroke(true);
669cb93a386Sopenharmony_ci            paint.setColor(color);
670cb93a386Sopenharmony_ci
671cb93a386Sopenharmony_ci            canvas->drawPath(SkPathBuilder().moveTo(a).quadTo(b, c).detach(), paint);
672cb93a386Sopenharmony_ci        };
673cb93a386Sopenharmony_ci
674cb93a386Sopenharmony_ci        SkPoint p0 = SkEvalQuadAt(&fPts[0], fT),
675cb93a386Sopenharmony_ci                p1 = SkEvalQuadAt(&fPts[1], fT),
676cb93a386Sopenharmony_ci                p2 = lerp(p0, p1, fT);
677cb93a386Sopenharmony_ci
678cb93a386Sopenharmony_ci        draw_quad(fPts[0], fPts[1], fPts[2], SK_ColorRED);
679cb93a386Sopenharmony_ci        Dot(canvas, p0, 4, SK_ColorRED);
680cb93a386Sopenharmony_ci
681cb93a386Sopenharmony_ci        draw_quad(fPts[1], fPts[2], fPts[3], SK_ColorBLUE);
682cb93a386Sopenharmony_ci        Dot(canvas, p1, 4, SK_ColorBLUE);
683cb93a386Sopenharmony_ci
684cb93a386Sopenharmony_ci        SkPaint paint;
685cb93a386Sopenharmony_ci        paint.setAntiAlias(true);
686cb93a386Sopenharmony_ci        paint.setColor(0xFF008800);
687cb93a386Sopenharmony_ci        canvas->drawLine(p0, p1, paint);
688cb93a386Sopenharmony_ci        Dot(canvas, p2, 4, 0xFF00AA00);
689cb93a386Sopenharmony_ci    }
690cb93a386Sopenharmony_ci
691cb93a386Sopenharmony_ci    void onDrawContent(SkCanvas* canvas) override {
692cb93a386Sopenharmony_ci        SkPaint paint;
693cb93a386Sopenharmony_ci        paint.setAntiAlias(true);
694cb93a386Sopenharmony_ci
695cb93a386Sopenharmony_ci        {
696cb93a386Sopenharmony_ci            paint.setStyle(SkPaint::kStroke_Style);
697cb93a386Sopenharmony_ci            SkPath path;
698cb93a386Sopenharmony_ci            path.moveTo(fPts[0]);
699cb93a386Sopenharmony_ci            path.cubicTo(fPts[1], fPts[2], fPts[3]);
700cb93a386Sopenharmony_ci            path.moveTo(fQuad[0]);
701cb93a386Sopenharmony_ci            path.quadTo(fQuad[1], fQuad[2]);
702cb93a386Sopenharmony_ci            canvas->drawPath(path, paint);
703cb93a386Sopenharmony_ci        }
704cb93a386Sopenharmony_ci
705cb93a386Sopenharmony_ci        if (fShowSub) {
706cb93a386Sopenharmony_ci            paint.setColor(SK_ColorRED);
707cb93a386Sopenharmony_ci            paint.setStrokeWidth(1.7f);
708cb93a386Sopenharmony_ci            this->showFrame(canvas, fPts, 3, paint);
709cb93a386Sopenharmony_ci            this->showFrame(canvas, fQuad, 2, paint);
710cb93a386Sopenharmony_ci
711cb93a386Sopenharmony_ci            paint.setColor(SK_ColorBLACK);
712cb93a386Sopenharmony_ci            paint.setStyle(SkPaint::kFill_Style);
713cb93a386Sopenharmony_ci            SkFont font(nullptr, 20);
714cb93a386Sopenharmony_ci            canvas->drawString(SkStringPrintf("t = %g", fT), 20, 20, font, paint);
715cb93a386Sopenharmony_ci        }
716cb93a386Sopenharmony_ci
717cb93a386Sopenharmony_ci        if (fShowFlatness) {
718cb93a386Sopenharmony_ci            this->showFlattness(canvas);
719cb93a386Sopenharmony_ci        }
720cb93a386Sopenharmony_ci
721cb93a386Sopenharmony_ci        if (fShowInnerQuads) {
722cb93a386Sopenharmony_ci            this->showInnerQuads(canvas);
723cb93a386Sopenharmony_ci        }
724cb93a386Sopenharmony_ci
725cb93a386Sopenharmony_ci        paint.setColor(SK_ColorGRAY);
726cb93a386Sopenharmony_ci        paint.setStroke(true);
727cb93a386Sopenharmony_ci        canvas->drawPath(SkPathBuilder().addPolygon(fPts, 4, false).detach(), paint);
728cb93a386Sopenharmony_ci        canvas->drawPath(SkPathBuilder().addPolygon(fQuad, 3, false).detach(), paint);
729cb93a386Sopenharmony_ci
730cb93a386Sopenharmony_ci        for (SkPoint p : fPts) {
731cb93a386Sopenharmony_ci            Dot(canvas, p, 7, SK_ColorBLACK);
732cb93a386Sopenharmony_ci        }
733cb93a386Sopenharmony_ci
734cb93a386Sopenharmony_ci        if (false) {
735cb93a386Sopenharmony_ci            SkScalar ts[2];
736cb93a386Sopenharmony_ci            int n = SkFindCubicInflections(fPts, ts);
737cb93a386Sopenharmony_ci            for (int i = 0; i < n; ++i) {
738cb93a386Sopenharmony_ci                SkPoint p;
739cb93a386Sopenharmony_ci                SkEvalCubicAt(fPts, ts[i], &p, nullptr, nullptr);
740cb93a386Sopenharmony_ci                canvas->drawCircle(p.fX, p.fY, 3, paint);
741cb93a386Sopenharmony_ci            }
742cb93a386Sopenharmony_ci        }
743cb93a386Sopenharmony_ci
744cb93a386Sopenharmony_ci    }
745cb93a386Sopenharmony_ci
746cb93a386Sopenharmony_ci    Sample::Click* onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override {
747cb93a386Sopenharmony_ci        const SkScalar tol = 8;
748cb93a386Sopenharmony_ci        const SkRect r = SkRect::MakeXYWH(x - tol, y - tol, tol * 2, tol * 2);
749cb93a386Sopenharmony_ci        for (int i = 0; i < N; ++i) {
750cb93a386Sopenharmony_ci            if (r.intersects(SkRect::MakeXYWH(fPts[i].fX, fPts[i].fY, 1, 1))) {
751cb93a386Sopenharmony_ci                return new Click([this, i](Click* c) {
752cb93a386Sopenharmony_ci                    fPts[i] = c->fCurr;
753cb93a386Sopenharmony_ci                    return true;
754cb93a386Sopenharmony_ci                });
755cb93a386Sopenharmony_ci            }
756cb93a386Sopenharmony_ci        }
757cb93a386Sopenharmony_ci        return this->INHERITED::onFindClickHandler(x, y, modi);
758cb93a386Sopenharmony_ci    }
759cb93a386Sopenharmony_ci
760cb93a386Sopenharmony_ciprivate:
761cb93a386Sopenharmony_ci    using INHERITED = Sample;
762cb93a386Sopenharmony_ci};
763cb93a386Sopenharmony_ciDEF_SAMPLE( return new CubicCurve2; )
764cb93a386Sopenharmony_ci
765