OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/gfx/color_space.h" | 5 #include "ui/gfx/color_space.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 | 8 |
9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
10 #include "base/synchronization/lock.h" | 10 #include "base/synchronization/lock.h" |
11 #include "third_party/skia/include/core/SkColorSpace.h" | 11 #include "third_party/skia/include/core/SkColorSpace.h" |
12 #include "ui/gfx/icc_profile.h" | 12 #include "ui/gfx/icc_profile.h" |
13 | 13 |
14 namespace gfx { | 14 namespace gfx { |
15 | 15 |
16 namespace { | |
17 | |
18 SkColorSpaceTransferFn InvertTransferFn(SkColorSpaceTransferFn fn) { | |
19 SkColorSpaceTransferFn fn_inv = {0}; | |
20 if (fn.fA > 0 && fn.fG > 0) { | |
21 double a_to_the_g = pow(fn.fA, fn.fG); | |
22 fn_inv.fA = 1.f / a_to_the_g; | |
23 fn_inv.fB = -fn.fE / a_to_the_g; | |
24 fn_inv.fG = 1.f / fn.fG; | |
25 } | |
26 fn_inv.fD = fn.fC * fn.fD + fn.fF; | |
27 fn_inv.fE = -fn.fB / fn.fA; | |
28 if (fn.fC != 0) { | |
29 fn_inv.fC = 1.f / fn.fC; | |
30 fn_inv.fF = -fn.fF / fn.fC; | |
31 } | |
32 return fn_inv; | |
33 } | |
34 }; | |
35 | |
36 ColorSpace::PrimaryID ColorSpace::PrimaryIDFromInt(int primary_id) { | 16 ColorSpace::PrimaryID ColorSpace::PrimaryIDFromInt(int primary_id) { |
37 if (primary_id < 0 || primary_id > static_cast<int>(PrimaryID::LAST)) | 17 if (primary_id < 0 || primary_id > static_cast<int>(PrimaryID::LAST)) |
38 return PrimaryID::UNKNOWN; | 18 return PrimaryID::UNKNOWN; |
39 if (primary_id > static_cast<int>(PrimaryID::LAST_STANDARD_VALUE) && | 19 if (primary_id > static_cast<int>(PrimaryID::LAST_STANDARD_VALUE) && |
40 primary_id < 1000) | 20 primary_id < 1000) |
41 return PrimaryID::UNKNOWN; | 21 return PrimaryID::UNKNOWN; |
42 return static_cast<PrimaryID>(primary_id); | 22 return static_cast<PrimaryID>(primary_id); |
43 } | 23 } |
44 | 24 |
45 ColorSpace::TransferID ColorSpace::TransferIDFromInt(int transfer_id) { | 25 ColorSpace::TransferID ColorSpace::TransferIDFromInt(int transfer_id) { |
46 if (transfer_id < 0 || transfer_id > static_cast<int>(TransferID::LAST)) | 26 if (transfer_id < 0 || transfer_id > static_cast<int>(TransferID::LAST)) |
47 return TransferID::UNKNOWN; | 27 return TransferID::UNKNOWN; |
48 if (transfer_id > static_cast<int>(TransferID::LAST_STANDARD_VALUE) && | 28 if (transfer_id > static_cast<int>(TransferID::LAST_STANDARD_VALUE) && |
49 transfer_id < 1000) | 29 transfer_id < 1000) |
50 return TransferID::UNKNOWN; | 30 return TransferID::UNKNOWN; |
51 return static_cast<TransferID>(transfer_id); | 31 return static_cast<TransferID>(transfer_id); |
52 } | 32 } |
53 | 33 |
54 ColorSpace::MatrixID ColorSpace::MatrixIDFromInt(int matrix_id) { | 34 ColorSpace::MatrixID ColorSpace::MatrixIDFromInt(int matrix_id) { |
55 if (matrix_id < 0 || matrix_id > static_cast<int>(MatrixID::LAST)) | 35 if (matrix_id < 0 || matrix_id > static_cast<int>(MatrixID::LAST)) |
56 return MatrixID::UNKNOWN; | 36 return MatrixID::UNKNOWN; |
57 if (matrix_id > static_cast<int>(MatrixID::LAST_STANDARD_VALUE) && | 37 if (matrix_id > static_cast<int>(MatrixID::LAST_STANDARD_VALUE) && |
58 matrix_id < 1000) | 38 matrix_id < 1000) |
59 return MatrixID::UNKNOWN; | 39 return MatrixID::UNKNOWN; |
60 return static_cast<MatrixID>(matrix_id); | 40 return static_cast<MatrixID>(matrix_id); |
61 } | 41 } |
62 | 42 |
63 ColorSpace::ColorSpace() { | 43 ColorSpace::ColorSpace() { |
64 memset(custom_transfer_params_, 0, sizeof(custom_transfer_params_)); | |
65 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); | 44 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); |
66 } | 45 } |
67 | 46 |
68 ColorSpace::ColorSpace(PrimaryID primaries, | 47 ColorSpace::ColorSpace(PrimaryID primaries, |
69 TransferID transfer, | 48 TransferID transfer, |
70 MatrixID matrix, | 49 MatrixID matrix, |
71 RangeID range) | 50 RangeID range) |
72 : primaries_(primaries), | 51 : primaries_(primaries), |
73 transfer_(transfer), | 52 transfer_(transfer), |
74 matrix_(matrix), | 53 matrix_(matrix), |
75 range_(range) { | 54 range_(range) { |
76 memset(custom_transfer_params_, 0, sizeof(custom_transfer_params_)); | |
77 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); | 55 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); |
| 56 // TODO: Set profile_id_ |
78 } | 57 } |
79 | 58 |
80 ColorSpace::ColorSpace(int primaries, int transfer, int matrix, RangeID range) | 59 ColorSpace::ColorSpace(int primaries, int transfer, int matrix, RangeID range) |
81 : primaries_(PrimaryIDFromInt(primaries)), | 60 : primaries_(PrimaryIDFromInt(primaries)), |
82 transfer_(TransferIDFromInt(transfer)), | 61 transfer_(TransferIDFromInt(transfer)), |
83 matrix_(MatrixIDFromInt(matrix)), | 62 matrix_(MatrixIDFromInt(matrix)), |
84 range_(range) { | 63 range_(range) { |
85 memset(custom_transfer_params_, 0, sizeof(custom_transfer_params_)); | |
86 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); | 64 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); |
| 65 // TODO: Set profile_id_ |
87 } | 66 } |
88 | 67 |
89 ColorSpace::ColorSpace(const ColorSpace& other) | 68 ColorSpace::ColorSpace(const ColorSpace& other) |
90 : primaries_(other.primaries_), | 69 : primaries_(other.primaries_), |
91 transfer_(other.transfer_), | 70 transfer_(other.transfer_), |
92 matrix_(other.matrix_), | 71 matrix_(other.matrix_), |
93 range_(other.range_), | 72 range_(other.range_), |
94 icc_profile_id_(other.icc_profile_id_), | 73 icc_profile_id_(other.icc_profile_id_), |
95 sk_color_space_(other.sk_color_space_) { | 74 sk_color_space_(other.sk_color_space_) { |
96 memcpy(custom_transfer_params_, other.custom_transfer_params_, | |
97 sizeof(custom_transfer_params_)); | |
98 memcpy(custom_primary_matrix_, other.custom_primary_matrix_, | 75 memcpy(custom_primary_matrix_, other.custom_primary_matrix_, |
99 sizeof(custom_primary_matrix_)); | 76 sizeof(custom_primary_matrix_)); |
100 } | 77 } |
101 | 78 |
102 ColorSpace::~ColorSpace() = default; | 79 ColorSpace::~ColorSpace() = default; |
103 | 80 |
104 // static | 81 // static |
105 ColorSpace ColorSpace::CreateSRGB() { | 82 ColorSpace ColorSpace::CreateSRGB() { |
106 ColorSpace result(PrimaryID::BT709, TransferID::IEC61966_2_1, MatrixID::RGB, | 83 ColorSpace result(PrimaryID::BT709, TransferID::IEC61966_2_1, MatrixID::RGB, |
107 RangeID::FULL); | 84 RangeID::FULL); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
140 } | 117 } |
141 | 118 |
142 bool ColorSpace::operator==(const ColorSpace& other) const { | 119 bool ColorSpace::operator==(const ColorSpace& other) const { |
143 if (primaries_ != other.primaries_ || transfer_ != other.transfer_ || | 120 if (primaries_ != other.primaries_ || transfer_ != other.transfer_ || |
144 matrix_ != other.matrix_ || range_ != other.range_) | 121 matrix_ != other.matrix_ || range_ != other.range_) |
145 return false; | 122 return false; |
146 if (primaries_ == PrimaryID::CUSTOM && | 123 if (primaries_ == PrimaryID::CUSTOM && |
147 memcmp(custom_primary_matrix_, other.custom_primary_matrix_, | 124 memcmp(custom_primary_matrix_, other.custom_primary_matrix_, |
148 sizeof(custom_primary_matrix_))) | 125 sizeof(custom_primary_matrix_))) |
149 return false; | 126 return false; |
150 if (transfer_ == TransferID::CUSTOM && | |
151 memcmp(custom_transfer_params_, other.custom_transfer_params_, | |
152 sizeof(custom_transfer_params_))) | |
153 return false; | |
154 return true; | 127 return true; |
155 } | 128 } |
156 | 129 |
157 bool ColorSpace::IsHDR() const { | 130 bool ColorSpace::IsHDR() const { |
158 return transfer_ == TransferID::SMPTEST2084 || | 131 return transfer_ == TransferID::SMPTEST2084 || |
159 transfer_ == TransferID::ARIB_STD_B67; | 132 transfer_ == TransferID::ARIB_STD_B67; |
160 } | 133 } |
161 | 134 |
162 bool ColorSpace::operator!=(const ColorSpace& other) const { | 135 bool ColorSpace::operator!=(const ColorSpace& other) const { |
163 return !(*this == other); | 136 return !(*this == other); |
(...skipping 18 matching lines...) Expand all Loading... |
182 return false; | 155 return false; |
183 if (primaries_ == PrimaryID::CUSTOM) { | 156 if (primaries_ == PrimaryID::CUSTOM) { |
184 int primary_result = | 157 int primary_result = |
185 memcmp(custom_primary_matrix_, other.custom_primary_matrix_, | 158 memcmp(custom_primary_matrix_, other.custom_primary_matrix_, |
186 sizeof(custom_primary_matrix_)); | 159 sizeof(custom_primary_matrix_)); |
187 if (primary_result < 0) | 160 if (primary_result < 0) |
188 return true; | 161 return true; |
189 if (primary_result > 0) | 162 if (primary_result > 0) |
190 return false; | 163 return false; |
191 } | 164 } |
192 if (transfer_ == TransferID::CUSTOM) { | |
193 int transfer_result = | |
194 memcmp(custom_transfer_params_, other.custom_transfer_params_, | |
195 sizeof(custom_transfer_params_)); | |
196 if (transfer_result < 0) | |
197 return true; | |
198 if (transfer_result > 0) | |
199 return false; | |
200 } | |
201 return false; | 165 return false; |
202 } | 166 } |
203 | 167 |
204 ColorSpace ColorSpace::FromSkColorSpace( | 168 ColorSpace ColorSpace::FromSkColorSpace( |
205 const sk_sp<SkColorSpace>& sk_color_space) { | 169 const sk_sp<SkColorSpace>& sk_color_space) { |
206 if (!sk_color_space) | 170 if (!sk_color_space) |
207 return gfx::ColorSpace(); | 171 return gfx::ColorSpace(); |
208 if (SkColorSpace::Equals( | 172 if (SkColorSpace::Equals( |
209 sk_color_space.get(), | 173 sk_color_space.get(), |
210 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get())) | 174 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get())) |
211 return gfx::ColorSpace::CreateSRGB(); | 175 return gfx::ColorSpace::CreateSRGB(); |
212 | 176 |
213 // TODO(crbug.com/634102): Add conversion to gfx::ColorSpace for | 177 // TODO(crbug.com/634102): Add conversion to gfx::ColorSpace for |
214 // non-ICC-profile based color spaces. | 178 // non-ICC-profile based color spaces. |
215 ICCProfile icc_profile = ICCProfile::FromSkColorSpace(sk_color_space); | 179 ICCProfile icc_profile = ICCProfile::FromSkColorSpace(sk_color_space); |
216 return icc_profile.GetColorSpace(); | 180 return icc_profile.GetColorSpace(); |
217 } | 181 } |
218 | 182 |
219 void ColorSpace::GetPrimaryMatrix(SkMatrix44* to_XYZD50) const { | |
220 SkColorSpacePrimaries primaries = {0}; | |
221 switch (primaries_) { | |
222 case ColorSpace::PrimaryID::CUSTOM: | |
223 to_XYZD50->set3x3RowMajorf(custom_primary_matrix_); | |
224 return; | |
225 | |
226 case ColorSpace::PrimaryID::RESERVED0: | |
227 case ColorSpace::PrimaryID::RESERVED: | |
228 case ColorSpace::PrimaryID::UNSPECIFIED: | |
229 case ColorSpace::PrimaryID::UNKNOWN: | |
230 case ColorSpace::PrimaryID::BT709: | |
231 // BT709 is our default case. Put it after the switch just | |
232 // in case we somehow get an id which is not listed in the switch. | |
233 // (We don't want to use "default", because we want the compiler | |
234 // to tell us if we forgot some enum values.) | |
235 primaries.fRX = 0.640f; | |
236 primaries.fRY = 0.330f; | |
237 primaries.fGX = 0.300f; | |
238 primaries.fGY = 0.600f; | |
239 primaries.fBX = 0.150f; | |
240 primaries.fBY = 0.060f; | |
241 primaries.fWX = 0.3127f; | |
242 primaries.fWY = 0.3290f; | |
243 break; | |
244 | |
245 case ColorSpace::PrimaryID::BT470M: | |
246 primaries.fRX = 0.67f; | |
247 primaries.fRY = 0.33f; | |
248 primaries.fGX = 0.21f; | |
249 primaries.fGY = 0.71f; | |
250 primaries.fBX = 0.14f; | |
251 primaries.fBY = 0.08f; | |
252 primaries.fWX = 0.31f; | |
253 primaries.fWY = 0.316f; | |
254 break; | |
255 | |
256 case ColorSpace::PrimaryID::BT470BG: | |
257 primaries.fRX = 0.64f; | |
258 primaries.fRY = 0.33f; | |
259 primaries.fGX = 0.29f; | |
260 primaries.fGY = 0.60f; | |
261 primaries.fBX = 0.15f; | |
262 primaries.fBY = 0.06f; | |
263 primaries.fWX = 0.3127f; | |
264 primaries.fWY = 0.3290f; | |
265 break; | |
266 | |
267 case ColorSpace::PrimaryID::SMPTE170M: | |
268 case ColorSpace::PrimaryID::SMPTE240M: | |
269 primaries.fRX = 0.630f; | |
270 primaries.fRY = 0.340f; | |
271 primaries.fGX = 0.310f; | |
272 primaries.fGY = 0.595f; | |
273 primaries.fBX = 0.155f; | |
274 primaries.fBY = 0.070f; | |
275 primaries.fWX = 0.3127f; | |
276 primaries.fWY = 0.3290f; | |
277 break; | |
278 | |
279 case ColorSpace::PrimaryID::FILM: | |
280 primaries.fRX = 0.681f; | |
281 primaries.fRY = 0.319f; | |
282 primaries.fGX = 0.243f; | |
283 primaries.fGY = 0.692f; | |
284 primaries.fBX = 0.145f; | |
285 primaries.fBY = 0.049f; | |
286 primaries.fWX = 0.310f; | |
287 primaries.fWY = 0.136f; | |
288 break; | |
289 | |
290 case ColorSpace::PrimaryID::BT2020: | |
291 primaries.fRX = 0.708f; | |
292 primaries.fRY = 0.292f; | |
293 primaries.fGX = 0.170f; | |
294 primaries.fGY = 0.797f; | |
295 primaries.fBX = 0.131f; | |
296 primaries.fBY = 0.046f; | |
297 primaries.fWX = 0.3127f; | |
298 primaries.fWY = 0.3290f; | |
299 break; | |
300 | |
301 case ColorSpace::PrimaryID::SMPTEST428_1: | |
302 primaries.fRX = 1.0f; | |
303 primaries.fRY = 0.0f; | |
304 primaries.fGX = 0.0f; | |
305 primaries.fGY = 1.0f; | |
306 primaries.fBX = 0.0f; | |
307 primaries.fBY = 0.0f; | |
308 primaries.fWX = 1.0f / 3.0f; | |
309 primaries.fWY = 1.0f / 3.0f; | |
310 break; | |
311 | |
312 case ColorSpace::PrimaryID::SMPTEST431_2: | |
313 primaries.fRX = 0.680f; | |
314 primaries.fRY = 0.320f; | |
315 primaries.fGX = 0.265f; | |
316 primaries.fGY = 0.690f; | |
317 primaries.fBX = 0.150f; | |
318 primaries.fBY = 0.060f; | |
319 primaries.fWX = 0.314f; | |
320 primaries.fWY = 0.351f; | |
321 break; | |
322 | |
323 case ColorSpace::PrimaryID::SMPTEST432_1: | |
324 primaries.fRX = 0.680f; | |
325 primaries.fRY = 0.320f; | |
326 primaries.fGX = 0.265f; | |
327 primaries.fGY = 0.690f; | |
328 primaries.fBX = 0.150f; | |
329 primaries.fBY = 0.060f; | |
330 primaries.fWX = 0.3127f; | |
331 primaries.fWY = 0.3290f; | |
332 break; | |
333 | |
334 case ColorSpace::PrimaryID::XYZ_D50: | |
335 primaries.fRX = 1.0f; | |
336 primaries.fRY = 0.0f; | |
337 primaries.fGX = 0.0f; | |
338 primaries.fGY = 1.0f; | |
339 primaries.fBX = 0.0f; | |
340 primaries.fBY = 0.0f; | |
341 primaries.fWX = 0.34567f; | |
342 primaries.fWY = 0.35850f; | |
343 break; | |
344 } | |
345 primaries.toXYZD50(to_XYZD50); | |
346 } | |
347 | |
348 bool ColorSpace::GetTransferFunction(SkColorSpaceTransferFn* fn) const { | |
349 // Default to F(x) = pow(x, 1) | |
350 fn->fA = 1; | |
351 fn->fB = 0; | |
352 fn->fC = 1; | |
353 fn->fD = 0; | |
354 fn->fE = 0; | |
355 fn->fF = 0; | |
356 fn->fG = 1; | |
357 | |
358 switch (transfer_) { | |
359 case ColorSpace::TransferID::CUSTOM: | |
360 fn->fA = custom_transfer_params_[0]; | |
361 fn->fB = custom_transfer_params_[1]; | |
362 fn->fC = custom_transfer_params_[2]; | |
363 fn->fD = custom_transfer_params_[3]; | |
364 fn->fE = custom_transfer_params_[4]; | |
365 fn->fF = custom_transfer_params_[5]; | |
366 fn->fG = custom_transfer_params_[6]; | |
367 return true; | |
368 case ColorSpace::TransferID::LINEAR: | |
369 return true; | |
370 case ColorSpace::TransferID::GAMMA22: | |
371 fn->fG = 2.2f; | |
372 return true; | |
373 case ColorSpace::TransferID::GAMMA24: | |
374 fn->fG = 2.4f; | |
375 return true; | |
376 case ColorSpace::TransferID::GAMMA28: | |
377 fn->fG = 2.8f; | |
378 return true; | |
379 case ColorSpace::TransferID::RESERVED0: | |
380 case ColorSpace::TransferID::RESERVED: | |
381 case ColorSpace::TransferID::UNSPECIFIED: | |
382 case ColorSpace::TransferID::UNKNOWN: | |
383 // All unknown values default to BT709 | |
384 case ColorSpace::TransferID::BT709: | |
385 case ColorSpace::TransferID::SMPTE170M: | |
386 case ColorSpace::TransferID::BT2020_10: | |
387 case ColorSpace::TransferID::BT2020_12: | |
388 fn->fA = 0.909672431050f; | |
389 fn->fB = 0.090327568950f; | |
390 fn->fC = 0.222222222222f; | |
391 fn->fD = 0.081242862158f; | |
392 fn->fG = 2.222222222222f; | |
393 return true; | |
394 case ColorSpace::TransferID::SMPTE240M: | |
395 fn->fA = 0.899626676224f; | |
396 fn->fB = 0.100373323776f; | |
397 fn->fC = 0.250000000000f; | |
398 fn->fD = 0.091286342118f; | |
399 fn->fG = 2.222222222222f; | |
400 return true; | |
401 case ColorSpace::TransferID::IEC61966_2_1: | |
402 fn->fA = 0.947867345704f; | |
403 fn->fB = 0.052132654296f; | |
404 fn->fC = 0.077399380805f; | |
405 fn->fD = 0.040449937172f; | |
406 fn->fG = 2.400000000000f; | |
407 return true; | |
408 case ColorSpace::TransferID::SMPTEST428_1: | |
409 fn->fA = 0.225615407568f; | |
410 fn->fE = -1.091041666667f; | |
411 fn->fG = 2.600000000000f; | |
412 return true; | |
413 case ColorSpace::TransferID::IEC61966_2_4: | |
414 // This could potentially be represented the same as IEC61966_2_1, but | |
415 // it handles negative values differently. | |
416 break; | |
417 case ColorSpace::TransferID::ARIB_STD_B67: | |
418 case ColorSpace::TransferID::BT1361_ECG: | |
419 case ColorSpace::TransferID::LOG: | |
420 case ColorSpace::TransferID::LOG_SQRT: | |
421 case ColorSpace::TransferID::SMPTEST2084: | |
422 case ColorSpace::TransferID::SMPTEST2084_NON_HDR: | |
423 break; | |
424 } | |
425 | |
426 return false; | |
427 } | |
428 | |
429 bool ColorSpace::GetInverseTransferFunction(SkColorSpaceTransferFn* fn) const { | |
430 if (!GetTransferFunction(fn)) | |
431 return false; | |
432 *fn = InvertTransferFn(*fn); | |
433 return true; | |
434 } | |
435 | |
436 } // namespace gfx | 183 } // namespace gfx |
OLD | NEW |