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 |