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
8#ifndef SkGammas_DEFINED
9#define SkGammas_DEFINED
10
11#include "SkColorSpace.h"
12#include "SkData.h"
13#include "SkTemplates.h"
14
15struct SkGammas : SkRefCnt {
16
17    // There are four possible representations for gamma curves.  kNone_Type is used
18    // as a placeholder until the struct is initialized.  It is not a valid value.
19    enum class Type {
20        kNone_Type,
21        kNamed_Type,
22        kValue_Type,
23        kTable_Type,
24        kParam_Type,
25    };
26
27    // Contains information for a gamma table.
28    struct Table {
29        size_t fOffset;
30        int    fSize;
31
32        const float* table(const SkGammas* base) const {
33            return SkTAddOffset<const float>(base, sizeof(SkGammas) + fOffset);
34        }
35    };
36
37    // Contains the actual gamma curve information.  Should be interpreted
38    // based on the type of the gamma curve.
39    union Data {
40        Data() : fTable{0, 0} {}
41
42        SkGammaNamed fNamed;
43        float        fValue;
44        Table        fTable;
45        size_t       fParamOffset;
46
47        const SkColorSpaceTransferFn& params(const SkGammas* base) const {
48            return *SkTAddOffset<const SkColorSpaceTransferFn>(base,
49                                                               sizeof(SkGammas) + fParamOffset);
50        }
51    };
52
53    bool allChannelsSame() const {
54        // All channels are the same type?
55        Type type = this->type(0);
56        for (int i = 1; i < this->channels(); i++) {
57            if (type != this->type(i)) {
58                return false;
59            }
60        }
61
62        // All data the same?
63        auto& first = this->data(0);
64        for (int i = 1; i < this->channels(); i++) {
65            auto& data = this->data(i);
66            switch (type) {
67                case Type:: kNone_Type:                                                    break;
68                case Type::kNamed_Type: if (first.fNamed != data.fNamed) { return false; } break;
69                case Type::kValue_Type: if (first.fValue != data.fValue) { return false; } break;
70                case Type::kTable_Type:
71                    if (first.fTable.fOffset != data.fTable.fOffset) { return false; }
72                    if (first.fTable.fSize   != data.fTable.fSize  ) { return false; }
73                    break;
74                case Type::kParam_Type:
75                    if (0 != memcmp(&first.params(this), &data.params(this),
76                                    sizeof(SkColorSpaceTransferFn))) {
77                        return false;
78                    }
79                    break;
80            }
81        }
82        return true;
83    }
84
85    bool isNamed     (int i) const { return Type::kNamed_Type == this->type(i); }
86    bool isValue     (int i) const { return Type::kValue_Type == this->type(i); }
87    bool isTable     (int i) const { return Type::kTable_Type == this->type(i); }
88    bool isParametric(int i) const { return Type::kParam_Type == this->type(i); }
89
90    const Data& data(int i) const {
91        SkASSERT(i >= 0 && i < fChannels);
92        return fData[i];
93    }
94
95    const float* table(int i) const {
96        SkASSERT(this->isTable(i));
97        return this->data(i).fTable.table(this);
98    }
99
100    int tableSize(int i) const {
101        SkASSERT(this->isTable(i));
102        return this->data(i).fTable.fSize;
103    }
104
105    const SkColorSpaceTransferFn& params(int i) const {
106        SkASSERT(this->isParametric(i));
107        return this->data(i).params(this);
108    }
109
110    Type type(int i) const {
111        SkASSERT(i >= 0 && i < fChannels);
112        return fType[i];
113    }
114
115    int channels() const { return fChannels; }
116
117    SkGammas(int channels) : fChannels(channels) {
118        SkASSERT(channels <= (int)SK_ARRAY_COUNT(fType));
119        for (Type& t : fType) {
120            t = Type::kNone_Type;
121        }
122    }
123
124    // These fields should only be modified when initializing the struct.
125    int  fChannels;
126    Data fData[4];
127    Type fType[4];
128
129    // Objects of this type are sometimes created in a custom fashion using
130    // sk_malloc_throw and therefore must be sk_freed.  We overload new to
131    // also call sk_malloc_throw so that memory can be unconditionally released
132    // using sk_free in an overloaded delete. Overloading regular new means we
133    // must also overload placement new.
134    void* operator new(size_t size) { return sk_malloc_throw(size); }
135    void* operator new(size_t, void* p) { return p; }
136    void operator delete(void* p) { sk_free(p); }
137};
138
139#endif
140