| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef UI_GFX_COLOR_SPACE_H_ |
| #define UI_GFX_COLOR_SPACE_H_ |
| |
| #include <stdint.h> |
| |
| #include <iosfwd> |
| #include <string> |
| |
| #include "base/gtest_prod_util.h" |
| #include "build/build_config.h" |
| #if !defined(STARBOARD) |
| #include "third_party/skia/include/core/SkRefCnt.h" |
| #endif // !defined(STARBOARD) |
| #include "ui/gfx/color_space_export.h" |
| |
| struct skcms_Matrix3x3; |
| struct skcms_TransferFunction; |
| class SkColorSpace; |
| #if !defined(STARBOARD) |
| enum SkYUVColorSpace : int; |
| #endif // !defined(STARBOARD) |
| |
| namespace skia { |
| class Matrix44; |
| } // namespace skia |
| |
| // These forward declarations are used to give IPC code friend access to private |
| // fields of gfx::ColorSpace for the purpose of serialization and |
| // deserialization. |
| namespace IPC { |
| template <class P> |
| struct ParamTraits; |
| } // namespace IPC |
| |
| namespace mojo { |
| template <class T, class U> |
| struct StructTraits; |
| } // namespace mojo |
| |
| // Used to serialize a gfx::ColorSpace through the GPU command buffer. |
| struct _GLcolorSpace; |
| |
| namespace gfx { |
| |
| enum class ContentColorUsage : uint8_t; |
| |
| namespace mojom { |
| class ColorSpaceDataView; |
| } // namespace mojom |
| |
| // Used to represet a color space for the purpose of color conversion. |
| // This is designed to be safe and compact enough to send over IPC |
| // between any processes. |
| class COLOR_SPACE_EXPORT ColorSpace { |
| public: |
| enum class PrimaryID : uint8_t { |
| INVALID, |
| BT709, |
| BT470M, |
| BT470BG, |
| SMPTE170M, |
| SMPTE240M, |
| FILM, |
| BT2020, |
| SMPTEST428_1, |
| SMPTEST431_2, |
| SMPTEST432_1, |
| XYZ_D50, |
| ADOBE_RGB, |
| // Corresponds the the primaries of the "Generic RGB" profile used in the |
| // Apple ColorSync application, used by layout tests on Mac. |
| APPLE_GENERIC_RGB, |
| // A very wide gamut space with rotated primaries. Used by layout tests. |
| WIDE_GAMUT_COLOR_SPIN, |
| // Primaries defined by the primary matrix |custom_primary_matrix_|. |
| CUSTOM, |
| kMaxValue = CUSTOM, |
| }; |
| |
| enum class TransferID : uint8_t { |
| INVALID, |
| BT709, |
| // On macOS, BT709 hardware decoded video frames, when displayed as |
| // overlays, will have a transfer function of gamma=1.961. |
| BT709_APPLE, |
| GAMMA18, |
| GAMMA22, |
| GAMMA24, |
| GAMMA28, |
| SMPTE170M, |
| SMPTE240M, |
| LINEAR, |
| LOG, |
| LOG_SQRT, |
| IEC61966_2_4, |
| BT1361_ECG, |
| IEC61966_2_1, |
| BT2020_10, |
| BT2020_12, |
| SMPTEST2084, |
| SMPTEST428_1, |
| ARIB_STD_B67, // AKA hybrid-log gamma, HLG. |
| // The same as IEC61966_2_1 on the interval [0, 1], with the nonlinear |
| // segment continuing beyond 1 and point symmetry defining values below 0. |
| IEC61966_2_1_HDR, |
| // The same as LINEAR but is defined for all real values. |
| LINEAR_HDR, |
| // A parametric transfer function defined by |transfer_params_|. |
| CUSTOM, |
| // An HDR parametric transfer function defined by |transfer_params_|. |
| CUSTOM_HDR, |
| // An HDR transfer function that is piecewise sRGB, and piecewise linear. |
| PIECEWISE_HDR, |
| kMaxValue = PIECEWISE_HDR, |
| }; |
| |
| enum class MatrixID : uint8_t { |
| INVALID, |
| RGB, |
| BT709, |
| FCC, |
| BT470BG, |
| SMPTE170M, |
| SMPTE240M, |
| YCOCG, |
| BT2020_NCL, |
| BT2020_CL, |
| YDZDX, |
| GBR, |
| kMaxValue = GBR, |
| }; |
| |
| enum class RangeID : uint8_t { |
| INVALID, |
| // Limited Rec. 709 color range with RGB values ranging from 16 to 235. |
| LIMITED, |
| // Full RGB color range with RGB valees from 0 to 255. |
| FULL, |
| // Range is defined by TransferID/MatrixID. |
| DERIVED, |
| kMaxValue = DERIVED, |
| }; |
| |
| constexpr ColorSpace() {} |
| constexpr ColorSpace(PrimaryID primaries, TransferID transfer) |
| : ColorSpace(primaries, transfer, MatrixID::RGB, RangeID::FULL) {} |
| constexpr ColorSpace(PrimaryID primaries, |
| TransferID transfer, |
| MatrixID matrix, |
| RangeID range) |
| : primaries_(primaries), |
| transfer_(transfer), |
| matrix_(matrix), |
| range_(range) {} |
| ColorSpace(PrimaryID primaries, |
| TransferID transfer, |
| MatrixID matrix, |
| RangeID range, |
| const skcms_Matrix3x3* custom_primary_matrix, |
| const skcms_TransferFunction* cunstom_transfer_fn); |
| |
| explicit ColorSpace(const SkColorSpace& sk_color_space); |
| |
| // Returns true if this is not the default-constructor object. |
| bool IsValid() const; |
| |
| static constexpr ColorSpace CreateSRGB() { |
| return ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1, MatrixID::RGB, |
| RangeID::FULL); |
| } |
| |
| static constexpr ColorSpace CreateDisplayP3D65() { |
| return ColorSpace(PrimaryID::SMPTEST432_1, TransferID::IEC61966_2_1, |
| MatrixID::RGB, RangeID::FULL); |
| } |
| static ColorSpace CreateCustom(const skcms_Matrix3x3& to_XYZD50, |
| const skcms_TransferFunction& fn); |
| static ColorSpace CreateCustom(const skcms_Matrix3x3& to_XYZD50, |
| TransferID transfer); |
| static constexpr ColorSpace CreateXYZD50() { |
| return ColorSpace(PrimaryID::XYZ_D50, TransferID::LINEAR, MatrixID::RGB, |
| RangeID::FULL); |
| } |
| |
| // Extended sRGB matches sRGB for values in [0, 1], and extends the transfer |
| // function to all real values. |
| static constexpr ColorSpace CreateExtendedSRGB() { |
| return ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1_HDR, |
| MatrixID::RGB, RangeID::FULL); |
| } |
| |
| // scRGB uses the same primaries as sRGB but has a linear transfer function |
| // for all real values, and a white point of kDefaultScrgbLinearSdrWhiteLevel. |
| static constexpr ColorSpace CreateSCRGBLinear() { |
| return ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR, MatrixID::RGB, |
| RangeID::FULL); |
| } |
| // Allows specifying a custom SDR white level. Only used on Windows. |
| static ColorSpace CreateSCRGBLinear(float sdr_white_level); |
| |
| // HDR10 uses BT.2020 primaries with SMPTE ST 2084 PQ transfer function. |
| static constexpr ColorSpace CreateHDR10() { |
| return ColorSpace(PrimaryID::BT2020, TransferID::SMPTEST2084, MatrixID::RGB, |
| RangeID::FULL); |
| } |
| // Allows specifying a custom SDR white level. Only used on Windows. |
| static ColorSpace CreateHDR10(float sdr_white_level); |
| |
| // HLG uses the BT.2020 primaries with the ARIB_STD_B67 transfer function. |
| static ColorSpace CreateHLG(); |
| |
| // Create a piecewise-HDR color space. |
| // - If |primaries| is CUSTOM, then |custom_primary_matrix| must be |
| // non-nullptr. |
| // - The SDR joint is the encoded pixel value where the SDR portion reaches 1, |
| // usually 0.25 or 0.5, corresponding to giving 8 or 9 of 10 bits to SDR. |
| // This must be in the open interval (0, 1). |
| // - The HDR level the value that the transfer function will evaluate to at 1, |
| // and represents the maximum HDR brightness relative to the maximum SDR |
| // brightness. This must be strictly greater than 1. |
| static ColorSpace CreatePiecewiseHDR( |
| PrimaryID primaries, |
| float sdr_joint, |
| float hdr_level, |
| const skcms_Matrix3x3* custom_primary_matrix = nullptr); |
| |
| // TODO(ccameron): Remove these, and replace with more generic constructors. |
| static constexpr ColorSpace CreateJpeg() { |
| // TODO(ccameron): Determine which primaries and transfer function were |
| // intended here. |
| return ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1, |
| MatrixID::SMPTE170M, RangeID::FULL); |
| } |
| static constexpr ColorSpace CreateREC601() { |
| return ColorSpace(PrimaryID::SMPTE170M, TransferID::SMPTE170M, |
| MatrixID::SMPTE170M, RangeID::LIMITED); |
| } |
| static constexpr ColorSpace CreateREC709() { |
| return ColorSpace(PrimaryID::BT709, TransferID::BT709, MatrixID::BT709, |
| RangeID::LIMITED); |
| } |
| |
| // On macOS and on ChromeOS, sRGB's (1,1,1) always coincides with PQ's 100 |
| // nits (which may not be 100 physical nits). On Windows, sRGB's (1,1,1) |
| // maps to scRGB linear's (1,1,1) when the SDR white level is set to 80 nits. |
| // See also kDefaultScrgbLinearSdrWhiteLevel. |
| static constexpr float kDefaultSDRWhiteLevel = 100.f; |
| |
| // The default white level in nits for scRGB linear color space. On Windows, |
| // sRGB's (1,1,1) maps to scRGB linear's (1,1,1) when the SDR white level is |
| // set to 80 nits. On Mac and ChromeOS, sRGB's (1,1,1) maps to PQ's 100 nits. |
| // Using a platform specific value here satisfies both constraints. |
| #if defined(OS_WIN) |
| static constexpr float kDefaultScrgbLinearSdrWhiteLevel = 80.0f; |
| #else |
| static constexpr float kDefaultScrgbLinearSdrWhiteLevel = |
| kDefaultSDRWhiteLevel; |
| #endif // OS_WIN |
| |
| bool operator==(const ColorSpace& other) const; |
| bool operator!=(const ColorSpace& other) const; |
| bool operator<(const ColorSpace& other) const; |
| size_t GetHash() const; |
| std::string ToString() const { |
| // TODO: Refine ColorSpace::ToString(). |
| return ""; |
| } |
| |
| bool IsWide() const; |
| |
| // Returns true if the transfer function is an HDR one (SMPTE 2084, HLG, etc). |
| bool IsHDR() const { |
| // TODO: Refine ColorSpace::IsHDR(). |
| return false; |
| } |
| |
| // Returns true if the encoded values can be outside of the 0.0-1.0 range. |
| bool FullRangeEncodedValues() const; |
| |
| // Returns the color space's content color usage category (sRGB, WCG, or HDR). |
| ContentColorUsage GetContentColorUsage() const; |
| |
| // Return this color space with any YUV to RGB conversion stripped off. |
| ColorSpace GetAsRGB() const; |
| |
| // Return this color space with any range adjust or YUV to RGB conversion |
| // stripped off. |
| ColorSpace GetAsFullRangeRGB() const; |
| |
| // Return a color space where all values are bigger/smaller by the given |
| // factor. If you convert colors from SRGB to SRGB.GetScaledColorSpace(2.0) |
| // everything will be half as bright in linear lumens. |
| ColorSpace GetScaledColorSpace(float factor) const; |
| |
| // Return true if blending in |this| is close enough to blending in sRGB to |
| // be considered acceptable (only PQ and nearly-linear transfer functions |
| // return false). |
| bool IsSuitableForBlending() const; |
| |
| // Return a combined color space with has the same primary and transfer than |
| // the caller but replacing the matrix and range with the given values. |
| ColorSpace GetWithMatrixAndRange(MatrixID matrix, RangeID range) const; |
| |
| // If this color space has a PQ or scRGB linear transfer function, then return |
| // |this| with its SDR white level set to |sdr_white_level|. Otherwise return |
| // |this| unmodified. |
| ColorSpace GetWithSDRWhiteLevel(float sdr_white_level) const; |
| |
| #if !defined(STARBOARD) |
| // This will return nullptr for non-RGB spaces, spaces with non-FULL |
| // range, and unspecified spaces. |
| sk_sp<SkColorSpace> ToSkColorSpace() const; |
| #endif // !defined(STARBOARD) |
| |
| // Return a GLcolorSpace value that is valid for the lifetime of |this|. This |
| // function is used to serialize ColorSpace objects across the GPU command |
| // buffer. |
| const _GLcolorSpace* AsGLColorSpace() const; |
| |
| #if !defined(STARBOARD) |
| // For YUV color spaces, return the closest SkYUVColorSpace. Returns true if a |
| // close match is found. Otherwise, leaves *out unchanged and returns false. |
| // If |matrix_id| is MatrixID::BT2020_NCL and |bit_depth| is provided, a bit |
| // depth appropriate SkYUVColorSpace will be provided. |
| bool ToSkYUVColorSpace(int bit_depth, SkYUVColorSpace* out) const; |
| bool ToSkYUVColorSpace(SkYUVColorSpace* out) const { |
| return ToSkYUVColorSpace(kDefaultBitDepth, out); |
| } |
| #endif // !defined(STARBOARD) |
| |
| void GetPrimaryMatrix(skcms_Matrix3x3* to_XYZD50) const; |
| void GetPrimaryMatrix(skia::Matrix44* to_XYZD50) const; |
| bool GetTransferFunction(skcms_TransferFunction* fn) const; |
| bool GetInverseTransferFunction(skcms_TransferFunction* fn) const; |
| |
| // Returns the SDR white level specified for the PQ or HLG transfer functions. |
| // If no value was specified, then use kDefaultSDRWhiteLevel. If the transfer |
| // function is not PQ then return false. |
| bool GetSDRWhiteLevel(float* sdr_white_level) const; |
| |
| // Returns the parameters for a PIECEWISE_HDR transfer function. See |
| // CreatePiecewiseHDR for parameter meanings. |
| bool GetPiecewiseHDRParams(float* sdr_point, float* hdr_level) const; |
| |
| // Returns the transfer matrix for |bit_depth|. For most formats, this is the |
| // RGB to YUV matrix. |
| void GetTransferMatrix(int bit_depth, skia::Matrix44* matrix) const; |
| |
| // Returns the range adjust matrix that converts from |range_| to full range |
| // for |bit_depth|. |
| void GetRangeAdjustMatrix(int bit_depth, skia::Matrix44* matrix) const; |
| |
| // Returns the current primary ID. |
| // Note: if SetCustomPrimaries() has been used, the primary ID returned |
| // may have been set to PrimaryID::CUSTOM, or been coerced to another |
| // PrimaryID if it was very close. |
| PrimaryID GetPrimaryID() const; |
| |
| // Returns the current transfer ID. |
| TransferID GetTransferID() const; |
| |
| // Returns the current matrix ID. |
| MatrixID GetMatrixID() const; |
| |
| // Returns the current range ID. |
| RangeID GetRangeID() const; |
| |
| // Returns true if the transfer function is defined by an |
| // skcms_TransferFunction which is extended to all real values. |
| bool HasExtendedSkTransferFn() const; |
| |
| // Returns true if each color in |other| can be expressed in this color space. |
| bool Contains(const ColorSpace& other) const; |
| |
| private: |
| // The default bit depth assumed by ToSkYUVColorSpace(). |
| static constexpr int kDefaultBitDepth = 8; |
| |
| static void GetPrimaryMatrix(PrimaryID, skcms_Matrix3x3* to_XYZD50); |
| static bool GetTransferFunction(TransferID, skcms_TransferFunction* fn); |
| static size_t TransferParamCount(TransferID); |
| |
| void SetCustomTransferFunction(const skcms_TransferFunction& fn); |
| void SetCustomPrimaries(const skcms_Matrix3x3& to_XYZD50); |
| |
| PrimaryID primaries_ = PrimaryID::INVALID; |
| TransferID transfer_ = TransferID::INVALID; |
| MatrixID matrix_ = MatrixID::INVALID; |
| RangeID range_ = RangeID::INVALID; |
| |
| // Only used if primaries_ is PrimaryID::CUSTOM. |
| float custom_primary_matrix_[9] = {0, 0, 0, 0, 0, 0, 0, 0}; |
| |
| // Parameters for the transfer function. The interpretation depends on |
| // |transfer_|. Only TransferParamCount() of these parameters are used, all |
| // others must be zero. |
| // - CUSTOM and CUSTOM_HDR: Entries A through G of the skcms_TransferFunction |
| // structure in alphabetical order. |
| // - SMPTEST2084: SDR white point. |
| float transfer_params_[7] = {0, 0, 0, 0, 0, 0, 0}; |
| |
| friend struct IPC::ParamTraits<gfx::ColorSpace>; |
| friend struct mojo::StructTraits<gfx::mojom::ColorSpaceDataView, |
| gfx::ColorSpace>; |
| }; |
| |
| // Stream operator so ColorSpace can be used in assertion statements. |
| COLOR_SPACE_EXPORT std::ostream& operator<<(std::ostream& out, |
| const ColorSpace& color_space); |
| |
| } // namespace gfx |
| |
| #endif // UI_GFX_COLOR_SPACE_H_ |