blob: c56641d7ba5e19d0eed9dafdf8444baad2da33cc [file] [log] [blame]
reed@google.comd230e3e2011-12-05 20:49:37 +00001/*
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 "Test.h"
9#include "SkFloatingPoint.h"
10#include "SkMath.h"
11#include "SkPoint.h"
12#include "SkRandom.h"
reed@google.com30d90eb2012-05-15 14:17:36 +000013#include "SkRect.h"
reed@google.comd230e3e2011-12-05 20:49:37 +000014
15#ifdef SK_CAN_USE_FLOAT
16
reed@google.com30d90eb2012-05-15 14:17:36 +000017struct PointSet {
18 const SkPoint* fPts;
19 size_t fCount;
20 bool fIsFinite;
21};
22
23static void test_isRectFinite(skiatest::Reporter* reporter) {
reed@google.com415e76a2012-05-15 14:32:42 +000024#ifdef SK_SCALAR_IS_FLOAT
reed@google.com30d90eb2012-05-15 14:17:36 +000025 static const SkPoint gF0[] = {
26 { 0, 0 }, { 1, 1 }
27 };
28 static const SkPoint gF1[] = {
29 { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }
30 };
31
32 static const SkPoint gI0[] = {
33 { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { SK_ScalarNaN, 3 }, { 2, 3 },
34 };
35 static const SkPoint gI1[] = {
36 { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { 3, SK_ScalarNaN }, { 2, 3 },
37 };
38 static const SkPoint gI2[] = {
39 { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { SK_ScalarInfinity, 3 }, { 2, 3 },
40 };
41 static const SkPoint gI3[] = {
42 { 0, 0 }, { 1, 1 }, { 99.234f, -42342 }, { 3, SK_ScalarInfinity }, { 2, 3 },
43 };
44
45 static const struct {
46 const SkPoint* fPts;
47 size_t fCount;
48 bool fIsFinite;
49 } gSets[] = {
50 { gF0, SK_ARRAY_COUNT(gF0), true },
51 { gF1, SK_ARRAY_COUNT(gF1), true },
52
53 { gI0, SK_ARRAY_COUNT(gI0), false },
54 { gI1, SK_ARRAY_COUNT(gI1), false },
55 { gI2, SK_ARRAY_COUNT(gI2), false },
56 { gI3, SK_ARRAY_COUNT(gI3), false },
57 };
58
59 for (size_t i = 0; i < SK_ARRAY_COUNT(gSets); ++i) {
60 SkRect r;
61 r.set(gSets[i].fPts, gSets[i].fCount);
62 bool rectIsFinite = !r.isEmpty();
63 REPORTER_ASSERT(reporter, gSets[i].fIsFinite == rectIsFinite);
64 }
reed@google.com415e76a2012-05-15 14:32:42 +000065#endif
reed@google.com30d90eb2012-05-15 14:17:36 +000066}
67
reed@google.comd230e3e2011-12-05 20:49:37 +000068static bool isFinite_int(float x) {
69 uint32_t bits = SkFloat2Bits(x); // need unsigned for our shifts
70 int exponent = bits << 1 >> 24;
71 return exponent != 0xFF;
72}
73
74static bool isFinite_float(float x) {
robertphillips@google.com6853e802012-04-16 15:50:18 +000075 return SkToBool(sk_float_isfinite(x));
reed@google.comd230e3e2011-12-05 20:49:37 +000076}
77
78static bool isFinite_mulzero(float x) {
79 float y = x * 0;
80 return y == y;
81}
82
83// return true if the float is finite
84typedef bool (*IsFiniteProc1)(float);
85
86static bool isFinite2_and(float x, float y, IsFiniteProc1 proc) {
87 return proc(x) && proc(y);
88}
89
90static bool isFinite2_mulzeroadd(float x, float y, IsFiniteProc1 proc) {
91 return proc(x * 0 + y * 0);
92}
93
94// return true if both floats are finite
95typedef bool (*IsFiniteProc2)(float, float, IsFiniteProc1);
96
97#endif
98
reed@google.com5ae777d2011-12-06 20:18:05 +000099enum FloatClass {
100 kFinite,
101 kInfinite,
102 kNaN
103};
104
105static void test_floatclass(skiatest::Reporter* reporter, float value, FloatClass fc) {
106 // our sk_float_is... function may return int instead of bool,
107 // hence the double ! to turn it into a bool
108 REPORTER_ASSERT(reporter, !!sk_float_isfinite(value) == (fc == kFinite));
109 REPORTER_ASSERT(reporter, !!sk_float_isinf(value) == (fc == kInfinite));
110 REPORTER_ASSERT(reporter, !!sk_float_isnan(value) == (fc == kNaN));
111}
112
robertphillips@google.com706f6212012-05-14 17:51:23 +0000113#if defined _WIN32
114#pragma warning ( push )
115// we are intentionally causing an overflow here
116// (warning C4756: overflow in constant arithmetic)
117#pragma warning ( disable : 4756 )
118#endif
119
reed@google.comd230e3e2011-12-05 20:49:37 +0000120static void test_isfinite(skiatest::Reporter* reporter) {
121#ifdef SK_CAN_USE_FLOAT
122 struct Rec {
123 float fValue;
124 bool fIsFinite;
125 };
126
127 float max = 3.402823466e+38f;
128 float inf = max * max;
reed@google.com5ae777d2011-12-06 20:18:05 +0000129 float nan = inf * 0;
130
131 test_floatclass(reporter, 0, kFinite);
132 test_floatclass(reporter, max, kFinite);
133 test_floatclass(reporter, -max, kFinite);
134 test_floatclass(reporter, inf, kInfinite);
135 test_floatclass(reporter, -inf, kInfinite);
136 test_floatclass(reporter, nan, kNaN);
137 test_floatclass(reporter, -nan, kNaN);
reed@google.comd230e3e2011-12-05 20:49:37 +0000138
139 const Rec data[] = {
bungeman@google.comf8aa18c2012-03-19 21:04:52 +0000140 { 0, true },
141 { 1, true },
142 { -1, true },
143 { max * 0.75f, true },
144 { max, true },
145 { -max * 0.75f, true },
146 { -max, true },
147 { inf, false },
148 { -inf, false },
149 { nan, false },
reed@google.comd230e3e2011-12-05 20:49:37 +0000150 };
151
152 const IsFiniteProc1 gProc1[] = {
153 isFinite_int,
154 isFinite_float,
155 isFinite_mulzero
156 };
157 const IsFiniteProc2 gProc2[] = {
158 isFinite2_and,
159 isFinite2_mulzeroadd
160 };
161
bsalomon@google.comcadbcb82012-01-06 19:22:11 +0000162 size_t i, n = SK_ARRAY_COUNT(data);
reed@google.comd230e3e2011-12-05 20:49:37 +0000163
164 for (i = 0; i < n; ++i) {
bsalomon@google.comcadbcb82012-01-06 19:22:11 +0000165 for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
reed@google.comd230e3e2011-12-05 20:49:37 +0000166 const Rec& rec = data[i];
167 bool finite = gProc1[k](rec.fValue);
168 REPORTER_ASSERT(reporter, rec.fIsFinite == finite);
169 }
170 }
171
172 for (i = 0; i < n; ++i) {
173 const Rec& rec0 = data[i];
bsalomon@google.comcadbcb82012-01-06 19:22:11 +0000174 for (size_t j = 0; j < n; ++j) {
reed@google.comd230e3e2011-12-05 20:49:37 +0000175 const Rec& rec1 = data[j];
bsalomon@google.comcadbcb82012-01-06 19:22:11 +0000176 for (size_t k = 0; k < SK_ARRAY_COUNT(gProc1); ++k) {
reed@google.comd230e3e2011-12-05 20:49:37 +0000177 IsFiniteProc1 proc1 = gProc1[k];
178
bsalomon@google.comcadbcb82012-01-06 19:22:11 +0000179 for (size_t m = 0; m < SK_ARRAY_COUNT(gProc2); ++m) {
reed@google.comd230e3e2011-12-05 20:49:37 +0000180 bool finite = gProc2[m](rec0.fValue, rec1.fValue, proc1);
181 bool finite2 = rec0.fIsFinite && rec1.fIsFinite;
182 REPORTER_ASSERT(reporter, finite2 == finite);
183 }
184 }
185 }
186 }
reed@google.com30d90eb2012-05-15 14:17:36 +0000187
188 test_isRectFinite(reporter);
reed@google.comd230e3e2011-12-05 20:49:37 +0000189#endif
190}
191
robertphillips@google.com706f6212012-05-14 17:51:23 +0000192#if defined _WIN32
193#pragma warning ( pop )
194#endif
195
reed@google.comd230e3e2011-12-05 20:49:37 +0000196static void TestScalar(skiatest::Reporter* reporter) {
197 test_isfinite(reporter);
198}
199
200#include "TestClassDef.h"
201DEFINE_TESTCLASS("Scalar", TestScalarClass, TestScalar)
202