| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 #include "SkGeometry.h" |
| 7 #include "SkOpEdgeBuilder.h" | 8 #include "SkOpEdgeBuilder.h" |
| 8 #include "SkReduceOrder.h" | 9 #include "SkReduceOrder.h" |
| 9 | 10 |
| 10 void SkOpEdgeBuilder::init() { | 11 void SkOpEdgeBuilder::init() { |
| 11 fCurrentContour = NULL; | 12 fCurrentContour = NULL; |
| 12 fOperand = false; | 13 fOperand = false; |
| 13 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMas
k | 14 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMas
k |
| 14 : kWinding_PathOpsMask; | 15 : kWinding_PathOpsMask; |
| 15 #if DEBUG_DUMP | 16 #if DEBUG_DUMP |
| 16 gContourID = 0; | 17 gContourID = 0; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 30 } | 31 } |
| 31 | 32 |
| 32 bool SkOpEdgeBuilder::finish() { | 33 bool SkOpEdgeBuilder::finish() { |
| 33 if (fUnparseable || !walk()) { | 34 if (fUnparseable || !walk()) { |
| 34 return false; | 35 return false; |
| 35 } | 36 } |
| 36 complete(); | 37 complete(); |
| 37 if (fCurrentContour && !fCurrentContour->segments().count()) { | 38 if (fCurrentContour && !fCurrentContour->segments().count()) { |
| 38 fContours.pop_back(); | 39 fContours.pop_back(); |
| 39 } | 40 } |
| 40 // correct pointers in contours since fReducePts may have moved as it grew | |
| 41 int cIndex = 0; | |
| 42 int extraCount = fExtra.count(); | |
| 43 SkASSERT(extraCount == 0 || fExtra[0] == -1); | |
| 44 int eIndex = 0; | |
| 45 int rIndex = 0; | |
| 46 while (++eIndex < extraCount) { | |
| 47 int offset = fExtra[eIndex]; | |
| 48 if (offset < 0) { | |
| 49 ++cIndex; | |
| 50 continue; | |
| 51 } | |
| 52 fCurrentContour = &fContours[cIndex]; | |
| 53 rIndex += fCurrentContour->updateSegment(offset - 1, | |
| 54 &fReducePts[rIndex]); | |
| 55 } | |
| 56 fExtra.reset(); // we're done with this | |
| 57 return true; | 41 return true; |
| 58 } | 42 } |
| 59 | 43 |
| 60 // Note that copying the points here avoids copying the resulting path later. | 44 void SkOpEdgeBuilder::closeContour(const SkPoint& curveEnd, const SkPoint& curve
Start) { |
| 61 // To allow Op() to take one of the input paths as an output parameter, either t
he source data | 45 if ((!AlmostEqualUlps(curveEnd.fX, curveStart.fX) |
| 62 // must be copied (as implemented below) or the result must be copied. | 46 || !AlmostEqualUlps(curveEnd.fY, curveStart.fY))) { |
| 63 // OPTIMIZATION: This copies both sets of input points every time. If the input
data was read | 47 fPathVerbs.push_back(SkPath::kLine_Verb); |
| 64 // directly, the output path would only need to be copied if it was also one of
the input paths. | 48 fPathPts.push_back_n(1, &curveStart); |
| 49 } else { |
| 50 if (curveEnd.fX != curveStart.fX || curveEnd.fY != curveStart.fY) { |
| 51 fPathPts[fPathPts.count() - 1] = curveStart; |
| 52 } else { |
| 53 fPathPts[fPathPts.count() - 1] = curveStart; |
| 54 } |
| 55 } |
| 56 fPathVerbs.push_back(SkPath::kClose_Verb); |
| 57 } |
| 58 |
| 65 int SkOpEdgeBuilder::preFetch() { | 59 int SkOpEdgeBuilder::preFetch() { |
| 66 if (!fPath->isFinite()) { | 60 if (!fPath->isFinite()) { |
| 67 fUnparseable = true; | 61 fUnparseable = true; |
| 68 return 0; | 62 return 0; |
| 69 } | 63 } |
| 64 SkAutoConicToQuads quadder; |
| 65 const SkScalar quadderTol = SK_Scalar1 / 16; |
| 70 SkPath::RawIter iter(*fPath); | 66 SkPath::RawIter iter(*fPath); |
| 67 SkPoint curveStart; |
| 68 SkPoint curve[4]; |
| 71 SkPoint pts[4]; | 69 SkPoint pts[4]; |
| 72 SkPath::Verb verb; | 70 SkPath::Verb verb; |
| 71 bool lastCurve = false; |
| 73 do { | 72 do { |
| 74 verb = iter.next(pts); | 73 verb = iter.next(pts); |
| 74 switch (verb) { |
| 75 case SkPath::kMove_Verb: |
| 76 if (!fAllowOpenContours && lastCurve) { |
| 77 closeContour(curve[0], curveStart); |
| 78 } |
| 79 fPathVerbs.push_back(verb); |
| 80 fPathPts.push_back(pts[0]); |
| 81 curveStart = curve[0] = pts[0]; |
| 82 lastCurve = false; |
| 83 continue; |
| 84 case SkPath::kLine_Verb: |
| 85 if (AlmostEqualUlps(curve[0].fX, pts[1].fX) |
| 86 && AlmostEqualUlps(curve[0].fY, pts[1].fY)) { |
| 87 continue; // skip degenerate points |
| 88 } |
| 89 break; |
| 90 case SkPath::kQuad_Verb: |
| 91 curve[1] = pts[1]; |
| 92 curve[2] = pts[2]; |
| 93 verb = SkReduceOrder::Quad(curve, pts); |
| 94 if (verb == SkPath::kMove_Verb) { |
| 95 continue; // skip degenerate points |
| 96 } |
| 97 break; |
| 98 case SkPath::kConic_Verb: { |
| 99 const SkPoint* quadPts = quadder.computeQuads(pts, iter.coni
cWeight(), |
| 100 quadderTol); |
| 101 const int nQuads = quadder.countQuads(); |
| 102 for (int i = 0; i < nQuads; ++i) { |
| 103 fPathVerbs.push_back(SkPath::kQuad_Verb); |
| 104 } |
| 105 fPathPts.push_back_n(nQuads * 2, quadPts); |
| 106 curve[0] = quadPts[nQuads * 2 - 1]; |
| 107 lastCurve = true; |
| 108 } |
| 109 continue; |
| 110 case SkPath::kCubic_Verb: |
| 111 curve[1] = pts[1]; |
| 112 curve[2] = pts[2]; |
| 113 curve[3] = pts[3]; |
| 114 verb = SkReduceOrder::Cubic(curve, pts); |
| 115 if (verb == SkPath::kMove_Verb) { |
| 116 continue; // skip degenerate points |
| 117 } |
| 118 break; |
| 119 case SkPath::kClose_Verb: |
| 120 closeContour(curve[0], curveStart); |
| 121 lastCurve = false; |
| 122 continue; |
| 123 case SkPath::kDone_Verb: |
| 124 continue; |
| 125 } |
| 75 fPathVerbs.push_back(verb); | 126 fPathVerbs.push_back(verb); |
| 76 if (verb == SkPath::kMove_Verb) { | 127 int ptCount = SkPathOpsVerbToPoints(verb); |
| 77 fPathPts.push_back(pts[0]); | 128 fPathPts.push_back_n(ptCount, &pts[1]); |
| 78 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) { | 129 curve[0] = pts[ptCount]; |
| 79 fPathPts.push_back_n(SkPathOpsVerbToPoints(verb), &pts[1]); | 130 lastCurve = true; |
| 80 } | |
| 81 } while (verb != SkPath::kDone_Verb); | 131 } while (verb != SkPath::kDone_Verb); |
| 132 if (!fAllowOpenContours && lastCurve) { |
| 133 closeContour(curve[0], curveStart); |
| 134 } |
| 135 fPathVerbs.push_back(SkPath::kDone_Verb); |
| 82 return fPathVerbs.count() - 1; | 136 return fPathVerbs.count() - 1; |
| 83 } | 137 } |
| 84 | 138 |
| 85 bool SkOpEdgeBuilder::close() { | 139 bool SkOpEdgeBuilder::close() { |
| 86 if (fFinalCurveStart && fFinalCurveEnd && *fFinalCurveStart != *fFinalCurveE
nd) { | |
| 87 fReducePts.push_back(*fFinalCurveStart); | |
| 88 fReducePts.push_back(*fFinalCurveEnd); | |
| 89 const SkPoint* lineStart = fReducePts.end() - 2; | |
| 90 fExtra.push_back(fCurrentContour->addLine(lineStart)); | |
| 91 } | |
| 92 complete(); | 140 complete(); |
| 93 return true; | 141 return true; |
| 94 } | 142 } |
| 95 | 143 |
| 96 bool SkOpEdgeBuilder::walk() { | 144 bool SkOpEdgeBuilder::walk() { |
| 97 SkPath::Verb reducedVerb; | |
| 98 uint8_t* verbPtr = fPathVerbs.begin(); | 145 uint8_t* verbPtr = fPathVerbs.begin(); |
| 99 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf]; | 146 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf]; |
| 100 const SkPoint* pointsPtr = fPathPts.begin(); | 147 const SkPoint* pointsPtr = fPathPts.begin() - 1; |
| 101 SkPath::Verb verb; | 148 SkPath::Verb verb; |
| 102 fFinalCurveStart = NULL; | |
| 103 fFinalCurveEnd = NULL; | |
| 104 while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) { | 149 while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) { |
| 105 if (verbPtr == endOfFirstHalf) { | 150 if (verbPtr == endOfFirstHalf) { |
| 106 fOperand = true; | 151 fOperand = true; |
| 107 } | 152 } |
| 108 verbPtr++; | 153 verbPtr++; |
| 109 switch (verb) { | 154 switch (verb) { |
| 110 case SkPath::kMove_Verb: | 155 case SkPath::kMove_Verb: |
| 111 if (fCurrentContour) { | 156 if (fCurrentContour) { |
| 112 if (fAllowOpenContours) { | 157 if (fAllowOpenContours) { |
| 113 complete(); | 158 complete(); |
| 114 } else if (!close()) { | 159 } else if (!close()) { |
| 115 return false; | 160 return false; |
| 116 } | 161 } |
| 117 } | 162 } |
| 118 if (!fCurrentContour) { | 163 if (!fCurrentContour) { |
| 119 fCurrentContour = fContours.push_back_n(1); | 164 fCurrentContour = fContours.push_back_n(1); |
| 120 fCurrentContour->setOperand(fOperand); | 165 fCurrentContour->setOperand(fOperand); |
| 121 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_PathO
psMask); | 166 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_PathO
psMask); |
| 122 fExtra.push_back(-1); // start new contour | |
| 123 } | 167 } |
| 124 fFinalCurveEnd = pointsPtr++; | 168 pointsPtr += 1; |
| 125 continue; | 169 continue; |
| 126 case SkPath::kLine_Verb: { | 170 case SkPath::kLine_Verb: |
| 127 const SkPoint& lineEnd = pointsPtr[0]; | 171 fCurrentContour->addLine(pointsPtr); |
| 128 const SkPoint& lineStart = pointsPtr[-1]; | 172 break; |
| 129 // skip degenerate points | 173 case SkPath::kQuad_Verb: |
| 130 if (lineStart.fX != lineEnd.fX || lineStart.fY != lineEnd.fY) { | 174 fCurrentContour->addQuad(pointsPtr); |
| 131 fCurrentContour->addLine(&lineStart); | 175 break; |
| 132 } | 176 case SkPath::kCubic_Verb: |
| 133 } break; | 177 fCurrentContour->addCubic(pointsPtr); |
| 134 case SkPath::kQuad_Verb: { | 178 break; |
| 135 const SkPoint* quadStart = &pointsPtr[-1]; | |
| 136 reducedVerb = SkReduceOrder::Quad(quadStart, &fReducePts); | |
| 137 if (reducedVerb == 0) { | |
| 138 break; // skip degenerate points | |
| 139 } | |
| 140 if (reducedVerb == SkPath::kLine_Verb) { | |
| 141 const SkPoint* lineStart = fReducePts.end() - 2; | |
| 142 fExtra.push_back(fCurrentContour->addLine(lineStart)); | |
| 143 break; | |
| 144 } | |
| 145 fCurrentContour->addQuad(quadStart); | |
| 146 } break; | |
| 147 case SkPath::kCubic_Verb: { | |
| 148 const SkPoint* cubicStart = &pointsPtr[-1]; | |
| 149 reducedVerb = SkReduceOrder::Cubic(cubicStart, &fReducePts); | |
| 150 if (reducedVerb == 0) { | |
| 151 break; // skip degenerate points | |
| 152 } | |
| 153 if (reducedVerb == SkPath::kLine_Verb) { | |
| 154 const SkPoint* lineStart = fReducePts.end() - 2; | |
| 155 fExtra.push_back(fCurrentContour->addLine(lineStart)); | |
| 156 break; | |
| 157 } | |
| 158 if (reducedVerb == SkPath::kQuad_Verb) { | |
| 159 const SkPoint* quadStart = fReducePts.end() - 3; | |
| 160 fExtra.push_back(fCurrentContour->addQuad(quadStart)); | |
| 161 break; | |
| 162 } | |
| 163 fCurrentContour->addCubic(cubicStart); | |
| 164 } break; | |
| 165 case SkPath::kClose_Verb: | 179 case SkPath::kClose_Verb: |
| 166 SkASSERT(fCurrentContour); | 180 SkASSERT(fCurrentContour); |
| 167 if (!close()) { | 181 if (!close()) { |
| 168 return false; | 182 return false; |
| 169 } | 183 } |
| 170 continue; | 184 continue; |
| 171 default: | 185 default: |
| 172 SkDEBUGFAIL("bad verb"); | 186 SkDEBUGFAIL("bad verb"); |
| 173 return false; | 187 return false; |
| 174 } | 188 } |
| 175 fFinalCurveStart = &pointsPtr[SkPathOpsVerbToPoints(verb) - 1]; | |
| 176 pointsPtr += SkPathOpsVerbToPoints(verb); | 189 pointsPtr += SkPathOpsVerbToPoints(verb); |
| 177 SkASSERT(fCurrentContour); | 190 SkASSERT(fCurrentContour); |
| 178 } | 191 } |
| 179 if (fCurrentContour && !fAllowOpenContours && !close()) { | 192 if (fCurrentContour && !fAllowOpenContours && !close()) { |
| 180 return false; | 193 return false; |
| 181 } | 194 } |
| 182 return true; | 195 return true; |
| 183 } | 196 } |
| OLD | NEW |