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