mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-02-23 07:27:42 +01:00
Windows: Fix per-monitor DPI scaling of top-level browser windows and placement of context menus (issue #2313)
This commit is contained in:
parent
57b9cf9ddd
commit
a5a5e7ff08
@ -20,6 +20,7 @@
|
|||||||
#include "base/memory/ref_counted_memory.h"
|
#include "base/memory/ref_counted_memory.h"
|
||||||
#include "base/strings/utf_string_conversions.h"
|
#include "base/strings/utf_string_conversions.h"
|
||||||
#include "base/win/registry.h"
|
#include "base/win/registry.h"
|
||||||
|
#include "base/win/win_util.h"
|
||||||
#include "content/public/browser/native_web_keyboard_event.h"
|
#include "content/public/browser/native_web_keyboard_event.h"
|
||||||
#include "third_party/WebKit/public/platform/WebMouseEvent.h"
|
#include "third_party/WebKit/public/platform/WebMouseEvent.h"
|
||||||
#include "third_party/WebKit/public/platform/WebMouseWheelEvent.h"
|
#include "third_party/WebKit/public/platform/WebMouseWheelEvent.h"
|
||||||
@ -95,6 +96,31 @@ void ExecuteExternalProtocol(const GURL& url) {
|
|||||||
ShellExecuteA(NULL, "open", address.c_str(), NULL, NULL, SW_SHOWNORMAL);
|
ShellExecuteA(NULL, "open", address.c_str(), NULL, NULL, SW_SHOWNORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DPI value for 1x scale factor.
|
||||||
|
#define DPI_1X 96.0f
|
||||||
|
|
||||||
|
float GetWindowScaleFactor(HWND hwnd) {
|
||||||
|
DCHECK(hwnd);
|
||||||
|
|
||||||
|
if (base::win::IsProcessPerMonitorDpiAware()) {
|
||||||
|
// Let Windows tell us the correct DPI.
|
||||||
|
static auto get_dpi_for_window_func = []() {
|
||||||
|
return reinterpret_cast<decltype(::GetDpiForWindow)*>(
|
||||||
|
GetProcAddress(GetModuleHandle(L"user32.dll"), "GetDpiForWindow"));
|
||||||
|
}();
|
||||||
|
if (get_dpi_for_window_func)
|
||||||
|
return static_cast<float>(get_dpi_for_window_func(hwnd)) / DPI_1X;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to the monitor that contains the window center point.
|
||||||
|
RECT cr;
|
||||||
|
GetWindowRect(hwnd, &cr);
|
||||||
|
return display::Screen::GetScreen()
|
||||||
|
->GetDisplayNearestPoint(
|
||||||
|
gfx::Point((cr.right - cr.left) / 2, (cr.bottom - cr.top) / 2))
|
||||||
|
.device_scale_factor();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
CefBrowserPlatformDelegateNativeWin::CefBrowserPlatformDelegateNativeWin(
|
CefBrowserPlatformDelegateNativeWin::CefBrowserPlatformDelegateNativeWin(
|
||||||
@ -117,40 +143,49 @@ void CefBrowserPlatformDelegateNativeWin::BrowserDestroyed(
|
|||||||
bool CefBrowserPlatformDelegateNativeWin::CreateHostWindow() {
|
bool CefBrowserPlatformDelegateNativeWin::CreateHostWindow() {
|
||||||
RegisterWindowClass();
|
RegisterWindowClass();
|
||||||
|
|
||||||
|
has_frame_ = !(window_info_.style & WS_CHILD);
|
||||||
|
|
||||||
std::wstring windowName(CefString(&window_info_.window_name));
|
std::wstring windowName(CefString(&window_info_.window_name));
|
||||||
|
|
||||||
// Create the new browser window.
|
// Create the new browser window.
|
||||||
window_info_.window = CreateWindowEx(
|
CreateWindowEx(window_info_.ex_style, GetWndClass(), windowName.c_str(),
|
||||||
window_info_.ex_style, GetWndClass(), windowName.c_str(),
|
window_info_.style, window_info_.x, window_info_.y,
|
||||||
window_info_.style, window_info_.x, window_info_.y, window_info_.width,
|
window_info_.width, window_info_.height,
|
||||||
window_info_.height, window_info_.parent_window, window_info_.menu,
|
window_info_.parent_window, window_info_.menu,
|
||||||
::GetModuleHandle(NULL), NULL);
|
::GetModuleHandle(NULL), this);
|
||||||
|
|
||||||
// It's possible for CreateWindowEx to fail if the parent window was
|
// It's possible for CreateWindowEx to fail if the parent window was
|
||||||
// destroyed between the call to CreateBrowser and the above one.
|
// destroyed between the call to CreateBrowser and the above one.
|
||||||
DCHECK(window_info_.window != NULL);
|
DCHECK(window_info_.window);
|
||||||
if (!window_info_.window)
|
if (!window_info_.window)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
host_window_created_ = true;
|
host_window_created_ = true;
|
||||||
|
|
||||||
// Set window user data to this object for future reference from the window
|
|
||||||
// procedure.
|
|
||||||
gfx::SetWindowUserData(window_info_.window, this);
|
|
||||||
|
|
||||||
// Add a reference that will later be released in DestroyBrowser().
|
// Add a reference that will later be released in DestroyBrowser().
|
||||||
browser_->AddRef();
|
browser_->AddRef();
|
||||||
|
|
||||||
RECT cr;
|
if (!called_enable_non_client_dpi_scaling_ && has_frame_ &&
|
||||||
GetClientRect(window_info_.window, &cr);
|
base::win::IsProcessPerMonitorDpiAware()) {
|
||||||
|
// This call gets Windows to scale the non-client area when WM_DPICHANGED
|
||||||
|
// is fired on Windows versions < 10.0.14393.0.
|
||||||
|
// Derived signature; not available in headers.
|
||||||
|
static auto enable_child_window_dpi_message_func = []() {
|
||||||
|
using EnableChildWindowDpiMessagePtr = LRESULT(WINAPI*)(HWND, BOOL);
|
||||||
|
return reinterpret_cast<EnableChildWindowDpiMessagePtr>(GetProcAddress(
|
||||||
|
GetModuleHandle(L"user32.dll"), "EnableChildWindowDpiMessage"));
|
||||||
|
}();
|
||||||
|
if (enable_child_window_dpi_message_func)
|
||||||
|
enable_child_window_dpi_message_func(window_info_.window, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
DCHECK(!window_widget_);
|
DCHECK(!window_widget_);
|
||||||
|
|
||||||
// Adjust for potential display scaling.
|
// Convert from device coordinates to logical coordinates.
|
||||||
|
RECT cr;
|
||||||
|
GetClientRect(window_info_.window, &cr);
|
||||||
gfx::Point point = gfx::Point(cr.right, cr.bottom);
|
gfx::Point point = gfx::Point(cr.right, cr.bottom);
|
||||||
float scale = display::Screen::GetScreen()
|
const float scale = GetWindowScaleFactor(window_info_.window);
|
||||||
->GetDisplayNearestPoint(point)
|
|
||||||
.device_scale_factor();
|
|
||||||
point =
|
point =
|
||||||
gfx::ToFlooredPoint(gfx::ScalePoint(gfx::PointF(point), 1.0f / scale));
|
gfx::ToFlooredPoint(gfx::ScalePoint(gfx::PointF(point), 1.0f / scale));
|
||||||
|
|
||||||
@ -270,19 +305,19 @@ gfx::Point CefBrowserPlatformDelegateNativeWin::GetScreenPoint(
|
|||||||
if (windowless_handler_)
|
if (windowless_handler_)
|
||||||
return windowless_handler_->GetParentScreenPoint(view);
|
return windowless_handler_->GetParentScreenPoint(view);
|
||||||
|
|
||||||
if (!window_widget_)
|
if (!window_info_.window)
|
||||||
return view;
|
return view;
|
||||||
|
|
||||||
aura::Window* window = window_widget_->GetNativeView();
|
// Convert from logical coordinates to device coordinates.
|
||||||
const gfx::Rect& bounds_in_screen = window->GetBoundsInScreen();
|
const float scale = GetWindowScaleFactor(window_info_.window);
|
||||||
const gfx::Point& screen_point = gfx::Point(bounds_in_screen.x() + view.x(),
|
const gfx::Point& device_pt =
|
||||||
bounds_in_screen.y() + view.y());
|
gfx::ToFlooredPoint(gfx::ScalePoint(gfx::PointF(view), scale));
|
||||||
|
|
||||||
// Adjust for potential display scaling.
|
// Convert from client coordinates to screen coordinates.
|
||||||
float scale = display::Screen::GetScreen()
|
POINT screen_pt = {device_pt.x(), device_pt.y()};
|
||||||
->GetDisplayNearestPoint(screen_point)
|
ClientToScreen(window_info_.window, &screen_pt);
|
||||||
.device_scale_factor();
|
|
||||||
return gfx::ToFlooredPoint(gfx::ScalePoint(gfx::PointF(screen_point), scale));
|
return gfx::Point(screen_pt.x, screen_pt.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CefBrowserPlatformDelegateNativeWin::ViewText(const std::string& text) {
|
void CefBrowserPlatformDelegateNativeWin::ViewText(const std::string& text) {
|
||||||
@ -562,12 +597,15 @@ LRESULT CALLBACK CefBrowserPlatformDelegateNativeWin::WndProc(HWND hwnd,
|
|||||||
UINT message,
|
UINT message,
|
||||||
WPARAM wParam,
|
WPARAM wParam,
|
||||||
LPARAM lParam) {
|
LPARAM lParam) {
|
||||||
CefBrowserPlatformDelegateNativeWin* platform_delegate =
|
CefBrowserPlatformDelegateNativeWin* platform_delegate = nullptr;
|
||||||
static_cast<CefBrowserPlatformDelegateNativeWin*>(
|
|
||||||
gfx::GetWindowUserData(hwnd));
|
|
||||||
CefBrowserHostImpl* browser = nullptr;
|
CefBrowserHostImpl* browser = nullptr;
|
||||||
if (platform_delegate)
|
|
||||||
browser = platform_delegate->browser_;
|
if (message != WM_NCCREATE) {
|
||||||
|
platform_delegate = static_cast<CefBrowserPlatformDelegateNativeWin*>(
|
||||||
|
gfx::GetWindowUserData(hwnd));
|
||||||
|
if (platform_delegate)
|
||||||
|
browser = platform_delegate->browser_;
|
||||||
|
}
|
||||||
|
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
@ -579,6 +617,31 @@ LRESULT CALLBACK CefBrowserPlatformDelegateNativeWin::WndProc(HWND hwnd,
|
|||||||
// Allow the close.
|
// Allow the close.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WM_NCCREATE: {
|
||||||
|
CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
|
||||||
|
platform_delegate =
|
||||||
|
reinterpret_cast<CefBrowserPlatformDelegateNativeWin*>(
|
||||||
|
cs->lpCreateParams);
|
||||||
|
DCHECK(platform_delegate);
|
||||||
|
// Associate |platform_delegate| with the window handle.
|
||||||
|
gfx::SetWindowUserData(hwnd, platform_delegate);
|
||||||
|
platform_delegate->window_info_.window = hwnd;
|
||||||
|
|
||||||
|
if (platform_delegate->has_frame_ &&
|
||||||
|
base::win::IsProcessPerMonitorDpiAware()) {
|
||||||
|
// This call gets Windows to scale the non-client area when
|
||||||
|
// WM_DPICHANGED is fired on Windows versions >= 10.0.14393.0.
|
||||||
|
static auto enable_non_client_dpi_scaling_func = []() {
|
||||||
|
return reinterpret_cast<decltype(::EnableNonClientDpiScaling)*>(
|
||||||
|
GetProcAddress(GetModuleHandle(L"user32.dll"),
|
||||||
|
"EnableNonClientDpiScaling"));
|
||||||
|
}();
|
||||||
|
platform_delegate->called_enable_non_client_dpi_scaling_ =
|
||||||
|
!!(enable_non_client_dpi_scaling_func &&
|
||||||
|
enable_non_client_dpi_scaling_func(hwnd));
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
case WM_NCDESTROY:
|
case WM_NCDESTROY:
|
||||||
if (platform_delegate) {
|
if (platform_delegate) {
|
||||||
// Clear the user data pointer.
|
// Clear the user data pointer.
|
||||||
@ -617,6 +680,17 @@ LRESULT CALLBACK CefBrowserPlatformDelegateNativeWin::WndProc(HWND hwnd,
|
|||||||
|
|
||||||
case WM_ERASEBKGND:
|
case WM_ERASEBKGND:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
case WM_DPICHANGED:
|
||||||
|
if (platform_delegate && platform_delegate->has_frame_) {
|
||||||
|
// Suggested size and position of the current window scaled for the
|
||||||
|
// new DPI.
|
||||||
|
const RECT* rect = reinterpret_cast<RECT*>(lParam);
|
||||||
|
SetWindowPos(platform_delegate->GetHostWindowHandle(), NULL, rect->left,
|
||||||
|
rect->top, rect->right - rect->left,
|
||||||
|
rect->bottom - rect->top, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefWindowProc(hwnd, message, wParam, lParam);
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
||||||
|
@ -68,6 +68,9 @@ class CefBrowserPlatformDelegateNativeWin
|
|||||||
// Widget hosting the web contents. It will be deleted automatically when the
|
// Widget hosting the web contents. It will be deleted automatically when the
|
||||||
// associated root window is destroyed.
|
// associated root window is destroyed.
|
||||||
views::Widget* window_widget_;
|
views::Widget* window_widget_;
|
||||||
|
|
||||||
|
bool has_frame_ = false;
|
||||||
|
bool called_enable_non_client_dpi_scaling_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_WIN_H_
|
#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_WIN_H_
|
||||||
|
@ -77,15 +77,15 @@ bool IsProcessPerMonitorDpiAware() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DPI value for 1x scale factor.
|
// DPI value for 1x scale factor.
|
||||||
#define DPI_1X 96
|
#define DPI_1X 96.0f
|
||||||
|
|
||||||
int GetWindowScaleFactor(HWND hwnd) {
|
float GetWindowScaleFactor(HWND hwnd) {
|
||||||
if (hwnd && IsProcessPerMonitorDpiAware()) {
|
if (hwnd && IsProcessPerMonitorDpiAware()) {
|
||||||
typedef UINT(WINAPI * GetDpiForWindowPtr)(HWND);
|
typedef UINT(WINAPI * GetDpiForWindowPtr)(HWND);
|
||||||
static GetDpiForWindowPtr func_ptr = reinterpret_cast<GetDpiForWindowPtr>(
|
static GetDpiForWindowPtr func_ptr = reinterpret_cast<GetDpiForWindowPtr>(
|
||||||
GetProcAddress(GetModuleHandle(L"user32.dll"), "GetDpiForWindow"));
|
GetProcAddress(GetModuleHandle(L"user32.dll"), "GetDpiForWindow"));
|
||||||
if (func_ptr)
|
if (func_ptr)
|
||||||
return func_ptr(hwnd) / DPI_1X;
|
return static_cast<float>(func_ptr(hwnd)) / DPI_1X;
|
||||||
}
|
}
|
||||||
|
|
||||||
return client::GetDeviceScaleFactor();
|
return client::GetDeviceScaleFactor();
|
||||||
@ -638,6 +638,7 @@ void RootWindowWin::OnSize(bool minimized) {
|
|||||||
const int font_height = LogicalToDevice(14, GetWindowScaleFactor(hwnd_));
|
const int font_height = LogicalToDevice(14, GetWindowScaleFactor(hwnd_));
|
||||||
|
|
||||||
if (font_height != font_height_) {
|
if (font_height != font_height_) {
|
||||||
|
font_height_ = font_height;
|
||||||
if (font_) {
|
if (font_) {
|
||||||
DeleteObject(font_);
|
DeleteObject(font_);
|
||||||
}
|
}
|
||||||
@ -716,18 +717,11 @@ void RootWindowWin::OnDpiChanged(WPARAM wParam, LPARAM lParam) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (browser_window_) {
|
if (browser_window_ && with_osr_) {
|
||||||
if (with_osr_) {
|
// Scale factor for the new display.
|
||||||
browser_window_->SetDeviceScaleFactor(LOWORD(wParam) / DPI_1X);
|
const float display_scale_factor =
|
||||||
} else {
|
static_cast<float>(LOWORD(wParam)) / DPI_1X;
|
||||||
// Forward the DPI change to the browser window handle.
|
browser_window_->SetDeviceScaleFactor(display_scale_factor);
|
||||||
HWND browser_hwnd = browser_window_->GetWindowHandle();
|
|
||||||
if (browser_hwnd) {
|
|
||||||
RECT child_rect = {};
|
|
||||||
SendMessage(browser_hwnd, WM_DPICHANGED, wParam,
|
|
||||||
reinterpret_cast<LPARAM>(&child_rect));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suggested size and position of the current window scaled for the new DPI.
|
// Suggested size and position of the current window scaled for the new DPI.
|
||||||
@ -928,7 +922,7 @@ void RootWindowWin::OnCreate(LPCREATESTRUCT lpCreateStruct) {
|
|||||||
::SetMenu(hwnd_, NULL);
|
::SetMenu(hwnd_, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int device_scale_factor = GetWindowScaleFactor(hwnd_);
|
const float device_scale_factor = GetWindowScaleFactor(hwnd_);
|
||||||
|
|
||||||
if (with_osr_) {
|
if (with_osr_) {
|
||||||
browser_window_->SetDeviceScaleFactor(device_scale_factor);
|
browser_window_->SetDeviceScaleFactor(device_scale_factor);
|
||||||
@ -938,7 +932,6 @@ void RootWindowWin::OnCreate(LPCREATESTRUCT lpCreateStruct) {
|
|||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
CefRect cef_rect(rect.left, rect.top, rect.right - rect.left,
|
CefRect cef_rect(rect.left, rect.top, rect.right - rect.left,
|
||||||
rect.bottom - rect.top);
|
rect.bottom - rect.top);
|
||||||
cef_rect = client::DeviceToLogical(cef_rect, device_scale_factor);
|
|
||||||
browser_window_->CreateBrowser(hwnd_, cef_rect, browser_settings_,
|
browser_window_->CreateBrowser(hwnd_, cef_rect, browser_settings_,
|
||||||
delegate_->GetRequestContext(this));
|
delegate_->GetRequestContext(this));
|
||||||
} else {
|
} else {
|
||||||
@ -1043,7 +1036,7 @@ void RootWindowWin::OnAutoResize(const CefSize& new_size) {
|
|||||||
if (new_width < 200)
|
if (new_width < 200)
|
||||||
new_width = 200;
|
new_width = 200;
|
||||||
|
|
||||||
const int device_scale_factor = GetWindowScaleFactor(hwnd_);
|
const float device_scale_factor = GetWindowScaleFactor(hwnd_);
|
||||||
RECT rect = {0, 0, LogicalToDevice(new_width, device_scale_factor),
|
RECT rect = {0, 0, LogicalToDevice(new_width, device_scale_factor),
|
||||||
LogicalToDevice(new_size.height, device_scale_factor)};
|
LogicalToDevice(new_size.height, device_scale_factor)};
|
||||||
DWORD style = GetWindowLong(hwnd_, GWL_STYLE);
|
DWORD style = GetWindowLong(hwnd_, GWL_STYLE);
|
||||||
|
@ -25,13 +25,6 @@ int DeviceToLogical(int value, float device_scale_factor) {
|
|||||||
return static_cast<int>(std::floor(scaled_val));
|
return static_cast<int>(std::floor(scaled_val));
|
||||||
}
|
}
|
||||||
|
|
||||||
CefRect DeviceToLogical(const CefRect& value, float device_scale_factor) {
|
|
||||||
return CefRect(DeviceToLogical(value.x, device_scale_factor),
|
|
||||||
DeviceToLogical(value.y, device_scale_factor),
|
|
||||||
DeviceToLogical(value.width, device_scale_factor),
|
|
||||||
DeviceToLogical(value.height, device_scale_factor));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceToLogical(CefMouseEvent& value, float device_scale_factor) {
|
void DeviceToLogical(CefMouseEvent& value, float device_scale_factor) {
|
||||||
value.x = DeviceToLogical(value.x, device_scale_factor);
|
value.x = DeviceToLogical(value.x, device_scale_factor);
|
||||||
value.y = DeviceToLogical(value.y, device_scale_factor);
|
value.y = DeviceToLogical(value.y, device_scale_factor);
|
||||||
|
@ -16,7 +16,6 @@ CefRect LogicalToDevice(const CefRect& value, float device_scale_factor);
|
|||||||
|
|
||||||
// Convert |value| from device coordinates to logical coordinates.
|
// Convert |value| from device coordinates to logical coordinates.
|
||||||
int DeviceToLogical(int value, float device_scale_factor);
|
int DeviceToLogical(int value, float device_scale_factor);
|
||||||
CefRect DeviceToLogical(const CefRect& value, float device_scale_factor);
|
|
||||||
void DeviceToLogical(CefMouseEvent& value, float device_scale_factor);
|
void DeviceToLogical(CefMouseEvent& value, float device_scale_factor);
|
||||||
|
|
||||||
} // namespace client
|
} // namespace client
|
||||||
|
Loading…
x
Reference in New Issue
Block a user