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