ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "ui/gfx/icc_profile.h" |
| 6 | |
| 7 | #include <list> |
Christopher Cameron | 374b6c4 | 2017-08-31 22:21:23 | [diff] [blame] | 8 | #include <set> |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 9 | |
ccameron | 290a91a | 2017-05-13 19:22:33 | [diff] [blame] | 10 | #include "base/command_line.h" |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 11 | #include "base/containers/mru_cache.h" |
| 12 | #include "base/lazy_instance.h" |
Christopher Cameron | 374b6c4 | 2017-08-31 22:21:23 | [diff] [blame] | 13 | #include "base/metrics/histogram_macros.h" |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 14 | #include "base/synchronization/lock.h" |
ccameron | b3206e2 | 2017-03-25 02:09:12 | [diff] [blame] | 15 | #include "third_party/skia/include/core/SkColorSpaceXform.h" |
Brian Osman | 37233e3 | 2018-05-17 16:53:17 | [diff] [blame^] | 16 | #include "third_party/skia/third_party/skcms/skcms.h" |
ccameron | 24c87c3 | 2017-03-14 21:50:42 | [diff] [blame] | 17 | #include "ui/gfx/skia_color_space_util.h" |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 18 | |
| 19 | namespace gfx { |
| 20 | |
Christopher Cameron | 374b6c4 | 2017-08-31 22:21:23 | [diff] [blame] | 21 | namespace { |
| 22 | |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 23 | static const size_t kMaxCachedICCProfiles = 16; |
| 24 | |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 25 | // An MRU cache mapping ColorSpace objects to the ICCProfile that created them. |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 26 | // This cache is necessary only on macOS, for power consumption reasons. In |
| 27 | // particular: |
| 28 | // * IOSurfaces specify their output color space by raw ICC profile data. |
| 29 | // * If the IOSurface ICC profile does not exactly match the output monitor's |
| 30 | // ICC profile, there is a substantial power cost. |
| 31 | // * This structure allows us to retrieve the exact ICC profile data that |
| 32 | // produced a given ColorSpace. |
| 33 | using SpaceToProfileCacheBase = base::MRUCache<ColorSpace, ICCProfile>; |
| 34 | class SpaceToProfileCache : public SpaceToProfileCacheBase { |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 35 | public: |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 36 | SpaceToProfileCache() : SpaceToProfileCacheBase(kMaxCachedICCProfiles) {} |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 37 | }; |
Christopher Cameron | a9b81c0b13 | 2017-12-21 00:23:54 | [diff] [blame] | 38 | base::LazyInstance<SpaceToProfileCache>::Leaky g_space_to_profile_cache_mac = |
| 39 | LAZY_INSTANCE_INITIALIZER; |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 40 | |
| 41 | // An MRU cache mapping data to ICCProfile objects, to avoid re-parsing |
| 42 | // profiles every time they are read. |
| 43 | using DataToProfileCacheBase = base::MRUCache<std::vector<char>, ICCProfile>; |
| 44 | class DataToProfileCache : public DataToProfileCacheBase { |
| 45 | public: |
| 46 | DataToProfileCache() : DataToProfileCacheBase(kMaxCachedICCProfiles) {} |
| 47 | }; |
Christopher Cameron | a9b81c0b13 | 2017-12-21 00:23:54 | [diff] [blame] | 48 | base::LazyInstance<DataToProfileCache>::Leaky g_data_to_profile_cache = |
| 49 | LAZY_INSTANCE_INITIALIZER; |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 50 | |
| 51 | // An MRU cache mapping IDs to ICCProfile objects. This is necessary for |
| 52 | // constructing LUT-based color transforms. In particular, it is used to look |
| 53 | // up the SkColorSpace for ColorSpace objects that are not parametric, so that |
| 54 | // that SkColorSpace may be used to construct the LUT. |
| 55 | using IdToProfileCacheBase = base::MRUCache<uint64_t, ICCProfile>; |
| 56 | class IdToProfileCache : public IdToProfileCacheBase { |
| 57 | public: |
| 58 | IdToProfileCache() : IdToProfileCacheBase(kMaxCachedICCProfiles) {} |
| 59 | }; |
Christopher Cameron | a9b81c0b13 | 2017-12-21 00:23:54 | [diff] [blame] | 60 | base::LazyInstance<IdToProfileCache>::Leaky g_id_to_profile_cache = |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 61 | LAZY_INSTANCE_INITIALIZER; |
| 62 | |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 63 | // The next id to assign to a color profile. |
| 64 | uint64_t g_next_unused_id = 1; |
| 65 | |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 66 | // Lock that must be held to access |g_space_to_profile_cache_mac| and |
| 67 | // |g_next_unused_id|. |
Daniel Bratell | b6c0ab8c | 2017-12-21 13:09:18 | [diff] [blame] | 68 | base::LazyInstance<base::Lock>::Leaky g_icc_profile_lock = |
| 69 | LAZY_INSTANCE_INITIALIZER; |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 70 | |
Christopher Cameron | 374b6c4 | 2017-08-31 22:21:23 | [diff] [blame] | 71 | } // namespace |
| 72 | |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 73 | ICCProfile::Internals::AnalyzeResult ICCProfile::Internals::Initialize() { |
Christopher Cameron | fdc0f87 | 2017-11-09 03:22:16 | [diff] [blame] | 74 | // Start out with no parametric data. |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 75 | if (data_.empty()) |
| 76 | return kICCNoProfile; |
Christopher Cameron | a4adb41b | 2017-07-13 06:44:25 | [diff] [blame] | 77 | |
Brian Osman | 37233e3 | 2018-05-17 16:53:17 | [diff] [blame^] | 78 | // Parse the profile. |
| 79 | skcms_ICCProfile profile; |
| 80 | if (!skcms_Parse(data_.data(), data_.size(), &profile)) { |
| 81 | DLOG(ERROR) << "Failed to parse ICC profile."; |
Christopher Cameron | 374b6c4 | 2017-08-31 22:21:23 | [diff] [blame] | 82 | return kICCFailedToParse; |
Christopher Cameron | a4adb41b | 2017-07-13 06:44:25 | [diff] [blame] | 83 | } |
Brian Osman | 37233e3 | 2018-05-17 16:53:17 | [diff] [blame^] | 84 | |
| 85 | // Coerce it into a rasterization destination (if possible). If the profile |
| 86 | // can't be approximated accurately, skcms will not allow transforming to it, |
| 87 | // and this will fail. |
| 88 | if (!skcms_MakeUsableAsDestinationWithSingleCurve(&profile)) { |
| 89 | DLOG(ERROR) << "Parsed ICC profile but can't make usable as destination."; |
| 90 | return kICCFailedToMakeUsable; |
Christopher Cameron | a4adb41b | 2017-07-13 06:44:25 | [diff] [blame] | 91 | } |
| 92 | |
Brian Osman | 37233e3 | 2018-05-17 16:53:17 | [diff] [blame^] | 93 | // Create an SkColorSpace from the profile. This should always succeed after |
| 94 | // calling MakeUsableAsDestinationWithSingleCurve. |
| 95 | sk_color_space_ = SkColorSpace::Make(profile); |
| 96 | DCHECK(sk_color_space_); |
Christopher Cameron | a4adb41b | 2017-07-13 06:44:25 | [diff] [blame] | 97 | |
Brian Osman | 37233e3 | 2018-05-17 16:53:17 | [diff] [blame^] | 98 | // Extract the primary matrix and transfer function |
| 99 | to_XYZD50_.set3x3RowMajorf(&profile.toXYZD50.vals[0][0]); |
| 100 | memcpy(&transfer_fn_, &profile.trc[0].parametric, sizeof(transfer_fn_)); |
ccameron | e35e232 | 2017-11-02 23:33:46 | [diff] [blame] | 101 | |
Brian Osman | 37233e3 | 2018-05-17 16:53:17 | [diff] [blame^] | 102 | // We assume that if we accurately approximated the profile, then the |
| 103 | // single-curve version (which may have higher error) is also okay. If we |
| 104 | // want to maintain the distinction between accurate and inaccurate profiles, |
| 105 | // we could check to see if the single-curve version is/ approximately equal |
| 106 | // to the original (or to the multi-channel approximation). |
| 107 | return kICCExtractedMatrixAndTrFn; |
Christopher Cameron | 374b6c4 | 2017-08-31 22:21:23 | [diff] [blame] | 108 | } |
Reilly Grant | c46032eb | 2017-08-30 22:53:52 | [diff] [blame] | 109 | |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 110 | ICCProfile::ICCProfile() = default; |
| 111 | ICCProfile::ICCProfile(ICCProfile&& other) = default; |
| 112 | ICCProfile::ICCProfile(const ICCProfile& other) = default; |
| 113 | ICCProfile& ICCProfile::operator=(ICCProfile&& other) = default; |
| 114 | ICCProfile& ICCProfile::operator=(const ICCProfile& other) = default; |
| 115 | ICCProfile::~ICCProfile() = default; |
| 116 | |
| 117 | bool ICCProfile::operator==(const ICCProfile& other) const { |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 118 | if (!internals_ && !other.internals_) |
| 119 | return true; |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 120 | if (internals_ && other.internals_) { |
| 121 | return internals_->data_ == other.internals_->data_ && |
| 122 | internals_->id_ == other.internals_->id_; |
| 123 | } |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 124 | return false; |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 125 | } |
| 126 | |
ccameron | c21ca23b | 2017-01-20 03:34:01 | [diff] [blame] | 127 | bool ICCProfile::operator!=(const ICCProfile& other) const { |
| 128 | return !(*this == other); |
| 129 | } |
| 130 | |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 131 | bool ICCProfile::IsValid() const { |
| 132 | return internals_ ? internals_->is_valid_ : false; |
| 133 | } |
| 134 | |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 135 | std::vector<char> ICCProfile::GetData() const { |
| 136 | return internals_ ? internals_->data_ : std::vector<char>(); |
| 137 | } |
| 138 | |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 139 | // static |
ccameron | 549738b | 2017-01-28 17:39:32 | [diff] [blame] | 140 | ICCProfile ICCProfile::FromData(const void* data, size_t size) { |
ccameron | 9b2a0b1b | 2017-02-02 23:29:14 | [diff] [blame] | 141 | return FromDataWithId(data, size, 0); |
| 142 | } |
| 143 | |
| 144 | // static |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 145 | ICCProfile ICCProfile::FromDataWithId(const void* data_as_void, |
ccameron | 9b2a0b1b | 2017-02-02 23:29:14 | [diff] [blame] | 146 | size_t size, |
| 147 | uint64_t new_profile_id) { |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 148 | const char* data_as_byte = reinterpret_cast<const char*>(data_as_void); |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 149 | std::vector<char> data(data_as_byte, data_as_byte + size); |
Reilly Grant | c46032eb | 2017-08-30 22:53:52 | [diff] [blame] | 150 | |
Daniel Bratell | b6c0ab8c | 2017-12-21 13:09:18 | [diff] [blame] | 151 | base::AutoLock lock(g_icc_profile_lock.Get()); |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 152 | |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 153 | // See if there is already an entry with the same data. If so, return that |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 154 | // entry. If not, parse the data. |
| 155 | ICCProfile icc_profile; |
| 156 | auto found_by_data = g_data_to_profile_cache.Get().Get(data); |
| 157 | if (found_by_data != g_data_to_profile_cache.Get().end()) { |
| 158 | icc_profile = found_by_data->second; |
| 159 | } else { |
| 160 | icc_profile.internals_ = |
| 161 | base::MakeRefCounted<Internals>(std::move(data), new_profile_id); |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 162 | } |
| 163 | |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 164 | // Insert the profile into all caches. |
| 165 | ColorSpace color_space = icc_profile.GetColorSpace(); |
| 166 | if (color_space.IsValid()) |
| 167 | g_space_to_profile_cache_mac.Get().Put(color_space, icc_profile); |
| 168 | if (icc_profile.internals_->id_) |
| 169 | g_id_to_profile_cache.Get().Put(icc_profile.internals_->id_, icc_profile); |
| 170 | g_data_to_profile_cache.Get().Put(icc_profile.internals_->data_, icc_profile); |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 171 | |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 172 | return icc_profile; |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 173 | } |
| 174 | |
Christopher Cameron | fdc0f87 | 2017-11-09 03:22:16 | [diff] [blame] | 175 | ColorSpace ICCProfile::GetColorSpace() const { |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 176 | if (!internals_) |
| 177 | return ColorSpace(); |
Christopher Cameron | fdc0f87 | 2017-11-09 03:22:16 | [diff] [blame] | 178 | |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 179 | if (!internals_->is_valid_) |
Christopher Cameron | fdc0f87 | 2017-11-09 03:22:16 | [diff] [blame] | 180 | return ColorSpace(); |
| 181 | |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 182 | // TODO(ccameron): Compute a reasonable approximation instead of always |
| 183 | // falling back to sRGB. |
Christopher Cameron | fdc0f87 | 2017-11-09 03:22:16 | [diff] [blame] | 184 | ColorSpace color_space = |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 185 | internals_->sk_color_space_->isSRGB() |
Christopher Cameron | fdc0f87 | 2017-11-09 03:22:16 | [diff] [blame] | 186 | ? ColorSpace::CreateSRGB() |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 187 | : ColorSpace::CreateCustom(internals_->to_XYZD50_, |
| 188 | internals_->transfer_fn_); |
Brian Osman | 8c2c27cb | 2018-04-23 22:50:09 | [diff] [blame] | 189 | color_space.icc_profile_id_ = internals_->id_; |
Christopher Cameron | fdc0f87 | 2017-11-09 03:22:16 | [diff] [blame] | 190 | return color_space; |
ccameron | 24c87c3 | 2017-03-14 21:50:42 | [diff] [blame] | 191 | } |
| 192 | |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 193 | // static |
| 194 | ICCProfile ICCProfile::FromParametricColorSpace(const ColorSpace& color_space) { |
| 195 | if (!color_space.IsValid()) { |
| 196 | return ICCProfile(); |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 197 | } |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 198 | if (color_space.matrix_ != ColorSpace::MatrixID::RGB) { |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 199 | DLOG(ERROR) << "Not creating non-RGB ICCProfile"; |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 200 | return ICCProfile(); |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 201 | } |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 202 | if (color_space.range_ != ColorSpace::RangeID::FULL) { |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 203 | DLOG(ERROR) << "Not creating non-full-range ICCProfile"; |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 204 | return ICCProfile(); |
| 205 | } |
| 206 | if (color_space.icc_profile_id_) { |
| 207 | DLOG(ERROR) << "Not creating non-parametric ICCProfile"; |
| 208 | return ICCProfile(); |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 209 | } |
| 210 | |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 211 | SkMatrix44 to_XYZD50_matrix; |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 212 | color_space.GetPrimaryMatrix(&to_XYZD50_matrix); |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 213 | SkColorSpaceTransferFn fn; |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 214 | if (!color_space.GetTransferFunction(&fn)) { |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 215 | DLOG(ERROR) << "Failed to get ColorSpace transfer function for ICCProfile."; |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 216 | return ICCProfile(); |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 217 | } |
| 218 | sk_sp<SkData> data = SkICC::WriteToICC(fn, to_XYZD50_matrix); |
| 219 | if (!data) { |
| 220 | DLOG(ERROR) << "Failed to create SkICC."; |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 221 | return ICCProfile(); |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 222 | } |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 223 | return FromDataWithId(data->data(), data->size(), 0); |
| 224 | } |
| 225 | |
| 226 | // static |
| 227 | ICCProfile ICCProfile::FromCacheMac(const ColorSpace& color_space) { |
Daniel Bratell | b6c0ab8c | 2017-12-21 13:09:18 | [diff] [blame] | 228 | base::AutoLock lock(g_icc_profile_lock.Get()); |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 229 | auto found_by_space = g_space_to_profile_cache_mac.Get().Get(color_space); |
| 230 | if (found_by_space != g_space_to_profile_cache_mac.Get().end()) |
| 231 | return found_by_space->second; |
| 232 | |
| 233 | if (color_space.icc_profile_id_) { |
| 234 | DLOG(ERROR) << "Failed to find id-based ColorSpace in ICCProfile cache"; |
| 235 | } |
| 236 | return ICCProfile(); |
| 237 | } |
| 238 | |
| 239 | // static |
| 240 | sk_sp<SkColorSpace> ICCProfile::GetSkColorSpaceFromId(uint64_t id) { |
Daniel Bratell | b6c0ab8c | 2017-12-21 13:09:18 | [diff] [blame] | 241 | base::AutoLock lock(g_icc_profile_lock.Get()); |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 242 | auto found = g_id_to_profile_cache.Get().Get(id); |
| 243 | if (found == g_id_to_profile_cache.Get().end()) { |
| 244 | DLOG(ERROR) << "Failed to find ICC profile with SkColorSpace from id."; |
| 245 | return nullptr; |
| 246 | } |
| 247 | return found->second.internals_->sk_color_space_; |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 248 | } |
| 249 | |
| 250 | ICCProfile::Internals::Internals(std::vector<char> data, uint64_t id) |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 251 | : data_(std::move(data)), id_(id) { |
Christopher Cameron | 374b6c4 | 2017-08-31 22:21:23 | [diff] [blame] | 252 | // Early out for empty entries. |
| 253 | if (data_.empty()) |
ccameron | 549738b | 2017-01-28 17:39:32 | [diff] [blame] | 254 | return; |
suzyh | c3de81a | 2017-01-27 00:28:10 | [diff] [blame] | 255 | |
Christopher Cameron | a4adb41b | 2017-07-13 06:44:25 | [diff] [blame] | 256 | // Parse the ICC profile |
Christopher Cameron | fdc0f87 | 2017-11-09 03:22:16 | [diff] [blame] | 257 | analyze_result_ = Initialize(); |
ccameron | e35e232 | 2017-11-02 23:33:46 | [diff] [blame] | 258 | switch (analyze_result_) { |
Brian Osman | 37233e3 | 2018-05-17 16:53:17 | [diff] [blame^] | 259 | case kICCExtractedMatrixAndTrFn: |
ccameron | e35e232 | 2017-11-02 23:33:46 | [diff] [blame] | 260 | // Successfully and accurately extracted color space. |
Christopher Cameron | fdc0f87 | 2017-11-09 03:22:16 | [diff] [blame] | 261 | is_valid_ = true; |
| 262 | is_parametric_ = true; |
ccameron | e35e232 | 2017-11-02 23:33:46 | [diff] [blame] | 263 | break; |
ccameron | e35e232 | 2017-11-02 23:33:46 | [diff] [blame] | 264 | case kICCFailedToParse: |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 265 | case kICCNoProfile: |
Brian Osman | 37233e3 | 2018-05-17 16:53:17 | [diff] [blame^] | 266 | case kICCFailedToMakeUsable: |
ccameron | e35e232 | 2017-11-02 23:33:46 | [diff] [blame] | 267 | // Can't even use this color space as a LUT. |
Christopher Cameron | fdc0f87 | 2017-11-09 03:22:16 | [diff] [blame] | 268 | is_valid_ = false; |
| 269 | is_parametric_ = false; |
ccameron | e35e232 | 2017-11-02 23:33:46 | [diff] [blame] | 270 | break; |
| 271 | } |
Christopher Cameron | deea252 | 2017-11-16 07:10:52 | [diff] [blame] | 272 | |
| 273 | if (id_) { |
| 274 | // If |id_| has been set here, then it was specified via sending an |
| 275 | // ICCProfile over IPC. Ensure that the computation of |is_valid_| and |
| 276 | // |is_parametric_| match the analysis done in the sending process. |
| 277 | DCHECK(is_valid_ && !is_parametric_); |
| 278 | } else { |
| 279 | // If this profile is not parametric, assign it an id so that we can look it |
| 280 | // up from a ColorSpace. This path should only be hit in the browser |
| 281 | // process. |
| 282 | if (is_valid_ && !is_parametric_) { |
| 283 | id_ = g_next_unused_id++; |
| 284 | } |
| 285 | } |
Christopher Cameron | 374b6c4 | 2017-08-31 22:21:23 | [diff] [blame] | 286 | } |
| 287 | |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 288 | ICCProfile::Internals::~Internals() {} |
| 289 | |
Christopher Cameron | 374b6c4 | 2017-08-31 22:21:23 | [diff] [blame] | 290 | void ICCProfile::HistogramDisplay(int64_t display_id) const { |
Christopher Cameron | 3bc3d5e | 2017-11-23 03:48:11 | [diff] [blame] | 291 | if (!internals_) { |
| 292 | // If this is an uninitialized profile, histogram it using an empty profile, |
| 293 | // so that we only histogram this display as empty once. |
| 294 | FromData(nullptr, 0).HistogramDisplay(display_id); |
| 295 | } else { |
| 296 | internals_->HistogramDisplay(display_id); |
| 297 | } |
Christopher Cameron | 43f1705 | 2017-11-11 01:52:01 | [diff] [blame] | 298 | } |
| 299 | |
| 300 | void ICCProfile::Internals::HistogramDisplay(int64_t display_id) { |
| 301 | // Ensure that we histogram this profile only once per display id. |
| 302 | if (histogrammed_display_ids_.count(display_id)) |
| 303 | return; |
| 304 | histogrammed_display_ids_.insert(display_id); |
Christopher Cameron | 374b6c4 | 2017-08-31 22:21:23 | [diff] [blame] | 305 | |
| 306 | UMA_HISTOGRAM_ENUMERATION("Blink.ColorSpace.Destination.ICCResult", |
Brian Osman | 37233e3 | 2018-05-17 16:53:17 | [diff] [blame^] | 307 | analyze_result_); |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 308 | } |
| 309 | |
ccameron | efdab16 | 2016-07-25 23:00:02 | [diff] [blame] | 310 | } // namespace gfx |