gfx/skia/trunk/src/pathops/SkPathOpsOp.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
michael@0 12 // FIXME: this and find chase should be merge together, along with
michael@0 13 // other code that walks winding in angles
michael@0 14 // OPTIMIZATION: Probably, the walked winding should be rolled into the angle structure
michael@0 15 // so it isn't duplicated by walkers like this one
michael@0 16 static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int& nextStart, int& nextEnd) {
michael@0 17 while (chase.count()) {
michael@0 18 SkOpSpan* span;
michael@0 19 chase.pop(&span);
michael@0 20 const SkOpSpan& backPtr = span->fOther->span(span->fOtherIndex);
michael@0 21 SkOpSegment* segment = backPtr.fOther;
michael@0 22 nextStart = backPtr.fOtherIndex;
michael@0 23 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles;
michael@0 24 int done = 0;
michael@0 25 if (segment->activeAngle(nextStart, &done, &angles)) {
michael@0 26 SkOpAngle* last = angles.end() - 1;
michael@0 27 nextStart = last->start();
michael@0 28 nextEnd = last->end();
michael@0 29 #if TRY_ROTATE
michael@0 30 *chase.insert(0) = span;
michael@0 31 #else
michael@0 32 *chase.append() = span;
michael@0 33 #endif
michael@0 34 return last->segment();
michael@0 35 }
michael@0 36 if (done == angles.count()) {
michael@0 37 continue;
michael@0 38 }
michael@0 39 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted;
michael@0 40 bool sortable = SkOpSegment::SortAngles(angles, &sorted,
michael@0 41 SkOpSegment::kMayBeUnordered_SortAngleKind);
michael@0 42 int angleCount = sorted.count();
michael@0 43 #if DEBUG_SORT
michael@0 44 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, sortable);
michael@0 45 #endif
michael@0 46 if (!sortable) {
michael@0 47 continue;
michael@0 48 }
michael@0 49 // find first angle, initialize winding to computed fWindSum
michael@0 50 int firstIndex = -1;
michael@0 51 const SkOpAngle* angle;
michael@0 52 bool foundAngle = true;
michael@0 53 do {
michael@0 54 ++firstIndex;
michael@0 55 if (firstIndex >= angleCount) {
michael@0 56 foundAngle = false;
michael@0 57 break;
michael@0 58 }
michael@0 59 angle = sorted[firstIndex];
michael@0 60 segment = angle->segment();
michael@0 61 } while (segment->windSum(angle) == SK_MinS32);
michael@0 62 if (!foundAngle) {
michael@0 63 continue;
michael@0 64 }
michael@0 65 #if DEBUG_SORT
michael@0 66 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, sortable);
michael@0 67 #endif
michael@0 68 int sumMiWinding = segment->updateWindingReverse(angle);
michael@0 69 int sumSuWinding = segment->updateOppWindingReverse(angle);
michael@0 70 if (segment->operand()) {
michael@0 71 SkTSwap<int>(sumMiWinding, sumSuWinding);
michael@0 72 }
michael@0 73 int nextIndex = firstIndex + 1;
michael@0 74 int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
michael@0 75 SkOpSegment* first = NULL;
michael@0 76 do {
michael@0 77 SkASSERT(nextIndex != firstIndex);
michael@0 78 if (nextIndex == angleCount) {
michael@0 79 nextIndex = 0;
michael@0 80 }
michael@0 81 angle = sorted[nextIndex];
michael@0 82 segment = angle->segment();
michael@0 83 int start = angle->start();
michael@0 84 int end = angle->end();
michael@0 85 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
michael@0 86 segment->setUpWindings(start, end, &sumMiWinding, &sumSuWinding,
michael@0 87 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
michael@0 88 if (!segment->done(angle)) {
michael@0 89 if (!first) {
michael@0 90 first = segment;
michael@0 91 nextStart = start;
michael@0 92 nextEnd = end;
michael@0 93 }
michael@0 94 (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding,
michael@0 95 oppSumWinding, angle);
michael@0 96 }
michael@0 97 } while (++nextIndex != lastIndex);
michael@0 98 if (first) {
michael@0 99 #if TRY_ROTATE
michael@0 100 *chase.insert(0) = span;
michael@0 101 #else
michael@0 102 *chase.append() = span;
michael@0 103 #endif
michael@0 104 return first;
michael@0 105 }
michael@0 106 }
michael@0 107 return NULL;
michael@0 108 }
michael@0 109
michael@0 110 /*
michael@0 111 static bool windingIsActive(int winding, int oppWinding, int spanWinding, int oppSpanWinding,
michael@0 112 bool windingIsOp, PathOp op) {
michael@0 113 bool active = windingIsActive(winding, spanWinding);
michael@0 114 if (!active) {
michael@0 115 return false;
michael@0 116 }
michael@0 117 if (oppSpanWinding && windingIsActive(oppWinding, oppSpanWinding)) {
michael@0 118 switch (op) {
michael@0 119 case kIntersect_Op:
michael@0 120 case kUnion_Op:
michael@0 121 return true;
michael@0 122 case kDifference_Op: {
michael@0 123 int absSpan = abs(spanWinding);
michael@0 124 int absOpp = abs(oppSpanWinding);
michael@0 125 return windingIsOp ? absSpan < absOpp : absSpan > absOpp;
michael@0 126 }
michael@0 127 case kXor_Op:
michael@0 128 return spanWinding != oppSpanWinding;
michael@0 129 default:
michael@0 130 SkASSERT(0);
michael@0 131 }
michael@0 132 }
michael@0 133 bool opActive = oppWinding != 0;
michael@0 134 return gOpLookup[op][opActive][windingIsOp];
michael@0 135 }
michael@0 136 */
michael@0 137
michael@0 138 static bool bridgeOp(SkTArray<SkOpContour*, true>& contourList, const SkPathOp op,
michael@0 139 const int xorMask, const int xorOpMask, SkPathWriter* simple) {
michael@0 140 bool firstContour = true;
michael@0 141 bool unsortable = false;
michael@0 142 bool topUnsortable = false;
michael@0 143 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
michael@0 144 do {
michael@0 145 int index, endIndex;
michael@0 146 bool done;
michael@0 147 SkOpSegment* current = FindSortableTop(contourList, SkOpAngle::kBinarySingle, &firstContour,
michael@0 148 &index, &endIndex, &topLeft, &topUnsortable, &done);
michael@0 149 if (!current) {
michael@0 150 if (topUnsortable || !done) {
michael@0 151 topUnsortable = false;
michael@0 152 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
michael@0 153 topLeft.fX = topLeft.fY = SK_ScalarMin;
michael@0 154 continue;
michael@0 155 }
michael@0 156 break;
michael@0 157 }
michael@0 158 SkTDArray<SkOpSpan*> chaseArray;
michael@0 159 do {
michael@0 160 if (current->activeOp(index, endIndex, xorMask, xorOpMask, op)) {
michael@0 161 do {
michael@0 162 if (!unsortable && current->done()) {
michael@0 163 #if DEBUG_ACTIVE_SPANS
michael@0 164 DebugShowActiveSpans(contourList);
michael@0 165 #endif
michael@0 166 if (simple->isEmpty()) {
michael@0 167 simple->init();
michael@0 168 }
michael@0 169 break;
michael@0 170 }
michael@0 171 SkASSERT(unsortable || !current->done());
michael@0 172 int nextStart = index;
michael@0 173 int nextEnd = endIndex;
michael@0 174 SkOpSegment* next = current->findNextOp(&chaseArray, &nextStart, &nextEnd,
michael@0 175 &unsortable, op, xorMask, xorOpMask);
michael@0 176 if (!next) {
michael@0 177 if (!unsortable && simple->hasMove()
michael@0 178 && current->verb() != SkPath::kLine_Verb
michael@0 179 && !simple->isClosed()) {
michael@0 180 current->addCurveTo(index, endIndex, simple, true);
michael@0 181 SkASSERT(simple->isClosed());
michael@0 182 }
michael@0 183 break;
michael@0 184 }
michael@0 185 #if DEBUG_FLOW
michael@0 186 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
michael@0 187 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
michael@0 188 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
michael@0 189 #endif
michael@0 190 current->addCurveTo(index, endIndex, simple, true);
michael@0 191 current = next;
michael@0 192 index = nextStart;
michael@0 193 endIndex = nextEnd;
michael@0 194 } while (!simple->isClosed() && (!unsortable
michael@0 195 || !current->done(SkMin32(index, endIndex))));
michael@0 196 if (current->activeWinding(index, endIndex) && !simple->isClosed()) {
michael@0 197 // FIXME : add to simplify, xor cpaths
michael@0 198 int min = SkMin32(index, endIndex);
michael@0 199 if (!unsortable && !simple->isEmpty()) {
michael@0 200 unsortable = current->checkSmall(min);
michael@0 201 }
michael@0 202 SkASSERT(unsortable || simple->isEmpty());
michael@0 203 if (!current->done(min)) {
michael@0 204 current->addCurveTo(index, endIndex, simple, true);
michael@0 205 current->markDoneBinary(min);
michael@0 206 }
michael@0 207 }
michael@0 208 simple->close();
michael@0 209 } else {
michael@0 210 SkOpSpan* last = current->markAndChaseDoneBinary(index, endIndex);
michael@0 211 if (last && !last->fLoop) {
michael@0 212 *chaseArray.append() = last;
michael@0 213 }
michael@0 214 }
michael@0 215 current = findChaseOp(chaseArray, index, endIndex);
michael@0 216 #if DEBUG_ACTIVE_SPANS
michael@0 217 DebugShowActiveSpans(contourList);
michael@0 218 #endif
michael@0 219 if (!current) {
michael@0 220 break;
michael@0 221 }
michael@0 222 } while (true);
michael@0 223 } while (true);
michael@0 224 return simple->someAssemblyRequired();
michael@0 225 }
michael@0 226
michael@0 227 // pretty picture:
michael@0 228 // https://docs.google.com/a/google.com/drawings/d/1sPV8rPfpEFXymBp3iSbDRWAycp1b-7vD9JP2V-kn9Ss/edit?usp=sharing
michael@0 229 static const SkPathOp gOpInverse[kReverseDifference_PathOp + 1][2][2] = {
michael@0 230 // inside minuend outside minuend
michael@0 231 // inside subtrahend outside subtrahend inside subtrahend outside subtrahend
michael@0 232 {{ kDifference_PathOp, kIntersect_PathOp }, { kUnion_PathOp, kReverseDifference_PathOp }},
michael@0 233 {{ kIntersect_PathOp, kDifference_PathOp }, { kReverseDifference_PathOp, kUnion_PathOp }},
michael@0 234 {{ kUnion_PathOp, kReverseDifference_PathOp }, { kDifference_PathOp, kIntersect_PathOp }},
michael@0 235 {{ kXOR_PathOp, kXOR_PathOp }, { kXOR_PathOp, kXOR_PathOp }},
michael@0 236 {{ kReverseDifference_PathOp, kUnion_PathOp }, { kIntersect_PathOp, kDifference_PathOp }},
michael@0 237 };
michael@0 238
michael@0 239 static const bool gOutInverse[kReverseDifference_PathOp + 1][2][2] = {
michael@0 240 {{ false, false }, { true, false }}, // diff
michael@0 241 {{ false, false }, { false, true }}, // sect
michael@0 242 {{ false, true }, { true, true }}, // union
michael@0 243 {{ false, true }, { true, false }}, // xor
michael@0 244 {{ false, true }, { false, false }}, // rev diff
michael@0 245 };
michael@0 246
michael@0 247 bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
michael@0 248 #if DEBUG_SHOW_TEST_NAME
michael@0 249 char* debugName = DEBUG_FILENAME_STRING;
michael@0 250 if (debugName && debugName[0]) {
michael@0 251 SkPathOpsDebug::BumpTestName(debugName);
michael@0 252 SkPathOpsDebug::ShowPath(one, two, op, debugName);
michael@0 253 }
michael@0 254 #endif
michael@0 255 op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()];
michael@0 256 SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isInverseFillType()]
michael@0 257 ? SkPath::kInverseEvenOdd_FillType : SkPath::kEvenOdd_FillType;
michael@0 258 const SkPath* minuend = &one;
michael@0 259 const SkPath* subtrahend = &two;
michael@0 260 if (op == kReverseDifference_PathOp) {
michael@0 261 minuend = &two;
michael@0 262 subtrahend = &one;
michael@0 263 op = kDifference_PathOp;
michael@0 264 }
michael@0 265 #if DEBUG_SORT || DEBUG_SWAP_TOP
michael@0 266 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault;
michael@0 267 #endif
michael@0 268 // turn path into list of segments
michael@0 269 SkTArray<SkOpContour> contours;
michael@0 270 // FIXME: add self-intersecting cubics' T values to segment
michael@0 271 SkOpEdgeBuilder builder(*minuend, contours);
michael@0 272 const int xorMask = builder.xorMask();
michael@0 273 builder.addOperand(*subtrahend);
michael@0 274 if (!builder.finish()) {
michael@0 275 return false;
michael@0 276 }
michael@0 277 result->reset();
michael@0 278 result->setFillType(fillType);
michael@0 279 const int xorOpMask = builder.xorMask();
michael@0 280 SkTArray<SkOpContour*, true> contourList;
michael@0 281 MakeContourList(contours, contourList, xorMask == kEvenOdd_PathOpsMask,
michael@0 282 xorOpMask == kEvenOdd_PathOpsMask);
michael@0 283 SkOpContour** currentPtr = contourList.begin();
michael@0 284 if (!currentPtr) {
michael@0 285 return true;
michael@0 286 }
michael@0 287 SkOpContour** listEnd = contourList.end();
michael@0 288 // find all intersections between segments
michael@0 289 do {
michael@0 290 SkOpContour** nextPtr = currentPtr;
michael@0 291 SkOpContour* current = *currentPtr++;
michael@0 292 if (current->containsCubics()) {
michael@0 293 AddSelfIntersectTs(current);
michael@0 294 }
michael@0 295 SkOpContour* next;
michael@0 296 do {
michael@0 297 next = *nextPtr++;
michael@0 298 } while (AddIntersectTs(current, next) && nextPtr != listEnd);
michael@0 299 } while (currentPtr != listEnd);
michael@0 300 // eat through coincident edges
michael@0 301
michael@0 302 int total = 0;
michael@0 303 int index;
michael@0 304 for (index = 0; index < contourList.count(); ++index) {
michael@0 305 total += contourList[index]->segments().count();
michael@0 306 }
michael@0 307 HandleCoincidence(&contourList, total);
michael@0 308 // construct closed contours
michael@0 309 SkPathWriter wrapper(*result);
michael@0 310 bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper);
michael@0 311 { // if some edges could not be resolved, assemble remaining fragments
michael@0 312 SkPath temp;
michael@0 313 temp.setFillType(fillType);
michael@0 314 SkPathWriter assembled(temp);
michael@0 315 Assemble(wrapper, &assembled);
michael@0 316 *result = *assembled.nativePath();
michael@0 317 result->setFillType(fillType);
michael@0 318 }
michael@0 319 return true;
michael@0 320 }

mercurial