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 |