未验证 提交 c3b50724 编写于 作者: F Francisco Magdaleno 提交者: GitHub

Expose DPI helper functions for Runner apps to use (#16313)

上级 539f64f5
......@@ -1116,6 +1116,9 @@ FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flu
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/plugin_registrar_windows_unittests.cc
FILE: ../../../flutter/shell/platform/windows/dpi_utils.cc
FILE: ../../../flutter/shell/platform/windows/dpi_utils.h
FILE: ../../../flutter/shell/platform/windows/dpi_utils_unittests.cc
FILE: ../../../flutter/shell/platform/windows/flutter_windows.cc
FILE: ../../../flutter/shell/platform/windows/key_event_handler.cc
FILE: ../../../flutter/shell/platform/windows/key_event_handler.h
......@@ -1125,10 +1128,9 @@ FILE: ../../../flutter/shell/platform/windows/platform_handler.h
FILE: ../../../flutter/shell/platform/windows/public/flutter_windows.h
FILE: ../../../flutter/shell/platform/windows/text_input_plugin.cc
FILE: ../../../flutter/shell/platform/windows/text_input_plugin.h
FILE: ../../../flutter/shell/platform/windows/win32_dpi_helper.cc
FILE: ../../../flutter/shell/platform/windows/win32_dpi_helper.h
FILE: ../../../flutter/shell/platform/windows/win32_flutter_window.cc
FILE: ../../../flutter/shell/platform/windows/win32_flutter_window.h
FILE: ../../../flutter/shell/platform/windows/win32_flutter_window_unittests.cc
FILE: ../../../flutter/shell/platform/windows/win32_task_runner.cc
FILE: ../../../flutter/shell/platform/windows/win32_task_runner.h
FILE: ../../../flutter/shell/platform/windows/win32_window.cc
......
......@@ -41,6 +41,8 @@ source_set("flutter_windows_source") {
sources = [
"angle_surface_manager.cc",
"angle_surface_manager.h",
"dpi_utils.cc",
"dpi_utils.h",
"flutter_windows.cc",
"key_event_handler.cc",
"key_event_handler.h",
......@@ -49,8 +51,6 @@ source_set("flutter_windows_source") {
"platform_handler.h",
"text_input_plugin.cc",
"text_input_plugin.h",
"win32_dpi_helper.cc",
"win32_dpi_helper.h",
"win32_flutter_window.cc",
"win32_flutter_window.h",
"win32_task_runner.cc",
......@@ -109,8 +109,12 @@ executable("flutter_windows_unittests") {
testonly = true
sources = [
"dpi_utils_unittests.cc",
"testing/win32_flutter_window_test.cc",
"testing/win32_flutter_window_test.h",
"testing/win32_window_test.cc",
"testing/win32_window_test.h",
"win32_flutter_window_unittests.cc",
"win32_window_unittests.cc",
]
......
#include "dpi_utils.h"
namespace flutter {
namespace {
constexpr UINT kDefaultDpi = 96;
// This is the MDT_EFFECTIVE_DPI value from MONITOR_DPI_TYPE, an enum declared
// in ShellScalingApi.h. Replicating here to avoid importing the library
// directly.
constexpr UINT kEffectiveDpiMonitorType = 0;
template <typename T>
/// Retrieves a function |name| from a given |comBaseModule| into |outProc|.
/// Returns a bool indicating whether the function was found.
bool AssignProcAddress(HMODULE comBaseModule, const char* name, T*& outProc) {
outProc = reinterpret_cast<T*>(GetProcAddress(comBaseModule, name));
return *outProc != nullptr;
}
/// A helper class for abstracting various Windows DPI related functions across
/// Windows OS versions.
class Win32DpiHelper {
public:
Win32DpiHelper();
~Win32DpiHelper();
/// Returns the DPI for |hwnd|. Supports all DPI awareness modes, and is
/// backward compatible down to Windows Vista. If |hwnd| is nullptr, returns
/// the DPI for the primary monitor. If Per-Monitor DPI awareness is not
/// available, returns the system's DPI.
UINT GetDpiForWindow(HWND);
/// Returns the DPI of a given monitor. Defaults to 96 if the API is not
/// available.
UINT GetDpiForMonitor(HMONITOR);
private:
using GetDpiForWindow_ = UINT __stdcall(HWND);
using GetDpiForMonitor_ = HRESULT __stdcall(HMONITOR hmonitor,
UINT dpiType,
UINT* dpiX,
UINT* dpiY);
using EnableNonClientDpiScaling_ = BOOL __stdcall(HWND hwnd);
GetDpiForWindow_* get_dpi_for_window_ = nullptr;
GetDpiForMonitor_* get_dpi_for_monitor_ = nullptr;
EnableNonClientDpiScaling_* enable_non_client_dpi_scaling_ = nullptr;
HMODULE user32_module_ = nullptr;
HMODULE shlib_module_ = nullptr;
bool dpi_for_window_supported_ = false;
bool dpi_for_monitor_supported_ = false;
};
Win32DpiHelper::Win32DpiHelper() {
if ((user32_module_ = LoadLibraryA("User32.dll")) != nullptr) {
dpi_for_window_supported_ = (AssignProcAddress(
user32_module_, "GetDpiForWindow", get_dpi_for_window_));
}
if ((shlib_module_ = LoadLibraryA("Shcore.dll")) != nullptr) {
dpi_for_monitor_supported_ = AssignProcAddress(
shlib_module_, "GetDpiForMonitor", get_dpi_for_monitor_);
}
}
Win32DpiHelper::~Win32DpiHelper() {
if (user32_module_ != nullptr) {
FreeLibrary(user32_module_);
}
if (shlib_module_ != nullptr) {
FreeLibrary(shlib_module_);
}
}
UINT Win32DpiHelper::GetDpiForWindow(HWND hwnd) {
// GetDpiForWindow returns the DPI for any awareness mode. If not available,
// or no |hwnd| is provided, fallback to a per monitor, system, or default
// DPI.
if (dpi_for_window_supported_ && hwnd != nullptr) {
return get_dpi_for_window_(hwnd);
}
if (dpi_for_monitor_supported_) {
HMONITOR monitor = nullptr;
if (hwnd != nullptr) {
monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
}
return GetDpiForMonitor(monitor);
}
HDC hdc = GetDC(hwnd);
UINT dpi = GetDeviceCaps(hdc, LOGPIXELSX);
ReleaseDC(hwnd, hdc);
return dpi;
}
UINT Win32DpiHelper::GetDpiForMonitor(HMONITOR monitor) {
if (dpi_for_monitor_supported_) {
if (monitor == nullptr) {
const POINT target_point = {0, 0};
monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTOPRIMARY);
}
UINT dpi_x = 0, dpi_y = 0;
HRESULT result =
get_dpi_for_monitor_(monitor, kEffectiveDpiMonitorType, &dpi_x, &dpi_y);
if (SUCCEEDED(result)) {
return dpi_x;
}
}
return kDefaultDpi;
} // namespace
Win32DpiHelper* GetHelper() {
static Win32DpiHelper* dpi_helper = new Win32DpiHelper();
return dpi_helper;
}
} // namespace
UINT GetDpiForHWND(HWND hwnd) {
return GetHelper()->GetDpiForWindow(hwnd);
}
UINT GetDpiForMonitor(HMONITOR monitor) {
return GetHelper()->GetDpiForMonitor(monitor);
}
} // namespace flutter
// Copyright 2013 The Flutter 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 "Windows.h"
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_DPI_UTILS_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_DPI_UTILS_H_
namespace flutter {
/// Returns the DPI for |hwnd|. Supports all DPI awareness modes, and is
/// backward compatible down to Windows Vista. If |hwnd| is nullptr, returns the
/// DPI for the primary monitor. If Per-Monitor DPI awareness is not available,
/// returns the system's DPI.
UINT GetDpiForHWND(HWND hwnd);
/// Returns the DPI of a given monitor. Defaults to 96 if the API is not
/// available.
UINT GetDpiForMonitor(HMONITOR monitor);
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_DPI_UTILS_H_
#include <windows.h>
#include "flutter/shell/platform/windows/dpi_utils.h"
#include "gtest/gtest.h"
namespace flutter {
namespace testing {
TEST(DpiUtilsTest, NonZero) {
ASSERT_GT(GetDpiForHWND(nullptr), 0);
ASSERT_GT(GetDpiForMonitor(nullptr), 0);
};
TEST(DpiUtilsTest, NullHwndUsesPrimaryMonitor) {
const POINT target_point = {0, 0};
HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTOPRIMARY);
ASSERT_EQ(GetDpiForHWND(nullptr), GetDpiForMonitor(monitor));
};
} // namespace testing
} // namespace flutter
......@@ -15,6 +15,7 @@
#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h"
#include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/windows/dpi_utils.h"
#include "flutter/shell/platform/windows/key_event_handler.h"
#include "flutter/shell/platform/windows/keyboard_hook_handler.h"
#include "flutter/shell/platform/windows/platform_handler.h"
......@@ -182,6 +183,14 @@ HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view) {
return view->window->GetWindowHandle();
}
UINT FlutterDesktopGetDpiForHWND(HWND hwnd) {
return flutter::GetDpiForHWND(hwnd);
}
UINT FlutterDesktopGetDpiForMonitor(HMONITOR monitor) {
return flutter::GetDpiForMonitor(monitor);
}
FlutterDesktopEngineRef FlutterDesktopRunEngine(const char* assets_path,
const char* icu_data_path,
const char** arguments,
......
......@@ -77,6 +77,15 @@ FlutterDesktopProcessMessages(FlutterDesktopViewControllerRef controller);
// Return backing HWND for manipulation in host application.
FLUTTER_EXPORT HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view);
// Gets the DPI for a given |hwnd|, depending on the supported APIs per
// windows version and DPI awareness mode. If nullptr is passed, returns the DPI
// of the primary monitor.
FLUTTER_EXPORT UINT FlutterDesktopGetDpiForHWND(HWND hwnd);
// Gets the DPI for a given |monitor|. If the API is not available, a default
// DPI of 96 is returned.
FLUTTER_EXPORT UINT FlutterDesktopGetDpiForMonitor(HMONITOR monitor);
// Runs an instance of a headless Flutter engine.
//
// The |assets_path| is the path to the flutter_assets folder for the Flutter
......
......@@ -4,18 +4,21 @@
#include <windowsx.h>
#include "flutter/fml/macros.h"
#include "flutter/shell/platform/windows/win32_flutter_window.h"
namespace flutter {
namespace testing {
/// Test class for Win32FlutterWindow.
class Win32FlutterWindowTest : public Win32FlutterWindow {
public:
Win32FlutterWindowTest(int width, int height);
virtual ~Win32FlutterWindowTest();
// Prevent copying.
Win32FlutterWindowTest(Win32FlutterWindowTest const&) = delete;
Win32FlutterWindowTest& operator=(Win32FlutterWindowTest const&) = delete;
// |Win32Window|
void OnFontChange() override;
......@@ -23,8 +26,6 @@ class Win32FlutterWindowTest : public Win32FlutterWindow {
private:
bool on_font_change_called_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(Win32FlutterWindowTest);
};
} // namespace testing
......
#include "flutter/shell/platform/windows/testing/win32_window_test.h"
namespace flutter {
namespace testing {
Win32WindowTest::Win32WindowTest() : Win32Window(){};
Win32WindowTest::~Win32WindowTest() = default;
void Win32WindowTest::OnDpiScale(unsigned int dpi){};
void Win32WindowTest::OnResize(unsigned int width, unsigned int height) {}
void Win32WindowTest::OnPointerMove(double x, double y) {}
void Win32WindowTest::OnPointerDown(double x, double y, UINT button) {}
void Win32WindowTest::OnPointerUp(double x, double y, UINT button) {}
void Win32WindowTest::OnPointerLeave() {}
void Win32WindowTest::OnChar(char32_t code_point) {}
void Win32WindowTest::OnKey(int key, int scancode, int action, int mods) {}
void Win32WindowTest::OnScroll(double delta_x, double delta_y) {}
void Win32WindowTest::OnFontChange() {}
UINT Win32WindowTest::GetDpi() {
return GetCurrentDPI();
}
} // namespace testing
} // namespace flutter
// Copyright 2013 The Flutter 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 <windowsx.h>
#include "flutter/shell/platform/windows/win32_window.h"
namespace flutter {
namespace testing {
/// Test class for the Win32Window base class. Used to access protected methods
/// for testing.
class Win32WindowTest : public Win32Window {
public:
Win32WindowTest();
virtual ~Win32WindowTest();
// Prevent copying.
Win32WindowTest(Win32WindowTest const&) = delete;
Win32WindowTest& operator=(Win32WindowTest const&) = delete;
// Wrapper for GetCurrentDPI() which is a protected method.
UINT GetDpi();
// |Win32Window|
void OnDpiScale(unsigned int dpi) override;
// |Win32Window|
void OnResize(unsigned int width, unsigned int height) override;
// |Win32Window|
void OnPointerMove(double x, double y) override;
// |Win32Window|
void OnPointerDown(double x, double y, UINT button) override;
// |Win32Window|
void OnPointerUp(double x, double y, UINT button) override;
// |Win32Window|
void OnPointerLeave() override;
// |Win32Window|
void OnChar(char32_t code_point) override;
// |Win32Window|
void OnKey(int key, int scancode, int action, int mods) override;
// |Win32Window|
void OnScroll(double delta_x, double delta_y) override;
// |Win32Window|
void OnFontChange() override;
};
} // namespace testing
} // namespace flutter
#include "flutter/shell/platform/windows/win32_dpi_helper.h"
namespace flutter {
namespace {
constexpr UINT kDefaultDpi = 96;
template <typename T>
bool AssignProcAddress(HMODULE comBaseModule, const char* name, T*& outProc) {
outProc = reinterpret_cast<T*>(GetProcAddress(comBaseModule, name));
return *outProc != nullptr;
}
} // namespace
Win32DpiHelper::Win32DpiHelper() {
user32_module_ = LoadLibraryA("User32.dll");
if (user32_module_ == nullptr) {
return;
}
if (AssignProcAddress(user32_module_, "GetDpiForWindow",
get_dpi_for_window_)) {
dpi_for_window_supported_ = true;
return;
}
shlib_module_ = LoadLibraryA("Shcore.dll");
if (shlib_module_ == nullptr) {
return;
}
if (AssignProcAddress(shlib_module_, "GetDpiForMonitor",
get_dpi_for_monitor_) &&
AssignProcAddress(user32_module_, "MonitorFromWindow",
monitor_from_window_)) {
dpi_for_monitor_supported_ = true;
}
}
Win32DpiHelper::~Win32DpiHelper() {
if (user32_module_ != nullptr) {
FreeLibrary(user32_module_);
}
if (shlib_module_ != nullptr) {
FreeLibrary(shlib_module_);
}
}
UINT Win32DpiHelper::GetDpi(HWND hwnd) {
// GetDpiForWindow returns the DPI for any awareness mode. If not available,
// fallback to a per monitor, system, or default DPI.
if (dpi_for_window_supported_) {
return get_dpi_for_window_(hwnd);
}
if (dpi_for_monitor_supported_) {
HMONITOR monitor = monitor_from_window_(hwnd, MONITOR_DEFAULTTONEAREST);
UINT dpi_x = 0, dpi_y = 0;
HRESULT result =
get_dpi_for_monitor_(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y);
return SUCCEEDED(result) ? dpi_x : kDefaultDpi;
}
HDC hdc = GetDC(hwnd);
UINT dpi = GetDeviceCaps(hdc, LOGPIXELSX);
ReleaseDC(hwnd, hdc);
return dpi;
}
} // namespace flutter
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_DPI_HELPER_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_DPI_HELPER_H_
#include <ShellScalingApi.h>
#include <VersionHelpers.h>
namespace flutter {
/// A helper class for abstracting various Windows DPI related functions across
/// Windows OS versions.
class Win32DpiHelper {
public:
Win32DpiHelper();
~Win32DpiHelper();
/// Returns the current DPI. Supports all DPI awareness modes, and is backward
/// compatible down to Windows Vista.
UINT GetDpi(HWND);
private:
using GetDpiForWindow_ = UINT __stdcall(HWND);
using GetDpiForMonitor_ = HRESULT __stdcall(HMONITOR hmonitor,
MONITOR_DPI_TYPE dpiType,
UINT* dpiX,
UINT* dpiY);
using MonitorFromWindow_ = HMONITOR __stdcall(HWND hwnd, DWORD dwFlags);
GetDpiForWindow_* get_dpi_for_window_ = nullptr;
GetDpiForMonitor_* get_dpi_for_monitor_ = nullptr;
MonitorFromWindow_* monitor_from_window_ = nullptr;
HMODULE user32_module_ = nullptr;
HMODULE shlib_module_ = nullptr;
bool dpi_for_window_supported_ = false;
bool dpi_for_monitor_supported_ = false;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_DPI_HELPER_H_
#include "flutter/shell/platform/windows/testing/win32_flutter_window_test.h"
#include "gtest/gtest.h"
namespace flutter {
namespace testing {
TEST(Win32FlutterWindowTest, CreateDestroy) {
Win32FlutterWindowTest window(800, 600);
ASSERT_TRUE(TRUE);
}
TEST(Win32FlutterWindowTest, CanFontChange) {
Win32FlutterWindowTest window(800, 600);
HWND hwnd = window.GetWindowHandle();
LRESULT result = SendMessage(hwnd, WM_FONTCHANGE, NULL, NULL);
ASSERT_EQ(result, 0);
ASSERT_TRUE(window.OnFontChangeWasCalled());
}
} // namespace testing
} // namespace flutter
......@@ -4,9 +4,16 @@
#include "flutter/shell/platform/windows/win32_window.h"
#include "dpi_utils.h"
namespace flutter {
Win32Window::Win32Window() {}
Win32Window::Win32Window() {
// Get the DPI of the primary monitor as the initial DPI. If Per-Monitor V2 is
// supported, |current_dpi_| should be updated in the
// kWmDpiChangedBeforeParent message.
current_dpi_ = GetDpiForHWND(nullptr);
}
Win32Window::~Win32Window() {
Destroy();
......@@ -74,7 +81,6 @@ LRESULT CALLBACK Win32Window::WndProc(HWND const window,
reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
auto that = static_cast<Win32Window*>(cs->lpCreateParams);
that->current_dpi_ = that->dpi_helper_->GetDpi(window);
that->window_handle_ = window;
} else if (Win32Window* that = GetThisFromHandle(window)) {
return that->MessageHandler(window, message, wparam, lparam);
......@@ -106,12 +112,10 @@ Win32Window::MessageHandler(HWND hwnd,
UINT button_pressed = 0;
if (window != nullptr) {
switch (message) {
case WM_DPICHANGED:
return HandleDpiChange(window_handle_, wparam, lparam, true);
break;
case kWmDpiChangedBeforeParent:
return HandleDpiChange(window_handle_, wparam, lparam, false);
break;
current_dpi_ = GetDpiForHWND(window_handle_);
window->OnDpiScale(current_dpi_);
return 0;
case WM_SIZE:
width = LOWORD(lparam);
height = HIWORD(lparam);
......@@ -248,40 +252,6 @@ void Win32Window::Destroy() {
UnregisterClass(window_class_name_.c_str(), nullptr);
}
// DPI Change handler. on WM_DPICHANGE resize the window
LRESULT
Win32Window::HandleDpiChange(HWND hwnd,
WPARAM wparam,
LPARAM lparam,
bool toplevel) {
if (hwnd != nullptr) {
auto window =
reinterpret_cast<Win32Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
UINT uDpi = HIWORD(wparam);
// The DPI is only passed for DPI change messages on top level windows,
// hence call function to get DPI if needed.
if (uDpi == 0) {
uDpi = dpi_helper_->GetDpi(hwnd);
}
current_dpi_ = uDpi;
window->OnDpiScale(uDpi);
if (toplevel) {
// Resize the window only for toplevel windows which have a suggested
// size.
auto lprcNewScale = reinterpret_cast<RECT*>(lparam);
LONG newWidth = lprcNewScale->right - lprcNewScale->left;
LONG newHeight = lprcNewScale->bottom - lprcNewScale->top;
SetWindowPos(hwnd, nullptr, lprcNewScale->left, lprcNewScale->top,
newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
}
}
return 0;
}
void Win32Window::HandleResize(UINT width, UINT height) {
current_width_ = width;
current_height_ = height;
......
......@@ -11,8 +11,6 @@
#include <memory>
#include <string>
#include "flutter/shell/platform/windows/win32_dpi_helper.h"
namespace flutter {
// Struct holding the mouse state. The engine doesn't keep track of which mouse
......@@ -169,11 +167,6 @@ class Win32Window {
// Member variable to hold the window title.
std::wstring window_class_name_;
// Member variable referencing an instance of dpi_helper used to abstract some
// aspects of win32 High DPI handling across different OS versions.
std::unique_ptr<Win32DpiHelper> dpi_helper_ =
std::make_unique<Win32DpiHelper>();
// Set to true to be notified when the mouse leaves the window.
bool tracking_mouse_leave_ = false;
......
#include "flutter/shell/platform/windows/testing/win32_flutter_window_test.h"
#include "flutter/shell/platform/windows/testing/win32_window_test.h"
#include "gtest/gtest.h"
namespace flutter {
namespace testing {
TEST(Win32FlutterWindowTest, CreateDestroy) {
Win32FlutterWindowTest window(800, 600);
TEST(Win32WindowTest, CreateDestroy) {
Win32WindowTest window;
ASSERT_TRUE(TRUE);
}
TEST(Win32FlutterWindowTest, CanFontChange) {
Win32FlutterWindowTest window(800, 600);
HWND hwnd = window.GetWindowHandle();
LRESULT result = SendMessage(hwnd, WM_FONTCHANGE, NULL, NULL);
ASSERT_EQ(result, 0);
ASSERT_TRUE(window.OnFontChangeWasCalled());
TEST(Win32WindowTest, GetDpiAfterCreate) {
Win32WindowTest window;
ASSERT_TRUE(window.GetDpi() > 0);
}
} // namespace testing
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册