SkOpContour.h revision 624637cc8ec22c000409704d0b403ac1b81ad4b0
1/* 2 * Copyright 2013 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#ifndef SkOpContour_DEFINED 8#define SkOpContour_DEFINED 9 10#include "SkOpSegment.h" 11#include "SkTDArray.h" 12#include "SkTSort.h" 13 14class SkChunkAlloc; 15enum class SkOpRayDir; 16struct SkOpRayHit; 17class SkPathWriter; 18 19class SkOpContour { 20public: 21 SkOpContour() { 22 reset(); 23 } 24 25 ~SkOpContour() { 26 if (fNext) { 27 fNext->~SkOpContour(); 28 } 29 } 30 31 bool operator<(const SkOpContour& rh) const { 32 return fBounds.fTop == rh.fBounds.fTop 33 ? fBounds.fLeft < rh.fBounds.fLeft 34 : fBounds.fTop < rh.fBounds.fTop; 35 } 36 37 void addConic(SkPoint pts[3], SkScalar weight, SkChunkAlloc* allocator) { 38 appendSegment(allocator).addConic(pts, weight, this); 39 } 40 41 void addCubic(SkPoint pts[4], SkChunkAlloc* allocator) { 42 appendSegment(allocator).addCubic(pts, this); 43 } 44 45 SkOpSegment* addCurve(SkPath::Verb verb, const SkPoint pts[4], SkChunkAlloc* allocator); 46 47 void addLine(SkPoint pts[2], SkChunkAlloc* allocator) { 48 appendSegment(allocator).addLine(pts, this); 49 } 50 51 void addQuad(SkPoint pts[3], SkChunkAlloc* allocator) { 52 appendSegment(allocator).addQuad(pts, this); 53 } 54 55 void align() { 56 SkASSERT(fCount > 0); 57 SkOpSegment* segment = &fHead; 58 do { 59 segment->align(); 60 } while ((segment = segment->next())); 61 } 62 63 SkOpSegment& appendSegment(SkChunkAlloc* allocator) { 64 SkOpSegment* result = fCount++ 65 ? SkOpTAllocator<SkOpSegment>::Allocate(allocator) : &fHead; 66 result->setPrev(fTail); 67 if (fTail) { 68 fTail->setNext(result); 69 } 70 fTail = result; 71 return *result; 72 } 73 74 SkOpContour* appendContour(SkChunkAlloc* allocator) { 75 SkOpContour* contour = SkOpTAllocator<SkOpContour>::New(allocator); 76 contour->setNext(NULL); 77 SkOpContour* prev = this; 78 SkOpContour* next; 79 while ((next = prev->next())) { 80 prev = next; 81 } 82 prev->setNext(contour); 83 return contour; 84 } 85 86 const SkPathOpsBounds& bounds() const { 87 return fBounds; 88 } 89 90 void calcAngles(SkChunkAlloc* allocator) { 91 SkASSERT(fCount > 0); 92 SkOpSegment* segment = &fHead; 93 do { 94 segment->calcAngles(allocator); 95 } while ((segment = segment->next())); 96 } 97 98 void complete() { 99 setBounds(); 100 } 101 102 int count() const { 103 return fCount; 104 } 105 106 int debugID() const { 107 return SkDEBUGRELEASE(fID, -1); 108 } 109 110 int debugIndent() const { 111 return SkDEBUGRELEASE(fDebugIndent, 0); 112 } 113 114#if DEBUG_ACTIVE_SPANS 115 void debugShowActiveSpans() { 116 SkOpSegment* segment = &fHead; 117 do { 118 segment->debugShowActiveSpans(); 119 } while ((segment = segment->next())); 120 } 121#endif 122 123 const SkOpAngle* debugAngle(int id) const { 124 return SkDEBUGRELEASE(this->globalState()->debugAngle(id), NULL); 125 } 126 127 SkOpContour* debugContour(int id) { 128 return SkDEBUGRELEASE(this->globalState()->debugContour(id), NULL); 129 } 130 131 const SkOpPtT* debugPtT(int id) const { 132 return SkDEBUGRELEASE(this->globalState()->debugPtT(id), NULL); 133 } 134 135 const SkOpSegment* debugSegment(int id) const { 136 return SkDEBUGRELEASE(this->globalState()->debugSegment(id), NULL); 137 } 138 139 const SkOpSpanBase* debugSpan(int id) const { 140 return SkDEBUGRELEASE(this->globalState()->debugSpan(id), NULL); 141 } 142 143 SkOpGlobalState* globalState() const { 144 return fState; 145 } 146 147 void debugValidate() const { 148#if DEBUG_VALIDATE 149 const SkOpSegment* segment = &fHead; 150 const SkOpSegment* prior = NULL; 151 do { 152 segment->debugValidate(); 153 SkASSERT(segment->prev() == prior); 154 prior = segment; 155 } while ((segment = segment->next())); 156 SkASSERT(prior == fTail); 157#endif 158 } 159 160 bool done() const { 161 return fDone; 162 } 163 164 void dump() const; 165 void dumpAll() const; 166 void dumpAngles() const; 167 void dumpContours() const; 168 void dumpContoursAll() const; 169 void dumpContoursAngles() const; 170 void dumpContoursPts() const; 171 void dumpContoursPt(int segmentID) const; 172 void dumpContoursSegment(int segmentID) const; 173 void dumpContoursSpan(int segmentID) const; 174 void dumpContoursSpans() const; 175 void dumpPt(int ) const; 176 void dumpPts() const; 177 void dumpPtsX() const; 178 void dumpSegment(int ) const; 179 void dumpSegments(SkPathOp op) const; 180 void dumpSpan(int ) const; 181 void dumpSpans() const; 182 183 const SkPoint& end() const { 184 return fTail->pts()[SkPathOpsVerbToPoints(fTail->verb())]; 185 } 186 187 SkOpSpan* findSortableTop(SkOpContour* ); 188 189 SkOpSegment* first() { 190 SkASSERT(fCount > 0); 191 return &fHead; 192 } 193 194 const SkOpSegment* first() const { 195 SkASSERT(fCount > 0); 196 return &fHead; 197 } 198 199 void indentDump() const { 200 SkDEBUGCODE(fDebugIndent += 2); 201 } 202 203 void init(SkOpGlobalState* globalState, bool operand, bool isXor) { 204 fState = globalState; 205 fOperand = operand; 206 fXor = isXor; 207 SkDEBUGCODE(fID = globalState->nextContourID()); 208 } 209 210 bool isXor() const { 211 return fXor; 212 } 213 214 void missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) { 215 SkASSERT(fCount > 0); 216 SkOpSegment* segment = &fHead; 217 do { 218 if (fState->angleCoincidence()) { 219 segment->checkAngleCoin(coincidences, allocator); 220 } else { 221 segment->missingCoincidence(coincidences, allocator); 222 } 223 } while ((segment = segment->next())); 224 } 225 226 bool moveMultiples() { 227 SkASSERT(fCount > 0); 228 SkOpSegment* segment = &fHead; 229 do { 230 segment->moveMultiples(); 231 } while ((segment = segment->next())); 232 return true; 233 } 234 235 void moveNearby() { 236 SkASSERT(fCount > 0); 237 SkOpSegment* segment = &fHead; 238 do { 239 segment->moveNearby(); 240 } while ((segment = segment->next())); 241 } 242 243 SkOpContour* next() { 244 return fNext; 245 } 246 247 const SkOpContour* next() const { 248 return fNext; 249 } 250 251 bool operand() const { 252 return fOperand; 253 } 254 255 bool oppXor() const { 256 return fOppXor; 257 } 258 259 void outdentDump() const { 260 SkDEBUGCODE(fDebugIndent -= 2); 261 } 262 263 void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkChunkAlloc* ); 264 265 void remove(SkOpContour* contour) { 266 if (contour == this) { 267 SkASSERT(fCount == 0); 268 return; 269 } 270 SkASSERT(contour->fNext == NULL); 271 SkOpContour* prev = this; 272 SkOpContour* next; 273 while ((next = prev->next()) != contour) { 274 SkASSERT(next); 275 prev = next; 276 } 277 SkASSERT(prev); 278 prev->setNext(NULL); 279 } 280 281 void reset() { 282 fTail = NULL; 283 fNext = NULL; 284 fCount = 0; 285 fDone = false; 286 fTopsFound = false; 287 SkDEBUGCODE(fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin)); 288 SkDEBUGCODE(fFirstSorted = -1); 289 SkDEBUGCODE(fDebugIndent = 0); 290 } 291 292 void setBounds() { 293 SkASSERT(fCount > 0); 294 const SkOpSegment* segment = &fHead; 295 fBounds = segment->bounds(); 296 while ((segment = segment->next())) { 297 fBounds.add(segment->bounds()); 298 } 299 } 300 301 void setGlobalState(SkOpGlobalState* state) { 302 fState = state; 303 } 304 305 void setNext(SkOpContour* contour) { 306// SkASSERT(!fNext == !!contour); 307 fNext = contour; 308 } 309 310 void setOperand(bool isOp) { 311 fOperand = isOp; 312 } 313 314 void setOppXor(bool isOppXor) { 315 fOppXor = isOppXor; 316 } 317 318 void setXor(bool isXor) { 319 fXor = isXor; 320 } 321 322 SkPath::Verb simplifyCubic(SkPoint pts[4]); 323 324 void sortAngles() { 325 SkASSERT(fCount > 0); 326 SkOpSegment* segment = &fHead; 327 do { 328 segment->sortAngles(); 329 } while ((segment = segment->next())); 330 } 331 332 const SkPoint& start() const { 333 return fHead.pts()[0]; 334 } 335 336 void toPartialBackward(SkPathWriter* path) const { 337 const SkOpSegment* segment = fTail; 338 do { 339 segment->addCurveTo(segment->tail(), segment->head(), path, true); 340 } while ((segment = segment->prev())); 341 } 342 343 void toPartialForward(SkPathWriter* path) const { 344 const SkOpSegment* segment = &fHead; 345 do { 346 segment->addCurveTo(segment->head(), segment->tail(), path, true); 347 } while ((segment = segment->next())); 348 } 349 350 void toPath(SkPathWriter* path) const; 351 SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr); 352 353private: 354 SkOpGlobalState* fState; 355 SkOpSegment fHead; 356 SkOpSegment* fTail; 357 SkOpContour* fNext; 358 SkPathOpsBounds fBounds; 359 int fCount; 360 int fFirstSorted; 361 bool fDone; // set by find top segment 362 bool fTopsFound; 363 bool fOperand; // true for the second argument to a binary operator 364 bool fXor; // set if original path had even-odd fill 365 bool fOppXor; // set if opposite path had even-odd fill 366 SkDEBUGCODE(int fID); 367 SkDEBUGCODE(mutable int fDebugIndent); 368}; 369 370class SkOpContourHead : public SkOpContour { 371}; 372 373#endif 374