blob: 9f902bb897f99ca506f9cc409567305c9703c5aa [file] [log] [blame]
benjaminwagnerec4d4d72016-03-25 12:59:53 -07001/*
2 * Copyright 2014 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 "include/core/SkPaint.h"
9#include "include/core/SkPath.h"
10#include "include/core/SkTime.h"
11#include "include/utils/SkRandom.h"
12#include "src/core/SkPointPriv.h"
13#include "src/core/SkStrokerPriv.h"
14#include "src/pathops/SkPathOpsCubic.h"
15#include "tests/PathOpsCubicIntersectionTestData.h"
16#include "tests/PathOpsQuadIntersectionTestData.h"
17#include "tests/Test.h"
18#include "tools/flags/CommandLineFlags.h"
caryclarkfeff7d22014-10-09 05:36:03 -070019
Mike Klein84836b72019-03-21 11:31:36 -050020static DEFINE_bool(timeout, true, "run until alloted time expires");
caryclarkfeff7d22014-10-09 05:36:03 -070021
22#define MS_TEST_DURATION 10
23
24const SkScalar widths[] = {-FLT_MAX, -1, -0.1f, -FLT_EPSILON, 0, FLT_EPSILON,
25 0.0000001f, 0.000001f, 0.00001f, 0.0001f, 0.001f, 0.01f,
26 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 1, 1.1f, 2, 10, 10e2f, 10e3f, 10e4f, 10e5f, 10e6f, 10e7f,
27 10e8f, 10e9f, 10e10f, 10e20f, FLT_MAX };
28size_t widths_count = SK_ARRAY_COUNT(widths);
29
30static void pathTest(const SkPath& path) {
31 SkPaint p;
benjaminwagnerec4d4d72016-03-25 12:59:53 -070032 SkPath fill;
caryclarkfeff7d22014-10-09 05:36:03 -070033 p.setStyle(SkPaint::kStroke_Style);
34 for (size_t index = 0; index < widths_count; ++index) {
35 p.setStrokeWidth(widths[index]);
36 p.getFillPath(path, &fill);
37 }
38}
39
40static void cubicTest(const SkPoint c[4]) {
benjaminwagnerec4d4d72016-03-25 12:59:53 -070041 SkPath path;
42 path.moveTo(c[0].fX, c[0].fY);
43 path.cubicTo(c[1].fX, c[1].fY, c[2].fX, c[2].fY, c[3].fX, c[3].fY);
44 pathTest(path);
caryclarkfeff7d22014-10-09 05:36:03 -070045}
46
47static void quadTest(const SkPoint c[3]) {
benjaminwagnerec4d4d72016-03-25 12:59:53 -070048 SkPath path;
49 path.moveTo(c[0].fX, c[0].fY);
50 path.quadTo(c[1].fX, c[1].fY, c[2].fX, c[2].fY);
51 pathTest(path);
caryclarkfeff7d22014-10-09 05:36:03 -070052}
53
caryclarka35ab3e2016-10-20 08:32:18 -070054static void cubicSetTest(const CubicPts* dCubic, size_t count) {
benjaminwagnerec4d4d72016-03-25 12:59:53 -070055 skiatest::Timer timer;
56 for (size_t index = 0; index < count; ++index) {
caryclarka35ab3e2016-10-20 08:32:18 -070057 const CubicPts& dPts = dCubic[index];
58 SkDCubic d;
59 d.debugSet(dPts.fPts);
benjaminwagnerec4d4d72016-03-25 12:59:53 -070060 SkPoint c[4] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
caryclarkfeff7d22014-10-09 05:36:03 -070061 {(float) d[2].fX, (float) d[2].fY}, {(float) d[3].fX, (float) d[3].fY} };
benjaminwagnerec4d4d72016-03-25 12:59:53 -070062 cubicTest(c);
63 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
caryclarkfeff7d22014-10-09 05:36:03 -070064 return;
65 }
benjaminwagnerec4d4d72016-03-25 12:59:53 -070066 }
caryclarkfeff7d22014-10-09 05:36:03 -070067}
68
caryclarka35ab3e2016-10-20 08:32:18 -070069static void cubicPairSetTest(const CubicPts dCubic[][2], size_t count) {
benjaminwagnerec4d4d72016-03-25 12:59:53 -070070 skiatest::Timer timer;
71 for (size_t index = 0; index < count; ++index) {
72 for (int pair = 0; pair < 2; ++pair) {
caryclarka35ab3e2016-10-20 08:32:18 -070073 const CubicPts& dPts = dCubic[index][pair];
74 SkDCubic d;
75 d.debugSet(dPts.fPts);
benjaminwagnerec4d4d72016-03-25 12:59:53 -070076 SkPoint c[4] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
caryclarkfeff7d22014-10-09 05:36:03 -070077 {(float) d[2].fX, (float) d[2].fY}, {(float) d[3].fX, (float) d[3].fY} };
benjaminwagnerec4d4d72016-03-25 12:59:53 -070078 cubicTest(c);
79 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
caryclarkfeff7d22014-10-09 05:36:03 -070080 return;
81 }
benjaminwagnerec4d4d72016-03-25 12:59:53 -070082 }
83 }
caryclarkfeff7d22014-10-09 05:36:03 -070084}
85
caryclarka35ab3e2016-10-20 08:32:18 -070086static void quadSetTest(const QuadPts* dQuad, size_t count) {
benjaminwagnerec4d4d72016-03-25 12:59:53 -070087 skiatest::Timer timer;
88 for (size_t index = 0; index < count; ++index) {
caryclarka35ab3e2016-10-20 08:32:18 -070089 const QuadPts& dPts = dQuad[index];
90 SkDQuad d;
91 d.debugSet(dPts.fPts);
benjaminwagnerec4d4d72016-03-25 12:59:53 -070092 SkPoint c[3] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
caryclarkfeff7d22014-10-09 05:36:03 -070093 {(float) d[2].fX, (float) d[2].fY} };
benjaminwagnerec4d4d72016-03-25 12:59:53 -070094 quadTest(c);
95 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
caryclarkfeff7d22014-10-09 05:36:03 -070096 return;
97 }
benjaminwagnerec4d4d72016-03-25 12:59:53 -070098 }
caryclarkfeff7d22014-10-09 05:36:03 -070099}
100
caryclarka35ab3e2016-10-20 08:32:18 -0700101static void quadPairSetTest(const QuadPts dQuad[][2], size_t count) {
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700102 skiatest::Timer timer;
103 for (size_t index = 0; index < count; ++index) {
104 for (int pair = 0; pair < 2; ++pair) {
caryclarka35ab3e2016-10-20 08:32:18 -0700105 const QuadPts& dPts = dQuad[index][pair];
106 SkDQuad d;
107 d.debugSet(dPts.fPts);
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700108 SkPoint c[3] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
caryclarkfeff7d22014-10-09 05:36:03 -0700109 {(float) d[2].fX, (float) d[2].fY} };
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700110 quadTest(c);
111 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
caryclarkfeff7d22014-10-09 05:36:03 -0700112 return;
113 }
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700114 }
115 }
caryclarkfeff7d22014-10-09 05:36:03 -0700116}
117
118DEF_TEST(QuadStrokerSet, reporter) {
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700119 quadSetTest(quadraticLines, quadraticLines_count);
120 quadSetTest(quadraticPoints, quadraticPoints_count);
121 quadSetTest(quadraticModEpsilonLines, quadraticModEpsilonLines_count);
122 quadPairSetTest(quadraticTests, quadraticTests_count);
caryclarkfeff7d22014-10-09 05:36:03 -0700123}
124
125DEF_TEST(CubicStrokerSet, reporter) {
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700126 cubicSetTest(pointDegenerates, pointDegenerates_count);
127 cubicSetTest(notPointDegenerates, notPointDegenerates_count);
128 cubicSetTest(lines, lines_count);
129 cubicSetTest(notLines, notLines_count);
130 cubicSetTest(modEpsilonLines, modEpsilonLines_count);
131 cubicSetTest(lessEpsilonLines, lessEpsilonLines_count);
132 cubicSetTest(negEpsilonLines, negEpsilonLines_count);
133 cubicPairSetTest(tests, tests_count);
caryclarkfeff7d22014-10-09 05:36:03 -0700134}
135
scroggof9d61012014-12-15 12:54:51 -0800136static SkScalar unbounded(SkRandom& r) {
caryclarkfeff7d22014-10-09 05:36:03 -0700137 uint32_t val = r.nextU();
138 return SkBits2Float(val);
139}
140
scroggof9d61012014-12-15 12:54:51 -0800141static SkScalar unboundedPos(SkRandom& r) {
caryclarkfeff7d22014-10-09 05:36:03 -0700142 uint32_t val = r.nextU() & 0x7fffffff;
143 return SkBits2Float(val);
144}
145
146DEF_TEST(QuadStrokerUnbounded, reporter) {
scroggof9d61012014-12-15 12:54:51 -0800147 SkRandom r;
caryclarkfeff7d22014-10-09 05:36:03 -0700148 SkPaint p;
149 p.setStyle(SkPaint::kStroke_Style);
Cary Clark66e393c2017-07-31 13:24:28 -0400150#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700151 int best = 0;
152 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
153#endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700154 skiatest::Timer timer;
caryclarkfeff7d22014-10-09 05:36:03 -0700155 for (int i = 0; i < 1000000; ++i) {
156 SkPath path, fill;
157 path.moveTo(unbounded(r), unbounded(r));
158 path.quadTo(unbounded(r), unbounded(r), unbounded(r), unbounded(r));
159 p.setStrokeWidth(unboundedPos(r));
160 p.getFillPath(path, &fill);
Cary Clark66e393c2017-07-31 13:24:28 -0400161#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700162 if (best < gMaxRecursion[2]) {
Mike Kleind0f321b2019-03-22 13:15:11 -0500163 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700164 SkDebugf("\n%s quad=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[2],
165 p.getStrokeWidth());
166 path.dumpHex();
167 SkDebugf("fill:\n");
168 fill.dumpHex();
169 }
170 best = gMaxRecursion[2];
171 }
172#endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700173 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
caryclarkfeff7d22014-10-09 05:36:03 -0700174 return;
175 }
176 }
Cary Clark66e393c2017-07-31 13:24:28 -0400177#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
Mike Kleind0f321b2019-03-22 13:15:11 -0500178 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700179 SkDebugf("\n%s max quad=%d\n", __FUNCTION__, best);
180 }
181#endif
182}
183
184DEF_TEST(CubicStrokerUnbounded, reporter) {
scroggof9d61012014-12-15 12:54:51 -0800185 SkRandom r;
caryclarkfeff7d22014-10-09 05:36:03 -0700186 SkPaint p;
187 p.setStyle(SkPaint::kStroke_Style);
Cary Clark66e393c2017-07-31 13:24:28 -0400188#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700189 int bestTan = 0;
190 int bestCubic = 0;
191 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
192#endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700193 skiatest::Timer timer;
caryclarkfeff7d22014-10-09 05:36:03 -0700194 for (int i = 0; i < 1000000; ++i) {
195 SkPath path, fill;
196 path.moveTo(unbounded(r), unbounded(r));
197 path.cubicTo(unbounded(r), unbounded(r), unbounded(r), unbounded(r),
198 unbounded(r), unbounded(r));
199 p.setStrokeWidth(unboundedPos(r));
200 p.getFillPath(path, &fill);
Cary Clark66e393c2017-07-31 13:24:28 -0400201 #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700202 if (bestTan < gMaxRecursion[0] || bestCubic < gMaxRecursion[1]) {
Mike Kleind0f321b2019-03-22 13:15:11 -0500203 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700204 SkDebugf("\n%s tan=%d cubic=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[0],
205 gMaxRecursion[1], p.getStrokeWidth());
206 path.dumpHex();
207 SkDebugf("fill:\n");
208 fill.dumpHex();
209 }
Brian Osman788b9162020-02-07 10:36:46 -0500210 bestTan = std::max(bestTan, gMaxRecursion[0]);
211 bestCubic = std::max(bestCubic, gMaxRecursion[1]);
caryclarkfeff7d22014-10-09 05:36:03 -0700212 }
213 #endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700214 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
caryclarkfeff7d22014-10-09 05:36:03 -0700215 return;
216 }
217 }
Cary Clark66e393c2017-07-31 13:24:28 -0400218#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
Mike Kleind0f321b2019-03-22 13:15:11 -0500219 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700220 SkDebugf("\n%s max tan=%d cubic=%d\n", __FUNCTION__, bestTan, bestCubic);
221 }
222#endif
223}
224
225DEF_TEST(QuadStrokerConstrained, reporter) {
scroggof9d61012014-12-15 12:54:51 -0800226 SkRandom r;
caryclarkfeff7d22014-10-09 05:36:03 -0700227 SkPaint p;
228 p.setStyle(SkPaint::kStroke_Style);
Cary Clark66e393c2017-07-31 13:24:28 -0400229#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700230 int best = 0;
231 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
232#endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700233 skiatest::Timer timer;
caryclarkfeff7d22014-10-09 05:36:03 -0700234 for (int i = 0; i < 1000000; ++i) {
235 SkPath path, fill;
236 SkPoint quad[3];
237 quad[0].fX = r.nextRangeF(0, 500);
238 quad[0].fY = r.nextRangeF(0, 500);
239 const SkScalar halfSquared = 0.5f * 0.5f;
240 do {
241 quad[1].fX = r.nextRangeF(0, 500);
242 quad[1].fY = r.nextRangeF(0, 500);
Cary Clarkdf429f32017-11-08 11:44:31 -0500243 } while (SkPointPriv::DistanceToSqd(quad[0], quad[1]) < halfSquared);
caryclarkfeff7d22014-10-09 05:36:03 -0700244 do {
245 quad[2].fX = r.nextRangeF(0, 500);
246 quad[2].fY = r.nextRangeF(0, 500);
Cary Clarkdf429f32017-11-08 11:44:31 -0500247 } while (SkPointPriv::DistanceToSqd(quad[0], quad[2]) < halfSquared
248 || SkPointPriv::DistanceToSqd(quad[1], quad[2]) < halfSquared);
caryclarkfeff7d22014-10-09 05:36:03 -0700249 path.moveTo(quad[0].fX, quad[0].fY);
250 path.quadTo(quad[1].fX, quad[1].fY, quad[2].fX, quad[2].fY);
251 p.setStrokeWidth(r.nextRangeF(0, 500));
252 p.getFillPath(path, &fill);
Cary Clark66e393c2017-07-31 13:24:28 -0400253#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700254 if (best < gMaxRecursion[2]) {
Mike Kleind0f321b2019-03-22 13:15:11 -0500255 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700256 SkDebugf("\n%s quad=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[2],
257 p.getStrokeWidth());
258 path.dumpHex();
259 SkDebugf("fill:\n");
260 fill.dumpHex();
261 }
262 best = gMaxRecursion[2];
263 }
264#endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700265 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
caryclarkfeff7d22014-10-09 05:36:03 -0700266 return;
267 }
268 }
Cary Clark66e393c2017-07-31 13:24:28 -0400269#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
Mike Kleind0f321b2019-03-22 13:15:11 -0500270 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700271 SkDebugf("\n%s max quad=%d\n", __FUNCTION__, best);
272 }
273#endif
274}
275
276DEF_TEST(CubicStrokerConstrained, reporter) {
scroggof9d61012014-12-15 12:54:51 -0800277 SkRandom r;
caryclarkfeff7d22014-10-09 05:36:03 -0700278 SkPaint p;
279 p.setStyle(SkPaint::kStroke_Style);
Cary Clark66e393c2017-07-31 13:24:28 -0400280#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700281 int bestTan = 0;
282 int bestCubic = 0;
283 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
284#endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700285 skiatest::Timer timer;
caryclarkfeff7d22014-10-09 05:36:03 -0700286 for (int i = 0; i < 1000000; ++i) {
287 SkPath path, fill;
288 SkPoint cubic[4];
289 cubic[0].fX = r.nextRangeF(0, 500);
290 cubic[0].fY = r.nextRangeF(0, 500);
291 const SkScalar halfSquared = 0.5f * 0.5f;
292 do {
293 cubic[1].fX = r.nextRangeF(0, 500);
294 cubic[1].fY = r.nextRangeF(0, 500);
Cary Clarkdf429f32017-11-08 11:44:31 -0500295 } while (SkPointPriv::DistanceToSqd(cubic[0], cubic[1]) < halfSquared);
caryclarkfeff7d22014-10-09 05:36:03 -0700296 do {
297 cubic[2].fX = r.nextRangeF(0, 500);
298 cubic[2].fY = r.nextRangeF(0, 500);
Cary Clarkdf429f32017-11-08 11:44:31 -0500299 } while ( SkPointPriv::DistanceToSqd(cubic[0], cubic[2]) < halfSquared
300 || SkPointPriv::DistanceToSqd(cubic[1], cubic[2]) < halfSquared);
caryclarkfeff7d22014-10-09 05:36:03 -0700301 do {
302 cubic[3].fX = r.nextRangeF(0, 500);
303 cubic[3].fY = r.nextRangeF(0, 500);
Cary Clarkdf429f32017-11-08 11:44:31 -0500304 } while ( SkPointPriv::DistanceToSqd(cubic[0], cubic[3]) < halfSquared
305 || SkPointPriv::DistanceToSqd(cubic[1], cubic[3]) < halfSquared
306 || SkPointPriv::DistanceToSqd(cubic[2], cubic[3]) < halfSquared);
caryclarkfeff7d22014-10-09 05:36:03 -0700307 path.moveTo(cubic[0].fX, cubic[0].fY);
308 path.cubicTo(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY);
309 p.setStrokeWidth(r.nextRangeF(0, 500));
310 p.getFillPath(path, &fill);
Cary Clark66e393c2017-07-31 13:24:28 -0400311#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700312 if (bestTan < gMaxRecursion[0] || bestCubic < gMaxRecursion[1]) {
Mike Kleind0f321b2019-03-22 13:15:11 -0500313 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700314 SkDebugf("\n%s tan=%d cubic=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[0],
315 gMaxRecursion[1], p.getStrokeWidth());
316 path.dumpHex();
317 SkDebugf("fill:\n");
318 fill.dumpHex();
319 }
Brian Osman788b9162020-02-07 10:36:46 -0500320 bestTan = std::max(bestTan, gMaxRecursion[0]);
321 bestCubic = std::max(bestCubic, gMaxRecursion[1]);
caryclarkfeff7d22014-10-09 05:36:03 -0700322 }
323#endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700324 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
caryclarkfeff7d22014-10-09 05:36:03 -0700325 return;
326 }
327 }
Cary Clark66e393c2017-07-31 13:24:28 -0400328#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
Mike Kleind0f321b2019-03-22 13:15:11 -0500329 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700330 SkDebugf("\n%s max tan=%d cubic=%d\n", __FUNCTION__, bestTan, bestCubic);
331 }
332#endif
333}
334
335DEF_TEST(QuadStrokerRange, reporter) {
scroggof9d61012014-12-15 12:54:51 -0800336 SkRandom r;
caryclarkfeff7d22014-10-09 05:36:03 -0700337 SkPaint p;
338 p.setStyle(SkPaint::kStroke_Style);
Cary Clark66e393c2017-07-31 13:24:28 -0400339#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700340 int best = 0;
341 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
342#endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700343 skiatest::Timer timer;
caryclarkfeff7d22014-10-09 05:36:03 -0700344 for (int i = 0; i < 1000000; ++i) {
345 SkPath path, fill;
346 SkPoint quad[3];
347 quad[0].fX = r.nextRangeF(0, 500);
348 quad[0].fY = r.nextRangeF(0, 500);
349 quad[1].fX = r.nextRangeF(0, 500);
350 quad[1].fY = r.nextRangeF(0, 500);
351 quad[2].fX = r.nextRangeF(0, 500);
352 quad[2].fY = r.nextRangeF(0, 500);
353 path.moveTo(quad[0].fX, quad[0].fY);
354 path.quadTo(quad[1].fX, quad[1].fY, quad[2].fX, quad[2].fY);
355 p.setStrokeWidth(r.nextRangeF(0, 500));
356 p.getFillPath(path, &fill);
Cary Clark66e393c2017-07-31 13:24:28 -0400357#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700358 if (best < gMaxRecursion[2]) {
Mike Kleind0f321b2019-03-22 13:15:11 -0500359 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700360 SkDebugf("\n%s quad=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[2],
361 p.getStrokeWidth());
362 path.dumpHex();
363 SkDebugf("fill:\n");
364 fill.dumpHex();
365 }
366 best = gMaxRecursion[2];
367 }
368#endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700369 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
caryclarkfeff7d22014-10-09 05:36:03 -0700370 return;
371 }
372 }
Cary Clark66e393c2017-07-31 13:24:28 -0400373#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
Mike Kleind0f321b2019-03-22 13:15:11 -0500374 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700375 SkDebugf("\n%s max quad=%d\n", __FUNCTION__, best);
376 }
377#endif
378}
379
380DEF_TEST(CubicStrokerRange, reporter) {
scroggof9d61012014-12-15 12:54:51 -0800381 SkRandom r;
caryclarkfeff7d22014-10-09 05:36:03 -0700382 SkPaint p;
383 p.setStyle(SkPaint::kStroke_Style);
Cary Clark66e393c2017-07-31 13:24:28 -0400384#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700385 int best[2] = { 0 };
386 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
387#endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700388 skiatest::Timer timer;
caryclarkfeff7d22014-10-09 05:36:03 -0700389 for (int i = 0; i < 1000000; ++i) {
390 SkPath path, fill;
391 path.moveTo(r.nextRangeF(0, 500), r.nextRangeF(0, 500));
392 path.cubicTo(r.nextRangeF(0, 500), r.nextRangeF(0, 500), r.nextRangeF(0, 500),
393 r.nextRangeF(0, 500), r.nextRangeF(0, 500), r.nextRangeF(0, 500));
394 p.setStrokeWidth(r.nextRangeF(0, 100));
395 p.getFillPath(path, &fill);
Cary Clark66e393c2017-07-31 13:24:28 -0400396#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700397 if (best[0] < gMaxRecursion[0] || best[1] < gMaxRecursion[1]) {
Mike Kleind0f321b2019-03-22 13:15:11 -0500398 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700399 SkDebugf("\n%s tan=%d cubic=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[0],
400 gMaxRecursion[1], p.getStrokeWidth());
401 path.dumpHex();
402 SkDebugf("fill:\n");
403 fill.dumpHex();
404 }
Brian Osman788b9162020-02-07 10:36:46 -0500405 best[0] = std::max(best[0], gMaxRecursion[0]);
406 best[1] = std::max(best[1], gMaxRecursion[1]);
caryclarkfeff7d22014-10-09 05:36:03 -0700407 }
408#endif
benjaminwagnerec4d4d72016-03-25 12:59:53 -0700409 if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
caryclarkfeff7d22014-10-09 05:36:03 -0700410 return;
411 }
412 }
Cary Clark66e393c2017-07-31 13:24:28 -0400413#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
Mike Kleind0f321b2019-03-22 13:15:11 -0500414 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700415 SkDebugf("\n%s max tan=%d cubic=%d\n", __FUNCTION__, best[0], best[1]);
416 }
417#endif
418}
419
420
421DEF_TEST(QuadStrokerOneOff, reporter) {
Cary Clark66e393c2017-07-31 13:24:28 -0400422#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700423 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
424#endif
425 SkPaint p;
426 p.setStyle(SkPaint::kStroke_Style);
427 p.setStrokeWidth(SkDoubleToScalar(164.683548));
428
429 SkPath path, fill;
430path.moveTo(SkBits2Float(0x43c99223), SkBits2Float(0x42b7417e));
431path.quadTo(SkBits2Float(0x4285d839), SkBits2Float(0x43ed6645), SkBits2Float(0x43c941c8), SkBits2Float(0x42b3ace3));
432 p.getFillPath(path, &fill);
Mike Kleind0f321b2019-03-22 13:15:11 -0500433 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700434 SkDebugf("\n%s path\n", __FUNCTION__);
435 path.dump();
436 SkDebugf("fill:\n");
437 fill.dump();
438 }
Cary Clark66e393c2017-07-31 13:24:28 -0400439#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
Mike Kleind0f321b2019-03-22 13:15:11 -0500440 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700441 SkDebugf("max quad=%d\n", gMaxRecursion[2]);
442 }
443#endif
444}
445
446DEF_TEST(CubicStrokerOneOff, reporter) {
Cary Clark66e393c2017-07-31 13:24:28 -0400447#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
caryclarkfeff7d22014-10-09 05:36:03 -0700448 sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
449#endif
450 SkPaint p;
451 p.setStyle(SkPaint::kStroke_Style);
452 p.setStrokeWidth(SkDoubleToScalar(42.835968));
453
454 SkPath path, fill;
455path.moveTo(SkBits2Float(0x433f5370), SkBits2Float(0x43d1f4b3));
456path.cubicTo(SkBits2Float(0x4331cb76), SkBits2Float(0x43ea3340), SkBits2Float(0x4388f498), SkBits2Float(0x42f7f08d), SkBits2Float(0x43f1cd32), SkBits2Float(0x42802ec1));
457 p.getFillPath(path, &fill);
Mike Kleind0f321b2019-03-22 13:15:11 -0500458 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700459 SkDebugf("\n%s path\n", __FUNCTION__);
460 path.dump();
461 SkDebugf("fill:\n");
462 fill.dump();
463 }
Cary Clark66e393c2017-07-31 13:24:28 -0400464#if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
Mike Kleind0f321b2019-03-22 13:15:11 -0500465 if (reporter->verbose()) {
caryclarkfeff7d22014-10-09 05:36:03 -0700466 SkDebugf("max tan=%d cubic=%d\n", gMaxRecursion[0], gMaxRecursion[1]);
467 }
468#endif
469}