Home | History | Annotate | Download | only in gfx
      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