1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2012 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#include "src/core/SkTSort.h" 8cb93a386Sopenharmony_ci#include "src/pathops/SkOpSegment.h" 9cb93a386Sopenharmony_ci#include "src/pathops/SkOpSpan.h" 10cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsPoint.h" 11cb93a386Sopenharmony_ci#include "src/pathops/SkPathWriter.h" 12cb93a386Sopenharmony_ci 13cb93a386Sopenharmony_ci// wrap path to keep track of whether the contour is initialized and non-empty 14cb93a386Sopenharmony_ciSkPathWriter::SkPathWriter(SkPath& path) 15cb93a386Sopenharmony_ci : fPathPtr(&path) 16cb93a386Sopenharmony_ci{ 17cb93a386Sopenharmony_ci init(); 18cb93a386Sopenharmony_ci} 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_civoid SkPathWriter::close() { 21cb93a386Sopenharmony_ci if (fCurrent.isEmpty()) { 22cb93a386Sopenharmony_ci return; 23cb93a386Sopenharmony_ci } 24cb93a386Sopenharmony_ci SkASSERT(this->isClosed()); 25cb93a386Sopenharmony_ci#if DEBUG_PATH_CONSTRUCTION 26cb93a386Sopenharmony_ci SkDebugf("path.close();\n"); 27cb93a386Sopenharmony_ci#endif 28cb93a386Sopenharmony_ci fCurrent.close(); 29cb93a386Sopenharmony_ci fPathPtr->addPath(fCurrent); 30cb93a386Sopenharmony_ci fCurrent.reset(); 31cb93a386Sopenharmony_ci init(); 32cb93a386Sopenharmony_ci} 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_civoid SkPathWriter::conicTo(const SkPoint& pt1, const SkOpPtT* pt2, SkScalar weight) { 35cb93a386Sopenharmony_ci SkPoint pt2pt = this->update(pt2); 36cb93a386Sopenharmony_ci#if DEBUG_PATH_CONSTRUCTION 37cb93a386Sopenharmony_ci SkDebugf("path.conicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g);\n", 38cb93a386Sopenharmony_ci pt1.fX, pt1.fY, pt2pt.fX, pt2pt.fY, weight); 39cb93a386Sopenharmony_ci#endif 40cb93a386Sopenharmony_ci fCurrent.conicTo(pt1, pt2pt, weight); 41cb93a386Sopenharmony_ci} 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_civoid SkPathWriter::cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkOpPtT* pt3) { 44cb93a386Sopenharmony_ci SkPoint pt3pt = this->update(pt3); 45cb93a386Sopenharmony_ci#if DEBUG_PATH_CONSTRUCTION 46cb93a386Sopenharmony_ci SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n", 47cb93a386Sopenharmony_ci pt1.fX, pt1.fY, pt2.fX, pt2.fY, pt3pt.fX, pt3pt.fY); 48cb93a386Sopenharmony_ci#endif 49cb93a386Sopenharmony_ci fCurrent.cubicTo(pt1, pt2, pt3pt); 50cb93a386Sopenharmony_ci} 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_cibool SkPathWriter::deferredLine(const SkOpPtT* pt) { 53cb93a386Sopenharmony_ci SkASSERT(fFirstPtT); 54cb93a386Sopenharmony_ci SkASSERT(fDefer[0]); 55cb93a386Sopenharmony_ci if (fDefer[0] == pt) { 56cb93a386Sopenharmony_ci // FIXME: why we're adding a degenerate line? Caller should have preflighted this. 57cb93a386Sopenharmony_ci return true; 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci if (pt->contains(fDefer[0])) { 60cb93a386Sopenharmony_ci // FIXME: why we're adding a degenerate line? 61cb93a386Sopenharmony_ci return true; 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci if (this->matchedLast(pt)) { 64cb93a386Sopenharmony_ci return false; 65cb93a386Sopenharmony_ci } 66cb93a386Sopenharmony_ci if (fDefer[1] && this->changedSlopes(pt)) { 67cb93a386Sopenharmony_ci this->lineTo(); 68cb93a386Sopenharmony_ci fDefer[0] = fDefer[1]; 69cb93a386Sopenharmony_ci } 70cb93a386Sopenharmony_ci fDefer[1] = pt; 71cb93a386Sopenharmony_ci return true; 72cb93a386Sopenharmony_ci} 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_civoid SkPathWriter::deferredMove(const SkOpPtT* pt) { 75cb93a386Sopenharmony_ci if (!fDefer[1]) { 76cb93a386Sopenharmony_ci fFirstPtT = fDefer[0] = pt; 77cb93a386Sopenharmony_ci return; 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci SkASSERT(fDefer[0]); 80cb93a386Sopenharmony_ci if (!this->matchedLast(pt)) { 81cb93a386Sopenharmony_ci this->finishContour(); 82cb93a386Sopenharmony_ci fFirstPtT = fDefer[0] = pt; 83cb93a386Sopenharmony_ci } 84cb93a386Sopenharmony_ci} 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_civoid SkPathWriter::finishContour() { 87cb93a386Sopenharmony_ci if (!this->matchedLast(fDefer[0])) { 88cb93a386Sopenharmony_ci if (!fDefer[1]) { 89cb93a386Sopenharmony_ci return; 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci this->lineTo(); 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci if (fCurrent.isEmpty()) { 94cb93a386Sopenharmony_ci return; 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci if (this->isClosed()) { 97cb93a386Sopenharmony_ci this->close(); 98cb93a386Sopenharmony_ci } else { 99cb93a386Sopenharmony_ci SkASSERT(fDefer[1]); 100cb93a386Sopenharmony_ci fEndPtTs.push_back(fFirstPtT); 101cb93a386Sopenharmony_ci fEndPtTs.push_back(fDefer[1]); 102cb93a386Sopenharmony_ci fPartials.push_back(fCurrent); 103cb93a386Sopenharmony_ci this->init(); 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci} 106cb93a386Sopenharmony_ci 107cb93a386Sopenharmony_civoid SkPathWriter::init() { 108cb93a386Sopenharmony_ci fCurrent.reset(); 109cb93a386Sopenharmony_ci fFirstPtT = fDefer[0] = fDefer[1] = nullptr; 110cb93a386Sopenharmony_ci} 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_cibool SkPathWriter::isClosed() const { 113cb93a386Sopenharmony_ci return this->matchedLast(fFirstPtT); 114cb93a386Sopenharmony_ci} 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_civoid SkPathWriter::lineTo() { 117cb93a386Sopenharmony_ci if (fCurrent.isEmpty()) { 118cb93a386Sopenharmony_ci this->moveTo(); 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci#if DEBUG_PATH_CONSTRUCTION 121cb93a386Sopenharmony_ci SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1]->fPt.fX, fDefer[1]->fPt.fY); 122cb93a386Sopenharmony_ci#endif 123cb93a386Sopenharmony_ci fCurrent.lineTo(fDefer[1]->fPt); 124cb93a386Sopenharmony_ci} 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_cibool SkPathWriter::matchedLast(const SkOpPtT* test) const { 127cb93a386Sopenharmony_ci if (test == fDefer[1]) { 128cb93a386Sopenharmony_ci return true; 129cb93a386Sopenharmony_ci } 130cb93a386Sopenharmony_ci if (!test) { 131cb93a386Sopenharmony_ci return false; 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci if (!fDefer[1]) { 134cb93a386Sopenharmony_ci return false; 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci return test->contains(fDefer[1]); 137cb93a386Sopenharmony_ci} 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_civoid SkPathWriter::moveTo() { 140cb93a386Sopenharmony_ci#if DEBUG_PATH_CONSTRUCTION 141cb93a386Sopenharmony_ci SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fFirstPtT->fPt.fX, fFirstPtT->fPt.fY); 142cb93a386Sopenharmony_ci#endif 143cb93a386Sopenharmony_ci fCurrent.moveTo(fFirstPtT->fPt); 144cb93a386Sopenharmony_ci} 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_civoid SkPathWriter::quadTo(const SkPoint& pt1, const SkOpPtT* pt2) { 147cb93a386Sopenharmony_ci SkPoint pt2pt = this->update(pt2); 148cb93a386Sopenharmony_ci#if DEBUG_PATH_CONSTRUCTION 149cb93a386Sopenharmony_ci SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n", 150cb93a386Sopenharmony_ci pt1.fX, pt1.fY, pt2pt.fX, pt2pt.fY); 151cb93a386Sopenharmony_ci#endif 152cb93a386Sopenharmony_ci fCurrent.quadTo(pt1, pt2pt); 153cb93a386Sopenharmony_ci} 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci// if last point to be written matches the current path's first point, alter the 156cb93a386Sopenharmony_ci// last to avoid writing a degenerate lineTo when the path is closed 157cb93a386Sopenharmony_ciSkPoint SkPathWriter::update(const SkOpPtT* pt) { 158cb93a386Sopenharmony_ci if (!fDefer[1]) { 159cb93a386Sopenharmony_ci this->moveTo(); 160cb93a386Sopenharmony_ci } else if (!this->matchedLast(fDefer[0])) { 161cb93a386Sopenharmony_ci this->lineTo(); 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci SkPoint result = pt->fPt; 164cb93a386Sopenharmony_ci if (fFirstPtT && result != fFirstPtT->fPt && fFirstPtT->contains(pt)) { 165cb93a386Sopenharmony_ci result = fFirstPtT->fPt; 166cb93a386Sopenharmony_ci } 167cb93a386Sopenharmony_ci fDefer[0] = fDefer[1] = pt; // set both to know that there is not a pending deferred line 168cb93a386Sopenharmony_ci return result; 169cb93a386Sopenharmony_ci} 170cb93a386Sopenharmony_ci 171cb93a386Sopenharmony_cibool SkPathWriter::someAssemblyRequired() { 172cb93a386Sopenharmony_ci this->finishContour(); 173cb93a386Sopenharmony_ci return fEndPtTs.count() > 0; 174cb93a386Sopenharmony_ci} 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_cibool SkPathWriter::changedSlopes(const SkOpPtT* ptT) const { 177cb93a386Sopenharmony_ci if (matchedLast(fDefer[0])) { 178cb93a386Sopenharmony_ci return false; 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci SkVector deferDxdy = fDefer[1]->fPt - fDefer[0]->fPt; 181cb93a386Sopenharmony_ci SkVector lineDxdy = ptT->fPt - fDefer[1]->fPt; 182cb93a386Sopenharmony_ci return deferDxdy.fX * lineDxdy.fY != deferDxdy.fY * lineDxdy.fX; 183cb93a386Sopenharmony_ci} 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ciclass DistanceLessThan { 186cb93a386Sopenharmony_cipublic: 187cb93a386Sopenharmony_ci DistanceLessThan(double* distances) : fDistances(distances) { } 188cb93a386Sopenharmony_ci double* fDistances; 189cb93a386Sopenharmony_ci bool operator()(const int one, const int two) const { 190cb93a386Sopenharmony_ci return fDistances[one] < fDistances[two]; 191cb93a386Sopenharmony_ci } 192cb93a386Sopenharmony_ci}; 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_ci /* 195cb93a386Sopenharmony_ci check start and end of each contour 196cb93a386Sopenharmony_ci if not the same, record them 197cb93a386Sopenharmony_ci match them up 198cb93a386Sopenharmony_ci connect closest 199cb93a386Sopenharmony_ci reassemble contour pieces into new path 200cb93a386Sopenharmony_ci */ 201cb93a386Sopenharmony_civoid SkPathWriter::assemble() { 202cb93a386Sopenharmony_ci if (!this->someAssemblyRequired()) { 203cb93a386Sopenharmony_ci return; 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci#if DEBUG_PATH_CONSTRUCTION 206cb93a386Sopenharmony_ci SkDebugf("%s\n", __FUNCTION__); 207cb93a386Sopenharmony_ci#endif 208cb93a386Sopenharmony_ci SkOpPtT const* const* runs = fEndPtTs.begin(); // starts, ends of partial contours 209cb93a386Sopenharmony_ci int endCount = fEndPtTs.count(); // all starts and ends 210cb93a386Sopenharmony_ci SkASSERT(endCount > 0); 211cb93a386Sopenharmony_ci SkASSERT(endCount == fPartials.count() * 2); 212cb93a386Sopenharmony_ci#if DEBUG_ASSEMBLE 213cb93a386Sopenharmony_ci for (int index = 0; index < endCount; index += 2) { 214cb93a386Sopenharmony_ci const SkOpPtT* eStart = runs[index]; 215cb93a386Sopenharmony_ci const SkOpPtT* eEnd = runs[index + 1]; 216cb93a386Sopenharmony_ci SkASSERT(eStart != eEnd); 217cb93a386Sopenharmony_ci SkASSERT(!eStart->contains(eEnd)); 218cb93a386Sopenharmony_ci SkDebugf("%s contour start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", __FUNCTION__, 219cb93a386Sopenharmony_ci eStart->fPt.fX, eStart->fPt.fY, eEnd->fPt.fX, eEnd->fPt.fY); 220cb93a386Sopenharmony_ci } 221cb93a386Sopenharmony_ci#endif 222cb93a386Sopenharmony_ci // lengthen any partial contour adjacent to a simple segment 223cb93a386Sopenharmony_ci for (int pIndex = 0; pIndex < endCount; pIndex++) { 224cb93a386Sopenharmony_ci SkOpPtT* opPtT = const_cast<SkOpPtT*>(runs[pIndex]); 225cb93a386Sopenharmony_ci SkPath p; 226cb93a386Sopenharmony_ci SkPathWriter partWriter(p); 227cb93a386Sopenharmony_ci do { 228cb93a386Sopenharmony_ci if (!zero_or_one(opPtT->fT)) { 229cb93a386Sopenharmony_ci break; 230cb93a386Sopenharmony_ci } 231cb93a386Sopenharmony_ci SkOpSpanBase* opSpanBase = opPtT->span(); 232cb93a386Sopenharmony_ci SkOpSpanBase* start = opPtT->fT ? opSpanBase->prev() : opSpanBase->upCast()->next(); 233cb93a386Sopenharmony_ci int step = opPtT->fT ? 1 : -1; 234cb93a386Sopenharmony_ci const SkOpSegment* opSegment = opSpanBase->segment(); 235cb93a386Sopenharmony_ci const SkOpSegment* nextSegment = opSegment->isSimple(&start, &step); 236cb93a386Sopenharmony_ci if (!nextSegment) { 237cb93a386Sopenharmony_ci break; 238cb93a386Sopenharmony_ci } 239cb93a386Sopenharmony_ci SkOpSpanBase* opSpanEnd = start->t() ? start->prev() : start->upCast()->next(); 240cb93a386Sopenharmony_ci if (start->starter(opSpanEnd)->alreadyAdded()) { 241cb93a386Sopenharmony_ci break; 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci nextSegment->addCurveTo(start, opSpanEnd, &partWriter); 244cb93a386Sopenharmony_ci opPtT = opSpanEnd->ptT(); 245cb93a386Sopenharmony_ci SkOpPtT** runsPtr = const_cast<SkOpPtT**>(&runs[pIndex]); 246cb93a386Sopenharmony_ci *runsPtr = opPtT; 247cb93a386Sopenharmony_ci } while (true); 248cb93a386Sopenharmony_ci partWriter.finishContour(); 249cb93a386Sopenharmony_ci const SkTArray<SkPath>& partPartials = partWriter.partials(); 250cb93a386Sopenharmony_ci if (!partPartials.count()) { 251cb93a386Sopenharmony_ci continue; 252cb93a386Sopenharmony_ci } 253cb93a386Sopenharmony_ci // if pIndex is even, reverse and prepend to fPartials; otherwise, append 254cb93a386Sopenharmony_ci SkPath& partial = const_cast<SkPath&>(fPartials[pIndex >> 1]); 255cb93a386Sopenharmony_ci const SkPath& part = partPartials[0]; 256cb93a386Sopenharmony_ci if (pIndex & 1) { 257cb93a386Sopenharmony_ci partial.addPath(part, SkPath::kExtend_AddPathMode); 258cb93a386Sopenharmony_ci } else { 259cb93a386Sopenharmony_ci SkPath reverse; 260cb93a386Sopenharmony_ci reverse.reverseAddPath(part); 261cb93a386Sopenharmony_ci reverse.addPath(partial, SkPath::kExtend_AddPathMode); 262cb93a386Sopenharmony_ci partial = reverse; 263cb93a386Sopenharmony_ci } 264cb93a386Sopenharmony_ci } 265cb93a386Sopenharmony_ci SkTDArray<int> sLink, eLink; 266cb93a386Sopenharmony_ci int linkCount = endCount / 2; // number of partial contours 267cb93a386Sopenharmony_ci sLink.append(linkCount); 268cb93a386Sopenharmony_ci eLink.append(linkCount); 269cb93a386Sopenharmony_ci int rIndex, iIndex; 270cb93a386Sopenharmony_ci for (rIndex = 0; rIndex < linkCount; ++rIndex) { 271cb93a386Sopenharmony_ci sLink[rIndex] = eLink[rIndex] = SK_MaxS32; 272cb93a386Sopenharmony_ci } 273cb93a386Sopenharmony_ci const int entries = endCount * (endCount - 1) / 2; // folded triangle 274cb93a386Sopenharmony_ci SkSTArray<8, double, true> distances(entries); 275cb93a386Sopenharmony_ci SkSTArray<8, int, true> sortedDist(entries); 276cb93a386Sopenharmony_ci SkSTArray<8, int, true> distLookup(entries); 277cb93a386Sopenharmony_ci int rRow = 0; 278cb93a386Sopenharmony_ci int dIndex = 0; 279cb93a386Sopenharmony_ci for (rIndex = 0; rIndex < endCount - 1; ++rIndex) { 280cb93a386Sopenharmony_ci const SkOpPtT* oPtT = runs[rIndex]; 281cb93a386Sopenharmony_ci for (iIndex = rIndex + 1; iIndex < endCount; ++iIndex) { 282cb93a386Sopenharmony_ci const SkOpPtT* iPtT = runs[iIndex]; 283cb93a386Sopenharmony_ci double dx = iPtT->fPt.fX - oPtT->fPt.fX; 284cb93a386Sopenharmony_ci double dy = iPtT->fPt.fY - oPtT->fPt.fY; 285cb93a386Sopenharmony_ci double dist = dx * dx + dy * dy; 286cb93a386Sopenharmony_ci distLookup.push_back(rRow + iIndex); 287cb93a386Sopenharmony_ci distances.push_back(dist); // oStart distance from iStart 288cb93a386Sopenharmony_ci sortedDist.push_back(dIndex++); 289cb93a386Sopenharmony_ci } 290cb93a386Sopenharmony_ci rRow += endCount; 291cb93a386Sopenharmony_ci } 292cb93a386Sopenharmony_ci SkASSERT(dIndex == entries); 293cb93a386Sopenharmony_ci SkTQSort<int>(sortedDist.begin(), sortedDist.end(), DistanceLessThan(distances.begin())); 294cb93a386Sopenharmony_ci int remaining = linkCount; // number of start/end pairs 295cb93a386Sopenharmony_ci for (rIndex = 0; rIndex < entries; ++rIndex) { 296cb93a386Sopenharmony_ci int pair = sortedDist[rIndex]; 297cb93a386Sopenharmony_ci pair = distLookup[pair]; 298cb93a386Sopenharmony_ci int row = pair / endCount; 299cb93a386Sopenharmony_ci int col = pair - row * endCount; 300cb93a386Sopenharmony_ci int ndxOne = row >> 1; 301cb93a386Sopenharmony_ci bool endOne = row & 1; 302cb93a386Sopenharmony_ci int* linkOne = endOne ? eLink.begin() : sLink.begin(); 303cb93a386Sopenharmony_ci if (linkOne[ndxOne] != SK_MaxS32) { 304cb93a386Sopenharmony_ci continue; 305cb93a386Sopenharmony_ci } 306cb93a386Sopenharmony_ci int ndxTwo = col >> 1; 307cb93a386Sopenharmony_ci bool endTwo = col & 1; 308cb93a386Sopenharmony_ci int* linkTwo = endTwo ? eLink.begin() : sLink.begin(); 309cb93a386Sopenharmony_ci if (linkTwo[ndxTwo] != SK_MaxS32) { 310cb93a386Sopenharmony_ci continue; 311cb93a386Sopenharmony_ci } 312cb93a386Sopenharmony_ci SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]); 313cb93a386Sopenharmony_ci bool flip = endOne == endTwo; 314cb93a386Sopenharmony_ci linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo; 315cb93a386Sopenharmony_ci linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne; 316cb93a386Sopenharmony_ci if (!--remaining) { 317cb93a386Sopenharmony_ci break; 318cb93a386Sopenharmony_ci } 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci SkASSERT(!remaining); 321cb93a386Sopenharmony_ci#if DEBUG_ASSEMBLE 322cb93a386Sopenharmony_ci for (rIndex = 0; rIndex < linkCount; ++rIndex) { 323cb93a386Sopenharmony_ci int s = sLink[rIndex]; 324cb93a386Sopenharmony_ci int e = eLink[rIndex]; 325cb93a386Sopenharmony_ci SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e', 326cb93a386Sopenharmony_ci s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e); 327cb93a386Sopenharmony_ci } 328cb93a386Sopenharmony_ci#endif 329cb93a386Sopenharmony_ci rIndex = 0; 330cb93a386Sopenharmony_ci do { 331cb93a386Sopenharmony_ci bool forward = true; 332cb93a386Sopenharmony_ci bool first = true; 333cb93a386Sopenharmony_ci int sIndex = sLink[rIndex]; 334cb93a386Sopenharmony_ci SkASSERT(sIndex != SK_MaxS32); 335cb93a386Sopenharmony_ci sLink[rIndex] = SK_MaxS32; 336cb93a386Sopenharmony_ci int eIndex; 337cb93a386Sopenharmony_ci if (sIndex < 0) { 338cb93a386Sopenharmony_ci eIndex = sLink[~sIndex]; 339cb93a386Sopenharmony_ci sLink[~sIndex] = SK_MaxS32; 340cb93a386Sopenharmony_ci } else { 341cb93a386Sopenharmony_ci eIndex = eLink[sIndex]; 342cb93a386Sopenharmony_ci eLink[sIndex] = SK_MaxS32; 343cb93a386Sopenharmony_ci } 344cb93a386Sopenharmony_ci SkASSERT(eIndex != SK_MaxS32); 345cb93a386Sopenharmony_ci#if DEBUG_ASSEMBLE 346cb93a386Sopenharmony_ci SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e', 347cb93a386Sopenharmony_ci sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', 348cb93a386Sopenharmony_ci eIndex < 0 ? ~eIndex : eIndex); 349cb93a386Sopenharmony_ci#endif 350cb93a386Sopenharmony_ci do { 351cb93a386Sopenharmony_ci const SkPath& contour = fPartials[rIndex]; 352cb93a386Sopenharmony_ci if (!first) { 353cb93a386Sopenharmony_ci SkPoint prior, next; 354cb93a386Sopenharmony_ci if (!fPathPtr->getLastPt(&prior)) { 355cb93a386Sopenharmony_ci return; 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci if (forward) { 358cb93a386Sopenharmony_ci next = contour.getPoint(0); 359cb93a386Sopenharmony_ci } else { 360cb93a386Sopenharmony_ci SkAssertResult(contour.getLastPt(&next)); 361cb93a386Sopenharmony_ci } 362cb93a386Sopenharmony_ci if (prior != next) { 363cb93a386Sopenharmony_ci /* TODO: if there is a gap between open path written so far and path to come, 364cb93a386Sopenharmony_ci connect by following segments from one to the other, rather than introducing 365cb93a386Sopenharmony_ci a diagonal to connect the two. 366cb93a386Sopenharmony_ci */ 367cb93a386Sopenharmony_ci } 368cb93a386Sopenharmony_ci } 369cb93a386Sopenharmony_ci if (forward) { 370cb93a386Sopenharmony_ci fPathPtr->addPath(contour, 371cb93a386Sopenharmony_ci first ? SkPath::kAppend_AddPathMode : SkPath::kExtend_AddPathMode); 372cb93a386Sopenharmony_ci } else { 373cb93a386Sopenharmony_ci SkASSERT(!first); 374cb93a386Sopenharmony_ci fPathPtr->reversePathTo(contour); 375cb93a386Sopenharmony_ci } 376cb93a386Sopenharmony_ci if (first) { 377cb93a386Sopenharmony_ci first = false; 378cb93a386Sopenharmony_ci } 379cb93a386Sopenharmony_ci#if DEBUG_ASSEMBLE 380cb93a386Sopenharmony_ci SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex, 381cb93a386Sopenharmony_ci eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, 382cb93a386Sopenharmony_ci sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); 383cb93a386Sopenharmony_ci#endif 384cb93a386Sopenharmony_ci if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { 385cb93a386Sopenharmony_ci fPathPtr->close(); 386cb93a386Sopenharmony_ci break; 387cb93a386Sopenharmony_ci } 388cb93a386Sopenharmony_ci if (forward) { 389cb93a386Sopenharmony_ci eIndex = eLink[rIndex]; 390cb93a386Sopenharmony_ci SkASSERT(eIndex != SK_MaxS32); 391cb93a386Sopenharmony_ci eLink[rIndex] = SK_MaxS32; 392cb93a386Sopenharmony_ci if (eIndex >= 0) { 393cb93a386Sopenharmony_ci SkASSERT(sLink[eIndex] == rIndex); 394cb93a386Sopenharmony_ci sLink[eIndex] = SK_MaxS32; 395cb93a386Sopenharmony_ci } else { 396cb93a386Sopenharmony_ci SkASSERT(eLink[~eIndex] == ~rIndex); 397cb93a386Sopenharmony_ci eLink[~eIndex] = SK_MaxS32; 398cb93a386Sopenharmony_ci } 399cb93a386Sopenharmony_ci } else { 400cb93a386Sopenharmony_ci eIndex = sLink[rIndex]; 401cb93a386Sopenharmony_ci SkASSERT(eIndex != SK_MaxS32); 402cb93a386Sopenharmony_ci sLink[rIndex] = SK_MaxS32; 403cb93a386Sopenharmony_ci if (eIndex >= 0) { 404cb93a386Sopenharmony_ci SkASSERT(eLink[eIndex] == rIndex); 405cb93a386Sopenharmony_ci eLink[eIndex] = SK_MaxS32; 406cb93a386Sopenharmony_ci } else { 407cb93a386Sopenharmony_ci SkASSERT(sLink[~eIndex] == ~rIndex); 408cb93a386Sopenharmony_ci sLink[~eIndex] = SK_MaxS32; 409cb93a386Sopenharmony_ci } 410cb93a386Sopenharmony_ci } 411cb93a386Sopenharmony_ci rIndex = eIndex; 412cb93a386Sopenharmony_ci if (rIndex < 0) { 413cb93a386Sopenharmony_ci forward ^= 1; 414cb93a386Sopenharmony_ci rIndex = ~rIndex; 415cb93a386Sopenharmony_ci } 416cb93a386Sopenharmony_ci } while (true); 417cb93a386Sopenharmony_ci for (rIndex = 0; rIndex < linkCount; ++rIndex) { 418cb93a386Sopenharmony_ci if (sLink[rIndex] != SK_MaxS32) { 419cb93a386Sopenharmony_ci break; 420cb93a386Sopenharmony_ci } 421cb93a386Sopenharmony_ci } 422cb93a386Sopenharmony_ci } while (rIndex < linkCount); 423cb93a386Sopenharmony_ci#if DEBUG_ASSEMBLE 424cb93a386Sopenharmony_ci for (rIndex = 0; rIndex < linkCount; ++rIndex) { 425cb93a386Sopenharmony_ci SkASSERT(sLink[rIndex] == SK_MaxS32); 426cb93a386Sopenharmony_ci SkASSERT(eLink[rIndex] == SK_MaxS32); 427cb93a386Sopenharmony_ci } 428cb93a386Sopenharmony_ci#endif 429cb93a386Sopenharmony_ci return; 430cb93a386Sopenharmony_ci} 431