1 /*
2 * Copyright 2023 Google LLC
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 "fuzz/Fuzz.h"
9 #include "include/private/base/SkAssert.h"
10 #include "include/private/base/SkFloatingPoint.h"
11 #include "src/base/SkCubics.h"
12 #include "src/base/SkQuads.h"
13 #include "src/base/SkUtils.h"
14
15 #include <cmath>
16
fuzz_cubic_real_roots(double A,double B,double C,double D)17 static void fuzz_cubic_real_roots(double A, double B, double C, double D) {
18 double roots[3];
19 const int numSolutions = SkCubics::RootsReal(A, B, C, D, roots);
20 SkASSERT_RELEASE(numSolutions >= 0 && numSolutions <= 3);
21 for (int i = 0; i < numSolutions; i++) {
22 SkASSERT_RELEASE(std::isfinite(roots[i]));
23 }
24 // Roots should not be duplicated
25 if (numSolutions >= 2) {
26 SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[1]));
27 }
28 if (numSolutions == 3) {
29 SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[1], roots[2]));
30 SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[2]));
31 }
32 }
33
fuzz_cubic_roots_valid_t(double A,double B,double C,double D)34 static void fuzz_cubic_roots_valid_t(double A, double B, double C, double D) {
35 double roots[3];
36 const int numSolutions = SkCubics::RootsValidT(A, B, C, D, roots);
37 SkASSERT_RELEASE(numSolutions >= 0 && numSolutions <= 3);
38 for (int i = 0; i < numSolutions; i++) {
39 SkASSERT_RELEASE(std::isfinite(roots[i]));
40 SkASSERT_RELEASE(roots[i] >= 0.0);
41 SkASSERT_RELEASE(roots[i] <= 1.0);
42 }
43 // Roots should not be duplicated
44 if (numSolutions >= 2) {
45 SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[1]));
46 }
47 if (numSolutions == 3) {
48 SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[1], roots[2]));
49 SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[2]));
50 }
51 }
52
fuzz_cubic_roots_binary_search(double A,double B,double C,double D)53 static void fuzz_cubic_roots_binary_search(double A, double B, double C, double D) {
54 double roots[3];
55 const int numSolutions = SkCubics::BinarySearchRootsValidT(A, B, C, D, roots);
56 SkASSERT_RELEASE(numSolutions >= 0 && numSolutions <= 3);
57 for (int i = 0; i < numSolutions; i++) {
58 SkASSERT_RELEASE(std::isfinite(roots[i]));
59 SkASSERT_RELEASE(roots[i] >= 0.0);
60 SkASSERT_RELEASE(roots[i] <= 1.0);
61 double actual = SkCubics::EvalAt(A, B, C, D, roots[i]);
62 // The binary search algorithm *should* be accurate regardless of the inputs.
63 SkASSERT_RELEASE(std::abs(actual) < 0.001);
64 }
65 // Roots should not be duplicated
66 if (numSolutions >= 2) {
67 SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[1]));
68 }
69 if (numSolutions == 3) {
70 SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[1], roots[2]));
71 SkASSERT_RELEASE(!sk_doubles_nearly_equal_ulps(roots[0], roots[2]));
72 }
73 }
74
DEF_FUZZ(CubicRoots,fuzz)75 DEF_FUZZ(CubicRoots, fuzz) {
76 double A, B, C, D;
77 fuzz->next(&A);
78 fuzz->next(&B);
79 fuzz->next(&C);
80 fuzz->next(&D);
81
82 // Uncomment for easy test case creation
83 // SkDebugf("A %16e (0x%lx) B %16e (0x%lx) C %16e (0x%lx) D %16e (0x%lx)\n",
84 // A, sk_bit_cast<uint64_t>(A), B, sk_bit_cast<uint64_t>(B),
85 // C, sk_bit_cast<uint64_t>(C), D, sk_bit_cast<uint64_t>(D));
86 fuzz_cubic_real_roots(A, B, C, D);
87
88 fuzz_cubic_roots_valid_t(A, B, C, D);
89
90 fuzz_cubic_roots_binary_search(A, B, C, D);
91 }
92