| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_profile.h" | 5 #include "ui/gfx/color_profile.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <map> | 9 #include <map> |
| 10 | 10 |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
| 13 #include "base/macros.h" | 13 #include "base/macros.h" |
| 14 #include "base/synchronization/lock.h" | 14 #include "base/synchronization/lock.h" |
| 15 | 15 |
| 16 namespace gfx { | 16 namespace gfx { |
| 17 | 17 |
| 18 class ColorProfileCache { | 18 namespace { |
| 19 public: | |
| 20 // A thread-safe cache of color profiles keyed by windows device name. | |
| 21 ColorProfileCache() {} | |
| 22 | 19 |
| 23 bool Find(const std::wstring& device, std::vector<char>* profile) { | 20 void ReadBestMonitorColorProfile(std::vector<char>* profile) { |
| 24 base::AutoLock lock(lock_); | |
| 25 DeviceColorProfile::const_iterator it = cache_.find(device); | |
| 26 if (it == cache_.end()) | |
| 27 return false; | |
| 28 *profile = it->second; | |
| 29 return true; | |
| 30 } | |
| 31 | |
| 32 void Insert(const std::wstring& device, const std::vector<char>& profile) { | |
| 33 base::AutoLock lock(lock_); | |
| 34 cache_[device] = profile; | |
| 35 } | |
| 36 | |
| 37 bool Erase(const std::wstring& device) { | |
| 38 base::AutoLock lock(lock_); | |
| 39 DeviceColorProfile::iterator it = cache_.find(device); | |
| 40 if (it == cache_.end()) | |
| 41 return false; | |
| 42 cache_.erase(device); | |
| 43 return true; | |
| 44 } | |
| 45 | |
| 46 void Clear() { | |
| 47 base::AutoLock lock(lock_); | |
| 48 cache_.clear(); | |
| 49 } | |
| 50 | |
| 51 private: | |
| 52 typedef std::map<std::wstring, std::vector<char> > DeviceColorProfile; | |
| 53 | |
| 54 DeviceColorProfile cache_; | |
| 55 base::Lock lock_; | |
| 56 | |
| 57 DISALLOW_COPY_AND_ASSIGN(ColorProfileCache); | |
| 58 }; | |
| 59 | |
| 60 base::LazyInstance<ColorProfileCache>::Leaky g_color_profile_cache = | |
| 61 LAZY_INSTANCE_INITIALIZER; | |
| 62 | |
| 63 inline ColorProfileCache& GetColorProfileCache() { | |
| 64 return g_color_profile_cache.Get(); | |
| 65 } | |
| 66 | |
| 67 bool GetDisplayColorProfile(const gfx::Rect& bounds, | |
| 68 std::vector<char>* profile) { | |
| 69 DCHECK(profile->empty()); | |
| 70 | |
| 71 RECT rect = bounds.ToRECT(); | |
| 72 HMONITOR handle = ::MonitorFromRect(&rect, MONITOR_DEFAULTTONULL); | |
| 73 if (bounds.IsEmpty() || !handle) | |
| 74 return false; | |
| 75 | |
| 76 MONITORINFOEX monitor; | |
| 77 monitor.cbSize = sizeof(MONITORINFOEX); | |
| 78 CHECK(::GetMonitorInfo(handle, &monitor)); | |
| 79 if (GetColorProfileCache().Find(monitor.szDevice, profile)) | |
| 80 return true; | |
| 81 | |
| 82 HDC hdc = ::CreateDC(monitor.szDevice, NULL, NULL, NULL); | |
| 83 DWORD path_length = MAX_PATH; | |
| 84 WCHAR path[MAX_PATH + 1]; | |
| 85 BOOL result = ::GetICMProfile(hdc, &path_length, path); | |
| 86 ::DeleteDC(hdc); | |
| 87 if (!result) | |
| 88 return false; | |
| 89 | |
| 90 base::FilePath file_name = base::FilePath(path).BaseName(); | |
| 91 if (file_name != base::FilePath(L"sRGB Color Space Profile.icm")) { | |
| 92 std::string data; | |
| 93 if (base::ReadFileToString(base::FilePath(path), &data)) | |
| 94 profile->assign(data.data(), data.data() + data.size()); | |
| 95 size_t length = profile->size(); | |
| 96 if (gfx::InvalidColorProfileLength(length)) | |
| 97 profile->clear(); | |
| 98 } | |
| 99 | |
| 100 GetColorProfileCache().Insert(monitor.szDevice, *profile); | |
| 101 return true; | |
| 102 } | |
| 103 | |
| 104 void ReadColorProfile(std::vector<char>* profile) { | |
| 105 // TODO: support multiple monitors. | |
| 106 HDC screen_dc = GetDC(NULL); | 21 HDC screen_dc = GetDC(NULL); |
| 107 DWORD path_len = MAX_PATH; | 22 DWORD path_len = MAX_PATH; |
| 108 WCHAR path[MAX_PATH + 1]; | 23 WCHAR path[MAX_PATH + 1]; |
| 109 | 24 |
| 110 BOOL result = GetICMProfile(screen_dc, &path_len, path); | 25 BOOL result = GetICMProfile(screen_dc, &path_len, path); |
| 111 ReleaseDC(NULL, screen_dc); | 26 ReleaseDC(NULL, screen_dc); |
| 112 if (!result) | 27 if (!result) |
| 113 return; | 28 return; |
| 114 std::string profileData; | 29 std::string profileData; |
| 115 if (!base::ReadFileToString(base::FilePath(path), &profileData)) | 30 if (!base::ReadFileToString(base::FilePath(path), &profileData)) |
| 116 return; | 31 return; |
| 117 size_t length = profileData.size(); | 32 size_t length = profileData.size(); |
| 118 if (gfx::InvalidColorProfileLength(length)) | 33 if (!ColorProfile::IsValidProfileLength(length)) |
| 119 return; | 34 return; |
| 120 profile->assign(profileData.data(), profileData.data() + length); | 35 profile->assign(profileData.data(), profileData.data() + length); |
| 121 } | 36 } |
| 122 | 37 |
| 38 base::LazyInstance<base::Lock> g_best_color_profile_lock = |
| 39 LAZY_INSTANCE_INITIALIZER; |
| 40 base::LazyInstance<gfx::ColorProfile> g_best_color_profile = |
| 41 LAZY_INSTANCE_INITIALIZER; |
| 42 bool g_has_initialized_best_color_profile = false; |
| 43 |
| 44 } // namespace |
| 45 |
| 46 // static |
| 47 ColorProfile ColorProfile::GetFromBestMonitor() { |
| 48 base::AutoLock lock(g_best_color_profile_lock.Get()); |
| 49 return g_best_color_profile.Get(); |
| 50 } |
| 51 |
| 52 // static |
| 53 bool ColorProfile::CachedProfilesNeedUpdate() { |
| 54 base::AutoLock lock(g_best_color_profile_lock.Get()); |
| 55 return !g_has_initialized_best_color_profile; |
| 56 } |
| 57 |
| 58 // static |
| 59 void ColorProfile::UpdateCachedProfilesOnBackgroundThread() { |
| 60 std::vector<char> profile; |
| 61 ReadBestMonitorColorProfile(&profile); |
| 62 |
| 63 base::AutoLock lock(g_best_color_profile_lock.Get()); |
| 64 g_best_color_profile.Get().profile_ = profile; |
| 65 g_has_initialized_best_color_profile = true; |
| 66 } |
| 67 |
| 123 } // namespace gfx | 68 } // namespace gfx |
| OLD | NEW |