gfx/skia/trunk/src/pathops/SkPathOpsCommon.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /*
michael@0 2 * Copyright 2012 Google Inc.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license that can be
michael@0 5 * found in the LICENSE file.
michael@0 6 */
michael@0 7 #include "SkAddIntersections.h"
michael@0 8 #include "SkOpEdgeBuilder.h"
michael@0 9 #include "SkPathOpsCommon.h"
michael@0 10 #include "SkPathWriter.h"
michael@0 11 #include "SkTSort.h"
michael@0 12
michael@0 13 static int contourRangeCheckY(const SkTArray<SkOpContour*, true>& contourList, SkOpSegment** currentPtr,
michael@0 14 int* indexPtr, int* endIndexPtr, double* bestHit, SkScalar* bestDx,
michael@0 15 bool* tryAgain, double* midPtr, bool opp) {
michael@0 16 const int index = *indexPtr;
michael@0 17 const int endIndex = *endIndexPtr;
michael@0 18 const double mid = *midPtr;
michael@0 19 const SkOpSegment* current = *currentPtr;
michael@0 20 double tAtMid = current->tAtMid(index, endIndex, mid);
michael@0 21 SkPoint basePt = current->ptAtT(tAtMid);
michael@0 22 int contourCount = contourList.count();
michael@0 23 SkScalar bestY = SK_ScalarMin;
michael@0 24 SkOpSegment* bestSeg = NULL;
michael@0 25 int bestTIndex = 0;
michael@0 26 bool bestOpp;
michael@0 27 bool hitSomething = false;
michael@0 28 for (int cTest = 0; cTest < contourCount; ++cTest) {
michael@0 29 SkOpContour* contour = contourList[cTest];
michael@0 30 bool testOpp = contour->operand() ^ current->operand() ^ opp;
michael@0 31 if (basePt.fY < contour->bounds().fTop) {
michael@0 32 continue;
michael@0 33 }
michael@0 34 if (bestY > contour->bounds().fBottom) {
michael@0 35 continue;
michael@0 36 }
michael@0 37 int segmentCount = contour->segments().count();
michael@0 38 for (int test = 0; test < segmentCount; ++test) {
michael@0 39 SkOpSegment* testSeg = &contour->segments()[test];
michael@0 40 SkScalar testY = bestY;
michael@0 41 double testHit;
michael@0 42 int testTIndex = testSeg->crossedSpanY(basePt, &testY, &testHit, &hitSomething, tAtMid,
michael@0 43 testOpp, testSeg == current);
michael@0 44 if (testTIndex < 0) {
michael@0 45 if (testTIndex == SK_MinS32) {
michael@0 46 hitSomething = true;
michael@0 47 bestSeg = NULL;
michael@0 48 goto abortContours; // vertical encountered, return and try different point
michael@0 49 }
michael@0 50 continue;
michael@0 51 }
michael@0 52 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
michael@0 53 double baseT = current->t(index);
michael@0 54 double endT = current->t(endIndex);
michael@0 55 double newMid = (testHit - baseT) / (endT - baseT);
michael@0 56 #if DEBUG_WINDING
michael@0 57 double midT = current->tAtMid(index, endIndex, mid);
michael@0 58 SkPoint midXY = current->xyAtT(midT);
michael@0 59 double newMidT = current->tAtMid(index, endIndex, newMid);
michael@0 60 SkPoint newXY = current->xyAtT(newMidT);
michael@0 61 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
michael@0 62 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
michael@0 63 current->debugID(), mid, newMid,
michael@0 64 baseT, current->xAtT(index), current->yAtT(index),
michael@0 65 baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
michael@0 66 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
michael@0 67 endT, current->xAtT(endIndex), current->yAtT(endIndex));
michael@0 68 #endif
michael@0 69 *midPtr = newMid * 2; // calling loop with divide by 2 before continuing
michael@0 70 return SK_MinS32;
michael@0 71 }
michael@0 72 bestSeg = testSeg;
michael@0 73 *bestHit = testHit;
michael@0 74 bestOpp = testOpp;
michael@0 75 bestTIndex = testTIndex;
michael@0 76 bestY = testY;
michael@0 77 }
michael@0 78 }
michael@0 79 abortContours:
michael@0 80 int result;
michael@0 81 if (!bestSeg) {
michael@0 82 result = hitSomething ? SK_MinS32 : 0;
michael@0 83 } else {
michael@0 84 if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
michael@0 85 *currentPtr = bestSeg;
michael@0 86 *indexPtr = bestTIndex;
michael@0 87 *endIndexPtr = bestSeg->nextSpan(bestTIndex, 1);
michael@0 88 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
michael@0 89 *tryAgain = true;
michael@0 90 return 0;
michael@0 91 }
michael@0 92 result = bestSeg->windingAtT(*bestHit, bestTIndex, bestOpp, bestDx);
michael@0 93 SkASSERT(result == SK_MinS32 || *bestDx);
michael@0 94 }
michael@0 95 double baseT = current->t(index);
michael@0 96 double endT = current->t(endIndex);
michael@0 97 *bestHit = baseT + mid * (endT - baseT);
michael@0 98 return result;
michael@0 99 }
michael@0 100
michael@0 101 SkOpSegment* FindUndone(SkTArray<SkOpContour*, true>& contourList, int* start, int* end) {
michael@0 102 int contourCount = contourList.count();
michael@0 103 SkOpSegment* result;
michael@0 104 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
michael@0 105 SkOpContour* contour = contourList[cIndex];
michael@0 106 result = contour->undoneSegment(start, end);
michael@0 107 if (result) {
michael@0 108 return result;
michael@0 109 }
michael@0 110 }
michael@0 111 return NULL;
michael@0 112 }
michael@0 113
michael@0 114 SkOpSegment* FindChase(SkTDArray<SkOpSpan*>& chase, int& tIndex, int& endIndex) {
michael@0 115 while (chase.count()) {
michael@0 116 SkOpSpan* span;
michael@0 117 chase.pop(&span);
michael@0 118 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex);
michael@0 119 SkOpSegment* segment = backPtr.fOther;
michael@0 120 tIndex = backPtr.fOtherIndex;
michael@0 121 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
michael@0 122 int done = 0;
michael@0 123 if (segment->activeAngle(tIndex, &done, &angles)) {
michael@0 124 SkOpAngle* last = angles.end() - 1;
michael@0 125 tIndex = last->start();
michael@0 126 endIndex = last->end();
michael@0 127 #if TRY_ROTATE
michael@0 128 *chase.insert(0) = span;
michael@0 129 #else
michael@0 130 *chase.append() = span;
michael@0 131 #endif
michael@0 132 return last->segment();
michael@0 133 }
michael@0 134 if (done == angles.count()) {
michael@0 135 continue;
michael@0 136 }
michael@0 137 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
michael@0 138 bool sortable = SkOpSegment::SortAngles(angles, &sorted,
michael@0 139 SkOpSegment::kMayBeUnordered_SortAngleKind);
michael@0 140 int angleCount = sorted.count();
michael@0 141 #if DEBUG_SORT
michael@0 142 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0, sortable);
michael@0 143 #endif
michael@0 144 if (!sortable) {
michael@0 145 continue;
michael@0 146 }
michael@0 147 // find first angle, initialize winding to computed fWindSum
michael@0 148 int firstIndex = -1;
michael@0 149 const SkOpAngle* angle;
michael@0 150 int winding;
michael@0 151 do {
michael@0 152 angle = sorted[++firstIndex];
michael@0 153 segment = angle->segment();
michael@0 154 winding = segment->windSum(angle);
michael@0 155 } while (winding == SK_MinS32);
michael@0 156 int spanWinding = segment->spanSign(angle->start(), angle->end());
michael@0 157 #if DEBUG_WINDING
michael@0 158 SkDebugf("%s winding=%d spanWinding=%d\n",
michael@0 159 __FUNCTION__, winding, spanWinding);
michael@0 160 #endif
michael@0 161 // turn span winding into contour winding
michael@0 162 if (spanWinding * winding < 0) {
michael@0 163 winding += spanWinding;
michael@0 164 }
michael@0 165 #if DEBUG_SORT
michael@0 166 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0, sortable);
michael@0 167 #endif
michael@0 168 // we care about first sign and whether wind sum indicates this
michael@0 169 // edge is inside or outside. Maybe need to pass span winding
michael@0 170 // or first winding or something into this function?
michael@0 171 // advance to first undone angle, then return it and winding
michael@0 172 // (to set whether edges are active or not)
michael@0 173 int nextIndex = firstIndex + 1;
michael@0 174 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
michael@0 175 angle = sorted[firstIndex];
michael@0 176 winding -= angle->segment()->spanSign(angle);
michael@0 177 do {
michael@0 178 SkASSERT(nextIndex != firstIndex);
michael@0 179 if (nextIndex == angleCount) {
michael@0 180 nextIndex = 0;
michael@0 181 }
michael@0 182 angle = sorted[nextIndex];
michael@0 183 segment = angle->segment();
michael@0 184 int maxWinding = winding;
michael@0 185 winding -= segment->spanSign(angle);
michael@0 186 #if DEBUG_SORT
michael@0 187 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__,
michael@0 188 segment->debugID(), maxWinding, winding, angle->sign());
michael@0 189 #endif
michael@0 190 tIndex = angle->start();
michael@0 191 endIndex = angle->end();
michael@0 192 int lesser = SkMin32(tIndex, endIndex);
michael@0 193 const SkOpSpan& nextSpan = segment->span(lesser);
michael@0 194 if (!nextSpan.fDone) {
michael@0 195 // FIXME: this be wrong? assign startWinding if edge is in
michael@0 196 // same direction. If the direction is opposite, winding to
michael@0 197 // assign is flipped sign or +/- 1?
michael@0 198 if (SkOpSegment::UseInnerWinding(maxWinding, winding)) {
michael@0 199 maxWinding = winding;
michael@0 200 }
michael@0 201 segment->markAndChaseWinding(angle, maxWinding, 0);
michael@0 202 break;
michael@0 203 }
michael@0 204 } while (++nextIndex != lastIndex);
michael@0 205 *chase.insert(0) = span;
michael@0 206 return segment;
michael@0 207 }
michael@0 208 return NULL;
michael@0 209 }
michael@0 210
michael@0 211 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
michael@0 212 void DebugShowActiveSpans(SkTArray<SkOpContour*, true>& contourList) {
michael@0 213 int index;
michael@0 214 for (index = 0; index < contourList.count(); ++ index) {
michael@0 215 contourList[index]->debugShowActiveSpans();
michael@0 216 }
michael@0 217 }
michael@0 218 #endif
michael@0 219
michael@0 220 static SkOpSegment* findSortableTop(const SkTArray<SkOpContour*, true>& contourList,
michael@0 221 int* index, int* endIndex, SkPoint* topLeft, bool* unsortable,
michael@0 222 bool* done, bool onlySortable) {
michael@0 223 SkOpSegment* result;
michael@0 224 do {
michael@0 225 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
michael@0 226 int contourCount = contourList.count();
michael@0 227 SkOpSegment* topStart = NULL;
michael@0 228 *done = true;
michael@0 229 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
michael@0 230 SkOpContour* contour = contourList[cIndex];
michael@0 231 if (contour->done()) {
michael@0 232 continue;
michael@0 233 }
michael@0 234 const SkPathOpsBounds& bounds = contour->bounds();
michael@0 235 if (bounds.fBottom < topLeft->fY) {
michael@0 236 *done = false;
michael@0 237 continue;
michael@0 238 }
michael@0 239 if (bounds.fBottom == topLeft->fY && bounds.fRight < topLeft->fX) {
michael@0 240 *done = false;
michael@0 241 continue;
michael@0 242 }
michael@0 243 contour->topSortableSegment(*topLeft, &bestXY, &topStart);
michael@0 244 if (!contour->done()) {
michael@0 245 *done = false;
michael@0 246 }
michael@0 247 }
michael@0 248 if (!topStart) {
michael@0 249 return NULL;
michael@0 250 }
michael@0 251 *topLeft = bestXY;
michael@0 252 result = topStart->findTop(index, endIndex, unsortable, onlySortable);
michael@0 253 } while (!result);
michael@0 254 if (result) {
michael@0 255 *unsortable = false;
michael@0 256 }
michael@0 257 return result;
michael@0 258 }
michael@0 259
michael@0 260 static int rightAngleWinding(const SkTArray<SkOpContour*, true>& contourList,
michael@0 261 SkOpSegment** current, int* index, int* endIndex, double* tHit,
michael@0 262 SkScalar* hitDx, bool* tryAgain, bool opp) {
michael@0 263 double test = 0.9;
michael@0 264 int contourWinding;
michael@0 265 do {
michael@0 266 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
michael@0 267 tryAgain, &test, opp);
michael@0 268 if (contourWinding != SK_MinS32 || *tryAgain) {
michael@0 269 return contourWinding;
michael@0 270 }
michael@0 271 test /= 2;
michael@0 272 } while (!approximately_negative(test));
michael@0 273 SkASSERT(0); // should be OK to comment out, but interested when this hits
michael@0 274 return contourWinding;
michael@0 275 }
michael@0 276
michael@0 277 static void skipVertical(const SkTArray<SkOpContour*, true>& contourList,
michael@0 278 SkOpSegment** current, int* index, int* endIndex) {
michael@0 279 if (!(*current)->isVertical(*index, *endIndex)) {
michael@0 280 return;
michael@0 281 }
michael@0 282 int contourCount = contourList.count();
michael@0 283 for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
michael@0 284 SkOpContour* contour = contourList[cIndex];
michael@0 285 if (contour->done()) {
michael@0 286 continue;
michael@0 287 }
michael@0 288 *current = contour->nonVerticalSegment(index, endIndex);
michael@0 289 if (*current) {
michael@0 290 return;
michael@0 291 }
michael@0 292 }
michael@0 293 }
michael@0 294
michael@0 295 SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
michael@0 296 SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexPtr,
michael@0 297 int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done) {
michael@0 298 SkOpSegment* current = findSortableTop(contourList, indexPtr, endIndexPtr, topLeft, unsortable,
michael@0 299 done, true);
michael@0 300 if (!current) {
michael@0 301 return NULL;
michael@0 302 }
michael@0 303 const int index = *indexPtr;
michael@0 304 const int endIndex = *endIndexPtr;
michael@0 305 if (*firstContour) {
michael@0 306 current->initWinding(index, endIndex);
michael@0 307 *firstContour = false;
michael@0 308 return current;
michael@0 309 }
michael@0 310 int minIndex = SkMin32(index, endIndex);
michael@0 311 int sumWinding = current->windSum(minIndex);
michael@0 312 if (sumWinding != SK_MinS32) {
michael@0 313 return current;
michael@0 314 }
michael@0 315 SkASSERT(current->windSum(SkMin32(index, endIndex)) == SK_MinS32);
michael@0 316 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
michael@0 317 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
michael@0 318 sumWinding = current->computeSum(index, endIndex, angleIncludeType, &angles, &sorted);
michael@0 319 if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) {
michael@0 320 return current;
michael@0 321 }
michael@0 322 int contourWinding;
michael@0 323 int oppContourWinding = 0;
michael@0 324 // the simple upward projection of the unresolved points hit unsortable angles
michael@0 325 // shoot rays at right angles to the segment to find its winding, ignoring angle cases
michael@0 326 bool tryAgain;
michael@0 327 double tHit;
michael@0 328 SkScalar hitDx = 0;
michael@0 329 SkScalar hitOppDx = 0;
michael@0 330 do {
michael@0 331 // if current is vertical, find another candidate which is not
michael@0 332 // if only remaining candidates are vertical, then they can be marked done
michael@0 333 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
michael@0 334 skipVertical(contourList, &current, indexPtr, endIndexPtr);
michael@0 335
michael@0 336 SkASSERT(*indexPtr != *endIndexPtr && *indexPtr >= 0 && *endIndexPtr >= 0);
michael@0 337 tryAgain = false;
michael@0 338 contourWinding = rightAngleWinding(contourList, &current, indexPtr, endIndexPtr, &tHit,
michael@0 339 &hitDx, &tryAgain, false);
michael@0 340 if (tryAgain) {
michael@0 341 continue;
michael@0 342 }
michael@0 343 if (angleIncludeType < SkOpAngle::kBinarySingle) {
michael@0 344 break;
michael@0 345 }
michael@0 346 oppContourWinding = rightAngleWinding(contourList, &current, indexPtr, endIndexPtr, &tHit,
michael@0 347 &hitOppDx, &tryAgain, true);
michael@0 348 } while (tryAgain);
michael@0 349 current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx, oppContourWinding,
michael@0 350 hitOppDx);
michael@0 351 return current;
michael@0 352 }
michael@0 353
michael@0 354 static void checkEnds(SkTArray<SkOpContour*, true>* contourList) {
michael@0 355 // it's hard to determine if the end of a cubic or conic nearly intersects another curve.
michael@0 356 // instead, look to see if the connecting curve intersected at that same end.
michael@0 357 int contourCount = (*contourList).count();
michael@0 358 for (int cTest = 0; cTest < contourCount; ++cTest) {
michael@0 359 SkOpContour* contour = (*contourList)[cTest];
michael@0 360 contour->checkEnds();
michael@0 361 }
michael@0 362 }
michael@0 363
michael@0 364 // A tiny interval may indicate an undiscovered coincidence. Find and fix.
michael@0 365 static void checkTiny(SkTArray<SkOpContour*, true>* contourList) {
michael@0 366 int contourCount = (*contourList).count();
michael@0 367 for (int cTest = 0; cTest < contourCount; ++cTest) {
michael@0 368 SkOpContour* contour = (*contourList)[cTest];
michael@0 369 contour->checkTiny();
michael@0 370 }
michael@0 371 }
michael@0 372
michael@0 373 static void fixOtherTIndex(SkTArray<SkOpContour*, true>* contourList) {
michael@0 374 int contourCount = (*contourList).count();
michael@0 375 for (int cTest = 0; cTest < contourCount; ++cTest) {
michael@0 376 SkOpContour* contour = (*contourList)[cTest];
michael@0 377 contour->fixOtherTIndex();
michael@0 378 }
michael@0 379 }
michael@0 380
michael@0 381 static void joinCoincidence(SkTArray<SkOpContour*, true>* contourList) {
michael@0 382 int contourCount = (*contourList).count();
michael@0 383 for (int cTest = 0; cTest < contourCount; ++cTest) {
michael@0 384 SkOpContour* contour = (*contourList)[cTest];
michael@0 385 contour->joinCoincidence();
michael@0 386 }
michael@0 387 }
michael@0 388
michael@0 389 static void sortSegments(SkTArray<SkOpContour*, true>* contourList) {
michael@0 390 int contourCount = (*contourList).count();
michael@0 391 for (int cTest = 0; cTest < contourCount; ++cTest) {
michael@0 392 SkOpContour* contour = (*contourList)[cTest];
michael@0 393 contour->sortSegments();
michael@0 394 }
michael@0 395 }
michael@0 396
michael@0 397 void MakeContourList(SkTArray<SkOpContour>& contours, SkTArray<SkOpContour*, true>& list,
michael@0 398 bool evenOdd, bool oppEvenOdd) {
michael@0 399 int count = contours.count();
michael@0 400 if (count == 0) {
michael@0 401 return;
michael@0 402 }
michael@0 403 for (int index = 0; index < count; ++index) {
michael@0 404 SkOpContour& contour = contours[index];
michael@0 405 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd);
michael@0 406 list.push_back(&contour);
michael@0 407 }
michael@0 408 SkTQSort<SkOpContour>(list.begin(), list.end() - 1);
michael@0 409 }
michael@0 410
michael@0 411 class DistanceLessThan {
michael@0 412 public:
michael@0 413 DistanceLessThan(double* distances) : fDistances(distances) { }
michael@0 414 double* fDistances;
michael@0 415 bool operator()(const int one, const int two) {
michael@0 416 return fDistances[one] < fDistances[two];
michael@0 417 }
michael@0 418 };
michael@0 419
michael@0 420 /*
michael@0 421 check start and end of each contour
michael@0 422 if not the same, record them
michael@0 423 match them up
michael@0 424 connect closest
michael@0 425 reassemble contour pieces into new path
michael@0 426 */
michael@0 427 void Assemble(const SkPathWriter& path, SkPathWriter* simple) {
michael@0 428 #if DEBUG_PATH_CONSTRUCTION
michael@0 429 SkDebugf("%s\n", __FUNCTION__);
michael@0 430 #endif
michael@0 431 SkTArray<SkOpContour> contours;
michael@0 432 SkOpEdgeBuilder builder(path, contours);
michael@0 433 builder.finish();
michael@0 434 int count = contours.count();
michael@0 435 int outer;
michael@0 436 SkTArray<int, true> runs(count); // indices of partial contours
michael@0 437 for (outer = 0; outer < count; ++outer) {
michael@0 438 const SkOpContour& eContour = contours[outer];
michael@0 439 const SkPoint& eStart = eContour.start();
michael@0 440 const SkPoint& eEnd = eContour.end();
michael@0 441 #if DEBUG_ASSEMBLE
michael@0 442 SkDebugf("%s contour", __FUNCTION__);
michael@0 443 if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) {
michael@0 444 SkDebugf("[%d]", runs.count());
michael@0 445 } else {
michael@0 446 SkDebugf(" ");
michael@0 447 }
michael@0 448 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n",
michael@0 449 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY);
michael@0 450 #endif
michael@0 451 if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) {
michael@0 452 eContour.toPath(simple);
michael@0 453 continue;
michael@0 454 }
michael@0 455 runs.push_back(outer);
michael@0 456 }
michael@0 457 count = runs.count();
michael@0 458 if (count == 0) {
michael@0 459 return;
michael@0 460 }
michael@0 461 SkTArray<int, true> sLink, eLink;
michael@0 462 sLink.push_back_n(count);
michael@0 463 eLink.push_back_n(count);
michael@0 464 int rIndex, iIndex;
michael@0 465 for (rIndex = 0; rIndex < count; ++rIndex) {
michael@0 466 sLink[rIndex] = eLink[rIndex] = SK_MaxS32;
michael@0 467 }
michael@0 468 const int ends = count * 2; // all starts and ends
michael@0 469 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
michael@0 470 SkTArray<double, true> distances;
michael@0 471 distances.push_back_n(entries);
michael@0 472 for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
michael@0 473 outer = runs[rIndex >> 1];
michael@0 474 const SkOpContour& oContour = contours[outer];
michael@0 475 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
michael@0 476 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
michael@0 477 * ends - rIndex - 1;
michael@0 478 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
michael@0 479 int inner = runs[iIndex >> 1];
michael@0 480 const SkOpContour& iContour = contours[inner];
michael@0 481 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
michael@0 482 double dx = iPt.fX - oPt.fX;
michael@0 483 double dy = iPt.fY - oPt.fY;
michael@0 484 double dist = dx * dx + dy * dy;
michael@0 485 distances[row + iIndex] = dist; // oStart distance from iStart
michael@0 486 }
michael@0 487 }
michael@0 488 SkTArray<int, true> sortedDist;
michael@0 489 sortedDist.push_back_n(entries);
michael@0 490 for (rIndex = 0; rIndex < entries; ++rIndex) {
michael@0 491 sortedDist[rIndex] = rIndex;
michael@0 492 }
michael@0 493 SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin()));
michael@0 494 int remaining = count; // number of start/end pairs
michael@0 495 for (rIndex = 0; rIndex < entries; ++rIndex) {
michael@0 496 int pair = sortedDist[rIndex];
michael@0 497 int row = pair / ends;
michael@0 498 int col = pair - row * ends;
michael@0 499 int thingOne = row < col ? row : ends - row - 2;
michael@0 500 int ndxOne = thingOne >> 1;
michael@0 501 bool endOne = thingOne & 1;
michael@0 502 int* linkOne = endOne ? eLink.begin() : sLink.begin();
michael@0 503 if (linkOne[ndxOne] != SK_MaxS32) {
michael@0 504 continue;
michael@0 505 }
michael@0 506 int thingTwo = row < col ? col : ends - row + col - 1;
michael@0 507 int ndxTwo = thingTwo >> 1;
michael@0 508 bool endTwo = thingTwo & 1;
michael@0 509 int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
michael@0 510 if (linkTwo[ndxTwo] != SK_MaxS32) {
michael@0 511 continue;
michael@0 512 }
michael@0 513 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
michael@0 514 bool flip = endOne == endTwo;
michael@0 515 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
michael@0 516 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
michael@0 517 if (!--remaining) {
michael@0 518 break;
michael@0 519 }
michael@0 520 }
michael@0 521 SkASSERT(!remaining);
michael@0 522 #if DEBUG_ASSEMBLE
michael@0 523 for (rIndex = 0; rIndex < count; ++rIndex) {
michael@0 524 int s = sLink[rIndex];
michael@0 525 int e = eLink[rIndex];
michael@0 526 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e',
michael@0 527 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e);
michael@0 528 }
michael@0 529 #endif
michael@0 530 rIndex = 0;
michael@0 531 do {
michael@0 532 bool forward = true;
michael@0 533 bool first = true;
michael@0 534 int sIndex = sLink[rIndex];
michael@0 535 SkASSERT(sIndex != SK_MaxS32);
michael@0 536 sLink[rIndex] = SK_MaxS32;
michael@0 537 int eIndex;
michael@0 538 if (sIndex < 0) {
michael@0 539 eIndex = sLink[~sIndex];
michael@0 540 sLink[~sIndex] = SK_MaxS32;
michael@0 541 } else {
michael@0 542 eIndex = eLink[sIndex];
michael@0 543 eLink[sIndex] = SK_MaxS32;
michael@0 544 }
michael@0 545 SkASSERT(eIndex != SK_MaxS32);
michael@0 546 #if DEBUG_ASSEMBLE
michael@0 547 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e',
michael@0 548 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e',
michael@0 549 eIndex < 0 ? ~eIndex : eIndex);
michael@0 550 #endif
michael@0 551 do {
michael@0 552 outer = runs[rIndex];
michael@0 553 const SkOpContour& contour = contours[outer];
michael@0 554 if (first) {
michael@0 555 first = false;
michael@0 556 const SkPoint* startPtr = &contour.start();
michael@0 557 simple->deferredMove(startPtr[0]);
michael@0 558 }
michael@0 559 if (forward) {
michael@0 560 contour.toPartialForward(simple);
michael@0 561 } else {
michael@0 562 contour.toPartialBackward(simple);
michael@0 563 }
michael@0 564 #if DEBUG_ASSEMBLE
michael@0 565 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex,
michael@0 566 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex,
michael@0 567 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex));
michael@0 568 #endif
michael@0 569 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) {
michael@0 570 simple->close();
michael@0 571 break;
michael@0 572 }
michael@0 573 if (forward) {
michael@0 574 eIndex = eLink[rIndex];
michael@0 575 SkASSERT(eIndex != SK_MaxS32);
michael@0 576 eLink[rIndex] = SK_MaxS32;
michael@0 577 if (eIndex >= 0) {
michael@0 578 SkASSERT(sLink[eIndex] == rIndex);
michael@0 579 sLink[eIndex] = SK_MaxS32;
michael@0 580 } else {
michael@0 581 SkASSERT(eLink[~eIndex] == ~rIndex);
michael@0 582 eLink[~eIndex] = SK_MaxS32;
michael@0 583 }
michael@0 584 } else {
michael@0 585 eIndex = sLink[rIndex];
michael@0 586 SkASSERT(eIndex != SK_MaxS32);
michael@0 587 sLink[rIndex] = SK_MaxS32;
michael@0 588 if (eIndex >= 0) {
michael@0 589 SkASSERT(eLink[eIndex] == rIndex);
michael@0 590 eLink[eIndex] = SK_MaxS32;
michael@0 591 } else {
michael@0 592 SkASSERT(sLink[~eIndex] == ~rIndex);
michael@0 593 sLink[~eIndex] = SK_MaxS32;
michael@0 594 }
michael@0 595 }
michael@0 596 rIndex = eIndex;
michael@0 597 if (rIndex < 0) {
michael@0 598 forward ^= 1;
michael@0 599 rIndex = ~rIndex;
michael@0 600 }
michael@0 601 } while (true);
michael@0 602 for (rIndex = 0; rIndex < count; ++rIndex) {
michael@0 603 if (sLink[rIndex] != SK_MaxS32) {
michael@0 604 break;
michael@0 605 }
michael@0 606 }
michael@0 607 } while (rIndex < count);
michael@0 608 #if DEBUG_ASSEMBLE
michael@0 609 for (rIndex = 0; rIndex < count; ++rIndex) {
michael@0 610 SkASSERT(sLink[rIndex] == SK_MaxS32);
michael@0 611 SkASSERT(eLink[rIndex] == SK_MaxS32);
michael@0 612 }
michael@0 613 #endif
michael@0 614 }
michael@0 615
michael@0 616 void HandleCoincidence(SkTArray<SkOpContour*, true>* contourList, int total) {
michael@0 617 #if DEBUG_SHOW_WINDING
michael@0 618 SkOpContour::debugShowWindingValues(contourList);
michael@0 619 #endif
michael@0 620 CoincidenceCheck(contourList, total);
michael@0 621 #if DEBUG_SHOW_WINDING
michael@0 622 SkOpContour::debugShowWindingValues(contourList);
michael@0 623 #endif
michael@0 624 fixOtherTIndex(contourList);
michael@0 625 checkEnds(contourList);
michael@0 626 checkTiny(contourList);
michael@0 627 joinCoincidence(contourList);
michael@0 628 sortSegments(contourList);
michael@0 629 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
michael@0 630 DebugShowActiveSpans(*contourList);
michael@0 631 #endif
michael@0 632 }

mercurial