blob: 9fdd21e7c0af721dfccf1e109fe4d1355797f8fa [file] [log] [blame]
Mike Klein6968f9c2018-05-24 12:33:23 -04001/*
2 * Copyright 2018 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 "SkColorSpacePriv.h"
9#include "SkColorSpaceXformSteps.h"
10#include "Test.h"
11
Mike Klein6968f9c2018-05-24 12:33:23 -040012DEF_TEST(SkColorSpaceXformSteps, r) {
Mike Klein97918ff2018-05-25 12:55:58 -040013 auto srgb = SkColorSpace::MakeSRGB(),
14 adobe = SkColorSpace::MakeRGB(g2Dot2_TransferFn, SkColorSpace::kAdobeRGB_Gamut),
15 srgb22 = SkColorSpace::MakeRGB(g2Dot2_TransferFn, SkColorSpace:: kSRGB_Gamut),
16 srgb1 = srgb ->makeLinearGamma(),
17 adobe1 = adobe->makeLinearGamma();
Mike Klein6968f9c2018-05-24 12:33:23 -040018
19 struct {
20 sk_sp<SkColorSpace> src, dst;
Mike Kleinbe6e5752018-05-24 15:27:03 -040021 SkAlphaType srcAT;
Mike Klein6968f9c2018-05-24 12:33:23 -040022
Mike Klein97918ff2018-05-25 12:55:58 -040023 bool unpremul;
24 bool linearize;
Mike Klein6968f9c2018-05-24 12:33:23 -040025 bool gamut_transform;
Mike Klein97918ff2018-05-25 12:55:58 -040026 bool encode;
Mike Klein6968f9c2018-05-24 12:33:23 -040027 bool premul;
28
Mike Klein6968f9c2018-05-24 12:33:23 -040029 } tests[] = {
Mike Klein97918ff2018-05-25 12:55:58 -040030 // The general case is converting between two color spaces with different gamuts
31 // and different transfer functions. There's no optimization possible here.
32 { adobe, srgb, kPremul_SkAlphaType,
33 true, // src is encoded as f(s)*a,a, so we unpremul to f(s),a before linearizing.
34 true, // linearize to s,a
35 true, // transform s to dst gamut, s'
36 true, // encode with dst transfer function, g(s'), a
37 true, // premul to g(s')*a, a
Mike Klein6968f9c2018-05-24 12:33:23 -040038 },
Mike Klein97918ff2018-05-25 12:55:58 -040039 // All the same going the other direction.
40 { srgb, adobe, kPremul_SkAlphaType, true,true,true,true,true },
Mike Klein6968f9c2018-05-24 12:33:23 -040041
Mike Klein97918ff2018-05-25 12:55:58 -040042 // If the src alpha type is unpremul, we'll not need that initial unpremul step.
43 { adobe, srgb, kUnpremul_SkAlphaType, false,true,true,true,true },
44 { srgb, adobe, kUnpremul_SkAlphaType, false,true,true,true,true },
Mike Klein6968f9c2018-05-24 12:33:23 -040045
Mike Klein97918ff2018-05-25 12:55:58 -040046 // If opaque, we need neither the initial unpremul, nor the premul later.
47 { adobe, srgb, kOpaque_SkAlphaType, false,true,true,true,false },
48 { srgb, adobe, kOpaque_SkAlphaType, false,true,true,true,false },
Mike Klein6968f9c2018-05-24 12:33:23 -040049
Mike Klein97918ff2018-05-25 12:55:58 -040050
51 // Now let's go between sRGB and sRGB with a 2.2 gamma, the gamut staying the same.
52 { srgb, srgb22, kPremul_SkAlphaType,
53 true, // we need to linearize, so we need to unpremul
54 true, // we need to encode to 2.2 gamma, so we need to get linear
55 false, // no need to change gamut
56 true, // linear -> gamma 2.2
57 true, // premul going into the blend
Mike Klein6968f9c2018-05-24 12:33:23 -040058 },
Mike Klein97918ff2018-05-25 12:55:58 -040059 // Same sort of logic in the other direction.
60 { srgb22, srgb, kPremul_SkAlphaType, true,true,false,true,true },
Mike Klein6968f9c2018-05-24 12:33:23 -040061
Mike Klein97918ff2018-05-25 12:55:58 -040062 // As in the general case, when we change the alpha type unpremul and premul steps drop out.
63 { srgb, srgb22, kUnpremul_SkAlphaType, false,true,false,true,true },
64 { srgb22, srgb, kUnpremul_SkAlphaType, false,true,false,true,true },
65 { srgb, srgb22, kOpaque_SkAlphaType, false,true,false,true,false },
66 { srgb22, srgb, kOpaque_SkAlphaType, false,true,false,true,false },
Mike Klein6968f9c2018-05-24 12:33:23 -040067
Mike Klein97918ff2018-05-25 12:55:58 -040068 // Let's look at the special case of completely matching color spaces.
69 // We should be ready to go into the blend without any fuss.
70 { srgb, srgb, kPremul_SkAlphaType, false,false,false,false,false },
71 { srgb, srgb, kUnpremul_SkAlphaType, false,false,false,false,true },
72 { srgb, srgb, kOpaque_SkAlphaType, false,false,false,false,false },
Mike Klein6968f9c2018-05-24 12:33:23 -040073
Mike Klein97918ff2018-05-25 12:55:58 -040074 // We can drop out the linearize step when the source is already linear.
75 { srgb1, adobe, kPremul_SkAlphaType, true,false,true,true,true },
76 { srgb1, srgb, kPremul_SkAlphaType, true,false,false,true,true },
77 // And we can drop the encode step when the destination is linear.
78 { adobe, srgb1, kPremul_SkAlphaType, true,true,true,false,true },
79 { srgb, srgb1, kPremul_SkAlphaType, true,true,false,false,true },
Mike Klein6968f9c2018-05-24 12:33:23 -040080
Mike Klein97918ff2018-05-25 12:55:58 -040081 // Here's an interesting case where only gamut transform is needed.
82 { adobe1, srgb1, kPremul_SkAlphaType, false,false,true,false,false },
83 { adobe1, srgb1, kOpaque_SkAlphaType, false,false,true,false,false },
84 { adobe1, srgb1, kUnpremul_SkAlphaType, false,false,true,false, true },
Mike Klein6968f9c2018-05-24 12:33:23 -040085
Mike Klein97918ff2018-05-25 12:55:58 -040086 // Just finishing up with something to produce each other possible output.
87 // Nothing terribly interesting in these eight.
88 { srgb, srgb1, kOpaque_SkAlphaType, false, true,false,false,false },
89 { srgb, srgb1, kUnpremul_SkAlphaType, false, true,false,false, true },
90 { srgb, adobe1, kOpaque_SkAlphaType, false, true, true,false,false },
91 { srgb, adobe1, kUnpremul_SkAlphaType, false, true, true,false, true },
92 { srgb1, srgb, kOpaque_SkAlphaType, false,false,false, true,false },
93 { srgb1, srgb, kUnpremul_SkAlphaType, false,false,false, true, true },
94 { srgb1, adobe, kOpaque_SkAlphaType, false,false, true, true,false },
95 { srgb1, adobe, kUnpremul_SkAlphaType, false,false, true, true, true },
Mike Klein6968f9c2018-05-24 12:33:23 -040096 };
97
Mike Klein97918ff2018-05-25 12:55:58 -040098 uint32_t tested = 0x00000000;
Mike Klein6968f9c2018-05-24 12:33:23 -040099 for (auto t : tests) {
Mike Klein97918ff2018-05-25 12:55:58 -0400100 SkColorSpaceXformSteps steps{t.src.get(), t.srcAT, t.dst.get()};
101 REPORTER_ASSERT(r, steps.unpremul == t.unpremul);
102 REPORTER_ASSERT(r, steps.linearize == t.linearize);
103 REPORTER_ASSERT(r, steps.gamut_transform == t.gamut_transform);
104 REPORTER_ASSERT(r, steps.encode == t.encode);
105 REPORTER_ASSERT(r, steps.premul == t.premul);
106
107 uint32_t bits = (uint32_t)t.unpremul << 0
108 | (uint32_t)t.linearize << 1
109 | (uint32_t)t.gamut_transform << 2
110 | (uint32_t)t.encode << 3
111 | (uint32_t)t.premul << 4;
112 tested |= (1<<bits);
113 }
114
115 // We'll check our test cases cover all 2^5 == 32 possible outputs.
116 for (uint32_t t = 0; t < 32; t++) {
117 if (tested & (1<<t)) {
118 continue;
119 }
120
121 // There a a few impossible outputs, so consider those bits tested.
122
123 // No way to need an unpremul but not premul later, ruling out all true,?,?,?,false.
124 if ((t & 1) == 1 && (t & 16) == 0) {
125 continue;
126 }
127 // Unpremul then premul should be optimized away to a noop, so 0b10001 isn't possible.
128 // A gamut transform in the middle is fine too, so 0b10101 isn't possible either.
129 if (t == 17 || t == 21) {
130 continue;
131 }
132
133 ERRORF(r, "{ xxx, yyy, at, %s,%s,%s,%s,%s }, not covered",
134 (t& 1) ? " true" : "false",
135 (t& 2) ? " true" : "false",
136 (t& 4) ? " true" : "false",
137 (t& 8) ? " true" : "false",
138 (t&16) ? " true" : "false");
Mike Klein6968f9c2018-05-24 12:33:23 -0400139 }
140}