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/base/win/dpi.h"
      6 
      7 #include <windows.h>
      8 #include "base/command_line.h"
      9 #include "base/win/scoped_hdc.h"
     10 #include "ui/base/layout.h"
     11 #include "base/win/registry.h"
     12 #include "ui/base/ui_base_switches.h"
     13 #include "ui/gfx/display.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 // Tests to see if the command line flag "--high-dpi-support" is set.
     24 bool IsHighDPIEnabled() {
     25   // Default is disabled.
     26   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kHighDPISupport)) {
     27     return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
     28         switches::kHighDPISupport).compare("1") == 0;
     29   }
     30   return false;
     31 }
     32 
     33 // Gets the device scale factor. If support is enabled, this will return the
     34 // best available scale based on the screen's pixel density. This can be
     35 // affected (overridden) by --force-device-scale-factor=x
     36 float GetDeviceScaleFactorImpl() {
     37   if (IsHighDPIEnabled()) {
     38     float scale = gfx::Display::HasForceDeviceScaleFactor() ?
     39         gfx::Display::GetForcedDeviceScaleFactor() : ui::GetDPIScale();
     40     // Quantize to nearest supported scale factor.
     41     scale = ui::GetScaleFactorScale(ui::GetScaleFactorFromScale(scale));
     42     return scale;
     43   }
     44   return 1.0f;
     45 }
     46 
     47 BOOL IsProcessDPIAwareWrapper() {
     48   typedef BOOL(WINAPI *IsProcessDPIAwarePtr)(VOID);
     49   IsProcessDPIAwarePtr is_process_dpi_aware_func =
     50       reinterpret_cast<IsProcessDPIAwarePtr>(
     51           GetProcAddress(GetModuleHandleA("user32.dll"), "IsProcessDPIAware"));
     52   if (is_process_dpi_aware_func)
     53     return is_process_dpi_aware_func();
     54   return FALSE;
     55 }
     56 
     57 }  // namespace
     58 
     59 namespace ui {
     60 
     61 gfx::Size GetDPI() {
     62   static int dpi_x = 0;
     63   static int dpi_y = 0;
     64   static bool should_initialize = true;
     65 
     66   if (should_initialize) {
     67     should_initialize = false;
     68     base::win::ScopedGetDC screen_dc(NULL);
     69     // This value is safe to cache for the life time of the app since the
     70     // user must logout to change the DPI setting. This value also applies
     71     // to all screens.
     72     dpi_x = GetDeviceCaps(screen_dc, LOGPIXELSX);
     73     dpi_y = GetDeviceCaps(screen_dc, LOGPIXELSY);
     74   }
     75   return gfx::Size(dpi_x, dpi_y);
     76 }
     77 
     78 float GetDPIScale() {
     79   if (IsHighDPIEnabled()) {
     80     return static_cast<float>(GetDPI().width()) /
     81         static_cast<float>(kDefaultDPIX);
     82   }
     83   return 1.0;
     84 }
     85 
     86 bool IsInHighDPIMode() {
     87   return GetDPIScale() > 1.0;
     88 }
     89 
     90 void EnableHighDPISupport() {
     91   if (IsHighDPIEnabled()) {
     92     typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID);
     93     SetProcessDPIAwarePtr set_process_dpi_aware_func =
     94         reinterpret_cast<SetProcessDPIAwarePtr>(
     95             GetProcAddress(GetModuleHandleA("user32.dll"),
     96                            "SetProcessDPIAware"));
     97     if (set_process_dpi_aware_func)
     98       set_process_dpi_aware_func();
     99   }
    100 }
    101 
    102 namespace win {
    103 
    104 float GetDeviceScaleFactor() {
    105   static const float device_scale_factor = GetDeviceScaleFactorImpl();
    106   return device_scale_factor;
    107 }
    108 
    109 gfx::Point ScreenToDIPPoint(const gfx::Point& pixel_point) {
    110   return gfx::ToFlooredPoint(
    111       gfx::ScalePoint(pixel_point, 1.0f / GetDeviceScaleFactor()));
    112 }
    113 
    114 gfx::Point DIPToScreenPoint(const gfx::Point& dip_point) {
    115   return gfx::ToFlooredPoint(
    116       gfx::ScalePoint(dip_point, GetDeviceScaleFactor()));
    117 }
    118 
    119 gfx::Rect ScreenToDIPRect(const gfx::Rect& pixel_bounds) {
    120   // TODO(kevers): Switch to non-deprecated method for float to int conversions.
    121   return gfx::ToFlooredRectDeprecated(
    122       gfx::ScaleRect(pixel_bounds, 1.0f / GetDeviceScaleFactor()));
    123 }
    124 
    125 gfx::Rect DIPToScreenRect(const gfx::Rect& dip_bounds) {
    126   // TODO(kevers): Switch to non-deprecated method for float to int conversions.
    127   return gfx::ToFlooredRectDeprecated(
    128       gfx::ScaleRect(dip_bounds, GetDeviceScaleFactor()));
    129 }
    130 
    131 gfx::Size ScreenToDIPSize(const gfx::Size& size_in_pixels) {
    132   return gfx::ToFlooredSize(
    133       gfx::ScaleSize(size_in_pixels, 1.0f / GetDeviceScaleFactor()));
    134 }
    135 
    136 gfx::Size DIPToScreenSize(const gfx::Size& dip_size) {
    137   return gfx::ToFlooredSize(gfx::ScaleSize(dip_size, GetDeviceScaleFactor()));
    138 }
    139 
    140 int GetSystemMetricsInDIP(int metric) {
    141   return static_cast<int>(GetSystemMetrics(metric) /
    142       GetDeviceScaleFactor() + 0.5);
    143 }
    144 
    145 double GetUndocumentedDPIScale() {
    146   // TODO(girard): Remove this code when chrome is DPIAware.
    147   static double scale = -1.0;
    148   if (scale == -1.0) {
    149     scale = 1.0;
    150     if (!IsProcessDPIAwareWrapper()) {
    151       base::win::RegKey key(HKEY_CURRENT_USER,
    152                             L"Control Panel\\Desktop\\WindowMetrics",
    153                             KEY_QUERY_VALUE);
    154       if (key.Valid()) {
    155         DWORD value = 0;
    156         if (key.ReadValueDW(L"AppliedDPI", &value) == ERROR_SUCCESS) {
    157           scale = static_cast<double>(value) / kDefaultDPIX;
    158         }
    159       }
    160     }
    161   }
    162   return scale;
    163 }
    164 
    165 }  // namespace win
    166 
    167 }  // namespace ui
    168