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