Flutter Engine
win32_dpi_utils.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 "win32_dpi_utils.h"
6 
7 namespace flutter {
8 
9 namespace {
10 
11 constexpr UINT kDefaultDpi = 96;
12 
13 // This is the MDT_EFFECTIVE_DPI value from MONITOR_DPI_TYPE, an enum declared
14 // in ShellScalingApi.h. Replicating here to avoid importing the library
15 // directly.
16 constexpr UINT kEffectiveDpiMonitorType = 0;
17 
18 template <typename T>
19 
20 /// Retrieves a function |name| from a given |comBaseModule| into |outProc|.
21 /// Returns a bool indicating whether the function was found.
22 bool AssignProcAddress(HMODULE comBaseModule, const char* name, T*& outProc) {
23  outProc = reinterpret_cast<T*>(GetProcAddress(comBaseModule, name));
24  return *outProc != nullptr;
25 }
26 
27 /// A helper class for abstracting various Windows DPI related functions across
28 /// Windows OS versions.
29 class Win32DpiHelper {
30  public:
31  Win32DpiHelper();
32 
33  ~Win32DpiHelper();
34 
35  /// Returns the DPI for |hwnd|. Supports all DPI awareness modes, and is
36  /// backward compatible down to Windows Vista. If |hwnd| is nullptr, returns
37  /// the DPI for the primary monitor. If Per-Monitor DPI awareness is not
38  /// available, returns the system's DPI.
39  UINT GetDpiForWindow(HWND);
40 
41  /// Returns the DPI of a given monitor. Defaults to 96 if the API is not
42  /// available.
43  UINT GetDpiForMonitor(HMONITOR);
44 
45  private:
46  using GetDpiForWindow_ = UINT __stdcall(HWND);
47  using GetDpiForMonitor_ = HRESULT __stdcall(HMONITOR hmonitor,
48  UINT dpiType,
49  UINT* dpiX,
50  UINT* dpiY);
51  using EnableNonClientDpiScaling_ = BOOL __stdcall(HWND hwnd);
52 
53  GetDpiForWindow_* get_dpi_for_window_ = nullptr;
54  GetDpiForMonitor_* get_dpi_for_monitor_ = nullptr;
55  EnableNonClientDpiScaling_* enable_non_client_dpi_scaling_ = nullptr;
56 
57  HMODULE user32_module_ = nullptr;
58  HMODULE shlib_module_ = nullptr;
59  bool dpi_for_window_supported_ = false;
60  bool dpi_for_monitor_supported_ = false;
61 };
62 
63 Win32DpiHelper::Win32DpiHelper() {
64  if ((user32_module_ = LoadLibraryA("User32.dll")) != nullptr) {
65  dpi_for_window_supported_ = (AssignProcAddress(
66  user32_module_, "GetDpiForWindow", get_dpi_for_window_));
67  }
68  if ((shlib_module_ = LoadLibraryA("Shcore.dll")) != nullptr) {
69  dpi_for_monitor_supported_ = AssignProcAddress(
70  shlib_module_, "GetDpiForMonitor", get_dpi_for_monitor_);
71  }
72 }
73 
74 Win32DpiHelper::~Win32DpiHelper() {
75  if (user32_module_ != nullptr) {
76  FreeLibrary(user32_module_);
77  }
78  if (shlib_module_ != nullptr) {
79  FreeLibrary(shlib_module_);
80  }
81 }
82 
83 UINT Win32DpiHelper::GetDpiForWindow(HWND hwnd) {
84  // GetDpiForWindow returns the DPI for any awareness mode. If not available,
85  // or no |hwnd| is provided, fallback to a per monitor, system, or default
86  // DPI.
87  if (dpi_for_window_supported_ && hwnd != nullptr) {
88  return get_dpi_for_window_(hwnd);
89  }
90 
91  if (dpi_for_monitor_supported_) {
92  HMONITOR monitor = nullptr;
93  if (hwnd != nullptr) {
94  monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
95  }
96  return GetDpiForMonitor(monitor);
97  }
98  HDC hdc = GetDC(hwnd);
99  UINT dpi = GetDeviceCaps(hdc, LOGPIXELSX);
100  ReleaseDC(hwnd, hdc);
101  return dpi;
102 }
103 
104 UINT Win32DpiHelper::GetDpiForMonitor(HMONITOR monitor) {
105  if (dpi_for_monitor_supported_) {
106  if (monitor == nullptr) {
107  const POINT target_point = {0, 0};
108  monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTOPRIMARY);
109  }
110  UINT dpi_x = 0, dpi_y = 0;
111  HRESULT result =
112  get_dpi_for_monitor_(monitor, kEffectiveDpiMonitorType, &dpi_x, &dpi_y);
113  if (SUCCEEDED(result)) {
114  return dpi_x;
115  }
116  }
117  return kDefaultDpi;
118 } // namespace
119 
120 Win32DpiHelper* GetHelper() {
121  static Win32DpiHelper* dpi_helper = new Win32DpiHelper();
122  return dpi_helper;
123 }
124 } // namespace
125 
126 UINT GetDpiForHWND(HWND hwnd) {
127  return GetHelper()->GetDpiForWindow(hwnd);
128 }
129 
130 UINT GetDpiForMonitor(HMONITOR monitor) {
131  return GetHelper()->GetDpiForMonitor(monitor);
132 }
133 } // namespace flutter
UINT GetDpiForMonitor(HMONITOR monitor)
UINT GetDpiForHWND(HWND hwnd)
const char * name
Definition: fuchsia.cc:50