Home | History | Annotate | Download | only in win
      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/win/dpi.h"
      6 
      7 #include <windows.h>
      8 #include "base/command_line.h"
      9 #include "base/win/scoped_hdc.h"
     10 #include "base/win/windows_version.h"
     11 #include "base/win/registry.h"
     12 #include "ui/gfx/display.h"
     13 #include "ui/gfx/switches.h"
     14 #include "ui/gfx/point_conversions.h"
     15 #include "ui/gfx/rect_conversions.h"
     16 #include "ui/gfx/size_conversions.h"
     17 
     18 namespace {
     19 
     20 int kDefaultDPIX = 96;
     21 int kDefaultDPIY = 96;
     22 
     23 BOOL IsProcessDPIAwareWrapper() {
     24   typedef BOOL(WINAPI *IsProcessDPIAwarePtr)(VOID);
     25   IsProcessDPIAwarePtr is_process_dpi_aware_func =
     26       reinterpret_cast<IsProcessDPIAwarePtr>(
     27           GetProcAddress(GetModuleHandleA("user32.dll"), "IsProcessDPIAware"));
     28   if (is_process_dpi_aware_func)
     29     return is_process_dpi_aware_func();
     30   return FALSE;
     31 }
     32 
     33 float g_device_scale_factor = 0.0f;
     34 
     35 float GetUnforcedDeviceScaleFactor() {
     36   return static_cast<float>(gfx::GetDPI().width()) /
     37       static_cast<float>(kDefaultDPIX);
     38 }
     39 
     40 float GetModernUIScaleWrapper() {
     41   float result = 1.0f;
     42   typedef float(WINAPI *GetModernUIScalePtr)(VOID);
     43   HMODULE lib = LoadLibraryA("metro_driver.dll");
     44   if (lib) {
     45     GetModernUIScalePtr func =
     46         reinterpret_cast<GetModernUIScalePtr>(
     47         GetProcAddress(lib, "GetModernUIScale"));
     48     if (func)
     49       result = func();
     50     FreeLibrary(lib);
     51   }
     52   return result;
     53 }
     54 
     55 }  // namespace
     56 
     57 namespace gfx {
     58 
     59 float GetModernUIScale() {
     60   return GetModernUIScaleWrapper();
     61 }
     62 
     63 void InitDeviceScaleFactor(float scale) {
     64   DCHECK_NE(0.0f, scale);
     65   g_device_scale_factor = scale;
     66 }
     67 
     68 Size GetDPI() {
     69   static int dpi_x = 0;
     70   static int dpi_y = 0;
     71   static bool should_initialize = true;
     72 
     73   if (should_initialize) {
     74     should_initialize = false;
     75     base::win::ScopedGetDC screen_dc(NULL);
     76     // This value is safe to cache for the life time of the app since the
     77     // user must logout to change the DPI setting. This value also applies
     78     // to all screens.
     79     dpi_x = GetDeviceCaps(screen_dc, LOGPIXELSX);
     80     dpi_y = GetDeviceCaps(screen_dc, LOGPIXELSY);
     81   }
     82   return Size(dpi_x, dpi_y);
     83 }
     84 
     85 float GetDPIScale() {
     86   if (IsHighDPIEnabled()) {
     87     return gfx::Display::HasForceDeviceScaleFactor() ?
     88         gfx::Display::GetForcedDeviceScaleFactor() :
     89         GetUnforcedDeviceScaleFactor();
     90   }
     91   return 1.0;
     92 }
     93 
     94 bool IsHighDPIEnabled() {
     95   // Default is disabled.
     96   if (CommandLine::ForCurrentProcess()->HasSwitch(
     97       switches::kHighDPISupport)) {
     98     return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
     99         switches::kHighDPISupport).compare("1") == 0;
    100   }
    101   return false;
    102 }
    103 
    104 bool IsInHighDPIMode() {
    105   return GetDPIScale() > 1.0;
    106 }
    107 
    108 void EnableHighDPISupport() {
    109   if (IsHighDPIEnabled() &&
    110       (base::win::GetVersion() < base::win::VERSION_WIN8_1)) {
    111     typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID);
    112     SetProcessDPIAwarePtr set_process_dpi_aware_func =
    113         reinterpret_cast<SetProcessDPIAwarePtr>(
    114             GetProcAddress(GetModuleHandleA("user32.dll"),
    115                            "SetProcessDPIAware"));
    116     if (set_process_dpi_aware_func)
    117       set_process_dpi_aware_func();
    118   }
    119 }
    120 
    121 namespace win {
    122 
    123 float GetDeviceScaleFactor() {
    124   DCHECK_NE(0.0f, g_device_scale_factor);
    125   return g_device_scale_factor;
    126 }
    127 
    128 Point ScreenToDIPPoint(const Point& pixel_point) {
    129   static float scaling_factor =
    130       GetDeviceScaleFactor() > GetUnforcedDeviceScaleFactor() ?
    131       1.0f / GetDeviceScaleFactor() :
    132       1.0f;
    133   return ToFlooredPoint(ScalePoint(pixel_point,
    134       scaling_factor));
    135 }
    136 
    137 Point DIPToScreenPoint(const Point& dip_point) {
    138   return ToFlooredPoint(ScalePoint(dip_point, GetDeviceScaleFactor()));
    139 }
    140 
    141 Rect ScreenToDIPRect(const Rect& pixel_bounds) {
    142   // TODO(kevers): Switch to non-deprecated method for float to int conversions.
    143   return ToFlooredRectDeprecated(
    144       ScaleRect(pixel_bounds, 1.0f / GetDeviceScaleFactor()));
    145 }
    146 
    147 Rect DIPToScreenRect(const Rect& dip_bounds) {
    148   // TODO(kevers): Switch to non-deprecated method for float to int conversions.
    149   return ToFlooredRectDeprecated(
    150       ScaleRect(dip_bounds, GetDeviceScaleFactor()));
    151 }
    152 
    153 Size ScreenToDIPSize(const Size& size_in_pixels) {
    154   return ToFlooredSize(
    155       ScaleSize(size_in_pixels, 1.0f / GetDeviceScaleFactor()));
    156 }
    157 
    158 Size DIPToScreenSize(const Size& dip_size) {
    159   return ToFlooredSize(ScaleSize(dip_size, GetDeviceScaleFactor()));
    160 }
    161 
    162 int GetSystemMetricsInDIP(int metric) {
    163   return static_cast<int>(GetSystemMetrics(metric) /
    164       GetDeviceScaleFactor() + 0.5);
    165 }
    166 
    167 double GetUndocumentedDPIScale() {
    168   // TODO(girard): Remove this code when chrome is DPIAware.
    169   static double scale = -1.0;
    170   if (scale == -1.0) {
    171     scale = 1.0;
    172     if (!IsProcessDPIAwareWrapper()) {
    173       base::win::RegKey key(HKEY_CURRENT_USER,
    174                             L"Control Panel\\Desktop\\WindowMetrics",
    175                             KEY_QUERY_VALUE);
    176       if (key.Valid()) {
    177         DWORD value = 0;
    178         if (key.ReadValueDW(L"AppliedDPI", &value) == ERROR_SUCCESS) {
    179           scale = static_cast<double>(value) / kDefaultDPIX;
    180         }
    181       }
    182     }
    183   }
    184   return scale;
    185 }
    186 
    187 double GetUndocumentedDPITouchScale() {
    188   static double scale =
    189       (base::win::GetVersion() < base::win::VERSION_WIN8_1) ?
    190       GetUndocumentedDPIScale() : 1.0;
    191   return scale;
    192 }
    193 
    194 }  // namespace win
    195 }  // namespace gfx
    196