From 9e0d84d94af8acc5b7af0ee13218c2ed9ba4a021 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Fri, 7 Aug 2015 16:04:03 -0400 Subject: [PATCH] Windows: Add CefEnableHighDPISupport function and fix high-dpi scaling issues (issue #1674) --- include/capi/cef_app_capi.h | 7 +++ include/cef_app.h | 8 +++ libcef/browser/browser_host_impl_win.cc | 9 ++- libcef/browser/menu_creator_runner_win.cc | 7 +++ libcef/common/base_impl.cc | 72 ++++++++++++++++++++++- libcef_dll/libcef_dll.cc | 7 +++ libcef_dll/wrapper/libcef_dll_wrapper.cc | 7 +++ tests/cefclient/cefclient_win.cc | 3 + tests/cefsimple/cefsimple_win.cc | 3 + 9 files changed, 119 insertions(+), 4 deletions(-) diff --git a/include/capi/cef_app_capi.h b/include/capi/cef_app_capi.h index 7d1a070da..16b132042 100644 --- a/include/capi/cef_app_capi.h +++ b/include/capi/cef_app_capi.h @@ -175,6 +175,13 @@ CEF_EXPORT void cef_quit_message_loop(); /// CEF_EXPORT void cef_set_osmodal_loop(int osModalLoop); +/// +// Call during process startup to enable High-DPI support on Windows 7 or newer. +// Older versions of Windows should be left DPI-unaware because they do not +// support DirectWrite and GDI fonts are kerned very badly. +/// +CEF_EXPORT void cef_enable_highdpi_support(); + #ifdef __cplusplus } #endif diff --git a/include/cef_app.h b/include/cef_app.h index bac622812..03f31f5c7 100644 --- a/include/cef_app.h +++ b/include/cef_app.h @@ -124,6 +124,14 @@ void CefQuitMessageLoop(); /*--cef()--*/ void CefSetOSModalLoop(bool osModalLoop); +/// +// Call during process startup to enable High-DPI support on Windows 7 or newer. +// Older versions of Windows should be left DPI-unaware because they do not +// support DirectWrite and GDI fonts are kerned very badly. +/// +/*--cef(capi_name=cef_enable_highdpi_support)--*/ +void CefEnableHighDPISupport(); + /// // Implement this interface to provide handler implementations. Methods will be // called by the process and/or thread indicated. diff --git a/libcef/browser/browser_host_impl_win.cc b/libcef/browser/browser_host_impl_win.cc index 113a97d4c..1c77f188d 100644 --- a/libcef/browser/browser_host_impl_win.cc +++ b/libcef/browser/browser_host_impl_win.cc @@ -37,6 +37,7 @@ #include "ui/aura/window_tree_host.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/win/shell.h" +#include "ui/gfx/screen.h" #include "ui/gfx/win/hwnd_util.h" #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h" #include "ui/views/widget/widget.h" @@ -809,11 +810,17 @@ bool CefBrowserHostImpl::PlatformCreateWindow() { CefColorGetB(settings.background_color)); } + // Adjust for potential display scaling. + gfx::Point point = gfx::Point(cr.right, cr.bottom); + float scale = gfx::Screen::GetNativeScreen()-> + GetDisplayNearestPoint(point).device_scale_factor(); + point = gfx::ToFlooredPoint(gfx::ScalePoint(point, 1.0f / scale)); + CefWindowDelegateView* delegate_view = new CefWindowDelegateView(background_color); delegate_view->Init(window_info_.window, web_contents(), - gfx::Rect(0, 0, cr.right, cr.bottom)); + gfx::Rect(0, 0, point.x(), point.y())); window_widget_ = delegate_view->GetWidget(); window_widget_->Show(); diff --git a/libcef/browser/menu_creator_runner_win.cc b/libcef/browser/menu_creator_runner_win.cc index 5ad234bc6..6cb999642 100644 --- a/libcef/browser/menu_creator_runner_win.cc +++ b/libcef/browser/menu_creator_runner_win.cc @@ -8,6 +8,8 @@ #include "base/message_loop/message_loop.h" #include "ui/aura/window.h" #include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/point_conversions.h" +#include "ui/gfx/screen.h" #include "ui/views/controls/menu/menu_2.h" CefMenuCreatorRunnerWin::CefMenuCreatorRunnerWin() { @@ -46,6 +48,11 @@ bool CefMenuCreatorRunnerWin::RunContextMenu(CefMenuCreator* manager) { const gfx::Rect& bounds_in_screen = window->GetBoundsInScreen(); screen_point = gfx::Point(bounds_in_screen.x() + manager->params().x, bounds_in_screen.y() + manager->params().y); + + // Adjust for potential display scaling. + float scale = gfx::Screen::GetScreenFor(window)-> + GetDisplayNearestWindow(window).device_scale_factor(); + screen_point = gfx::ToFlooredPoint(gfx::ScalePoint(screen_point, scale)); } // Show the menu. Blocks until the menu is dismissed. diff --git a/libcef/common/base_impl.cc b/libcef/common/base_impl.cc index d3fd4900a..f3b3e6cbb 100644 --- a/libcef/common/base_impl.cc +++ b/libcef/common/base_impl.cc @@ -1,6 +1,13 @@ -// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights -// reserved. Use of this source code is governed by a BSD-style license that can -// be found in the LICENSE file. +// Copyright 2014 The Chromium Embedded Framework Authors. Portions copyright +// 2011 the Chromium 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 "include/base/cef_build.h" + +#if defined(OS_WIN) +#include +#include +#endif #include "include/internal/cef_trace_event_internal.h" #include "include/internal/cef_logging_internal.h" @@ -10,6 +17,55 @@ #include "base/threading/platform_thread.h" #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) + // 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 // linker stage if we don't call a stub function. @@ -343,3 +399,13 @@ CEF_EXPORT cef_platform_thread_handle_t return base::PlatformThread::CurrentHandle().platform_handle(); #endif } + +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(); +#endif +} diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index f06ed8e12..852591ad2 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -311,6 +311,13 @@ CEF_EXPORT void cef_set_osmodal_loop(int osModalLoop) { osModalLoop?true:false); } +CEF_EXPORT void cef_enable_highdpi_support() { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + CefEnableHighDPISupport(); +} + CEF_EXPORT int cef_get_geolocation( struct _cef_get_geolocation_callback_t* callback) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index ed43e9ead..c2dfb6ccf 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -303,6 +303,13 @@ CEF_GLOBAL void CefSetOSModalLoop(bool osModalLoop) { osModalLoop); } +CEF_GLOBAL void CefEnableHighDPISupport() { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_enable_highdpi_support(); +} + CEF_GLOBAL bool CefGetGeolocation( CefRefPtr callback) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING diff --git a/tests/cefclient/cefclient_win.cc b/tests/cefclient/cefclient_win.cc index d0c7666ec..f2cabe551 100644 --- a/tests/cefclient/cefclient_win.cc +++ b/tests/cefclient/cefclient_win.cc @@ -32,6 +32,9 @@ namespace client { namespace { int RunMain(HINSTANCE hInstance, int nCmdShow) { + // Enable High-DPI support on Windows 7 or newer. + CefEnableHighDPISupport(); + CefMainArgs main_args(hInstance); void* sandbox_info = NULL; diff --git a/tests/cefsimple/cefsimple_win.cc b/tests/cefsimple/cefsimple_win.cc index 84a082a90..8b2356ae7 100644 --- a/tests/cefsimple/cefsimple_win.cc +++ b/tests/cefsimple/cefsimple_win.cc @@ -29,6 +29,9 @@ int APIENTRY wWinMain(HINSTANCE hInstance, UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); + // Enable High-DPI support on Windows 7 or newer. + CefEnableHighDPISupport(); + void* sandbox_info = NULL; #if defined(CEF_USE_SANDBOX)