color_space.h 15 KB

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