1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2020 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 "include/core/SkPathBuilder.h" 9cb93a386Sopenharmony_ci#include "include/core/SkPathTypes.h" 10cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 11cb93a386Sopenharmony_ci#include "tests/Test.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_cistatic void is_empty(skiatest::Reporter* reporter, const SkPath& p) { 14cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, p.getBounds().isEmpty()); 15cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, p.countPoints() == 0); 16cb93a386Sopenharmony_ci} 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ciDEF_TEST(pathbuilder, reporter) { 19cb93a386Sopenharmony_ci SkPathBuilder b; 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ci is_empty(reporter, b.snapshot()); 22cb93a386Sopenharmony_ci is_empty(reporter, b.detach()); 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ci b.moveTo(10, 10).lineTo(20, 20).quadTo(30, 10, 10, 20); 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci SkPath p0 = b.snapshot(); 27cb93a386Sopenharmony_ci SkPath p1 = b.snapshot(); 28cb93a386Sopenharmony_ci SkPath p2 = b.detach(); 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci // Builders should always precompute the path's bounds, so there is no race condition later 31cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkPathPriv::HasComputedBounds(p0)); 32cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkPathPriv::HasComputedBounds(p1)); 33cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkPathPriv::HasComputedBounds(p2)); 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, p0.getBounds() == SkRect::MakeLTRB(10, 10, 30, 20)); 36cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, p0.countPoints() == 4); 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, p0 == p1); 39cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, p0 == p2); 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci is_empty(reporter, b.snapshot()); 42cb93a386Sopenharmony_ci is_empty(reporter, b.detach()); 43cb93a386Sopenharmony_ci} 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ciDEF_TEST(pathbuilder_filltype, reporter) { 46cb93a386Sopenharmony_ci for (auto fillType : { SkPathFillType::kWinding, 47cb93a386Sopenharmony_ci SkPathFillType::kEvenOdd, 48cb93a386Sopenharmony_ci SkPathFillType::kInverseWinding, 49cb93a386Sopenharmony_ci SkPathFillType::kInverseEvenOdd }) { 50cb93a386Sopenharmony_ci SkPathBuilder b(fillType); 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, b.fillType() == fillType); 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci for (const SkPath& path : { b.snapshot(), b.detach() }) { 55cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, path.getFillType() == fillType); 56cb93a386Sopenharmony_ci is_empty(reporter, path); 57cb93a386Sopenharmony_ci } 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci} 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_cistatic bool check_points(const SkPath& path, const SkPoint expected[], size_t count) { 62cb93a386Sopenharmony_ci std::vector<SkPoint> iter_pts; 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ci for (auto [v, p, w] : SkPathPriv::Iterate(path)) { 65cb93a386Sopenharmony_ci switch (v) { 66cb93a386Sopenharmony_ci case SkPathVerb::kMove: 67cb93a386Sopenharmony_ci iter_pts.push_back(p[0]); 68cb93a386Sopenharmony_ci break; 69cb93a386Sopenharmony_ci case SkPathVerb::kLine: 70cb93a386Sopenharmony_ci iter_pts.push_back(p[1]); 71cb93a386Sopenharmony_ci break; 72cb93a386Sopenharmony_ci case SkPathVerb::kQuad: 73cb93a386Sopenharmony_ci case SkPathVerb::kConic: 74cb93a386Sopenharmony_ci iter_pts.push_back(p[1]); 75cb93a386Sopenharmony_ci iter_pts.push_back(p[2]); 76cb93a386Sopenharmony_ci break; 77cb93a386Sopenharmony_ci case SkPathVerb::kCubic: 78cb93a386Sopenharmony_ci iter_pts.push_back(p[1]); 79cb93a386Sopenharmony_ci iter_pts.push_back(p[2]); 80cb93a386Sopenharmony_ci iter_pts.push_back(p[3]); 81cb93a386Sopenharmony_ci break; 82cb93a386Sopenharmony_ci case SkPathVerb::kClose: 83cb93a386Sopenharmony_ci break; 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci if (iter_pts.size() != count) { 87cb93a386Sopenharmony_ci return false; 88cb93a386Sopenharmony_ci } 89cb93a386Sopenharmony_ci for (size_t i = 0; i < count; ++i) { 90cb93a386Sopenharmony_ci if (iter_pts[i] != expected[i]) { 91cb93a386Sopenharmony_ci return false; 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci return true; 95cb93a386Sopenharmony_ci} 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ciDEF_TEST(pathbuilder_missing_move, reporter) { 98cb93a386Sopenharmony_ci SkPathBuilder b; 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ci b.lineTo(10, 10).lineTo(20, 30); 101cb93a386Sopenharmony_ci const SkPoint pts0[] = { 102cb93a386Sopenharmony_ci {0, 0}, {10, 10}, {20, 30}, 103cb93a386Sopenharmony_ci }; 104cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, check_points(b.snapshot(), pts0, SK_ARRAY_COUNT(pts0))); 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci b.reset().moveTo(20, 20).lineTo(10, 10).lineTo(20, 30).close().lineTo(60, 60); 107cb93a386Sopenharmony_ci const SkPoint pts1[] = { 108cb93a386Sopenharmony_ci {20, 20}, {10, 10}, {20, 30}, 109cb93a386Sopenharmony_ci {20, 20}, {60, 60}, 110cb93a386Sopenharmony_ci }; 111cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, check_points(b.snapshot(), pts1, SK_ARRAY_COUNT(pts1))); 112cb93a386Sopenharmony_ci} 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ciDEF_TEST(pathbuilder_addRect, reporter) { 115cb93a386Sopenharmony_ci const SkRect r = { 10, 20, 30, 40 }; 116cb93a386Sopenharmony_ci 117cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 118cb93a386Sopenharmony_ci for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { 119cb93a386Sopenharmony_ci SkPathBuilder b; 120cb93a386Sopenharmony_ci b.addRect(r, dir, i); 121cb93a386Sopenharmony_ci auto bp = b.detach(); 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci SkRect r2; 124cb93a386Sopenharmony_ci bool closed = false; 125cb93a386Sopenharmony_ci SkPathDirection dir2; 126cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, bp.isRect(&r2, &closed, &dir2)); 127cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, r2 == r); 128cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, closed); 129cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, dir == dir2); 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci SkPath p; 132cb93a386Sopenharmony_ci p.addRect(r, dir, i); 133cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, p == bp); 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci} 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_cistatic bool is_eq(const SkPath& a, const SkPath& b) { 139cb93a386Sopenharmony_ci if (a != b) { 140cb93a386Sopenharmony_ci return false; 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci { 144cb93a386Sopenharmony_ci SkRect ra, rb; 145cb93a386Sopenharmony_ci bool is_a = a.isOval(&ra); 146cb93a386Sopenharmony_ci bool is_b = b.isOval(&rb); 147cb93a386Sopenharmony_ci if (is_a != is_b) { 148cb93a386Sopenharmony_ci return false; 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci if (is_a && (ra != rb)) { 151cb93a386Sopenharmony_ci return false; 152cb93a386Sopenharmony_ci } 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci { 156cb93a386Sopenharmony_ci SkRRect rra, rrb; 157cb93a386Sopenharmony_ci bool is_a = a.isRRect(&rra); 158cb93a386Sopenharmony_ci bool is_b = b.isRRect(&rrb); 159cb93a386Sopenharmony_ci if (is_a != is_b) { 160cb93a386Sopenharmony_ci return false; 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci if (is_a && (rra != rrb)) { 163cb93a386Sopenharmony_ci return false; 164cb93a386Sopenharmony_ci } 165cb93a386Sopenharmony_ci } 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci // getConvextity() should be sufficient to test, but internally we sometimes don't want 168cb93a386Sopenharmony_ci // to trigger computing it, so this is the stronger test for equality. 169cb93a386Sopenharmony_ci { 170cb93a386Sopenharmony_ci SkPathConvexity ca = SkPathPriv::GetConvexityOrUnknown(a), 171cb93a386Sopenharmony_ci cb = SkPathPriv::GetConvexityOrUnknown(b); 172cb93a386Sopenharmony_ci if (ca != cb) { 173cb93a386Sopenharmony_ci return false; 174cb93a386Sopenharmony_ci } 175cb93a386Sopenharmony_ci } 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_ci return true; 178cb93a386Sopenharmony_ci} 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ciDEF_TEST(pathbuilder_addOval, reporter) { 181cb93a386Sopenharmony_ci const SkRect r = { 10, 20, 30, 40 }; 182cb93a386Sopenharmony_ci SkRect tmp; 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ci for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { 185cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 186cb93a386Sopenharmony_ci auto bp = SkPathBuilder().addOval(r, dir, i).detach(); 187cb93a386Sopenharmony_ci SkPath p; 188cb93a386Sopenharmony_ci p.addOval(r, dir, i); 189cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, is_eq(p, bp)); 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci auto bp = SkPathBuilder().addOval(r, dir).detach(); 192cb93a386Sopenharmony_ci SkPath p; 193cb93a386Sopenharmony_ci p.addOval(r, dir); 194cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, is_eq(p, bp)); 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci // test negative case -- can't have any other segments 197cb93a386Sopenharmony_ci bp = SkPathBuilder().addOval(r, dir).lineTo(10, 10).detach(); 198cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !bp.isOval(&tmp)); 199cb93a386Sopenharmony_ci bp = SkPathBuilder().lineTo(10, 10).addOval(r, dir).detach(); 200cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !bp.isOval(&tmp)); 201cb93a386Sopenharmony_ci } 202cb93a386Sopenharmony_ci} 203cb93a386Sopenharmony_ci 204cb93a386Sopenharmony_ciDEF_TEST(pathbuilder_addRRect, reporter) { 205cb93a386Sopenharmony_ci const SkRRect rr = SkRRect::MakeRectXY({ 10, 20, 30, 40 }, 5, 6); 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci for (auto dir : {SkPathDirection::kCW, SkPathDirection::kCCW}) { 208cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 209cb93a386Sopenharmony_ci SkPathBuilder b; 210cb93a386Sopenharmony_ci b.addRRect(rr, dir, i); 211cb93a386Sopenharmony_ci auto bp = b.detach(); 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ci SkPath p; 214cb93a386Sopenharmony_ci p.addRRect(rr, dir, i); 215cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, is_eq(p, bp)); 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci auto bp = SkPathBuilder().addRRect(rr, dir).detach(); 218cb93a386Sopenharmony_ci SkPath p; 219cb93a386Sopenharmony_ci p.addRRect(rr, dir); 220cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, is_eq(p, bp)); 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci // test negative case -- can't have any other segments 223cb93a386Sopenharmony_ci SkRRect tmp; 224cb93a386Sopenharmony_ci bp = SkPathBuilder().addRRect(rr, dir).lineTo(10, 10).detach(); 225cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !bp.isRRect(&tmp)); 226cb93a386Sopenharmony_ci bp = SkPathBuilder().lineTo(10, 10).addRRect(rr, dir).detach(); 227cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !bp.isRRect(&tmp)); 228cb93a386Sopenharmony_ci } 229cb93a386Sopenharmony_ci} 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h" 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_ciDEF_TEST(pathbuilder_make, reporter) { 234cb93a386Sopenharmony_ci constexpr int N = 100; 235cb93a386Sopenharmony_ci uint8_t vbs[N]; 236cb93a386Sopenharmony_ci SkPoint pts[N]; 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci SkRandom rand; 239cb93a386Sopenharmony_ci SkPathBuilder b; 240cb93a386Sopenharmony_ci b.moveTo(0, 0); 241cb93a386Sopenharmony_ci pts[0] = {0, 0}; vbs[0] = (uint8_t)SkPathVerb::kMove; 242cb93a386Sopenharmony_ci for (int i = 1; i < N; ++i) { 243cb93a386Sopenharmony_ci float x = rand.nextF(); 244cb93a386Sopenharmony_ci float y = rand.nextF(); 245cb93a386Sopenharmony_ci b.lineTo(x, y); 246cb93a386Sopenharmony_ci pts[i] = {x, y}; vbs[i] = (uint8_t)SkPathVerb::kLine; 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci auto p0 = b.detach(); 249cb93a386Sopenharmony_ci auto p1 = SkPath::Make(pts, N, vbs, N, nullptr, 0, p0.getFillType()); 250cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, p0 == p1); 251cb93a386Sopenharmony_ci} 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_ciDEF_TEST(pathbuilder_genid, r) { 254cb93a386Sopenharmony_ci SkPathBuilder builder; 255cb93a386Sopenharmony_ci 256cb93a386Sopenharmony_ci builder.lineTo(10, 10); 257cb93a386Sopenharmony_ci auto p1 = builder.snapshot(); 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_ci builder.lineTo(10, 20); 260cb93a386Sopenharmony_ci auto p2 = builder.snapshot(); 261cb93a386Sopenharmony_ci 262cb93a386Sopenharmony_ci REPORTER_ASSERT(r, p1.getGenerationID() != p2.getGenerationID()); 263cb93a386Sopenharmony_ci} 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_ciDEF_TEST(pathbuilder_addPolygon, reporter) { 266cb93a386Sopenharmony_ci SkPoint pts[] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}}; 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_ci auto addpoly = [](const SkPoint pts[], int count, bool isClosed) { 269cb93a386Sopenharmony_ci SkPathBuilder builder; 270cb93a386Sopenharmony_ci if (count > 0) { 271cb93a386Sopenharmony_ci builder.moveTo(pts[0]); 272cb93a386Sopenharmony_ci for (int i = 1; i < count; ++i) { 273cb93a386Sopenharmony_ci builder.lineTo(pts[i]); 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci if (isClosed) { 276cb93a386Sopenharmony_ci builder.close(); 277cb93a386Sopenharmony_ci } 278cb93a386Sopenharmony_ci } 279cb93a386Sopenharmony_ci return builder.detach(); 280cb93a386Sopenharmony_ci }; 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci for (bool isClosed : {false, true}) { 283cb93a386Sopenharmony_ci for (size_t i = 0; i <= SK_ARRAY_COUNT(pts); ++i) { 284cb93a386Sopenharmony_ci auto path0 = SkPathBuilder().addPolygon(pts, i, isClosed).detach(); 285cb93a386Sopenharmony_ci auto path1 = addpoly(pts, i, isClosed); 286cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, path0 == path1); 287cb93a386Sopenharmony_ci } 288cb93a386Sopenharmony_ci } 289cb93a386Sopenharmony_ci} 290cb93a386Sopenharmony_ci 291cb93a386Sopenharmony_ciDEF_TEST(pathbuilder_shrinkToFit, reporter) { 292cb93a386Sopenharmony_ci // SkPathBuilder::snapshot() creates copies of its arrays for perfectly sized paths, 293cb93a386Sopenharmony_ci // where SkPathBuilder::detach() moves its larger scratch arrays for speed. 294cb93a386Sopenharmony_ci bool any_smaller = false; 295cb93a386Sopenharmony_ci for (int pts = 0; pts < 10; pts++) { 296cb93a386Sopenharmony_ci 297cb93a386Sopenharmony_ci SkPathBuilder b; 298cb93a386Sopenharmony_ci for (int i = 0; i < pts; i++) { 299cb93a386Sopenharmony_ci b.lineTo(i,i); 300cb93a386Sopenharmony_ci } 301cb93a386Sopenharmony_ci b.close(); 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci SkPath s = b.snapshot(), 304cb93a386Sopenharmony_ci d = b.detach(); 305cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, s.approximateBytesUsed() <= d.approximateBytesUsed()); 306cb93a386Sopenharmony_ci any_smaller |= s.approximateBytesUsed() < d.approximateBytesUsed(); 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, any_smaller); 309cb93a386Sopenharmony_ci} 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_ciDEF_TEST(pathbuilder_addPath, reporter) { 312cb93a386Sopenharmony_ci const auto p = SkPath() 313cb93a386Sopenharmony_ci .moveTo(10, 10) 314cb93a386Sopenharmony_ci .lineTo(100, 10) 315cb93a386Sopenharmony_ci .quadTo(200, 100, 100, 200) 316cb93a386Sopenharmony_ci .close() 317cb93a386Sopenharmony_ci .moveTo(200, 200) 318cb93a386Sopenharmony_ci .cubicTo(210, 200, 210, 300, 200, 300) 319cb93a386Sopenharmony_ci .conicTo(150, 250, 100, 200, 1.4f); 320cb93a386Sopenharmony_ci 321cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, p == SkPathBuilder().addPath(p).detach()); 322cb93a386Sopenharmony_ci} 323cb93a386Sopenharmony_ci 324cb93a386Sopenharmony_ci/* 325cb93a386Sopenharmony_ci * If paths were immutable, we would not have to track this, but until that day, we need 326cb93a386Sopenharmony_ci * to ensure that paths are built correctly/consistently with this field, regardless of 327cb93a386Sopenharmony_ci * either the classic mutable apis, or via SkPathBuilder (SkPath::Polygon uses builder). 328cb93a386Sopenharmony_ci */ 329cb93a386Sopenharmony_ciDEF_TEST(pathbuilder_lastmoveindex, reporter) { 330cb93a386Sopenharmony_ci const SkPoint pts[] = { 331cb93a386Sopenharmony_ci {0, 1}, {2, 3}, {4, 5}, 332cb93a386Sopenharmony_ci }; 333cb93a386Sopenharmony_ci constexpr int N = (int)SK_ARRAY_COUNT(pts); 334cb93a386Sopenharmony_ci 335cb93a386Sopenharmony_ci for (int ctrCount = 1; ctrCount < 4; ++ctrCount) { 336cb93a386Sopenharmony_ci const int lastMoveToIndex = (ctrCount - 1) * N; 337cb93a386Sopenharmony_ci 338cb93a386Sopenharmony_ci for (bool isClosed : {false, true}) { 339cb93a386Sopenharmony_ci SkPath a, b; 340cb93a386Sopenharmony_ci 341cb93a386Sopenharmony_ci SkPathBuilder builder; 342cb93a386Sopenharmony_ci for (int i = 0; i < ctrCount; ++i) { 343cb93a386Sopenharmony_ci builder.addPolygon(pts, N, isClosed); // new-school way 344cb93a386Sopenharmony_ci b.addPoly(pts, N, isClosed); // old-school way 345cb93a386Sopenharmony_ci } 346cb93a386Sopenharmony_ci a = builder.detach(); 347cb93a386Sopenharmony_ci 348cb93a386Sopenharmony_ci // We track the last moveTo verb index, and we invert it if the last verb was a close 349cb93a386Sopenharmony_ci const int expected = isClosed ? ~lastMoveToIndex : lastMoveToIndex; 350cb93a386Sopenharmony_ci const int a_last = SkPathPriv::LastMoveToIndex(a); 351cb93a386Sopenharmony_ci const int b_last = SkPathPriv::LastMoveToIndex(b); 352cb93a386Sopenharmony_ci 353cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, a_last == expected); 354cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, b_last == expected); 355cb93a386Sopenharmony_ci } 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci} 358