Windows: cefclient: Improve high-dpi display (issue #1674).

- Add high-dpi support to the OSR example.
- Apply DPI scaling to the buttons and URL bar.
This commit is contained in:
Marshall Greenblatt 2015-08-07 19:00:07 -04:00
parent 9e0d84d94a
commit 41669141eb
5 changed files with 174 additions and 36 deletions

View File

@ -443,6 +443,8 @@ void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
LONG currentTime = 0;
bool cancelPreviousClick = false;
const float device_scale_factor = GetDeviceScaleFactor();
if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN ||
message == WM_MBUTTONDOWN || message == WM_MOUSEMOVE ||
message == WM_MOUSELEAVE) {
@ -496,6 +498,7 @@ void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
mouse_event.y = y;
last_mouse_down_on_view_ = !IsOverPopupWidget(x, y);
ApplyPopupOffset(mouse_event.x, mouse_event.y);
DeviceToLogical(mouse_event, device_scale_factor);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser_host->SendMouseClickEvent(mouse_event, btnType, false,
last_click_count_);
@ -529,6 +532,7 @@ void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
break;
}
ApplyPopupOffset(mouse_event.x, mouse_event.y);
DeviceToLogical(mouse_event, device_scale_factor);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser_host->SendMouseClickEvent(mouse_event, btnType, true,
last_click_count_);
@ -566,6 +570,7 @@ void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
mouse_event.x = x;
mouse_event.y = y;
ApplyPopupOffset(mouse_event.x, mouse_event.y);
DeviceToLogical(mouse_event, device_scale_factor);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser_host->SendMouseMoveEvent(mouse_event, false);
}
@ -593,6 +598,7 @@ void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
CefMouseEvent mouse_event;
mouse_event.x = p.x;
mouse_event.y = p.y;
DeviceToLogical(mouse_event, device_scale_factor);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser_host->SendMouseMoveEvent(mouse_event, true);
}
@ -612,8 +618,8 @@ void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
mouse_event.x = screen_point.x;
mouse_event.y = screen_point.y;
ApplyPopupOffset(mouse_event.x, mouse_event.y);
DeviceToLogical(mouse_event, device_scale_factor);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser_host->SendMouseWheelEvent(mouse_event,
IsKeyDown(VK_SHIFT) ? delta : 0,
!IsKeyDown(VK_SHIFT) ? delta : 0);
@ -731,16 +737,6 @@ void OsrWindowWin::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
bool OsrWindowWin::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
RECT window_rect = {0};
HWND root_window = GetAncestor(hwnd_, GA_ROOT);
if (::GetWindowRect(root_window, &window_rect)) {
rect = CefRect(window_rect.left,
window_rect.top,
window_rect.right - window_rect.left,
window_rect.bottom - window_rect.top);
return true;
}
return false;
}
@ -748,9 +744,13 @@ bool OsrWindowWin::GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
rect.x = rect.y = 0;
rect.width = client_rect_.right - client_rect_.left;
rect.height = client_rect_.bottom - client_rect_.top;
const float device_scale_factor = GetDeviceScaleFactor();
rect.x = rect.y = 0;
rect.width = DeviceToLogical(client_rect_.right - client_rect_.left,
device_scale_factor);
rect.height = DeviceToLogical(client_rect_.bottom - client_rect_.top,
device_scale_factor);
return true;
}
@ -764,8 +764,13 @@ bool OsrWindowWin::GetScreenPoint(CefRefPtr<CefBrowser> browser,
if (!::IsWindow(hwnd_))
return false;
const float device_scale_factor = GetDeviceScaleFactor();
// Convert the point from view coordinates to actual screen coordinates.
POINT screen_pt = {viewX, viewY};
POINT screen_pt = {
LogicalToDevice(viewX, device_scale_factor),
LogicalToDevice(viewY, device_scale_factor)
};
ClientToScreen(hwnd_, &screen_pt);
screenX = screen_pt.x;
screenY = screen_pt.y;
@ -776,7 +781,19 @@ bool OsrWindowWin::GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) {
CEF_REQUIRE_UI_THREAD();
return false;
if (!::IsWindow(hwnd_))
return false;
CefRect view_rect;
GetViewRect(browser, view_rect);
screen_info.device_scale_factor = GetDeviceScaleFactor();
// The screen info rectangles are used by the renderer to create and position
// popups. Keep popups inside the view rectangle.
screen_info.rect = view_rect;
screen_info.available_rect = view_rect;
return true;
}
void OsrWindowWin::OnPopupShow(CefRefPtr<CefBrowser> browser,
@ -794,7 +811,7 @@ void OsrWindowWin::OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
renderer_.OnPopupSize(browser, rect);
renderer_.OnPopupSize(browser, LogicalToDevice(rect, GetDeviceScaleFactor()));
}
void OsrWindowWin::OnPaint(CefRefPtr<CefBrowser> browser,
@ -848,6 +865,7 @@ bool OsrWindowWin::StartDragging(
#if defined(CEF_USE_ATL)
if (!drop_target_)
return false;
current_drag_op_ = DRAG_OPERATION_NONE;
CefBrowserHost::DragOperationsMask result =
drop_target_->StartDragging(browser, drag_data, allowed_ops, x, y);
@ -855,7 +873,13 @@ bool OsrWindowWin::StartDragging(
POINT pt = {};
GetCursorPos(&pt);
ScreenToClient(hwnd_, &pt);
browser->GetHost()->DragSourceEndedAt(pt.x, pt.y, result);
const float device_scale_factor = GetDeviceScaleFactor();
browser->GetHost()->DragSourceEndedAt(
DeviceToLogical(pt.x, device_scale_factor),
DeviceToLogical(pt.y, device_scale_factor),
result);
browser->GetHost()->DragSourceSystemDragEnded();
return true;
#else
@ -881,6 +905,7 @@ OsrWindowWin::OnDragEnter(CefRefPtr<CefDragData> drag_data,
CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) {
if (browser_) {
DeviceToLogical(ev, GetDeviceScaleFactor());
browser_->GetHost()->DragTargetDragEnter(drag_data, ev, effect);
browser_->GetHost()->DragTargetDragOver(ev, effect);
}
@ -890,8 +915,10 @@ OsrWindowWin::OnDragEnter(CefRefPtr<CefDragData> drag_data,
CefBrowserHost::DragOperationsMask
OsrWindowWin::OnDragOver(CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) {
if (browser_)
if (browser_) {
DeviceToLogical(ev, GetDeviceScaleFactor());
browser_->GetHost()->DragTargetDragOver(ev, effect);
}
return current_drag_op_;
}
@ -904,6 +931,7 @@ CefBrowserHost::DragOperationsMask
OsrWindowWin::OnDrop(CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) {
if (browser_) {
DeviceToLogical(ev, GetDeviceScaleFactor());
browser_->GetHost()->DragTargetDragOver(ev, effect);
browser_->GetHost()->DragTargetDrop(ev);
}

View File

@ -43,6 +43,30 @@ INT_PTR CALLBACK AboutWndProc(HWND hDlg, UINT message,
return FALSE;
}
int GetButtonWidth() {
static int button_width = BUTTON_WIDTH;
static bool initialized = false;
if (!initialized) {
button_width = LogicalToDevice(BUTTON_WIDTH, GetDeviceScaleFactor());
initialized = true;
}
return button_width;
}
int GetURLBarHeight() {
static int urlbar_height = URLBAR_HEIGHT;
static bool initialized = false;
if (!initialized) {
urlbar_height = LogicalToDevice(URLBAR_HEIGHT, GetDeviceScaleFactor());
initialized = true;
}
return urlbar_height;
}
} // namespace
RootWindowWin::RootWindowWin()
@ -54,6 +78,7 @@ RootWindowWin::RootWindowWin()
initialized_(false),
hwnd_(NULL),
draggable_region_(NULL),
font_(NULL),
back_hwnd_(NULL),
forward_hwnd_(NULL),
reload_hwnd_(NULL),
@ -78,6 +103,7 @@ RootWindowWin::~RootWindowWin() {
REQUIRE_MAIN_THREAD();
::DeleteObject(draggable_region_);
::DeleteObject(font_);
// The window and browser should already have been destroyed.
DCHECK(window_destroyed_);
@ -254,7 +280,7 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings) {
RECT window_rect = start_rect_;
::AdjustWindowRectEx(&window_rect, dwStyle, with_controls_, 0);
if (with_controls_)
window_rect.bottom += URLBAR_HEIGHT;
window_rect.bottom += GetURLBarHeight();
x = start_rect_.left;
y = start_rect_.top;
@ -279,44 +305,61 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings) {
// Create the child controls.
int x = 0;
static int button_width = GetButtonWidth();
static int urlbar_height = GetURLBarHeight();
static int font_height = LogicalToDevice(14, 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, 0, BUTTON_WIDTH, URLBAR_HEIGHT,
x, 0, button_width, urlbar_height,
hwnd_, reinterpret_cast<HMENU>(IDC_NAV_BACK), hInstance, 0);
CHECK(back_hwnd_);
x += BUTTON_WIDTH;
SendMessage(back_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_), TRUE);
x += button_width;
forward_hwnd_ = CreateWindow(
L"BUTTON", L"Forward",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
x, 0, BUTTON_WIDTH, URLBAR_HEIGHT,
x, 0, button_width, urlbar_height,
hwnd_, reinterpret_cast<HMENU>(IDC_NAV_FORWARD), hInstance, 0);
CHECK(forward_hwnd_);
x += BUTTON_WIDTH;
SendMessage(forward_hwnd_, WM_SETFONT,
reinterpret_cast<WPARAM>(font_), TRUE);
x += button_width;
reload_hwnd_ = CreateWindow(
L"BUTTON", L"Reload",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON| WS_DISABLED,
x, 0, BUTTON_WIDTH, URLBAR_HEIGHT,
x, 0, button_width, urlbar_height,
hwnd_, reinterpret_cast<HMENU>(IDC_NAV_RELOAD), hInstance, 0);
CHECK(reload_hwnd_);
x += BUTTON_WIDTH;
SendMessage(reload_hwnd_, WM_SETFONT,
reinterpret_cast<WPARAM>(font_), TRUE);
x += button_width;
stop_hwnd_ = CreateWindow(
L"BUTTON", L"Stop",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
x, 0, BUTTON_WIDTH, URLBAR_HEIGHT,
x, 0, button_width, urlbar_height,
hwnd_, reinterpret_cast<HMENU>(IDC_NAV_STOP), hInstance, 0);
CHECK(stop_hwnd_);
x += BUTTON_WIDTH;
SendMessage(stop_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_), TRUE);
x += button_width;
edit_hwnd_ = CreateWindow(
L"EDIT", 0,
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL |
ES_AUTOHSCROLL| WS_DISABLED,
x, 0, rect.right - BUTTON_WIDTH * 4, URLBAR_HEIGHT,
x, 0, rect.right - button_width * 4, urlbar_height,
hwnd_, 0, hInstance, 0);
SendMessage(edit_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_), TRUE);
CHECK(edit_hwnd_);
// Override the edit control's window procedure.
@ -325,7 +368,7 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings) {
// Associate |this| with the edit window.
SetUserDataPtr(edit_hwnd_, this);
rect.top += URLBAR_HEIGHT;
rect.top += urlbar_height;
if (!with_osr_) {
// Remove the menu items that are only used with OSR.
@ -573,23 +616,26 @@ void RootWindowWin::OnSize(bool minimized) {
GetClientRect(hwnd_, &rect);
if (with_controls_) {
// Resize the window and address bar to match the new frame size.
rect.top += URLBAR_HEIGHT;
static int button_width = GetButtonWidth();
static int urlbar_height = GetURLBarHeight();
int urloffset = rect.left + BUTTON_WIDTH * 4;
// Resize the window and address bar to match the new frame size.
rect.top += urlbar_height;
int urloffset = rect.left + button_width * 4;
if (browser_window_) {
HWND browser_hwnd = browser_window_->GetWindowHandle();
HDWP hdwp = BeginDeferWindowPos(1);
hdwp = DeferWindowPos(hdwp, edit_hwnd_, NULL, urloffset,
0, rect.right - urloffset, URLBAR_HEIGHT, SWP_NOZORDER);
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);
EndDeferWindowPos(hdwp);
} else {
SetWindowPos(edit_hwnd_, NULL, urloffset,
0, rect.right - urloffset, URLBAR_HEIGHT, SWP_NOZORDER);
0, rect.right - urloffset, urlbar_height, SWP_NOZORDER);
}
} else if (browser_window_) {
// Size the browser window to the whole client area.

View File

@ -112,6 +112,9 @@ class RootWindowWin : public RootWindow,
// Draggable region.
HRGN draggable_region_;
// Font for buttons and text fields.
HFONT font_;
// Buttons.
HWND back_hwnd_;
HWND forward_hwnd_;

View File

@ -5,7 +5,6 @@
#include "cefclient/browser/util_win.h"
#include "include/base/cef_logging.h"
#include "include/internal/cef_types.h"
namespace client {
@ -140,4 +139,51 @@ bool IsKeyDown(WPARAM wparam) {
return (GetKeyState(wparam) & 0x8000) != 0;
}
float GetDeviceScaleFactor() {
static float scale_factor = 1.0;
static bool initialized = false;
if (!initialized) {
// This value is safe to cache for the life time of the app since the user
// must logout to change the DPI setting. This value also applies to all
// screens.
HDC screen_dc = ::GetDC(NULL);
int dpi_x = GetDeviceCaps(screen_dc, LOGPIXELSX);
scale_factor = static_cast<float>(dpi_x) / 96.0f;
::ReleaseDC(NULL, screen_dc);
initialized = true;
}
return scale_factor;
}
int LogicalToDevice(int value, float device_scale_factor) {
float scaled_val = static_cast<float>(value) * device_scale_factor;
return static_cast<int>(std::floor(scaled_val));
}
CefRect LogicalToDevice(const CefRect& value, float device_scale_factor) {
return CefRect(LogicalToDevice(value.x, device_scale_factor),
LogicalToDevice(value.y, device_scale_factor),
LogicalToDevice(value.width, device_scale_factor),
LogicalToDevice(value.height, device_scale_factor));
}
int DeviceToLogical(int value, float device_scale_factor) {
float scaled_val = static_cast<float>(value) / device_scale_factor;
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) {
value.x = DeviceToLogical(value.x, device_scale_factor);
value.y = DeviceToLogical(value.y, device_scale_factor);
}
} // namespace client

View File

@ -9,6 +9,8 @@
#include <windows.h>
#include <string>
#include "include/internal/cef_types_wrappers.h"
namespace client {
// Set the window's user data pointer.
@ -30,6 +32,19 @@ int GetCefMouseModifiers(WPARAM wparam);
int GetCefKeyboardModifiers(WPARAM wparam, LPARAM lparam);
bool IsKeyDown(WPARAM wparam);
// Returns the device scale factor. For example, 200% display scaling will
// return 2.0.
float GetDeviceScaleFactor();
// Convert |value| from logical coordinates to device coordinates.
int LogicalToDevice(int value, float device_scale_factor);
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
#endif // CEF_TESTS_CEFCLIENT_BROWSER_UTIL_WIN_H_