Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: ui/gfx/color_transform.cc

Issue 2755953005: color: Use SkColorSpaceXform instead of QCMS for LUTs (Closed)
Patch Set: Rebase Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/gfx/color_space.cc ('k') | ui/gfx/icc_profile.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/skia/include/core/SkColor.h"
17 #include "third_party/skia/include/core/SkColorSpaceXform.h"
17 #include "ui/gfx/color_space.h" 18 #include "ui/gfx/color_space.h"
18 #include "ui/gfx/icc_profile.h" 19 #include "ui/gfx/icc_profile.h"
19 #include "ui/gfx/skia_color_space_util.h" 20 #include "ui/gfx/skia_color_space_util.h"
20 #include "ui/gfx/transform.h" 21 #include "ui/gfx/transform.h"
21 22
22 #ifndef THIS_MUST_BE_INCLUDED_AFTER_QCMS_H
23 extern "C" {
24 #include "third_party/qcms/src/chain.h"
25 };
26 #endif
27
28 using std::abs; 23 using std::abs;
29 using std::copysign; 24 using std::copysign;
30 using std::exp; 25 using std::exp;
31 using std::log; 26 using std::log;
32 using std::max; 27 using std::max;
33 using std::min; 28 using std::min;
34 using std::pow; 29 using std::pow;
35 using std::sqrt; 30 using std::sqrt;
36 using std::endl; 31 using std::endl;
37 32
38 namespace gfx { 33 namespace gfx {
39 34
40 namespace { 35 namespace {
41 36
42 void InitStringStream(std::stringstream* ss) { 37 void InitStringStream(std::stringstream* ss) {
43 ss->imbue(std::locale::classic()); 38 ss->imbue(std::locale::classic());
44 ss->precision(8); 39 ss->precision(8);
45 *ss << std::scientific; 40 *ss << std::scientific;
46 } 41 }
47 42
48 std::string Str(float f) { 43 std::string Str(float f) {
49 std::stringstream ss; 44 std::stringstream ss;
50 InitStringStream(&ss); 45 InitStringStream(&ss);
51 ss << f; 46 ss << f;
52 return ss.str(); 47 return ss.str();
53 } 48 }
54 49
55 // Helper for scoped QCMS profiles.
56 struct QcmsProfileDeleter {
57 void operator()(qcms_profile* p) {
58 if (p) {
59 qcms_profile_release(p);
60 }
61 }
62 };
63 using ScopedQcmsProfile = std::unique_ptr<qcms_profile, QcmsProfileDeleter>;
64
65 Transform Invert(const Transform& t) { 50 Transform Invert(const Transform& t) {
66 Transform ret = t; 51 Transform ret = t;
67 if (!t.GetInverse(&ret)) { 52 if (!t.GetInverse(&ret)) {
68 LOG(ERROR) << "Inverse should always be possible."; 53 LOG(ERROR) << "Inverse should always be possible.";
69 } 54 }
70 return ret; 55 return ret;
71 } 56 }
72 57
73 float FromLinear(ColorSpace::TransferID id, float v) { 58 float FromLinear(ColorSpace::TransferID id, float v) {
74 switch (id) { 59 switch (id) {
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 } 220 }
236 221
237 } // namespace 222 } // namespace
238 223
239 class ColorTransformMatrix; 224 class ColorTransformMatrix;
240 class ColorTransformSkTransferFn; 225 class ColorTransformSkTransferFn;
241 class ColorTransformFromLinear; 226 class ColorTransformFromLinear;
242 class ColorTransformToBT2020CL; 227 class ColorTransformToBT2020CL;
243 class ColorTransformFromBT2020CL; 228 class ColorTransformFromBT2020CL;
244 class ColorTransformNull; 229 class ColorTransformNull;
245 class QCMSColorTransform; 230 class SkiaColorTransform;
246 231
247 class ColorTransformStep { 232 class ColorTransformStep {
248 public: 233 public:
249 ColorTransformStep() {} 234 ColorTransformStep() {}
250 virtual ~ColorTransformStep() {} 235 virtual ~ColorTransformStep() {}
251 virtual ColorTransformFromLinear* GetFromLinear() { return nullptr; } 236 virtual ColorTransformFromLinear* GetFromLinear() { return nullptr; }
252 virtual ColorTransformToBT2020CL* GetToBT2020CL() { return nullptr; } 237 virtual ColorTransformToBT2020CL* GetToBT2020CL() { return nullptr; }
253 virtual ColorTransformFromBT2020CL* GetFromBT2020CL() { return nullptr; } 238 virtual ColorTransformFromBT2020CL* GetFromBT2020CL() { return nullptr; }
254 virtual ColorTransformSkTransferFn* GetSkTransferFn() { return nullptr; } 239 virtual ColorTransformSkTransferFn* GetSkTransferFn() { return nullptr; }
255 virtual ColorTransformMatrix* GetMatrix() { return nullptr; } 240 virtual ColorTransformMatrix* GetMatrix() { return nullptr; }
256 virtual ColorTransformNull* GetNull() { return nullptr; } 241 virtual ColorTransformNull* GetNull() { return nullptr; }
257 virtual QCMSColorTransform* GetQCMS() { return nullptr; } 242 virtual SkiaColorTransform* GetSkia() { return nullptr; }
258 243
259 // Join methods, returns true if the |next| transform was successfully 244 // Join methods, returns true if the |next| transform was successfully
260 // assimilated into |this|. 245 // assimilated into |this|.
261 // If Join() returns true, |next| is no longer needed and can be deleted. 246 // If Join() returns true, |next| is no longer needed and can be deleted.
262 virtual bool Join(ColorTransformStep* next) { return false; } 247 virtual bool Join(ColorTransformStep* next) { return false; }
263 248
264 // Return true if this is a null transform. 249 // Return true if this is a null transform.
265 virtual bool IsNull() { return false; } 250 virtual bool IsNull() { return false; }
266 virtual void Transform(ColorTransform::TriStim* color, size_t num) const = 0; 251 virtual void Transform(ColorTransform::TriStim* color, size_t num) const = 0;
267 virtual bool CanAppendShaderSource() { return false; } 252 virtual bool CanAppendShaderSource() { return false; }
268 // In the shader, |hdr| will appear before |src|, so any helper functions that 253 // In the shader, |hdr| will appear before |src|, so any helper functions that
269 // are created should be put in |hdr|. Any helper functions should have 254 // are created should be put in |hdr|. Any helper functions should have
270 // |step_index| included in the function name, to ensure that there are no 255 // |step_index| included in the function name, to ensure that there are no
271 // naming conflicts. 256 // naming conflicts.
272 virtual void AppendShaderSource(std::stringstream* hdr, 257 virtual void AppendShaderSource(std::stringstream* hdr,
273 std::stringstream* src, 258 std::stringstream* src,
274 size_t step_index) const { 259 size_t step_index) const {
275 NOTREACHED(); 260 NOTREACHED();
276 } 261 }
277 262
278 private: 263 private:
279 DISALLOW_COPY_AND_ASSIGN(ColorTransformStep); 264 DISALLOW_COPY_AND_ASSIGN(ColorTransformStep);
280 }; 265 };
281 266
282 class ColorTransformInternal : public ColorTransform { 267 class ColorTransformInternal : public ColorTransform {
283 public: 268 public:
284 ColorTransformInternal(const ColorSpace& from, 269 ColorTransformInternal(const ColorSpace& src,
285 const ColorSpace& to, 270 const ColorSpace& dst,
286 Intent intent); 271 Intent intent);
287 ~ColorTransformInternal() override; 272 ~ColorTransformInternal() override;
288 273
289 gfx::ColorSpace GetSrcColorSpace() const override { return src_; }; 274 gfx::ColorSpace GetSrcColorSpace() const override { return src_; };
290 gfx::ColorSpace GetDstColorSpace() const override { return dst_; }; 275 gfx::ColorSpace GetDstColorSpace() const override { return dst_; };
291 276
292 void Transform(TriStim* colors, size_t num) const override { 277 void Transform(TriStim* colors, size_t num) const override {
293 for (const auto& step : steps_) 278 for (const auto& step : steps_)
294 step->Transform(colors, num); 279 step->Transform(colors, num);
295 } 280 }
296 bool CanGetShaderSource() const override; 281 bool CanGetShaderSource() const override;
297 std::string GetShaderSource() const override; 282 std::string GetShaderSource() const override;
298 bool IsIdentity() const override { return steps_.empty(); } 283 bool IsIdentity() const override { return steps_.empty(); }
299 size_t NumberOfStepsForTesting() const override { return steps_.size(); } 284 size_t NumberOfStepsForTesting() const override { return steps_.size(); }
300 285
301 private: 286 private:
302 void AppendColorSpaceToColorSpaceTransform(ColorSpace from, 287 void AppendColorSpaceToColorSpaceTransform(ColorSpace src,
303 const ColorSpace& to, 288 const ColorSpace& dst,
304 ColorTransform::Intent intent); 289 ColorTransform::Intent intent);
305 void Simplify(); 290 void Simplify();
306 291
307 // Retrieve the ICC profile from which |color_space| was created, only if that 292 // Retrieve the SkColorSpace for the ICC profile from which |color_space| was
308 // is a more precise representation of the color space than the primaries and 293 // created, only if that is a more precise than the parametric representation.
309 // transfer function in |color_space|. 294 sk_sp<SkColorSpace> GetSkColorSpaceIfNecessary(const ColorSpace& color_space);
310 ScopedQcmsProfile GetQCMSProfileIfNecessary(const ColorSpace& color_space);
311 295
312 std::list<std::unique_ptr<ColorTransformStep>> steps_; 296 std::list<std::unique_ptr<ColorTransformStep>> steps_;
313 gfx::ColorSpace src_; 297 gfx::ColorSpace src_;
314 gfx::ColorSpace dst_; 298 gfx::ColorSpace dst_;
315 }; 299 };
316 300
317 class ColorTransformNull : public ColorTransformStep { 301 class ColorTransformNull : public ColorTransformStep {
318 public: 302 public:
319 ColorTransformNull* GetNull() override { return this; } 303 ColorTransformNull* GetNull() override { return this; }
320 bool IsNull() override { return true; } 304 bool IsNull() override { return true; }
(...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after
810 794
811 *src << " color.rgb = BT2020_YUV_to_RYB_Step" << step_index 795 *src << " color.rgb = BT2020_YUV_to_RYB_Step" << step_index
812 << "(color.rgb);" << endl; 796 << "(color.rgb);" << endl;
813 } 797 }
814 798
815 private: 799 private:
816 bool null_ = false; 800 bool null_ = false;
817 }; 801 };
818 802
819 void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform( 803 void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform(
820 ColorSpace from, 804 ColorSpace src,
821 const ColorSpace& to, 805 const ColorSpace& dst,
822 ColorTransform::Intent intent) { 806 ColorTransform::Intent intent) {
823 if (intent == ColorTransform::Intent::INTENT_PERCEPTUAL) { 807 if (intent == ColorTransform::Intent::INTENT_PERCEPTUAL) {
824 switch (from.transfer_) { 808 switch (src.transfer_) {
825 case ColorSpace::TransferID::BT709: 809 case ColorSpace::TransferID::BT709:
826 case ColorSpace::TransferID::SMPTE170M: 810 case ColorSpace::TransferID::SMPTE170M:
827 // SMPTE 1886 suggests that we should be using gamma 2.4 for BT709 811 // SMPTE 1886 suggests that we should be using gamma 2.4 for BT709
828 // content. However, most displays actually use a gamma of 2.2, and 812 // content. However, most displays actually use a gamma of 2.2, and
829 // user studies shows that users don't really care. Using the same 813 // user studies shows that users don't really care. Using the same
830 // gamma as the display will let us optimize a lot more, so lets stick 814 // gamma as the display will let us optimize a lot more, so lets stick
831 // with using the SRGB transfer function. 815 // with using the SRGB transfer function.
832 from.transfer_ = ColorSpace::TransferID::IEC61966_2_1; 816 src.transfer_ = ColorSpace::TransferID::IEC61966_2_1;
833 break; 817 break;
834 818
835 case ColorSpace::TransferID::SMPTEST2084: 819 case ColorSpace::TransferID::SMPTEST2084:
836 if (!to.IsHDR()) { 820 if (!dst.IsHDR()) {
837 // We don't have an HDR display, so replace SMPTE 2084 with 821 // We don't have an HDR display, so replace SMPTE 2084 with
838 // something that returns ranges more or less suitable for a normal 822 // something that returns ranges more or less suitable for a normal
839 // display. 823 // display.
840 from.transfer_ = ColorSpace::TransferID::SMPTEST2084_NON_HDR; 824 src.transfer_ = ColorSpace::TransferID::SMPTEST2084_NON_HDR;
841 } 825 }
842 break; 826 break;
843 827
844 case ColorSpace::TransferID::ARIB_STD_B67: 828 case ColorSpace::TransferID::ARIB_STD_B67:
845 if (!to.IsHDR()) { 829 if (!dst.IsHDR()) {
846 // Interpreting HLG using a gamma 2.4 works reasonably well for SDR 830 // Interpreting HLG using a gamma 2.4 works reasonably well for SDR
847 // displays. 831 // displays.
848 from.transfer_ = ColorSpace::TransferID::GAMMA24; 832 src.transfer_ = ColorSpace::TransferID::GAMMA24;
849 } 833 }
850 break; 834 break;
851 835
852 default: // Do nothing 836 default: // Do nothing
853 break; 837 break;
854 } 838 }
855 839
856 // TODO(hubbe): shrink gamuts here (never stretch gamuts) 840 // TODO(hubbe): shrink gamuts here (never stretch gamuts)
857 } 841 }
858 842
859 steps_.push_back( 843 steps_.push_back(
860 base::MakeUnique<ColorTransformMatrix>(GetRangeAdjustMatrix(from))); 844 base::MakeUnique<ColorTransformMatrix>(GetRangeAdjustMatrix(src)));
861 845
862 steps_.push_back( 846 steps_.push_back(
863 base::MakeUnique<ColorTransformMatrix>(Invert(GetTransferMatrix(from)))); 847 base::MakeUnique<ColorTransformMatrix>(Invert(GetTransferMatrix(src))));
864 848
865 // If the target color space is not defined, just apply the adjust and 849 // If the target color space is not defined, just apply the adjust and
866 // tranfer matrices. This path is used by YUV to RGB color conversion 850 // tranfer matrices. This path is used by YUV to RGB color conversion
867 // when full color conversion is not enabled. 851 // when full color conversion is not enabled.
868 if (!to.IsValid()) 852 if (!dst.IsValid())
869 return; 853 return;
870 854
871 SkColorSpaceTransferFn to_linear_fn; 855 SkColorSpaceTransferFn src_to_linear_fn;
872 if (from.GetTransferFunction(&to_linear_fn)) { 856 if (src.GetTransferFunction(&src_to_linear_fn)) {
873 steps_.push_back(base::MakeUnique<ColorTransformSkTransferFn>( 857 steps_.push_back(base::MakeUnique<ColorTransformSkTransferFn>(
874 to_linear_fn, from.HasExtendedSkTransferFn())); 858 src_to_linear_fn, src.HasExtendedSkTransferFn()));
875 } else if (from.transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) { 859 } else if (src.transfer_ == ColorSpace::TransferID::SMPTEST2084_NON_HDR) {
876 steps_.push_back( 860 steps_.push_back(
877 base::MakeUnique<ColorTransformSMPTEST2048NonHdrToLinear>()); 861 base::MakeUnique<ColorTransformSMPTEST2048NonHdrToLinear>());
878 } else { 862 } else {
879 steps_.push_back(base::MakeUnique<ColorTransformToLinear>(from.transfer_)); 863 steps_.push_back(base::MakeUnique<ColorTransformToLinear>(src.transfer_));
880 } 864 }
881 865
882 if (from.matrix_ == ColorSpace::MatrixID::BT2020_CL) { 866 if (src.matrix_ == ColorSpace::MatrixID::BT2020_CL) {
883 // BT2020 CL is a special case. 867 // BT2020 CL is a special case.
884 steps_.push_back(base::MakeUnique<ColorTransformFromBT2020CL>()); 868 steps_.push_back(base::MakeUnique<ColorTransformFromBT2020CL>());
885 } 869 }
886 steps_.push_back( 870 steps_.push_back(
887 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(from))); 871 base::MakeUnique<ColorTransformMatrix>(GetPrimaryTransform(src)));
888 872
889 steps_.push_back( 873 steps_.push_back(
890 base::MakeUnique<ColorTransformMatrix>(Invert(GetPrimaryTransform(to)))); 874 base::MakeUnique<ColorTransformMatrix>(Invert(GetPrimaryTransform(dst))));
891 if (to.matrix_ == ColorSpace::MatrixID::BT2020_CL) { 875 if (dst.matrix_ == ColorSpace::MatrixID::BT2020_CL) {
892 // BT2020 CL is a special case. 876 // BT2020 CL is a special case.
893 steps_.push_back(base::MakeUnique<ColorTransformToBT2020CL>()); 877 steps_.push_back(base::MakeUnique<ColorTransformToBT2020CL>());
894 } 878 }
895 879
896 SkColorSpaceTransferFn from_linear_fn; 880 SkColorSpaceTransferFn dst_from_linear_fn;
897 if (to.GetInverseTransferFunction(&from_linear_fn)) { 881 if (dst.GetInverseTransferFunction(&dst_from_linear_fn)) {
898 steps_.push_back(base::MakeUnique<ColorTransformSkTransferFn>( 882 steps_.push_back(base::MakeUnique<ColorTransformSkTransferFn>(
899 from_linear_fn, to.HasExtendedSkTransferFn())); 883 dst_from_linear_fn, dst.HasExtendedSkTransferFn()));
900 } else { 884 } else {
901 steps_.push_back(base::MakeUnique<ColorTransformFromLinear>(to.transfer_)); 885 steps_.push_back(base::MakeUnique<ColorTransformFromLinear>(dst.transfer_));
902 } 886 }
903 887
904 steps_.push_back( 888 steps_.push_back(
905 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(to))); 889 base::MakeUnique<ColorTransformMatrix>(GetTransferMatrix(dst)));
906 890
907 steps_.push_back( 891 steps_.push_back(base::MakeUnique<ColorTransformMatrix>(
908 base::MakeUnique<ColorTransformMatrix>(Invert(GetRangeAdjustMatrix(to)))); 892 Invert(GetRangeAdjustMatrix(dst))));
909 } 893 }
910 894
911 // TODO(ccameron): Change this to SkColorSpaceXform. 895 class SkiaColorTransform : public ColorTransformStep {
912 class QCMSColorTransform : public ColorTransformStep {
913 public: 896 public:
914 // Takes ownership of the profiles 897 // Takes ownership of the profiles
915 QCMSColorTransform(ScopedQcmsProfile from, ScopedQcmsProfile to) 898 SkiaColorTransform(sk_sp<SkColorSpace> src, sk_sp<SkColorSpace> dst)
916 : from_(std::move(from)), to_(std::move(to)) {} 899 : src_(src), dst_(dst) {}
917 ~QCMSColorTransform() override {} 900 ~SkiaColorTransform() override {
918 QCMSColorTransform* GetQCMS() override { return this; } 901 src_ = nullptr;
902 dst_ = nullptr;
903 }
904 SkiaColorTransform* GetSkia() override { return this; }
919 bool Join(ColorTransformStep* next_untyped) override { 905 bool Join(ColorTransformStep* next_untyped) override {
920 QCMSColorTransform* next = next_untyped->GetQCMS(); 906 SkiaColorTransform* next = next_untyped->GetSkia();
921 if (!next) 907 if (!next)
922 return false; 908 return false;
923 if (qcms_profile_match(to_.get(), next->from_.get())) { 909 if (SkColorSpace::Equals(dst_.get(), next->src_.get())) {
924 to_ = std::move(next->to_); 910 dst_ = next->dst_;
925 return true; 911 return true;
926 } 912 }
927 return false; 913 return false;
928 } 914 }
929 bool IsNull() override { 915 bool IsNull() override {
930 if (qcms_profile_match(from_.get(), to_.get())) 916 if (SkColorSpace::Equals(src_.get(), dst_.get()))
931 return true; 917 return true;
932 return false; 918 return false;
933 } 919 }
934 void Transform(ColorTransform::TriStim* colors, size_t num) const override { 920 void Transform(ColorTransform::TriStim* colors, size_t num) const override {
935 CHECK(sizeof(ColorTransform::TriStim) == sizeof(float[3])); 921 // Transform to SkColors.
936 // QCMS doesn't like numbers outside 0..1 922 std::vector<uint8_t> sk_colors(4 * num);
937 for (size_t i = 0; i < num; i++) { 923 for (size_t i = 0; i < num; ++i) {
938 colors[i].set_x(min(1.0f, max(0.0f, colors[i].x()))); 924 float rgb[3] = {colors[i].x(), colors[i].y(), colors[i].z()};
939 colors[i].set_y(min(1.0f, max(0.0f, colors[i].y()))); 925 for (size_t c = 0; c < 3; ++c) {
940 colors[i].set_z(min(1.0f, max(0.0f, colors[i].z()))); 926 int value_int = static_cast<int>(255.f * rgb[c] + 0.5f);
927 value_int = min(value_int, 255);
928 value_int = max(value_int, 0);
929 sk_colors[4 * i + c] = value_int;
930 }
931 sk_colors[4 * i + 3] = 255;
941 } 932 }
942 qcms_chain_transform(from_.get(), to_.get(), 933
943 reinterpret_cast<float*>(colors), 934 // Perform the transform.
944 reinterpret_cast<float*>(colors), num * 3); 935 std::unique_ptr<SkColorSpaceXform> xform =
936 SkColorSpaceXform::New(src_.get(), dst_.get());
937 DCHECK(xform);
938 if (!xform)
939 return;
940 std::vector<uint8_t> sk_colors_transformed(4 * num);
941 bool xform_apply_result = xform->apply(
942 SkColorSpaceXform::kRGBA_8888_ColorFormat, sk_colors_transformed.data(),
943 SkColorSpaceXform::kRGBA_8888_ColorFormat, sk_colors.data(), num,
944 kOpaque_SkAlphaType);
945 DCHECK(xform_apply_result);
946 sk_colors = sk_colors_transformed;
947
948 // Convert back to TriStim.
949 for (size_t i = 0; i < num; ++i) {
950 colors[i].set_x(sk_colors[4 * i + 0] / 255.f);
951 colors[i].set_y(sk_colors[4 * i + 1] / 255.f);
952 colors[i].set_z(sk_colors[4 * i + 2] / 255.f);
953 }
945 } 954 }
946 955
947 private: 956 private:
948 ScopedQcmsProfile from_; 957 sk_sp<SkColorSpace> src_;
949 ScopedQcmsProfile to_; 958 sk_sp<SkColorSpace> dst_;
950 }; 959 };
951 960
952 ScopedQcmsProfile ColorTransformInternal::GetQCMSProfileIfNecessary( 961 sk_sp<SkColorSpace> ColorTransformInternal::GetSkColorSpaceIfNecessary(
953 const ColorSpace& color_space) { 962 const ColorSpace& color_space) {
954 if (color_space.primaries_ != ColorSpace::PrimaryID::ICC_BASED && 963 if (color_space.primaries_ != ColorSpace::PrimaryID::ICC_BASED &&
955 color_space.transfer_ != ColorSpace::TransferID::ICC_BASED) { 964 color_space.transfer_ != ColorSpace::TransferID::ICC_BASED) {
956 return nullptr; 965 return nullptr;
957 } 966 }
958 // TODO(ccameron): Use SkColorSpaceXform here to avoid looking up the 967 DCHECK(color_space.icc_profile_sk_color_space_);
959 // ICCProfile. 968 return color_space.icc_profile_sk_color_space_;
960 ICCProfile icc_profile;
961 if (!ICCProfile::FromId(color_space.icc_profile_id_, &icc_profile)) {
962 // We needed the original ICC profile to construct this transform, but it
963 // has been flushed from our cache. Fall back to using the ICC profile's
964 // inaccurate, so spam the console.
965 // TODO(ccameron): This will go away when we switch to SkColorSpaceXform.
966 LOG(ERROR) << "Failed to retrieve original ICC profile, using sRGB";
967 return ScopedQcmsProfile(qcms_profile_sRGB());
968 }
969 return ScopedQcmsProfile(qcms_profile_from_memory(
970 icc_profile.GetData().data(), icc_profile.GetData().size()));
971 } 969 }
972
973 ScopedQcmsProfile GetXYZD50Profile() {
974 // QCMS is trixy, it has a datatype called qcms_CIE_xyY, but what it expects
975 // is in fact not xyY color coordinates, it just wants the x/y values of the
976 // primaries with Y equal to 1.0.
977 qcms_CIE_xyYTRIPLE xyz;
978 qcms_CIE_xyY w;
979 xyz.red.x = 1.0f;
980 xyz.red.y = 0.0f;
981 xyz.red.Y = 1.0f;
982 xyz.green.x = 0.0f;
983 xyz.green.y = 1.0f;
984 xyz.green.Y = 1.0f;
985 xyz.blue.x = 0.0f;
986 xyz.blue.y = 0.0f;
987 xyz.blue.Y = 1.0f;
988 w.x = 0.34567f;
989 w.y = 0.35850f;
990 w.Y = 1.0f;
991 return ScopedQcmsProfile(qcms_profile_create_rgb_with_gamma(w, xyz, 1.0f));
992 }
993
994 ColorTransformInternal::ColorTransformInternal(const ColorSpace& src, 970 ColorTransformInternal::ColorTransformInternal(const ColorSpace& src,
995 const ColorSpace& dst, 971 const ColorSpace& dst,
996 Intent intent) 972 Intent intent)
997 : src_(src), dst_(dst) { 973 : src_(src), dst_(dst) {
998 // If no source color space is specified, do no transformation. 974 // If no source color space is specified, do no transformation.
999 // TODO(ccameron): We may want dst assume sRGB at some point in the future. 975 // TODO(ccameron): We may want dst assume sRGB at some point in the future.
1000 if (!src_.IsValid()) 976 if (!src_.IsValid())
1001 return; 977 return;
1002 978
1003 // If the target color space is not defined, just apply the adjust and 979 // If the target color space is not defined, just apply the adjust and
1004 // tranfer matrices. This path is used by YUV to RGB color conversion 980 // tranfer matrices. This path is used by YUV to RGB color conversion
1005 // when full color conversion is not enabled. 981 // when full color conversion is not enabled.
1006 ScopedQcmsProfile src_profile; 982 sk_sp<SkColorSpace> src_sk_color_space;
1007 ScopedQcmsProfile dst_profile; 983 sk_sp<SkColorSpace> dst_sk_color_space;
984
985 bool has_src_profile = false;
986 bool has_dst_profile = false;
1008 if (dst.IsValid()) { 987 if (dst.IsValid()) {
1009 src_profile = GetQCMSProfileIfNecessary(src_); 988 src_sk_color_space = GetSkColorSpaceIfNecessary(src_);
1010 dst_profile = GetQCMSProfileIfNecessary(dst_); 989 dst_sk_color_space = GetSkColorSpaceIfNecessary(dst_);
1011 } 990 }
1012 bool has_src_profile = !!src_profile; 991 has_src_profile = !!src_sk_color_space;
1013 bool has_dst_profile = !!dst_profile; 992 has_dst_profile = !!dst_sk_color_space;
1014 993
1015 if (src_profile) { 994 if (has_src_profile) {
1016 steps_.push_back(base::MakeUnique<QCMSColorTransform>( 995 steps_.push_back(base::MakeUnique<SkiaColorTransform>(
1017 std::move(src_profile), GetXYZD50Profile())); 996 std::move(src_sk_color_space),
997 ColorSpace::CreateXYZD50().ToSkColorSpace()));
1018 } 998 }
1019
1020 AppendColorSpaceToColorSpaceTransform( 999 AppendColorSpaceToColorSpaceTransform(
1021 has_src_profile ? ColorSpace::CreateXYZD50() : src_, 1000 has_src_profile ? ColorSpace::CreateXYZD50() : src_,
1022 has_dst_profile ? ColorSpace::CreateXYZD50() : dst_, intent); 1001 has_dst_profile ? ColorSpace::CreateXYZD50() : dst_, intent);
1023 1002 if (has_dst_profile) {
1024 if (dst_profile) { 1003 steps_.push_back(base::MakeUnique<SkiaColorTransform>(
1025 steps_.push_back(base::MakeUnique<QCMSColorTransform>( 1004 ColorSpace::CreateXYZD50().ToSkColorSpace(),
1026 GetXYZD50Profile(), std::move(dst_profile))); 1005 std::move(dst_sk_color_space)));
1027 } 1006 }
1028 1007
1029 if (intent != Intent::TEST_NO_OPT) 1008 if (intent != Intent::TEST_NO_OPT)
1030 Simplify(); 1009 Simplify();
1031 } 1010 }
1032 1011
1033 std::string ColorTransformInternal::GetShaderSource() const { 1012 std::string ColorTransformInternal::GetShaderSource() const {
1034 std::stringstream hdr; 1013 std::stringstream hdr;
1035 std::stringstream src; 1014 std::stringstream src;
1036 InitStringStream(&hdr); 1015 InitStringStream(&hdr);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1080 --iter; 1059 --iter;
1081 continue; 1060 continue;
1082 } 1061 }
1083 1062
1084 ++iter; 1063 ++iter;
1085 } 1064 }
1086 } 1065 }
1087 1066
1088 // static 1067 // static
1089 std::unique_ptr<ColorTransform> ColorTransform::NewColorTransform( 1068 std::unique_ptr<ColorTransform> ColorTransform::NewColorTransform(
1090 const ColorSpace& from, 1069 const ColorSpace& src,
1091 const ColorSpace& to, 1070 const ColorSpace& dst,
1092 Intent intent) { 1071 Intent intent) {
1093 return std::unique_ptr<ColorTransform>( 1072 return std::unique_ptr<ColorTransform>(
1094 new ColorTransformInternal(from, to, intent)); 1073 new ColorTransformInternal(src, dst, intent));
1095 } 1074 }
1096 1075
1097 ColorTransform::ColorTransform() {} 1076 ColorTransform::ColorTransform() {}
1098 ColorTransform::~ColorTransform() {} 1077 ColorTransform::~ColorTransform() {}
1099 1078
1100 } // namespace gfx 1079 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/color_space.cc ('k') | ui/gfx/icc_profile.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698