diff --git a/libcef/browser/native/browser_platform_delegate_native_win.cc b/libcef/browser/native/browser_platform_delegate_native_win.cc index 3d7445fee..813f27b04 100644 --- a/libcef/browser/native/browser_platform_delegate_native_win.cc +++ b/libcef/browser/native/browser_platform_delegate_native_win.cc @@ -20,6 +20,7 @@ #include "base/memory/ref_counted_memory.h" #include "base/strings/utf_string_conversions.h" #include "base/win/registry.h" +#include "base/win/win_util.h" #include "content/public/browser/native_web_keyboard_event.h" #include "third_party/WebKit/public/platform/WebMouseEvent.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); } +// 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( + GetProcAddress(GetModuleHandle(L"user32.dll"), "GetDpiForWindow")); + }(); + if (get_dpi_for_window_func) + return static_cast(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 CefBrowserPlatformDelegateNativeWin::CefBrowserPlatformDelegateNativeWin( @@ -117,40 +143,49 @@ void CefBrowserPlatformDelegateNativeWin::BrowserDestroyed( bool CefBrowserPlatformDelegateNativeWin::CreateHostWindow() { RegisterWindowClass(); + has_frame_ = !(window_info_.style & WS_CHILD); + std::wstring windowName(CefString(&window_info_.window_name)); // Create the new browser window. - window_info_.window = CreateWindowEx( - window_info_.ex_style, GetWndClass(), windowName.c_str(), - window_info_.style, window_info_.x, window_info_.y, window_info_.width, - window_info_.height, window_info_.parent_window, window_info_.menu, - ::GetModuleHandle(NULL), NULL); + CreateWindowEx(window_info_.ex_style, GetWndClass(), windowName.c_str(), + window_info_.style, window_info_.x, window_info_.y, + window_info_.width, window_info_.height, + window_info_.parent_window, window_info_.menu, + ::GetModuleHandle(NULL), this); // It's possible for CreateWindowEx to fail if the parent window was // destroyed between the call to CreateBrowser and the above one. - DCHECK(window_info_.window != NULL); + DCHECK(window_info_.window); if (!window_info_.window) return false; 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(). browser_->AddRef(); - RECT cr; - GetClientRect(window_info_.window, &cr); + if (!called_enable_non_client_dpi_scaling_ && 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. + // Derived signature; not available in headers. + static auto enable_child_window_dpi_message_func = []() { + using EnableChildWindowDpiMessagePtr = LRESULT(WINAPI*)(HWND, BOOL); + return reinterpret_cast(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_); - // 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); - float scale = display::Screen::GetScreen() - ->GetDisplayNearestPoint(point) - .device_scale_factor(); + const float scale = GetWindowScaleFactor(window_info_.window); point = gfx::ToFlooredPoint(gfx::ScalePoint(gfx::PointF(point), 1.0f / scale)); @@ -270,19 +305,19 @@ gfx::Point CefBrowserPlatformDelegateNativeWin::GetScreenPoint( if (windowless_handler_) return windowless_handler_->GetParentScreenPoint(view); - if (!window_widget_) + if (!window_info_.window) return view; - aura::Window* window = window_widget_->GetNativeView(); - const gfx::Rect& bounds_in_screen = window->GetBoundsInScreen(); - const gfx::Point& screen_point = gfx::Point(bounds_in_screen.x() + view.x(), - bounds_in_screen.y() + view.y()); + // Convert from logical coordinates to device coordinates. + const float scale = GetWindowScaleFactor(window_info_.window); + const gfx::Point& device_pt = + gfx::ToFlooredPoint(gfx::ScalePoint(gfx::PointF(view), scale)); - // Adjust for potential display scaling. - float scale = display::Screen::GetScreen() - ->GetDisplayNearestPoint(screen_point) - .device_scale_factor(); - return gfx::ToFlooredPoint(gfx::ScalePoint(gfx::PointF(screen_point), scale)); + // Convert from client coordinates to screen coordinates. + POINT screen_pt = {device_pt.x(), device_pt.y()}; + ClientToScreen(window_info_.window, &screen_pt); + + return gfx::Point(screen_pt.x, screen_pt.y); } void CefBrowserPlatformDelegateNativeWin::ViewText(const std::string& text) { @@ -562,12 +597,15 @@ LRESULT CALLBACK CefBrowserPlatformDelegateNativeWin::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - CefBrowserPlatformDelegateNativeWin* platform_delegate = - static_cast( - gfx::GetWindowUserData(hwnd)); + CefBrowserPlatformDelegateNativeWin* platform_delegate = nullptr; CefBrowserHostImpl* browser = nullptr; - if (platform_delegate) - browser = platform_delegate->browser_; + + if (message != WM_NCCREATE) { + platform_delegate = static_cast( + gfx::GetWindowUserData(hwnd)); + if (platform_delegate) + browser = platform_delegate->browser_; + } switch (message) { case WM_CLOSE: @@ -579,6 +617,31 @@ LRESULT CALLBACK CefBrowserPlatformDelegateNativeWin::WndProc(HWND hwnd, // Allow the close. break; + case WM_NCCREATE: { + CREATESTRUCT* cs = reinterpret_cast(lParam); + platform_delegate = + reinterpret_cast( + 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( + 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: if (platform_delegate) { // Clear the user data pointer. @@ -617,6 +680,17 @@ LRESULT CALLBACK CefBrowserPlatformDelegateNativeWin::WndProc(HWND hwnd, case WM_ERASEBKGND: 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(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); diff --git a/libcef/browser/native/browser_platform_delegate_native_win.h b/libcef/browser/native/browser_platform_delegate_native_win.h index ec2e9673c..b59d87483 100644 --- a/libcef/browser/native/browser_platform_delegate_native_win.h +++ b/libcef/browser/native/browser_platform_delegate_native_win.h @@ -68,6 +68,9 @@ class CefBrowserPlatformDelegateNativeWin // Widget hosting the web contents. It will be deleted automatically when the // associated root window is destroyed. 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_ diff --git a/tests/cefclient/browser/root_window_win.cc b/tests/cefclient/browser/root_window_win.cc index be37b126d..64e58b9c6 100644 --- a/tests/cefclient/browser/root_window_win.cc +++ b/tests/cefclient/browser/root_window_win.cc @@ -77,15 +77,15 @@ bool IsProcessPerMonitorDpiAware() { } // 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()) { typedef UINT(WINAPI * GetDpiForWindowPtr)(HWND); static GetDpiForWindowPtr func_ptr = reinterpret_cast( GetProcAddress(GetModuleHandle(L"user32.dll"), "GetDpiForWindow")); if (func_ptr) - return func_ptr(hwnd) / DPI_1X; + return static_cast(func_ptr(hwnd)) / DPI_1X; } return client::GetDeviceScaleFactor(); @@ -638,6 +638,7 @@ void RootWindowWin::OnSize(bool minimized) { const int font_height = LogicalToDevice(14, GetWindowScaleFactor(hwnd_)); if (font_height != font_height_) { + font_height_ = font_height; if (font_) { DeleteObject(font_); } @@ -716,18 +717,11 @@ void RootWindowWin::OnDpiChanged(WPARAM wParam, LPARAM lParam) { return; } - if (browser_window_) { - if (with_osr_) { - browser_window_->SetDeviceScaleFactor(LOWORD(wParam) / DPI_1X); - } else { - // Forward the DPI change to the browser window handle. - HWND browser_hwnd = browser_window_->GetWindowHandle(); - if (browser_hwnd) { - RECT child_rect = {}; - SendMessage(browser_hwnd, WM_DPICHANGED, wParam, - reinterpret_cast(&child_rect)); - } - } + if (browser_window_ && with_osr_) { + // Scale factor for the new display. + const float display_scale_factor = + static_cast(LOWORD(wParam)) / DPI_1X; + browser_window_->SetDeviceScaleFactor(display_scale_factor); } // 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); } - const int device_scale_factor = GetWindowScaleFactor(hwnd_); + const float device_scale_factor = GetWindowScaleFactor(hwnd_); if (with_osr_) { browser_window_->SetDeviceScaleFactor(device_scale_factor); @@ -938,7 +932,6 @@ void RootWindowWin::OnCreate(LPCREATESTRUCT lpCreateStruct) { // Create the browser window. CefRect cef_rect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); - cef_rect = client::DeviceToLogical(cef_rect, device_scale_factor); browser_window_->CreateBrowser(hwnd_, cef_rect, browser_settings_, delegate_->GetRequestContext(this)); } else { @@ -1043,7 +1036,7 @@ void RootWindowWin::OnAutoResize(const CefSize& new_size) { if (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), LogicalToDevice(new_size.height, device_scale_factor)}; DWORD style = GetWindowLong(hwnd_, GWL_STYLE); diff --git a/tests/shared/browser/geometry_util.cc b/tests/shared/browser/geometry_util.cc index cb40a4eba..206edbc80 100644 --- a/tests/shared/browser/geometry_util.cc +++ b/tests/shared/browser/geometry_util.cc @@ -25,13 +25,6 @@ int DeviceToLogical(int value, float device_scale_factor) { return static_cast(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) { value.x = DeviceToLogical(value.x, device_scale_factor); value.y = DeviceToLogical(value.y, device_scale_factor); diff --git a/tests/shared/browser/geometry_util.h b/tests/shared/browser/geometry_util.h index 5384adfe8..1f1e188a6 100644 --- a/tests/shared/browser/geometry_util.h +++ b/tests/shared/browser/geometry_util.h @@ -16,7 +16,6 @@ CefRect LogicalToDevice(const CefRect& value, float device_scale_factor); // Convert |value| from device coordinates to logical coordinates. 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); } // namespace client