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