-
-
Notifications
You must be signed in to change notification settings - Fork 474
/
Copy pathdpi_aware.cpp
228 lines (210 loc) · 9.13 KB
/
dpi_aware.cpp
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
// Copyright (c) 2014 CEF Python, see the Authors file.
// All rights reserved. Licensed under BSD 3-clause license.
// Project website: https://github.com/cztomczak/cefpython
// Windows only
#pragma comment(lib, "Gdi32.lib")
#include <math.h>
#include "dpi_aware.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/base/cef_bind.h"
#include "include/base/cef_logging.h"
const int DEFAULT_DPIX = 96;
bool IsProcessDpiAware() {
typedef BOOL(WINAPI *IsProcessDPIAwarePtr)(VOID);
IsProcessDPIAwarePtr is_process_dpi_aware_func =
reinterpret_cast<IsProcessDPIAwarePtr>(
GetProcAddress(GetModuleHandleA("user32.dll"),
"IsProcessDPIAware"));
BOOL is_aware = FALSE;
if (is_process_dpi_aware_func) {
is_aware = is_process_dpi_aware_func();
if (is_aware == TRUE) {
return true;
}
}
// GetProcessDpiAwareness is available only on Win8. So it
// should be called only as a back-up plan after IsProcessDPIAware
// was called. Also if IsProcessDPIAware returned false,
// then GetProcessDpiAwareness is called as well.
if (GetProcessDpiAwareness() != PROCESS_DPI_UNAWARE) {
return true;
}
return false;
}
PROCESS_DPI_AWARENESS GetProcessDpiAwareness() {
// Win8.1 supports monitor-specific DPI scaling, so it is
// recommended to use GetProcessDPIAwareness instead of the
// deprecated IsProcessDPIAware.
typedef HRESULT(WINAPI *GetProcessDpiAwarenessPtr)
(HANDLE,PROCESS_DPI_AWARENESS*);
GetProcessDpiAwarenessPtr get_process_dpi_awareness_func =
reinterpret_cast<GetProcessDpiAwarenessPtr>(
GetProcAddress(GetModuleHandleA("user32.dll"),
"GetProcessDpiAwarenessInternal"));
if (get_process_dpi_awareness_func) {
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false,
GetCurrentProcessId());
PROCESS_DPI_AWARENESS result;
HRESULT hr = get_process_dpi_awareness_func(hProcess, &result);
if (SUCCEEDED(hr)) {
return result;
}
// Possible failures include E_INVALIDARG or E_ACCESSDENIED.
LOG(INFO) << "[Browser process] GetProcessDpiAwareness():"
" hr=" << hr;
}
return PROCESS_DPI_UNAWARE;
}
void SetProcessDpiAware() {
// Win8.1 supports monitor-specific DPI scaling, so it is
// recommended to use SetProcessDPIAwareness instead of the
// deprecated SetProcessDPIAware. SetProcessDpiAwareness is
// only available on Win8. So as a back-up plan SetProcessDPIAware
// is called.
// If DPI aware manifest was embedded in executable, or
// "Disable display scaling on high DPI settings" was checked
// on the executable properties (Compatibility tab), then
// DPI awareness is already set.
/*
What if GetProcessDpiAwareness returned
PROCESS_PER_MONITOR_DPI_AWARE? The code below sets awareness
to PROCESS_SYSTEM_DPI_AWARE, so it should be called either way.
--OFF:
if (IsProcessDpiAware()) {
return;
}
*/
typedef BOOL(WINAPI *SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS);
SetProcessDpiAwarenessPtr set_process_dpi_awareness_func =
reinterpret_cast<SetProcessDpiAwarenessPtr>(
GetProcAddress(GetModuleHandleA("user32.dll"),
"SetProcessDpiAwarenessInternal"));
if (set_process_dpi_awareness_func) {
LOG(INFO) << "[Browser process] SetProcessDpiAware():"
" calling user32.dll SetProcessDpiAwareness";
HRESULT hr = set_process_dpi_awareness_func(PROCESS_SYSTEM_DPI_AWARE);
if (SUCCEEDED(hr)) {
LOG(INFO) << "[Browser process]: SetBrowserDpiAware():"
" SetProcessDpiAwareness succeeded";
return;
} else if (hr == E_ACCESSDENIED) {
LOG(ERROR) << "[Browser process] SetBrowserDpiAware():"
" SetProcessDpiAwareness failed:"
" The DPI awareness is already set, either by calling"
" this API previously or through the application"
" (.exe) manifest.";
// Do not return here, let's try to call SetProcessDPIAware.
} else {
LOG(ERROR) << "[Browser process] SetBrowserDpiAware():"
" SetProcessDpiAwareness failed";
// Do not return here, let's try to call SetProcessDPIAware.
}
}
// SetProcessDpiAwareness not found in user32.dll or the call failed.
typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID);
SetProcessDPIAwarePtr set_process_dpi_aware_func =
reinterpret_cast<SetProcessDPIAwarePtr>(
GetProcAddress(GetModuleHandleA("user32.dll"),
"SetProcessDPIAware"));
if (set_process_dpi_aware_func) {
// If cefpython.Initialize() wasn't yet called, then
// this log message won't be written, as g_debug is
// is set during CEF initialization.
LOG(INFO) << "[Browser process] SetProcessDpiAware():"
" calling user32.dll SetProcessDPIAware";
set_process_dpi_aware_func();
}
}
void GetSystemDpi(int* dpix, int* dpiy) {
// Win7 DPI (Control Panel > Appearance and Personalization > Display):
// text size Larger 150% => dpix/dpiy 144
// text size Medium 125% => dpix/dpiy 120
// text size Smaller 100% => dpix/dpiy 96
//
// DPI settings should not be cached. When SetProcessDpiAware
// is not yet called, then OS returns 96 DPI, even though it
// is set to 144 DPI. After DPI Awareness is enabled for the
// running process it will return the correct 144 DPI.
HDC hdc = GetDC(HWND_DESKTOP);
*dpix = GetDeviceCaps(hdc, LOGPIXELSX);
*dpiy = GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(HWND_DESKTOP, hdc);
}
void GetDpiAwareWindowSize(int* width, int* height) {
int dpix = 0;
int dpiy = 0;
GetSystemDpi(&dpix, &dpiy);
double newZoomLevel = 0.0;
// 1. Using only "dpix" value to calculate zoom level. All
// modern displays have equal horizontal and vertical resolution.
// 2. Calculation for DPI < 96 is not yet supported (newZoomLevel<0.0).
newZoomLevel = (dpix - DEFAULT_DPIX) / 24;
if (newZoomLevel > 0.0) {
*width = *width + (int)ceil(newZoomLevel * 0.25 * (*width));
*height = *height + (int)ceil(newZoomLevel * 0.25 * (*height));
LOG(INFO) << "[Browser process] GetDpiAwareWindowSize():"
" enlarged by " << ceil(newZoomLevel * 0.25 * 100) << "%"
" new size = " << *width << "/" << *height;
}
}
void SetBrowserDpiSettings(CefRefPtr<CefBrowser> cefBrowser,
CefString autoZooming) {
// Setting zoom level immediately after browser was created
// won't work. We need to wait a moment before we can set it.
REQUIRE_UI_THREAD();
double oldZoomLevel = cefBrowser->GetHost()->GetZoomLevel();
double newZoomLevel = 0.0;
int dpix = 0;
int dpiy = 0;
GetSystemDpi(&dpix, &dpiy);
if (autoZooming.ToString() == "system_dpi") {
// Using only "dpix" value to calculate zoom level. All
// modern displays have equal horizontal/vertical resolution.
// Examples:
// dpix=96 zoom=0.0
// dpix=120 zoom=1.0
// dpix=144 zoom=2.0
// dpix=72 zoom=-1.0
newZoomLevel = (dpix - DEFAULT_DPIX) / 24;
} else {
// When atof() fails converting string to double, then
// 0.0 is returned.
newZoomLevel = atof(autoZooming.ToString().c_str());
}
if (oldZoomLevel != newZoomLevel) {
cefBrowser->GetHost()->SetZoomLevel(newZoomLevel);
if (cefBrowser->GetHost()->GetZoomLevel() != oldZoomLevel) {
// OK succes.
LOG(INFO) << "[Browser process] SetBrowserDpiSettings():"
" DPI=" << dpix << ""
" zoom=" << cefBrowser->GetHost()->GetZoomLevel();
}
} else {
// This code block running can also be a result of executing
// SetZoomLevel(), as GetZoomLevel() didn't return the new
// value that was set. Documentation says that if SetZoomLevel
// is called on the UI thread, then GetZoomLevel should
// immediately return the same value that was set. Unfortunately
// this seems not to be true.
static bool already_logged = false;
if (!already_logged) {
already_logged = true;
// OK success.
LOG(INFO) << "[Browser process] SetBrowserDpiSettings():"
" DPI=" << dpix << ""
" zoom=" << cefBrowser->GetHost()->GetZoomLevel();
}
}
// We need to check zooming constantly, during loading of pages.
// If we set zooming to 2.0 for localhost/ and then it navigates
// to google.com, then the zomming is back at 0.0 and needs to
// be set again.
CefPostDelayedTask(
TID_UI,
CefCreateClosureTask(
base::Bind(&SetBrowserDpiSettings,
cefBrowser, autoZooming)
),
50
);
}