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