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 |
16 ColorSpace::PrimaryID ColorSpace::PrimaryIDFromInt(int primary_id) { | 36 ColorSpace::PrimaryID ColorSpace::PrimaryIDFromInt(int primary_id) { |
17 if (primary_id < 0 || primary_id > static_cast<int>(PrimaryID::LAST)) | 37 if (primary_id < 0 || primary_id > static_cast<int>(PrimaryID::LAST)) |
18 return PrimaryID::UNKNOWN; | 38 return PrimaryID::UNKNOWN; |
19 if (primary_id > static_cast<int>(PrimaryID::LAST_STANDARD_VALUE) && | 39 if (primary_id > static_cast<int>(PrimaryID::LAST_STANDARD_VALUE) && |
20 primary_id < 1000) | 40 primary_id < 1000) |
21 return PrimaryID::UNKNOWN; | 41 return PrimaryID::UNKNOWN; |
22 return static_cast<PrimaryID>(primary_id); | 42 return static_cast<PrimaryID>(primary_id); |
23 } | 43 } |
24 | 44 |
25 ColorSpace::TransferID ColorSpace::TransferIDFromInt(int transfer_id) { | 45 ColorSpace::TransferID ColorSpace::TransferIDFromInt(int transfer_id) { |
26 if (transfer_id < 0 || transfer_id > static_cast<int>(TransferID::LAST)) | 46 if (transfer_id < 0 || transfer_id > static_cast<int>(TransferID::LAST)) |
27 return TransferID::UNKNOWN; | 47 return TransferID::UNKNOWN; |
28 if (transfer_id > static_cast<int>(TransferID::LAST_STANDARD_VALUE) && | 48 if (transfer_id > static_cast<int>(TransferID::LAST_STANDARD_VALUE) && |
29 transfer_id < 1000) | 49 transfer_id < 1000) |
30 return TransferID::UNKNOWN; | 50 return TransferID::UNKNOWN; |
31 return static_cast<TransferID>(transfer_id); | 51 return static_cast<TransferID>(transfer_id); |
32 } | 52 } |
33 | 53 |
34 ColorSpace::MatrixID ColorSpace::MatrixIDFromInt(int matrix_id) { | 54 ColorSpace::MatrixID ColorSpace::MatrixIDFromInt(int matrix_id) { |
35 if (matrix_id < 0 || matrix_id > static_cast<int>(MatrixID::LAST)) | 55 if (matrix_id < 0 || matrix_id > static_cast<int>(MatrixID::LAST)) |
36 return MatrixID::UNKNOWN; | 56 return MatrixID::UNKNOWN; |
37 if (matrix_id > static_cast<int>(MatrixID::LAST_STANDARD_VALUE) && | 57 if (matrix_id > static_cast<int>(MatrixID::LAST_STANDARD_VALUE) && |
38 matrix_id < 1000) | 58 matrix_id < 1000) |
39 return MatrixID::UNKNOWN; | 59 return MatrixID::UNKNOWN; |
40 return static_cast<MatrixID>(matrix_id); | 60 return static_cast<MatrixID>(matrix_id); |
41 } | 61 } |
42 | 62 |
43 ColorSpace::ColorSpace() { | 63 ColorSpace::ColorSpace() { |
| 64 memset(custom_transfer_params_, 0, sizeof(custom_transfer_params_)); |
44 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); | 65 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); |
45 } | 66 } |
46 | 67 |
47 ColorSpace::ColorSpace(PrimaryID primaries, | 68 ColorSpace::ColorSpace(PrimaryID primaries, |
48 TransferID transfer, | 69 TransferID transfer, |
49 MatrixID matrix, | 70 MatrixID matrix, |
50 RangeID range) | 71 RangeID range) |
51 : primaries_(primaries), | 72 : primaries_(primaries), |
52 transfer_(transfer), | 73 transfer_(transfer), |
53 matrix_(matrix), | 74 matrix_(matrix), |
54 range_(range) { | 75 range_(range) { |
| 76 memset(custom_transfer_params_, 0, sizeof(custom_transfer_params_)); |
55 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); | 77 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); |
56 // TODO: Set profile_id_ | |
57 } | 78 } |
58 | 79 |
59 ColorSpace::ColorSpace(int primaries, int transfer, int matrix, RangeID range) | 80 ColorSpace::ColorSpace(int primaries, int transfer, int matrix, RangeID range) |
60 : primaries_(PrimaryIDFromInt(primaries)), | 81 : primaries_(PrimaryIDFromInt(primaries)), |
61 transfer_(TransferIDFromInt(transfer)), | 82 transfer_(TransferIDFromInt(transfer)), |
62 matrix_(MatrixIDFromInt(matrix)), | 83 matrix_(MatrixIDFromInt(matrix)), |
63 range_(range) { | 84 range_(range) { |
| 85 memset(custom_transfer_params_, 0, sizeof(custom_transfer_params_)); |
64 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); | 86 memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_)); |
65 // TODO: Set profile_id_ | |
66 } | 87 } |
67 | 88 |
68 ColorSpace::ColorSpace(const ColorSpace& other) | 89 ColorSpace::ColorSpace(const ColorSpace& other) |
69 : primaries_(other.primaries_), | 90 : primaries_(other.primaries_), |
70 transfer_(other.transfer_), | 91 transfer_(other.transfer_), |
71 matrix_(other.matrix_), | 92 matrix_(other.matrix_), |
72 range_(other.range_), | 93 range_(other.range_), |
73 icc_profile_id_(other.icc_profile_id_), | 94 icc_profile_id_(other.icc_profile_id_), |
74 sk_color_space_(other.sk_color_space_) { | 95 sk_color_space_(other.sk_color_space_) { |
| 96 memcpy(custom_transfer_params_, other.custom_transfer_params_, |
| 97 sizeof(custom_transfer_params_)); |
75 memcpy(custom_primary_matrix_, other.custom_primary_matrix_, | 98 memcpy(custom_primary_matrix_, other.custom_primary_matrix_, |
76 sizeof(custom_primary_matrix_)); | 99 sizeof(custom_primary_matrix_)); |
77 } | 100 } |
78 | 101 |
79 ColorSpace::~ColorSpace() = default; | 102 ColorSpace::~ColorSpace() = default; |
80 | 103 |
81 // static | 104 // static |
82 ColorSpace ColorSpace::CreateSRGB() { | 105 ColorSpace ColorSpace::CreateSRGB() { |
83 ColorSpace result(PrimaryID::BT709, TransferID::IEC61966_2_1, MatrixID::RGB, | 106 ColorSpace result(PrimaryID::BT709, TransferID::IEC61966_2_1, MatrixID::RGB, |
84 RangeID::FULL); | 107 RangeID::FULL); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 } | 140 } |
118 | 141 |
119 bool ColorSpace::operator==(const ColorSpace& other) const { | 142 bool ColorSpace::operator==(const ColorSpace& other) const { |
120 if (primaries_ != other.primaries_ || transfer_ != other.transfer_ || | 143 if (primaries_ != other.primaries_ || transfer_ != other.transfer_ || |
121 matrix_ != other.matrix_ || range_ != other.range_) | 144 matrix_ != other.matrix_ || range_ != other.range_) |
122 return false; | 145 return false; |
123 if (primaries_ == PrimaryID::CUSTOM && | 146 if (primaries_ == PrimaryID::CUSTOM && |
124 memcmp(custom_primary_matrix_, other.custom_primary_matrix_, | 147 memcmp(custom_primary_matrix_, other.custom_primary_matrix_, |
125 sizeof(custom_primary_matrix_))) | 148 sizeof(custom_primary_matrix_))) |
126 return false; | 149 return false; |
| 150 if (transfer_ == TransferID::CUSTOM && |
| 151 memcmp(custom_transfer_params_, other.custom_transfer_params_, |
| 152 sizeof(custom_transfer_params_))) |
| 153 return false; |
127 return true; | 154 return true; |
128 } | 155 } |
129 | 156 |
130 bool ColorSpace::IsHDR() const { | 157 bool ColorSpace::IsHDR() const { |
131 return transfer_ == TransferID::SMPTEST2084 || | 158 return transfer_ == TransferID::SMPTEST2084 || |
132 transfer_ == TransferID::ARIB_STD_B67; | 159 transfer_ == TransferID::ARIB_STD_B67; |
133 } | 160 } |
134 | 161 |
135 bool ColorSpace::operator!=(const ColorSpace& other) const { | 162 bool ColorSpace::operator!=(const ColorSpace& other) const { |
136 return !(*this == other); | 163 return !(*this == other); |
(...skipping 18 matching lines...) Expand all Loading... |
155 return false; | 182 return false; |
156 if (primaries_ == PrimaryID::CUSTOM) { | 183 if (primaries_ == PrimaryID::CUSTOM) { |
157 int primary_result = | 184 int primary_result = |
158 memcmp(custom_primary_matrix_, other.custom_primary_matrix_, | 185 memcmp(custom_primary_matrix_, other.custom_primary_matrix_, |
159 sizeof(custom_primary_matrix_)); | 186 sizeof(custom_primary_matrix_)); |
160 if (primary_result < 0) | 187 if (primary_result < 0) |
161 return true; | 188 return true; |
162 if (primary_result > 0) | 189 if (primary_result > 0) |
163 return false; | 190 return false; |
164 } | 191 } |
| 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 } |
165 return false; | 201 return false; |
166 } | 202 } |
167 | 203 |
168 ColorSpace ColorSpace::FromSkColorSpace( | 204 ColorSpace ColorSpace::FromSkColorSpace( |
169 const sk_sp<SkColorSpace>& sk_color_space) { | 205 const sk_sp<SkColorSpace>& sk_color_space) { |
170 if (!sk_color_space) | 206 if (!sk_color_space) |
171 return gfx::ColorSpace(); | 207 return gfx::ColorSpace(); |
172 if (SkColorSpace::Equals( | 208 if (SkColorSpace::Equals( |
173 sk_color_space.get(), | 209 sk_color_space.get(), |
174 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get())) | 210 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get())) |
175 return gfx::ColorSpace::CreateSRGB(); | 211 return gfx::ColorSpace::CreateSRGB(); |
176 | 212 |
177 // TODO(crbug.com/634102): Add conversion to gfx::ColorSpace for | 213 // TODO(crbug.com/634102): Add conversion to gfx::ColorSpace for |
178 // non-ICC-profile based color spaces. | 214 // non-ICC-profile based color spaces. |
179 ICCProfile icc_profile = ICCProfile::FromSkColorSpace(sk_color_space); | 215 ICCProfile icc_profile = ICCProfile::FromSkColorSpace(sk_color_space); |
180 return icc_profile.GetColorSpace(); | 216 return icc_profile.GetColorSpace(); |
181 } | 217 } |
182 | 218 |
| 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 |
183 } // namespace gfx | 436 } // namespace gfx |
OLD | NEW |