1 /* 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 */ 7 #include "SkGeometry.h" 8 #include "SkOpEdgeBuilder.h" 9 #include "SkReduceOrder.h" 10 11 void SkOpEdgeBuilder::init() { 12 fOperand = false; 13 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask 14 : kWinding_PathOpsMask; 15 fUnparseable = false; 16 fSecondHalf = preFetch(); 17 } 18 19 // very tiny points cause numerical instability : don't allow them 20 static 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 29 static bool can_add_curve(SkPath::Verb verb, SkPoint* curve) { 30 if (SkPath::kMove_Verb == verb) { 31 return false; 32 } 33 for (int index = 0; index <= SkPathOpsVerbToPoints(verb); ++index) { 34 force_small_to_zero(&curve[index]); 35 } 36 return SkPath::kLine_Verb != verb || !SkDPoint::ApproximatelyEqual(curve[0], curve[1]); 37 } 38 39 void SkOpEdgeBuilder::addOperand(const SkPath& path) { 40 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb); 41 fPathVerbs.pop(); 42 fPath = &path; 43 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_PathOpsMask 44 : kWinding_PathOpsMask; 45 preFetch(); 46 } 47 48 bool SkOpEdgeBuilder::finish() { 49 fOperand = false; 50 if (fUnparseable || !walk()) { 51 return false; 52 } 53 complete(); 54 SkOpContour* contour = fContourBuilder.contour(); 55 if (contour && !contour->count()) { 56 fContoursHead->remove(contour); 57 } 58 return true; 59 } 60 61 void SkOpEdgeBuilder::closeContour(const SkPoint& curveEnd, const SkPoint& curveStart) { 62 if (!SkDPoint::ApproximatelyEqual(curveEnd, curveStart)) { 63 *fPathVerbs.append() = SkPath::kLine_Verb; 64 *fPathPts.append() = curveStart; 65 } else { 66 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 } 75 } 76 *fPathVerbs.append() = SkPath::kClose_Verb; 77 } 78 79 int SkOpEdgeBuilder::preFetch() { 80 if (!fPath->isFinite()) { 81 fUnparseable = true; 82 return 0; 83 } 84 SkPath::RawIter iter(*fPath); 85 SkPoint curveStart; 86 SkPoint curve[4]; 87 SkPoint pts[4]; 88 SkPath::Verb verb; 89 bool lastCurve = false; 90 do { 91 verb = iter.next(pts); 92 switch (verb) { 93 case SkPath::kMove_Verb: 94 if (!fAllowOpenContours && lastCurve) { 95 closeContour(curve[0], curveStart); 96 } 97 *fPathVerbs.append() = verb; 98 force_small_to_zero(&pts[0]); 99 *fPathPts.append() = pts[0]; 100 curveStart = curve[0] = pts[0]; 101 lastCurve = false; 102 continue; 103 case SkPath::kLine_Verb: 104 force_small_to_zero(&pts[1]); 105 if (SkDPoint::ApproximatelyEqual(curve[0], pts[1])) { 106 uint8_t lastVerb = fPathVerbs.top(); 107 if (lastVerb != SkPath::kLine_Verb && lastVerb != SkPath::kMove_Verb) { 108 fPathPts.top() = curve[0] = pts[1]; 109 } 110 continue; // skip degenerate points 111 } 112 break; 113 case SkPath::kQuad_Verb: 114 force_small_to_zero(&pts[1]); 115 force_small_to_zero(&pts[2]); 116 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; 123 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]; 128 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) { 132 continue; // skip degenerate points 133 } 134 break; 135 case SkPath::kCubic_Verb: 136 force_small_to_zero(&pts[1]); 137 force_small_to_zero(&pts[2]); 138 force_small_to_zero(&pts[3]); 139 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; 153 } 154 *fPathVerbs.append() = verb; 155 int ptCount = SkPathOpsVerbToPoints(verb); 156 fPathPts.append(ptCount, &pts[1]); 157 if (verb == SkPath::kConic_Verb) { 158 *fWeights.append() = iter.conicWeight(); 159 } 160 curve[0] = pts[ptCount]; 161 lastCurve = true; 162 } while (verb != SkPath::kDone_Verb); 163 if (!fAllowOpenContours && lastCurve) { 164 closeContour(curve[0], curveStart); 165 } 166 *fPathVerbs.append() = SkPath::kDone_Verb; 167 return fPathVerbs.count() - 1; 168 } 169 170 bool SkOpEdgeBuilder::close() { 171 complete(); 172 return true; 173 } 174 175 bool SkOpEdgeBuilder::walk() { 176 uint8_t* verbPtr = fPathVerbs.begin(); 177 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf]; 178 SkPoint* pointsPtr = fPathPts.begin() - 1; 179 SkScalar* weightPtr = fWeights.begin(); 180 SkPath::Verb verb; 181 SkOpContour* contour = fContourBuilder.contour(); 182 while ((verb = (SkPath::Verb) *verbPtr) != SkPath::kDone_Verb) { 183 if (verbPtr == endOfFirstHalf) { 184 fOperand = true; 185 } 186 verbPtr++; 187 switch (verb) { 188 case SkPath::kMove_Verb: 189 if (contour && contour->count()) { 190 if (fAllowOpenContours) { 191 complete(); 192 } else if (!close()) { 193 return false; 194 } 195 } 196 if (!contour) { 197 fContourBuilder.setContour(contour = fContoursHead->appendContour()); 198 } 199 contour->init(fGlobalState, fOperand, 200 fXorMask[fOperand] == kEvenOdd_PathOpsMask); 201 pointsPtr += 1; 202 continue; 203 case SkPath::kLine_Verb: 204 fContourBuilder.addLine(pointsPtr); 205 break; 206 case SkPath::kQuad_Verb: 207 { 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 } 218 for (unsigned index = 0; index < SK_ARRAY_COUNT(pair); ++index) { 219 force_small_to_zero(&pair[index]); 220 } 221 SkPoint cStorage[2][2]; 222 SkPath::Verb v1 = SkReduceOrder::Quad(&pair[0], cStorage[0]); 223 SkPath::Verb v2 = SkReduceOrder::Quad(&pair[2], cStorage[1]); 224 SkPoint* curve1 = v1 != SkPath::kLine_Verb ? &pair[0] : cStorage[0]; 225 SkPoint* curve2 = v2 != SkPath::kLine_Verb ? &pair[2] : cStorage[1]; 226 if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) { 227 fContourBuilder.addCurve(v1, curve1); 228 fContourBuilder.addCurve(v2, curve2); 229 break; 230 } 231 } 232 } 233 addOneQuad: 234 fContourBuilder.addQuad(pointsPtr); 235 break; 236 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]; 246 if (!conic.chopAt(maxCurvature, pair)) { 247 // if result can't be computed, use original 248 fContourBuilder.addConic(pointsPtr, weight); 249 break; 250 } 251 SkPoint cStorage[2][3]; 252 SkPath::Verb v1 = SkReduceOrder::Conic(pair[0], cStorage[0]); 253 SkPath::Verb v2 = SkReduceOrder::Conic(pair[1], cStorage[1]); 254 SkPoint* curve1 = v1 != SkPath::kLine_Verb ? pair[0].fPts : cStorage[0]; 255 SkPoint* curve2 = v2 != SkPath::kLine_Verb ? pair[1].fPts : cStorage[1]; 256 if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) { 257 fContourBuilder.addCurve(v1, curve1, pair[0].fW); 258 fContourBuilder.addCurve(v2, curve2, pair[1].fW); 259 break; 260 } 261 } 262 } 263 fContourBuilder.addConic(pointsPtr, weight); 264 } break; 265 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. 270 SkScalar splitT[3]; 271 int breaks = SkDCubic::ComplexBreak(pointsPtr, splitT); 272 if (!breaks) { 273 fContourBuilder.addCubic(pointsPtr); 274 break; 275 } 276 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; 283 } splits[4]; 284 SkASSERT(SK_ARRAY_COUNT(splits) == SK_ARRAY_COUNT(splitT) + 1); 285 SkTQSort(splitT, &splitT[breaks - 1]); 286 for (int index = 0; index <= breaks; ++index) { 287 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)) { 292 return false; 293 } 294 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; 312 int breakLimit = SkTMin(breaks, (int) SK_ARRAY_COUNT(splits) - 1); 313 while (next < breakLimit && !splits[next + 1].fCanAdd) { 314 ++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); 335 } 336 } 337 break; 338 case SkPath::kClose_Verb: 339 SkASSERT(contour); 340 if (!close()) { 341 return false; 342 } 343 contour = nullptr; 344 continue; 345 default: 346 SkDEBUGFAIL("bad verb"); 347 return false; 348 } 349 SkASSERT(contour); 350 if (contour->count()) { 351 contour->debugValidate(); 352 } 353 pointsPtr += SkPathOpsVerbToPoints(verb); 354 } 355 fContourBuilder.flush(); 356 if (contour && contour->count() &&!fAllowOpenContours && !close()) { 357 return false; 358 } 359 return true; 360 } 361