Index: ui/gfx/color_space.cc |
diff --git a/ui/gfx/color_space.cc b/ui/gfx/color_space.cc |
index 7650b1e3a9d274e45bbb538fb08041a19607d863..f2fdced3bb443359a01c9d44e3a8bb37c48fb32a 100644 |
--- a/ui/gfx/color_space.cc |
+++ b/ui/gfx/color_space.cc |
@@ -2,15 +2,89 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "build/build_config.h" |
#include "ui/gfx/color_space.h" |
+#include <map> |
+ |
+#include "base/synchronization/lock.h" |
+ |
namespace gfx { |
namespace { |
static const size_t kMinProfileLength = 128; |
static const size_t kMaxProfileLength = 4 * 1024 * 1024; |
-} |
+} // namespace |
+ |
+// The structure used to look up GlobalData structures. |
+struct ColorSpace::Key { |
+ Key(ColorSpace::Type type, const std::vector<char>& icc_profile) |
+ : type(type), icc_profile(icc_profile) {} |
+ |
+ bool operator<(const Key& other) const { |
+ if (type < other.type) |
+ return true; |
+ if (type > other.type) |
+ return false; |
+ if (type != Type::ICC_PROFILE) |
+ return false; |
+ |
+ if (icc_profile.size() < other.icc_profile.size()) |
+ return true; |
+ if (icc_profile.size() > other.icc_profile.size()) |
+ return false; |
+ for (size_t i = 0; i < icc_profile.size(); ++i) { |
+ if (icc_profile[i] < other.icc_profile[i]) |
+ return true; |
+ if (icc_profile[i] > other.icc_profile[i]) |
+ return false; |
+ } |
+ return false; |
+ } |
+ |
+ ColorSpace::Type type; |
+ const std::vector<char> icc_profile; |
+}; |
+ |
+// Because this structure is shared across gfx::ColorSpace objects on |
+// different threads, it needs to be thread-safe. |
+class ColorSpace::GlobalData |
+ : public base::RefCountedThreadSafe<ColorSpace::GlobalData> { |
+ public: |
+ static void Get(const Key& key, scoped_refptr<GlobalData>* value) { |
+ base::AutoLock lock(map_lock_); |
+ auto insert_result = map_.insert(std::make_pair(key, nullptr)); |
+ if (insert_result.second) |
+ insert_result.first->second = new GlobalData(key, insert_result.first); |
+ *value = make_scoped_refptr(insert_result.first->second); |
+ } |
+ |
+ const std::vector<char>& GetICCProfile() const { return icc_profile_; } |
+ |
+ private: |
+ friend class base::RefCountedThreadSafe<GlobalData>; |
+ |
+ GlobalData(const Key& key, std::map<Key, GlobalData*>::iterator iterator) |
+ : iterator_(iterator) { |
+ // TODO: Compute the ICC profile for named color spaces. |
+ if (key.type == Type::ICC_PROFILE) |
+ icc_profile_ = key.icc_profile; |
+ } |
+ ~GlobalData() { |
+ base::AutoLock lock(map_lock_); |
+ map_.erase(iterator_); |
+ } |
+ |
+ std::vector<char> icc_profile_; |
+ |
+ // In order to remove |this| from |map_| when its last reference goes away, |
+ // keep in |iterator_| the corresponding iterator in |map_|. |
+ std::map<Key, GlobalData*>::iterator iterator_; |
hubbe
2016/07/12 05:12:40
Seems like map_.erase(Key(icc_profile_)) would wor
ccameron
2016/07/12 19:11:03
True, ror now it's pretty small (we'd also need th
|
+ static std::map<Key, GlobalData*> map_; |
+ static base::Lock map_lock_; |
+}; |
+ |
+std::map<ColorSpace::Key, ColorSpace::GlobalData*> ColorSpace::GlobalData::map_; |
+base::Lock ColorSpace::GlobalData::map_lock_; |
Dan Beam
2016/07/13 19:15:10
i think these are adding static initializers:
http
|
ColorSpace::ColorSpace() = default; |
ColorSpace::ColorSpace(ColorSpace&& other) = default; |
@@ -19,13 +93,26 @@ ColorSpace& ColorSpace::operator=(const ColorSpace& other) = default; |
ColorSpace::~ColorSpace() = default; |
bool ColorSpace::operator==(const ColorSpace& other) const { |
- return icc_profile_ == other.icc_profile_; |
+ if (type_ == Type::ICC_PROFILE && other.type_ == Type::ICC_PROFILE) |
+ return global_data_ == other.global_data_; |
+ return type_ == other.type_; |
} |
+bool ColorSpace::operator<(const ColorSpace& other) const { |
+ // Note that this does a pointer-based comparision. |
+ if (type_ == Type::ICC_PROFILE && other.type_ == Type::ICC_PROFILE) |
+ return global_data_.get() < other.global_data_.get(); |
+ return type_ < other.type_; |
+} |
+ |
+// static |
ColorSpace ColorSpace::FromICCProfile(const std::vector<char>& icc_profile) { |
ColorSpace color_space; |
- if (IsValidProfileLength(icc_profile.size())) |
- color_space.icc_profile_ = icc_profile; |
+ if (IsValidProfileLength(icc_profile.size())) { |
+ color_space.type_ = Type::ICC_PROFILE; |
+ Key key(Type::ICC_PROFILE, icc_profile); |
+ GlobalData::Get(key, &color_space.global_data_); |
+ } |
return color_space; |
} |
@@ -36,6 +123,14 @@ ColorSpace ColorSpace::FromBestMonitor() { |
} |
#endif |
+const std::vector<char>& ColorSpace::GetICCProfile() const { |
+ if (!global_data_) { |
+ Key key(type_, std::vector<char>()); |
+ GlobalData::Get(key, &global_data_); |
+ } |
+ return global_data_->GetICCProfile(); |
+} |
+ |
// static |
bool ColorSpace::IsValidProfileLength(size_t length) { |
return length >= kMinProfileLength && length <= kMaxProfileLength; |