Home | History | Annotate | Download | only in tests
      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