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 #ifndef SkPathOpsTypes_DEFINED
8 #define SkPathOpsTypes_DEFINED
9
10 #include <float.h> // for FLT_EPSILON
11
12 #include "include/core/SkPath.h"
13 #include "include/core/SkScalar.h"
14 #include "include/pathops/SkPathOps.h"
15 #include "include/private/SkFloatingPoint.h"
16 #include "include/private/SkSafe_math.h"
17 #include "src/pathops/SkPathOpsDebug.h"
18
19 enum SkPathOpsMask {
20 kWinding_PathOpsMask = -1,
21 kNo_PathOpsMask = 0,
22 kEvenOdd_PathOpsMask = 1
23 };
24
25 class SkArenaAlloc;
26 class SkOpCoincidence;
27 class SkOpContour;
28 class SkOpContourHead;
29 class SkIntersections;
30 class SkIntersectionHelper;
31
32 enum class SkOpPhase : char {
33 kNoChange,
34 kIntersecting,
35 kWalking,
36 kFixWinding,
37 };
38
39 class SkOpGlobalState {
40 public:
41 SkOpGlobalState(SkOpContourHead* head,
42 SkArenaAlloc* allocator SkDEBUGPARAMS(bool debugSkipAssert)
43 SkDEBUGPARAMS(const char* testName));
44
45 enum {
46 kMaxWindingTries = 10
47 };
48
allocatedOpSpan()49 bool allocatedOpSpan() const {
50 return fAllocatedOpSpan;
51 }
52
allocator()53 SkArenaAlloc* allocator() {
54 return fAllocator;
55 }
56
bumpNested()57 void bumpNested() {
58 ++fNested;
59 }
60
clearNested()61 void clearNested() {
62 fNested = 0;
63 }
64
coincidence()65 SkOpCoincidence* coincidence() {
66 return fCoincidence;
67 }
68
contourHead()69 SkOpContourHead* contourHead() {
70 return fContourHead;
71 }
72
73 #ifdef SK_DEBUG
74 const class SkOpAngle* debugAngle(int id) const;
75 const SkOpCoincidence* debugCoincidence() const;
76 SkOpContour* debugContour(int id) const;
77 const class SkOpPtT* debugPtT(int id) const;
78 #endif
79
80 static bool DebugRunFail();
81
82 #ifdef SK_DEBUG
83 const class SkOpSegment* debugSegment(int id) const;
debugSkipAssert()84 bool debugSkipAssert() const { return fDebugSkipAssert; }
85 const class SkOpSpanBase* debugSpan(int id) const;
debugTestName()86 const char* debugTestName() const { return fDebugTestName; }
87 #endif
88
89 #if DEBUG_T_SECT_LOOP_COUNT
90 void debugAddLoopCount(SkIntersections* , const SkIntersectionHelper& ,
91 const SkIntersectionHelper& );
92 void debugDoYourWorst(SkOpGlobalState* );
93 void debugLoopReport();
94 void debugResetLoopCounts();
95 #endif
96
97 #if DEBUG_COINCIDENCE
debugSetCheckHealth(bool check)98 void debugSetCheckHealth(bool check) { fDebugCheckHealth = check; }
debugCheckHealth()99 bool debugCheckHealth() const { return fDebugCheckHealth; }
100 #endif
101
102 #if DEBUG_VALIDATE || DEBUG_COIN
103 void debugSetPhase(const char* funcName DEBUG_COIN_DECLARE_PARAMS()) const;
104 #endif
105
106 #if DEBUG_COIN
107 void debugAddToCoinChangedDict();
108 void debugAddToGlobalCoinDicts();
debugCoinChangedDict()109 SkPathOpsDebug::CoinDict* debugCoinChangedDict() { return &fCoinChangedDict; }
debugCoinDictEntry()110 const SkPathOpsDebug::CoinDictEntry& debugCoinDictEntry() const { return fCoinDictEntry; }
111
112 static void DumpCoinDict();
113 #endif
114
115
nested()116 int nested() const {
117 return fNested;
118 }
119
120 #ifdef SK_DEBUG
nextAngleID()121 int nextAngleID() {
122 return ++fAngleID;
123 }
124
nextCoinID()125 int nextCoinID() {
126 return ++fCoinID;
127 }
128
nextContourID()129 int nextContourID() {
130 return ++fContourID;
131 }
132
nextPtTID()133 int nextPtTID() {
134 return ++fPtTID;
135 }
136
nextSegmentID()137 int nextSegmentID() {
138 return ++fSegmentID;
139 }
140
nextSpanID()141 int nextSpanID() {
142 return ++fSpanID;
143 }
144 #endif
145
phase()146 SkOpPhase phase() const {
147 return fPhase;
148 }
149
resetAllocatedOpSpan()150 void resetAllocatedOpSpan() {
151 fAllocatedOpSpan = false;
152 }
153
setAllocatedOpSpan()154 void setAllocatedOpSpan() {
155 fAllocatedOpSpan = true;
156 }
157
setCoincidence(SkOpCoincidence * coincidence)158 void setCoincidence(SkOpCoincidence* coincidence) {
159 fCoincidence = coincidence;
160 }
161
setContourHead(SkOpContourHead * contourHead)162 void setContourHead(SkOpContourHead* contourHead) {
163 fContourHead = contourHead;
164 }
165
setPhase(SkOpPhase phase)166 void setPhase(SkOpPhase phase) {
167 if (SkOpPhase::kNoChange == phase) {
168 return;
169 }
170 SkASSERT(fPhase != phase);
171 fPhase = phase;
172 }
173
174 // called in very rare cases where angles are sorted incorrectly -- signfies op will fail
setWindingFailed()175 void setWindingFailed() {
176 fWindingFailed = true;
177 }
178
windingFailed()179 bool windingFailed() const {
180 return fWindingFailed;
181 }
182
183 private:
184 SkArenaAlloc* fAllocator;
185 SkOpCoincidence* fCoincidence;
186 SkOpContourHead* fContourHead;
187 int fNested;
188 bool fAllocatedOpSpan;
189 bool fWindingFailed;
190 SkOpPhase fPhase;
191 #ifdef SK_DEBUG
192 const char* fDebugTestName;
193 void* fDebugReporter;
194 int fAngleID;
195 int fCoinID;
196 int fContourID;
197 int fPtTID;
198 int fSegmentID;
199 int fSpanID;
200 bool fDebugSkipAssert;
201 #endif
202 #if DEBUG_T_SECT_LOOP_COUNT
203 int fDebugLoopCount[3];
204 SkPath::Verb fDebugWorstVerb[6];
205 SkPoint fDebugWorstPts[24];
206 float fDebugWorstWeight[6];
207 #endif
208 #if DEBUG_COIN
209 SkPathOpsDebug::CoinDict fCoinChangedDict;
210 SkPathOpsDebug::CoinDict fCoinVisitedDict;
211 SkPathOpsDebug::CoinDictEntry fCoinDictEntry;
212 const char* fPreviousFuncName;
213 #endif
214 #if DEBUG_COINCIDENCE
215 bool fDebugCheckHealth;
216 #endif
217 };
218
219 #ifdef SK_DEBUG
220 #if DEBUG_COINCIDENCE
221 #define SkOPASSERT(cond) SkASSERT((this->globalState() && \
222 (this->globalState()->debugCheckHealth() || \
223 this->globalState()->debugSkipAssert())) || (cond))
224 #else
225 #define SkOPASSERT(cond) SkASSERT((this->globalState() && \
226 this->globalState()->debugSkipAssert()) || (cond))
227 #endif
228 #define SkOPOBJASSERT(obj, cond) SkASSERT((obj->globalState() && \
229 obj->globalState()->debugSkipAssert()) || (cond))
230 #else
231 #define SkOPASSERT(cond)
232 #define SkOPOBJASSERT(obj, cond)
233 #endif
234
235 // Use Almost Equal when comparing coordinates. Use epsilon to compare T values.
236 bool AlmostEqualUlps(float a, float b);
AlmostEqualUlps(double a,double b)237 inline bool AlmostEqualUlps(double a, double b) {
238 return AlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
239 }
240
241 bool AlmostEqualUlpsNoNormalCheck(float a, float b);
AlmostEqualUlpsNoNormalCheck(double a,double b)242 inline bool AlmostEqualUlpsNoNormalCheck(double a, double b) {
243 return AlmostEqualUlpsNoNormalCheck(SkDoubleToScalar(a), SkDoubleToScalar(b));
244 }
245
246 bool AlmostEqualUlps_Pin(float a, float b);
AlmostEqualUlps_Pin(double a,double b)247 inline bool AlmostEqualUlps_Pin(double a, double b) {
248 return AlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
249 }
250
251 // Use Almost Dequal when comparing should not special case denormalized values.
252 bool AlmostDequalUlps(float a, float b);
253 bool AlmostDequalUlps(double a, double b);
254
255 bool NotAlmostEqualUlps(float a, float b);
NotAlmostEqualUlps(double a,double b)256 inline bool NotAlmostEqualUlps(double a, double b) {
257 return NotAlmostEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
258 }
259
260 bool NotAlmostEqualUlps_Pin(float a, float b);
NotAlmostEqualUlps_Pin(double a,double b)261 inline bool NotAlmostEqualUlps_Pin(double a, double b) {
262 return NotAlmostEqualUlps_Pin(SkDoubleToScalar(a), SkDoubleToScalar(b));
263 }
264
265 bool NotAlmostDequalUlps(float a, float b);
NotAlmostDequalUlps(double a,double b)266 inline bool NotAlmostDequalUlps(double a, double b) {
267 return NotAlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
268 }
269
270 // Use Almost Bequal when comparing coordinates in conjunction with between.
271 bool AlmostBequalUlps(float a, float b);
AlmostBequalUlps(double a,double b)272 inline bool AlmostBequalUlps(double a, double b) {
273 return AlmostBequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
274 }
275
276 bool AlmostPequalUlps(float a, float b);
AlmostPequalUlps(double a,double b)277 inline bool AlmostPequalUlps(double a, double b) {
278 return AlmostPequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
279 }
280
281 bool RoughlyEqualUlps(float a, float b);
RoughlyEqualUlps(double a,double b)282 inline bool RoughlyEqualUlps(double a, double b) {
283 return RoughlyEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
284 }
285
286 bool AlmostLessUlps(float a, float b);
AlmostLessUlps(double a,double b)287 inline bool AlmostLessUlps(double a, double b) {
288 return AlmostLessUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
289 }
290
291 bool AlmostLessOrEqualUlps(float a, float b);
AlmostLessOrEqualUlps(double a,double b)292 inline bool AlmostLessOrEqualUlps(double a, double b) {
293 return AlmostLessOrEqualUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
294 }
295
296 bool AlmostBetweenUlps(float a, float b, float c);
AlmostBetweenUlps(double a,double b,double c)297 inline bool AlmostBetweenUlps(double a, double b, double c) {
298 return AlmostBetweenUlps(SkDoubleToScalar(a), SkDoubleToScalar(b), SkDoubleToScalar(c));
299 }
300
301 int UlpsDistance(float a, float b);
UlpsDistance(double a,double b)302 inline int UlpsDistance(double a, double b) {
303 return UlpsDistance(SkDoubleToScalar(a), SkDoubleToScalar(b));
304 }
305
306 // FLT_EPSILON == 1.19209290E-07 == 1 / (2 ^ 23)
307 // DBL_EPSILON == 2.22045e-16
308 const double FLT_EPSILON_CUBED = FLT_EPSILON * FLT_EPSILON * FLT_EPSILON;
309 const double FLT_EPSILON_HALF = FLT_EPSILON / 2;
310 const double FLT_EPSILON_DOUBLE = FLT_EPSILON * 2;
311 const double FLT_EPSILON_ORDERABLE_ERR = FLT_EPSILON * 16;
312 const double FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;
313 // Use a compile-time constant for FLT_EPSILON_SQRT to avoid initializers.
314 // A 17 digit constant guarantees exact results.
315 const double FLT_EPSILON_SQRT = 0.00034526697709225118; // sqrt(FLT_EPSILON);
316 const double FLT_EPSILON_INVERSE = 1 / FLT_EPSILON;
317 const double DBL_EPSILON_ERR = DBL_EPSILON * 4; // FIXME: tune -- allow a few bits of error
318 const double DBL_EPSILON_SUBDIVIDE_ERR = DBL_EPSILON * 16;
319 const double ROUGH_EPSILON = FLT_EPSILON * 64;
320 const double MORE_ROUGH_EPSILON = FLT_EPSILON * 256;
321 const double WAY_ROUGH_EPSILON = FLT_EPSILON * 2048;
322 const double BUMP_EPSILON = FLT_EPSILON * 4096;
323
324 const SkScalar INVERSE_NUMBER_RANGE = FLT_EPSILON_ORDERABLE_ERR;
325
zero_or_one(double x)326 inline bool zero_or_one(double x) {
327 return x == 0 || x == 1;
328 }
329
approximately_zero(double x)330 inline bool approximately_zero(double x) {
331 return fabs(x) < FLT_EPSILON;
332 }
333
precisely_zero(double x)334 inline bool precisely_zero(double x) {
335 return fabs(x) < DBL_EPSILON_ERR;
336 }
337
precisely_subdivide_zero(double x)338 inline bool precisely_subdivide_zero(double x) {
339 return fabs(x) < DBL_EPSILON_SUBDIVIDE_ERR;
340 }
341
approximately_zero(float x)342 inline bool approximately_zero(float x) {
343 return fabs(x) < FLT_EPSILON;
344 }
345
approximately_zero_cubed(double x)346 inline bool approximately_zero_cubed(double x) {
347 return fabs(x) < FLT_EPSILON_CUBED;
348 }
349
approximately_zero_half(double x)350 inline bool approximately_zero_half(double x) {
351 return fabs(x) < FLT_EPSILON_HALF;
352 }
353
approximately_zero_double(double x)354 inline bool approximately_zero_double(double x) {
355 return fabs(x) < FLT_EPSILON_DOUBLE;
356 }
357
approximately_zero_orderable(double x)358 inline bool approximately_zero_orderable(double x) {
359 return fabs(x) < FLT_EPSILON_ORDERABLE_ERR;
360 }
361
approximately_zero_squared(double x)362 inline bool approximately_zero_squared(double x) {
363 return fabs(x) < FLT_EPSILON_SQUARED;
364 }
365
approximately_zero_sqrt(double x)366 inline bool approximately_zero_sqrt(double x) {
367 return fabs(x) < FLT_EPSILON_SQRT;
368 }
369
roughly_zero(double x)370 inline bool roughly_zero(double x) {
371 return fabs(x) < ROUGH_EPSILON;
372 }
373
approximately_zero_inverse(double x)374 inline bool approximately_zero_inverse(double x) {
375 return fabs(x) > FLT_EPSILON_INVERSE;
376 }
377
approximately_zero_when_compared_to(double x,double y)378 inline bool approximately_zero_when_compared_to(double x, double y) {
379 return x == 0 || fabs(x) < fabs(y * FLT_EPSILON);
380 }
381
precisely_zero_when_compared_to(double x,double y)382 inline bool precisely_zero_when_compared_to(double x, double y) {
383 return x == 0 || fabs(x) < fabs(y * DBL_EPSILON);
384 }
385
roughly_zero_when_compared_to(double x,double y)386 inline bool roughly_zero_when_compared_to(double x, double y) {
387 return x == 0 || fabs(x) < fabs(y * ROUGH_EPSILON);
388 }
389
390 // Use this for comparing Ts in the range of 0 to 1. For general numbers (larger and smaller) use
391 // AlmostEqualUlps instead.
approximately_equal(double x,double y)392 inline bool approximately_equal(double x, double y) {
393 return approximately_zero(x - y);
394 }
395
precisely_equal(double x,double y)396 inline bool precisely_equal(double x, double y) {
397 return precisely_zero(x - y);
398 }
399
precisely_subdivide_equal(double x,double y)400 inline bool precisely_subdivide_equal(double x, double y) {
401 return precisely_subdivide_zero(x - y);
402 }
403
approximately_equal_half(double x,double y)404 inline bool approximately_equal_half(double x, double y) {
405 return approximately_zero_half(x - y);
406 }
407
approximately_equal_double(double x,double y)408 inline bool approximately_equal_double(double x, double y) {
409 return approximately_zero_double(x - y);
410 }
411
approximately_equal_orderable(double x,double y)412 inline bool approximately_equal_orderable(double x, double y) {
413 return approximately_zero_orderable(x - y);
414 }
415
approximately_equal_squared(double x,double y)416 inline bool approximately_equal_squared(double x, double y) {
417 return approximately_equal(x, y);
418 }
419
approximately_greater(double x,double y)420 inline bool approximately_greater(double x, double y) {
421 return x - FLT_EPSILON >= y;
422 }
423
approximately_greater_double(double x,double y)424 inline bool approximately_greater_double(double x, double y) {
425 return x - FLT_EPSILON_DOUBLE >= y;
426 }
427
approximately_greater_orderable(double x,double y)428 inline bool approximately_greater_orderable(double x, double y) {
429 return x - FLT_EPSILON_ORDERABLE_ERR >= y;
430 }
431
approximately_greater_or_equal(double x,double y)432 inline bool approximately_greater_or_equal(double x, double y) {
433 return x + FLT_EPSILON > y;
434 }
435
approximately_greater_or_equal_double(double x,double y)436 inline bool approximately_greater_or_equal_double(double x, double y) {
437 return x + FLT_EPSILON_DOUBLE > y;
438 }
439
approximately_greater_or_equal_orderable(double x,double y)440 inline bool approximately_greater_or_equal_orderable(double x, double y) {
441 return x + FLT_EPSILON_ORDERABLE_ERR > y;
442 }
443
approximately_lesser(double x,double y)444 inline bool approximately_lesser(double x, double y) {
445 return x + FLT_EPSILON <= y;
446 }
447
approximately_lesser_double(double x,double y)448 inline bool approximately_lesser_double(double x, double y) {
449 return x + FLT_EPSILON_DOUBLE <= y;
450 }
451
approximately_lesser_orderable(double x,double y)452 inline bool approximately_lesser_orderable(double x, double y) {
453 return x + FLT_EPSILON_ORDERABLE_ERR <= y;
454 }
455
approximately_lesser_or_equal(double x,double y)456 inline bool approximately_lesser_or_equal(double x, double y) {
457 return x - FLT_EPSILON < y;
458 }
459
approximately_lesser_or_equal_double(double x,double y)460 inline bool approximately_lesser_or_equal_double(double x, double y) {
461 return x - FLT_EPSILON_DOUBLE < y;
462 }
463
approximately_lesser_or_equal_orderable(double x,double y)464 inline bool approximately_lesser_or_equal_orderable(double x, double y) {
465 return x - FLT_EPSILON_ORDERABLE_ERR < y;
466 }
467
approximately_greater_than_one(double x)468 inline bool approximately_greater_than_one(double x) {
469 return x > 1 - FLT_EPSILON;
470 }
471
precisely_greater_than_one(double x)472 inline bool precisely_greater_than_one(double x) {
473 return x > 1 - DBL_EPSILON_ERR;
474 }
475
approximately_less_than_zero(double x)476 inline bool approximately_less_than_zero(double x) {
477 return x < FLT_EPSILON;
478 }
479
precisely_less_than_zero(double x)480 inline bool precisely_less_than_zero(double x) {
481 return x < DBL_EPSILON_ERR;
482 }
483
approximately_negative(double x)484 inline bool approximately_negative(double x) {
485 return x < FLT_EPSILON;
486 }
487
approximately_negative_orderable(double x)488 inline bool approximately_negative_orderable(double x) {
489 return x < FLT_EPSILON_ORDERABLE_ERR;
490 }
491
precisely_negative(double x)492 inline bool precisely_negative(double x) {
493 return x < DBL_EPSILON_ERR;
494 }
495
approximately_one_or_less(double x)496 inline bool approximately_one_or_less(double x) {
497 return x < 1 + FLT_EPSILON;
498 }
499
approximately_one_or_less_double(double x)500 inline bool approximately_one_or_less_double(double x) {
501 return x < 1 + FLT_EPSILON_DOUBLE;
502 }
503
approximately_positive(double x)504 inline bool approximately_positive(double x) {
505 return x > -FLT_EPSILON;
506 }
507
approximately_positive_squared(double x)508 inline bool approximately_positive_squared(double x) {
509 return x > -(FLT_EPSILON_SQUARED);
510 }
511
approximately_zero_or_more(double x)512 inline bool approximately_zero_or_more(double x) {
513 return x > -FLT_EPSILON;
514 }
515
approximately_zero_or_more_double(double x)516 inline bool approximately_zero_or_more_double(double x) {
517 return x > -FLT_EPSILON_DOUBLE;
518 }
519
approximately_between_orderable(double a,double b,double c)520 inline bool approximately_between_orderable(double a, double b, double c) {
521 return a <= c
522 ? approximately_negative_orderable(a - b) && approximately_negative_orderable(b - c)
523 : approximately_negative_orderable(b - a) && approximately_negative_orderable(c - b);
524 }
525
approximately_between(double a,double b,double c)526 inline bool approximately_between(double a, double b, double c) {
527 return a <= c ? approximately_negative(a - b) && approximately_negative(b - c)
528 : approximately_negative(b - a) && approximately_negative(c - b);
529 }
530
precisely_between(double a,double b,double c)531 inline bool precisely_between(double a, double b, double c) {
532 return a <= c ? precisely_negative(a - b) && precisely_negative(b - c)
533 : precisely_negative(b - a) && precisely_negative(c - b);
534 }
535
536 // returns true if (a <= b <= c) || (a >= b >= c)
between(double a,double b,double c)537 inline bool between(double a, double b, double c) {
538 SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0)
539 || (precisely_zero(a) && precisely_zero(b) && precisely_zero(c)));
540 return (a - b) * (c - b) <= 0;
541 }
542
roughly_equal(double x,double y)543 inline bool roughly_equal(double x, double y) {
544 return fabs(x - y) < ROUGH_EPSILON;
545 }
546
roughly_negative(double x)547 inline bool roughly_negative(double x) {
548 return x < ROUGH_EPSILON;
549 }
550
roughly_between(double a,double b,double c)551 inline bool roughly_between(double a, double b, double c) {
552 return a <= c ? roughly_negative(a - b) && roughly_negative(b - c)
553 : roughly_negative(b - a) && roughly_negative(c - b);
554 }
555
more_roughly_equal(double x,double y)556 inline bool more_roughly_equal(double x, double y) {
557 return fabs(x - y) < MORE_ROUGH_EPSILON;
558 }
559
560 struct SkDPoint;
561 struct SkDVector;
562 struct SkDLine;
563 struct SkDQuad;
564 struct SkDConic;
565 struct SkDCubic;
566 struct SkDRect;
567
SkPathOpsPointsToVerb(int points)568 inline SkPath::Verb SkPathOpsPointsToVerb(int points) {
569 int verb = (1 << points) >> 1;
570 #ifdef SK_DEBUG
571 switch (points) {
572 case 0: SkASSERT(SkPath::kMove_Verb == verb); break;
573 case 1: SkASSERT(SkPath::kLine_Verb == verb); break;
574 case 2: SkASSERT(SkPath::kQuad_Verb == verb); break;
575 case 3: SkASSERT(SkPath::kCubic_Verb == verb); break;
576 default: SkDEBUGFAIL("should not be here");
577 }
578 #endif
579 return (SkPath::Verb)verb;
580 }
581
SkPathOpsVerbToPoints(SkPath::Verb verb)582 inline int SkPathOpsVerbToPoints(SkPath::Verb verb) {
583 int points = (int) verb - (((int) verb + 1) >> 2);
584 #ifdef SK_DEBUG
585 switch (verb) {
586 case SkPath::kLine_Verb: SkASSERT(1 == points); break;
587 case SkPath::kQuad_Verb: SkASSERT(2 == points); break;
588 case SkPath::kConic_Verb: SkASSERT(2 == points); break;
589 case SkPath::kCubic_Verb: SkASSERT(3 == points); break;
590 default: SkDEBUGFAIL("should not get here");
591 }
592 #endif
593 return points;
594 }
595
SkDInterp(double A,double B,double t)596 inline double SkDInterp(double A, double B, double t) {
597 return A + (B - A) * t;
598 }
599
600 double SkDCubeRoot(double x);
601
602 /* Returns -1 if negative, 0 if zero, 1 if positive
603 */
SkDSign(double x)604 inline int SkDSign(double x) {
605 return (x > 0) - (x < 0);
606 }
607
608 /* Returns 0 if negative, 1 if zero, 2 if positive
609 */
SKDSide(double x)610 inline int SKDSide(double x) {
611 return (x > 0) + (x >= 0);
612 }
613
614 /* Returns 1 if negative, 2 if zero, 4 if positive
615 */
SkDSideBit(double x)616 inline int SkDSideBit(double x) {
617 return 1 << SKDSide(x);
618 }
619
SkPinT(double t)620 inline double SkPinT(double t) {
621 return precisely_less_than_zero(t) ? 0 : precisely_greater_than_one(t) ? 1 : t;
622 }
623
624 #endif
625