1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2018 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/SkPaint.h"
12cb93a386Sopenharmony_ci#include "include/core/SkPath.h"
13cb93a386Sopenharmony_ci#include "include/core/SkPoint.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/SkTDArray.h"
20cb93a386Sopenharmony_ci#include "src/utils/SkPolyUtils.h"
21cb93a386Sopenharmony_ci#include "tools/ToolUtils.h"
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ci#include <functional>
24cb93a386Sopenharmony_ci#include <memory>
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_cistatic void create_ngon(int n, SkPoint* pts, SkScalar w, SkScalar h, SkPathDirection dir) {
27cb93a386Sopenharmony_ci    float angleStep = 360.0f / n, angle = 0.0f;
28cb93a386Sopenharmony_ci    if ((n % 2) == 1) {
29cb93a386Sopenharmony_ci        angle = angleStep/2.0f;
30cb93a386Sopenharmony_ci    }
31cb93a386Sopenharmony_ci    if (SkPathDirection::kCCW == dir) {
32cb93a386Sopenharmony_ci        angle = -angle;
33cb93a386Sopenharmony_ci        angleStep = -angleStep;
34cb93a386Sopenharmony_ci    }
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci    for (int i = 0; i < n; ++i) {
37cb93a386Sopenharmony_ci        pts[i].fX = -SkScalarSin(SkDegreesToRadians(angle)) * w;
38cb93a386Sopenharmony_ci        pts[i].fY =  SkScalarCos(SkDegreesToRadians(angle)) * h;
39cb93a386Sopenharmony_ci        angle += angleStep;
40cb93a386Sopenharmony_ci    }
41cb93a386Sopenharmony_ci}
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_cinamespace PolygonOffsetData {
44cb93a386Sopenharmony_ci// narrow rect
45cb93a386Sopenharmony_ciconst SkPoint gPoints0[] = {
46cb93a386Sopenharmony_ci    { -1.5f, -50.0f },
47cb93a386Sopenharmony_ci    { 1.5f, -50.0f },
48cb93a386Sopenharmony_ci    { 1.5f,  50.0f },
49cb93a386Sopenharmony_ci    { -1.5f,  50.0f }
50cb93a386Sopenharmony_ci};
51cb93a386Sopenharmony_ci// narrow rect on an angle
52cb93a386Sopenharmony_ciconst SkPoint gPoints1[] = {
53cb93a386Sopenharmony_ci    { -50.0f, -49.0f },
54cb93a386Sopenharmony_ci    { -49.0f, -50.0f },
55cb93a386Sopenharmony_ci    { 50.0f,  49.0f },
56cb93a386Sopenharmony_ci    { 49.0f,  50.0f }
57cb93a386Sopenharmony_ci};
58cb93a386Sopenharmony_ci// trap - narrow on top - wide on bottom
59cb93a386Sopenharmony_ciconst SkPoint gPoints2[] = {
60cb93a386Sopenharmony_ci    { -10.0f, -50.0f },
61cb93a386Sopenharmony_ci    { 10.0f, -50.0f },
62cb93a386Sopenharmony_ci    { 50.0f,  50.0f },
63cb93a386Sopenharmony_ci    { -50.0f,  50.0f }
64cb93a386Sopenharmony_ci};
65cb93a386Sopenharmony_ci// wide skewed rect
66cb93a386Sopenharmony_ciconst SkPoint gPoints3[] = {
67cb93a386Sopenharmony_ci    { -50.0f, -50.0f },
68cb93a386Sopenharmony_ci    { 0.0f, -50.0f },
69cb93a386Sopenharmony_ci    { 50.0f,  50.0f },
70cb93a386Sopenharmony_ci    { 0.0f,  50.0f }
71cb93a386Sopenharmony_ci};
72cb93a386Sopenharmony_ci// thin rect with colinear-ish lines
73cb93a386Sopenharmony_ciconst SkPoint gPoints4[] = {
74cb93a386Sopenharmony_ci    { -6.0f, -50.0f },
75cb93a386Sopenharmony_ci    { 4.0f, -50.0f },
76cb93a386Sopenharmony_ci    { 5.0f, -25.0f },
77cb93a386Sopenharmony_ci    { 6.0f,   0.0f },
78cb93a386Sopenharmony_ci    { 5.0f,  25.0f },
79cb93a386Sopenharmony_ci    { 4.0f,  50.0f },
80cb93a386Sopenharmony_ci    { -4.0f,  50.0f }
81cb93a386Sopenharmony_ci};
82cb93a386Sopenharmony_ci// degenerate
83cb93a386Sopenharmony_ciconst SkPoint gPoints5[] = {
84cb93a386Sopenharmony_ci    { -0.025f, -0.025f },
85cb93a386Sopenharmony_ci    { 0.025f, -0.025f },
86cb93a386Sopenharmony_ci    { 0.025f,  0.025f },
87cb93a386Sopenharmony_ci    { -0.025f,  0.025f }
88cb93a386Sopenharmony_ci};
89cb93a386Sopenharmony_ci// Quad with near coincident point
90cb93a386Sopenharmony_ciconst SkPoint gPoints6[] = {
91cb93a386Sopenharmony_ci    { -20.0f, -13.0f },
92cb93a386Sopenharmony_ci    { -20.0f, -13.05f },
93cb93a386Sopenharmony_ci    { 20.0f, -13.0f },
94cb93a386Sopenharmony_ci    { 20.0f,  27.0f }
95cb93a386Sopenharmony_ci};
96cb93a386Sopenharmony_ci// thin rect with colinear lines
97cb93a386Sopenharmony_ciconst SkPoint gPoints7[] = {
98cb93a386Sopenharmony_ci    { -10.0f, -50.0f },
99cb93a386Sopenharmony_ci    { 10.0f, -50.0f },
100cb93a386Sopenharmony_ci    { 10.0f, -20.0f },
101cb93a386Sopenharmony_ci    { 10.0f,   0.0f },
102cb93a386Sopenharmony_ci    { 10.0f,  35.0f },
103cb93a386Sopenharmony_ci    { 10.0f,  50.0f },
104cb93a386Sopenharmony_ci    { -10.0f,  50.0f }
105cb93a386Sopenharmony_ci};
106cb93a386Sopenharmony_ci// capped teardrop
107cb93a386Sopenharmony_ciconst SkPoint gPoints8[] = {
108cb93a386Sopenharmony_ci    { 50.00f,  50.00f },
109cb93a386Sopenharmony_ci    { 0.00f,  50.00f },
110cb93a386Sopenharmony_ci    { -15.45f,  47.55f },
111cb93a386Sopenharmony_ci    { -29.39f,  40.45f },
112cb93a386Sopenharmony_ci    { -40.45f,  29.39f },
113cb93a386Sopenharmony_ci    { -47.55f,  15.45f },
114cb93a386Sopenharmony_ci    { -50.00f,   0.00f },
115cb93a386Sopenharmony_ci    { -47.55f, -15.45f },
116cb93a386Sopenharmony_ci    { -40.45f, -29.39f },
117cb93a386Sopenharmony_ci    { -29.39f, -40.45f },
118cb93a386Sopenharmony_ci    { -15.45f, -47.55f },
119cb93a386Sopenharmony_ci    { 0.00f, -50.00f },
120cb93a386Sopenharmony_ci    { 50.00f, -50.00f }
121cb93a386Sopenharmony_ci};
122cb93a386Sopenharmony_ci// teardrop
123cb93a386Sopenharmony_ciconst SkPoint gPoints9[] = {
124cb93a386Sopenharmony_ci    { 4.39f,  40.45f },
125cb93a386Sopenharmony_ci    { -9.55f,  47.55f },
126cb93a386Sopenharmony_ci    { -25.00f,  50.00f },
127cb93a386Sopenharmony_ci    { -40.45f,  47.55f },
128cb93a386Sopenharmony_ci    { -54.39f,  40.45f },
129cb93a386Sopenharmony_ci    { -65.45f,  29.39f },
130cb93a386Sopenharmony_ci    { -72.55f,  15.45f },
131cb93a386Sopenharmony_ci    { -75.00f,   0.00f },
132cb93a386Sopenharmony_ci    { -72.55f, -15.45f },
133cb93a386Sopenharmony_ci    { -65.45f, -29.39f },
134cb93a386Sopenharmony_ci    { -54.39f, -40.45f },
135cb93a386Sopenharmony_ci    { -40.45f, -47.55f },
136cb93a386Sopenharmony_ci    { -25.0f,  -50.0f },
137cb93a386Sopenharmony_ci    { -9.55f, -47.55f },
138cb93a386Sopenharmony_ci    { 4.39f, -40.45f },
139cb93a386Sopenharmony_ci    { 75.00f,   0.00f }
140cb93a386Sopenharmony_ci};
141cb93a386Sopenharmony_ci// clipped triangle
142cb93a386Sopenharmony_ciconst SkPoint gPoints10[] = {
143cb93a386Sopenharmony_ci    { -10.0f, -50.0f },
144cb93a386Sopenharmony_ci    { 10.0f, -50.0f },
145cb93a386Sopenharmony_ci    { 50.0f,  31.0f },
146cb93a386Sopenharmony_ci    { 40.0f,  50.0f },
147cb93a386Sopenharmony_ci    { -40.0f,  50.0f },
148cb93a386Sopenharmony_ci    { -50.0f,  31.0f },
149cb93a386Sopenharmony_ci};
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci// tab
152cb93a386Sopenharmony_ciconst SkPoint gPoints11[] = {
153cb93a386Sopenharmony_ci    { -45, -25 },
154cb93a386Sopenharmony_ci    { 45, -25 },
155cb93a386Sopenharmony_ci    { 45, 25 },
156cb93a386Sopenharmony_ci    { 20, 25 },
157cb93a386Sopenharmony_ci    { 19.6157f, 25.f + 3.9018f },
158cb93a386Sopenharmony_ci    { 18.4776f, 25.f + 7.6537f },
159cb93a386Sopenharmony_ci    { 16.6294f, 25.f + 11.1114f },
160cb93a386Sopenharmony_ci    { 14.1421f, 25.f + 14.1421f },
161cb93a386Sopenharmony_ci    { 11.1114f, 25.f + 16.6294f },
162cb93a386Sopenharmony_ci    { 7.6537f, 25.f + 18.4776f },
163cb93a386Sopenharmony_ci    { 3.9018f, 25.f + 19.6157f },
164cb93a386Sopenharmony_ci    { 0, 45.f },
165cb93a386Sopenharmony_ci    { -3.9018f, 25.f + 19.6157f },
166cb93a386Sopenharmony_ci    { -7.6537f, 25.f + 18.4776f },
167cb93a386Sopenharmony_ci    { -11.1114f, 25.f + 16.6294f },
168cb93a386Sopenharmony_ci    { -14.1421f, 25.f + 14.1421f },
169cb93a386Sopenharmony_ci    { -16.6294f, 25.f + 11.1114f },
170cb93a386Sopenharmony_ci    { -18.4776f, 25.f + 7.6537f },
171cb93a386Sopenharmony_ci    { -19.6157f, 25.f + 3.9018f },
172cb93a386Sopenharmony_ci    { -20, 25 },
173cb93a386Sopenharmony_ci    { -45, 25 }
174cb93a386Sopenharmony_ci};
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci// star of david
177cb93a386Sopenharmony_ciconst SkPoint gPoints12[] = {
178cb93a386Sopenharmony_ci    { 0.0f, -50.0f },
179cb93a386Sopenharmony_ci    { 14.43f, -25.0f },
180cb93a386Sopenharmony_ci    { 43.30f, -25.0f },
181cb93a386Sopenharmony_ci    { 28.86f, 0.0f },
182cb93a386Sopenharmony_ci    { 43.30f, 25.0f },
183cb93a386Sopenharmony_ci    { 14.43f, 25.0f },
184cb93a386Sopenharmony_ci    { 0.0f, 50.0f },
185cb93a386Sopenharmony_ci    { -14.43f, 25.0f },
186cb93a386Sopenharmony_ci    { -43.30f, 25.0f },
187cb93a386Sopenharmony_ci    { -28.86f, 0.0f },
188cb93a386Sopenharmony_ci    { -43.30f, -25.0f },
189cb93a386Sopenharmony_ci    { -14.43f, -25.0f },
190cb93a386Sopenharmony_ci};
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci// notch
193cb93a386Sopenharmony_ciconst SkScalar kBottom = 25.f;
194cb93a386Sopenharmony_ciconst SkPoint gPoints13[] = {
195cb93a386Sopenharmony_ci    { -50, kBottom - 50.f },
196cb93a386Sopenharmony_ci    { 50, kBottom - 50.f },
197cb93a386Sopenharmony_ci    { 50, kBottom },
198cb93a386Sopenharmony_ci    { 20, kBottom },
199cb93a386Sopenharmony_ci    { 19.6157f, kBottom - 3.9018f },
200cb93a386Sopenharmony_ci    { 18.4776f, kBottom - 7.6537f },
201cb93a386Sopenharmony_ci    { 16.6294f, kBottom - 11.1114f },
202cb93a386Sopenharmony_ci    { 14.1421f, kBottom - 14.1421f },
203cb93a386Sopenharmony_ci    { 11.1114f, kBottom - 16.6294f },
204cb93a386Sopenharmony_ci    { 7.6537f, kBottom - 18.4776f },
205cb93a386Sopenharmony_ci    { 3.9018f, kBottom - 19.6157f },
206cb93a386Sopenharmony_ci    { 0, kBottom - 20.f },
207cb93a386Sopenharmony_ci    { -3.9018f, kBottom - 19.6157f },
208cb93a386Sopenharmony_ci    { -7.6537f, kBottom - 18.4776f },
209cb93a386Sopenharmony_ci    { -11.1114f, kBottom - 16.6294f },
210cb93a386Sopenharmony_ci    { -14.1421f, kBottom - 14.1421f },
211cb93a386Sopenharmony_ci    { -16.6294f, kBottom - 11.1114f },
212cb93a386Sopenharmony_ci    { -18.4776f, kBottom - 7.6537f },
213cb93a386Sopenharmony_ci    { -19.6157f, kBottom - 3.9018f },
214cb93a386Sopenharmony_ci    { -20, kBottom },
215cb93a386Sopenharmony_ci    { -50, kBottom }
216cb93a386Sopenharmony_ci};
217cb93a386Sopenharmony_ci
218cb93a386Sopenharmony_ci// crown
219cb93a386Sopenharmony_ciconst SkPoint gPoints14[] = {
220cb93a386Sopenharmony_ci    { -40, -39 },
221cb93a386Sopenharmony_ci    { 40, -39 },
222cb93a386Sopenharmony_ci    { 40, -20 },
223cb93a386Sopenharmony_ci    { 30, 40 },
224cb93a386Sopenharmony_ci    { 20, -20 },
225cb93a386Sopenharmony_ci    { 10, 40 },
226cb93a386Sopenharmony_ci    { 0, -20 },
227cb93a386Sopenharmony_ci    { -10, 40 },
228cb93a386Sopenharmony_ci    { -20, -20 },
229cb93a386Sopenharmony_ci    { -30, 40 },
230cb93a386Sopenharmony_ci    { -40, -20 }
231cb93a386Sopenharmony_ci};
232cb93a386Sopenharmony_ci
233cb93a386Sopenharmony_ci// dumbbell
234cb93a386Sopenharmony_ciconst SkPoint gPoints15[] = {
235cb93a386Sopenharmony_ci    { -26, -3 },
236cb93a386Sopenharmony_ci    { -24, -6.2f },
237cb93a386Sopenharmony_ci    { -22.5f, -8 },
238cb93a386Sopenharmony_ci    { -20, -9.9f },
239cb93a386Sopenharmony_ci    { -17.5f, -10.3f },
240cb93a386Sopenharmony_ci    { -15, -10.9f },
241cb93a386Sopenharmony_ci    { -12.5f, -10.2f },
242cb93a386Sopenharmony_ci    { -10, -9.7f },
243cb93a386Sopenharmony_ci    { -7.5f, -8.1f },
244cb93a386Sopenharmony_ci    { -5, -7.7f },
245cb93a386Sopenharmony_ci    { -2.5f, -7.4f },
246cb93a386Sopenharmony_ci    { 0, -7.7f },
247cb93a386Sopenharmony_ci    { 3, -9 },
248cb93a386Sopenharmony_ci    { 6.5f, -11.5f },
249cb93a386Sopenharmony_ci    { 10.6f, -14 },
250cb93a386Sopenharmony_ci    { 14, -15.2f },
251cb93a386Sopenharmony_ci    { 17, -15.5f },
252cb93a386Sopenharmony_ci    { 20, -15.2f },
253cb93a386Sopenharmony_ci    { 23.4f, -14 },
254cb93a386Sopenharmony_ci    { 27.5f, -11.5f },
255cb93a386Sopenharmony_ci    { 30, -8 },
256cb93a386Sopenharmony_ci    { 32, -4 },
257cb93a386Sopenharmony_ci    { 32.5f, 0 },
258cb93a386Sopenharmony_ci    { 32, 4 },
259cb93a386Sopenharmony_ci    { 30, 8 },
260cb93a386Sopenharmony_ci    { 27.5f, 11.5f },
261cb93a386Sopenharmony_ci    { 23.4f, 14 },
262cb93a386Sopenharmony_ci    { 20, 15.2f },
263cb93a386Sopenharmony_ci    { 17, 15.5f },
264cb93a386Sopenharmony_ci    { 14, 15.2f },
265cb93a386Sopenharmony_ci    { 10.6f, 14 },
266cb93a386Sopenharmony_ci    { 6.5f, 11.5f },
267cb93a386Sopenharmony_ci    { 3, 9 },
268cb93a386Sopenharmony_ci    { 0, 7.7f },
269cb93a386Sopenharmony_ci    { -2.5f, 7.4f },
270cb93a386Sopenharmony_ci    { -5, 7.7f },
271cb93a386Sopenharmony_ci    { -7.5f, 8.1f },
272cb93a386Sopenharmony_ci    { -10, 9.7f },
273cb93a386Sopenharmony_ci    { -12.5f, 10.2f },
274cb93a386Sopenharmony_ci    { -15, 10.9f },
275cb93a386Sopenharmony_ci    { -17.5f, 10.3f },
276cb93a386Sopenharmony_ci    { -20, 9.9f },
277cb93a386Sopenharmony_ci    { -22.5f, 8 },
278cb93a386Sopenharmony_ci    { -24, 6.2f },
279cb93a386Sopenharmony_ci    { -26, 3 },
280cb93a386Sopenharmony_ci    { -26.5f, 0 }
281cb93a386Sopenharmony_ci};
282cb93a386Sopenharmony_ci
283cb93a386Sopenharmony_ci// truncated dumbbell
284cb93a386Sopenharmony_ci// (checks winding computation in OffsetSimplePolygon)
285cb93a386Sopenharmony_ciconst SkPoint gPoints16[] = {
286cb93a386Sopenharmony_ci    { -15 + 3, -9 },
287cb93a386Sopenharmony_ci    { -15 + 6.5f, -11.5f },
288cb93a386Sopenharmony_ci    { -15 + 10.6f, -14 },
289cb93a386Sopenharmony_ci    { -15 + 14, -15.2f },
290cb93a386Sopenharmony_ci    { -15 + 17, -15.5f },
291cb93a386Sopenharmony_ci    { -15 + 20, -15.2f },
292cb93a386Sopenharmony_ci    { -15 + 23.4f, -14 },
293cb93a386Sopenharmony_ci    { -15 + 27.5f, -11.5f },
294cb93a386Sopenharmony_ci    { -15 + 30, -8 },
295cb93a386Sopenharmony_ci    { -15 + 32, -4 },
296cb93a386Sopenharmony_ci    { -15 + 32.5f, 0 },
297cb93a386Sopenharmony_ci    { -15 + 32, 4 },
298cb93a386Sopenharmony_ci    { -15 + 30, 8 },
299cb93a386Sopenharmony_ci    { -15 + 27.5f, 11.5f },
300cb93a386Sopenharmony_ci    { -15 + 23.4f, 14 },
301cb93a386Sopenharmony_ci    { -15 + 20, 15.2f },
302cb93a386Sopenharmony_ci    { -15 + 17, 15.5f },
303cb93a386Sopenharmony_ci    { -15 + 14, 15.2f },
304cb93a386Sopenharmony_ci    { -15 + 10.6f, 14 },
305cb93a386Sopenharmony_ci    { -15 + 6.5f, 11.5f },
306cb93a386Sopenharmony_ci    { -15 + 3, 9 },
307cb93a386Sopenharmony_ci};
308cb93a386Sopenharmony_ci
309cb93a386Sopenharmony_ci// square notch
310cb93a386Sopenharmony_ci// (to detect segment-segment intersection)
311cb93a386Sopenharmony_ciconst SkPoint gPoints17[] = {
312cb93a386Sopenharmony_ci    { -50, kBottom - 50.f },
313cb93a386Sopenharmony_ci    { 50, kBottom - 50.f },
314cb93a386Sopenharmony_ci    { 50, kBottom },
315cb93a386Sopenharmony_ci    { 20, kBottom },
316cb93a386Sopenharmony_ci    { 20, kBottom - 20.f },
317cb93a386Sopenharmony_ci    { -20, kBottom - 20.f },
318cb93a386Sopenharmony_ci    { -20, kBottom },
319cb93a386Sopenharmony_ci    { -50, kBottom }
320cb93a386Sopenharmony_ci};
321cb93a386Sopenharmony_ci
322cb93a386Sopenharmony_ci// box with Peano curve
323cb93a386Sopenharmony_ciconst SkPoint gPoints18[] = {
324cb93a386Sopenharmony_ci    { 0, 0 },
325cb93a386Sopenharmony_ci    { 0, -12 },
326cb93a386Sopenharmony_ci    { -6, -12 },
327cb93a386Sopenharmony_ci    { -6, 0 },
328cb93a386Sopenharmony_ci    { -12, 0 },
329cb93a386Sopenharmony_ci    { -12, -12},
330cb93a386Sopenharmony_ci    { -18, -12},
331cb93a386Sopenharmony_ci    { -18, 18},
332cb93a386Sopenharmony_ci    { -12, 18},
333cb93a386Sopenharmony_ci    {-12, 6},
334cb93a386Sopenharmony_ci    {-6, 6},
335cb93a386Sopenharmony_ci    {-6, 36},
336cb93a386Sopenharmony_ci    {-12, 36},
337cb93a386Sopenharmony_ci    {-12, 24},
338cb93a386Sopenharmony_ci    {-18, 24},
339cb93a386Sopenharmony_ci    {-18, 36},
340cb93a386Sopenharmony_ci    {-24, 36},
341cb93a386Sopenharmony_ci    {-24, 24},
342cb93a386Sopenharmony_ci    {-30, 24},
343cb93a386Sopenharmony_ci    {-30, 36},
344cb93a386Sopenharmony_ci    {-36, 36},
345cb93a386Sopenharmony_ci    {-36, 6},
346cb93a386Sopenharmony_ci    {-30, 6},
347cb93a386Sopenharmony_ci    {-30, 18},
348cb93a386Sopenharmony_ci    {-24, 18},
349cb93a386Sopenharmony_ci    {-24, -12},
350cb93a386Sopenharmony_ci    {-30, -12},
351cb93a386Sopenharmony_ci    {-30, 0},
352cb93a386Sopenharmony_ci    {-36, 0},
353cb93a386Sopenharmony_ci    {-36, -36},
354cb93a386Sopenharmony_ci    {36, -36},
355cb93a386Sopenharmony_ci    {36, 36},
356cb93a386Sopenharmony_ci    {12, 36},
357cb93a386Sopenharmony_ci    {12, 24},
358cb93a386Sopenharmony_ci    {6, 24},
359cb93a386Sopenharmony_ci    {6, 36},
360cb93a386Sopenharmony_ci    {0, 36},
361cb93a386Sopenharmony_ci    {0, 6},
362cb93a386Sopenharmony_ci    {6, 6},
363cb93a386Sopenharmony_ci    {6, 18},
364cb93a386Sopenharmony_ci    {12, 18},
365cb93a386Sopenharmony_ci    {12, -12},
366cb93a386Sopenharmony_ci    {6, -12},
367cb93a386Sopenharmony_ci    {6, 0}
368cb93a386Sopenharmony_ci};
369cb93a386Sopenharmony_ci
370cb93a386Sopenharmony_ci
371cb93a386Sopenharmony_ciconst SkPoint* gConvexPoints[] = {
372cb93a386Sopenharmony_ci    gPoints0, gPoints1, gPoints2, gPoints3, gPoints4, gPoints5, gPoints6,
373cb93a386Sopenharmony_ci    gPoints7, gPoints8, gPoints9, gPoints10,
374cb93a386Sopenharmony_ci};
375cb93a386Sopenharmony_ci
376cb93a386Sopenharmony_ciconst size_t gConvexSizes[] = {
377cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints0),
378cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints1),
379cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints2),
380cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints3),
381cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints4),
382cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints5),
383cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints6),
384cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints7),
385cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints8),
386cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints9),
387cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints10),
388cb93a386Sopenharmony_ci};
389cb93a386Sopenharmony_cistatic_assert(SK_ARRAY_COUNT(gConvexSizes) == SK_ARRAY_COUNT(gConvexPoints), "array_mismatch");
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_ciconst SkPoint* gSimplePoints[] = {
392cb93a386Sopenharmony_ci    gPoints0, gPoints1, gPoints2, gPoints4, gPoints5, gPoints7,
393cb93a386Sopenharmony_ci    gPoints8, gPoints11, gPoints12, gPoints13, gPoints14, gPoints15,
394cb93a386Sopenharmony_ci    gPoints16, gPoints17, gPoints18,
395cb93a386Sopenharmony_ci};
396cb93a386Sopenharmony_ci
397cb93a386Sopenharmony_ciconst size_t gSimpleSizes[] = {
398cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints0),
399cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints1),
400cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints2),
401cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints4),
402cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints5),
403cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints7),
404cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints8),
405cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints11),
406cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints12),
407cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints13),
408cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints14),
409cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints15),
410cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints16),
411cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints17),
412cb93a386Sopenharmony_ci    SK_ARRAY_COUNT(gPoints18),
413cb93a386Sopenharmony_ci};
414cb93a386Sopenharmony_cistatic_assert(SK_ARRAY_COUNT(gSimpleSizes) == SK_ARRAY_COUNT(gSimplePoints), "array_mismatch");
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_ci}  // namespace PolygonOffsetData
417cb93a386Sopenharmony_ci
418cb93a386Sopenharmony_cinamespace skiagm {
419cb93a386Sopenharmony_ci
420cb93a386Sopenharmony_ci// This GM is intended to exercise the offsetting of polygons
421cb93a386Sopenharmony_ci// When fVariableOffset is true it will skew the offset by x,
422cb93a386Sopenharmony_ci// to test perspective and other variable offset functions
423cb93a386Sopenharmony_ciclass PolygonOffsetGM : public GM {
424cb93a386Sopenharmony_cipublic:
425cb93a386Sopenharmony_ci    PolygonOffsetGM(bool convexOnly)
426cb93a386Sopenharmony_ci        : fConvexOnly(convexOnly) {
427cb93a386Sopenharmony_ci        this->setBGColor(0xFFFFFFFF);
428cb93a386Sopenharmony_ci    }
429cb93a386Sopenharmony_ci
430cb93a386Sopenharmony_ciprotected:
431cb93a386Sopenharmony_ci    SkString onShortName() override {
432cb93a386Sopenharmony_ci        if (fConvexOnly) {
433cb93a386Sopenharmony_ci            return SkString("convex-polygon-inset");
434cb93a386Sopenharmony_ci        } else {
435cb93a386Sopenharmony_ci            return SkString("simple-polygon-offset");
436cb93a386Sopenharmony_ci        }
437cb93a386Sopenharmony_ci    }
438cb93a386Sopenharmony_ci    SkISize onISize() override { return SkISize::Make(kGMWidth, kGMHeight); }
439cb93a386Sopenharmony_ci    bool runAsBench() const override { return true; }
440cb93a386Sopenharmony_ci
441cb93a386Sopenharmony_ci    static void GetConvexPolygon(int index, SkPathDirection dir,
442cb93a386Sopenharmony_ci                                 std::unique_ptr<SkPoint[]>* data, int* numPts) {
443cb93a386Sopenharmony_ci        if (index < (int)SK_ARRAY_COUNT(PolygonOffsetData::gConvexPoints)) {
444cb93a386Sopenharmony_ci            // manually specified
445cb93a386Sopenharmony_ci            *numPts = (int)PolygonOffsetData::gConvexSizes[index];
446cb93a386Sopenharmony_ci            *data = std::make_unique<SkPoint[]>(*numPts);
447cb93a386Sopenharmony_ci            if (SkPathDirection::kCW == dir) {
448cb93a386Sopenharmony_ci                for (int i = 0; i < *numPts; ++i) {
449cb93a386Sopenharmony_ci                    (*data)[i] = PolygonOffsetData::gConvexPoints[index][i];
450cb93a386Sopenharmony_ci                }
451cb93a386Sopenharmony_ci            } else {
452cb93a386Sopenharmony_ci                for (int i = 0; i < *numPts; ++i) {
453cb93a386Sopenharmony_ci                    (*data)[i] = PolygonOffsetData::gConvexPoints[index][*numPts - i - 1];
454cb93a386Sopenharmony_ci                }
455cb93a386Sopenharmony_ci            }
456cb93a386Sopenharmony_ci        } else {
457cb93a386Sopenharmony_ci            // procedurally generated
458cb93a386Sopenharmony_ci            SkScalar width = kMaxPathHeight / 2;
459cb93a386Sopenharmony_ci            SkScalar height = kMaxPathHeight / 2;
460cb93a386Sopenharmony_ci            int numPtsArray[] = { 3, 4, 5, 5, 6, 8, 8, 20, 100 };
461cb93a386Sopenharmony_ci
462cb93a386Sopenharmony_ci            size_t arrayIndex = index - SK_ARRAY_COUNT(PolygonOffsetData::gConvexPoints);
463cb93a386Sopenharmony_ci            SkASSERT(arrayIndex < SK_ARRAY_COUNT(numPtsArray));
464cb93a386Sopenharmony_ci            *numPts = numPtsArray[arrayIndex];
465cb93a386Sopenharmony_ci            if (arrayIndex == 3 || arrayIndex == 6) {
466cb93a386Sopenharmony_ci                // squashed pentagon and octagon
467cb93a386Sopenharmony_ci                width = kMaxPathHeight / 5;
468cb93a386Sopenharmony_ci            }
469cb93a386Sopenharmony_ci
470cb93a386Sopenharmony_ci            *data = std::make_unique<SkPoint[]>(*numPts);
471cb93a386Sopenharmony_ci
472cb93a386Sopenharmony_ci            create_ngon(*numPts, data->get(), width, height, dir);
473cb93a386Sopenharmony_ci        }
474cb93a386Sopenharmony_ci    }
475cb93a386Sopenharmony_ci
476cb93a386Sopenharmony_ci    static void GetSimplePolygon(int index, SkPathDirection dir,
477cb93a386Sopenharmony_ci                                 std::unique_ptr<SkPoint[]>* data, int* numPts) {
478cb93a386Sopenharmony_ci        if (index < (int)SK_ARRAY_COUNT(PolygonOffsetData::gSimplePoints)) {
479cb93a386Sopenharmony_ci            // manually specified
480cb93a386Sopenharmony_ci            *numPts = (int)PolygonOffsetData::gSimpleSizes[index];
481cb93a386Sopenharmony_ci            *data = std::make_unique<SkPoint[]>(*numPts);
482cb93a386Sopenharmony_ci            if (SkPathDirection::kCW == dir) {
483cb93a386Sopenharmony_ci                for (int i = 0; i < *numPts; ++i) {
484cb93a386Sopenharmony_ci                    (*data)[i] = PolygonOffsetData::gSimplePoints[index][i];
485cb93a386Sopenharmony_ci                }
486cb93a386Sopenharmony_ci            } else {
487cb93a386Sopenharmony_ci                for (int i = 0; i < *numPts; ++i) {
488cb93a386Sopenharmony_ci                    (*data)[i] = PolygonOffsetData::gSimplePoints[index][*numPts - i - 1];
489cb93a386Sopenharmony_ci                }
490cb93a386Sopenharmony_ci            }
491cb93a386Sopenharmony_ci        } else {
492cb93a386Sopenharmony_ci            // procedurally generated
493cb93a386Sopenharmony_ci            SkScalar width = kMaxPathHeight / 2;
494cb93a386Sopenharmony_ci            SkScalar height = kMaxPathHeight / 2;
495cb93a386Sopenharmony_ci            int numPtsArray[] = { 5, 7, 8, 20, 100 };
496cb93a386Sopenharmony_ci
497cb93a386Sopenharmony_ci            size_t arrayIndex = index - SK_ARRAY_COUNT(PolygonOffsetData::gSimplePoints);
498cb93a386Sopenharmony_ci            arrayIndex = std::min(arrayIndex, SK_ARRAY_COUNT(numPtsArray) - 1);
499cb93a386Sopenharmony_ci            SkASSERT(arrayIndex < SK_ARRAY_COUNT(numPtsArray));
500cb93a386Sopenharmony_ci            *numPts = numPtsArray[arrayIndex];
501cb93a386Sopenharmony_ci            // squash horizontally
502cb93a386Sopenharmony_ci            width = kMaxPathHeight / 5;
503cb93a386Sopenharmony_ci
504cb93a386Sopenharmony_ci            *data = std::make_unique<SkPoint[]>(*numPts);
505cb93a386Sopenharmony_ci
506cb93a386Sopenharmony_ci            create_ngon(*numPts, data->get(), width, height, dir);
507cb93a386Sopenharmony_ci        }
508cb93a386Sopenharmony_ci    }
509cb93a386Sopenharmony_ci    // Draw a single polygon with insets and potentially outsets
510cb93a386Sopenharmony_ci    void drawPolygon(SkCanvas* canvas, int index, SkPoint* position) {
511cb93a386Sopenharmony_ci
512cb93a386Sopenharmony_ci        SkPoint center;
513cb93a386Sopenharmony_ci        {
514cb93a386Sopenharmony_ci            std::unique_ptr<SkPoint[]> data(nullptr);
515cb93a386Sopenharmony_ci            int numPts;
516cb93a386Sopenharmony_ci            if (fConvexOnly) {
517cb93a386Sopenharmony_ci                GetConvexPolygon(index, SkPathDirection::kCW, &data, &numPts);
518cb93a386Sopenharmony_ci            } else {
519cb93a386Sopenharmony_ci                GetSimplePolygon(index, SkPathDirection::kCW, &data, &numPts);
520cb93a386Sopenharmony_ci            }
521cb93a386Sopenharmony_ci            SkRect bounds;
522cb93a386Sopenharmony_ci            bounds.setBounds(data.get(), numPts);
523cb93a386Sopenharmony_ci            if (!fConvexOnly) {
524cb93a386Sopenharmony_ci                bounds.outset(kMaxOutset, kMaxOutset);
525cb93a386Sopenharmony_ci            }
526cb93a386Sopenharmony_ci            if (position->fX + bounds.width() > kGMWidth) {
527cb93a386Sopenharmony_ci                position->fX = 0;
528cb93a386Sopenharmony_ci                position->fY += kMaxPathHeight;
529cb93a386Sopenharmony_ci            }
530cb93a386Sopenharmony_ci            center = { position->fX + SkScalarHalf(bounds.width()), position->fY };
531cb93a386Sopenharmony_ci            position->fX += bounds.width();
532cb93a386Sopenharmony_ci        }
533cb93a386Sopenharmony_ci
534cb93a386Sopenharmony_ci        const SkPathDirection dirs[2] = { SkPathDirection::kCW, SkPathDirection::kCCW };
535cb93a386Sopenharmony_ci        const float insets[] = { 5, 10, 15, 20, 25, 30, 35, 40 };
536cb93a386Sopenharmony_ci        const float offsets[] = { 2, 5, 9, 14, 20, 27, 35, 44, -2, -5, -9 };
537cb93a386Sopenharmony_ci        const SkColor colors[] = { 0xFF901313, 0xFF8D6214, 0xFF698B14, 0xFF1C8914,
538cb93a386Sopenharmony_ci                                   0xFF148755, 0xFF146C84, 0xFF142482, 0xFF4A1480,
539cb93a386Sopenharmony_ci                                   0xFF901313, 0xFF8D6214, 0xFF698B14 };
540cb93a386Sopenharmony_ci
541cb93a386Sopenharmony_ci        SkPaint paint;
542cb93a386Sopenharmony_ci        paint.setAntiAlias(true);
543cb93a386Sopenharmony_ci        paint.setStyle(SkPaint::kStroke_Style);
544cb93a386Sopenharmony_ci        paint.setStrokeWidth(1);
545cb93a386Sopenharmony_ci
546cb93a386Sopenharmony_ci        std::unique_ptr<SkPoint[]> data(nullptr);
547cb93a386Sopenharmony_ci        int numPts;
548cb93a386Sopenharmony_ci        if (fConvexOnly) {
549cb93a386Sopenharmony_ci            GetConvexPolygon(index, dirs[index % 2], &data, &numPts);
550cb93a386Sopenharmony_ci        } else {
551cb93a386Sopenharmony_ci            GetSimplePolygon(index, dirs[index % 2], &data, &numPts);
552cb93a386Sopenharmony_ci        }
553cb93a386Sopenharmony_ci
554cb93a386Sopenharmony_ci        {
555cb93a386Sopenharmony_ci            SkPath path;
556cb93a386Sopenharmony_ci            path.moveTo(data.get()[0]);
557cb93a386Sopenharmony_ci            for (int i = 1; i < numPts; ++i) {
558cb93a386Sopenharmony_ci                path.lineTo(data.get()[i]);
559cb93a386Sopenharmony_ci            }
560cb93a386Sopenharmony_ci            path.close();
561cb93a386Sopenharmony_ci            canvas->save();
562cb93a386Sopenharmony_ci            canvas->translate(center.fX, center.fY);
563cb93a386Sopenharmony_ci            canvas->drawPath(path, paint);
564cb93a386Sopenharmony_ci            canvas->restore();
565cb93a386Sopenharmony_ci        }
566cb93a386Sopenharmony_ci
567cb93a386Sopenharmony_ci        SkTDArray<SkPoint> offsetPoly;
568cb93a386Sopenharmony_ci        size_t count = fConvexOnly ? SK_ARRAY_COUNT(insets) : SK_ARRAY_COUNT(offsets);
569cb93a386Sopenharmony_ci        for (size_t i = 0; i < count; ++i) {
570cb93a386Sopenharmony_ci            SkScalar offset = fConvexOnly ? insets[i] : offsets[i];
571cb93a386Sopenharmony_ci            std::function<SkScalar(const SkPoint&)> offsetFunc;
572cb93a386Sopenharmony_ci
573cb93a386Sopenharmony_ci            bool result;
574cb93a386Sopenharmony_ci            if (fConvexOnly) {
575cb93a386Sopenharmony_ci                result = SkInsetConvexPolygon(data.get(), numPts, offset, &offsetPoly);
576cb93a386Sopenharmony_ci            } else {
577cb93a386Sopenharmony_ci                SkRect bounds;
578cb93a386Sopenharmony_ci                bounds.setBoundsCheck(data.get(), numPts);
579cb93a386Sopenharmony_ci                result = SkOffsetSimplePolygon(data.get(), numPts, bounds, offset, &offsetPoly);
580cb93a386Sopenharmony_ci            }
581cb93a386Sopenharmony_ci            if (result) {
582cb93a386Sopenharmony_ci                SkPath path;
583cb93a386Sopenharmony_ci                path.moveTo(offsetPoly[0]);
584cb93a386Sopenharmony_ci                for (int j = 1; j < offsetPoly.count(); ++j) {
585cb93a386Sopenharmony_ci                    path.lineTo(offsetPoly[j]);
586cb93a386Sopenharmony_ci                }
587cb93a386Sopenharmony_ci                path.close();
588cb93a386Sopenharmony_ci
589cb93a386Sopenharmony_ci                paint.setColor(ToolUtils::color_to_565(colors[i]));
590cb93a386Sopenharmony_ci                canvas->save();
591cb93a386Sopenharmony_ci                canvas->translate(center.fX, center.fY);
592cb93a386Sopenharmony_ci                canvas->drawPath(path, paint);
593cb93a386Sopenharmony_ci                canvas->restore();
594cb93a386Sopenharmony_ci            }
595cb93a386Sopenharmony_ci        }
596cb93a386Sopenharmony_ci    }
597cb93a386Sopenharmony_ci
598cb93a386Sopenharmony_ci    void onDraw(SkCanvas* canvas) override {
599cb93a386Sopenharmony_ci        // the right edge of the last drawn path
600cb93a386Sopenharmony_ci        SkPoint offset = { 0, SkScalarHalf(kMaxPathHeight) };
601cb93a386Sopenharmony_ci        if (!fConvexOnly) {
602cb93a386Sopenharmony_ci            offset.fY += kMaxOutset;
603cb93a386Sopenharmony_ci        }
604cb93a386Sopenharmony_ci
605cb93a386Sopenharmony_ci        for (int i = 0; i < kNumPaths; ++i) {
606cb93a386Sopenharmony_ci            this->drawPolygon(canvas, i, &offset);
607cb93a386Sopenharmony_ci        }
608cb93a386Sopenharmony_ci    }
609cb93a386Sopenharmony_ci
610cb93a386Sopenharmony_ciprivate:
611cb93a386Sopenharmony_ci    inline static constexpr int kNumPaths = 20;
612cb93a386Sopenharmony_ci    inline static constexpr int kMaxPathHeight = 100;
613cb93a386Sopenharmony_ci    inline static constexpr int kMaxOutset = 16;
614cb93a386Sopenharmony_ci    inline static constexpr int kGMWidth = 512;
615cb93a386Sopenharmony_ci    inline static constexpr int kGMHeight = 512;
616cb93a386Sopenharmony_ci
617cb93a386Sopenharmony_ci    bool fConvexOnly;
618cb93a386Sopenharmony_ci
619cb93a386Sopenharmony_ci    using INHERITED = GM;
620cb93a386Sopenharmony_ci};
621cb93a386Sopenharmony_ci
622cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
623cb93a386Sopenharmony_ci
624cb93a386Sopenharmony_ciDEF_GM(return new PolygonOffsetGM(true);)
625cb93a386Sopenharmony_ciDEF_GM(return new PolygonOffsetGM(false);)
626cb93a386Sopenharmony_ci}  // namespace skiagm
627