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 SkColorSpace_Base_DEFINED
      9 #define SkColorSpace_Base_DEFINED
     10 
     11 #include "SkColorLookUpTable.h"
     12 #include "SkColorSpace.h"
     13 #include "SkData.h"
     14 #include "SkOnce.h"
     15 #include "SkTemplates.h"
     16 
     17 enum SkGammaNamed : uint8_t {
     18     kLinear_SkGammaNamed,
     19     kSRGB_SkGammaNamed,
     20     k2Dot2Curve_SkGammaNamed,
     21     kNonStandard_SkGammaNamed,
     22 };
     23 
     24 struct SkGammas : SkRefCnt {
     25 
     26     // There are four possible representations for gamma curves.  kNone_Type is used
     27     // as a placeholder until the struct is initialized.  It is not a valid value.
     28     enum class Type : uint8_t {
     29         kNone_Type,
     30         kNamed_Type,
     31         kValue_Type,
     32         kTable_Type,
     33         kParam_Type,
     34     };
     35 
     36     // Contains information for a gamma table.
     37     struct Table {
     38         size_t fOffset;
     39         int    fSize;
     40 
     41         const float* table(const SkGammas* base) const {
     42             return SkTAddOffset<const float>(base, sizeof(SkGammas) + fOffset);
     43         }
     44     };
     45 
     46     // Contains the actual gamma curve information.  Should be interpreted
     47     // based on the type of the gamma curve.
     48     union Data {
     49         Data()
     50             : fTable{ 0, 0 }
     51         {}
     52 
     53         inline bool operator==(const Data& that) const {
     54             return this->fTable.fOffset == that.fTable.fOffset &&
     55                    this->fTable.fSize == that.fTable.fSize;
     56         }
     57 
     58         inline bool operator!=(const Data& that) const {
     59             return !(*this == that);
     60         }
     61 
     62         SkGammaNamed             fNamed;
     63         float                    fValue;
     64         Table                    fTable;
     65         size_t                   fParamOffset;
     66 
     67         const SkColorSpaceTransferFn& params(const SkGammas* base) const {
     68             return *SkTAddOffset<const SkColorSpaceTransferFn>(
     69                     base, sizeof(SkGammas) + fParamOffset);
     70         }
     71     };
     72 
     73     bool isNamed(int i) const {
     74         return Type::kNamed_Type == this->type(i);
     75     }
     76 
     77     bool isValue(int i) const {
     78         return Type::kValue_Type == this->type(i);
     79     }
     80 
     81     bool isTable(int i) const {
     82         return Type::kTable_Type == this->type(i);
     83     }
     84 
     85     bool isParametric(int i) const {
     86         return Type::kParam_Type == this->type(i);
     87     }
     88 
     89     const Data& data(int i) const {
     90         SkASSERT(i >= 0 && i < fChannels);
     91         return fData[i];
     92     }
     93 
     94     const float* table(int i) const {
     95         SkASSERT(isTable(i));
     96         return this->data(i).fTable.table(this);
     97     }
     98 
     99     int tableSize(int i) const {
    100         SkASSERT(isTable(i));
    101         return this->data(i).fTable.fSize;
    102     }
    103 
    104     const SkColorSpaceTransferFn& params(int i) const {
    105         SkASSERT(isParametric(i));
    106         return this->data(i).params(this);
    107     }
    108 
    109     Type type(int i) const {
    110         SkASSERT(i >= 0 && i < fChannels);
    111         return fType[i];
    112     }
    113 
    114     uint8_t channels() const { return fChannels; }
    115 
    116     SkGammas(uint8_t channels)
    117         : fChannels(channels) {
    118         SkASSERT(channels <= kMaxColorChannels);
    119         for (uint8_t i = 0; i < kMaxColorChannels; ++i) {
    120             fType[i] = Type::kNone_Type;
    121         }
    122     }
    123 
    124     // These fields should only be modified when initializing the struct.
    125     uint8_t fChannels;
    126     Data    fData[kMaxColorChannels];
    127     Type    fType[kMaxColorChannels];
    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 class SkColorSpace_Base : public SkColorSpace {
    140 public:
    141 
    142     /**
    143      *  Describes color space gamut as a transformation to XYZ D50.
    144      *  Returns nullptr if color gamut cannot be described in terms of XYZ D50.
    145      */
    146     virtual const SkMatrix44* toXYZD50() const = 0;
    147 
    148     /**
    149      *  Returns a hash of the gamut transofmration to XYZ D50. Allows for fast equality checking
    150      *  of gamuts, at the (very small) risk of collision.
    151      *  Returns 0 if color gamut cannot be described in terms of XYZ D50.
    152      */
    153     virtual uint32_t toXYZD50Hash() const = 0;
    154 
    155     /**
    156      *  Describes color space gamut as a transformation from XYZ D50
    157      *  Returns nullptr if color gamut cannot be described in terms of XYZ D50.
    158      */
    159     virtual const SkMatrix44* fromXYZD50() const = 0;
    160 
    161     virtual bool onGammaCloseToSRGB() const = 0;
    162 
    163     virtual bool onGammaIsLinear() const = 0;
    164 
    165     virtual bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const = 0;
    166 
    167     virtual bool onIsCMYK() const { return false; }
    168 
    169     /**
    170      *  Returns a color space with the same gamut as this one, but with a linear gamma.
    171      *  For color spaces whose gamut can not be described in terms of XYZ D50, returns
    172      *  linear sRGB.
    173      */
    174     virtual sk_sp<SkColorSpace> makeLinearGamma() = 0;
    175 
    176     /**
    177      *  Returns a color space with the same gamut as this one, with with the sRGB transfer
    178      *  function. For color spaces whose gamut can not be described in terms of XYZ D50, returns
    179      *  sRGB.
    180      */
    181     virtual sk_sp<SkColorSpace> makeSRGBGamma() = 0;
    182 
    183     enum class Type : uint8_t {
    184         kXYZ,
    185         kA2B
    186     };
    187 
    188     virtual Type type() const = 0;
    189 
    190     typedef uint8_t ICCTypeFlag;
    191     static constexpr ICCTypeFlag kRGB_ICCTypeFlag  = 1 << 0;
    192     static constexpr ICCTypeFlag kCMYK_ICCTypeFlag = 1 << 1;
    193     static constexpr ICCTypeFlag kGray_ICCTypeFlag = 1 << 2;
    194 
    195     static sk_sp<SkColorSpace> MakeICC(const void* input, size_t len, ICCTypeFlag type);
    196 
    197     static sk_sp<SkColorSpace> MakeRGB(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50);
    198 
    199     enum Named : uint8_t {
    200         kSRGB_Named,
    201         kAdobeRGB_Named,
    202         kSRGBLinear_Named,
    203         kSRGB_NonLinearBlending_Named,
    204     };
    205 
    206     static sk_sp<SkColorSpace> MakeNamed(Named);
    207 
    208 protected:
    209     SkColorSpace_Base(sk_sp<SkData> profileData);
    210 
    211 private:
    212     sk_sp<SkData> fProfileData;
    213 
    214     friend class SkColorSpace;
    215     friend class SkColorSpace_XYZ;
    216     friend class ColorSpaceXformTest;
    217     friend class ColorSpaceTest;
    218     typedef SkColorSpace INHERITED;
    219 };
    220 
    221 static inline SkColorSpace_Base* as_CSB(SkColorSpace* colorSpace) {
    222     return static_cast<SkColorSpace_Base*>(colorSpace);
    223 }
    224 
    225 static inline const SkColorSpace_Base* as_CSB(const SkColorSpace* colorSpace) {
    226     return static_cast<const SkColorSpace_Base*>(colorSpace);
    227 }
    228 
    229 static inline SkColorSpace_Base* as_CSB(const sk_sp<SkColorSpace>& colorSpace) {
    230     return static_cast<SkColorSpace_Base*>(colorSpace.get());
    231 }
    232 
    233 #endif
    234