Commit b45b7718 authored by yzshen@chromium.org's avatar yzshen@chromium.org

Fix mouse lock perf issue on Windows.

Don't move the cursor back to the center of the view unless it approaches the border.

BUG=106054
TEST=None


Review URL: http://codereview.chromium.org/8791001

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113061 0039d316-1c4b-4281-b951-d872f2087c98
parent ae1c2f0e
...@@ -88,8 +88,17 @@ const int kIdCustom = 1; ...@@ -88,8 +88,17 @@ const int kIdCustom = 1;
// process a grace period to stop referencing it. // process a grace period to stop referencing it.
const int kDestroyCompositorHostWindowDelay = 10000; const int kDestroyCompositorHostWindowDelay = 10000;
// In mouse lock mode, we need to prevent the (invisible) cursor from hitting
// the border of the view, in order to get valid movement information. However,
// forcing the cursor back to the center of the view after each mouse move
// doesn't work well. It reduces the frequency of useful WM_MOUSEMOVE messages
// significantly. Therefore, we move the cursor to the center of the view only
// if it approaches the border. |kMouseLockBorderPercentage| specifies the width
// of the border area, in percentage of the corresponding dimension.
const int kMouseLockBorderPercentage = 15;
// A callback function for EnumThreadWindows to enumerate and dismiss // A callback function for EnumThreadWindows to enumerate and dismiss
// any owned popop windows // any owned popup windows.
BOOL CALLBACK DismissOwnedPopups(HWND window, LPARAM arg) { BOOL CALLBACK DismissOwnedPopups(HWND window, LPARAM arg) {
const HWND toplevel_hwnd = reinterpret_cast<HWND>(arg); const HWND toplevel_hwnd = reinterpret_cast<HWND>(arg);
...@@ -1358,7 +1367,7 @@ LRESULT RenderWidgetHostViewWin::OnMouseEvent(UINT message, WPARAM wparam, ...@@ -1358,7 +1367,7 @@ LRESULT RenderWidgetHostViewWin::OnMouseEvent(UINT message, WPARAM wparam,
if (mouse_locked_) { if (mouse_locked_) {
HandleLockedMouseEvent(message, wparam, lparam); HandleLockedMouseEvent(message, wparam, lparam);
MoveCursorToCenter(); MoveCursorToCenterIfNecessary();
return 0; return 0;
} }
...@@ -1846,12 +1855,13 @@ bool RenderWidgetHostViewWin::LockMouse() { ...@@ -1846,12 +1855,13 @@ bool RenderWidgetHostViewWin::LockMouse() {
::ShowWindow(tooltip_hwnd_, SW_HIDE); ::ShowWindow(tooltip_hwnd_, SW_HIDE);
} }
// TODO(yzshen): Show an invisible cursor instead of using // TODO(yzshen): ShowCursor(FALSE) causes SetCursorPos() to be ignored on
// ::ShowCursor(FALSE), so that MoveCursorToCenter() works with Remote // Remote Desktop.
// Desktop.
::ShowCursor(FALSE); ::ShowCursor(FALSE);
MoveCursorToCenter(); move_to_center_request_.pending = false;
last_mouse_position_.locked_global = last_mouse_position_.unlocked_global;
MoveCursorToCenterIfNecessary();
CRect rect; CRect rect;
GetWindowRect(&rect); GetWindowRect(&rect);
...@@ -1867,8 +1877,8 @@ void RenderWidgetHostViewWin::UnlockMouse() { ...@@ -1867,8 +1877,8 @@ void RenderWidgetHostViewWin::UnlockMouse() {
mouse_locked_ = false; mouse_locked_ = false;
::ClipCursor(NULL); ::ClipCursor(NULL);
::SetCursorPos(last_global_mouse_position_.x(), ::SetCursorPos(last_mouse_position_.unlocked_global.x(),
last_global_mouse_position_.y()); last_mouse_position_.unlocked_global.y());
::ShowCursor(TRUE); ::ShowCursor(TRUE);
if (render_widget_host_) if (render_widget_host_)
...@@ -2268,28 +2278,30 @@ void RenderWidgetHostViewWin::ForwardMouseEventToRenderer(UINT message, ...@@ -2268,28 +2278,30 @@ void RenderWidgetHostViewWin::ForwardMouseEventToRenderer(UINT message,
WebInputEventFactory::mouseEvent(m_hWnd, message, wparam, lparam)); WebInputEventFactory::mouseEvent(m_hWnd, message, wparam, lparam));
if (mouse_locked_) { if (mouse_locked_) {
CPoint center = GetClientCenter(); event.movementX = event.globalX - last_mouse_position_.locked_global.x();
event.movementY = event.globalY - last_mouse_position_.locked_global.y();
event.movementX = event.windowX - center.x; last_mouse_position_.locked_global.SetPoint(event.globalX, event.globalY);
event.movementY = event.windowY - center.y;
event.x = last_mouse_position_.x(); event.x = last_mouse_position_.unlocked.x();
event.y = last_mouse_position_.y(); event.y = last_mouse_position_.unlocked.y();
event.windowX = last_mouse_position_.x(); event.windowX = last_mouse_position_.unlocked.x();
event.windowY = last_mouse_position_.y(); event.windowY = last_mouse_position_.unlocked.y();
event.globalX = last_global_mouse_position_.x(); event.globalX = last_mouse_position_.unlocked_global.x();
event.globalY = last_global_mouse_position_.y(); event.globalY = last_mouse_position_.unlocked_global.y();
} else { } else {
if (ignore_mouse_movement_) { if (ignore_mouse_movement_) {
ignore_mouse_movement_ = false; ignore_mouse_movement_ = false;
event.movementX = 0; event.movementX = 0;
event.movementY = 0; event.movementY = 0;
} else { } else {
event.movementX = event.globalX - last_global_mouse_position_.x(); event.movementX =
event.movementY = event.globalY - last_global_mouse_position_.y(); event.globalX - last_mouse_position_.unlocked_global.x();
event.movementY =
event.globalY - last_mouse_position_.unlocked_global.y();
} }
last_mouse_position_.SetPoint(event.windowX, event.windowY); last_mouse_position_.unlocked.SetPoint(event.windowX, event.windowY);
last_global_mouse_position_.SetPoint(event.globalX, event.globalY); last_mouse_position_.unlocked_global.SetPoint(event.globalX, event.globalY);
} }
// Send the event to the renderer before changing mouse capture, so that the // Send the event to the renderer before changing mouse capture, so that the
...@@ -2347,11 +2359,28 @@ CPoint RenderWidgetHostViewWin::GetClientCenter() const { ...@@ -2347,11 +2359,28 @@ CPoint RenderWidgetHostViewWin::GetClientCenter() const {
return rect.CenterPoint(); return rect.CenterPoint();
} }
void RenderWidgetHostViewWin::MoveCursorToCenter() const { void RenderWidgetHostViewWin::MoveCursorToCenterIfNecessary() {
CPoint center = GetClientCenter(); DCHECK(mouse_locked_);
ClientToScreen(&center);
if (!::SetCursorPos(center.x, center.y)) CRect rect;
LOG_GETLASTERROR(WARNING) << "Failed to set cursor position."; GetWindowRect(&rect);
int border_x = rect.Width() * kMouseLockBorderPercentage / 100;
int border_y = rect.Height() * kMouseLockBorderPercentage / 100;
bool should_move =
last_mouse_position_.locked_global.x() < rect.left + border_x ||
last_mouse_position_.locked_global.x() > rect.right - border_x ||
last_mouse_position_.locked_global.y() < rect.top + border_y ||
last_mouse_position_.locked_global.y() > rect.bottom - border_y;
if (should_move) {
move_to_center_request_.pending = true;
move_to_center_request_.target = rect.CenterPoint();
if (!::SetCursorPos(move_to_center_request_.target.x(),
move_to_center_request_.target.y())) {
LOG_GETLASTERROR(WARNING) << "Failed to set cursor position.";
}
}
} }
void RenderWidgetHostViewWin::HandleLockedMouseEvent(UINT message, void RenderWidgetHostViewWin::HandleLockedMouseEvent(UINT message,
...@@ -2359,11 +2388,17 @@ void RenderWidgetHostViewWin::HandleLockedMouseEvent(UINT message, ...@@ -2359,11 +2388,17 @@ void RenderWidgetHostViewWin::HandleLockedMouseEvent(UINT message,
LPARAM lparam) { LPARAM lparam) {
DCHECK(mouse_locked_); DCHECK(mouse_locked_);
if (message == WM_MOUSEMOVE) { if (message == WM_MOUSEMOVE && move_to_center_request_.pending) {
CPoint center = GetClientCenter(); // Ignore WM_MOUSEMOVE messages generated by
// Ignore WM_MOUSEMOVE messages generated by MoveCursorToCenter(). // MoveCursorToCenterIfNecessary().
if (LOWORD(lparam) == center.x && HIWORD(lparam) == center.y) CPoint current_position(LOWORD(lparam), HIWORD(lparam));
ClientToScreen(&current_position);
if (move_to_center_request_.target.x() == current_position.x &&
move_to_center_request_.target.y() == current_position.y) {
move_to_center_request_.pending = false;
last_mouse_position_.locked_global = move_to_center_request_.target;
return; return;
}
} }
ForwardMouseEventToRenderer(message, wparam, lparam); ForwardMouseEventToRenderer(message, wparam, lparam);
......
...@@ -337,7 +337,9 @@ class RenderWidgetHostViewWin ...@@ -337,7 +337,9 @@ class RenderWidgetHostViewWin
DWORD ex_style); DWORD ex_style);
CPoint GetClientCenter() const; CPoint GetClientCenter() const;
void MoveCursorToCenter() const; // In mouse lock mode, moves the mouse cursor to the center of the view if it
// is too close to the border.
void MoveCursorToCenterIfNecessary();
void HandleLockedMouseEvent(UINT message, WPARAM wparam, LPARAM lparam); void HandleLockedMouseEvent(UINT message, WPARAM wparam, LPARAM lparam);
...@@ -477,12 +479,26 @@ class RenderWidgetHostViewWin ...@@ -477,12 +479,26 @@ class RenderWidgetHostViewWin
bool is_fullscreen_; bool is_fullscreen_;
// Used to record the last position of the mouse. // Used to record the last position of the mouse.
// While the mouse is locked, they store the last known position just as mouse struct {
// lock was entered. // While the mouse is locked, |unlocked| and |unlocked_global| store the
// Relative to the upper-left corner of the view. // last known position just as mouse lock was entered.
gfx::Point last_mouse_position_; // Relative to the upper-left corner of the view.
// Relative to the upper-left corner of the screen. gfx::Point unlocked;
gfx::Point last_global_mouse_position_; // Relative to the upper-left corner of the screen.
gfx::Point unlocked_global;
// Only valid while the mouse is locked.
gfx::Point locked_global;
} last_mouse_position_;
// When the mouse cursor is moved to the center of the view by
// MoveCursorToCenterIfNecessary(), we ignore the resulting WM_MOUSEMOVE
// message.
struct {
bool pending;
// Relative to the upper-left corner of the screen.
gfx::Point target;
} move_to_center_request_;
// In the case of the mouse being moved away from the view and then moved // In the case of the mouse being moved away from the view and then moved
// back, we regard the mouse movement as (0, 0). // back, we regard the mouse movement as (0, 0).
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment