1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef UI_GFX_COLOR_SPACE_H_ 6 #define UI_GFX_COLOR_SPACE_H_ 7 8 #include <stdint.h> 9 10 #include <ostream> 11 #include <string> 12 #include <vector> 13 14 #include "base/gtest_prod_util.h" 15 #include "base/macros.h" 16 #include "build/build_config.h" 17 #include "third_party/skia/include/core/SkColorSpace.h" 18 #include "third_party/skia/include/core/SkImageInfo.h" 19 #include "third_party/skia/include/core/SkMatrix44.h" 20 #include "ui/gfx/color_space_export.h" 21 22 // These forward declarations are used to give IPC code friend access to private 23 // fields of gfx::ColorSpace for the purpose of serialization and 24 // deserialization. 25 namespace IPC { 26 template <class P> 27 struct ParamTraits; 28 } // namespace IPC 29 30 namespace mojo { 31 template <class T, class U> 32 struct StructTraits; 33 } // namespace mojo 34 35 // Used to serialize a gfx::ColorSpace through the GPU command buffer. 36 struct _GLcolorSpace; 37 38 namespace gfx { 39 40 enum class ContentColorUsage : uint8_t; 41 42 namespace mojom { 43 class ColorSpaceDataView; 44 } // namespace mojom 45 46 // Used to represet a color space for the purpose of color conversion. 47 // This is designed to be safe and compact enough to send over IPC 48 // between any processes. 49 class COLOR_SPACE_EXPORT ColorSpace { 50 public: 51 enum class PrimaryID : uint8_t { 52 INVALID, 53 BT709, 54 BT470M, 55 BT470BG, 56 SMPTE170M, 57 SMPTE240M, 58 FILM, 59 BT2020, 60 SMPTEST428_1, 61 SMPTEST431_2, 62 SMPTEST432_1, 63 XYZ_D50, 64 ADOBE_RGB, 65 // Corresponds the the primaries of the "Generic RGB" profile used in the 66 // Apple ColorSync application, used by layout tests on Mac. 67 APPLE_GENERIC_RGB, 68 // A very wide gamut space with rotated primaries. Used by layout tests. 69 WIDE_GAMUT_COLOR_SPIN, 70 // Primaries defined by the primary matrix |custom_primary_matrix_|. 71 CUSTOM, 72 kMaxValue = CUSTOM, 73 }; 74 75 enum class TransferID : uint8_t { 76 INVALID, 77 BT709, 78 // On macOS, BT709 hardware decoded video frames, when displayed as 79 // overlays, will have a transfer function of gamma=1.961. 80 BT709_APPLE, 81 GAMMA18, 82 GAMMA22, 83 GAMMA24, 84 GAMMA28, 85 SMPTE170M, 86 SMPTE240M, 87 LINEAR, 88 LOG, 89 LOG_SQRT, 90 IEC61966_2_4, 91 BT1361_ECG, 92 IEC61966_2_1, 93 BT2020_10, 94 BT2020_12, 95 SMPTEST2084, 96 SMPTEST428_1, 97 ARIB_STD_B67, // AKA hybrid-log gamma, HLG. 98 // The same as IEC61966_2_1 on the interval [0, 1], with the nonlinear 99 // segment continuing beyond 1 and point symmetry defining values below 0. 100 IEC61966_2_1_HDR, 101 // The same as LINEAR but is defined for all real values. 102 LINEAR_HDR, 103 // A parametric transfer function defined by |transfer_params_|. 104 CUSTOM, 105 // An HDR parametric transfer function defined by |transfer_params_|. 106 CUSTOM_HDR, 107 // An HDR transfer function that is piecewise sRGB, and piecewise linear. 108 PIECEWISE_HDR, 109 kMaxValue = PIECEWISE_HDR, 110 }; 111 112 enum class MatrixID : uint8_t { 113 INVALID, 114 RGB, 115 BT709, 116 FCC, 117 BT470BG, 118 SMPTE170M, 119 SMPTE240M, 120 YCOCG, 121 BT2020_NCL, 122 BT2020_CL, 123 YDZDX, 124 GBR, 125 kMaxValue = GBR, 126 }; 127 128 enum class RangeID : uint8_t { 129 INVALID, 130 // Limited Rec. 709 color range with RGB values ranging from 16 to 235. 131 LIMITED, 132 // Full RGB color range with RGB valees from 0 to 255. 133 FULL, 134 // Range is defined by TransferID/MatrixID. 135 DERIVED, 136 kMaxValue = DERIVED, 137 }; 138 ColorSpace()139 constexpr ColorSpace() {} ColorSpace(PrimaryID primaries,TransferID transfer)140 constexpr ColorSpace(PrimaryID primaries, TransferID transfer) 141 : ColorSpace(primaries, transfer, MatrixID::RGB, RangeID::FULL) {} ColorSpace(PrimaryID primaries,TransferID transfer,MatrixID matrix,RangeID range)142 constexpr ColorSpace(PrimaryID primaries, 143 TransferID transfer, 144 MatrixID matrix, 145 RangeID range) 146 : primaries_(primaries), 147 transfer_(transfer), 148 matrix_(matrix), 149 range_(range) {} 150 ColorSpace(PrimaryID primaries, 151 TransferID transfer, 152 MatrixID matrix, 153 RangeID range, 154 const skcms_Matrix3x3* custom_primary_matrix, 155 const skcms_TransferFunction* cunstom_transfer_fn); 156 157 explicit ColorSpace(const SkColorSpace& sk_color_space); 158 159 // Returns true if this is not the default-constructor object. 160 bool IsValid() const; 161 CreateSRGB()162 static constexpr ColorSpace CreateSRGB() { 163 return ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1, MatrixID::RGB, 164 RangeID::FULL); 165 } 166 CreateDisplayP3D65()167 static constexpr ColorSpace CreateDisplayP3D65() { 168 return ColorSpace(PrimaryID::SMPTEST432_1, TransferID::IEC61966_2_1, 169 MatrixID::RGB, RangeID::FULL); 170 } 171 static ColorSpace CreateCustom(const skcms_Matrix3x3& to_XYZD50, 172 const skcms_TransferFunction& fn); 173 static ColorSpace CreateCustom(const skcms_Matrix3x3& to_XYZD50, 174 TransferID transfer); CreateXYZD50()175 static constexpr ColorSpace CreateXYZD50() { 176 return ColorSpace(PrimaryID::XYZ_D50, TransferID::LINEAR, MatrixID::RGB, 177 RangeID::FULL); 178 } 179 180 // Extended sRGB matches sRGB for values in [0, 1], and extends the transfer 181 // function to all real values. CreateExtendedSRGB()182 static constexpr ColorSpace CreateExtendedSRGB() { 183 return ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1_HDR, 184 MatrixID::RGB, RangeID::FULL); 185 } 186 187 // scRGB uses the same primaries as sRGB but has a linear transfer function 188 // for all real values. The slope of the transfer function may be specified 189 // by |slope|. 190 static ColorSpace CreateSCRGBLinear(float slope = 1.f); 191 192 // HDR10 uses BT.2020 primaries with SMPTE ST 2084 PQ transfer function. 193 static ColorSpace CreateHDR10(float sdr_white_point = 0.f); 194 195 // Create a piecewise-HDR color space. 196 // - If |primaries| is CUSTOM, then |custom_primary_matrix| must be 197 // non-nullptr. 198 // - The SDR joint is the encoded pixel value where the SDR portion reaches 1, 199 // usually 0.25 or 0.5, corresponding to giving 8 or 9 of 10 bits to SDR. 200 // This must be in the open interval (0, 1). 201 // - The HDR level the value that the transfer function will evaluate to at 1, 202 // and represents the maximum HDR brightness relative to the maximum SDR 203 // brightness. This must be strictly greater than 1. 204 static ColorSpace CreatePiecewiseHDR( 205 PrimaryID primaries, 206 float sdr_joint, 207 float hdr_level, 208 const skcms_Matrix3x3* custom_primary_matrix = nullptr); 209 210 // TODO(ccameron): Remove these, and replace with more generic constructors. CreateJpeg()211 static constexpr ColorSpace CreateJpeg() { 212 // TODO(ccameron): Determine which primaries and transfer function were 213 // intended here. 214 return ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1, 215 MatrixID::SMPTE170M, RangeID::FULL); 216 } CreateREC601()217 static constexpr ColorSpace CreateREC601() { 218 return ColorSpace(PrimaryID::SMPTE170M, TransferID::SMPTE170M, 219 MatrixID::SMPTE170M, RangeID::LIMITED); 220 } CreateREC709()221 static constexpr ColorSpace CreateREC709() { 222 return ColorSpace(PrimaryID::BT709, TransferID::BT709, MatrixID::BT709, 223 RangeID::LIMITED); 224 } 225 226 // On macOS and on ChromeOS, sRGB's (1,1,1) always coincides with PQ's 100 227 // nits (which may not be 100 physical nits). Life is more complicated on 228 // Windows. 229 static constexpr float kDefaultSDRWhiteLevel = 100.f; 230 231 bool operator==(const ColorSpace& other) const; 232 bool operator!=(const ColorSpace& other) const; 233 bool operator<(const ColorSpace& other) const; 234 size_t GetHash() const; 235 std::string ToString() const; 236 237 bool IsWide() const; 238 239 // Returns true if the transfer function is an HDR one (SMPTE 2084, HLG, etc). 240 bool IsHDR() const; 241 242 // Returns true if the encoded values can be outside of the 0.0-1.0 range. 243 bool FullRangeEncodedValues() const; 244 245 // Returns the color space's content color usage category (sRGB, WCG, or HDR). 246 ContentColorUsage GetContentColorUsage() const; 247 248 // Return this color space with any YUV to RGB conversion stripped off. 249 ColorSpace GetAsRGB() const; 250 251 // Return this color space with any range adjust or YUV to RGB conversion 252 // stripped off. 253 ColorSpace GetAsFullRangeRGB() const; 254 255 // Return a color space where all values are bigger/smaller by the given 256 // factor. If you convert colors from SRGB to SRGB.GetScaledColorSpace(2.0) 257 // everything will be half as bright in linear lumens. 258 ColorSpace GetScaledColorSpace(float factor) const; 259 260 // If |this| is the final output color space, return the color space that 261 // would be appropriate for rasterization. 262 ColorSpace GetRasterColorSpace() const; 263 264 // Return true if blending in |this| is close enough to blending in sRGB to 265 // be considered acceptable (only PQ and nearly-linear transfer functions 266 // return false). 267 bool IsSuitableForBlending() const; 268 269 // Return a combined color space with has the same primary and transfer than 270 // the caller but replacing the matrix and range with the given values. 271 ColorSpace GetWithMatrixAndRange(MatrixID matrix, RangeID range) const; 272 273 // If this color space has a PQ transfer function that did not specify an 274 // SDR white level, then return |this| with its SDR white level set to 275 // |sdr_white_level|. Otherwise return |this| unmodified. 276 ColorSpace GetWithPQSDRWhiteLevel(float sdr_white_level) const; 277 278 // This will return nullptr for non-RGB spaces, spaces with non-FULL 279 // range, and unspecified spaces. 280 sk_sp<SkColorSpace> ToSkColorSpace() const; 281 282 // Return a GLcolorSpace value that is valid for the lifetime of |this|. This 283 // function is used to serialize ColorSpace objects across the GPU command 284 // buffer. 285 const _GLcolorSpace* AsGLColorSpace() const; 286 287 // For YUV color spaces, return the closest SkYUVColorSpace. 288 // Returns true if a close match is found. 289 bool ToSkYUVColorSpace(SkYUVColorSpace* out) const; 290 291 void GetPrimaryMatrix(skcms_Matrix3x3* to_XYZD50) const; 292 void GetPrimaryMatrix(SkMatrix44* to_XYZD50) const; 293 bool GetTransferFunction(skcms_TransferFunction* fn) const; 294 bool GetInverseTransferFunction(skcms_TransferFunction* fn) const; 295 296 // Returns the SDR white level specified for the PQ transfer function. If 297 // no value was specified, then use kDefaultSDRWhiteLevel. If the transfer 298 // function is not PQ then return false. 299 bool GetPQSDRWhiteLevel(float* sdr_white_level) const; 300 301 // Returns the parameters for a PIECEWISE_HDR transfer function. See 302 // CreatePiecewiseHDR for parameter meanings. 303 bool GetPiecewiseHDRParams(float* sdr_point, float* hdr_level) const; 304 305 // For most formats, this is the RGB to YUV matrix. 306 void GetTransferMatrix(SkMatrix44* matrix) const; 307 void GetRangeAdjustMatrix(SkMatrix44* matrix) const; 308 309 // Returns the current primary ID. 310 // Note: if SetCustomPrimaries() has been used, the primary ID returned 311 // may have been set to PrimaryID::CUSTOM, or been coerced to another 312 // PrimaryID if it was very close. 313 PrimaryID GetPrimaryID() const; 314 315 // Returns the current transfer ID. 316 TransferID GetTransferID() const; 317 318 // Returns the current matrix ID. 319 MatrixID GetMatrixID() const; 320 321 // Returns the current range ID. 322 RangeID GetRangeID() const; 323 324 // Returns true if the transfer function is defined by an 325 // skcms_TransferFunction which is extended to all real values. 326 bool HasExtendedSkTransferFn() const; 327 328 private: 329 static void GetPrimaryMatrix(PrimaryID, skcms_Matrix3x3* to_XYZD50); 330 static bool GetTransferFunction(TransferID, skcms_TransferFunction* fn); 331 static size_t TransferParamCount(TransferID); 332 333 void GetPQTransferFunction(skcms_TransferFunction* fn) const; 334 335 void SetCustomTransferFunction(const skcms_TransferFunction& fn); 336 void SetCustomPrimaries(const skcms_Matrix3x3& to_XYZD50); 337 338 PrimaryID primaries_ = PrimaryID::INVALID; 339 TransferID transfer_ = TransferID::INVALID; 340 MatrixID matrix_ = MatrixID::INVALID; 341 RangeID range_ = RangeID::INVALID; 342 343 // Only used if primaries_ is PrimaryID::CUSTOM. 344 float custom_primary_matrix_[9] = {0, 0, 0, 0, 0, 0, 0, 0}; 345 346 // Parameters for the transfer function. The interpretation depends on 347 // |transfer_|. Only TransferParamCount() of these parameters are used, all 348 // others must be zero. 349 // - CUSTOM and CUSTOM_HDR: Entries A through G of the skcms_TransferFunction 350 // structure in alphabetical order. 351 // - SMPTEST2084: SDR white point. 352 float transfer_params_[7] = {0, 0, 0, 0, 0, 0, 0}; 353 354 friend struct IPC::ParamTraits<gfx::ColorSpace>; 355 friend struct mojo::StructTraits<gfx::mojom::ColorSpaceDataView, 356 gfx::ColorSpace>; 357 }; 358 359 // Stream operator so ColorSpace can be used in assertion statements. 360 COLOR_SPACE_EXPORT std::ostream& operator<<(std::ostream& out, 361 const ColorSpace& color_space); 362 363 } // namespace gfx 364 365 #endif // UI_GFX_COLOR_SPACE_H_ 366