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

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

Issue 2691213007: color: Don't use QCMS for transforms unless necessary (Closed)
Patch Set: Incorporate review feedback Created 3 years, 10 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/icc_profile.h ('k') | ui/gfx/icc_profile_unittest.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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 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/icc_profile.h" 5 #include "ui/gfx/icc_profile.h"
6 6
7 #include <list> 7 #include <list>
8 8
9 #include "base/containers/mru_cache.h" 9 #include "base/containers/mru_cache.h"
10 #include "base/lazy_instance.h" 10 #include "base/lazy_instance.h"
11 #include "base/synchronization/lock.h" 11 #include "base/synchronization/lock.h"
12 #include "third_party/skia/include/core/SkData.h"
13 #include "third_party/skia/include/core/SkICC.h" 12 #include "third_party/skia/include/core/SkICC.h"
14 #include "ui/gfx/color_transform.h" 13 #include "ui/gfx/color_transform.h"
15 14
16 namespace gfx { 15 namespace gfx {
17 16
18 const uint64_t ICCProfile::test_id_adobe_rgb_ = 1; 17 const uint64_t ICCProfile::test_id_adobe_rgb_ = 1;
19 const uint64_t ICCProfile::test_id_color_spin_ = 2; 18 const uint64_t ICCProfile::test_id_color_spin_ = 2;
20 const uint64_t ICCProfile::test_id_generic_rgb_ = 3; 19 const uint64_t ICCProfile::test_id_generic_rgb_ = 3;
21 const uint64_t ICCProfile::test_id_srgb_ = 4; 20 const uint64_t ICCProfile::test_id_srgb_ = 4;
22 21
(...skipping 27 matching lines...) Expand all
50 ICCProfile::~ICCProfile() = default; 49 ICCProfile::~ICCProfile() = default;
51 50
52 bool ICCProfile::operator==(const ICCProfile& other) const { 51 bool ICCProfile::operator==(const ICCProfile& other) const {
53 return data_ == other.data_; 52 return data_ == other.data_;
54 } 53 }
55 54
56 bool ICCProfile::operator!=(const ICCProfile& other) const { 55 bool ICCProfile::operator!=(const ICCProfile& other) const {
57 return !(*this == other); 56 return !(*this == other);
58 } 57 }
59 58
59 bool ICCProfile::IsValid() const {
60 return successfully_parsed_by_sk_icc_;
61 }
62
60 // static 63 // static
61 ICCProfile ICCProfile::FromData(const void* data, size_t size) { 64 ICCProfile ICCProfile::FromData(const void* data, size_t size) {
62 return FromDataWithId(data, size, 0); 65 return FromDataWithId(data, size, 0);
63 } 66 }
64 67
65 // static 68 // static
66 ICCProfile ICCProfile::FromDataWithId(const void* data, 69 ICCProfile ICCProfile::FromDataWithId(const void* data,
67 size_t size, 70 size_t size,
68 uint64_t new_profile_id) { 71 uint64_t new_profile_id) {
69 if (!IsValidProfileLength(size)) { 72 if (!IsValidProfileLength(size)) {
(...skipping 30 matching lines...) Expand all
100 } 103 }
101 104
102 #if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(USE_X11) 105 #if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(USE_X11)
103 // static 106 // static
104 ICCProfile ICCProfile::FromBestMonitor() { 107 ICCProfile ICCProfile::FromBestMonitor() {
105 return ICCProfile(); 108 return ICCProfile();
106 } 109 }
107 #endif 110 #endif
108 111
109 // static 112 // static
110 ICCProfile ICCProfile::FromColorSpace(const gfx::ColorSpace& color_space) {
111 if (color_space == gfx::ColorSpace())
112 return ICCProfile();
113
114 // If |color_space| was created from an ICC profile, retrieve that exact
115 // profile.
116 if (color_space.icc_profile_id_) {
117 Cache& cache = g_cache.Get();
118 base::AutoLock lock(cache.lock);
119 auto found = cache.id_to_icc_profile_mru.Get(color_space.icc_profile_id_);
120 if (found != cache.id_to_icc_profile_mru.end())
121 return found->second;
122 }
123
124 // Otherwise, construct an ICC profile based on the best approximated
125 // primaries and matrix.
126 SkMatrix44 to_XYZD50_matrix;
127 color_space.GetPrimaryMatrix(&to_XYZD50_matrix);
128 SkColorSpaceTransferFn fn;
129 if (!color_space.GetTransferFunction(&fn)) {
130 DLOG(ERROR) << "Failed to get ColorSpace transfer function for ICCProfile.";
131 return ICCProfile();
132 }
133
134 sk_sp<SkData> data = SkICC::WriteToICC(fn, to_XYZD50_matrix);
135 if (!data) {
136 DLOG(ERROR) << "Failed to create SkICC.";
137 return ICCProfile();
138 }
139
140 // gfx::ColorTransform assumes that this will return an empty profile for any
141 // color space that was not constructed from an ICC profile.
142 // TODO(ccameron): Fix this assumption.
143 // return FromData(data->data(), data->size());
144 return ICCProfile();
145 }
146
147 const std::vector<char>& ICCProfile::GetData() const { 113 const std::vector<char>& ICCProfile::GetData() const {
148 return data_; 114 return data_;
149 } 115 }
150 116
151 const ColorSpace& ICCProfile::GetColorSpace() const { 117 const ColorSpace& ICCProfile::GetColorSpace() const {
152 // Move this ICC profile to the most recently used end of the cache, 118 // Move this ICC profile to the most recently used end of the cache,
153 // inserting if needed. 119 // inserting if needed.
154 if (id_) { 120 if (id_) {
155 Cache& cache = g_cache.Get(); 121 Cache& cache = g_cache.Get();
156 base::AutoLock lock(cache.lock); 122 base::AutoLock lock(cache.lock);
157 auto found = cache.id_to_icc_profile_mru.Get(id_); 123 auto found = cache.id_to_icc_profile_mru.Get(id_);
158 if (found == cache.id_to_icc_profile_mru.end()) 124 if (found == cache.id_to_icc_profile_mru.end())
159 found = cache.id_to_icc_profile_mru.Put(id_, *this); 125 found = cache.id_to_icc_profile_mru.Put(id_, *this);
160 } 126 }
161 return color_space_; 127 return color_space_;
162 } 128 }
163 129
130 // static
131 bool ICCProfile::FromId(uint64_t id,
132 bool only_if_needed,
133 ICCProfile* icc_profile) {
134 if (!id)
135 return false;
136
137 Cache& cache = g_cache.Get();
138 base::AutoLock lock(cache.lock);
139
140 auto found = cache.id_to_icc_profile_mru.Get(id);
141 if (found == cache.id_to_icc_profile_mru.end())
142 return false;
143
144 const ICCProfile& found_icc_profile = found->second;
145 if (found_icc_profile.color_space_is_accurate_ && only_if_needed)
146 return false;
147
148 *icc_profile = found_icc_profile;
149 return true;
150 }
151
164 void ICCProfile::ComputeColorSpaceAndCache() { 152 void ICCProfile::ComputeColorSpaceAndCache() {
165 if (!id_) 153 if (!id_)
166 return; 154 return;
167 155
168 // If this already exists in the cache, just update its |color_space_|. 156 // If this already exists in the cache, just update its |color_space_|.
169 { 157 {
170 Cache& cache = g_cache.Get(); 158 Cache& cache = g_cache.Get();
171 base::AutoLock lock(cache.lock); 159 base::AutoLock lock(cache.lock);
172 auto found = cache.id_to_icc_profile_mru.Get(id_); 160 auto found = cache.id_to_icc_profile_mru.Get(id_);
173 if (found != cache.id_to_icc_profile_mru.end()) { 161 if (found != cache.id_to_icc_profile_mru.end()) {
174 color_space_ = found->second.color_space_; 162 color_space_ = found->second.color_space_;
163 successfully_parsed_by_sk_icc_ =
164 found->second.successfully_parsed_by_sk_icc_;
175 return; 165 return;
176 } 166 }
177 } 167 }
178 168
169 color_space_is_accurate_ = true;
170 SkMatrix44 to_XYZD50_matrix;
171 SkColorSpaceTransferFn fn;
172 sk_sp<SkICC> sk_icc = SkICC::Make(data_.data(), data_.size());
173 if (sk_icc) {
174 successfully_parsed_by_sk_icc_ = true;
175 if (!sk_icc->toXYZD50(&to_XYZD50_matrix)) {
176 // Just say that the primaries were the sRGB primaries if we can't
177 // extract them.
178 gfx::ColorSpace::CreateSRGB().GetPrimaryMatrix(&to_XYZD50_matrix);
179 color_space_is_accurate_ = false;
180 DLOG(ERROR) << "Unable to handle ICCProfile primaries.";
181 }
182 if (!sk_icc->isNumericalTransferFn(&fn)) {
183 // Just say that the transfer function was sRGB if we cannot read it.
184 // TODO(ccameron): Use a least squares approximation of the transfer
185 // function when it is not numerical.
186 gfx::ColorSpace::CreateSRGB().GetTransferFunction(&fn);
187 color_space_is_accurate_ = false;
188 DLOG(ERROR) << "Unable to handle ICCProfile transfer function.";
189 }
190 } else {
191 successfully_parsed_by_sk_icc_ = false;
192 gfx::ColorSpace::CreateSRGB().GetPrimaryMatrix(&to_XYZD50_matrix);
193 gfx::ColorSpace::CreateSRGB().GetTransferFunction(&fn);
194 color_space_is_accurate_ = false;
195 DLOG(ERROR) << "Unable parse ICCProfile.";
196 }
197
179 // Compute the color space. 198 // Compute the color space.
180 color_space_ = gfx::ColorSpace( 199 color_space_ = gfx::ColorSpace::CreateCustom(to_XYZD50_matrix, fn);
181 ColorSpace::PrimaryID::CUSTOM, ColorSpace::TransferID::CUSTOM,
182 ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
183 color_space_.icc_profile_id_ = id_; 200 color_space_.icc_profile_id_ = id_;
184 color_space_.icc_profile_sk_color_space_ = 201 color_space_.icc_profile_sk_color_space_ =
185 SkColorSpace::MakeICC(data_.data(), data_.size()); 202 SkColorSpace::MakeICC(data_.data(), data_.size());
186 203
187 sk_sp<SkICC> sk_icc = SkICC::Make(data_.data(), data_.size());
188 if (sk_icc) {
189 bool result;
190 SkMatrix44 to_XYZD50_matrix;
191 result = sk_icc->toXYZD50(&to_XYZD50_matrix);
192 if (result) {
193 for (int row = 0; row < 3; ++row) {
194 for (int col = 0; col < 3; ++col) {
195 color_space_.custom_primary_matrix_[3 * row + col] =
196 to_XYZD50_matrix.get(row, col);
197 }
198 }
199 } else {
200 // Just say that the primaries were the sRGB primaries if we can't
201 // extract them.
202 color_space_.primaries_ = ColorSpace::PrimaryID::BT709;
203 DLOG(ERROR) << "Unable to handle ICCProfile primaries.";
204 }
205 SkColorSpaceTransferFn fn;
206 result = sk_icc->isNumericalTransferFn(&fn);
207 if (result) {
208 color_space_.custom_transfer_params_[0] = fn.fA;
209 color_space_.custom_transfer_params_[1] = fn.fB;
210 color_space_.custom_transfer_params_[2] = fn.fC;
211 color_space_.custom_transfer_params_[3] = fn.fD;
212 color_space_.custom_transfer_params_[4] = fn.fE;
213 color_space_.custom_transfer_params_[5] = fn.fF;
214 color_space_.custom_transfer_params_[6] = fn.fG;
215 } else {
216 // Just say that the transfer function was sRGB if we cannot read it.
217 // TODO(ccameron): Use a least squares approximation of the transfer
218 // function when it is not numerical.
219 color_space_.transfer_ = ColorSpace::TransferID::IEC61966_2_1;
220 DLOG(ERROR) << "Unable to handle ICCProfile transfer function.";
221 }
222 }
223
224 // Add to the cache. 204 // Add to the cache.
225 { 205 {
226 Cache& cache = g_cache.Get(); 206 Cache& cache = g_cache.Get();
227 base::AutoLock lock(cache.lock); 207 base::AutoLock lock(cache.lock);
228 cache.id_to_icc_profile_mru.Put(id_, *this); 208 cache.id_to_icc_profile_mru.Put(id_, *this);
229 } 209 }
230 } 210 }
231 211
232 // static 212 // static
233 bool ICCProfile::IsValidProfileLength(size_t length) { 213 bool ICCProfile::IsValidProfileLength(size_t length) {
234 return length >= kMinProfileLength && length <= kMaxProfileLength; 214 return length >= kMinProfileLength && length <= kMaxProfileLength;
235 } 215 }
236 216
237 } // namespace gfx 217 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/icc_profile.h ('k') | ui/gfx/icc_profile_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698