1 /*
2 * Copyright 2016 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 #ifndef SkColorSpacePriv_DEFINED
8 #define SkColorSpacePriv_DEFINED
9
10 #include <math.h>
11
12 #include "include/core/SkColorSpace.h"
13 #include "include/private/SkFixed.h"
14
15 #define SkColorSpacePrintf(...)
16
17 // A gamut narrower than sRGB, useful for testing.
18 static constexpr skcms_Matrix3x3 gNarrow_toXYZD50 = {{
19 { 0.190974f, 0.404865f, 0.368380f },
20 { 0.114746f, 0.582937f, 0.302318f },
21 { 0.032925f, 0.153615f, 0.638669f },
22 }};
23
color_space_almost_equal(float a,float b)24 static inline bool color_space_almost_equal(float a, float b) {
25 return SkTAbs(a - b) < 0.01f;
26 }
27
28 // Let's use a stricter version for transfer functions. Worst case, these are encoded
29 // in ICC format, which offers 16-bits of fractional precision.
transfer_fn_almost_equal(float a,float b)30 static inline bool transfer_fn_almost_equal(float a, float b) {
31 return SkTAbs(a - b) < 0.001f;
32 }
33
is_valid_transfer_fn(const skcms_TransferFunction & coeffs)34 static inline bool is_valid_transfer_fn(const skcms_TransferFunction& coeffs) {
35 if (SkScalarIsNaN(coeffs.a) || SkScalarIsNaN(coeffs.b) ||
36 SkScalarIsNaN(coeffs.c) || SkScalarIsNaN(coeffs.d) ||
37 SkScalarIsNaN(coeffs.e) || SkScalarIsNaN(coeffs.f) ||
38 SkScalarIsNaN(coeffs.g))
39 {
40 return false;
41 }
42
43 if (coeffs.d < 0.0f) {
44 return false;
45 }
46
47 if (coeffs.d == 0.0f) {
48 // Y = (aX + b)^g + e for always
49 if (0.0f == coeffs.a || 0.0f == coeffs.g) {
50 SkColorSpacePrintf("A or G is zero, constant transfer function "
51 "is nonsense");
52 return false;
53 }
54 }
55
56 if (coeffs.d >= 1.0f) {
57 // Y = cX + f for always
58 if (0.0f == coeffs.c) {
59 SkColorSpacePrintf("C is zero, constant transfer function is "
60 "nonsense");
61 return false;
62 }
63 }
64
65 if ((0.0f == coeffs.a || 0.0f == coeffs.g) && 0.0f == coeffs.c) {
66 SkColorSpacePrintf("A or G, and C are zero, constant transfer function "
67 "is nonsense");
68 return false;
69 }
70
71 if (coeffs.c < 0.0f) {
72 SkColorSpacePrintf("Transfer function must be increasing");
73 return false;
74 }
75
76 if (coeffs.a < 0.0f || coeffs.g < 0.0f) {
77 SkColorSpacePrintf("Transfer function must be positive or increasing");
78 return false;
79 }
80
81 return true;
82 }
83
is_almost_srgb(const skcms_TransferFunction & coeffs)84 static inline bool is_almost_srgb(const skcms_TransferFunction& coeffs) {
85 return transfer_fn_almost_equal(SkNamedTransferFn::kSRGB.a, coeffs.a) &&
86 transfer_fn_almost_equal(SkNamedTransferFn::kSRGB.b, coeffs.b) &&
87 transfer_fn_almost_equal(SkNamedTransferFn::kSRGB.c, coeffs.c) &&
88 transfer_fn_almost_equal(SkNamedTransferFn::kSRGB.d, coeffs.d) &&
89 transfer_fn_almost_equal(SkNamedTransferFn::kSRGB.e, coeffs.e) &&
90 transfer_fn_almost_equal(SkNamedTransferFn::kSRGB.f, coeffs.f) &&
91 transfer_fn_almost_equal(SkNamedTransferFn::kSRGB.g, coeffs.g);
92 }
93
is_almost_2dot2(const skcms_TransferFunction & coeffs)94 static inline bool is_almost_2dot2(const skcms_TransferFunction& coeffs) {
95 return transfer_fn_almost_equal(1.0f, coeffs.a) &&
96 transfer_fn_almost_equal(0.0f, coeffs.b) &&
97 transfer_fn_almost_equal(0.0f, coeffs.e) &&
98 transfer_fn_almost_equal(2.2f, coeffs.g) &&
99 coeffs.d <= 0.0f;
100 }
101
is_almost_linear(const skcms_TransferFunction & coeffs)102 static inline bool is_almost_linear(const skcms_TransferFunction& coeffs) {
103 // OutputVal = InputVal ^ 1.0f
104 const bool linearExp =
105 transfer_fn_almost_equal(1.0f, coeffs.a) &&
106 transfer_fn_almost_equal(0.0f, coeffs.b) &&
107 transfer_fn_almost_equal(0.0f, coeffs.e) &&
108 transfer_fn_almost_equal(1.0f, coeffs.g) &&
109 coeffs.d <= 0.0f;
110
111 // OutputVal = 1.0f * InputVal
112 const bool linearFn =
113 transfer_fn_almost_equal(1.0f, coeffs.c) &&
114 transfer_fn_almost_equal(0.0f, coeffs.f) &&
115 coeffs.d >= 1.0f;
116
117 return linearExp || linearFn;
118 }
119
120 // Return raw pointers to commonly used SkColorSpaces.
121 // No need to ref/unref these, but if you do, do it in pairs.
122 SkColorSpace* sk_srgb_singleton();
123 SkColorSpace* sk_srgb_linear_singleton();
124
125 #endif // SkColorSpacePriv_DEFINED
126