blob: 572942dab4116d4b8166c98444cf04048f675cd9 [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
caryclark@google.com07e97fc2013-07-08 17:17:02 +00007#include "SkGeometry.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +00008#include "SkOpEdgeBuilder.h"
9#include "SkReduceOrder.h"
10
11void SkOpEdgeBuilder::init() {
caryclark@google.com07393ca2013-04-08 11:47:37 +000012 fOperand = false;
13 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask
14 : kWinding_PathOpsMask;
caryclark@google.com66560ca2013-04-26 19:51:16 +000015 fUnparseable = false;
caryclark@google.com07393ca2013-04-08 11:47:37 +000016 fSecondHalf = preFetch();
17}
18
caryclark27c015d2016-09-23 05:47:20 -070019// very tiny points cause numerical instability : don't allow them
20static void force_small_to_zero(SkPoint* pt) {
21 if (SkScalarAbs(pt->fX) < FLT_EPSILON_ORDERABLE_ERR) {
22 pt->fX = 0;
23 }
24 if (SkScalarAbs(pt->fY) < FLT_EPSILON_ORDERABLE_ERR) {
25 pt->fY = 0;
26 }
27}
28
29static bool can_add_curve(SkPath::Verb verb, SkPoint* curve) {
30 if (SkPath::kMove_Verb == verb) {
31 return false;
32 }
caryclarkcc093722016-09-23 09:32:26 -070033 for (int index = 0; index <= SkPathOpsVerbToPoints(verb); ++index) {
caryclark27c015d2016-09-23 05:47:20 -070034 force_small_to_zero(&curve[index]);
35 }
36 return SkPath::kLine_Verb != verb || !SkDPoint::ApproximatelyEqual(curve[0], curve[1]);
37}
38
caryclark@google.com07393ca2013-04-08 11:47:37 +000039void SkOpEdgeBuilder::addOperand(const SkPath& path) {
40 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
caryclark54359292015-03-26 07:52:43 -070041 fPathVerbs.pop();
caryclark@google.com07393ca2013-04-08 11:47:37 +000042 fPath = &path;
43 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask
44 : kWinding_PathOpsMask;
45 preFetch();
46}
47
caryclark55888e42016-07-18 10:01:36 -070048bool SkOpEdgeBuilder::finish() {
caryclark54359292015-03-26 07:52:43 -070049 fOperand = false;
caryclark55888e42016-07-18 10:01:36 -070050 if (fUnparseable || !walk()) {
caryclark@google.com66560ca2013-04-26 19:51:16 +000051 return false;
52 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000053 complete();
Cary Clarkff114282016-12-14 11:56:16 -050054 SkOpContour* contour = fContourBuilder.contour();
55 if (contour && !contour->count()) {
56 fContoursHead->remove(contour);
caryclark@google.com07393ca2013-04-08 11:47:37 +000057 }
caryclark@google.com66560ca2013-04-26 19:51:16 +000058 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +000059}
60
caryclark@google.com07e97fc2013-07-08 17:17:02 +000061void SkOpEdgeBuilder::closeContour(const SkPoint& curveEnd, const SkPoint& curveStart) {
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +000062 if (!SkDPoint::ApproximatelyEqual(curveEnd, curveStart)) {
caryclark54359292015-03-26 07:52:43 -070063 *fPathVerbs.append() = SkPath::kLine_Verb;
64 *fPathPts.append() = curveStart;
caryclark@google.com07e97fc2013-07-08 17:17:02 +000065 } else {
Cary Clarkb9ae5372016-10-05 10:40:07 -040066 int verbCount = fPathVerbs.count();
67 int ptsCount = fPathPts.count();
68 if (SkPath::kLine_Verb == fPathVerbs[verbCount - 1]
69 && fPathPts[ptsCount - 2] == curveStart) {
70 fPathVerbs.pop();
71 fPathPts.pop();
72 } else {
73 fPathPts[ptsCount - 1] = curveStart;
74 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +000075 }
caryclark54359292015-03-26 07:52:43 -070076 *fPathVerbs.append() = SkPath::kClose_Verb;
caryclark@google.com07e97fc2013-07-08 17:17:02 +000077}
78
caryclark@google.com07393ca2013-04-08 11:47:37 +000079int SkOpEdgeBuilder::preFetch() {
caryclark@google.com66560ca2013-04-26 19:51:16 +000080 if (!fPath->isFinite()) {
81 fUnparseable = true;
82 return 0;
83 }
caryclark@google.com6dc7df62013-04-25 11:51:54 +000084 SkPath::RawIter iter(*fPath);
caryclark@google.com07e97fc2013-07-08 17:17:02 +000085 SkPoint curveStart;
86 SkPoint curve[4];
caryclark@google.com07393ca2013-04-08 11:47:37 +000087 SkPoint pts[4];
88 SkPath::Verb verb;
caryclark@google.com07e97fc2013-07-08 17:17:02 +000089 bool lastCurve = false;
caryclark@google.com07393ca2013-04-08 11:47:37 +000090 do {
91 verb = iter.next(pts);
caryclark@google.com07e97fc2013-07-08 17:17:02 +000092 switch (verb) {
93 case SkPath::kMove_Verb:
94 if (!fAllowOpenContours && lastCurve) {
95 closeContour(curve[0], curveStart);
96 }
caryclark54359292015-03-26 07:52:43 -070097 *fPathVerbs.append() = verb;
caryclark65b427c2014-09-18 10:32:57 -070098 force_small_to_zero(&pts[0]);
caryclark54359292015-03-26 07:52:43 -070099 *fPathPts.append() = pts[0];
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000100 curveStart = curve[0] = pts[0];
101 lastCurve = false;
102 continue;
103 case SkPath::kLine_Verb:
caryclark65b427c2014-09-18 10:32:57 -0700104 force_small_to_zero(&pts[1]);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000105 if (SkDPoint::ApproximatelyEqual(curve[0], pts[1])) {
caryclark54359292015-03-26 07:52:43 -0700106 uint8_t lastVerb = fPathVerbs.top();
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000107 if (lastVerb != SkPath::kLine_Verb && lastVerb != SkPath::kMove_Verb) {
Cary Clark40f23782016-10-06 12:04:16 -0400108 fPathPts.top() = curve[0] = pts[1];
caryclark@google.com570863f2013-09-16 15:55:01 +0000109 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000110 continue; // skip degenerate points
111 }
112 break;
113 case SkPath::kQuad_Verb:
caryclark65b427c2014-09-18 10:32:57 -0700114 force_small_to_zero(&pts[1]);
115 force_small_to_zero(&pts[2]);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000116 curve[1] = pts[1];
117 curve[2] = pts[2];
118 verb = SkReduceOrder::Quad(curve, pts);
119 if (verb == SkPath::kMove_Verb) {
120 continue; // skip degenerate points
121 }
122 break;
caryclark1049f122015-04-20 08:31:59 -0700123 case SkPath::kConic_Verb:
124 force_small_to_zero(&pts[1]);
125 force_small_to_zero(&pts[2]);
126 curve[1] = pts[1];
127 curve[2] = pts[2];
caryclark27c015d2016-09-23 05:47:20 -0700128 verb = SkReduceOrder::Quad(curve, pts);
129 if (SkPath::kQuad_Verb == verb && 1 != iter.conicWeight()) {
130 verb = SkPath::kConic_Verb;
131 } else if (verb == SkPath::kMove_Verb) {
caryclark1049f122015-04-20 08:31:59 -0700132 continue; // skip degenerate points
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000133 }
caryclark1049f122015-04-20 08:31:59 -0700134 break;
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000135 case SkPath::kCubic_Verb:
caryclark65b427c2014-09-18 10:32:57 -0700136 force_small_to_zero(&pts[1]);
137 force_small_to_zero(&pts[2]);
138 force_small_to_zero(&pts[3]);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000139 curve[1] = pts[1];
140 curve[2] = pts[2];
141 curve[3] = pts[3];
142 verb = SkReduceOrder::Cubic(curve, pts);
143 if (verb == SkPath::kMove_Verb) {
144 continue; // skip degenerate points
145 }
146 break;
147 case SkPath::kClose_Verb:
148 closeContour(curve[0], curveStart);
149 lastCurve = false;
150 continue;
151 case SkPath::kDone_Verb:
152 continue;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000153 }
caryclark54359292015-03-26 07:52:43 -0700154 *fPathVerbs.append() = verb;
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000155 int ptCount = SkPathOpsVerbToPoints(verb);
caryclark54359292015-03-26 07:52:43 -0700156 fPathPts.append(ptCount, &pts[1]);
caryclark1049f122015-04-20 08:31:59 -0700157 if (verb == SkPath::kConic_Verb) {
158 *fWeights.append() = iter.conicWeight();
159 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000160 curve[0] = pts[ptCount];
161 lastCurve = true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000162 } while (verb != SkPath::kDone_Verb);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000163 if (!fAllowOpenContours && lastCurve) {
164 closeContour(curve[0], curveStart);
165 }
caryclark54359292015-03-26 07:52:43 -0700166 *fPathVerbs.append() = SkPath::kDone_Verb;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000167 return fPathVerbs.count() - 1;
168}
169
caryclark@google.com66560ca2013-04-26 19:51:16 +0000170bool SkOpEdgeBuilder::close() {
caryclark@google.com66560ca2013-04-26 19:51:16 +0000171 complete();
172 return true;
173}
174
caryclark55888e42016-07-18 10:01:36 -0700175bool SkOpEdgeBuilder::walk() {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000176 uint8_t* verbPtr = fPathVerbs.begin();
177 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf];
caryclark54359292015-03-26 07:52:43 -0700178 SkPoint* pointsPtr = fPathPts.begin() - 1;
caryclark1049f122015-04-20 08:31:59 -0700179 SkScalar* weightPtr = fWeights.begin();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000180 SkPath::Verb verb;
Cary Clarkff114282016-12-14 11:56:16 -0500181 SkOpContour* contour = fContourBuilder.contour();
caryclark@google.com6dc7df62013-04-25 11:51:54 +0000182 while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) {
183 if (verbPtr == endOfFirstHalf) {
184 fOperand = true;
185 }
186 verbPtr++;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000187 switch (verb) {
188 case SkPath::kMove_Verb:
Cary Clarkff114282016-12-14 11:56:16 -0500189 if (contour && contour->count()) {
caryclark@google.com66560ca2013-04-26 19:51:16 +0000190 if (fAllowOpenContours) {
191 complete();
192 } else if (!close()) {
193 return false;
194 }
195 }
Cary Clarkff114282016-12-14 11:56:16 -0500196 if (!contour) {
197 fContourBuilder.setContour(contour = fContoursHead->appendContour());
caryclark@google.com07393ca2013-04-08 11:47:37 +0000198 }
Cary Clarkff114282016-12-14 11:56:16 -0500199 contour->init(fGlobalState, fOperand,
caryclark54359292015-03-26 07:52:43 -0700200 fXorMask[fOperand] == kEvenOdd_PathOpsMask);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000201 pointsPtr += 1;
caryclark@google.com6dc7df62013-04-25 11:51:54 +0000202 continue;
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000203 case SkPath::kLine_Verb:
Cary Clarkff114282016-12-14 11:56:16 -0500204 fContourBuilder.addLine(pointsPtr);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000205 break;
206 case SkPath::kQuad_Verb:
caryclark27c015d2016-09-23 05:47:20 -0700207 {
208 SkVector v1 = pointsPtr[1] - pointsPtr[0];
209 SkVector v2 = pointsPtr[2] - pointsPtr[1];
210 if (v1.dot(v2) < 0) {
211 SkPoint pair[5];
212 if (SkChopQuadAtMaxCurvature(pointsPtr, pair) == 1) {
213 goto addOneQuad;
214 }
215 if (!SkScalarsAreFinite(&pair[0].fX, SK_ARRAY_COUNT(pair) * 2)) {
216 return false;
217 }
Cary Clarkafca4d62017-12-01 15:23:00 -0500218 for (unsigned index = 0; index < SK_ARRAY_COUNT(pair); ++index) {
219 force_small_to_zero(&pair[index]);
220 }
caryclark27c015d2016-09-23 05:47:20 -0700221 SkPoint cStorage[2][2];
222 SkPath::Verb v1 = SkReduceOrder::Quad(&pair[0], cStorage[0]);
223 SkPath::Verb v2 = SkReduceOrder::Quad(&pair[2], cStorage[1]);
caryclarkcc093722016-09-23 09:32:26 -0700224 SkPoint* curve1 = v1 != SkPath::kLine_Verb ? &pair[0] : cStorage[0];
225 SkPoint* curve2 = v2 != SkPath::kLine_Verb ? &pair[2] : cStorage[1];
caryclark27c015d2016-09-23 05:47:20 -0700226 if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) {
Cary Clarkff114282016-12-14 11:56:16 -0500227 fContourBuilder.addCurve(v1, curve1);
228 fContourBuilder.addCurve(v2, curve2);
caryclark27c015d2016-09-23 05:47:20 -0700229 break;
230 }
231 }
232 }
233 addOneQuad:
Cary Clarkff114282016-12-14 11:56:16 -0500234 fContourBuilder.addQuad(pointsPtr);
caryclark@google.com07e97fc2013-07-08 17:17:02 +0000235 break;
caryclark27c015d2016-09-23 05:47:20 -0700236 case SkPath::kConic_Verb: {
237 SkVector v1 = pointsPtr[1] - pointsPtr[0];
238 SkVector v2 = pointsPtr[2] - pointsPtr[1];
239 SkScalar weight = *weightPtr++;
240 if (v1.dot(v2) < 0) {
241 // FIXME: max curvature for conics hasn't been implemented; use placeholder
242 SkScalar maxCurvature = SkFindQuadMaxCurvature(pointsPtr);
243 if (maxCurvature > 0) {
244 SkConic conic(pointsPtr, weight);
245 SkConic pair[2];
caryclark414c4292016-09-26 11:03:54 -0700246 if (!conic.chopAt(maxCurvature, pair)) {
247 // if result can't be computed, use original
Cary Clarkff114282016-12-14 11:56:16 -0500248 fContourBuilder.addConic(pointsPtr, weight);
caryclark414c4292016-09-26 11:03:54 -0700249 break;
250 }
caryclark27c015d2016-09-23 05:47:20 -0700251 SkPoint cStorage[2][3];
252 SkPath::Verb v1 = SkReduceOrder::Conic(pair[0], cStorage[0]);
253 SkPath::Verb v2 = SkReduceOrder::Conic(pair[1], cStorage[1]);
caryclarkcc093722016-09-23 09:32:26 -0700254 SkPoint* curve1 = v1 != SkPath::kLine_Verb ? pair[0].fPts : cStorage[0];
255 SkPoint* curve2 = v2 != SkPath::kLine_Verb ? pair[1].fPts : cStorage[1];
caryclark27c015d2016-09-23 05:47:20 -0700256 if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) {
Cary Clarkff114282016-12-14 11:56:16 -0500257 fContourBuilder.addCurve(v1, curve1, pair[0].fW);
258 fContourBuilder.addCurve(v2, curve2, pair[1].fW);
caryclark27c015d2016-09-23 05:47:20 -0700259 break;
260 }
caryclark1049f122015-04-20 08:31:59 -0700261 }
caryclark54359292015-03-26 07:52:43 -0700262 }
Cary Clarkff114282016-12-14 11:56:16 -0500263 fContourBuilder.addConic(pointsPtr, weight);
caryclark54359292015-03-26 07:52:43 -0700264 } break;
caryclark27c015d2016-09-23 05:47:20 -0700265 case SkPath::kCubic_Verb:
266 {
267 // Split complex cubics (such as self-intersecting curves or
268 // ones with difficult curvature) in two before proceeding.
269 // This can be required for intersection to succeed.
Cary Clark7eb01e02016-12-08 14:36:32 -0500270 SkScalar splitT[3];
271 int breaks = SkDCubic::ComplexBreak(pointsPtr, splitT);
272 if (!breaks) {
Cary Clarkff114282016-12-14 11:56:16 -0500273 fContourBuilder.addCubic(pointsPtr);
Cary Clark7eb01e02016-12-08 14:36:32 -0500274 break;
275 }
Cary Clarkff114282016-12-14 11:56:16 -0500276 SkASSERT(breaks <= (int) SK_ARRAY_COUNT(splitT));
277 struct Splitsville {
278 double fT[2];
279 SkPoint fPts[4];
280 SkPoint fReduced[4];
281 SkPath::Verb fVerb;
282 bool fCanAdd;
Cary Clark0eb6ed42016-12-16 16:31:11 -0500283 } splits[4];
284 SkASSERT(SK_ARRAY_COUNT(splits) == SK_ARRAY_COUNT(splitT) + 1);
285 SkTQSort(splitT, &splitT[breaks - 1]);
Cary Clark7eb01e02016-12-08 14:36:32 -0500286 for (int index = 0; index <= breaks; ++index) {
Cary Clarkff114282016-12-14 11:56:16 -0500287 Splitsville* split = &splits[index];
288 split->fT[0] = index ? splitT[index - 1] : 0;
289 split->fT[1] = index < breaks ? splitT[index] : 1;
290 SkDCubic part = SkDCubic::SubDivide(pointsPtr, split->fT[0], split->fT[1]);
291 if (!part.toFloatPoints(split->fPts)) {
caryclark27c015d2016-09-23 05:47:20 -0700292 return false;
293 }
Cary Clarkff114282016-12-14 11:56:16 -0500294 split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced);
295 SkPoint* curve = SkPath::kCubic_Verb == verb
296 ? split->fPts : split->fReduced;
297 split->fCanAdd = can_add_curve(split->fVerb, curve);
298 }
299 for (int index = 0; index <= breaks; ++index) {
300 Splitsville* split = &splits[index];
301 if (!split->fCanAdd) {
302 continue;
303 }
304 int prior = index;
305 while (prior > 0 && !splits[prior - 1].fCanAdd) {
306 --prior;
307 }
308 if (prior < index) {
309 split->fT[0] = splits[prior].fT[0];
310 }
311 int next = index;
Eric Boren746e2632017-06-21 13:39:32 -0400312 int breakLimit = SkTMin(breaks, (int) SK_ARRAY_COUNT(splits) - 1);
313 while (next < breakLimit && !splits[next + 1].fCanAdd) {
Cary Clarkff114282016-12-14 11:56:16 -0500314 ++next;
315 }
316 if (next > index) {
317 split->fT[1] = splits[next].fT[1];
318 }
319 if (prior < index || next > index) {
320 if (0 == split->fT[0] && 1 == split->fT[1]) {
321 fContourBuilder.addCubic(pointsPtr);
322 break;
323 }
324 SkDCubic part = SkDCubic::SubDivide(pointsPtr, split->fT[0],
325 split->fT[1]);
326 if (!part.toFloatPoints(split->fPts)) {
327 return false;
328 }
329 split->fVerb = SkReduceOrder::Cubic(split->fPts, split->fReduced);
330 }
331 SkPoint* curve = SkPath::kCubic_Verb == split->fVerb
332 ? split->fPts : split->fReduced;
333 SkAssertResult(can_add_curve(split->fVerb, curve));
334 fContourBuilder.addCurve(split->fVerb, curve);
caryclark27c015d2016-09-23 05:47:20 -0700335 }
336 }
caryclark27c015d2016-09-23 05:47:20 -0700337 break;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000338 case SkPath::kClose_Verb:
Cary Clarkff114282016-12-14 11:56:16 -0500339 SkASSERT(contour);
caryclark@google.com66560ca2013-04-26 19:51:16 +0000340 if (!close()) {
341 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000342 }
Cary Clarkff114282016-12-14 11:56:16 -0500343 contour = nullptr;
caryclark@google.com6dc7df62013-04-25 11:51:54 +0000344 continue;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000345 default:
346 SkDEBUGFAIL("bad verb");
caryclark@google.com66560ca2013-04-26 19:51:16 +0000347 return false;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000348 }
Cary Clarkff114282016-12-14 11:56:16 -0500349 SkASSERT(contour);
350 if (contour->count()) {
351 contour->debugValidate();
352 }
caryclark54359292015-03-26 07:52:43 -0700353 pointsPtr += SkPathOpsVerbToPoints(verb);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000354 }
Cary Clarkff114282016-12-14 11:56:16 -0500355 fContourBuilder.flush();
356 if (contour && contour->count() &&!fAllowOpenContours && !close()) {
357 return false;
358 }
359 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000360}