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 "SkFloatingPoint.h"
      9 #include "SkMath.h"
     10 #include "SkPoint.h"
     11 #include "SkRandom.h"
     12 #include "SkRect.h"
     13 #include "Test.h"
     14 
     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 
     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 
     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 
     83 static bool isFinite_float(float x) {
     84     return SkToBool(sk_float_isfinite(x));
     85 }
     86 
     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 
     95 static bool isFinite2_and(float x, float y, IsFiniteProc1 proc) {
     96     return proc(x) && proc(y);
     97 }
     98 
     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 
    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 
    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 
    201 DEF_TEST(Scalar, reporter) {
    202     test_isfinite(reporter);
    203     test_roundtoint(reporter);
    204 }
    205