OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkColorSpace.h" | 8 #include "SkColorSpace.h" |
9 #include "SkColorSpace_Base.h" | 9 #include "SkColorSpace_Base.h" |
10 #include "SkColorSpacePriv.h" | 10 #include "SkColorSpacePriv.h" |
11 #include "SkOnce.h" | 11 #include "SkOnce.h" |
12 #include "SkPoint3.h" | 12 #include "SkPoint3.h" |
13 | 13 |
14 static inline bool is_zero_to_one(float v) { | |
15 return (0.0f <= v) && (v <= 1.0f); | |
16 } | |
17 | |
18 bool SkColorSpacePrimaries::toXYZD50(SkMatrix44* toXYZ_D50) const { | 14 bool SkColorSpacePrimaries::toXYZD50(SkMatrix44* toXYZ_D50) const { |
19 if (!is_zero_to_one(fRX) || !is_zero_to_one(fRY) || | 15 if (!is_zero_to_one(fRX) || !is_zero_to_one(fRY) || |
20 !is_zero_to_one(fGX) || !is_zero_to_one(fGY) || | 16 !is_zero_to_one(fGX) || !is_zero_to_one(fGY) || |
21 !is_zero_to_one(fBX) || !is_zero_to_one(fBY) || | 17 !is_zero_to_one(fBX) || !is_zero_to_one(fBY) || |
22 !is_zero_to_one(fWX) || !is_zero_to_one(fWY)) | 18 !is_zero_to_one(fWX) || !is_zero_to_one(fWY)) |
23 { | 19 { |
24 return false; | 20 return false; |
25 } | 21 } |
26 | 22 |
27 // First, we need to convert xy values (primaries) to XYZ. | 23 // First, we need to convert xy values (primaries) to XYZ. |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 switch (gamma) { | 200 switch (gamma) { |
205 case kLinear_RenderTargetGamma: | 201 case kLinear_RenderTargetGamma: |
206 return SkColorSpace_Base::NewRGB(kLinear_SkGammaNamed, toXYZD50); | 202 return SkColorSpace_Base::NewRGB(kLinear_SkGammaNamed, toXYZD50); |
207 case kSRGB_RenderTargetGamma: | 203 case kSRGB_RenderTargetGamma: |
208 return SkColorSpace_Base::NewRGB(kSRGB_SkGammaNamed, toXYZD50); | 204 return SkColorSpace_Base::NewRGB(kSRGB_SkGammaNamed, toXYZD50); |
209 default: | 205 default: |
210 return nullptr; | 206 return nullptr; |
211 } | 207 } |
212 } | 208 } |
213 | 209 |
| 210 sk_sp<SkColorSpace> SkColorSpace::NewRGB(const SkColorSpaceTransferFn& coeffs, |
| 211 const SkMatrix44& toXYZD50) { |
| 212 if (!is_valid_transfer_fn(coeffs)) { |
| 213 return nullptr; |
| 214 } |
| 215 |
| 216 if (is_almost_srgb(coeffs)) { |
| 217 return SkColorSpace::NewRGB(kSRGB_RenderTargetGamma, toXYZD50); |
| 218 } |
| 219 |
| 220 if (is_almost_2dot2(coeffs)) { |
| 221 return SkColorSpace_Base::NewRGB(k2Dot2Curve_SkGammaNamed, toXYZD50); |
| 222 } |
| 223 |
| 224 void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkColorSpaceTransfe
rFn)); |
| 225 sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas()); |
| 226 SkColorSpaceTransferFn* fn = SkTAddOffset<SkColorSpaceTransferFn>(memory, si
zeof(SkGammas)); |
| 227 *fn = coeffs; |
| 228 gammas->fRedType = SkGammas::Type::kParam_Type; |
| 229 gammas->fGreenType = SkGammas::Type::kParam_Type; |
| 230 gammas->fBlueType = SkGammas::Type::kParam_Type; |
| 231 |
| 232 SkGammas::Data data; |
| 233 data.fParamOffset = 0; |
| 234 gammas->fRedData = data; |
| 235 gammas->fGreenData = data; |
| 236 gammas->fBlueData = data; |
| 237 return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, kNonStandard_SkGam
maNamed, |
| 238 std::move(gammas), toXYZD50
, nullptr)); |
| 239 } |
| 240 |
214 static SkColorSpace* gAdobeRGB; | 241 static SkColorSpace* gAdobeRGB; |
215 static SkColorSpace* gSRGB; | 242 static SkColorSpace* gSRGB; |
216 static SkColorSpace* gSRGBLinear; | 243 static SkColorSpace* gSRGBLinear; |
217 | 244 |
218 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { | 245 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { |
219 static SkOnce sRGBOnce; | 246 static SkOnce sRGBOnce; |
220 static SkOnce adobeRGBOnce; | 247 static SkOnce adobeRGBOnce; |
221 static SkOnce sRGBLinearOnce; | 248 static SkOnce sRGBLinearOnce; |
222 | 249 |
223 switch (named) { | 250 switch (named) { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 } | 320 } |
294 | 321 |
295 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 322 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
296 | 323 |
297 enum Version { | 324 enum Version { |
298 k0_Version, // Initial version, header + flags for matrix and profile | 325 k0_Version, // Initial version, header + flags for matrix and profile |
299 }; | 326 }; |
300 | 327 |
301 struct ColorSpaceHeader { | 328 struct ColorSpaceHeader { |
302 /** | 329 /** |
| 330 * It is only valid to set zero or one flags. |
| 331 * Setting multiple flags is invalid. |
| 332 */ |
| 333 |
| 334 /** |
303 * If kMatrix_Flag is set, we will write 12 floats after the header. | 335 * If kMatrix_Flag is set, we will write 12 floats after the header. |
304 * Should not be set at the same time as the kICC_Flag or kFloatGamma_Flag. | |
305 */ | 336 */ |
306 static constexpr uint8_t kMatrix_Flag = 1 << 0; | 337 static constexpr uint8_t kMatrix_Flag = 1 << 0; |
307 | 338 |
308 /** | 339 /** |
309 * If kICC_Flag is set, we will write an ICC profile after the header. | 340 * If kICC_Flag is set, we will write an ICC profile after the header. |
310 * The ICC profile will be written as a uint32 size, followed immediately | 341 * The ICC profile will be written as a uint32 size, followed immediately |
311 * by the data (padded to 4 bytes). | 342 * by the data (padded to 4 bytes). |
312 * Should not be set at the same time as the kMatrix_Flag or kFloatGamma_Fl
ag. | |
313 */ | 343 */ |
314 static constexpr uint8_t kICC_Flag = 1 << 1; | 344 static constexpr uint8_t kICC_Flag = 1 << 1; |
315 | 345 |
316 /** | 346 /** |
317 * If kFloatGamma_Flag is set, we will write 15 floats after the header. | 347 * If kFloatGamma_Flag is set, we will write 15 floats after the header. |
318 * The first three are the gamma values, and the next twelve are the | 348 * The first three are the gamma values, and the next twelve are the |
319 * matrix. | 349 * matrix. |
320 * Should not be set at the same time as the kICC_Flag or kMatrix_Flag. | |
321 */ | 350 */ |
322 static constexpr uint8_t kFloatGamma_Flag = 1 << 2; | 351 static constexpr uint8_t kFloatGamma_Flag = 1 << 2; |
323 | 352 |
| 353 /** |
| 354 * If kTransferFn_Flag is set, we will write 19 floats after the header. |
| 355 * The first seven represent the transfer fn, and the next twelve are the |
| 356 * matrix. |
| 357 */ |
| 358 static constexpr uint8_t kTransferFn_Flag = 1 << 3; |
| 359 |
324 static ColorSpaceHeader Pack(Version version, uint8_t named, uint8_t gammaNa
med, uint8_t flags) | 360 static ColorSpaceHeader Pack(Version version, uint8_t named, uint8_t gammaNa
med, uint8_t flags) |
325 { | 361 { |
326 ColorSpaceHeader header; | 362 ColorSpaceHeader header; |
327 | 363 |
328 SkASSERT(k0_Version == version); | 364 SkASSERT(k0_Version == version); |
329 header.fVersion = (uint8_t) version; | 365 header.fVersion = (uint8_t) version; |
330 | 366 |
331 SkASSERT(named <= SkColorSpace::kSRGBLinear_Named); | 367 SkASSERT(named <= SkColorSpace::kSRGBLinear_Named); |
332 header.fNamed = (uint8_t) named; | 368 header.fNamed = (uint8_t) named; |
333 | 369 |
334 SkASSERT(gammaNamed <= kNonStandard_SkGammaNamed); | 370 SkASSERT(gammaNamed <= kNonStandard_SkGammaNamed); |
335 header.fGammaNamed = (uint8_t) gammaNamed; | 371 header.fGammaNamed = (uint8_t) gammaNamed; |
336 | 372 |
337 SkASSERT(flags <= kFloatGamma_Flag); | 373 SkASSERT(flags <= kTransferFn_Flag); |
338 header.fFlags = flags; | 374 header.fFlags = flags; |
339 return header; | 375 return header; |
340 } | 376 } |
341 | 377 |
342 uint8_t fVersion; // Always zero | 378 uint8_t fVersion; // Always zero |
343 uint8_t fNamed; // Must be a SkColorSpace::Named | 379 uint8_t fNamed; // Must be a SkColorSpace::Named |
344 uint8_t fGammaNamed; // Must be a SkGammaNamed | 380 uint8_t fGammaNamed; // Must be a SkGammaNamed |
345 uint8_t fFlags; // Some combination of the flags listed above | 381 uint8_t fFlags; // Some combination of the flags listed above |
346 }; | 382 }; |
347 | 383 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 if (memory) { | 417 if (memory) { |
382 *((ColorSpaceHeader*) memory) = | 418 *((ColorSpaceHeader*) memory) = |
383 ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->
fGammaNamed, | 419 ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->
fGammaNamed, |
384 ColorSpaceHeader::kMatrix_Fla
g); | 420 ColorSpaceHeader::kMatrix_Fla
g); |
385 memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader)
); | 421 memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader)
); |
386 as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); | 422 as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); |
387 } | 423 } |
388 return sizeof(ColorSpaceHeader) + 12 * sizeof(float); | 424 return sizeof(ColorSpaceHeader) + 12 * sizeof(float); |
389 } | 425 } |
390 default: | 426 default: |
391 // Otherwise, write the gamma values and the matrix. | 427 const SkGammas* gammas = as_CSB(this)->gammas(); |
392 if (memory) { | 428 SkASSERT(gammas); |
393 *((ColorSpaceHeader*) memory) = | 429 if (gammas->isValue(0) && gammas->isValue(1) && gammas->isValue(
2)) { |
394 ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->
fGammaNamed, | 430 if (memory) { |
395 ColorSpaceHeader::kFloatGamma
_Flag); | 431 *((ColorSpaceHeader*) memory) = |
396 memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader)
); | 432 ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(thi
s)->fGammaNamed, |
| 433 ColorSpaceHeader::kFloatG
amma_Flag); |
| 434 memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHea
der)); |
397 | 435 |
398 const SkGammas* gammas = as_CSB(this)->gammas(); | 436 *(((float*) memory) + 0) = gammas->fRedData.fValue; |
399 SkASSERT(gammas); | 437 *(((float*) memory) + 1) = gammas->fGreenData.fValue; |
400 SkASSERT(SkGammas::Type::kValue_Type == gammas->fRedType && | 438 *(((float*) memory) + 2) = gammas->fBlueData.fValue; |
401 SkGammas::Type::kValue_Type == gammas->fGreenType &
& | 439 memory = SkTAddOffset<void>(memory, 3 * sizeof(float)); |
402 SkGammas::Type::kValue_Type == gammas->fBlueType); | |
403 *(((float*) memory) + 0) = gammas->fRedData.fValue; | |
404 *(((float*) memory) + 1) = gammas->fGreenData.fValue; | |
405 *(((float*) memory) + 2) = gammas->fBlueData.fValue; | |
406 memory = SkTAddOffset<void>(memory, 3 * sizeof(float)); | |
407 | 440 |
408 as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); | 441 as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); |
| 442 } |
| 443 |
| 444 return sizeof(ColorSpaceHeader) + 15 * sizeof(float); |
| 445 } else { |
| 446 SkASSERT(gammas->isParametric(0)); |
| 447 SkASSERT(gammas->isParametric(1)); |
| 448 SkASSERT(gammas->isParametric(2)); |
| 449 SkASSERT(gammas->data(0) == gammas->data(1)); |
| 450 SkASSERT(gammas->data(0) == gammas->data(2)); |
| 451 |
| 452 if (memory) { |
| 453 *((ColorSpaceHeader*) memory) = |
| 454 ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(thi
s)->fGammaNamed, |
| 455 ColorSpaceHeader::kTransf
erFn_Flag); |
| 456 memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHea
der)); |
| 457 |
| 458 *(((float*) memory) + 0) = gammas->params(0).fA; |
| 459 *(((float*) memory) + 1) = gammas->params(0).fB; |
| 460 *(((float*) memory) + 2) = gammas->params(0).fC; |
| 461 *(((float*) memory) + 3) = gammas->params(0).fD; |
| 462 *(((float*) memory) + 4) = gammas->params(0).fE; |
| 463 *(((float*) memory) + 5) = gammas->params(0).fF; |
| 464 *(((float*) memory) + 6) = gammas->params(0).fG; |
| 465 memory = SkTAddOffset<void>(memory, 7 * sizeof(float)); |
| 466 |
| 467 as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); |
| 468 } |
| 469 |
| 470 return sizeof(ColorSpaceHeader) + 19 * sizeof(float); |
409 } | 471 } |
410 return sizeof(ColorSpaceHeader) + 15 * sizeof(float); | |
411 } | 472 } |
412 } | 473 } |
413 | 474 |
414 // Otherwise, serialize the ICC data. | 475 // Otherwise, serialize the ICC data. |
415 size_t profileSize = as_CSB(this)->fProfileData->size(); | 476 size_t profileSize = as_CSB(this)->fProfileData->size(); |
416 if (SkAlign4(profileSize) != (uint32_t) SkAlign4(profileSize)) { | 477 if (SkAlign4(profileSize) != (uint32_t) SkAlign4(profileSize)) { |
417 return 0; | 478 return 0; |
418 } | 479 } |
419 | 480 |
420 if (memory) { | 481 if (memory) { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
494 float gammas[3]; | 555 float gammas[3]; |
495 gammas[0] = *(((const float*) data) + 0); | 556 gammas[0] = *(((const float*) data) + 0); |
496 gammas[1] = *(((const float*) data) + 1); | 557 gammas[1] = *(((const float*) data) + 1); |
497 gammas[2] = *(((const float*) data) + 2); | 558 gammas[2] = *(((const float*) data) + 2); |
498 data = SkTAddOffset<const void>(data, 3 * sizeof(float)); | 559 data = SkTAddOffset<const void>(data, 3 * sizeof(float)); |
499 | 560 |
500 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); | 561 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); |
501 toXYZ.set3x4RowMajorf((const float*) data); | 562 toXYZ.set3x4RowMajorf((const float*) data); |
502 return SkColorSpace_Base::NewRGB(gammas, toXYZ); | 563 return SkColorSpace_Base::NewRGB(gammas, toXYZ); |
503 } | 564 } |
| 565 case ColorSpaceHeader::kTransferFn_Flag: { |
| 566 if (length < 19 * sizeof(float)) { |
| 567 return nullptr; |
| 568 } |
| 569 |
| 570 SkColorSpaceTransferFn transferFn; |
| 571 transferFn.fA = *(((const float*) data) + 0); |
| 572 transferFn.fB = *(((const float*) data) + 1); |
| 573 transferFn.fC = *(((const float*) data) + 2); |
| 574 transferFn.fD = *(((const float*) data) + 3); |
| 575 transferFn.fE = *(((const float*) data) + 4); |
| 576 transferFn.fF = *(((const float*) data) + 5); |
| 577 transferFn.fG = *(((const float*) data) + 6); |
| 578 data = SkTAddOffset<const void>(data, 7 * sizeof(float)); |
| 579 |
| 580 SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); |
| 581 toXYZ.set3x4RowMajorf((const float*) data); |
| 582 return SkColorSpace::NewRGB(transferFn, toXYZ); |
| 583 } |
504 default: | 584 default: |
505 return nullptr; | 585 return nullptr; |
506 } | 586 } |
507 } | 587 } |
508 | 588 |
509 bool SkColorSpace::Equals(const SkColorSpace* src, const SkColorSpace* dst) { | 589 bool SkColorSpace::Equals(const SkColorSpace* src, const SkColorSpace* dst) { |
510 if (src == dst) { | 590 if (src == dst) { |
511 return true; | 591 return true; |
512 } | 592 } |
513 | 593 |
(...skipping 25 matching lines...) Expand all Loading... |
539 return false; | 619 return false; |
540 } | 620 } |
541 | 621 |
542 // It is unlikely that we will reach this case. | 622 // It is unlikely that we will reach this case. |
543 sk_sp<SkData> srcData = src->serialize(); | 623 sk_sp<SkData> srcData = src->serialize(); |
544 sk_sp<SkData> dstData = dst->serialize(); | 624 sk_sp<SkData> dstData = dst->serialize(); |
545 return srcData->size() == dstData->size() && | 625 return srcData->size() == dstData->size() && |
546 0 == memcmp(srcData->data(), dstData->data(), srcData->size()
); | 626 0 == memcmp(srcData->data(), dstData->data(), srcData->size()
); |
547 } | 627 } |
548 } | 628 } |
OLD | NEW |