| OLD | NEW |
| 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2016 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_transform.h" | 5 #include "ui/gfx/color_transform.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <list> | 9 #include <list> |
| 10 #include <memory> | 10 #include <memory> |
| 11 #include <sstream> | 11 #include <sstream> |
| 12 | 12 |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/strings/stringprintf.h" | 15 #include "base/strings/stringprintf.h" |
| 16 #include "third_party/qcms/src/qcms.h" | 16 #include "third_party/qcms/src/qcms.h" |
| 17 #include "ui/gfx/color_space.h" | 17 #include "ui/gfx/color_space.h" |
| 18 #include "ui/gfx/icc_profile.h" | 18 #include "ui/gfx/icc_profile.h" |
| 19 #include "ui/gfx/skia_color_space_util.h" | 19 #include "ui/gfx/skia_color_space_util.h" |
| 20 #include "ui/gfx/transform.h" | 20 #include "ui/gfx/transform.h" |
| 21 | 21 |
| 22 #ifndef THIS_MUST_BE_INCLUDED_AFTER_QCMS_H | 22 #ifndef THIS_MUST_BE_INCLUDED_AFTER_QCMS_H |
| 23 extern "C" { | 23 extern "C" { |
| 24 #include "third_party/qcms/src/chain.h" | 24 #include "third_party/qcms/src/chain.h" |
| 25 }; | 25 }; |
| 26 #endif | 26 #endif |
| 27 | 27 |
| 28 using std::abs; |
| 29 using std::copysign; |
| 28 using std::exp; | 30 using std::exp; |
| 29 using std::log; | 31 using std::log; |
| 30 using std::max; | 32 using std::max; |
| 31 using std::min; | 33 using std::min; |
| 32 using std::pow; | 34 using std::pow; |
| 33 using std::sqrt; | 35 using std::sqrt; |
| 34 | 36 |
| 35 namespace gfx { | 37 namespace gfx { |
| 36 | 38 |
| 37 namespace { | 39 namespace { |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 *result << ");" << std::endl; | 366 *result << ");" << std::endl; |
| 365 } | 367 } |
| 366 } | 368 } |
| 367 | 369 |
| 368 private: | 370 private: |
| 369 class Transform matrix_; | 371 class Transform matrix_; |
| 370 }; | 372 }; |
| 371 | 373 |
| 372 class ColorTransformSkTransferFn : public ColorTransformStep { | 374 class ColorTransformSkTransferFn : public ColorTransformStep { |
| 373 public: | 375 public: |
| 374 explicit ColorTransformSkTransferFn(const SkColorSpaceTransferFn& fn) | 376 explicit ColorTransformSkTransferFn(const SkColorSpaceTransferFn& fn, |
| 375 : fn_(fn) {} | 377 bool extended) |
| 378 : fn_(fn), extended_(extended) {} |
| 376 ColorTransformSkTransferFn* GetSkTransferFn() override { return this; } | 379 ColorTransformSkTransferFn* GetSkTransferFn() override { return this; } |
| 377 | 380 |
| 378 bool Join(ColorTransformStep* next_untyped) override { | 381 bool Join(ColorTransformStep* next_untyped) override { |
| 379 ColorTransformSkTransferFn* next = next_untyped->GetSkTransferFn(); | 382 ColorTransformSkTransferFn* next = next_untyped->GetSkTransferFn(); |
| 380 if (!next) | 383 if (!next) |
| 381 return false; | 384 return false; |
| 382 if (SkTransferFnsApproximatelyCancel(fn_, next->fn_)) { | 385 if (!extended_ && !next->extended_ && |
| 386 SkTransferFnsApproximatelyCancel(fn_, next->fn_)) { |
| 383 // Set to be the identity. | 387 // Set to be the identity. |
| 384 fn_.fA = 1; | 388 fn_.fA = 1; |
| 385 fn_.fB = 0; | 389 fn_.fB = 0; |
| 386 fn_.fC = 1; | 390 fn_.fC = 1; |
| 387 fn_.fD = 0; | 391 fn_.fD = 0; |
| 388 fn_.fE = 0; | 392 fn_.fE = 0; |
| 389 fn_.fF = 0; | 393 fn_.fF = 0; |
| 390 fn_.fG = 1; | 394 fn_.fG = 1; |
| 391 return true; | 395 return true; |
| 392 } | 396 } |
| 393 return false; | 397 return false; |
| 394 } | 398 } |
| 395 | 399 |
| 396 bool IsNull() override { return SkTransferFnIsApproximatelyIdentity(fn_); } | 400 bool IsNull() override { return SkTransferFnIsApproximatelyIdentity(fn_); } |
| 397 | 401 |
| 398 void Transform(ColorTransform::TriStim* colors, size_t num) const override { | 402 void Transform(ColorTransform::TriStim* colors, size_t num) const override { |
| 399 for (size_t i = 0; i < num; i++) { | 403 for (size_t i = 0; i < num; i++) { |
| 400 colors[i].set_x(SkTransferFnEval(fn_, colors[i].x())); | 404 ColorTransform::TriStim& c = colors[i]; |
| 401 colors[i].set_y(SkTransferFnEval(fn_, colors[i].y())); | 405 if (extended_) { |
| 402 colors[i].set_z(SkTransferFnEval(fn_, colors[i].z())); | 406 c.set_x(copysign(SkTransferFnEval(fn_, abs(c.x())), c.x())); |
| 407 c.set_y(copysign(SkTransferFnEval(fn_, abs(c.y())), c.y())); |
| 408 c.set_z(copysign(SkTransferFnEval(fn_, abs(c.z())), c.z())); |
| 409 } else { |
| 410 c.set_x(SkTransferFnEval(fn_, c.x())); |
| 411 c.set_y(SkTransferFnEval(fn_, c.y())); |
| 412 c.set_z(SkTransferFnEval(fn_, c.z())); |
| 413 } |
| 403 } | 414 } |
| 404 } | 415 } |
| 405 | 416 |
| 406 bool CanAppendShaderSource() override { return true; } | 417 bool CanAppendShaderSource() override { return true; } |
| 407 | 418 |
| 408 void AppendShaderSourceChannel(std::stringstream* result, const char* value) { | 419 void AppendShaderSourceChannel(std::stringstream* result, |
| 420 const std::string& value) { |
| 421 std::string abs_value = "abs(" + value + ")"; |
| 409 const float kEpsilon = 1.f / 1024.f; | 422 const float kEpsilon = 1.f / 1024.f; |
| 410 | 423 |
| 411 // Construct the linear segment | 424 // Construct the linear segment |
| 412 // linear = C * x + F | 425 // linear = C * x + F |
| 413 // Elide operations that will be close to the identity. | 426 // Elide operations that will be close to the identity. |
| 414 std::string linear = value; | 427 std::string linear = value; |
| 415 if (std::abs(fn_.fC - 1.f) > kEpsilon) | 428 if (std::abs(fn_.fC - 1.f) > kEpsilon) |
| 416 linear = Str(fn_.fC) + " * " + linear; | 429 linear = Str(fn_.fC) + " * " + linear; |
| 417 if (std::abs(fn_.fF) > kEpsilon) | 430 if (std::abs(fn_.fF) > kEpsilon) |
| 418 linear = linear + " + " + Str(fn_.fF); | 431 linear = linear + " + " + Str(fn_.fF); |
| 419 | 432 |
| 420 // Construct the nonlinear segment. | 433 // Construct the nonlinear segment. |
| 421 // nonlinear = pow(A * x + B, G) + E | 434 // nonlinear = pow(A * x + B, G) + E |
| 422 // Elide operations (especially the pow) that will be close to the | 435 // Elide operations (especially the pow) that will be close to the |
| 423 // identity. | 436 // identity. |
| 424 std::string nonlinear = value; | 437 std::string nonlinear = extended_ ? abs_value : value; |
| 425 if (std::abs(fn_.fA - 1.f) > kEpsilon) | 438 if (std::abs(fn_.fA - 1.f) > kEpsilon) |
| 426 nonlinear = Str(fn_.fA) + " * " + nonlinear; | 439 nonlinear = Str(fn_.fA) + " * " + nonlinear; |
| 427 if (std::abs(fn_.fB) > kEpsilon) | 440 if (std::abs(fn_.fB) > kEpsilon) |
| 428 nonlinear = nonlinear + " + " + Str(fn_.fB); | 441 nonlinear = nonlinear + " + " + Str(fn_.fB); |
| 429 if (std::abs(fn_.fG - 1.f) > kEpsilon) | 442 if (std::abs(fn_.fG - 1.f) > kEpsilon) |
| 430 nonlinear = "pow(" + nonlinear + ", " + Str(fn_.fG) + ")"; | 443 nonlinear = "pow(" + nonlinear + ", " + Str(fn_.fG) + ")"; |
| 431 if (std::abs(fn_.fE) > kEpsilon) | 444 if (std::abs(fn_.fE) > kEpsilon) |
| 432 nonlinear = nonlinear + " + " + Str(fn_.fE); | 445 nonlinear = nonlinear + " + " + Str(fn_.fE); |
| 446 if (extended_) { |
| 447 if (nonlinear == abs_value) |
| 448 nonlinear = value; |
| 449 else |
| 450 nonlinear = "sign(" + value + ") * (" + nonlinear + ")"; |
| 451 } |
| 433 | 452 |
| 434 // Add both parts, skpping the if clause if possible. | 453 // Add both parts, skpping the if clause if possible. |
| 435 if (fn_.fD > kEpsilon) { | 454 if (fn_.fD > kEpsilon) { |
| 436 *result << " if (" << value << " < " << Str(fn_.fD) << ")" << std::endl; | 455 if (extended_) { |
| 456 *result << " if (" << abs_value << " < " << Str(fn_.fD) << ")" |
| 457 << std::endl; |
| 458 } else { |
| 459 *result << " if (" << value << " < " << Str(fn_.fD) << ")" |
| 460 << std::endl; |
| 461 } |
| 437 *result << " " << value << " = " << linear << ";" << std::endl; | 462 *result << " " << value << " = " << linear << ";" << std::endl; |
| 438 *result << " else" << std::endl; | 463 *result << " else" << std::endl; |
| 439 *result << " " << value << " = " << nonlinear << ";" << std::endl; | 464 *result << " " << value << " = " << nonlinear << ";" << std::endl; |
| 440 } else { | 465 } else { |
| 441 *result << " " << value << " = " << nonlinear << ";" << std::endl; | 466 *result << " " << value << " = " << nonlinear << ";" << std::endl; |
| 442 } | 467 } |
| 443 } | 468 } |
| 444 | 469 |
| 445 void AppendShaderSource(std::stringstream* result) override { | 470 void AppendShaderSource(std::stringstream* result) override { |
| 446 // Append the transfer function for each channel. | 471 // Append the transfer function for each channel. |
| 447 AppendShaderSourceChannel(result, "color.r"); | 472 AppendShaderSourceChannel(result, "color.r"); |
| 448 AppendShaderSourceChannel(result, "color.g"); | 473 AppendShaderSourceChannel(result, "color.g"); |
| 449 AppendShaderSourceChannel(result, "color.b"); | 474 AppendShaderSourceChannel(result, "color.b"); |
| 450 } | 475 } |
| 451 | 476 |
| 452 private: | 477 private: |
| 453 SkColorSpaceTransferFn fn_; | 478 SkColorSpaceTransferFn fn_; |
| 479 // True if the transfer function is extended to be defined for all real |
| 480 // values. |
| 481 const bool extended_ = false; |
| 454 }; | 482 }; |
| 455 | 483 |
| 456 class ColorTransformFromLinear : public ColorTransformStep { | 484 class ColorTransformFromLinear : public ColorTransformStep { |
| 457 public: | 485 public: |
| 458 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer) | 486 explicit ColorTransformFromLinear(ColorSpace::TransferID transfer) |
| 459 : transfer_(transfer) {} | 487 : transfer_(transfer) {} |
| 460 ColorTransformFromLinear* GetFromLinear() override { return this; } | 488 ColorTransformFromLinear* GetFromLinear() override { return this; } |
| 461 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } | 489 bool IsNull() override { return transfer_ == ColorSpace::TransferID::LINEAR; } |
| 462 void Transform(ColorTransform::TriStim* colors, size_t num) const override { | 490 void Transform(ColorTransform::TriStim* colors, size_t num) const override { |
| 463 for (size_t i = 0; i < num; i++) { | 491 for (size_t i = 0; i < num; i++) { |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 676 base::MakeUnique<ColorTransformMatrix>(Invert(GetTransferMatrix(from)))); | 704 base::MakeUnique<ColorTransformMatrix>(Invert(GetTransferMatrix(from)))); |
| 677 | 705 |
| 678 // If the target color space is not defined, just apply the adjust and | 706 // If the target color space is not defined, just apply the adjust and |
| 679 // tranfer matrices. This path is used by YUV to RGB color conversion | 707 // tranfer matrices. This path is used by YUV to RGB color conversion |
| 680 // when full color conversion is not enabled. | 708 // when full color conversion is not enabled. |
| 681 if (!to.IsValid()) | 709 if (!to.IsValid()) |
| 682 return; | 710 return; |
| 683 | 711 |
| 684 SkColorSpaceTransferFn to_linear_fn; | 712 SkColorSpaceTransferFn to_linear_fn; |
| 685 if (from.GetTransferFunction(&to_linear_fn)) { | 713 if (from.GetTransferFunction(&to_linear_fn)) { |
| 686 steps_.push_back( | 714 steps_.push_back(base::MakeUnique<ColorTransformSkTransferFn>( |
| 687 base::MakeUnique<ColorTransformSkTransferFn>(to_linear_fn)); | 715 to_linear_fn, from.HasExtendedSkTransferFn())); |
| 688 } else { | 716 } else { |
| 689 steps_.push_back(base::MakeUnique<ColorTransformToLinear>(from.transfer_)); | 717 steps_.push_back(base::MakeUnique<ColorTransformToLinear>(from.transfer_)); |
| 690 } | 718 } |
| 691 | 719 |
| 692 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) { | 720 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) { |
| 693 // BT2020 CL is a special case. | 721 // BT2020 CL is a special case. |
| 694 steps_.push_back(base::MakeUnique<ColorTransformFromBT2020CL>()); | 722 steps_.push_back(base::MakeUnique<ColorTransformFromBT2020CL>()); |
| 695 } | 723 } |
| 696 steps_.push_back( | 724 steps_.push_back( |
| 697 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from))); | 725 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from))); |
| 698 | 726 |
| 699 steps_.push_back( | 727 steps_.push_back( |
| 700 base::MakeUnique<ColorTransformMatrix>(Invert(GetPrimaryTransform(to)))); | 728 base::MakeUnique<ColorTransformMatrix>(Invert(GetPrimaryTransform(to)))); |
| 701 if (to.matrix_ == ColorSpace::MatrixID::BT2020_CL) { | 729 if (to.matrix_ == ColorSpace::MatrixID::BT2020_CL) { |
| 702 // BT2020 CL is a special case. | 730 // BT2020 CL is a special case. |
| 703 steps_.push_back(base::MakeUnique<ColorTransformToBT2020CL>()); | 731 steps_.push_back(base::MakeUnique<ColorTransformToBT2020CL>()); |
| 704 } | 732 } |
| 705 | 733 |
| 706 SkColorSpaceTransferFn from_linear_fn; | 734 SkColorSpaceTransferFn from_linear_fn; |
| 707 if (to.GetInverseTransferFunction(&from_linear_fn)) { | 735 if (to.GetInverseTransferFunction(&from_linear_fn)) { |
| 708 steps_.push_back( | 736 steps_.push_back(base::MakeUnique<ColorTransformSkTransferFn>( |
| 709 base::MakeUnique<ColorTransformSkTransferFn>(from_linear_fn)); | 737 from_linear_fn, to.HasExtendedSkTransferFn())); |
| 710 } else { | 738 } else { |
| 711 steps_.push_back(base::MakeUnique<ColorTransformFromLinear>(to.transfer_)); | 739 steps_.push_back(base::MakeUnique<ColorTransformFromLinear>(to.transfer_)); |
| 712 } | 740 } |
| 713 | 741 |
| 714 steps_.push_back( | 742 steps_.push_back( |
| 715 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to))); | 743 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to))); |
| 716 | 744 |
| 717 steps_.push_back( | 745 steps_.push_back( |
| 718 base::MakeUnique<ColorTransformMatrix>(Invert(GetRangeAdjustMatrix(to)))); | 746 base::MakeUnique<ColorTransformMatrix>(Invert(GetRangeAdjustMatrix(to)))); |
| 719 } | 747 } |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 885 const ColorSpace& to, | 913 const ColorSpace& to, |
| 886 Intent intent) { | 914 Intent intent) { |
| 887 return std::unique_ptr<ColorTransform>( | 915 return std::unique_ptr<ColorTransform>( |
| 888 new ColorTransformInternal(from, to, intent)); | 916 new ColorTransformInternal(from, to, intent)); |
| 889 } | 917 } |
| 890 | 918 |
| 891 ColorTransform::ColorTransform() {} | 919 ColorTransform::ColorTransform() {} |
| 892 ColorTransform::~ColorTransform() {} | 920 ColorTransform::~ColorTransform() {} |
| 893 | 921 |
| 894 } // namespace gfx | 922 } // namespace gfx |
| OLD | NEW |