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 // 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 DpiHelper {
30  public:
31  DpiHelper();
32 
33  ~DpiHelper();
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  FML_DISALLOW_COPY_AND_ASSIGN(DpiHelper);
63 };
64 
65 DpiHelper::DpiHelper() {
66  if ((user32_module_ = LoadLibraryA("User32.dll")) != nullptr) {
67  dpi_for_window_supported_ = (AssignProcAddress(
68  user32_module_, "GetDpiForWindow", get_dpi_for_window_));
69  }
70  if ((shlib_module_ = LoadLibraryA("Shcore.dll")) != nullptr) {
71  dpi_for_monitor_supported_ = AssignProcAddress(
72  shlib_module_, "GetDpiForMonitor", get_dpi_for_monitor_);
73  }
74 }
75 
76 DpiHelper::~DpiHelper() {
77  if (user32_module_ != nullptr) {
78  FreeLibrary(user32_module_);
79  }
80  if (shlib_module_ != nullptr) {
81  FreeLibrary(shlib_module_);
82  }
83 }
84 
85 UINT DpiHelper::GetDpiForWindow(HWND hwnd) {
86  // GetDpiForWindow returns the DPI for any awareness mode. If not available,
87  // or no |hwnd| is provided, fallback to a per monitor, system, or default
88  // DPI.
89  if (dpi_for_window_supported_ && hwnd != nullptr) {
90  return get_dpi_for_window_(hwnd);
91  }
92 
93  if (dpi_for_monitor_supported_) {
94  HMONITOR monitor = nullptr;
95  if (hwnd != nullptr) {
96  monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
97  }
98  return GetDpiForMonitor(monitor);
99  }
100  HDC hdc = GetDC(hwnd);
101  UINT dpi = GetDeviceCaps(hdc, LOGPIXELSX);
102  ReleaseDC(hwnd, hdc);
103  return dpi;
104 }
105 
106 UINT DpiHelper::GetDpiForMonitor(HMONITOR monitor) {
107  if (dpi_for_monitor_supported_) {
108  if (monitor == nullptr) {
109  const POINT target_point = {0, 0};
110  monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTOPRIMARY);
111  }
112  UINT dpi_x = 0, dpi_y = 0;
113  HRESULT result =
114  get_dpi_for_monitor_(monitor, kEffectiveDpiMonitorType, &dpi_x, &dpi_y);
115  if (SUCCEEDED(result)) {
116  return dpi_x;
117  }
118  }
119  return kDefaultDpi;
120 } // namespace
121 
122 DpiHelper* GetHelper() {
123  static DpiHelper* dpi_helper = new DpiHelper();
124  return dpi_helper;
125 }
126 } // namespace
127 
128 UINT GetDpiForHWND(HWND hwnd) {
129  return GetHelper()->GetDpiForWindow(hwnd);
130 }
131 
132 UINT GetDpiForMonitor(HMONITOR monitor) {
133  return GetHelper()->GetDpiForMonitor(monitor);
134 }
135 } // namespace flutter
UINT GetDpiForHWND(HWND hwnd)
Definition: dpi_utils.cc:128
UINT GetDpiForMonitor(HMONITOR monitor)
Definition: dpi_utils.cc:132
constexpr UINT kDefaultDpi
Definition: dpi_utils.h:12