From 57b9cf9dddb16fc27a0f4c747e354c2e3e45ce11 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Tue, 20 Feb 2018 17:24:59 -0500 Subject: [PATCH] Windows: Add per-monitor DPI support (issue #2313) --- libcef/common/base_impl.cc | 58 +-- .../browser/browser_window_osr_win.cc | 6 +- tests/cefclient/browser/osr_window_win.cc | 5 +- tests/cefclient/browser/root_window_win.cc | 420 ++++++++++++------ tests/cefclient/browser/root_window_win.h | 7 + tests/shared/browser/geometry_util.cc | 7 + tests/shared/browser/geometry_util.h | 1 + 7 files changed, 298 insertions(+), 206 deletions(-) diff --git a/libcef/common/base_impl.cc b/libcef/common/base_impl.cc index 60b3b76b4..b6c947146 100644 --- a/libcef/common/base_impl.cc +++ b/libcef/common/base_impl.cc @@ -4,12 +4,6 @@ #include "include/base/cef_build.h" -#if defined(OS_WIN) -#include - -#include -#endif - #include "include/internal/cef_logging_internal.h" #include "include/internal/cef_thread_internal.h" #include "include/internal/cef_trace_event_internal.h" @@ -19,50 +13,8 @@ #include "base/trace_event/trace_event.h" #if defined(OS_WIN) -#include "base/win/windows_version.h" - -namespace { - -// Implementation from chrome/app/chrome_exe_main_win.cc. - -// Win8.1 supports monitor-specific DPI scaling. -bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) { - typedef HRESULT(WINAPI * SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS); - SetProcessDpiAwarenessPtr set_process_dpi_awareness_func = - reinterpret_cast(GetProcAddress( - GetModuleHandleA("user32.dll"), "SetProcessDpiAwarenessInternal")); - if (set_process_dpi_awareness_func) { - HRESULT hr = set_process_dpi_awareness_func(value); - if (SUCCEEDED(hr)) { - VLOG(1) << "SetProcessDpiAwareness succeeded."; - return true; - } else if (hr == E_ACCESSDENIED) { - LOG(ERROR) << "Access denied error from SetProcessDpiAwareness. " - "Function called twice, or manifest was used."; - } - } - return false; -} - -// This function works for Windows Vista through Win8. Win8.1 must use -// SetProcessDpiAwareness[Wrapper]. -BOOL SetProcessDPIAwareWrapper() { - typedef BOOL(WINAPI * SetProcessDPIAwarePtr)(VOID); - SetProcessDPIAwarePtr set_process_dpi_aware_func = - reinterpret_cast( - GetProcAddress(GetModuleHandleA("user32.dll"), "SetProcessDPIAware")); - return set_process_dpi_aware_func && set_process_dpi_aware_func(); -} - -void EnableHighDPISupport() { - if (!SetProcessDpiAwarenessWrapper(PROCESS_SYSTEM_DPI_AWARE)) { - SetProcessDPIAwareWrapper(); - } -} - -} // namespace - -#endif // defined(OS_WIN) +#include "base/win/win_util.h" +#endif // The contents of this file are a compilation unit that is not called by other // functions in the the library. Consiquently MSVS will exclude it during the @@ -399,10 +351,6 @@ cef_get_current_platform_thread_handle() { void CefEnableHighDPISupport() { #if defined(OS_WIN) - // We don't want to set DPI awareness on pre-Win7 because we don't support - // DirectWrite there. GDI fonts are kerned very badly, so better to leave - // DPI-unaware and at effective 1.0. See also ShouldUseDirectWrite(). - if (base::win::GetVersion() >= base::win::VERSION_WIN7) - EnableHighDPISupport(); + base::win::EnableHighDPISupport(); #endif } diff --git a/tests/cefclient/browser/browser_window_osr_win.cc b/tests/cefclient/browser/browser_window_osr_win.cc index 57eef1696..2b1851fba 100644 --- a/tests/cefclient/browser/browser_window_osr_win.cc +++ b/tests/cefclient/browser/browser_window_osr_win.cc @@ -5,16 +5,13 @@ #include "tests/cefclient/browser/browser_window_osr_win.h" #include "tests/shared/browser/main_message_loop.h" -#include "tests/shared/browser/util_win.h" namespace client { BrowserWindowOsrWin::BrowserWindowOsrWin(BrowserWindow::Delegate* delegate, const std::string& startup_url, const OsrRenderer::Settings& settings) - : BrowserWindow(delegate), - osr_hwnd_(NULL), - device_scale_factor_(client::GetDeviceScaleFactor()) { + : BrowserWindow(delegate), osr_hwnd_(NULL), device_scale_factor_(0) { osr_window_ = new OsrWindowWin(this, settings); client_handler_ = new ClientHandlerOsr(this, osr_window_.get(), startup_url); } @@ -92,6 +89,7 @@ void BrowserWindowOsrWin::SetDeviceScaleFactor(float device_scale_factor) { float BrowserWindowOsrWin::GetDeviceScaleFactor() const { REQUIRE_MAIN_THREAD(); + DCHECK_GT(device_scale_factor_, 0); return device_scale_factor_; } diff --git a/tests/cefclient/browser/osr_window_win.cc b/tests/cefclient/browser/osr_window_win.cc index af42fc1f1..288c964ae 100644 --- a/tests/cefclient/browser/osr_window_win.cc +++ b/tests/cefclient/browser/osr_window_win.cc @@ -60,7 +60,7 @@ OsrWindowWin::OsrWindowWin(Delegate* delegate, hwnd_(NULL), hdc_(NULL), hrc_(NULL), - device_scale_factor_(client::GetDeviceScaleFactor()), + device_scale_factor_(0), painting_popup_(false), render_task_pending_(false), hidden_(false), @@ -872,6 +872,7 @@ bool OsrWindowWin::GetRootScreenRect(CefRefPtr browser, bool OsrWindowWin::GetViewRect(CefRefPtr browser, CefRect& rect) { CEF_REQUIRE_UI_THREAD(); + DCHECK_GT(device_scale_factor_, 0); rect.x = rect.y = 0; rect.width = DeviceToLogical(client_rect_.right - client_rect_.left, @@ -887,6 +888,7 @@ bool OsrWindowWin::GetScreenPoint(CefRefPtr browser, int& screenX, int& screenY) { CEF_REQUIRE_UI_THREAD(); + DCHECK_GT(device_scale_factor_, 0); if (!::IsWindow(hwnd_)) return false; @@ -903,6 +905,7 @@ bool OsrWindowWin::GetScreenPoint(CefRefPtr browser, bool OsrWindowWin::GetScreenInfo(CefRefPtr browser, CefScreenInfo& screen_info) { CEF_REQUIRE_UI_THREAD(); + DCHECK_GT(device_scale_factor_, 0); if (!::IsWindow(hwnd_)) return false; diff --git a/tests/cefclient/browser/root_window_win.cc b/tests/cefclient/browser/root_window_win.cc index 6eddeeb83..be37b126d 100644 --- a/tests/cefclient/browser/root_window_win.cc +++ b/tests/cefclient/browser/root_window_win.cc @@ -4,6 +4,8 @@ #include "tests/cefclient/browser/root_window_win.h" +#include + #include "include/base/cef_bind.h" #include "include/base/cef_build.h" #include "include/cef_app.h" @@ -46,30 +48,55 @@ INT_PTR CALLBACK AboutWndProc(HWND hDlg, return FALSE; } -int GetButtonWidth() { - static int button_width = BUTTON_WIDTH; - static bool initialized = false; - - if (!initialized) { - button_width = - LogicalToDevice(BUTTON_WIDTH, client::GetDeviceScaleFactor()); - initialized = true; +// Returns true if the process is per monitor DPI aware. +bool IsProcessPerMonitorDpiAware() { + enum class PerMonitorDpiAware { + UNKNOWN = 0, + PER_MONITOR_DPI_UNAWARE, + PER_MONITOR_DPI_AWARE, + }; + static PerMonitorDpiAware per_monitor_dpi_aware = PerMonitorDpiAware::UNKNOWN; + if (per_monitor_dpi_aware == PerMonitorDpiAware::UNKNOWN) { + per_monitor_dpi_aware = PerMonitorDpiAware::PER_MONITOR_DPI_UNAWARE; + HMODULE shcore_dll = ::LoadLibrary(L"shcore.dll"); + if (shcore_dll) { + typedef HRESULT(WINAPI * GetProcessDpiAwarenessPtr)( + HANDLE, PROCESS_DPI_AWARENESS*); + GetProcessDpiAwarenessPtr func_ptr = + reinterpret_cast( + ::GetProcAddress(shcore_dll, "GetProcessDpiAwareness")); + if (func_ptr) { + PROCESS_DPI_AWARENESS awareness; + if (SUCCEEDED(func_ptr(nullptr, &awareness)) && + awareness == PROCESS_PER_MONITOR_DPI_AWARE) + per_monitor_dpi_aware = PerMonitorDpiAware::PER_MONITOR_DPI_AWARE; + } + } } - - return button_width; + return per_monitor_dpi_aware == PerMonitorDpiAware::PER_MONITOR_DPI_AWARE; } -int GetURLBarHeight() { - static int urlbar_height = URLBAR_HEIGHT; - static bool initialized = false; +// DPI value for 1x scale factor. +#define DPI_1X 96 - if (!initialized) { - urlbar_height = - LogicalToDevice(URLBAR_HEIGHT, client::GetDeviceScaleFactor()); - initialized = true; +int 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 urlbar_height; + return client::GetDeviceScaleFactor(); +} + +int GetButtonWidth(HWND hwnd) { + return LogicalToDevice(BUTTON_WIDTH, GetWindowScaleFactor(hwnd)); +} + +int GetURLBarHeight(HWND hwnd) { + return LogicalToDevice(URLBAR_HEIGHT, GetWindowScaleFactor(hwnd)); } } // namespace @@ -84,6 +111,7 @@ RootWindowWin::RootWindowWin() hwnd_(NULL), draggable_region_(NULL), font_(NULL), + font_height_(0), back_hwnd_(NULL), forward_hwnd_(NULL), reload_hwnd_(NULL), @@ -97,7 +125,8 @@ RootWindowWin::RootWindowWin() find_next_(false), find_match_case_last_(false), window_destroyed_(false), - browser_destroyed_(false) { + browser_destroyed_(false), + called_enable_non_client_dpi_scaling_(false) { find_buff_[0] = 0; // Create a HRGN representing the draggable window area. @@ -313,8 +342,6 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings, // Adjust the window size to account for window frame and controls. RECT window_rect = start_rect_; ::AdjustWindowRectEx(&window_rect, dwStyle, with_controls_, 0); - if (with_controls_) - window_rect.bottom += GetURLBarHeight(); x = start_rect_.left; y = start_rect_.top; @@ -322,110 +349,23 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings, height = window_rect.bottom - window_rect.top; } + browser_settings_ = settings; + // Create the main window initially hidden. - hwnd_ = CreateWindow(window_class.c_str(), window_title.c_str(), dwStyle, x, - y, width, height, NULL, NULL, hInstance, NULL); + CreateWindow(window_class.c_str(), window_title.c_str(), dwStyle, x, y, width, + height, NULL, NULL, hInstance, this); CHECK(hwnd_); - // Associate |this| with the main window. - SetUserDataPtr(hwnd_, this); - - RECT rect; - GetClientRect(hwnd_, &rect); - - if (with_controls_) { - // Create the child controls. - int x_offset = 0; - - const int button_width = GetButtonWidth(); - const int urlbar_height = GetURLBarHeight(); - const int font_height = LogicalToDevice(14, client::GetDeviceScaleFactor()); - - // Create a scaled font. - font_ = - ::CreateFont(-font_height, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, - DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial"); - - back_hwnd_ = CreateWindow( - L"BUTTON", L"Back", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, - x_offset, 0, button_width, urlbar_height, hwnd_, - reinterpret_cast(IDC_NAV_BACK), hInstance, 0); - CHECK(back_hwnd_); - SendMessage(back_hwnd_, WM_SETFONT, reinterpret_cast(font_), TRUE); - x_offset += button_width; - - forward_hwnd_ = - CreateWindow(L"BUTTON", L"Forward", - WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, - x_offset, 0, button_width, urlbar_height, hwnd_, - reinterpret_cast(IDC_NAV_FORWARD), hInstance, 0); - CHECK(forward_hwnd_); - SendMessage(forward_hwnd_, WM_SETFONT, reinterpret_cast(font_), - TRUE); - x_offset += button_width; - - reload_hwnd_ = - CreateWindow(L"BUTTON", L"Reload", - WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, - x_offset, 0, button_width, urlbar_height, hwnd_, - reinterpret_cast(IDC_NAV_RELOAD), hInstance, 0); - CHECK(reload_hwnd_); - SendMessage(reload_hwnd_, WM_SETFONT, reinterpret_cast(font_), - TRUE); - x_offset += button_width; - - stop_hwnd_ = CreateWindow( - L"BUTTON", L"Stop", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, - x_offset, 0, button_width, urlbar_height, hwnd_, - reinterpret_cast(IDC_NAV_STOP), hInstance, 0); - CHECK(stop_hwnd_); - SendMessage(stop_hwnd_, WM_SETFONT, reinterpret_cast(font_), TRUE); - x_offset += button_width; - - edit_hwnd_ = CreateWindow(L"EDIT", 0, - WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | - ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_DISABLED, - x_offset, 0, rect.right - button_width * 4, - urlbar_height, hwnd_, 0, hInstance, 0); - SendMessage(edit_hwnd_, WM_SETFONT, reinterpret_cast(font_), TRUE); - CHECK(edit_hwnd_); - - // Override the edit control's window procedure. - edit_wndproc_old_ = SetWndProcPtr(edit_hwnd_, EditWndProc); - - // Associate |this| with the edit window. - SetUserDataPtr(edit_hwnd_, this); - - rect.top += urlbar_height; - - if (!with_osr_) { - // Remove the menu items that are only used with OSR. - HMENU hMenu = ::GetMenu(hwnd_); - if (hMenu) { - HMENU hTestMenu = ::GetSubMenu(hMenu, 2); - if (hTestMenu) { - ::RemoveMenu(hTestMenu, ID_TESTS_OSR_FPS, MF_BYCOMMAND); - ::RemoveMenu(hTestMenu, ID_TESTS_OSR_DSF, MF_BYCOMMAND); - } - } - } - } else { - // No controls so also remove the default menu. - ::SetMenu(hwnd_, NULL); - } - - if (!is_popup_) { - // Create the browser window. - CefRect cef_rect(rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top); - browser_window_->CreateBrowser(hwnd_, cef_rect, settings, - delegate_->GetRequestContext(this)); - } else { - // With popups we already have a browser window. Parent the browser window - // to the root window and show it in the correct location. - browser_window_->ShowPopup(hwnd_, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top); + if (!called_enable_non_client_dpi_scaling_ && 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. + typedef LRESULT(WINAPI * EnableChildWindowDpiMessagePtr)(HWND, BOOL); + static EnableChildWindowDpiMessagePtr func_ptr = + reinterpret_cast(GetProcAddress( + GetModuleHandle(L"user32.dll"), "EnableChildWindowDpiMessage")); + if (func_ptr) + func_ptr(hwnd_, TRUE); } if (!initially_hidden) { @@ -535,12 +475,15 @@ LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd, LPARAM lParam) { REQUIRE_MAIN_THREAD(); - RootWindowWin* self = GetUserDataPtr(hWnd); - if (!self) - return DefWindowProc(hWnd, message, wParam, lParam); - DCHECK(hWnd == self->hwnd_); + RootWindowWin* self = NULL; + if (message != WM_NCCREATE) { + self = GetUserDataPtr(hWnd); + if (!self) + return DefWindowProc(hWnd, message, wParam, lParam); + DCHECK_EQ(hWnd, self->hwnd_); + } - if (message == self->find_message_id_) { + if (self && message == self->find_message_id_) { // Message targeting the find dialog. LPFINDREPLACE lpfr = reinterpret_cast(lParam); CHECK(lpfr == &self->find_state_); @@ -589,6 +532,10 @@ LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd, self->OnMove(); return 0; + case WM_DPICHANGED: + self->OnDpiChanged(wParam, lParam); + break; + case WM_ERASEBKGND: if (self->OnEraseBkgnd()) break; @@ -629,6 +576,21 @@ LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd, return hit; } + case WM_NCCREATE: { + CREATESTRUCT* cs = reinterpret_cast(lParam); + self = reinterpret_cast(cs->lpCreateParams); + DCHECK(self); + // Associate |self| with the main window. + SetUserDataPtr(hWnd, self); + self->hwnd_ = hWnd; + + self->OnNCCreate(cs); + } break; + + case WM_CREATE: + self->OnCreate(reinterpret_cast(lParam)); + break; + case WM_NCDESTROY: // Clear the reference to |self|. SetUserDataPtr(hWnd, NULL); @@ -670,37 +632,70 @@ void RootWindowWin::OnSize(bool minimized) { RECT rect; GetClientRect(hwnd_, &rect); - if (with_controls_) { - static int button_width = GetButtonWidth(); - static int urlbar_height = GetURLBarHeight(); + if (with_controls_ && edit_hwnd_) { + const int button_width = GetButtonWidth(hwnd_); + const int urlbar_height = GetURLBarHeight(hwnd_); + const int font_height = LogicalToDevice(14, GetWindowScaleFactor(hwnd_)); + + if (font_height != font_height_) { + if (font_) { + DeleteObject(font_); + } + + // Create a scaled font. + font_ = + ::CreateFont(-font_height, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial"); + + SendMessage(back_hwnd_, WM_SETFONT, reinterpret_cast(font_), + TRUE); + SendMessage(forward_hwnd_, WM_SETFONT, reinterpret_cast(font_), + TRUE); + SendMessage(reload_hwnd_, WM_SETFONT, reinterpret_cast(font_), + TRUE); + SendMessage(stop_hwnd_, WM_SETFONT, reinterpret_cast(font_), + TRUE); + SendMessage(edit_hwnd_, WM_SETFONT, reinterpret_cast(font_), + TRUE); + } // Resize the window and address bar to match the new frame size. rect.top += urlbar_height; - int urloffset = rect.left + button_width * 4; + int x_offset = rect.left; // |browser_hwnd| may be NULL if the browser has not yet been created. HWND browser_hwnd = NULL; if (browser_window_) browser_hwnd = browser_window_->GetWindowHandle(); + // Resize all controls. + HDWP hdwp = BeginDeferWindowPos(browser_hwnd ? 6 : 5); + hdwp = DeferWindowPos(hdwp, back_hwnd_, NULL, x_offset, 0, button_width, + urlbar_height, SWP_NOZORDER); + x_offset += button_width; + hdwp = DeferWindowPos(hdwp, forward_hwnd_, NULL, x_offset, 0, button_width, + urlbar_height, SWP_NOZORDER); + x_offset += button_width; + hdwp = DeferWindowPos(hdwp, reload_hwnd_, NULL, x_offset, 0, button_width, + urlbar_height, SWP_NOZORDER); + x_offset += button_width; + hdwp = DeferWindowPos(hdwp, stop_hwnd_, NULL, x_offset, 0, button_width, + urlbar_height, SWP_NOZORDER); + x_offset += button_width; + hdwp = DeferWindowPos(hdwp, edit_hwnd_, NULL, x_offset, 0, + rect.right - x_offset, urlbar_height, SWP_NOZORDER); + if (browser_hwnd) { - // Resize both the browser and the URL edit field. - HDWP hdwp = BeginDeferWindowPos(2); - hdwp = - DeferWindowPos(hdwp, edit_hwnd_, NULL, urloffset, 0, - rect.right - urloffset, urlbar_height, SWP_NOZORDER); hdwp = DeferWindowPos(hdwp, browser_hwnd, NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER); - BOOL result = EndDeferWindowPos(hdwp); - ALLOW_UNUSED_LOCAL(result); - DCHECK(result); - } else { - // Resize just the URL edit field. - SetWindowPos(edit_hwnd_, NULL, urloffset, 0, rect.right - urloffset, - urlbar_height, SWP_NOZORDER); } + + BOOL result = EndDeferWindowPos(hdwp); + ALLOW_UNUSED_LOCAL(result); + DCHECK(result); } else if (browser_window_) { // Size the browser window to the whole client area. browser_window_->SetBounds(0, 0, rect.right, rect.bottom); @@ -715,6 +710,32 @@ void RootWindowWin::OnMove() { browser->GetHost()->NotifyMoveOrResizeStarted(); } +void RootWindowWin::OnDpiChanged(WPARAM wParam, LPARAM lParam) { + if (LOWORD(wParam) != HIWORD(wParam)) { + NOTIMPLEMENTED() << "Received non-square scaling factors"; + 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)); + } + } + } + + // Suggested size and position of the current window scaled for the new DPI. + const RECT* rect = reinterpret_cast(lParam); + SetBounds(rect->left, rect->top, rect->right - rect->left, + rect->bottom - rect->top); +} + bool RootWindowWin::OnEraseBkgnd() { // Erase the background when the browser does not exist. return (GetBrowser() == NULL); @@ -821,6 +842,113 @@ void RootWindowWin::OnAbout() { AboutWndProc); } +void RootWindowWin::OnNCCreate(LPCREATESTRUCT lpCreateStruct) { + if (IsProcessPerMonitorDpiAware()) { + // This call gets Windows to scale the non-client area when WM_DPICHANGED + // is fired on Windows versions >= 10.0.14393.0. + typedef BOOL(WINAPI * EnableNonClientDpiScalingPtr)(HWND); + static EnableNonClientDpiScalingPtr func_ptr = + reinterpret_cast(GetProcAddress( + GetModuleHandle(L"user32.dll"), "EnableNonClientDpiScaling")); + called_enable_non_client_dpi_scaling_ = !!(func_ptr && func_ptr(hwnd_)); + } +} + +void RootWindowWin::OnCreate(LPCREATESTRUCT lpCreateStruct) { + const HINSTANCE hInstance = lpCreateStruct->hInstance; + + RECT rect; + GetClientRect(hwnd_, &rect); + + if (with_controls_) { + // Create the child controls. + int x_offset = 0; + + const int button_width = GetButtonWidth(hwnd_); + const int urlbar_height = GetURLBarHeight(hwnd_); + + back_hwnd_ = CreateWindow( + L"BUTTON", L"Back", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, + x_offset, 0, button_width, urlbar_height, hwnd_, + reinterpret_cast(IDC_NAV_BACK), hInstance, 0); + CHECK(back_hwnd_); + x_offset += button_width; + + forward_hwnd_ = + CreateWindow(L"BUTTON", L"Forward", + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, + x_offset, 0, button_width, urlbar_height, hwnd_, + reinterpret_cast(IDC_NAV_FORWARD), hInstance, 0); + CHECK(forward_hwnd_); + x_offset += button_width; + + reload_hwnd_ = + CreateWindow(L"BUTTON", L"Reload", + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, + x_offset, 0, button_width, urlbar_height, hwnd_, + reinterpret_cast(IDC_NAV_RELOAD), hInstance, 0); + CHECK(reload_hwnd_); + x_offset += button_width; + + stop_hwnd_ = CreateWindow( + L"BUTTON", L"Stop", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, + x_offset, 0, button_width, urlbar_height, hwnd_, + reinterpret_cast(IDC_NAV_STOP), hInstance, 0); + CHECK(stop_hwnd_); + x_offset += button_width; + + edit_hwnd_ = CreateWindow(L"EDIT", 0, + WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | + ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_DISABLED, + x_offset, 0, rect.right - button_width * 4, + urlbar_height, hwnd_, 0, hInstance, 0); + CHECK(edit_hwnd_); + + // Override the edit control's window procedure. + edit_wndproc_old_ = SetWndProcPtr(edit_hwnd_, EditWndProc); + + // Associate |this| with the edit window. + SetUserDataPtr(edit_hwnd_, this); + + rect.top += urlbar_height; + + if (!with_osr_) { + // Remove the menu items that are only used with OSR. + HMENU hMenu = ::GetMenu(hwnd_); + if (hMenu) { + HMENU hTestMenu = ::GetSubMenu(hMenu, 2); + if (hTestMenu) { + ::RemoveMenu(hTestMenu, ID_TESTS_OSR_FPS, MF_BYCOMMAND); + ::RemoveMenu(hTestMenu, ID_TESTS_OSR_DSF, MF_BYCOMMAND); + } + } + } + } else { + // No controls so also remove the default menu. + ::SetMenu(hwnd_, NULL); + } + + const int device_scale_factor = GetWindowScaleFactor(hwnd_); + + if (with_osr_) { + browser_window_->SetDeviceScaleFactor(device_scale_factor); + } + + if (!is_popup_) { + // 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 { + // With popups we already have a browser window. Parent the browser window + // to the root window and show it in the correct location. + browser_window_->ShowPopup(hwnd_, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top); + } +} + bool RootWindowWin::OnClose() { if (browser_window_ && !browser_window_->IsClosing()) { CefRefPtr browser = GetBrowser(); @@ -915,9 +1043,9 @@ void RootWindowWin::OnAutoResize(const CefSize& new_size) { if (new_width < 200) new_width = 200; - RECT rect = { - 0, 0, LogicalToDevice(new_width, client::GetDeviceScaleFactor()), - LogicalToDevice(new_size.height, client::GetDeviceScaleFactor())}; + const int 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); DWORD ex_style = GetWindowLong(hwnd_, GWL_EXSTYLE); bool has_menu = !(style & WS_CHILD) && (GetMenu(hwnd_) != NULL); diff --git a/tests/cefclient/browser/root_window_win.h b/tests/cefclient/browser/root_window_win.h index 50e2e9b8b..f301da6d5 100644 --- a/tests/cefclient/browser/root_window_win.h +++ b/tests/cefclient/browser/root_window_win.h @@ -83,11 +83,14 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate { void OnActivate(bool active); void OnSize(bool minimized); void OnMove(); + void OnDpiChanged(WPARAM wParam, LPARAM lParam); bool OnEraseBkgnd(); bool OnCommand(UINT id); void OnFind(); void OnFindEvent(); void OnAbout(); + void OnNCCreate(LPCREATESTRUCT lpCreateStruct); + void OnCreate(LPCREATESTRUCT lpCreateStruct); bool OnClose(); void OnDestroyed(); @@ -114,6 +117,7 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate { bool is_popup_; RECT start_rect_; scoped_ptr browser_window_; + CefBrowserSettings browser_settings_; bool initialized_; // Main window. @@ -124,6 +128,7 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate { // Font for buttons and text fields. HFONT font_; + int font_height_; // Buttons. HWND back_hwnd_; @@ -150,6 +155,8 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate { bool window_destroyed_; bool browser_destroyed_; + bool called_enable_non_client_dpi_scaling_; + DISALLOW_COPY_AND_ASSIGN(RootWindowWin); }; diff --git a/tests/shared/browser/geometry_util.cc b/tests/shared/browser/geometry_util.cc index 206edbc80..cb40a4eba 100644 --- a/tests/shared/browser/geometry_util.cc +++ b/tests/shared/browser/geometry_util.cc @@ -25,6 +25,13 @@ 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 1f1e188a6..5384adfe8 100644 --- a/tests/shared/browser/geometry_util.h +++ b/tests/shared/browser/geometry_util.h @@ -16,6 +16,7 @@ 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