mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Windows: Improvements to off-screen rendering support (issue #518).
- Implement support for transparency. Change the backing store to use Skia instead of GDI and to keep alpha values. - Implement support for select popups. Requires a patch to Chromium (content_popups.patch). - Implicitly disable accelerated compositing when using off-screen rendering. - Introduce a new CefMouseEvent structure for representing mouse event information passed to CefBrowser methods. - Merge cef_key_event_modifiers_t into cef_event_flags_t. - Add a new argument to CefBrowser::Invalidate telling the browser whether to invalidate the select popup or the main view. - Add a new cefclient "transparent-painting-enabled" command-line flag to test transparent off-screen rendering. - Add a new cefclient "Transparency" test. - Fix the cefclient off-screen rendering rotation effect to work even when the underlying web content is not updating. - Add unit tests for transparent painting and select popups. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@979 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
@ -3,6 +3,10 @@
|
||||
// can be found in the LICENSE file.
|
||||
|
||||
#include "cefclient/cefclient_osr_widget_win.h"
|
||||
|
||||
#include <windowsx.h>
|
||||
|
||||
#include "include/cef_runnable.h"
|
||||
#include "cefclient/resource.h"
|
||||
#include "cefclient/util.h"
|
||||
|
||||
@ -108,11 +112,23 @@ void OSRWindow::OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
const RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width, int height) {
|
||||
if (painting_popup_) {
|
||||
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
|
||||
return;
|
||||
}
|
||||
if (!hDC_)
|
||||
EnableGL();
|
||||
|
||||
wglMakeCurrent(hDC_, hRC_);
|
||||
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
|
||||
if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) {
|
||||
painting_popup_ = true;
|
||||
CefRect client_popup_rect(0, 0,
|
||||
renderer_.popup_rect().width,
|
||||
renderer_.popup_rect().height);
|
||||
browser->GetHost()->Invalidate(client_popup_rect, PET_POPUP);
|
||||
painting_popup_ = false;
|
||||
}
|
||||
renderer_.Render();
|
||||
SwapBuffers(hDC_);
|
||||
}
|
||||
@ -128,18 +144,51 @@ void OSRWindow::OnCursorChange(CefRefPtr<CefBrowser> browser,
|
||||
SetCursor(cursor);
|
||||
}
|
||||
|
||||
void OSRWindow::Invalidate() {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI, NewCefRunnableMethod(this, &OSRWindow::Invalidate));
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't post another task if the previous task is still pending.
|
||||
if (render_task_pending_)
|
||||
return;
|
||||
|
||||
render_task_pending_ = true;
|
||||
|
||||
// Render at 30fps.
|
||||
static const int kRenderDelay = 1 / 30;
|
||||
CefPostDelayedTask(TID_UI, NewCefRunnableMethod(this, &OSRWindow::Render),
|
||||
kRenderDelay);
|
||||
}
|
||||
|
||||
OSRWindow::OSRWindow(OSRBrowserProvider* browser_provider, bool transparent)
|
||||
: renderer_(transparent),
|
||||
browser_provider_(browser_provider),
|
||||
hWnd_(NULL),
|
||||
hDC_(NULL),
|
||||
hRC_(NULL) {
|
||||
hRC_(NULL),
|
||||
painting_popup_(false),
|
||||
render_task_pending_(false) {
|
||||
}
|
||||
|
||||
OSRWindow::~OSRWindow() {
|
||||
DestroyWidget();
|
||||
}
|
||||
|
||||
void OSRWindow::Render() {
|
||||
ASSERT(CefCurrentlyOn(TID_UI));
|
||||
if (render_task_pending_)
|
||||
render_task_pending_ = false;
|
||||
|
||||
if (!hDC_)
|
||||
EnableGL();
|
||||
|
||||
wglMakeCurrent(hDC_, hRC_);
|
||||
renderer_.Render();
|
||||
SwapBuffers(hDC_);
|
||||
}
|
||||
|
||||
void OSRWindow::EnableGL() {
|
||||
ASSERT(CefCurrentlyOn(TID_UI));
|
||||
|
||||
@ -210,6 +259,136 @@ ATOM OSRWindow::RegisterOSRClass(HINSTANCE hInstance, LPCTSTR className) {
|
||||
return RegisterClassEx(&wcex);
|
||||
}
|
||||
|
||||
bool OSRWindow::isKeyDown(WPARAM wparam) {
|
||||
return (GetKeyState(wparam) & 0x8000) != 0;
|
||||
}
|
||||
|
||||
int OSRWindow::GetCefMouseModifiers(WPARAM wparam) {
|
||||
int modifiers = 0;
|
||||
if (wparam & MK_CONTROL)
|
||||
modifiers |= EVENTFLAG_CONTROL_DOWN;
|
||||
if (wparam & MK_SHIFT)
|
||||
modifiers |= EVENTFLAG_SHIFT_DOWN;
|
||||
if (isKeyDown(VK_MENU))
|
||||
modifiers |= EVENTFLAG_ALT_DOWN;
|
||||
if (wparam & MK_LBUTTON)
|
||||
modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
|
||||
if (wparam & MK_MBUTTON)
|
||||
modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
|
||||
if (wparam & MK_RBUTTON)
|
||||
modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
|
||||
|
||||
// Low bit set from GetKeyState indicates "toggled".
|
||||
if (::GetKeyState(VK_NUMLOCK) & 1)
|
||||
modifiers |= EVENTFLAG_NUM_LOCK_ON;
|
||||
if (::GetKeyState(VK_CAPITAL) & 1)
|
||||
modifiers |= EVENTFLAG_CAPS_LOCK_ON;
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
int OSRWindow::GetCefKeyboardModifiers(WPARAM wparam, LPARAM lparam) {
|
||||
int modifiers = 0;
|
||||
if (isKeyDown(VK_SHIFT))
|
||||
modifiers |= EVENTFLAG_SHIFT_DOWN;
|
||||
if (isKeyDown(VK_CONTROL))
|
||||
modifiers |= EVENTFLAG_CONTROL_DOWN;
|
||||
if (isKeyDown(VK_MENU))
|
||||
modifiers |= EVENTFLAG_ALT_DOWN;
|
||||
|
||||
// Low bit set from GetKeyState indicates "toggled".
|
||||
if (::GetKeyState(VK_NUMLOCK) & 1)
|
||||
modifiers |= EVENTFLAG_NUM_LOCK_ON;
|
||||
if (::GetKeyState(VK_CAPITAL) & 1)
|
||||
modifiers |= EVENTFLAG_CAPS_LOCK_ON;
|
||||
|
||||
switch (wparam) {
|
||||
case VK_RETURN:
|
||||
if ((lparam >> 16) & KF_EXTENDED)
|
||||
modifiers |= EVENTFLAG_IS_KEY_PAD;
|
||||
break;
|
||||
case VK_INSERT:
|
||||
case VK_DELETE:
|
||||
case VK_HOME:
|
||||
case VK_END:
|
||||
case VK_PRIOR:
|
||||
case VK_NEXT:
|
||||
case VK_UP:
|
||||
case VK_DOWN:
|
||||
case VK_LEFT:
|
||||
case VK_RIGHT:
|
||||
if (!((lparam >> 16) & KF_EXTENDED))
|
||||
modifiers |= EVENTFLAG_IS_KEY_PAD;
|
||||
break;
|
||||
case VK_NUMLOCK:
|
||||
case VK_NUMPAD0:
|
||||
case VK_NUMPAD1:
|
||||
case VK_NUMPAD2:
|
||||
case VK_NUMPAD3:
|
||||
case VK_NUMPAD4:
|
||||
case VK_NUMPAD5:
|
||||
case VK_NUMPAD6:
|
||||
case VK_NUMPAD7:
|
||||
case VK_NUMPAD8:
|
||||
case VK_NUMPAD9:
|
||||
case VK_DIVIDE:
|
||||
case VK_MULTIPLY:
|
||||
case VK_SUBTRACT:
|
||||
case VK_ADD:
|
||||
case VK_DECIMAL:
|
||||
case VK_CLEAR:
|
||||
modifiers |= EVENTFLAG_IS_KEY_PAD;
|
||||
break;
|
||||
case VK_SHIFT:
|
||||
if (isKeyDown(VK_LSHIFT))
|
||||
modifiers |= EVENTFLAG_IS_LEFT;
|
||||
else if (isKeyDown(VK_RSHIFT))
|
||||
modifiers |= EVENTFLAG_IS_RIGHT;
|
||||
break;
|
||||
case VK_CONTROL:
|
||||
if (isKeyDown(VK_LCONTROL))
|
||||
modifiers |= EVENTFLAG_IS_LEFT;
|
||||
else if (isKeyDown(VK_RCONTROL))
|
||||
modifiers |= EVENTFLAG_IS_RIGHT;
|
||||
break;
|
||||
case VK_MENU:
|
||||
if (isKeyDown(VK_LMENU))
|
||||
modifiers |= EVENTFLAG_IS_LEFT;
|
||||
else if (isKeyDown(VK_RMENU))
|
||||
modifiers |= EVENTFLAG_IS_RIGHT;
|
||||
break;
|
||||
case VK_LWIN:
|
||||
modifiers |= EVENTFLAG_IS_LEFT;
|
||||
break;
|
||||
case VK_RWIN:
|
||||
modifiers |= EVENTFLAG_IS_RIGHT;
|
||||
break;
|
||||
}
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
bool OSRWindow::IsOverPopupWidget(int x, int y) const {
|
||||
const CefRect& rc = renderer_.popup_rect();
|
||||
int popup_right = rc.x + rc.width;
|
||||
int popup_bottom = rc.y + rc.height;
|
||||
return (x >= rc.x) && (x < popup_right) &&
|
||||
(y >= rc.y) && (y < popup_bottom);
|
||||
}
|
||||
|
||||
int OSRWindow::GetPopupXOffset() const {
|
||||
return renderer_.original_popup_rect().x - renderer_.popup_rect().x;
|
||||
}
|
||||
|
||||
int OSRWindow::GetPopupYOffset() const {
|
||||
return renderer_.original_popup_rect().y - renderer_.popup_rect().y;
|
||||
}
|
||||
|
||||
void OSRWindow::ApplyPopupOffset(int& x, int& y) const {
|
||||
if (IsOverPopupWidget(x, y)) {
|
||||
x += GetPopupXOffset();
|
||||
y += GetPopupYOffset();
|
||||
}
|
||||
}
|
||||
|
||||
// Plugin window procedure.
|
||||
// static
|
||||
LRESULT CALLBACK OSRWindow::WndProc(HWND hWnd, UINT message,
|
||||
@ -218,12 +397,42 @@ LRESULT CALLBACK OSRWindow::WndProc(HWND hWnd, UINT message,
|
||||
static bool mouseRotation = false;
|
||||
static bool mouseTracking = false;
|
||||
|
||||
static int lastClickX = 0;
|
||||
static int lastClickY = 0;
|
||||
static CefBrowserHost::MouseButtonType lastClickButton = MBT_LEFT;
|
||||
static int gLastClickCount = 0;
|
||||
static double gLastClickTime = 0;
|
||||
|
||||
static bool gLastMouseDownOnView = false;
|
||||
|
||||
OSRWindow* window =
|
||||
reinterpret_cast<OSRWindow*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
||||
CefRefPtr<CefBrowserHost> browser;
|
||||
if (window && window->browser_provider_->GetBrowser().get())
|
||||
browser = window->browser_provider_->GetBrowser()->GetHost();
|
||||
|
||||
LONG currentTime = 0;
|
||||
bool cancelPreviousClick = false;
|
||||
|
||||
if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN ||
|
||||
message == WM_MBUTTONDOWN || message == WM_MOUSEMOVE ||
|
||||
message == WM_MOUSELEAVE) {
|
||||
currentTime = GetMessageTime();
|
||||
int x = GET_X_LPARAM(lParam);
|
||||
int y = GET_Y_LPARAM(lParam);
|
||||
cancelPreviousClick =
|
||||
(abs(lastClickX - x) > (GetSystemMetrics(SM_CXDOUBLECLK) / 2))
|
||||
|| (abs(lastClickY - y) > (GetSystemMetrics(SM_CYDOUBLECLK) / 2))
|
||||
|| ((currentTime - gLastClickTime) > GetDoubleClickTime());
|
||||
if (cancelPreviousClick &&
|
||||
(message == WM_MOUSEMOVE || message == WM_MOUSELEAVE)) {
|
||||
gLastClickCount = 0;
|
||||
lastClickX = 0;
|
||||
lastClickY = 0;
|
||||
gLastClickTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (message) {
|
||||
case WM_DESTROY:
|
||||
if (window)
|
||||
@ -232,46 +441,89 @@ LRESULT CALLBACK OSRWindow::WndProc(HWND hWnd, UINT message,
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_MBUTTONDOWN: {
|
||||
SetCapture(hWnd);
|
||||
SetFocus(hWnd);
|
||||
int x = GET_X_LPARAM(lParam);
|
||||
int y = GET_Y_LPARAM(lParam);
|
||||
if (wParam & MK_SHIFT) {
|
||||
// Start rotation effect.
|
||||
lastMousePos.x = curMousePos.x = LOWORD(lParam);
|
||||
lastMousePos.y = curMousePos.y = HIWORD(lParam);
|
||||
lastMousePos.x = curMousePos.x = x;
|
||||
lastMousePos.y = curMousePos.y = y;
|
||||
mouseRotation = true;
|
||||
} else {
|
||||
CefBrowserHost::MouseButtonType btnType =
|
||||
(message == WM_LBUTTONDOWN ? MBT_LEFT : (
|
||||
message == WM_RBUTTONDOWN ? MBT_RIGHT : MBT_MIDDLE));
|
||||
if (!cancelPreviousClick && (btnType == lastClickButton)) {
|
||||
++gLastClickCount;
|
||||
} else {
|
||||
gLastClickCount = 1;
|
||||
lastClickX = x;
|
||||
lastClickY = y;
|
||||
}
|
||||
gLastClickTime = currentTime;
|
||||
lastClickButton = btnType;
|
||||
|
||||
if (browser.get()) {
|
||||
browser->SendMouseClickEvent(LOWORD(lParam), HIWORD(lParam),
|
||||
(message == WM_LBUTTONDOWN?MBT_LEFT:MBT_RIGHT), false, 1);
|
||||
CefMouseEvent mouse_event;
|
||||
mouse_event.x = x;
|
||||
mouse_event.y = y;
|
||||
gLastMouseDownOnView = !window->IsOverPopupWidget(x, y);
|
||||
window->ApplyPopupOffset(mouse_event.x, mouse_event.y);
|
||||
mouse_event.modifiers = GetCefMouseModifiers(wParam);
|
||||
browser->SendMouseClickEvent(mouse_event, btnType, false,
|
||||
gLastClickCount);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONUP:
|
||||
if (GetCapture() == hWnd)
|
||||
ReleaseCapture();
|
||||
if (mouseRotation) {
|
||||
// End rotation effect.
|
||||
mouseRotation = false;
|
||||
window->renderer_.SetSpin(0, 0);
|
||||
window->Invalidate();
|
||||
} else {
|
||||
int x = GET_X_LPARAM(lParam);
|
||||
int y = GET_Y_LPARAM(lParam);
|
||||
CefBrowserHost::MouseButtonType btnType =
|
||||
(message == WM_LBUTTONDOWN ? MBT_LEFT : (
|
||||
message == WM_RBUTTONDOWN ? MBT_RIGHT : MBT_MIDDLE));
|
||||
if (browser.get()) {
|
||||
browser->SendMouseClickEvent(LOWORD(lParam), HIWORD(lParam),
|
||||
(message == WM_LBUTTONUP?MBT_LEFT:MBT_RIGHT), true, 1);
|
||||
CefMouseEvent mouse_event;
|
||||
mouse_event.x = x;
|
||||
mouse_event.y = y;
|
||||
if (gLastMouseDownOnView &&
|
||||
window->IsOverPopupWidget(x, y) &&
|
||||
(window->GetPopupXOffset() || window->GetPopupYOffset())) {
|
||||
break;
|
||||
}
|
||||
window->ApplyPopupOffset(mouse_event.x, mouse_event.y);
|
||||
mouse_event.modifiers = GetCefMouseModifiers(wParam);
|
||||
browser->SendMouseClickEvent(mouse_event, btnType, true,
|
||||
gLastClickCount);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
case WM_MOUSEMOVE: {
|
||||
int x = GET_X_LPARAM(lParam);
|
||||
int y = GET_Y_LPARAM(lParam);
|
||||
if (mouseRotation) {
|
||||
// Apply rotation effect.
|
||||
curMousePos.x = LOWORD(lParam);
|
||||
curMousePos.y = HIWORD(lParam);
|
||||
curMousePos.x = x;
|
||||
curMousePos.y = y;
|
||||
window->renderer_.IncrementSpin((curMousePos.x - lastMousePos.x),
|
||||
(curMousePos.y - lastMousePos.y));
|
||||
lastMousePos.x = curMousePos.x;
|
||||
lastMousePos.y = curMousePos.y;
|
||||
window->Invalidate();
|
||||
} else {
|
||||
if (!mouseTracking) {
|
||||
// Start tracking mouse leave. Required for the WM_MOUSELEAVE event to
|
||||
@ -284,10 +536,16 @@ LRESULT CALLBACK OSRWindow::WndProc(HWND hWnd, UINT message,
|
||||
mouseTracking = true;
|
||||
}
|
||||
if (browser.get()) {
|
||||
browser->SendMouseMoveEvent(LOWORD(lParam), HIWORD(lParam), false);
|
||||
CefMouseEvent mouse_event;
|
||||
mouse_event.x = x;
|
||||
mouse_event.y = y;
|
||||
window->ApplyPopupOffset(mouse_event.x, mouse_event.y);
|
||||
mouse_event.modifiers = GetCefMouseModifiers(wParam);
|
||||
browser->SendMouseMoveEvent(mouse_event, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_MOUSELEAVE:
|
||||
if (mouseTracking) {
|
||||
@ -299,14 +557,34 @@ LRESULT CALLBACK OSRWindow::WndProc(HWND hWnd, UINT message,
|
||||
TrackMouseEvent(&tme);
|
||||
mouseTracking = false;
|
||||
}
|
||||
if (browser.get())
|
||||
browser->SendMouseMoveEvent(0, 0, true);
|
||||
if (browser.get()) {
|
||||
CefMouseEvent mouse_event;
|
||||
mouse_event.x = 0;
|
||||
mouse_event.y = 0;
|
||||
mouse_event.modifiers = GetCefMouseModifiers(wParam);
|
||||
browser->SendMouseMoveEvent(mouse_event, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_MOUSEWHEEL:
|
||||
if (browser.get()) {
|
||||
browser->SendMouseWheelEvent(LOWORD(lParam), HIWORD(lParam),
|
||||
0, GET_WHEEL_DELTA_WPARAM(wParam));
|
||||
POINT screen_point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
||||
HWND scrolled_wnd = ::WindowFromPoint(screen_point);
|
||||
if (scrolled_wnd != hWnd) {
|
||||
break;
|
||||
}
|
||||
ScreenToClient(hWnd, &screen_point);
|
||||
int delta = GET_WHEEL_DELTA_WPARAM(wParam);
|
||||
|
||||
CefMouseEvent mouse_event;
|
||||
mouse_event.x = screen_point.x;
|
||||
mouse_event.y = screen_point.y;
|
||||
window->ApplyPopupOffset(mouse_event.x, mouse_event.y);
|
||||
mouse_event.modifiers = GetCefMouseModifiers(wParam);
|
||||
|
||||
browser->SendMouseWheelEvent(mouse_event,
|
||||
isKeyDown(VK_SHIFT) ? delta : 0,
|
||||
!isKeyDown(VK_SHIFT) ? delta : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -347,7 +625,7 @@ LRESULT CALLBACK OSRWindow::WndProc(HWND hWnd, UINT message,
|
||||
event.type = KEYEVENT_KEYUP;
|
||||
else
|
||||
event.type = KEYEVENT_CHAR;
|
||||
|
||||
event.modifiers = GetCefKeyboardModifiers(wParam, lParam);
|
||||
if (browser.get())
|
||||
browser->SendKeyEvent(event);
|
||||
break;
|
||||
@ -363,7 +641,7 @@ LRESULT CALLBACK OSRWindow::WndProc(HWND hWnd, UINT message,
|
||||
browser->Invalidate(CefRect(rc.left,
|
||||
rc.top,
|
||||
rc.right - rc.left,
|
||||
rc.bottom - rc.top));
|
||||
rc.bottom - rc.top), PET_VIEW);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user