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