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