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 "src/pathops/SkPathOpsTypes.h"
8
9 #include "include/private/base/SkFloatingPoint.h"
10 #include "include/private/base/SkTemplates.h"
11 #include "include/private/base/SkFloatBits.h"
12 #include "include/private/base/SkMath.h"
13
14 #include <algorithm>
15 #include <cstdint>
16
arguments_denormalized(float a,float b,int epsilon)17 static bool arguments_denormalized(float a, float b, int epsilon) {
18 float denormalizedCheck = FLT_EPSILON * epsilon / 2;
19 return fabsf(a) <= denormalizedCheck && fabsf(b) <= denormalizedCheck;
20 }
21
22 // from http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
23 // FIXME: move to SkFloatBits.h
equal_ulps(float a,float b,int epsilon,int depsilon)24 static bool equal_ulps(float a, float b, int epsilon, int depsilon) {
25 if (arguments_denormalized(a, b, depsilon)) {
26 return true;
27 }
28 int aBits = SkFloatAs2sCompliment(a);
29 int bBits = SkFloatAs2sCompliment(b);
30 // Find the difference in ULPs.
31 return aBits < bBits + epsilon && bBits < aBits + epsilon;
32 }
33
equal_ulps_no_normal_check(float a,float b,int epsilon,int depsilon)34 static bool equal_ulps_no_normal_check(float a, float b, int epsilon, int depsilon) {
35 int aBits = SkFloatAs2sCompliment(a);
36 int bBits = SkFloatAs2sCompliment(b);
37 // Find the difference in ULPs.
38 return aBits < bBits + epsilon && bBits < aBits + epsilon;
39 }
40
equal_ulps_pin(float a,float b,int epsilon,int depsilon)41 static bool equal_ulps_pin(float a, float b, int epsilon, int depsilon) {
42 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
43 return false;
44 }
45 if (arguments_denormalized(a, b, depsilon)) {
46 return true;
47 }
48 int aBits = SkFloatAs2sCompliment(a);
49 int bBits = SkFloatAs2sCompliment(b);
50 // Find the difference in ULPs.
51 return aBits < bBits + epsilon && bBits < aBits + epsilon;
52 }
53
d_equal_ulps(float a,float b,int epsilon)54 static bool d_equal_ulps(float a, float b, int epsilon) {
55 int aBits = SkFloatAs2sCompliment(a);
56 int bBits = SkFloatAs2sCompliment(b);
57 // Find the difference in ULPs.
58 return aBits < bBits + epsilon && bBits < aBits + epsilon;
59 }
60
not_equal_ulps(float a,float b,int epsilon)61 static bool not_equal_ulps(float a, float b, int epsilon) {
62 if (arguments_denormalized(a, b, epsilon)) {
63 return false;
64 }
65 int aBits = SkFloatAs2sCompliment(a);
66 int bBits = SkFloatAs2sCompliment(b);
67 // Find the difference in ULPs.
68 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
69 }
70
not_equal_ulps_pin(float a,float b,int epsilon)71 static bool not_equal_ulps_pin(float a, float b, int epsilon) {
72 if (!SkScalarIsFinite(a) || !SkScalarIsFinite(b)) {
73 return false;
74 }
75 if (arguments_denormalized(a, b, epsilon)) {
76 return false;
77 }
78 int aBits = SkFloatAs2sCompliment(a);
79 int bBits = SkFloatAs2sCompliment(b);
80 // Find the difference in ULPs.
81 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
82 }
83
d_not_equal_ulps(float a,float b,int epsilon)84 static bool d_not_equal_ulps(float a, float b, int epsilon) {
85 int aBits = SkFloatAs2sCompliment(a);
86 int bBits = SkFloatAs2sCompliment(b);
87 // Find the difference in ULPs.
88 return aBits >= bBits + epsilon || bBits >= aBits + epsilon;
89 }
90
less_ulps(float a,float b,int epsilon)91 static bool less_ulps(float a, float b, int epsilon) {
92 if (arguments_denormalized(a, b, epsilon)) {
93 return a <= b - FLT_EPSILON * epsilon;
94 }
95 int aBits = SkFloatAs2sCompliment(a);
96 int bBits = SkFloatAs2sCompliment(b);
97 // Find the difference in ULPs.
98 return aBits <= bBits - epsilon;
99 }
100
less_or_equal_ulps(float a,float b,int epsilon)101 static bool less_or_equal_ulps(float a, float b, int epsilon) {
102 if (arguments_denormalized(a, b, epsilon)) {
103 return a < b + FLT_EPSILON * epsilon;
104 }
105 int aBits = SkFloatAs2sCompliment(a);
106 int bBits = SkFloatAs2sCompliment(b);
107 // Find the difference in ULPs.
108 return aBits < bBits + epsilon;
109 }
110
111 // equality using the same error term as between
AlmostBequalUlps(float a,float b)112 bool AlmostBequalUlps(float a, float b) {
113 const int UlpsEpsilon = 2;
114 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
115 }
116
AlmostPequalUlps(float a,float b)117 bool AlmostPequalUlps(float a, float b) {
118 const int UlpsEpsilon = 8;
119 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
120 }
121
AlmostDequalUlps(float a,float b)122 bool AlmostDequalUlps(float a, float b) {
123 const int UlpsEpsilon = 16;
124 return d_equal_ulps(a, b, UlpsEpsilon);
125 }
126
AlmostDequalUlps(double a,double b)127 bool AlmostDequalUlps(double a, double b) {
128 if (fabs(a) < SK_ScalarMax && fabs(b) < SK_ScalarMax) {
129 return AlmostDequalUlps(SkDoubleToScalar(a), SkDoubleToScalar(b));
130 }
131 // We allow divide-by-zero here. It only happens if one of a,b is zero, and the other is NaN.
132 // (Otherwise, we'd hit the condition above). Thus, if std::max returns 0, we compute NaN / 0,
133 // which will produce NaN. The comparison will return false, which is the correct answer.
134 return sk_ieee_double_divide(fabs(a - b), std::max(fabs(a), fabs(b))) < FLT_EPSILON * 16;
135 }
136
AlmostEqualUlps(float a,float b)137 bool AlmostEqualUlps(float a, float b) {
138 const int UlpsEpsilon = 16;
139 return equal_ulps(a, b, UlpsEpsilon, UlpsEpsilon);
140 }
141
AlmostEqualUlpsNoNormalCheck(float a,float b)142 bool AlmostEqualUlpsNoNormalCheck(float a, float b) {
143 const int UlpsEpsilon = 16;
144 return equal_ulps_no_normal_check(a, b, UlpsEpsilon, UlpsEpsilon);
145 }
146
AlmostEqualUlps_Pin(float a,float b)147 bool AlmostEqualUlps_Pin(float a, float b) {
148 const int UlpsEpsilon = 16;
149 return equal_ulps_pin(a, b, UlpsEpsilon, UlpsEpsilon);
150 }
151
NotAlmostEqualUlps(float a,float b)152 bool NotAlmostEqualUlps(float a, float b) {
153 const int UlpsEpsilon = 16;
154 return not_equal_ulps(a, b, UlpsEpsilon);
155 }
156
NotAlmostEqualUlps_Pin(float a,float b)157 bool NotAlmostEqualUlps_Pin(float a, float b) {
158 const int UlpsEpsilon = 16;
159 return not_equal_ulps_pin(a, b, UlpsEpsilon);
160 }
161
NotAlmostDequalUlps(float a,float b)162 bool NotAlmostDequalUlps(float a, float b) {
163 const int UlpsEpsilon = 16;
164 return d_not_equal_ulps(a, b, UlpsEpsilon);
165 }
166
RoughlyEqualUlps(float a,float b)167 bool RoughlyEqualUlps(float a, float b) {
168 const int UlpsEpsilon = 256;
169 const int DUlpsEpsilon = 1024;
170 return equal_ulps(a, b, UlpsEpsilon, DUlpsEpsilon);
171 }
172
AlmostBetweenUlps(float a,float b,float c)173 bool AlmostBetweenUlps(float a, float b, float c) {
174 const int UlpsEpsilon = 2;
175 return a <= c ? less_or_equal_ulps(a, b, UlpsEpsilon) && less_or_equal_ulps(b, c, UlpsEpsilon)
176 : less_or_equal_ulps(b, a, UlpsEpsilon) && less_or_equal_ulps(c, b, UlpsEpsilon);
177 }
178
AlmostLessUlps(float a,float b)179 bool AlmostLessUlps(float a, float b) {
180 const int UlpsEpsilon = 16;
181 return less_ulps(a, b, UlpsEpsilon);
182 }
183
AlmostLessOrEqualUlps(float a,float b)184 bool AlmostLessOrEqualUlps(float a, float b) {
185 const int UlpsEpsilon = 16;
186 return less_or_equal_ulps(a, b, UlpsEpsilon);
187 }
188
UlpsDistance(float a,float b)189 int UlpsDistance(float a, float b) {
190 SkFloatIntUnion floatIntA, floatIntB;
191 floatIntA.fFloat = a;
192 floatIntB.fFloat = b;
193 // Different signs means they do not match.
194 if ((floatIntA.fSignBitInt < 0) != (floatIntB.fSignBitInt < 0)) {
195 // Check for equality to make sure +0 == -0
196 return a == b ? 0 : SK_MaxS32;
197 }
198 // Find the difference in ULPs.
199 return SkTAbs(floatIntA.fSignBitInt - floatIntB.fSignBitInt);
200 }
201
SkOpGlobalState(SkOpContourHead * head,SkArenaAlloc * allocator SkDEBUGPARAMS (bool debugSkipAssert)SkDEBUGPARAMS (const char * testName))202 SkOpGlobalState::SkOpGlobalState(SkOpContourHead* head,
203 SkArenaAlloc* allocator
204 SkDEBUGPARAMS(bool debugSkipAssert)
205 SkDEBUGPARAMS(const char* testName))
206 : fAllocator(allocator)
207 , fCoincidence(nullptr)
208 , fContourHead(head)
209 , fNested(0)
210 , fWindingFailed(false)
211 , fPhase(SkOpPhase::kIntersecting)
212 SkDEBUGPARAMS(fDebugTestName(testName))
213 SkDEBUGPARAMS(fAngleID(0))
214 SkDEBUGPARAMS(fCoinID(0))
215 SkDEBUGPARAMS(fContourID(0))
216 SkDEBUGPARAMS(fPtTID(0))
217 SkDEBUGPARAMS(fSegmentID(0))
218 SkDEBUGPARAMS(fSpanID(0))
219 SkDEBUGPARAMS(fDebugSkipAssert(debugSkipAssert)) {
220 #if DEBUG_T_SECT_LOOP_COUNT
221 debugResetLoopCounts();
222 #endif
223 #if DEBUG_COIN
224 fPreviousFuncName = nullptr;
225 #endif
226 }
227