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 "gm/gm.h"
9cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h"
10cb93a386Sopenharmony_ci#include "include/core/SkColor.h"
11cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h"
12cb93a386Sopenharmony_ci#include "include/core/SkPaint.h"
13cb93a386Sopenharmony_ci#include "include/core/SkPathBuilder.h"
14cb93a386Sopenharmony_ci#include "include/core/SkRect.h"
15cb93a386Sopenharmony_ci#include "include/core/SkScalar.h"
16cb93a386Sopenharmony_ci#include "include/core/SkSize.h"
17cb93a386Sopenharmony_ci#include "include/core/SkString.h"
18cb93a386Sopenharmony_ci#include "include/core/SkTypes.h"
19cb93a386Sopenharmony_ci#include "include/private/SkNoncopyable.h"
20cb93a386Sopenharmony_ci#include "include/private/SkTArray.h"
21cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h"
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_cinamespace {
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_ciclass SkDoOnce : SkNoncopyable {
26cb93a386Sopenharmony_cipublic:
27cb93a386Sopenharmony_ci    SkDoOnce() { fDidOnce = false; }
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci    bool needToDo() const { return !fDidOnce; }
30cb93a386Sopenharmony_ci    bool alreadyDone() const { return fDidOnce; }
31cb93a386Sopenharmony_ci    void accomplished() {
32cb93a386Sopenharmony_ci        SkASSERT(!fDidOnce);
33cb93a386Sopenharmony_ci        fDidOnce = true;
34cb93a386Sopenharmony_ci    }
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ciprivate:
37cb93a386Sopenharmony_ci    bool fDidOnce;
38cb93a386Sopenharmony_ci};
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ciclass ConvexPathsGM : public skiagm::GM {
41cb93a386Sopenharmony_ci    SkDoOnce fOnce;
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci    void onOnceBeforeDraw() override { this->setBGColor(0xFF000000); }
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci    SkString onShortName() override { return SkString("convexpaths"); }
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci
48cb93a386Sopenharmony_ci    SkISize onISize() override { return {1200, 1100}; }
49cb93a386Sopenharmony_ci
50cb93a386Sopenharmony_ci    void makePaths() {
51cb93a386Sopenharmony_ci        if (fOnce.alreadyDone()) {
52cb93a386Sopenharmony_ci            return;
53cb93a386Sopenharmony_ci        }
54cb93a386Sopenharmony_ci        fOnce.accomplished();
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci        SkPathBuilder b;
57cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(0, 0)
58cb93a386Sopenharmony_ci                          .quadTo(50, 100, 0, 100)
59cb93a386Sopenharmony_ci                          .lineTo(0, 0)
60cb93a386Sopenharmony_ci                          .detach());
61cb93a386Sopenharmony_ci
62cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(0, 50)
63cb93a386Sopenharmony_ci                          .quadTo(50, 0, 100, 50)
64cb93a386Sopenharmony_ci                          .quadTo(50, 100, 0, 50)
65cb93a386Sopenharmony_ci                          .detach());
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ci        fPaths.push_back(SkPath::Rect({0, 0, 100, 100}, SkPathDirection::kCW));
68cb93a386Sopenharmony_ci        fPaths.push_back(SkPath::Rect({0, 0, 100, 100}, SkPathDirection::kCCW));
69cb93a386Sopenharmony_ci        fPaths.push_back(SkPath::Circle(50, 50, 50, SkPathDirection::kCW));
70cb93a386Sopenharmony_ci        fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 50, 100), SkPathDirection::kCW));
71cb93a386Sopenharmony_ci        fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 100, 5), SkPathDirection::kCCW));
72cb93a386Sopenharmony_ci        fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 1, 100), SkPathDirection::kCCW));
73cb93a386Sopenharmony_ci        fPaths.push_back(SkPath::RRect(SkRRect::MakeRectXY({0, 0, 100, 100}, 40, 20),
74cb93a386Sopenharmony_ci                                       SkPathDirection::kCW));
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci        // large number of points
77cb93a386Sopenharmony_ci        enum {
78cb93a386Sopenharmony_ci            kLength = 100,
79cb93a386Sopenharmony_ci            kPtsPerSide = (1 << 12),
80cb93a386Sopenharmony_ci        };
81cb93a386Sopenharmony_ci        b.moveTo(0, 0);
82cb93a386Sopenharmony_ci        for (int i = 1; i < kPtsPerSide; ++i) { // skip the first point due to moveTo.
83cb93a386Sopenharmony_ci            b.lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, 0);
84cb93a386Sopenharmony_ci        }
85cb93a386Sopenharmony_ci        for (int i = 0; i < kPtsPerSide; ++i) {
86cb93a386Sopenharmony_ci            b.lineTo(kLength, kLength * SkIntToScalar(i) / kPtsPerSide);
87cb93a386Sopenharmony_ci        }
88cb93a386Sopenharmony_ci        for (int i = kPtsPerSide; i > 0; --i) {
89cb93a386Sopenharmony_ci            b.lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, kLength);
90cb93a386Sopenharmony_ci        }
91cb93a386Sopenharmony_ci        for (int i = kPtsPerSide; i > 0; --i) {
92cb93a386Sopenharmony_ci            b.lineTo(0, kLength * SkIntToScalar(i) / kPtsPerSide);
93cb93a386Sopenharmony_ci        }
94cb93a386Sopenharmony_ci        fPaths.push_back(b.detach());
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ci        // shallow diagonals
97cb93a386Sopenharmony_ci        fPaths.push_back(SkPath::Polygon({{0,0}, {100,1}, {98,100}, {3,96}}, false));
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci        fPaths.push_back(b.arcTo(SkRect::MakeXYWH(0, 0, 50, 100), 25, 130, false)
100cb93a386Sopenharmony_ci                          .detach());
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ci        // cubics
103cb93a386Sopenharmony_ci        fPaths.push_back(b.cubicTo(  1,  1, 10,  90, 0, 100).detach());
104cb93a386Sopenharmony_ci        fPaths.push_back(b.cubicTo(100, 50, 20, 100, 0,   0).detach());
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci        // path that has a cubic with a repeated first control point and
107cb93a386Sopenharmony_ci        // a repeated last control point.
108cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(10, 10)
109cb93a386Sopenharmony_ci                          .cubicTo(10, 10, 10, 0, 20, 0)
110cb93a386Sopenharmony_ci                          .lineTo(40, 0)
111cb93a386Sopenharmony_ci                          .cubicTo(40, 0, 50, 0, 50, 10)
112cb93a386Sopenharmony_ci                          .detach());
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_ci        // path that has two cubics with repeated middle control points.
115cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(10, 10)
116cb93a386Sopenharmony_ci                          .cubicTo(10, 0, 10, 0, 20, 0)
117cb93a386Sopenharmony_ci                          .lineTo(40, 0)
118cb93a386Sopenharmony_ci                          .cubicTo(50, 0, 50, 0, 50, 10)
119cb93a386Sopenharmony_ci                          .detach());
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ci        // cubic where last three points are almost a line
122cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(0, 228.0f/8)
123cb93a386Sopenharmony_ci                          .cubicTo( 628.0f/ 8,  82.0f/8,
124cb93a386Sopenharmony_ci                                   1255.0f/ 8, 141.0f/8,
125cb93a386Sopenharmony_ci                                   1883.0f/ 8, 202.0f/8)
126cb93a386Sopenharmony_ci                          .detach());
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_ci        // flat cubic where the at end point tangents both point outward.
129cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(10, 0)
130cb93a386Sopenharmony_ci                          .cubicTo(0, 1, 30, 1, 20, 0)
131cb93a386Sopenharmony_ci                          .detach());
132cb93a386Sopenharmony_ci
133cb93a386Sopenharmony_ci        // flat cubic where initial tangent is in, end tangent out
134cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(0, 0)
135cb93a386Sopenharmony_ci                          .cubicTo(10, 1, 30, 1, 20, 0)
136cb93a386Sopenharmony_ci                          .detach());
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ci        // flat cubic where initial tangent is out, end tangent in
139cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(10, 0)
140cb93a386Sopenharmony_ci                          .cubicTo(0, 1, 20, 1, 30, 0)
141cb93a386Sopenharmony_ci                          .detach());
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci        // triangle where one edge is a degenerate quad
144cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(8.59375f, 45)
145cb93a386Sopenharmony_ci                          .quadTo(16.9921875f,   45,
146cb93a386Sopenharmony_ci                                  31.25f,        45)
147cb93a386Sopenharmony_ci                          .lineTo(100,          100)
148cb93a386Sopenharmony_ci                          .lineTo(8.59375f,      45)
149cb93a386Sopenharmony_ci                          .detach());
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci        // triangle where one edge is a quad with a repeated point
152cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(0, 25)
153cb93a386Sopenharmony_ci                          .lineTo(50, 0)
154cb93a386Sopenharmony_ci                          .quadTo(50, 50, 50, 50)
155cb93a386Sopenharmony_ci                          .detach());
156cb93a386Sopenharmony_ci
157cb93a386Sopenharmony_ci        // triangle where one edge is a cubic with a 2x repeated point
158cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(0, 25)
159cb93a386Sopenharmony_ci                          .lineTo(50, 0)
160cb93a386Sopenharmony_ci                          .cubicTo(50, 0, 50, 50, 50, 50)
161cb93a386Sopenharmony_ci                          .detach());
162cb93a386Sopenharmony_ci
163cb93a386Sopenharmony_ci        // triangle where one edge is a quad with a nearly repeated point
164cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(0, 25)
165cb93a386Sopenharmony_ci                          .lineTo(50, 0)
166cb93a386Sopenharmony_ci                          .quadTo(50, 49.95f, 50, 50)
167cb93a386Sopenharmony_ci                          .detach());
168cb93a386Sopenharmony_ci
169cb93a386Sopenharmony_ci        // triangle where one edge is a cubic with a 3x nearly repeated point
170cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(0, 25)
171cb93a386Sopenharmony_ci                          .lineTo(50, 0)
172cb93a386Sopenharmony_ci                          .cubicTo(50, 49.95f, 50, 49.97f, 50, 50)
173cb93a386Sopenharmony_ci                          .detach());
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_ci        // triangle where there is a point degenerate cubic at one corner
176cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(0, 25)
177cb93a386Sopenharmony_ci                          .lineTo(50, 0)
178cb93a386Sopenharmony_ci                          .lineTo(50, 50)
179cb93a386Sopenharmony_ci                          .cubicTo(50, 50, 50, 50, 50, 50)
180cb93a386Sopenharmony_ci                          .detach());
181cb93a386Sopenharmony_ci
182cb93a386Sopenharmony_ci        // point line
183cb93a386Sopenharmony_ci        fPaths.push_back(SkPath::Line({50, 50}, {50, 50}));
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci        // point quad
186cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(50, 50)
187cb93a386Sopenharmony_ci                          .quadTo(50, 50, 50, 50)
188cb93a386Sopenharmony_ci                          .detach());
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ci        // point cubic
191cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(50, 50)
192cb93a386Sopenharmony_ci                          .cubicTo(50, 50, 50, 50, 50, 50)
193cb93a386Sopenharmony_ci                          .detach());
194cb93a386Sopenharmony_ci
195cb93a386Sopenharmony_ci        // moveTo only paths
196cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(0, 0)
197cb93a386Sopenharmony_ci                          .moveTo(0, 0)
198cb93a386Sopenharmony_ci                          .moveTo(1, 1)
199cb93a386Sopenharmony_ci                          .moveTo(1, 1)
200cb93a386Sopenharmony_ci                          .moveTo(10, 10)
201cb93a386Sopenharmony_ci                          .detach());
202cb93a386Sopenharmony_ci
203cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(0, 0)
204cb93a386Sopenharmony_ci                          .moveTo(0, 0)
205cb93a386Sopenharmony_ci                          .detach());
206cb93a386Sopenharmony_ci
207cb93a386Sopenharmony_ci        // line degenerate
208cb93a386Sopenharmony_ci        fPaths.push_back(b.lineTo(100, 100).detach());
209cb93a386Sopenharmony_ci        fPaths.push_back(b.quadTo(100, 100, 0, 0).detach());
210cb93a386Sopenharmony_ci        fPaths.push_back(b.quadTo(100, 100, 50, 50).detach());
211cb93a386Sopenharmony_ci        fPaths.push_back(b.quadTo(50, 50, 100, 100).detach());
212cb93a386Sopenharmony_ci        fPaths.push_back(b.cubicTo(0, 0, 0, 0, 100, 100).detach());
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ci        // skbug.com/8928
215cb93a386Sopenharmony_ci        fPaths.push_back(b.moveTo(16.875f, 192.594f)
216cb93a386Sopenharmony_ci                          .cubicTo(45.625f, 192.594f, 74.375f, 192.594f, 103.125f, 192.594f)
217cb93a386Sopenharmony_ci                          .cubicTo(88.75f, 167.708f, 74.375f, 142.823f, 60, 117.938f)
218cb93a386Sopenharmony_ci                          .cubicTo(45.625f, 142.823f, 31.25f, 167.708f, 16.875f, 192.594f)
219cb93a386Sopenharmony_ci                          .close()
220cb93a386Sopenharmony_ci                          .detach());
221cb93a386Sopenharmony_ci        SkMatrix m;
222cb93a386Sopenharmony_ci        m.setAll(0.1f, 0, -1, 0, 0.115207f, -2.64977f, 0, 0, 1);
223cb93a386Sopenharmony_ci        fPaths.back().transform(m);
224cb93a386Sopenharmony_ci
225cb93a386Sopenharmony_ci        // small circle. This is listed last so that it has device coords far
226cb93a386Sopenharmony_ci        // from the origin (small area relative to x,y values).
227cb93a386Sopenharmony_ci        fPaths.push_back(SkPath::Circle(0, 0, 1.2f));
228cb93a386Sopenharmony_ci    }
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_ci    void onDraw(SkCanvas* canvas) override {
231cb93a386Sopenharmony_ci        this->makePaths();
232cb93a386Sopenharmony_ci
233cb93a386Sopenharmony_ci        SkPaint paint;
234cb93a386Sopenharmony_ci        paint.setAntiAlias(true);
235cb93a386Sopenharmony_ci        SkRandom rand;
236cb93a386Sopenharmony_ci        canvas->translate(20, 20);
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_ci        // As we've added more paths this has gotten pretty big. Scale the whole thing down.
239cb93a386Sopenharmony_ci        canvas->scale(2.0f/3, 2.0f/3);
240cb93a386Sopenharmony_ci
241cb93a386Sopenharmony_ci        for (int i = 0; i < fPaths.count(); ++i) {
242cb93a386Sopenharmony_ci            canvas->save();
243cb93a386Sopenharmony_ci            // position the path, and make it at off-integer coords.
244cb93a386Sopenharmony_ci            canvas->translate(200.0f * (i % 5) + 1.0f/10,
245cb93a386Sopenharmony_ci                              200.0f * (i / 5) + 9.0f/10);
246cb93a386Sopenharmony_ci            SkColor color = rand.nextU();
247cb93a386Sopenharmony_ci            color |= 0xff000000;
248cb93a386Sopenharmony_ci            paint.setColor(color);
249cb93a386Sopenharmony_ci#if 0       // This hitting on 32bit Linux builds for some paths. Temporarily disabling while it is
250cb93a386Sopenharmony_ci            // debugged.
251cb93a386Sopenharmony_ci            SkASSERT(fPaths[i].isConvex());
252cb93a386Sopenharmony_ci#endif
253cb93a386Sopenharmony_ci            canvas->drawPath(fPaths[i], paint);
254cb93a386Sopenharmony_ci            canvas->restore();
255cb93a386Sopenharmony_ci        }
256cb93a386Sopenharmony_ci    }
257cb93a386Sopenharmony_ci
258cb93a386Sopenharmony_ci    SkTArray<SkPath> fPaths;
259cb93a386Sopenharmony_ci};
260cb93a386Sopenharmony_ci}  // namespace
261cb93a386Sopenharmony_ci
262cb93a386Sopenharmony_ciDEF_GM( return new ConvexPathsGM; )
263