| 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 <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "third_party/skia/include/core/SkColorSpaceXform.h" |
| 11 #include "third_party/skia/include/core/SkImageInfo.h" |
| 10 #include "ui/gfx/color_space.h" | 12 #include "ui/gfx/color_space.h" |
| 11 #include "ui/gfx/icc_profile.h" | 13 #include "ui/gfx/icc_profile.h" |
| 12 #include "ui/gfx/transform.h" | 14 #include "ui/gfx/transform.h" |
| 13 #include "third_party/qcms/src/qcms.h" | |
| 14 | |
| 15 #ifndef THIS_MUST_BE_INCLUDED_AFTER_QCMS_H | |
| 16 extern "C" { | |
| 17 #include "third_party/qcms/src/chain.h" | |
| 18 }; | |
| 19 #endif | |
| 20 | 15 |
| 21 namespace gfx { | 16 namespace gfx { |
| 22 | 17 |
| 23 Transform Invert(const Transform& t) { | 18 Transform Invert(const Transform& t) { |
| 24 Transform ret = t; | 19 Transform ret = t; |
| 25 if (!t.GetInverse(&ret)) { | 20 if (!t.GetInverse(&ret)) { |
| 26 LOG(ERROR) << "Inverse should alsways be possible."; | 21 LOG(ERROR) << "Inverse should alsways be possible."; |
| 27 } | 22 } |
| 28 return ret; | 23 return ret; |
| 29 } | 24 } |
| (...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 558 case ColorSpace::RangeID::UNSPECIFIED: | 553 case ColorSpace::RangeID::UNSPECIFIED: |
| 559 return Transform(); | 554 return Transform(); |
| 560 | 555 |
| 561 case ColorSpace::RangeID::DERIVED: | 556 case ColorSpace::RangeID::DERIVED: |
| 562 case ColorSpace::RangeID::LIMITED: | 557 case ColorSpace::RangeID::LIMITED: |
| 563 break; | 558 break; |
| 564 } | 559 } |
| 565 switch (matrix) { | 560 switch (matrix) { |
| 566 case ColorSpace::MatrixID::RGB: | 561 case ColorSpace::MatrixID::RGB: |
| 567 case ColorSpace::MatrixID::YCOCG: | 562 case ColorSpace::MatrixID::YCOCG: |
| 563 DCHECK(0); |
| 568 return Transform(255.0f / 219.0f, 0.0f, 0.0f, -16.0f / 219.0f, // 1 | 564 return Transform(255.0f / 219.0f, 0.0f, 0.0f, -16.0f / 219.0f, // 1 |
| 569 0.0f, 255.0f / 219.0f, 0.0f, -16.0f / 219.0f, // 2 | 565 0.0f, 255.0f / 219.0f, 0.0f, -16.0f / 219.0f, // 2 |
| 570 0.0f, 0.0f, 255.0f / 219.0f, -16.0f / 219.0f, // 3 | 566 0.0f, 0.0f, 255.0f / 219.0f, -16.0f / 219.0f, // 3 |
| 571 0.0f, 0.0f, 0.0f, 1.0f); // 4 | 567 0.0f, 0.0f, 0.0f, 1.0f); // 4 |
| 572 | 568 |
| 573 case ColorSpace::MatrixID::BT709: | 569 case ColorSpace::MatrixID::BT709: |
| 574 case ColorSpace::MatrixID::UNSPECIFIED: | 570 case ColorSpace::MatrixID::UNSPECIFIED: |
| 575 case ColorSpace::MatrixID::RESERVED: | 571 case ColorSpace::MatrixID::RESERVED: |
| 576 case ColorSpace::MatrixID::FCC: | 572 case ColorSpace::MatrixID::FCC: |
| 577 case ColorSpace::MatrixID::BT470BG: | 573 case ColorSpace::MatrixID::BT470BG: |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 private: | 669 private: |
| 674 ColorSpace from_; | 670 ColorSpace from_; |
| 675 ColorSpace to_; | 671 ColorSpace to_; |
| 676 | 672 |
| 677 // a_ -> tolinear -> b_ -> fromlinear -> c_; | 673 // a_ -> tolinear -> b_ -> fromlinear -> c_; |
| 678 Transform a_; | 674 Transform a_; |
| 679 Transform b_; | 675 Transform b_; |
| 680 Transform c_; | 676 Transform c_; |
| 681 }; | 677 }; |
| 682 | 678 |
| 683 class QCMSColorTransform : public ColorTransform { | 679 class SkColorTransform : public ColorTransform { |
| 684 public: | 680 public: |
| 685 // Takes ownership of the profiles | 681 SkColorTransform(SkColorSpace* src, SkColorSpace* dst) { |
| 686 QCMSColorTransform(qcms_profile* from, qcms_profile* to) | 682 DCHECK(src && dst); |
| 687 : from_(from), to_(to) {} | 683 sk_xform_ = SkColorSpaceXform::New(src, dst); |
| 688 ~QCMSColorTransform() override { | 684 DCHECK(sk_xform_); |
| 689 qcms_profile_release(from_); | |
| 690 qcms_profile_release(to_); | |
| 691 } | 685 } |
| 686 private: |
| 692 void transform(TriStim* colors, size_t num) override { | 687 void transform(TriStim* colors, size_t num) override { |
| 693 CHECK(sizeof(TriStim) == sizeof(float[3])); | 688 for (size_t i = 0; i < num; ++i) { |
| 694 // QCMS doesn't like numbers outside 0..1 | 689 float in[4] = {colors[i].x(), colors[i].y(), colors[i].z(), 1.f}; |
| 695 for (size_t i = 0; i < num; i++) { | 690 float out[4] = {0, 0, 0, 1}; |
| 696 colors[i].set_x(fmin(1.0f, fmax(0.0f, colors[i].x()))); | 691 sk_xform_->apply(SkColorSpaceXform::kRGBA_F32_ColorFormat, out, |
| 697 colors[i].set_y(fmin(1.0f, fmax(0.0f, colors[i].y()))); | 692 SkColorSpaceXform::kRGBA_F32_ColorFormat, in, 1, |
| 698 colors[i].set_z(fmin(1.0f, fmax(0.0f, colors[i].z()))); | 693 kOpaque_SkAlphaType); |
| 699 } | 694 } |
| 700 qcms_chain_transform(from_, to_, reinterpret_cast<float*>(colors), | |
| 701 reinterpret_cast<float*>(colors), num * 3); | |
| 702 } | 695 } |
| 703 | 696 std::unique_ptr<SkColorSpaceXform> sk_xform_; |
| 704 private: | |
| 705 qcms_profile *from_, *to_; | |
| 706 }; | 697 }; |
| 707 | 698 |
| 708 class ChainColorTransform : public ColorTransform { | 699 class ChainColorTransform : public ColorTransform { |
| 709 public: | 700 public: |
| 710 ChainColorTransform(std::unique_ptr<ColorTransform> a, | 701 ChainColorTransform(std::unique_ptr<ColorTransform> a, |
| 711 std::unique_ptr<ColorTransform> b) | 702 std::unique_ptr<ColorTransform> b) |
| 712 : a_(std::move(a)), b_(std::move(b)) {} | 703 : a_(std::move(a)), b_(std::move(b)) {} |
| 713 | 704 |
| 714 private: | 705 private: |
| 715 void transform(TriStim* colors, size_t num) override { | 706 void transform(TriStim* colors, size_t num) override { |
| 716 a_->transform(colors, num); | 707 a_->transform(colors, num); |
| 717 b_->transform(colors, num); | 708 b_->transform(colors, num); |
| 718 } | 709 } |
| 719 std::unique_ptr<ColorTransform> a_; | 710 std::unique_ptr<ColorTransform> a_; |
| 720 std::unique_ptr<ColorTransform> b_; | 711 std::unique_ptr<ColorTransform> b_; |
| 721 }; | 712 }; |
| 722 | 713 |
| 723 qcms_profile* GetQCMSProfileIfAvailable(const ColorSpace& color_space) { | 714 sk_sp<SkColorSpace> GetXYZD50ColorSpace() { |
| 724 ICCProfile icc_profile = ICCProfile::FromColorSpace(color_space); | 715 printf("GetXYZD50ColorSpace\n"); |
| 725 if (icc_profile.GetData().empty()) | 716 SkMatrix44 should_be_eye; |
| 726 return nullptr; | 717 SkColorSpacePrimaries primaries; |
| 727 return qcms_profile_from_memory(icc_profile.GetData().data(), | 718 primaries.fRX = 1.0f; |
| 728 icc_profile.GetData().size()); | 719 primaries.fRY = 0.0f; |
| 729 } | 720 primaries.fGX = 0.0f; |
| 721 primaries.fGY = 1.0f; |
| 722 primaries.fBX = 0.0f; |
| 723 primaries.fBY = 0.0f; |
| 724 primaries.fWX = 0.34567f; |
| 725 primaries.fWY = 0.35850f; |
| 726 primaries.toXYZD50(&should_be_eye); |
| 727 should_be_eye.dump(); |
| 730 | 728 |
| 731 qcms_profile* GetXYZD50Profile() { | 729 SkMatrix44 to_xyzd50_matrix; |
| 732 // QCMS is trixy, it has a datatype called qcms_CIE_xyY, but what it expects | 730 to_xyzd50_matrix.dump(); |
| 733 // is in fact not xyY color coordinates, it just wants the x/y values of the | 731 return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, to_xyzd5
0_matrix); |
| 734 // primaries with Y equal to 1.0. | |
| 735 qcms_CIE_xyYTRIPLE xyz; | |
| 736 qcms_CIE_xyY w; | |
| 737 xyz.red.x = 1.0f; | |
| 738 xyz.red.y = 0.0f; | |
| 739 xyz.red.Y = 1.0f; | |
| 740 xyz.green.x = 0.0f; | |
| 741 xyz.green.y = 1.0f; | |
| 742 xyz.green.Y = 1.0f; | |
| 743 xyz.blue.x = 0.0f; | |
| 744 xyz.blue.y = 0.0f; | |
| 745 xyz.blue.Y = 1.0f; | |
| 746 w.x = 0.34567f; | |
| 747 w.y = 0.35850f; | |
| 748 w.Y = 1.0f; | |
| 749 return qcms_profile_create_rgb_with_gamma(w, xyz, 1.0f); | |
| 750 } | 732 } |
| 751 | 733 |
| 752 std::unique_ptr<ColorTransform> ColorTransform::NewColorTransform( | 734 std::unique_ptr<ColorTransform> ColorTransform::NewColorTransform( |
| 753 const ColorSpace& from, | 735 const ColorSpace& src, |
| 754 const ColorSpace& to, | 736 const ColorSpace& dst, |
| 755 Intent intent) { | 737 Intent intent) { |
| 756 qcms_profile* from_profile = GetQCMSProfileIfAvailable(from); | 738 sk_sp<SkColorSpace> src_sk_color_space = src.ToSkColorSpace(); |
| 757 qcms_profile* to_profile = GetQCMSProfileIfAvailable(to); | 739 sk_sp<SkColorSpace> dst_sk_color_space = dst.ToSkColorSpace(); |
| 758 if (from_profile) { | 740 |
| 759 if (to_profile) { | 741 printf("XFORM: %p %p\n", src_sk_color_space.get(), dst_sk_color_space.get()); |
| 760 return std::unique_ptr<ColorTransform>( | 742 |
| 761 new QCMSColorTransform(from_profile, to_profile)); | 743 // Single SkColorSpaceXForm object. |
| 762 } else { | 744 if (src_sk_color_space && dst_sk_color_space) { |
| 763 return std::unique_ptr<ColorTransform>(new ChainColorTransform( | 745 return std::unique_ptr<ColorTransform>(new SkColorTransform( |
| 764 std::unique_ptr<ColorTransform>( | 746 src_sk_color_space.get(), dst_sk_color_space.get())); |
| 765 new QCMSColorTransform(from_profile, GetXYZD50Profile())), | 747 } |
| 766 std::unique_ptr<ColorTransform>(new ColorSpaceToColorSpaceTransform( | 748 |
| 767 ColorSpace::CreateXYZD50(), to, intent)))); | 749 // Single ColorSpaceToColorSpaceTransform object. |
| 768 } | 750 if (!src_sk_color_space && !dst_sk_color_space) { |
| 751 return std::unique_ptr<ColorTransform>( |
| 752 new ColorSpaceToColorSpaceTransform(src, dst, intent)); |
| 753 } |
| 754 |
| 755 // Chained SkColorSpaceXForm then ColorSpaceToColorSpaceTransform or |
| 756 // ColorSpaceToColorSpaceTransform then SkColorSpaceXForm. |
| 757 std::unique_ptr<ColorTransform> src_to_xyzD50; |
| 758 std::unique_ptr<ColorTransform> xyzD50_to_dst; |
| 759 |
| 760 if (src_sk_color_space) { |
| 761 src_to_xyzD50.reset(new SkColorTransform( |
| 762 src_sk_color_space.get(), GetXYZD50ColorSpace().get())); |
| 769 } else { | 763 } else { |
| 770 if (to_profile) { | 764 src_to_xyzD50.reset(new ColorSpaceToColorSpaceTransform( |
| 771 return std::unique_ptr<ColorTransform>(new ChainColorTransform( | 765 src, ColorSpace::CreateXYZD50(), intent)); |
| 772 std::unique_ptr<ColorTransform>(new ColorSpaceToColorSpaceTransform( | |
| 773 from, ColorSpace::CreateXYZD50(), intent)), | |
| 774 std::unique_ptr<ColorTransform>( | |
| 775 new QCMSColorTransform(GetXYZD50Profile(), to_profile)))); | |
| 776 } else { | |
| 777 return std::unique_ptr<ColorTransform>( | |
| 778 new ColorSpaceToColorSpaceTransform(from, to, intent)); | |
| 779 } | |
| 780 } | 766 } |
| 767 if (dst_sk_color_space) { |
| 768 src_to_xyzD50.reset(new SkColorTransform( |
| 769 GetXYZD50ColorSpace().get(), dst_sk_color_space.get())); |
| 770 } else { |
| 771 xyzD50_to_dst.reset(new ColorSpaceToColorSpaceTransform( |
| 772 ColorSpace::CreateXYZD50(), dst, intent)); |
| 773 } |
| 774 return std::unique_ptr<ColorTransform>(new ChainColorTransform( |
| 775 std::move(src_to_xyzD50), std::move(xyzD50_to_dst))); |
| 781 } | 776 } |
| 782 | 777 |
| 783 } // namespace gfx | 778 } // namespace gfx |
| OLD | NEW |