gfx/skia/trunk/src/pathops/SkOpContour.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 2013 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 "SkIntersections.h"
michael@0 8 #include "SkOpContour.h"
michael@0 9 #include "SkPathWriter.h"
michael@0 10 #include "SkTSort.h"
michael@0 11
michael@0 12 bool SkOpContour::addCoincident(int index, SkOpContour* other, int otherIndex,
michael@0 13 const SkIntersections& ts, bool swap) {
michael@0 14 SkPoint pt0 = ts.pt(0).asSkPoint();
michael@0 15 SkPoint pt1 = ts.pt(1).asSkPoint();
michael@0 16 if (pt0 == pt1) {
michael@0 17 // FIXME: one could imagine a case where it would be incorrect to ignore this
michael@0 18 // suppose two self-intersecting cubics overlap to be coincident --
michael@0 19 // this needs to check that by some measure the t values are far enough apart
michael@0 20 // or needs to check to see if the self-intersection bit was set on the cubic segment
michael@0 21 return false;
michael@0 22 }
michael@0 23 SkCoincidence& coincidence = fCoincidences.push_back();
michael@0 24 coincidence.fOther = other;
michael@0 25 coincidence.fSegments[0] = index;
michael@0 26 coincidence.fSegments[1] = otherIndex;
michael@0 27 coincidence.fTs[swap][0] = ts[0][0];
michael@0 28 coincidence.fTs[swap][1] = ts[0][1];
michael@0 29 coincidence.fTs[!swap][0] = ts[1][0];
michael@0 30 coincidence.fTs[!swap][1] = ts[1][1];
michael@0 31 coincidence.fPts[0] = pt0;
michael@0 32 coincidence.fPts[1] = pt1;
michael@0 33 return true;
michael@0 34 }
michael@0 35
michael@0 36 SkOpSegment* SkOpContour::nonVerticalSegment(int* start, int* end) {
michael@0 37 int segmentCount = fSortedSegments.count();
michael@0 38 SkASSERT(segmentCount > 0);
michael@0 39 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
michael@0 40 SkOpSegment* testSegment = fSortedSegments[sortedIndex];
michael@0 41 if (testSegment->done()) {
michael@0 42 continue;
michael@0 43 }
michael@0 44 *start = *end = 0;
michael@0 45 while (testSegment->nextCandidate(start, end)) {
michael@0 46 if (!testSegment->isVertical(*start, *end)) {
michael@0 47 return testSegment;
michael@0 48 }
michael@0 49 }
michael@0 50 }
michael@0 51 return NULL;
michael@0 52 }
michael@0 53
michael@0 54 // first pass, add missing T values
michael@0 55 // second pass, determine winding values of overlaps
michael@0 56 void SkOpContour::addCoincidentPoints() {
michael@0 57 int count = fCoincidences.count();
michael@0 58 for (int index = 0; index < count; ++index) {
michael@0 59 SkCoincidence& coincidence = fCoincidences[index];
michael@0 60 int thisIndex = coincidence.fSegments[0];
michael@0 61 SkOpSegment& thisOne = fSegments[thisIndex];
michael@0 62 SkOpContour* otherContour = coincidence.fOther;
michael@0 63 int otherIndex = coincidence.fSegments[1];
michael@0 64 SkOpSegment& other = otherContour->fSegments[otherIndex];
michael@0 65 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) {
michael@0 66 // OPTIMIZATION: remove from array
michael@0 67 continue;
michael@0 68 }
michael@0 69 #if DEBUG_CONCIDENT
michael@0 70 thisOne.debugShowTs("-");
michael@0 71 other.debugShowTs("o");
michael@0 72 #endif
michael@0 73 double startT = coincidence.fTs[0][0];
michael@0 74 double endT = coincidence.fTs[0][1];
michael@0 75 bool startSwapped, oStartSwapped, cancelers;
michael@0 76 if ((cancelers = startSwapped = startT > endT)) {
michael@0 77 SkTSwap(startT, endT);
michael@0 78 }
michael@0 79 if (startT == endT) { // if one is very large the smaller may have collapsed to nothing
michael@0 80 if (endT <= 1 - FLT_EPSILON) {
michael@0 81 endT += FLT_EPSILON;
michael@0 82 SkASSERT(endT <= 1);
michael@0 83 } else {
michael@0 84 startT -= FLT_EPSILON;
michael@0 85 SkASSERT(startT >= 0);
michael@0 86 }
michael@0 87 }
michael@0 88 SkASSERT(!approximately_negative(endT - startT));
michael@0 89 double oStartT = coincidence.fTs[1][0];
michael@0 90 double oEndT = coincidence.fTs[1][1];
michael@0 91 if ((oStartSwapped = oStartT > oEndT)) {
michael@0 92 SkTSwap(oStartT, oEndT);
michael@0 93 cancelers ^= true;
michael@0 94 }
michael@0 95 SkASSERT(!approximately_negative(oEndT - oStartT));
michael@0 96 if (cancelers) {
michael@0 97 // make sure startT and endT have t entries
michael@0 98 const SkPoint& startPt = coincidence.fPts[startSwapped];
michael@0 99 if (startT > 0 || oEndT < 1
michael@0 100 || thisOne.isMissing(startT, startPt) || other.isMissing(oEndT, startPt)) {
michael@0 101 thisOne.addTPair(startT, &other, oEndT, true, startPt);
michael@0 102 }
michael@0 103 const SkPoint& oStartPt = coincidence.fPts[oStartSwapped];
michael@0 104 if (oStartT > 0 || endT < 1
michael@0 105 || thisOne.isMissing(endT, oStartPt) || other.isMissing(oStartT, oStartPt)) {
michael@0 106 other.addTPair(oStartT, &thisOne, endT, true, oStartPt);
michael@0 107 }
michael@0 108 } else {
michael@0 109 const SkPoint& startPt = coincidence.fPts[startSwapped];
michael@0 110 if (startT > 0 || oStartT > 0
michael@0 111 || thisOne.isMissing(startT, startPt) || other.isMissing(oStartT, startPt)) {
michael@0 112 thisOne.addTPair(startT, &other, oStartT, true, startPt);
michael@0 113 }
michael@0 114 const SkPoint& oEndPt = coincidence.fPts[!oStartSwapped];
michael@0 115 if (endT < 1 || oEndT < 1
michael@0 116 || thisOne.isMissing(endT, oEndPt) || other.isMissing(oEndT, oEndPt)) {
michael@0 117 other.addTPair(oEndT, &thisOne, endT, true, oEndPt);
michael@0 118 }
michael@0 119 }
michael@0 120 #if DEBUG_CONCIDENT
michael@0 121 thisOne.debugShowTs("+");
michael@0 122 other.debugShowTs("o");
michael@0 123 #endif
michael@0 124 }
michael@0 125 }
michael@0 126
michael@0 127 bool SkOpContour::addPartialCoincident(int index, SkOpContour* other, int otherIndex,
michael@0 128 const SkIntersections& ts, int ptIndex, bool swap) {
michael@0 129 SkPoint pt0 = ts.pt(ptIndex).asSkPoint();
michael@0 130 SkPoint pt1 = ts.pt(ptIndex + 1).asSkPoint();
michael@0 131 if (SkDPoint::ApproximatelyEqual(pt0, pt1)) {
michael@0 132 // FIXME: one could imagine a case where it would be incorrect to ignore this
michael@0 133 // suppose two self-intersecting cubics overlap to form a partial coincidence --
michael@0 134 // although it isn't clear why the regular coincidence could wouldn't pick this up
michael@0 135 // this is exceptional enough to ignore for now
michael@0 136 return false;
michael@0 137 }
michael@0 138 SkCoincidence& coincidence = fPartialCoincidences.push_back();
michael@0 139 coincidence.fOther = other;
michael@0 140 coincidence.fSegments[0] = index;
michael@0 141 coincidence.fSegments[1] = otherIndex;
michael@0 142 coincidence.fTs[swap][0] = ts[0][ptIndex];
michael@0 143 coincidence.fTs[swap][1] = ts[0][ptIndex + 1];
michael@0 144 coincidence.fTs[!swap][0] = ts[1][ptIndex];
michael@0 145 coincidence.fTs[!swap][1] = ts[1][ptIndex + 1];
michael@0 146 coincidence.fPts[0] = pt0;
michael@0 147 coincidence.fPts[1] = pt1;
michael@0 148 return true;
michael@0 149 }
michael@0 150
michael@0 151 void SkOpContour::calcCoincidentWinding() {
michael@0 152 int count = fCoincidences.count();
michael@0 153 #if DEBUG_CONCIDENT
michael@0 154 if (count > 0) {
michael@0 155 SkDebugf("%s count=%d\n", __FUNCTION__, count);
michael@0 156 }
michael@0 157 #endif
michael@0 158 for (int index = 0; index < count; ++index) {
michael@0 159 SkCoincidence& coincidence = fCoincidences[index];
michael@0 160 calcCommonCoincidentWinding(coincidence);
michael@0 161 }
michael@0 162 }
michael@0 163
michael@0 164 void SkOpContour::calcPartialCoincidentWinding() {
michael@0 165 int count = fPartialCoincidences.count();
michael@0 166 #if DEBUG_CONCIDENT
michael@0 167 if (count > 0) {
michael@0 168 SkDebugf("%s count=%d\n", __FUNCTION__, count);
michael@0 169 }
michael@0 170 #endif
michael@0 171 for (int index = 0; index < count; ++index) {
michael@0 172 SkCoincidence& coincidence = fPartialCoincidences[index];
michael@0 173 calcCommonCoincidentWinding(coincidence);
michael@0 174 }
michael@0 175 }
michael@0 176
michael@0 177 void SkOpContour::joinCoincidence(const SkTArray<SkCoincidence, true>& coincidences, bool partial) {
michael@0 178 int count = coincidences.count();
michael@0 179 #if DEBUG_CONCIDENT
michael@0 180 if (count > 0) {
michael@0 181 SkDebugf("%s count=%d\n", __FUNCTION__, count);
michael@0 182 }
michael@0 183 #endif
michael@0 184 // look for a lineup where the partial implies another adjoining coincidence
michael@0 185 for (int index = 0; index < count; ++index) {
michael@0 186 const SkCoincidence& coincidence = coincidences[index];
michael@0 187 int thisIndex = coincidence.fSegments[0];
michael@0 188 SkOpSegment& thisOne = fSegments[thisIndex];
michael@0 189 SkOpContour* otherContour = coincidence.fOther;
michael@0 190 int otherIndex = coincidence.fSegments[1];
michael@0 191 SkOpSegment& other = otherContour->fSegments[otherIndex];
michael@0 192 double startT = coincidence.fTs[0][0];
michael@0 193 double endT = coincidence.fTs[0][1];
michael@0 194 if (startT == endT) { // this can happen in very large compares
michael@0 195 continue;
michael@0 196 }
michael@0 197 double oStartT = coincidence.fTs[1][0];
michael@0 198 double oEndT = coincidence.fTs[1][1];
michael@0 199 if (oStartT == oEndT) {
michael@0 200 continue;
michael@0 201 }
michael@0 202 bool swapStart = startT > endT;
michael@0 203 bool swapOther = oStartT > oEndT;
michael@0 204 if (swapStart) {
michael@0 205 SkTSwap<double>(startT, endT);
michael@0 206 SkTSwap<double>(oStartT, oEndT);
michael@0 207 }
michael@0 208 bool cancel = swapOther != swapStart;
michael@0 209 int step = swapStart ? -1 : 1;
michael@0 210 int oStep = swapOther ? -1 : 1;
michael@0 211 double oMatchStart = cancel ? oEndT : oStartT;
michael@0 212 if (partial ? startT != 0 || oMatchStart != 0 : (startT == 0) != (oMatchStart == 0)) {
michael@0 213 bool added = false;
michael@0 214 if (oMatchStart != 0) {
michael@0 215 added = thisOne.joinCoincidence(&other, oMatchStart, oStep, cancel);
michael@0 216 }
michael@0 217 if (!cancel && startT != 0 && !added) {
michael@0 218 (void) other.joinCoincidence(&thisOne, startT, step, cancel);
michael@0 219 }
michael@0 220 }
michael@0 221 double oMatchEnd = cancel ? oStartT : oEndT;
michael@0 222 if (partial ? endT != 1 || oMatchEnd != 1 : (endT == 1) != (oMatchEnd == 1)) {
michael@0 223 bool added = false;
michael@0 224 if (cancel && endT != 1 && !added) {
michael@0 225 (void) other.joinCoincidence(&thisOne, endT, -step, cancel);
michael@0 226 }
michael@0 227 }
michael@0 228 }
michael@0 229 }
michael@0 230
michael@0 231 void SkOpContour::calcCommonCoincidentWinding(const SkCoincidence& coincidence) {
michael@0 232 int thisIndex = coincidence.fSegments[0];
michael@0 233 SkOpSegment& thisOne = fSegments[thisIndex];
michael@0 234 if (thisOne.done()) {
michael@0 235 return;
michael@0 236 }
michael@0 237 SkOpContour* otherContour = coincidence.fOther;
michael@0 238 int otherIndex = coincidence.fSegments[1];
michael@0 239 SkOpSegment& other = otherContour->fSegments[otherIndex];
michael@0 240 if (other.done()) {
michael@0 241 return;
michael@0 242 }
michael@0 243 double startT = coincidence.fTs[0][0];
michael@0 244 double endT = coincidence.fTs[0][1];
michael@0 245 const SkPoint* startPt = &coincidence.fPts[0];
michael@0 246 const SkPoint* endPt = &coincidence.fPts[1];
michael@0 247 bool cancelers;
michael@0 248 if ((cancelers = startT > endT)) {
michael@0 249 SkTSwap<double>(startT, endT);
michael@0 250 SkTSwap<const SkPoint*>(startPt, endPt);
michael@0 251 }
michael@0 252 if (startT == endT) { // if span is very large, the smaller may have collapsed to nothing
michael@0 253 if (endT <= 1 - FLT_EPSILON) {
michael@0 254 endT += FLT_EPSILON;
michael@0 255 SkASSERT(endT <= 1);
michael@0 256 } else {
michael@0 257 startT -= FLT_EPSILON;
michael@0 258 SkASSERT(startT >= 0);
michael@0 259 }
michael@0 260 }
michael@0 261 SkASSERT(!approximately_negative(endT - startT));
michael@0 262 double oStartT = coincidence.fTs[1][0];
michael@0 263 double oEndT = coincidence.fTs[1][1];
michael@0 264 if (oStartT > oEndT) {
michael@0 265 SkTSwap<double>(oStartT, oEndT);
michael@0 266 cancelers ^= true;
michael@0 267 }
michael@0 268 SkASSERT(!approximately_negative(oEndT - oStartT));
michael@0 269 if (cancelers) {
michael@0 270 thisOne.addTCancel(*startPt, *endPt, &other);
michael@0 271 } else {
michael@0 272 thisOne.addTCoincident(*startPt, *endPt, endT, &other);
michael@0 273 }
michael@0 274 #if DEBUG_CONCIDENT
michael@0 275 thisOne.debugShowTs("p");
michael@0 276 other.debugShowTs("o");
michael@0 277 #endif
michael@0 278 }
michael@0 279
michael@0 280 void SkOpContour::sortSegments() {
michael@0 281 int segmentCount = fSegments.count();
michael@0 282 fSortedSegments.push_back_n(segmentCount);
michael@0 283 for (int test = 0; test < segmentCount; ++test) {
michael@0 284 fSortedSegments[test] = &fSegments[test];
michael@0 285 }
michael@0 286 SkTQSort<SkOpSegment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
michael@0 287 fFirstSorted = 0;
michael@0 288 }
michael@0 289
michael@0 290 void SkOpContour::toPath(SkPathWriter* path) const {
michael@0 291 int segmentCount = fSegments.count();
michael@0 292 const SkPoint& pt = fSegments.front().pts()[0];
michael@0 293 path->deferredMove(pt);
michael@0 294 for (int test = 0; test < segmentCount; ++test) {
michael@0 295 fSegments[test].addCurveTo(0, 1, path, true);
michael@0 296 }
michael@0 297 path->close();
michael@0 298 }
michael@0 299
michael@0 300 void SkOpContour::topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY,
michael@0 301 SkOpSegment** topStart) {
michael@0 302 int segmentCount = fSortedSegments.count();
michael@0 303 SkASSERT(segmentCount > 0);
michael@0 304 int sortedIndex = fFirstSorted;
michael@0 305 fDone = true; // may be cleared below
michael@0 306 for ( ; sortedIndex < segmentCount; ++sortedIndex) {
michael@0 307 SkOpSegment* testSegment = fSortedSegments[sortedIndex];
michael@0 308 if (testSegment->done()) {
michael@0 309 if (sortedIndex == fFirstSorted) {
michael@0 310 ++fFirstSorted;
michael@0 311 }
michael@0 312 continue;
michael@0 313 }
michael@0 314 fDone = false;
michael@0 315 SkPoint testXY = testSegment->activeLeftTop(true, NULL);
michael@0 316 if (*topStart) {
michael@0 317 if (testXY.fY < topLeft.fY) {
michael@0 318 continue;
michael@0 319 }
michael@0 320 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
michael@0 321 continue;
michael@0 322 }
michael@0 323 if (bestXY->fY < testXY.fY) {
michael@0 324 continue;
michael@0 325 }
michael@0 326 if (bestXY->fY == testXY.fY && bestXY->fX < testXY.fX) {
michael@0 327 continue;
michael@0 328 }
michael@0 329 }
michael@0 330 *topStart = testSegment;
michael@0 331 *bestXY = testXY;
michael@0 332 }
michael@0 333 }
michael@0 334
michael@0 335 SkOpSegment* SkOpContour::undoneSegment(int* start, int* end) {
michael@0 336 int segmentCount = fSegments.count();
michael@0 337 for (int test = 0; test < segmentCount; ++test) {
michael@0 338 SkOpSegment* testSegment = &fSegments[test];
michael@0 339 if (testSegment->done()) {
michael@0 340 continue;
michael@0 341 }
michael@0 342 testSegment->undoneSpan(start, end);
michael@0 343 return testSegment;
michael@0 344 }
michael@0 345 return NULL;
michael@0 346 }
michael@0 347
michael@0 348 #if DEBUG_SHOW_WINDING
michael@0 349 int SkOpContour::debugShowWindingValues(int totalSegments, int ofInterest) {
michael@0 350 int count = fSegments.count();
michael@0 351 int sum = 0;
michael@0 352 for (int index = 0; index < count; ++index) {
michael@0 353 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest);
michael@0 354 }
michael@0 355 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum);
michael@0 356 return sum;
michael@0 357 }
michael@0 358
michael@0 359 void SkOpContour::debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList) {
michael@0 360 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13;
michael@0 361 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16;
michael@0 362 int ofInterest = 1 << 5 | 1 << 8;
michael@0 363 int total = 0;
michael@0 364 int index;
michael@0 365 for (index = 0; index < contourList.count(); ++index) {
michael@0 366 total += contourList[index]->segments().count();
michael@0 367 }
michael@0 368 int sum = 0;
michael@0 369 for (index = 0; index < contourList.count(); ++index) {
michael@0 370 sum += contourList[index]->debugShowWindingValues(total, ofInterest);
michael@0 371 }
michael@0 372 // SkDebugf("%s total=%d\n", __FUNCTION__, sum);
michael@0 373 }
michael@0 374 #endif
michael@0 375
michael@0 376 void SkOpContour::setBounds() {
michael@0 377 int count = fSegments.count();
michael@0 378 if (count == 0) {
michael@0 379 SkDebugf("%s empty contour\n", __FUNCTION__);
michael@0 380 SkASSERT(0);
michael@0 381 // FIXME: delete empty contour?
michael@0 382 return;
michael@0 383 }
michael@0 384 fBounds = fSegments.front().bounds();
michael@0 385 for (int index = 1; index < count; ++index) {
michael@0 386 fBounds.add(fSegments[index].bounds());
michael@0 387 }
michael@0 388 }

mercurial