1 /*
2  * Copyright 2011 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 
8 #include "SkFloatingPoint.h"
9 #include "SkMath.h"
10 #include "SkPoint.h"
11 #include "SkRandom.h"
12 #include "SkRect.h"
13 #include "Test.h"
14 
test_roundtoint(skiatest::Reporter * reporter)15 static void test_roundtoint(skiatest::Reporter* reporter) {
16     SkScalar x = 0.49999997f;
17     int ix = SkScalarRoundToInt(x);
18     // We "should" get 0, since x < 0.5, but we don't due to float addition rounding up the low
19     // bit after adding 0.5.
20     REPORTER_ASSERT(reporter, 1 == ix);
21 
22     // This version explicitly performs the +0.5 step using double, which should avoid losing the
23     // low bits.
24     ix = SkDScalarRoundToInt(x);
25     REPORTER_ASSERT(reporter, 0 == ix);
26 }
27 
28 struct PointSet {
29     const SkPoint* fPts;
30     size_t         fCount;
31     bool           fIsFinite;
32 };
33 
test_isRectFinite(skiatest::Reporter * reporter)34 static void test_isRectFinite(skiatest::Reporter* reporter) {
35     static const SkPoint gF0[] = {
36         { 0, 0 }, { 1, 1 }
37     };
38     static const SkPoint gF1[] = {
39         { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }
40     };
41 
42     static const SkPoint gI0[] = {
43         { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { SK_ScalarNaN, 3 }, { 2, 3 },
44     };
45     static const SkPoint gI1[] = {
46         { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { 3, SK_ScalarNaN }, { 2, 3 },
47     };
48     static const SkPoint gI2[] = {
49         { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { SK_ScalarInfinity, 3 }, { 2, 3 },
50     };
51     static const SkPoint gI3[] = {
52         { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { 3, SK_ScalarInfinity }, { 2, 3 },
53     };
54 
55     static const struct {
56         const SkPoint* fPts;
57         int            fCount;
58         bool           fIsFinite;
59     } gSets[] = {
60         { gF0, SK_ARRAY_COUNT(gF0), true },
61         { gF1, SK_ARRAY_COUNT(gF1), true },
62 
63         { gI0, SK_ARRAY_COUNT(gI0), false },
64         { gI1, SK_ARRAY_COUNT(gI1), false },
65         { gI2, SK_ARRAY_COUNT(gI2), false },
66         { gI3, SK_ARRAY_COUNT(gI3), false },
67     };
68 
69     for (size_t i = 0; i < SK_ARRAY_COUNT(gSets); ++i) {
70         SkRect r;
71         r.set(gSets[i].fPts, gSets[i].fCount);
72         bool rectIsFinite = !r.isEmpty();
73         REPORTER_ASSERT(reporter, gSets[i].fIsFinite == rectIsFinite);
74     }
75 }
76 
isFinite_int(float x)77 static bool isFinite_int(float x) {
78     uint32_t bits = SkFloat2Bits(x);    // need unsigned for our shifts
79     int exponent = bits << 1 >> 24;
80     return exponent != 0xFF;
81 }
82 
isFinite_float(float x)83 static bool isFinite_float(float x) {
84     return SkToBool(sk_float_isfinite(x));
85 }
86 
isFinite_mulzero(float x)87 static bool isFinite_mulzero(float x) {
88     float y = x * 0;
89     return y == y;
90 }
91 
92 // return true if the float is finite
93 typedef bool (*IsFiniteProc1)(float);
94 
isFinite2_and(float x,float y,IsFiniteProc1 proc)95 static bool isFinite2_and(float x, float y, IsFiniteProc1 proc) {
96     return proc(x) && proc(y);
97 }
98 
isFinite2_mulzeroadd(float x,float y,IsFiniteProc1 proc)99 static bool isFinite2_mulzeroadd(float x, float y, IsFiniteProc1 proc) {
100     return proc(x * 0 + y * 0);
101 }
102 
103 // return true if both floats are finite
104 typedef bool (*IsFiniteProc2)(float, float, IsFiniteProc1);
105 
106 enum FloatClass {
107     kFinite,
108     kInfinite,
109     kNaN
110 };
111 
test_floatclass(skiatest::Reporter * reporter,float value,FloatClass fc)112 static void test_floatclass(skiatest::Reporter* reporter, float value, FloatClass fc) {
113     // our sk_float_is... function may return int instead of bool,
114     // hence the double ! to turn it into a bool
115     REPORTER_ASSERT(reporter, !!sk_float_isfinite(value) == (fc == kFinite));
116     REPORTER_ASSERT(reporter, !!sk_float_isinf(value) == (fc == kInfinite));
117     REPORTER_ASSERT(reporter, !!sk_float_isnan(value) == (fc == kNaN));
118 }
119 
120 #if defined _WIN32
121 #pragma warning ( push )
122 // we are intentionally causing an overflow here
123 //      (warning C4756: overflow in constant arithmetic)
124 #pragma warning ( disable : 4756 )
125 #endif
126 
test_isfinite(skiatest::Reporter * reporter)127 static void test_isfinite(skiatest::Reporter* reporter) {
128     struct Rec {
129         float   fValue;
130         bool    fIsFinite;
131     };
132 
133     float max = 3.402823466e+38f;
134     float inf = max * max;
135     float nan = inf * 0;
136 
137     test_floatclass(reporter,    0, kFinite);
138     test_floatclass(reporter,  max, kFinite);
139     test_floatclass(reporter, -max, kFinite);
140     test_floatclass(reporter,  inf, kInfinite);
141     test_floatclass(reporter, -inf, kInfinite);
142     test_floatclass(reporter,  nan, kNaN);
143     test_floatclass(reporter, -nan, kNaN);
144 
145     const Rec data[] = {
146         {   0,           true    },
147         {   1,           true    },
148         {  -1,           true    },
149         {  max * 0.75f,  true    },
150         {  max,          true    },
151         {  -max * 0.75f, true    },
152         {  -max,         true    },
153         {  inf,          false   },
154         { -inf,          false   },
155         {  nan,          false   },
156     };
157 
158     const IsFiniteProc1 gProc1[] = {
159         isFinite_int,
160         isFinite_float,
161         isFinite_mulzero
162     };
163     const IsFiniteProc2 gProc2[] = {
164         isFinite2_and,
165         isFinite2_mulzeroadd
166     };
167 
168     size_t i, n = SK_ARRAY_COUNT(data);
169 
170     for (i = 0; i < n; ++i) {
171         for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
172             const Rec& rec = data[i];
173             bool finite = gProc1[k](rec.fValue);
174             REPORTER_ASSERT(reporter, rec.fIsFinite == finite);
175         }
176     }
177 
178     for (i = 0; i < n; ++i) {
179         const Rec& rec0 = data[i];
180         for (size_t j = 0; j < n; ++j) {
181             const Rec& rec1 = data[j];
182             for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
183                 IsFiniteProc1 proc1 = gProc1[k];
184 
185                 for (size_t m = 0; m < SK_ARRAY_COUNT(gProc2); ++m) {
186                     bool finite = gProc2[m](rec0.fValue, rec1.fValue, proc1);
187                     bool finite2 = rec0.fIsFinite && rec1.fIsFinite;
188                     REPORTER_ASSERT(reporter, finite2 == finite);
189                 }
190             }
191         }
192     }
193 
194     test_isRectFinite(reporter);
195 }
196 
197 #if defined _WIN32
198 #pragma warning ( pop )
199 #endif
200 
DEF_TEST(Scalar,reporter)201 DEF_TEST(Scalar, reporter) {
202     test_isfinite(reporter);
203     test_roundtoint(reporter);
204 }
205