OLD | NEW |
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" |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 | 101 |
102 #if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(USE_X11) | 102 #if !defined(OS_WIN) && !defined(OS_MACOSX) && !defined(USE_X11) |
103 // static | 103 // static |
104 ICCProfile ICCProfile::FromBestMonitor() { | 104 ICCProfile ICCProfile::FromBestMonitor() { |
105 return ICCProfile(); | 105 return ICCProfile(); |
106 } | 106 } |
107 #endif | 107 #endif |
108 | 108 |
109 // static | 109 // static |
110 ICCProfile ICCProfile::FromColorSpace(const gfx::ColorSpace& color_space) { | 110 ICCProfile ICCProfile::FromColorSpace(const gfx::ColorSpace& color_space) { |
111 if (color_space == gfx::ColorSpace()) | 111 if (!color_space.IsValid()) |
112 return ICCProfile(); | 112 return ICCProfile(); |
113 | 113 |
114 // If |color_space| was created from an ICC profile, retrieve that exact | 114 // If |color_space| was created from an ICC profile, retrieve that exact |
115 // profile. | 115 // profile. |
116 if (color_space.icc_profile_id_) { | 116 ICCProfile result; |
117 Cache& cache = g_cache.Get(); | 117 if (FromId(color_space.icc_profile_id_, false, &result)) { |
118 base::AutoLock lock(cache.lock); | 118 return result; |
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 } | 119 } |
123 | 120 |
124 // Otherwise, construct an ICC profile based on the best approximated | 121 // Otherwise, construct an ICC profile based on the best approximated |
125 // primaries and matrix. | 122 // primaries and matrix. |
126 SkMatrix44 to_XYZD50_matrix; | 123 SkMatrix44 to_XYZD50_matrix; |
127 color_space.GetPrimaryMatrix(&to_XYZD50_matrix); | 124 color_space.GetPrimaryMatrix(&to_XYZD50_matrix); |
128 SkColorSpaceTransferFn fn; | 125 SkColorSpaceTransferFn fn; |
129 if (!color_space.GetTransferFunction(&fn)) { | 126 if (!color_space.GetTransferFunction(&fn)) { |
130 DLOG(ERROR) << "Failed to get ColorSpace transfer function for ICCProfile."; | 127 DLOG(ERROR) << "Failed to get ColorSpace transfer function for ICCProfile."; |
131 return ICCProfile(); | 128 return ICCProfile(); |
132 } | 129 } |
133 | |
134 sk_sp<SkData> data = SkICC::WriteToICC(fn, to_XYZD50_matrix); | 130 sk_sp<SkData> data = SkICC::WriteToICC(fn, to_XYZD50_matrix); |
135 if (!data) { | 131 if (!data) { |
136 DLOG(ERROR) << "Failed to create SkICC."; | 132 DLOG(ERROR) << "Failed to create SkICC."; |
137 return ICCProfile(); | 133 return ICCProfile(); |
138 } | 134 } |
139 | 135 return FromData(data->data(), data->size()); |
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 } | 136 } |
146 | 137 |
147 const std::vector<char>& ICCProfile::GetData() const { | 138 const std::vector<char>& ICCProfile::GetData() const { |
148 return data_; | 139 return data_; |
149 } | 140 } |
150 | 141 |
151 const ColorSpace& ICCProfile::GetColorSpace() const { | 142 const ColorSpace& ICCProfile::GetColorSpace() const { |
152 // Move this ICC profile to the most recently used end of the cache, | 143 // Move this ICC profile to the most recently used end of the cache, |
153 // inserting if needed. | 144 // inserting if needed. |
154 if (id_) { | 145 if (id_) { |
155 Cache& cache = g_cache.Get(); | 146 Cache& cache = g_cache.Get(); |
156 base::AutoLock lock(cache.lock); | 147 base::AutoLock lock(cache.lock); |
157 auto found = cache.id_to_icc_profile_mru.Get(id_); | 148 auto found = cache.id_to_icc_profile_mru.Get(id_); |
158 if (found == cache.id_to_icc_profile_mru.end()) | 149 if (found == cache.id_to_icc_profile_mru.end()) |
159 found = cache.id_to_icc_profile_mru.Put(id_, *this); | 150 found = cache.id_to_icc_profile_mru.Put(id_, *this); |
160 } | 151 } |
161 return color_space_; | 152 return color_space_; |
162 } | 153 } |
163 | 154 |
| 155 // static |
| 156 bool ICCProfile::FromId(uint64_t id, |
| 157 bool only_if_needed, |
| 158 ICCProfile* icc_profile) { |
| 159 if (!id) |
| 160 return false; |
| 161 |
| 162 Cache& cache = g_cache.Get(); |
| 163 base::AutoLock lock(cache.lock); |
| 164 |
| 165 auto found = cache.id_to_icc_profile_mru.Get(id); |
| 166 if (found == cache.id_to_icc_profile_mru.end()) |
| 167 return false; |
| 168 |
| 169 const ICCProfile& found_icc_profile = found->second; |
| 170 if (found_icc_profile.color_space_is_accurate_ && only_if_needed) |
| 171 return false; |
| 172 |
| 173 *icc_profile = found_icc_profile; |
| 174 return true; |
| 175 } |
| 176 |
164 void ICCProfile::ComputeColorSpaceAndCache() { | 177 void ICCProfile::ComputeColorSpaceAndCache() { |
165 if (!id_) | 178 if (!id_) |
166 return; | 179 return; |
167 | 180 |
168 // If this already exists in the cache, just update its |color_space_|. | 181 // If this already exists in the cache, just update its |color_space_|. |
169 { | 182 { |
170 Cache& cache = g_cache.Get(); | 183 Cache& cache = g_cache.Get(); |
171 base::AutoLock lock(cache.lock); | 184 base::AutoLock lock(cache.lock); |
172 auto found = cache.id_to_icc_profile_mru.Get(id_); | 185 auto found = cache.id_to_icc_profile_mru.Get(id_); |
173 if (found != cache.id_to_icc_profile_mru.end()) { | 186 if (found != cache.id_to_icc_profile_mru.end()) { |
174 color_space_ = found->second.color_space_; | 187 color_space_ = found->second.color_space_; |
175 return; | 188 return; |
176 } | 189 } |
177 } | 190 } |
178 | 191 |
| 192 color_space_is_accurate_ = true; |
| 193 SkMatrix44 to_XYZD50_matrix; |
| 194 SkColorSpaceTransferFn fn; |
| 195 sk_sp<SkICC> sk_icc = SkICC::Make(data_.data(), data_.size()); |
| 196 if (sk_icc) { |
| 197 if (!sk_icc->toXYZD50(&to_XYZD50_matrix)) { |
| 198 // Just say that the primaries were the sRGB primaries if we can't |
| 199 // extract them. |
| 200 gfx::ColorSpace::CreateSRGB().GetPrimaryMatrix(&to_XYZD50_matrix); |
| 201 color_space_is_accurate_ = false; |
| 202 DLOG(ERROR) << "Unable to handle ICCProfile primaries."; |
| 203 } |
| 204 if (!sk_icc->isNumericalTransferFn(&fn)) { |
| 205 // Just say that the transfer function was sRGB if we cannot read it. |
| 206 // TODO(ccameron): Use a least squares approximation of the transfer |
| 207 // function when it is not numerical. |
| 208 gfx::ColorSpace::CreateSRGB().GetTransferFunction(&fn); |
| 209 color_space_is_accurate_ = false; |
| 210 DLOG(ERROR) << "Unable to handle ICCProfile transfer function."; |
| 211 } |
| 212 } else { |
| 213 gfx::ColorSpace::CreateSRGB().GetPrimaryMatrix(&to_XYZD50_matrix); |
| 214 gfx::ColorSpace::CreateSRGB().GetTransferFunction(&fn); |
| 215 color_space_is_accurate_ = false; |
| 216 DLOG(ERROR) << "Unable parse ICCProfile."; |
| 217 } |
| 218 |
179 // Compute the color space. | 219 // Compute the color space. |
180 color_space_ = gfx::ColorSpace( | 220 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_; | 221 color_space_.icc_profile_id_ = id_; |
184 color_space_.icc_profile_sk_color_space_ = | 222 color_space_.icc_profile_sk_color_space_ = |
185 SkColorSpace::MakeICC(data_.data(), data_.size()); | 223 SkColorSpace::MakeICC(data_.data(), data_.size()); |
186 | 224 |
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. | 225 // Add to the cache. |
225 { | 226 { |
226 Cache& cache = g_cache.Get(); | 227 Cache& cache = g_cache.Get(); |
227 base::AutoLock lock(cache.lock); | 228 base::AutoLock lock(cache.lock); |
228 cache.id_to_icc_profile_mru.Put(id_, *this); | 229 cache.id_to_icc_profile_mru.Put(id_, *this); |
229 } | 230 } |
230 } | 231 } |
231 | 232 |
232 // static | 233 // static |
233 bool ICCProfile::IsValidProfileLength(size_t length) { | 234 bool ICCProfile::IsValidProfileLength(size_t length) { |
234 return length >= kMinProfileLength && length <= kMaxProfileLength; | 235 return length >= kMinProfileLength && length <= kMaxProfileLength; |
235 } | 236 } |
236 | 237 |
237 } // namespace gfx | 238 } // namespace gfx |
OLD | NEW |