StrokerTest.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /*
  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. #include "include/core/SkPaint.h"
  8. #include "include/core/SkPath.h"
  9. #include "include/core/SkTime.h"
  10. #include "include/utils/SkRandom.h"
  11. #include "src/core/SkPointPriv.h"
  12. #include "src/core/SkStrokerPriv.h"
  13. #include "src/pathops/SkPathOpsCubic.h"
  14. #include "tests/PathOpsCubicIntersectionTestData.h"
  15. #include "tests/PathOpsQuadIntersectionTestData.h"
  16. #include "tests/Test.h"
  17. #include "tools/flags/CommandLineFlags.h"
  18. static DEFINE_bool(timeout, true, "run until alloted time expires");
  19. #define MS_TEST_DURATION 10
  20. const SkScalar widths[] = {-FLT_MAX, -1, -0.1f, -FLT_EPSILON, 0, FLT_EPSILON,
  21. 0.0000001f, 0.000001f, 0.00001f, 0.0001f, 0.001f, 0.01f,
  22. 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 1, 1.1f, 2, 10, 10e2f, 10e3f, 10e4f, 10e5f, 10e6f, 10e7f,
  23. 10e8f, 10e9f, 10e10f, 10e20f, FLT_MAX };
  24. size_t widths_count = SK_ARRAY_COUNT(widths);
  25. static void pathTest(const SkPath& path) {
  26. SkPaint p;
  27. SkPath fill;
  28. p.setStyle(SkPaint::kStroke_Style);
  29. for (size_t index = 0; index < widths_count; ++index) {
  30. p.setStrokeWidth(widths[index]);
  31. p.getFillPath(path, &fill);
  32. }
  33. }
  34. static void cubicTest(const SkPoint c[4]) {
  35. SkPath path;
  36. path.moveTo(c[0].fX, c[0].fY);
  37. path.cubicTo(c[1].fX, c[1].fY, c[2].fX, c[2].fY, c[3].fX, c[3].fY);
  38. pathTest(path);
  39. }
  40. static void quadTest(const SkPoint c[3]) {
  41. SkPath path;
  42. path.moveTo(c[0].fX, c[0].fY);
  43. path.quadTo(c[1].fX, c[1].fY, c[2].fX, c[2].fY);
  44. pathTest(path);
  45. }
  46. static void cubicSetTest(const CubicPts* dCubic, size_t count) {
  47. skiatest::Timer timer;
  48. for (size_t index = 0; index < count; ++index) {
  49. const CubicPts& dPts = dCubic[index];
  50. SkDCubic d;
  51. d.debugSet(dPts.fPts);
  52. SkPoint c[4] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
  53. {(float) d[2].fX, (float) d[2].fY}, {(float) d[3].fX, (float) d[3].fY} };
  54. cubicTest(c);
  55. if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
  56. return;
  57. }
  58. }
  59. }
  60. static void cubicPairSetTest(const CubicPts dCubic[][2], size_t count) {
  61. skiatest::Timer timer;
  62. for (size_t index = 0; index < count; ++index) {
  63. for (int pair = 0; pair < 2; ++pair) {
  64. const CubicPts& dPts = dCubic[index][pair];
  65. SkDCubic d;
  66. d.debugSet(dPts.fPts);
  67. SkPoint c[4] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
  68. {(float) d[2].fX, (float) d[2].fY}, {(float) d[3].fX, (float) d[3].fY} };
  69. cubicTest(c);
  70. if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
  71. return;
  72. }
  73. }
  74. }
  75. }
  76. static void quadSetTest(const QuadPts* dQuad, size_t count) {
  77. skiatest::Timer timer;
  78. for (size_t index = 0; index < count; ++index) {
  79. const QuadPts& dPts = dQuad[index];
  80. SkDQuad d;
  81. d.debugSet(dPts.fPts);
  82. SkPoint c[3] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
  83. {(float) d[2].fX, (float) d[2].fY} };
  84. quadTest(c);
  85. if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
  86. return;
  87. }
  88. }
  89. }
  90. static void quadPairSetTest(const QuadPts dQuad[][2], size_t count) {
  91. skiatest::Timer timer;
  92. for (size_t index = 0; index < count; ++index) {
  93. for (int pair = 0; pair < 2; ++pair) {
  94. const QuadPts& dPts = dQuad[index][pair];
  95. SkDQuad d;
  96. d.debugSet(dPts.fPts);
  97. SkPoint c[3] = { {(float) d[0].fX, (float) d[0].fY}, {(float) d[1].fX, (float) d[1].fY},
  98. {(float) d[2].fX, (float) d[2].fY} };
  99. quadTest(c);
  100. if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
  101. return;
  102. }
  103. }
  104. }
  105. }
  106. DEF_TEST(QuadStrokerSet, reporter) {
  107. quadSetTest(quadraticLines, quadraticLines_count);
  108. quadSetTest(quadraticPoints, quadraticPoints_count);
  109. quadSetTest(quadraticModEpsilonLines, quadraticModEpsilonLines_count);
  110. quadPairSetTest(quadraticTests, quadraticTests_count);
  111. }
  112. DEF_TEST(CubicStrokerSet, reporter) {
  113. cubicSetTest(pointDegenerates, pointDegenerates_count);
  114. cubicSetTest(notPointDegenerates, notPointDegenerates_count);
  115. cubicSetTest(lines, lines_count);
  116. cubicSetTest(notLines, notLines_count);
  117. cubicSetTest(modEpsilonLines, modEpsilonLines_count);
  118. cubicSetTest(lessEpsilonLines, lessEpsilonLines_count);
  119. cubicSetTest(negEpsilonLines, negEpsilonLines_count);
  120. cubicPairSetTest(tests, tests_count);
  121. }
  122. static SkScalar unbounded(SkRandom& r) {
  123. uint32_t val = r.nextU();
  124. return SkBits2Float(val);
  125. }
  126. static SkScalar unboundedPos(SkRandom& r) {
  127. uint32_t val = r.nextU() & 0x7fffffff;
  128. return SkBits2Float(val);
  129. }
  130. DEF_TEST(QuadStrokerUnbounded, reporter) {
  131. SkRandom r;
  132. SkPaint p;
  133. p.setStyle(SkPaint::kStroke_Style);
  134. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  135. int best = 0;
  136. sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
  137. #endif
  138. skiatest::Timer timer;
  139. for (int i = 0; i < 1000000; ++i) {
  140. SkPath path, fill;
  141. path.moveTo(unbounded(r), unbounded(r));
  142. path.quadTo(unbounded(r), unbounded(r), unbounded(r), unbounded(r));
  143. p.setStrokeWidth(unboundedPos(r));
  144. p.getFillPath(path, &fill);
  145. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  146. if (best < gMaxRecursion[2]) {
  147. if (reporter->verbose()) {
  148. SkDebugf("\n%s quad=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[2],
  149. p.getStrokeWidth());
  150. path.dumpHex();
  151. SkDebugf("fill:\n");
  152. fill.dumpHex();
  153. }
  154. best = gMaxRecursion[2];
  155. }
  156. #endif
  157. if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
  158. return;
  159. }
  160. }
  161. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  162. if (reporter->verbose()) {
  163. SkDebugf("\n%s max quad=%d\n", __FUNCTION__, best);
  164. }
  165. #endif
  166. }
  167. DEF_TEST(CubicStrokerUnbounded, reporter) {
  168. SkRandom r;
  169. SkPaint p;
  170. p.setStyle(SkPaint::kStroke_Style);
  171. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  172. int bestTan = 0;
  173. int bestCubic = 0;
  174. sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
  175. #endif
  176. skiatest::Timer timer;
  177. for (int i = 0; i < 1000000; ++i) {
  178. SkPath path, fill;
  179. path.moveTo(unbounded(r), unbounded(r));
  180. path.cubicTo(unbounded(r), unbounded(r), unbounded(r), unbounded(r),
  181. unbounded(r), unbounded(r));
  182. p.setStrokeWidth(unboundedPos(r));
  183. p.getFillPath(path, &fill);
  184. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  185. if (bestTan < gMaxRecursion[0] || bestCubic < gMaxRecursion[1]) {
  186. if (reporter->verbose()) {
  187. SkDebugf("\n%s tan=%d cubic=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[0],
  188. gMaxRecursion[1], p.getStrokeWidth());
  189. path.dumpHex();
  190. SkDebugf("fill:\n");
  191. fill.dumpHex();
  192. }
  193. bestTan = SkTMax(bestTan, gMaxRecursion[0]);
  194. bestCubic = SkTMax(bestCubic, gMaxRecursion[1]);
  195. }
  196. #endif
  197. if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
  198. return;
  199. }
  200. }
  201. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  202. if (reporter->verbose()) {
  203. SkDebugf("\n%s max tan=%d cubic=%d\n", __FUNCTION__, bestTan, bestCubic);
  204. }
  205. #endif
  206. }
  207. DEF_TEST(QuadStrokerConstrained, reporter) {
  208. SkRandom r;
  209. SkPaint p;
  210. p.setStyle(SkPaint::kStroke_Style);
  211. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  212. int best = 0;
  213. sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
  214. #endif
  215. skiatest::Timer timer;
  216. for (int i = 0; i < 1000000; ++i) {
  217. SkPath path, fill;
  218. SkPoint quad[3];
  219. quad[0].fX = r.nextRangeF(0, 500);
  220. quad[0].fY = r.nextRangeF(0, 500);
  221. const SkScalar halfSquared = 0.5f * 0.5f;
  222. do {
  223. quad[1].fX = r.nextRangeF(0, 500);
  224. quad[1].fY = r.nextRangeF(0, 500);
  225. } while (SkPointPriv::DistanceToSqd(quad[0], quad[1]) < halfSquared);
  226. do {
  227. quad[2].fX = r.nextRangeF(0, 500);
  228. quad[2].fY = r.nextRangeF(0, 500);
  229. } while (SkPointPriv::DistanceToSqd(quad[0], quad[2]) < halfSquared
  230. || SkPointPriv::DistanceToSqd(quad[1], quad[2]) < halfSquared);
  231. path.moveTo(quad[0].fX, quad[0].fY);
  232. path.quadTo(quad[1].fX, quad[1].fY, quad[2].fX, quad[2].fY);
  233. p.setStrokeWidth(r.nextRangeF(0, 500));
  234. p.getFillPath(path, &fill);
  235. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  236. if (best < gMaxRecursion[2]) {
  237. if (reporter->verbose()) {
  238. SkDebugf("\n%s quad=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[2],
  239. p.getStrokeWidth());
  240. path.dumpHex();
  241. SkDebugf("fill:\n");
  242. fill.dumpHex();
  243. }
  244. best = gMaxRecursion[2];
  245. }
  246. #endif
  247. if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
  248. return;
  249. }
  250. }
  251. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  252. if (reporter->verbose()) {
  253. SkDebugf("\n%s max quad=%d\n", __FUNCTION__, best);
  254. }
  255. #endif
  256. }
  257. DEF_TEST(CubicStrokerConstrained, reporter) {
  258. SkRandom r;
  259. SkPaint p;
  260. p.setStyle(SkPaint::kStroke_Style);
  261. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  262. int bestTan = 0;
  263. int bestCubic = 0;
  264. sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
  265. #endif
  266. skiatest::Timer timer;
  267. for (int i = 0; i < 1000000; ++i) {
  268. SkPath path, fill;
  269. SkPoint cubic[4];
  270. cubic[0].fX = r.nextRangeF(0, 500);
  271. cubic[0].fY = r.nextRangeF(0, 500);
  272. const SkScalar halfSquared = 0.5f * 0.5f;
  273. do {
  274. cubic[1].fX = r.nextRangeF(0, 500);
  275. cubic[1].fY = r.nextRangeF(0, 500);
  276. } while (SkPointPriv::DistanceToSqd(cubic[0], cubic[1]) < halfSquared);
  277. do {
  278. cubic[2].fX = r.nextRangeF(0, 500);
  279. cubic[2].fY = r.nextRangeF(0, 500);
  280. } while ( SkPointPriv::DistanceToSqd(cubic[0], cubic[2]) < halfSquared
  281. || SkPointPriv::DistanceToSqd(cubic[1], cubic[2]) < halfSquared);
  282. do {
  283. cubic[3].fX = r.nextRangeF(0, 500);
  284. cubic[3].fY = r.nextRangeF(0, 500);
  285. } while ( SkPointPriv::DistanceToSqd(cubic[0], cubic[3]) < halfSquared
  286. || SkPointPriv::DistanceToSqd(cubic[1], cubic[3]) < halfSquared
  287. || SkPointPriv::DistanceToSqd(cubic[2], cubic[3]) < halfSquared);
  288. path.moveTo(cubic[0].fX, cubic[0].fY);
  289. path.cubicTo(cubic[1].fX, cubic[1].fY, cubic[2].fX, cubic[2].fY, cubic[3].fX, cubic[3].fY);
  290. p.setStrokeWidth(r.nextRangeF(0, 500));
  291. p.getFillPath(path, &fill);
  292. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  293. if (bestTan < gMaxRecursion[0] || bestCubic < gMaxRecursion[1]) {
  294. if (reporter->verbose()) {
  295. SkDebugf("\n%s tan=%d cubic=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[0],
  296. gMaxRecursion[1], p.getStrokeWidth());
  297. path.dumpHex();
  298. SkDebugf("fill:\n");
  299. fill.dumpHex();
  300. }
  301. bestTan = SkTMax(bestTan, gMaxRecursion[0]);
  302. bestCubic = SkTMax(bestCubic, gMaxRecursion[1]);
  303. }
  304. #endif
  305. if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
  306. return;
  307. }
  308. }
  309. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  310. if (reporter->verbose()) {
  311. SkDebugf("\n%s max tan=%d cubic=%d\n", __FUNCTION__, bestTan, bestCubic);
  312. }
  313. #endif
  314. }
  315. DEF_TEST(QuadStrokerRange, reporter) {
  316. SkRandom r;
  317. SkPaint p;
  318. p.setStyle(SkPaint::kStroke_Style);
  319. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  320. int best = 0;
  321. sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
  322. #endif
  323. skiatest::Timer timer;
  324. for (int i = 0; i < 1000000; ++i) {
  325. SkPath path, fill;
  326. SkPoint quad[3];
  327. quad[0].fX = r.nextRangeF(0, 500);
  328. quad[0].fY = r.nextRangeF(0, 500);
  329. quad[1].fX = r.nextRangeF(0, 500);
  330. quad[1].fY = r.nextRangeF(0, 500);
  331. quad[2].fX = r.nextRangeF(0, 500);
  332. quad[2].fY = r.nextRangeF(0, 500);
  333. path.moveTo(quad[0].fX, quad[0].fY);
  334. path.quadTo(quad[1].fX, quad[1].fY, quad[2].fX, quad[2].fY);
  335. p.setStrokeWidth(r.nextRangeF(0, 500));
  336. p.getFillPath(path, &fill);
  337. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  338. if (best < gMaxRecursion[2]) {
  339. if (reporter->verbose()) {
  340. SkDebugf("\n%s quad=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[2],
  341. p.getStrokeWidth());
  342. path.dumpHex();
  343. SkDebugf("fill:\n");
  344. fill.dumpHex();
  345. }
  346. best = gMaxRecursion[2];
  347. }
  348. #endif
  349. if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
  350. return;
  351. }
  352. }
  353. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  354. if (reporter->verbose()) {
  355. SkDebugf("\n%s max quad=%d\n", __FUNCTION__, best);
  356. }
  357. #endif
  358. }
  359. DEF_TEST(CubicStrokerRange, reporter) {
  360. SkRandom r;
  361. SkPaint p;
  362. p.setStyle(SkPaint::kStroke_Style);
  363. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  364. int best[2] = { 0 };
  365. sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
  366. #endif
  367. skiatest::Timer timer;
  368. for (int i = 0; i < 1000000; ++i) {
  369. SkPath path, fill;
  370. path.moveTo(r.nextRangeF(0, 500), r.nextRangeF(0, 500));
  371. path.cubicTo(r.nextRangeF(0, 500), r.nextRangeF(0, 500), r.nextRangeF(0, 500),
  372. r.nextRangeF(0, 500), r.nextRangeF(0, 500), r.nextRangeF(0, 500));
  373. p.setStrokeWidth(r.nextRangeF(0, 100));
  374. p.getFillPath(path, &fill);
  375. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  376. if (best[0] < gMaxRecursion[0] || best[1] < gMaxRecursion[1]) {
  377. if (reporter->verbose()) {
  378. SkDebugf("\n%s tan=%d cubic=%d width=%1.9g\n", __FUNCTION__, gMaxRecursion[0],
  379. gMaxRecursion[1], p.getStrokeWidth());
  380. path.dumpHex();
  381. SkDebugf("fill:\n");
  382. fill.dumpHex();
  383. }
  384. best[0] = SkTMax(best[0], gMaxRecursion[0]);
  385. best[1] = SkTMax(best[1], gMaxRecursion[1]);
  386. }
  387. #endif
  388. if (FLAGS_timeout && timer.elapsedMs() > MS_TEST_DURATION) {
  389. return;
  390. }
  391. }
  392. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  393. if (reporter->verbose()) {
  394. SkDebugf("\n%s max tan=%d cubic=%d\n", __FUNCTION__, best[0], best[1]);
  395. }
  396. #endif
  397. }
  398. DEF_TEST(QuadStrokerOneOff, reporter) {
  399. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  400. sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
  401. #endif
  402. SkPaint p;
  403. p.setStyle(SkPaint::kStroke_Style);
  404. p.setStrokeWidth(SkDoubleToScalar(164.683548));
  405. SkPath path, fill;
  406. path.moveTo(SkBits2Float(0x43c99223), SkBits2Float(0x42b7417e));
  407. path.quadTo(SkBits2Float(0x4285d839), SkBits2Float(0x43ed6645), SkBits2Float(0x43c941c8), SkBits2Float(0x42b3ace3));
  408. p.getFillPath(path, &fill);
  409. if (reporter->verbose()) {
  410. SkDebugf("\n%s path\n", __FUNCTION__);
  411. path.dump();
  412. SkDebugf("fill:\n");
  413. fill.dump();
  414. }
  415. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  416. if (reporter->verbose()) {
  417. SkDebugf("max quad=%d\n", gMaxRecursion[2]);
  418. }
  419. #endif
  420. }
  421. DEF_TEST(CubicStrokerOneOff, reporter) {
  422. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  423. sk_bzero(gMaxRecursion, sizeof(gMaxRecursion[0]) * 3);
  424. #endif
  425. SkPaint p;
  426. p.setStyle(SkPaint::kStroke_Style);
  427. p.setStrokeWidth(SkDoubleToScalar(42.835968));
  428. SkPath path, fill;
  429. path.moveTo(SkBits2Float(0x433f5370), SkBits2Float(0x43d1f4b3));
  430. path.cubicTo(SkBits2Float(0x4331cb76), SkBits2Float(0x43ea3340), SkBits2Float(0x4388f498), SkBits2Float(0x42f7f08d), SkBits2Float(0x43f1cd32), SkBits2Float(0x42802ec1));
  431. p.getFillPath(path, &fill);
  432. if (reporter->verbose()) {
  433. SkDebugf("\n%s path\n", __FUNCTION__);
  434. path.dump();
  435. SkDebugf("fill:\n");
  436. fill.dump();
  437. }
  438. #if defined(SK_DEBUG) && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
  439. if (reporter->verbose()) {
  440. SkDebugf("max tan=%d cubic=%d\n", gMaxRecursion[0], gMaxRecursion[1]);
  441. }
  442. #endif
  443. }