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 <windows.h> 8#include <map> 9 10#include "base/files/file_util.h" 11#include "base/lazy_instance.h" 12#include "base/synchronization/lock.h" 13 14namespace gfx { 15 16class 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 58base::LazyInstance<ColorProfileCache>::Leaky g_color_profile_cache = 59 LAZY_INSTANCE_INITIALIZER; 60 61inline ColorProfileCache& GetColorProfileCache() { 62 return g_color_profile_cache.Get(); 63} 64 65bool 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 102void 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