Home | History | Annotate | Download | only in core
      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 
     15 struct 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