Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2017 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 SkImageInfoPriv_DEFINED
      9 #define SkImageInfoPriv_DEFINED
     10 
     11 #include "SkImageInfo.h"
     12 
     13 enum class SkDestinationSurfaceColorMode {
     14     kLegacy,
     15     kGammaAndColorSpaceAware,
     16 };
     17 
     18 static inline bool SkAlphaTypeIsValid(unsigned value) {
     19     return value <= kLastEnum_SkAlphaType;
     20 }
     21 
     22 static int SkColorTypeShiftPerPixel(SkColorType ct) {
     23     switch (ct) {
     24         case kUnknown_SkColorType:      return 0;
     25         case kAlpha_8_SkColorType:      return 0;
     26         case kRGB_565_SkColorType:      return 1;
     27         case kARGB_4444_SkColorType:    return 1;
     28         case kRGBA_8888_SkColorType:    return 2;
     29         case kRGB_888x_SkColorType:     return 2;
     30         case kBGRA_8888_SkColorType:    return 2;
     31         case kRGBA_1010102_SkColorType: return 2;
     32         case kRGB_101010x_SkColorType:  return 2;
     33         case kGray_8_SkColorType:       return 0;
     34         case kRGBA_F16_SkColorType:     return 3;
     35     }
     36     return 0;
     37 }
     38 
     39 static inline size_t SkColorTypeMinRowBytes(SkColorType ct, int width) {
     40     return width * SkColorTypeBytesPerPixel(ct);
     41 }
     42 
     43 static inline bool SkColorTypeIsValid(unsigned value) {
     44     return value <= kLastEnum_SkColorType;
     45 }
     46 
     47 static inline size_t SkColorTypeComputeOffset(SkColorType ct, int x, int y, size_t rowBytes) {
     48     if (kUnknown_SkColorType == ct) {
     49         return 0;
     50     }
     51     return y * rowBytes + (x << SkColorTypeShiftPerPixel(ct));
     52 }
     53 
     54 /**
     55  *  This contains shared checks on SkImageInfo.  Depending on the desired color space behavior,
     56  *  the caller should choose one of the two versions below.
     57  */
     58 static inline bool SkImageInfoIsValidCommon(const SkImageInfo& info) {
     59     if (info.width() <= 0 || info.height() <= 0) {
     60         return false;
     61     }
     62 
     63     const int kMaxDimension = SK_MaxS32 >> 2;
     64     if (info.width() > kMaxDimension || info.height() > kMaxDimension) {
     65         return false;
     66     }
     67 
     68     if (kUnknown_SkColorType == info.colorType() || kUnknown_SkAlphaType == info.alphaType()) {
     69         return false;
     70     }
     71 
     72     if (kOpaque_SkAlphaType != info.alphaType() &&
     73        (kRGB_565_SkColorType == info.colorType() || kGray_8_SkColorType == info.colorType())) {
     74         return false;
     75     }
     76 
     77     if (kRGBA_F16_SkColorType == info.colorType() &&
     78        (info.colorSpace() && (!info.colorSpace()->gammaIsLinear()))) {
     79         return false;
     80     }
     81 
     82     return true;
     83 }
     84 
     85 /**
     86  *  Returns true if |info| contains a valid combination of width, height, colorType, alphaType,
     87  *  colorSpace.  Allows numerical color spaces.  Returns false otherwise.
     88  */
     89 static inline bool SkImageInfoIsValidAllowNumericalCS(const SkImageInfo& info) {
     90     if (!SkImageInfoIsValidCommon(info)) {
     91         return false;
     92     }
     93 
     94     SkColorSpaceTransferFn fn;
     95     if (info.colorSpace() && !info.colorSpace()->isNumericalTransferFn(&fn)) {
     96         return false;
     97     }
     98 
     99     return true;
    100 }
    101 
    102 /**
    103  *  Returns true if |info| contains a valid combination of width, height, colorType, alphaType,
    104  *  colorSpace.  Only supports rendering color spaces.  Returns false otherwise.
    105  */
    106 static inline bool SkImageInfoIsValidRenderingCS(const SkImageInfo& info) {
    107     if (!SkImageInfoIsValidCommon(info)) {
    108         return false;
    109     }
    110 
    111     if (info.colorSpace() &&
    112        (!info.colorSpace()->gammaCloseToSRGB() && !info.colorSpace()->gammaIsLinear())) {
    113         return false;
    114     }
    115 
    116     return true;
    117 }
    118 
    119 /**
    120  *  Returns true if |info| contains a valid combination of width, height, colorType, alphaType,
    121  *  colorSpace.  Uses |colorMode| to decide how to treat color spaces.
    122  */
    123 static inline bool SkImageInfoIsValid(const SkImageInfo& info,
    124                                       SkDestinationSurfaceColorMode colorMode) {
    125     if (SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware == colorMode) {
    126         return SkImageInfoIsValidRenderingCS(info);
    127     }
    128 
    129     return SkImageInfoIsValidAllowNumericalCS(info);
    130 }
    131 
    132 /**
    133  *  Returns true if Skia has defined a pixel conversion from the |src| to the |dst|.
    134  *  Returns false otherwise.  Some discussion of false cases:
    135  *      We will not convert to kIndex8 unless it exactly matches the src, since color tables
    136  *      are immutable.
    137  *      We do not convert to kGray8 when the |src| is not kGray8 in the same color space.
    138  *      We may add this feature - it just requires some work to convert to luminance while
    139  *      handling color spaces correctly.  Currently no one is asking for this.
    140  *      We will not convert from kAlpha8 when the |dst| is not kAlpha8.  This would require
    141  *      inventing color information.
    142  *      We will not convert to kOpaque when the |src| is not kOpaque.  This could be
    143  *      implemented to set all the alpha values to 1, but there is still some ambiguity -
    144  *      should we use kPremul or kUnpremul color values with the opaque alphas?  Or should
    145  *      we just use whatever the |src| alpha is?  In the future, we could choose to clearly
    146  *      define this, but currently no one is asking for this feature.
    147  *      We will not convert to a particular color space if |src| is nullptr.  The color space
    148  *      conversion is not well-defined.
    149  */
    150 static inline bool SkImageInfoValidConversion(const SkImageInfo& dst, const SkImageInfo& src) {
    151     if (!SkImageInfoIsValidAllowNumericalCS(dst) || !SkImageInfoIsValidAllowNumericalCS(src)) {
    152         return false;
    153     }
    154 
    155     if (kGray_8_SkColorType == dst.colorType()) {
    156         if (kGray_8_SkColorType != src.colorType()) {
    157             return false;
    158         }
    159 
    160         if (dst.colorSpace() && !SkColorSpace::Equals(dst.colorSpace(), src.colorSpace())) {
    161             return false;
    162         }
    163     }
    164 
    165     if (kAlpha_8_SkColorType != dst.colorType() && kAlpha_8_SkColorType == src.colorType()) {
    166         return false;
    167     }
    168 
    169     if (kOpaque_SkAlphaType == dst.alphaType() && kOpaque_SkAlphaType != src.alphaType()) {
    170         return false;
    171     }
    172 
    173     if (dst.colorSpace() && !src.colorSpace()) {
    174         return false;
    175     }
    176 
    177     return true;
    178 }
    179 #endif  // SkImageInfoPriv_DEFINED
    180