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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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 static bool bridgeWinding(SkTArray<SkOpContour*, true>& contourList, SkPathWriter* simple) {
michael@0 13 bool firstContour = true;
michael@0 14 bool unsortable = false;
michael@0 15 bool topUnsortable = false;
michael@0 16 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
michael@0 17 do {
michael@0 18 int index, endIndex;
michael@0 19 bool topDone;
michael@0 20 SkOpSegment* current = FindSortableTop(contourList, SkOpAngle::kUnaryWinding, &firstContour,
michael@0 21 &index, &endIndex, &topLeft, &topUnsortable, &topDone);
michael@0 22 if (!current) {
michael@0 23 if (topUnsortable || !topDone) {
michael@0 24 topUnsortable = false;
michael@0 25 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
michael@0 26 topLeft.fX = topLeft.fY = SK_ScalarMin;
michael@0 27 continue;
michael@0 28 }
michael@0 29 break;
michael@0 30 }
michael@0 31 SkTDArray<SkOpSpan*> chaseArray;
michael@0 32 do {
michael@0 33 if (current->activeWinding(index, endIndex)) {
michael@0 34 do {
michael@0 35 if (!unsortable && current->done()) {
michael@0 36 #if DEBUG_ACTIVE_SPANS
michael@0 37 DebugShowActiveSpans(contourList);
michael@0 38 #endif
michael@0 39 if (simple->isEmpty()) {
michael@0 40 simple->init();
michael@0 41 break;
michael@0 42 }
michael@0 43 }
michael@0 44 SkASSERT(unsortable || !current->done());
michael@0 45 int nextStart = index;
michael@0 46 int nextEnd = endIndex;
michael@0 47 SkOpSegment* next = current->findNextWinding(&chaseArray, &nextStart, &nextEnd,
michael@0 48 &unsortable);
michael@0 49 if (!next) {
michael@0 50 if (!unsortable && simple->hasMove()
michael@0 51 && current->verb() != SkPath::kLine_Verb
michael@0 52 && !simple->isClosed()) {
michael@0 53 current->addCurveTo(index, endIndex, simple, true);
michael@0 54 SkASSERT(simple->isClosed());
michael@0 55 }
michael@0 56 break;
michael@0 57 }
michael@0 58 #if DEBUG_FLOW
michael@0 59 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
michael@0 60 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY,
michael@0 61 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY);
michael@0 62 #endif
michael@0 63 current->addCurveTo(index, endIndex, simple, true);
michael@0 64 current = next;
michael@0 65 index = nextStart;
michael@0 66 endIndex = nextEnd;
michael@0 67 } while (!simple->isClosed() && (!unsortable
michael@0 68 || !current->done(SkMin32(index, endIndex))));
michael@0 69 if (current->activeWinding(index, endIndex) && !simple->isClosed()) {
michael@0 70 SkASSERT(unsortable || simple->isEmpty());
michael@0 71 int min = SkMin32(index, endIndex);
michael@0 72 if (!current->done(min)) {
michael@0 73 current->addCurveTo(index, endIndex, simple, true);
michael@0 74 current->markDoneUnary(min);
michael@0 75 }
michael@0 76 }
michael@0 77 simple->close();
michael@0 78 } else {
michael@0 79 SkOpSpan* last = current->markAndChaseDoneUnary(index, endIndex);
michael@0 80 if (last && !last->fLoop) {
michael@0 81 *chaseArray.append() = last;
michael@0 82 }
michael@0 83 }
michael@0 84 current = FindChase(chaseArray, index, endIndex);
michael@0 85 #if DEBUG_ACTIVE_SPANS
michael@0 86 DebugShowActiveSpans(contourList);
michael@0 87 #endif
michael@0 88 if (!current) {
michael@0 89 break;
michael@0 90 }
michael@0 91 } while (true);
michael@0 92 } while (true);
michael@0 93 return simple->someAssemblyRequired();
michael@0 94 }
michael@0 95
michael@0 96 // returns true if all edges were processed
michael@0 97 static bool bridgeXor(SkTArray<SkOpContour*, true>& contourList, SkPathWriter* simple) {
michael@0 98 SkOpSegment* current;
michael@0 99 int start, end;
michael@0 100 bool unsortable = false;
michael@0 101 bool closable = true;
michael@0 102 while ((current = FindUndone(contourList, &start, &end))) {
michael@0 103 do {
michael@0 104 #if DEBUG_ACTIVE_SPANS
michael@0 105 if (!unsortable && current->done()) {
michael@0 106 DebugShowActiveSpans(contourList);
michael@0 107 }
michael@0 108 #endif
michael@0 109 SkASSERT(unsortable || !current->done());
michael@0 110 int nextStart = start;
michael@0 111 int nextEnd = end;
michael@0 112 SkOpSegment* next = current->findNextXor(&nextStart, &nextEnd, &unsortable);
michael@0 113 if (!next) {
michael@0 114 if (!unsortable && simple->hasMove()
michael@0 115 && current->verb() != SkPath::kLine_Verb
michael@0 116 && !simple->isClosed()) {
michael@0 117 current->addCurveTo(start, end, simple, true);
michael@0 118 SkASSERT(simple->isClosed());
michael@0 119 }
michael@0 120 break;
michael@0 121 }
michael@0 122 #if DEBUG_FLOW
michael@0 123 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__,
michael@0 124 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY,
michael@0 125 current->xyAtT(end).fX, current->xyAtT(end).fY);
michael@0 126 #endif
michael@0 127 current->addCurveTo(start, end, simple, true);
michael@0 128 current = next;
michael@0 129 start = nextStart;
michael@0 130 end = nextEnd;
michael@0 131 } while (!simple->isClosed() && (!unsortable || !current->done(SkMin32(start, end))));
michael@0 132 if (!simple->isClosed()) {
michael@0 133 SkASSERT(unsortable);
michael@0 134 int min = SkMin32(start, end);
michael@0 135 if (!current->done(min)) {
michael@0 136 current->addCurveTo(start, end, simple, true);
michael@0 137 current->markDone(min, 1);
michael@0 138 }
michael@0 139 closable = false;
michael@0 140 }
michael@0 141 simple->close();
michael@0 142 #if DEBUG_ACTIVE_SPANS
michael@0 143 DebugShowActiveSpans(contourList);
michael@0 144 #endif
michael@0 145 }
michael@0 146 return closable;
michael@0 147 }
michael@0 148
michael@0 149 // FIXME : add this as a member of SkPath
michael@0 150 bool Simplify(const SkPath& path, SkPath* result) {
michael@0 151 #if DEBUG_SORT || DEBUG_SWAP_TOP
michael@0 152 SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault;
michael@0 153 #endif
michael@0 154 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
michael@0 155 SkPath::FillType fillType = path.isInverseFillType() ? SkPath::kInverseEvenOdd_FillType
michael@0 156 : SkPath::kEvenOdd_FillType;
michael@0 157
michael@0 158 // turn path into list of segments
michael@0 159 SkTArray<SkOpContour> contours;
michael@0 160 SkOpEdgeBuilder builder(path, contours);
michael@0 161 if (!builder.finish()) {
michael@0 162 return false;
michael@0 163 }
michael@0 164 SkTArray<SkOpContour*, true> contourList;
michael@0 165 MakeContourList(contours, contourList, false, false);
michael@0 166 SkOpContour** currentPtr = contourList.begin();
michael@0 167 result->reset();
michael@0 168 result->setFillType(fillType);
michael@0 169 if (!currentPtr) {
michael@0 170 return true;
michael@0 171 }
michael@0 172 SkOpContour** listEnd = contourList.end();
michael@0 173 // find all intersections between segments
michael@0 174 do {
michael@0 175 SkOpContour** nextPtr = currentPtr;
michael@0 176 SkOpContour* current = *currentPtr++;
michael@0 177 if (current->containsCubics()) {
michael@0 178 AddSelfIntersectTs(current);
michael@0 179 }
michael@0 180 SkOpContour* next;
michael@0 181 do {
michael@0 182 next = *nextPtr++;
michael@0 183 } while (AddIntersectTs(current, next) && nextPtr != listEnd);
michael@0 184 } while (currentPtr != listEnd);
michael@0 185 HandleCoincidence(&contourList, 0);
michael@0 186 // construct closed contours
michael@0 187 SkPathWriter simple(*result);
michael@0 188 if (builder.xorMask() == kWinding_PathOpsMask ? bridgeWinding(contourList, &simple)
michael@0 189 : !bridgeXor(contourList, &simple))
michael@0 190 { // if some edges could not be resolved, assemble remaining fragments
michael@0 191 SkPath temp;
michael@0 192 temp.setFillType(fillType);
michael@0 193 SkPathWriter assembled(temp);
michael@0 194 Assemble(simple, &assembled);
michael@0 195 *result = *assembled.nativePath();
michael@0 196 result->setFillType(fillType);
michael@0 197 }
michael@0 198 return true;
michael@0 199 }

mercurial