summaryrefslogtreecommitdiffstats
path: root/ui/base/win/dpi.cc
blob: cc713319882f67ccd6620d6b647866af5e68c80c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/base/win/dpi.h"

#include <windows.h>

#include "base/win/scoped_hdc.h"
#include "ui/base/layout.h"
#include "base/win/registry.h"
#include "ui/gfx/display.h"
#include "ui/gfx/point_conversions.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/size_conversions.h"

namespace {

int kDefaultDPIX = 96;
int kDefaultDPIY = 96;

float GetDeviceScaleFactorImpl() {
#if defined(ENABLE_HIDPI)
  float scale = gfx::Display::HasForceDeviceScaleFactor() ?
      gfx::Display::GetForcedDeviceScaleFactor() : ui::GetDPIScale();
  // Quantize to nearest supported scale factor.
  scale = ui::GetScaleFactorScale(ui::GetScaleFactorFromScale(scale));
  return scale;
#else
  return 1.0f;
#endif
}

FARPROC GetProcAddressWrapper(LPCSTR module_name, LPCSTR proc_name) {
  HMODULE module = ::GetModuleHandleA(module_name);
  if (module) {
    return ::GetProcAddress(module, proc_name);
  }
  return NULL;
}

BOOL IsProcessDPIAwareWrapper() {
  typedef BOOL(WINAPI *IsProcessDPIAwarePtr)(VOID);
  IsProcessDPIAwarePtr is_process_dpi_aware_func =
      reinterpret_cast<IsProcessDPIAwarePtr>(
          GetProcAddressWrapper("user32.dll", "IsProcessDPIAware"));
  if (is_process_dpi_aware_func)
    return is_process_dpi_aware_func();
  return FALSE;
}

}  // namespace

namespace ui {

gfx::Size GetDPI() {
  static int dpi_x = 0;
  static int dpi_y = 0;
  static bool should_initialize = true;

  if (should_initialize) {
    should_initialize = false;
    base::win::ScopedGetDC screen_dc(NULL);
    // This value is safe to cache for the life time of the app since the
    // user must logout to change the DPI setting. This value also applies
    // to all screens.
    dpi_x = GetDeviceCaps(screen_dc, LOGPIXELSX);
    dpi_y = GetDeviceCaps(screen_dc, LOGPIXELSY);
  }
  return gfx::Size(dpi_x, dpi_y);
}

float GetDPIScale() {
  return static_cast<float>(GetDPI().width()) /
      static_cast<float>(kDefaultDPIX);
}

bool IsInHighDPIMode() {
  gfx::Size dpi(GetDPI());
  return dpi.width() > kDefaultDPIX || dpi.height() > kDefaultDPIY;
}

void EnableHighDPISupport() {
  typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID);
  SetProcessDPIAwarePtr set_process_dpi_aware_func =
      reinterpret_cast<SetProcessDPIAwarePtr>(
          GetProcAddressWrapper("user32.dll", "SetProcessDPIAware"));
  if (set_process_dpi_aware_func)
    set_process_dpi_aware_func();
}

namespace win {

float GetDeviceScaleFactor() {
  static const float device_scale_factor = GetDeviceScaleFactorImpl();
  return device_scale_factor;
}

gfx::Point ScreenToDIPPoint(const gfx::Point& pixel_point) {
  return gfx::ToFlooredPoint(
      gfx::ScalePoint(pixel_point, 1.0f / GetDeviceScaleFactor()));
}

gfx::Rect ScreenToDIPRect(const gfx::Rect& pixel_bounds) {
  // TODO(kevers): Switch to non-deprecated method for float to int conversions.
  return gfx::ToFlooredRectDeprecated(
      gfx::ScaleRect(pixel_bounds, 1.0f / GetDeviceScaleFactor()));
}

gfx::Rect DIPToScreenRect(const gfx::Rect& dip_bounds) {
  // TODO(kevers): Switch to non-deprecated method for float to int conversions.
  return gfx::ToFlooredRectDeprecated(
      gfx::ScaleRect(dip_bounds, GetDeviceScaleFactor()));
}

gfx::Size ScreenToDIPSize(const gfx::Size& size_in_pixels) {
  return gfx::ToFlooredSize(
      gfx::ScaleSize(size_in_pixels, 1.0f / GetDeviceScaleFactor()));
}

gfx::Size DIPToScreenSize(const gfx::Size& dip_size) {
  return gfx::ToFlooredSize(gfx::ScaleSize(dip_size, GetDeviceScaleFactor()));
}

double GetDPIScaleFromRegistry() {
  static double scale = -1.0;
  if (scale == -1.0) {
    double result = 1.0;
    if (!IsProcessDPIAwareWrapper()) {
      //HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\AppliedDPI
      base::win::RegKey key(HKEY_CURRENT_USER,
                            L"Control Panel\\Desktop\\WindowMetrics",
                            KEY_QUERY_VALUE);

      if (key.Valid()) {
        DWORD value = 0;
        if (key.ReadValueDW(L"AppliedDPI", &value) == ERROR_SUCCESS) {
          result = ((double)value) / kDefaultDPIX;
        }
      }
    }
    scale = result;
  }

  // Safety test to ignore invalid settings.
  if (scale <= 0.0)
    scale = 1.0;

  return scale;
}

}  // namespace win

}  // namespace ui