aboutsummaryrefslogtreecommitdiffhomepage
path: root/tests/SkColorSpaceXformStepsTest.cpp
blob: 05daa25b6bf8caa97805a6396754a572874757ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkColorSpacePriv.h"
#include "SkColorSpaceXformSteps.h"
#include "Test.h"

DEF_TEST(SkColorSpaceXformSteps, r) {
    auto srgb   = SkColorSpace::MakeSRGB(),
         adobe  = SkColorSpace::MakeRGB(g2Dot2_TransferFn, SkColorSpace::kAdobeRGB_Gamut),
         srgb22 = SkColorSpace::MakeRGB(g2Dot2_TransferFn, SkColorSpace::    kSRGB_Gamut),
         srgb1  = srgb ->makeLinearGamma(),
         adobe1 = adobe->makeLinearGamma();

    struct {
        sk_sp<SkColorSpace> src, dst;
        SkAlphaType         srcAT;

        bool unpremul;
        bool linearize;
        bool gamut_transform;
        bool encode;
        bool premul;

    } tests[] = {
        // The general case is converting between two color spaces with different gamuts
        // and different transfer functions.  There's no optimization possible here.
        { adobe, srgb, kPremul_SkAlphaType,
            true,  // src is encoded as f(s)*a,a, so we unpremul to f(s),a before linearizing.
            true,  // linearize to s,a
            true,  // transform s to dst gamut, s'
            true,  // encode with dst transfer function, g(s'), a
            true,  // premul to g(s')*a, a
        },
        // All the same going the other direction.
        { srgb, adobe, kPremul_SkAlphaType,  true,true,true,true,true },

        // If the src alpha type is unpremul, we'll not need that initial unpremul step.
        { adobe, srgb, kUnpremul_SkAlphaType, false,true,true,true,true },
        { srgb, adobe, kUnpremul_SkAlphaType, false,true,true,true,true },

        // If opaque, we need neither the initial unpremul, nor the premul later.
        { adobe, srgb, kOpaque_SkAlphaType, false,true,true,true,false },
        { srgb, adobe, kOpaque_SkAlphaType, false,true,true,true,false },


        // Now let's go between sRGB and sRGB with a 2.2 gamma, the gamut staying the same.
        { srgb, srgb22, kPremul_SkAlphaType,
            true,  // we need to linearize, so we need to unpremul
            true,  // we need to encode to 2.2 gamma, so we need to get linear
            false, // no need to change gamut
            true,  // linear -> gamma 2.2
            true,  // premul going into the blend
        },
        // Same sort of logic in the other direction.
        { srgb22, srgb, kPremul_SkAlphaType,  true,true,false,true,true },

        // As in the general case, when we change the alpha type unpremul and premul steps drop out.
        { srgb, srgb22, kUnpremul_SkAlphaType, false,true,false,true,true },
        { srgb22, srgb, kUnpremul_SkAlphaType, false,true,false,true,true },
        { srgb, srgb22,   kOpaque_SkAlphaType, false,true,false,true,false },
        { srgb22, srgb,   kOpaque_SkAlphaType, false,true,false,true,false },

        // Let's look at the special case of completely matching color spaces.
        // We should be ready to go into the blend without any fuss.
        { srgb, srgb,   kPremul_SkAlphaType, false,false,false,false,false },
        { srgb, srgb, kUnpremul_SkAlphaType, false,false,false,false,true },
        { srgb, srgb,   kOpaque_SkAlphaType, false,false,false,false,false },

        // We can drop out the linearize step when the source is already linear.
        { srgb1, adobe,   kPremul_SkAlphaType, true,false,true,true,true },
        { srgb1,  srgb,   kPremul_SkAlphaType, true,false,false,true,true },
        // And we can drop the encode step when the destination is linear.
        { adobe, srgb1,   kPremul_SkAlphaType, true,true,true,false,true },
        {  srgb, srgb1,   kPremul_SkAlphaType, true,true,false,false,true },

        // Here's an interesting case where only gamut transform is needed.
        { adobe1, srgb1,   kPremul_SkAlphaType, false,false,true,false,false },
        { adobe1, srgb1,   kOpaque_SkAlphaType, false,false,true,false,false },
        { adobe1, srgb1, kUnpremul_SkAlphaType, false,false,true,false, true },

        // Just finishing up with something to produce each other possible output.
        // Nothing terribly interesting in these eight.
        { srgb,  srgb1,   kOpaque_SkAlphaType, false, true,false,false,false },
        { srgb,  srgb1, kUnpremul_SkAlphaType, false, true,false,false, true },
        { srgb, adobe1,   kOpaque_SkAlphaType, false, true, true,false,false },
        { srgb, adobe1, kUnpremul_SkAlphaType, false, true, true,false, true },
        { srgb1,  srgb,   kOpaque_SkAlphaType, false,false,false, true,false },
        { srgb1,  srgb, kUnpremul_SkAlphaType, false,false,false, true, true },
        { srgb1, adobe,   kOpaque_SkAlphaType, false,false, true, true,false },
        { srgb1, adobe, kUnpremul_SkAlphaType, false,false, true, true, true },
    };

    uint32_t tested = 0x00000000;
    for (auto t : tests) {
        SkColorSpaceXformSteps steps{t.src.get(), t.srcAT, t.dst.get()};
        REPORTER_ASSERT(r, steps.flags.unpremul        == t.unpremul);
        REPORTER_ASSERT(r, steps.flags.linearize       == t.linearize);
        REPORTER_ASSERT(r, steps.flags.gamut_transform == t.gamut_transform);
        REPORTER_ASSERT(r, steps.flags.encode          == t.encode);
        REPORTER_ASSERT(r, steps.flags.premul          == t.premul);

        uint32_t bits = (uint32_t)t.unpremul        << 0
                      | (uint32_t)t.linearize       << 1
                      | (uint32_t)t.gamut_transform << 2
                      | (uint32_t)t.encode          << 3
                      | (uint32_t)t.premul          << 4;
        tested |= (1<<bits);
    }

    // We'll check our test cases cover all 2^5 == 32 possible outputs.
    for (uint32_t t = 0; t < 32; t++) {
        if (tested & (1<<t)) {
            continue;
        }

        // There a a few impossible outputs, so consider those bits tested.

        // No way to need an unpremul but not premul later, ruling out all true,?,?,?,false.
        if ((t & 1) == 1 && (t & 16) == 0) {
            continue;
        }
        // Unpremul then premul should be optimized away to a noop, so 0b10001 isn't possible.
        // A gamut transform in the middle is fine too, so 0b10101 isn't possible either.
        if (t == 0b10001 || t == 0b10101) {
            continue;
        }

        ERRORF(r, "{ xxx, yyy, at, %s,%s,%s,%s,%s }, not covered",
                (t& 1) ? " true" : "false",
                (t& 2) ? " true" : "false",
                (t& 4) ? " true" : "false",
                (t& 8) ? " true" : "false",
                (t&16) ? " true" : "false");
    }
}