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