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