summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/browser/renderer_host/render_widget_host.cc42
-rw-r--r--content/browser/renderer_host/render_widget_host.h8
-rw-r--r--content/browser/renderer_host/render_widget_host_view.cc9
-rw-r--r--content/browser/renderer_host/render_widget_host_view.h15
-rw-r--r--content/browser/renderer_host/render_widget_host_view_gtk.cc9
-rw-r--r--content/browser/renderer_host/render_widget_host_view_gtk.h2
-rw-r--r--content/browser/renderer_host/render_widget_host_view_win.cc127
-rw-r--r--content/browser/renderer_host/render_widget_host_view_win.h20
-rw-r--r--content/browser/renderer_host/test_render_view_host.cc7
-rw-r--r--content/browser/renderer_host/test_render_view_host.h3
-rw-r--r--content/common/view_messages.h22
-rw-r--r--content/renderer/pepper_plugin_delegate_impl.cc131
-rw-r--r--content/renderer/pepper_plugin_delegate_impl.h31
-rw-r--r--content/renderer/render_view.cc15
-rw-r--r--content/renderer/render_view.h4
-rw-r--r--content/renderer/render_widget.cc24
-rw-r--r--content/renderer/render_widget.h7
17 files changed, 457 insertions, 19 deletions
diff --git a/content/browser/renderer_host/render_widget_host.cc b/content/browser/renderer_host/render_widget_host.cc
index 77248cb..01077f7 100644
--- a/content/browser/renderer_host/render_widget_host.cc
+++ b/content/browser/renderer_host/render_widget_host.cc
@@ -199,6 +199,8 @@ bool RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) {
OnMsgImeCancelComposition)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidActivateAcceleratedCompositing,
OnMsgDidActivateAcceleratedCompositing)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_LockMouse, OnMsgLockMouse)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UnlockMouse, OnMsgUnlockMouse)
#if defined(OS_POSIX)
IPC_MESSAGE_HANDLER(ViewHostMsg_GetScreenInfo, OnMsgGetScreenInfo)
IPC_MESSAGE_HANDLER(ViewHostMsg_GetWindowRect, OnMsgGetWindowRect)
@@ -381,6 +383,9 @@ void RenderWidgetHost::Focus() {
}
void RenderWidgetHost::Blur() {
+ if (IsMouseLocked())
+ view_->UnlockMouse();
+
Send(new ViewMsg_SetFocus(routing_id_, false));
}
@@ -388,7 +393,14 @@ void RenderWidgetHost::LostCapture() {
Send(new ViewMsg_MouseCaptureLost(routing_id_));
}
+void RenderWidgetHost::LostMouseLock() {
+ Send(new ViewMsg_MouseLockLost(routing_id_));
+}
+
void RenderWidgetHost::ViewDestroyed() {
+ if (IsMouseLocked())
+ view_->UnlockMouse();
+
// TODO(evanm): tracking this may no longer be necessary;
// eliminate this function if so.
SetView(NULL);
@@ -527,7 +539,16 @@ void RenderWidgetHost::ForwardMouseEvent(const WebMouseEvent& mouse_event) {
// more WM_MOUSEMOVE events than we wish to send to the renderer.
if (mouse_event.type == WebInputEvent::MouseMove) {
if (mouse_move_pending_) {
- next_mouse_move_.reset(new WebMouseEvent(mouse_event));
+ if (!next_mouse_move_.get()) {
+ next_mouse_move_.reset(new WebMouseEvent(mouse_event));
+ } else {
+ // Accumulate movement deltas.
+ int x = next_mouse_move_->movementX;
+ int y = next_mouse_move_->movementY;
+ *next_mouse_move_ = mouse_event;
+ next_mouse_move_->movementX += x;
+ next_mouse_move_->movementY += y;
+ }
return;
}
mouse_move_pending_ = true;
@@ -780,6 +801,10 @@ void RenderWidgetHost::ImeCancelComposition() {
std::vector<WebKit::WebCompositionUnderline>(), 0, 0));
}
+bool RenderWidgetHost::IsMouseLocked() const {
+ return view_ ? view_->mouse_locked() : false;
+}
+
void RenderWidgetHost::Destroy() {
NotificationService::current()->Notify(
content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
@@ -1125,6 +1150,21 @@ void RenderWidgetHost::OnMsgDidActivateAcceleratedCompositing(bool activated) {
#endif
}
+void RenderWidgetHost::OnMsgLockMouse() {
+ // TODO(yzshen): Only allow to lock the mouse when in fullscreen mode, and
+ // make sure that the mouse is unlocked when leaving fullscreen mode.
+ if (!view_ || !view_->HasFocus() || !view_->LockMouse()) {
+ Send(new ViewMsg_LockMouse_ACK(routing_id_, false));
+ } else {
+ Send(new ViewMsg_LockMouse_ACK(routing_id_, true));
+ }
+}
+
+void RenderWidgetHost::OnMsgUnlockMouse() {
+ if (IsMouseLocked())
+ view_->UnlockMouse();
+}
+
#if defined(OS_POSIX)
void RenderWidgetHost::OnMsgGetScreenInfo(gfx::NativeViewId window_id,
WebKit::WebScreenInfo* results) {
diff --git a/content/browser/renderer_host/render_widget_host.h b/content/browser/renderer_host/render_widget_host.h
index 10463c2..9b6a14c 100644
--- a/content/browser/renderer_host/render_widget_host.h
+++ b/content/browser/renderer_host/render_widget_host.h
@@ -196,6 +196,9 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Channel::Listener,
void Blur();
virtual void LostCapture();
+ // Called to notify the RenderWidget that it has lost the mouse lock.
+ virtual void LostMouseLock();
+
// Tells us whether the page is rendered directly via the GPU process.
bool is_accelerated_compositing_active() {
return is_accelerated_compositing_active_;
@@ -465,6 +468,8 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Channel::Listener,
virtual void NotifyRendererUnresponsive() {}
virtual void NotifyRendererResponsive() {}
+ bool IsMouseLocked() const;
+
protected:
// true if a renderer has once been valid. We use this flag to display a sad
// tab only when we lose our renderer and not if a paint occurs during
@@ -511,6 +516,9 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Channel::Listener,
void OnMsgDidActivateAcceleratedCompositing(bool activated);
+ void OnMsgLockMouse();
+ void OnMsgUnlockMouse();
+
#if defined(OS_POSIX)
void OnMsgGetScreenInfo(gfx::NativeViewId view,
WebKit::WebScreenInfo* results);
diff --git a/content/browser/renderer_host/render_widget_host_view.cc b/content/browser/renderer_host/render_widget_host_view.cc
index ba714df..94f287c 100644
--- a/content/browser/renderer_host/render_widget_host_view.cc
+++ b/content/browser/renderer_host/render_widget_host_view.cc
@@ -4,6 +4,7 @@
#include "content/browser/renderer_host/render_widget_host_view.h"
+#include "base/logging.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h"
#if defined(OS_MACOSX)
@@ -39,7 +40,13 @@ void RenderWidgetHostView::GetDefaultScreenInfo(
}
#endif
-RenderWidgetHostView::~RenderWidgetHostView() {}
+RenderWidgetHostView::RenderWidgetHostView()
+ : popup_type_(WebKit::WebPopupTypeNone), mouse_locked_(false) {
+}
+
+RenderWidgetHostView::~RenderWidgetHostView() {
+ DCHECK(!mouse_locked_);
+}
void RenderWidgetHostView::SetBackground(const SkBitmap& background) {
background_ = background;
diff --git a/content/browser/renderer_host/render_widget_host_view.h b/content/browser/renderer_host/render_widget_host_view.h
index 3456a67..8859d2a 100644
--- a/content/browser/renderer_host/render_widget_host_view.h
+++ b/content/browser/renderer_host/render_widget_host_view.h
@@ -313,6 +313,10 @@ class RenderWidgetHostView {
virtual void SetScrollOffsetPinning(
bool is_pinned_to_left, bool is_pinned_to_right) = 0;
+ // Return value indicates whether the mouse is locked successfully or not.
+ virtual bool LockMouse() = 0;
+ virtual void UnlockMouse() = 0;
+
void set_popup_type(WebKit::WebPopupType popup_type) {
popup_type_ = popup_type;
}
@@ -334,9 +338,11 @@ class RenderWidgetHostView {
reserved_rect_ = reserved_rect;
}
+ bool mouse_locked() const { return mouse_locked_; }
+
protected:
// Interface class only, do not construct.
- RenderWidgetHostView() : popup_type_(WebKit::WebPopupTypeNone) {}
+ RenderWidgetHostView();
// Whether this view is a popup and what kind of popup it is (select,
// autofill...).
@@ -350,6 +356,13 @@ class RenderWidgetHostView {
// rendered to draw the resize corner, sidebar mini tabs etc.
gfx::Rect reserved_rect_;
+ // While the mouse is locked, the cursor is hidden from the user. Mouse events
+ // are still generated. However, the position they report is the last known
+ // mouse position just as mouse lock was entered; the movement they report
+ // indicates what the change in position of the mouse would be had it not been
+ // locked.
+ bool mouse_locked_;
+
private:
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostView);
};
diff --git a/content/browser/renderer_host/render_widget_host_view_gtk.cc b/content/browser/renderer_host/render_widget_host_view_gtk.cc
index d258aac..c92290c 100644
--- a/content/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/content/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -1183,6 +1183,15 @@ gfx::PluginWindowHandle RenderWidgetHostViewGtk::GetCompositingSurface() {
return compositing_surface_;
}
+bool RenderWidgetHostViewGtk::LockMouse() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void RenderWidgetHostViewGtk::UnlockMouse() {
+ NOTIMPLEMENTED();
+}
+
void RenderWidgetHostViewGtk::ForwardKeyboardEvent(
const NativeWebKeyboardEvent& event) {
if (!host_)
diff --git a/content/browser/renderer_host/render_widget_host_view_gtk.h b/content/browser/renderer_host/render_widget_host_view_gtk.h
index 5eb9ed4..93925f4 100644
--- a/content/browser/renderer_host/render_widget_host_view_gtk.h
+++ b/content/browser/renderer_host/render_widget_host_view_gtk.h
@@ -106,6 +106,8 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView,
virtual void GetScreenInfo(WebKit::WebScreenInfo* results) OVERRIDE;
virtual gfx::Rect GetRootWindowBounds() OVERRIDE;
virtual gfx::PluginWindowHandle GetCompositingSurface() OVERRIDE;
+ virtual bool LockMouse() OVERRIDE;
+ virtual void UnlockMouse() OVERRIDE;
// ui::AnimationDelegate implementation.
virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE;
diff --git a/content/browser/renderer_host/render_widget_host_view_win.cc b/content/browser/renderer_host/render_widget_host_view_win.cc
index 1e94b60..04f8ddb 100644
--- a/content/browser/renderer_host/render_widget_host_view_win.cc
+++ b/content/browser/renderer_host/render_widget_host_view_win.cc
@@ -243,7 +243,8 @@ RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost* widget)
is_loading_(false),
overlay_color_(0),
text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
- is_fullscreen_(false) {
+ is_fullscreen_(false),
+ ignore_mouse_movement_(true) {
render_widget_host_->SetView(this);
registrar_.Add(this,
content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
@@ -251,6 +252,7 @@ RenderWidgetHostViewWin::RenderWidgetHostViewWin(RenderWidgetHost* widget)
}
RenderWidgetHostViewWin::~RenderWidgetHostViewWin() {
+ UnlockMouse();
ResetTooltip();
}
@@ -1100,12 +1102,14 @@ LRESULT RenderWidgetHostViewWin::OnNotify(int w_param, NMHDR* header) {
tooltip_hwnd_, TTM_SETMAXTIPWIDTH, 0, kTooltipMaxWidthPixels);
SetMsgHandled(TRUE);
break;
- }
+ }
case TTN_POP:
tooltip_showing_ = false;
SetMsgHandled(TRUE);
break;
case TTN_SHOW:
+ // Tooltip shouldn't be shown when the mouse is locked.
+ DCHECK(!mouse_locked_);
tooltip_showing_ = true;
SetMsgHandled(TRUE);
break;
@@ -1226,6 +1230,15 @@ LRESULT RenderWidgetHostViewWin::OnMouseEvent(UINT message, WPARAM wparam,
LPARAM lparam, BOOL& handled) {
handled = TRUE;
+ if (message == WM_MOUSELEAVE)
+ ignore_mouse_movement_ = true;
+
+ if (mouse_locked_) {
+ HandleLockedMouseEvent(message, wparam, lparam);
+ MoveCursorToCenter();
+ return 0;
+ }
+
if (::IsWindow(tooltip_hwnd_)) {
// Forward mouse events through to the tooltip window
MSG msg;
@@ -1289,10 +1302,12 @@ LRESULT RenderWidgetHostViewWin::OnKeyEvent(UINT message, WPARAM wparam,
handled = TRUE;
// Force fullscreen windows to close on Escape.
- if (is_fullscreen_ && (message == WM_KEYDOWN || message == WM_KEYUP) &&
- wparam == VK_ESCAPE) {
- SendMessage(WM_CANCELMODE);
- return 0;
+ if ((message == WM_KEYDOWN || message == WM_KEYUP) && wparam == VK_ESCAPE) {
+ if (mouse_locked_)
+ UnlockMouse();
+ if (is_fullscreen_)
+ SendMessage(WM_CANCELMODE);
+ return 0;
}
// If we are a pop-up, forward tab related messages to our parent HWND, so
@@ -1477,6 +1492,52 @@ void RenderWidgetHostViewWin::OnAccessibilityNotifications(
browser_accessibility_manager_->OnAccessibilityNotifications(params);
}
+bool RenderWidgetHostViewWin::LockMouse() {
+ if (mouse_locked_)
+ return true;
+
+ mouse_locked_ = true;
+
+ // Hide the tooltip window if it is currently visible. When the mouse is
+ // locked, no mouse message is relayed to the tooltip window, so we don't need
+ // to worry that it will reappear.
+ if (::IsWindow(tooltip_hwnd_) && tooltip_showing_) {
+ ::SendMessage(tooltip_hwnd_, TTM_POP, 0, 0);
+ // Sending a TTM_POP message doesn't seem to actually hide the tooltip
+ // window, although we will receive a TTN_POP notification. As a result,
+ // ShowWindow() is explicitly called to hide the window.
+ ::ShowWindow(tooltip_hwnd_, SW_HIDE);
+ }
+
+ // TODO(yzshen): Show an invisible cursor instead of using
+ // ::ShowCursor(FALSE), so that MoveCursorToCenter() works with Remote
+ // Desktop.
+ ::ShowCursor(FALSE);
+
+ MoveCursorToCenter();
+
+ CRect rect;
+ GetWindowRect(&rect);
+ ::ClipCursor(&rect);
+
+ return true;
+}
+
+void RenderWidgetHostViewWin::UnlockMouse() {
+ if (!mouse_locked_)
+ return;
+
+ mouse_locked_ = false;
+
+ ::ClipCursor(NULL);
+ ::SetCursorPos(last_global_mouse_position_.x(),
+ last_global_mouse_position_.y());
+ ::ShowCursor(TRUE);
+
+ if (render_widget_host_)
+ render_widget_host_->LostMouseLock();
+}
+
void RenderWidgetHostViewWin::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
@@ -1795,6 +1856,31 @@ void RenderWidgetHostViewWin::ForwardMouseEventToRenderer(UINT message,
WebMouseEvent event(
WebInputEventFactory::mouseEvent(m_hWnd, message, wparam, lparam));
+ if (mouse_locked_) {
+ CPoint center = GetClientCenter();
+
+ event.movementX = event.windowX - center.x;
+ event.movementY = event.windowY - center.y;
+ event.x = last_mouse_position_.x();
+ event.y = last_mouse_position_.y();
+ event.windowX = last_mouse_position_.x();
+ event.windowY = last_mouse_position_.y();
+ event.globalX = last_global_mouse_position_.x();
+ event.globalY = last_global_mouse_position_.y();
+ } else {
+ if (ignore_mouse_movement_) {
+ ignore_mouse_movement_ = false;
+ event.movementX = 0;
+ event.movementY = 0;
+ } else {
+ event.movementX = event.globalX - last_global_mouse_position_.x();
+ event.movementY = event.globalY - last_global_mouse_position_.y();
+ }
+
+ last_mouse_position_.SetPoint(event.windowX, event.windowY);
+ last_global_mouse_position_.SetPoint(event.globalX, event.globalY);
+ }
+
// Send the event to the renderer before changing mouse capture, so that the
// capturelost event arrives after mouseup.
render_widget_host_->ForwardMouseEvent(event);
@@ -1843,3 +1929,32 @@ void RenderWidgetHostViewWin::DoPopupOrFullscreenInit(HWND parent_hwnd,
EnsureTooltip();
ShowWindow(IsActivatable() ? SW_SHOW : SW_SHOWNA);
}
+
+CPoint RenderWidgetHostViewWin::GetClientCenter() const {
+ CRect rect;
+ GetClientRect(&rect);
+ return rect.CenterPoint();
+}
+
+void RenderWidgetHostViewWin::MoveCursorToCenter() const {
+ CPoint center = GetClientCenter();
+ ClientToScreen(&center);
+ if (!::SetCursorPos(center.x, center.y))
+ LOG_GETLASTERROR(WARNING) << "Failed to set cursor position.";
+}
+
+void RenderWidgetHostViewWin::HandleLockedMouseEvent(UINT message,
+ WPARAM wparam,
+ LPARAM lparam) {
+ DCHECK(mouse_locked_);
+
+ if (message == WM_MOUSEMOVE) {
+ CPoint center = GetClientCenter();
+ // Ignore WM_MOUSEMOVE messages generated by MoveCursorToCenter().
+ if (LOWORD(lparam) == center.x && HIWORD(lparam) == center.y)
+ return;
+ }
+
+ ForwardMouseEventToRenderer(message, wparam, lparam);
+}
+
diff --git a/content/browser/renderer_host/render_widget_host_view_win.h b/content/browser/renderer_host/render_widget_host_view_win.h
index 74e58a6..6a9511f 100644
--- a/content/browser/renderer_host/render_widget_host_view_win.h
+++ b/content/browser/renderer_host/render_widget_host_view_win.h
@@ -26,6 +26,7 @@
#include "content/common/notification_registrar.h"
#include "ui/base/win/ime_input.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/point.h"
#include "webkit/glue/webcursor.h"
class BackingStore;
@@ -181,6 +182,8 @@ class RenderWidgetHostViewWin
virtual void OnAccessibilityNotifications(
const std::vector<ViewHostMsg_AccessibilityNotification_Params>& params
) OVERRIDE;
+ virtual bool LockMouse() OVERRIDE;
+ virtual void UnlockMouse() OVERRIDE;
// Implementation of NotificationObserver:
virtual void Observe(int type,
@@ -291,6 +294,11 @@ class RenderWidgetHostViewWin
const gfx::Rect& pos,
DWORD ex_style);
+ CPoint GetClientCenter() const;
+ void MoveCursorToCenter() const;
+
+ void HandleLockedMouseEvent(UINT message, WPARAM wparam, LPARAM lparam);
+
// The associated Model. While |this| is being Destroyed,
// |render_widget_host_| is NULL and the Windows message loop is run one last
// time. Message handlers must check for a NULL |render_widget_host_|.
@@ -386,6 +394,18 @@ class RenderWidgetHostViewWin
// Is the widget fullscreen?
bool is_fullscreen_;
+ // Used to record the last position of the mouse.
+ // While the mouse is locked, they store the last known position just as mouse
+ // lock was entered.
+ // Relative to the upper-left corner of the view.
+ gfx::Point last_mouse_position_;
+ // Relative to the upper-left corner of the screen.
+ gfx::Point last_global_mouse_position_;
+
+ // In the case of the mouse being moved away from the view and then moved
+ // back, we regard the mouse movement as (0, 0).
+ bool ignore_mouse_movement_;
+
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewWin);
};
diff --git a/content/browser/renderer_host/test_render_view_host.cc b/content/browser/renderer_host/test_render_view_host.cc
index 9303f86..e15018e 100644
--- a/content/browser/renderer_host/test_render_view_host.cc
+++ b/content/browser/renderer_host/test_render_view_host.cc
@@ -252,6 +252,13 @@ gfx::PluginWindowHandle TestRenderWidgetHostView::GetCompositingSurface() {
return gfx::kNullPluginWindow;
}
+bool TestRenderWidgetHostView::LockMouse() {
+ return false;
+}
+
+void TestRenderWidgetHostView::UnlockMouse() {
+}
+
TestRenderViewHostFactory::TestRenderViewHostFactory(
RenderProcessHostFactory* rph_factory)
: render_process_host_factory_(rph_factory) {
diff --git a/content/browser/renderer_host/test_render_view_host.h b/content/browser/renderer_host/test_render_view_host.h
index 3afebf7..2952242 100644
--- a/content/browser/renderer_host/test_render_view_host.h
+++ b/content/browser/renderer_host/test_render_view_host.h
@@ -155,6 +155,9 @@ class TestRenderWidgetHostView : public RenderWidgetHostView {
virtual gfx::PluginWindowHandle GetCompositingSurface() OVERRIDE;
+ virtual bool LockMouse() OVERRIDE;
+ virtual void UnlockMouse() OVERRIDE;
+
bool is_showing() const { return is_showing_; }
private:
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 0d4c597..f80be55 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -1335,6 +1335,14 @@ IPC_MESSAGE_ROUTED3(ViewMsg_GetSerializedHtmlDataForCurrentPageWithLocalLinks,
IPC_MESSAGE_ROUTED1(ViewMsg_UpdateRemoteAccessClientFirewallTraversal,
std::string /* traversal_data */)
+// Tells the render side that a ViewHostMsg_LockMouse message has been
+// processed. |succeeded| indicates whether the mouse has been successfully
+// locked or not.
+IPC_MESSAGE_ROUTED1(ViewMsg_LockMouse_ACK,
+ bool /* succeeded */)
+// Tells the render side that the mouse has been unlocked.
+IPC_MESSAGE_ROUTED0(ViewMsg_MouseLockLost)
+
// These three messages are sent to the parent RenderViewHost to display the
// page/widget that was created by
// CreateWindow/CreateWidget/CreateFullscreenWidget. routing_id
@@ -1900,8 +1908,8 @@ IPC_MESSAGE_ROUTED3(ViewHostMsg_UpdateZoomLimits,
// Asks the browser to create a block of shared memory for the renderer to
// fill in and pass back to the browser.
IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_AllocateSharedMemoryBuffer,
- uint32 /* buffer size */,
- base::SharedMemoryHandle /* browser handle */)
+ uint32 /* buffer size */,
+ base::SharedMemoryHandle /* browser handle */)
// Notify the browser that this render process can or can't be suddenly
// terminated.
@@ -2086,3 +2094,13 @@ IPC_MESSAGE_ROUTED0(ViewHostMsg_RequestRemoteAccessClientFirewallTraversal)
// Notifies the browser of an event occurring in the media pipeline.
IPC_MESSAGE_CONTROL1(ViewHostMsg_MediaLogEvent,
media::MediaLogEvent /* event */)
+
+// Requests to lock the mouse. Will result in a ViewMsg_LockMouse_ACK message
+// being sent back.
+IPC_MESSAGE_ROUTED0(ViewHostMsg_LockMouse)
+
+// Requests to unlock the mouse. A ViewMsg_MouseLockLost message will be sent
+// whenever the mouse is unlocked (which may or may not be caused by
+// ViewHostMsg_UnlockMouse).
+IPC_MESSAGE_ROUTED0(ViewHostMsg_UnlockMouse)
+
diff --git a/content/renderer/pepper_plugin_delegate_impl.cc b/content/renderer/pepper_plugin_delegate_impl.cc
index c21353f..37a71b5 100644
--- a/content/renderer/pepper_plugin_delegate_impl.cc
+++ b/content/renderer/pepper_plugin_delegate_impl.cc
@@ -52,8 +52,10 @@
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/ppapi_preferences.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserCompletion.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFileChooserParams.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebScreenInfo.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
@@ -663,10 +665,15 @@ PepperPluginDelegateImpl::PepperPluginDelegateImpl(RenderView* render_view)
has_saved_context_menu_action_(false),
saved_context_menu_action_(0),
id_generator_(0),
- is_pepper_plugin_focused_(false) {
+ is_pepper_plugin_focused_(false),
+ mouse_lock_owner_(NULL),
+ mouse_locked_(false),
+ pending_lock_request_(false),
+ pending_unlock_request_(false) {
}
PepperPluginDelegateImpl::~PepperPluginDelegateImpl() {
+ DCHECK(!mouse_lock_owner_);
}
scoped_refptr<webkit::ppapi::PluginModule>
@@ -851,6 +858,8 @@ void PepperPluginDelegateImpl::PluginCrashed(
webkit::ppapi::PluginInstance* instance) {
subscribed_to_policy_updates_.erase(instance);
render_view_->PluginCrashed(instance->module()->path());
+
+ UnlockMouse(instance);
}
void PepperPluginDelegateImpl::InstanceCreated(
@@ -865,6 +874,14 @@ void PepperPluginDelegateImpl::InstanceDeleted(
webkit::ppapi::PluginInstance* instance) {
active_instances_.erase(instance);
subscribed_to_policy_updates_.erase(instance);
+
+ if (mouse_lock_owner_ && mouse_lock_owner_ == instance) {
+ // UnlockMouse() will determine whether a ViewHostMsg_UnlockMouse needs to
+ // be sent, and set internal state properly. We only need to forget about
+ // the current |mouse_lock_owner_|.
+ UnlockMouse(mouse_lock_owner_);
+ mouse_lock_owner_ = NULL;
+ }
}
SkBitmap* PepperPluginDelegateImpl::GetSadPluginBitmap() {
@@ -1027,7 +1044,7 @@ void PepperPluginDelegateImpl::OnAsyncFileOpened(
void PepperPluginDelegateImpl::OnSetFocus(bool has_focus) {
for (std::set<webkit::ppapi::PluginInstance*>::iterator i =
- active_instances_.begin();
+ active_instances_.begin();
i != active_instances_.end(); ++i)
(*i)->SetContentAreaFocus(has_focus);
}
@@ -1036,6 +1053,64 @@ bool PepperPluginDelegateImpl::IsPluginFocused() const {
return is_pepper_plugin_focused_;
}
+void PepperPluginDelegateImpl::OnLockMouseACK(bool succeeded) {
+ DCHECK(!mouse_locked_ && pending_lock_request_);
+
+ mouse_locked_ = succeeded;
+ pending_lock_request_ = false;
+ if (pending_unlock_request_ && !succeeded) {
+ // We have sent an unlock request after the lock request. However, since
+ // the lock request has failed, the unlock request will be ignored by the
+ // browser side and there won't be any response to it.
+ pending_unlock_request_ = false;
+ }
+ // If the PluginInstance has been deleted, |mouse_lock_owner_| can be NULL.
+ if (mouse_lock_owner_) {
+ webkit::ppapi::PluginInstance* last_mouse_lock_owner = mouse_lock_owner_;
+ if (!succeeded) {
+ // Reset |mouse_lock_owner_| to NULL before calling OnLockMouseACK(), so
+ // that if OnLockMouseACK() results in calls to any mouse lock method
+ // (e.g., LockMouse()), the method will see consistent internal state.
+ mouse_lock_owner_ = NULL;
+ }
+
+ last_mouse_lock_owner->OnLockMouseACK(succeeded ? PP_OK : PP_ERROR_FAILED);
+ }
+}
+
+void PepperPluginDelegateImpl::OnMouseLockLost() {
+ DCHECK(mouse_locked_ && !pending_lock_request_);
+
+ mouse_locked_ = false;
+ pending_unlock_request_ = false;
+ // If the PluginInstance has been deleted, |mouse_lock_owner_| can be NULL.
+ if (mouse_lock_owner_) {
+ // Reset |mouse_lock_owner_| to NULL before calling OnMouseLockLost(), so
+ // that if OnMouseLockLost() results in calls to any mouse lock method
+ // (e.g., LockMouse()), the method will see consistent internal state.
+ webkit::ppapi::PluginInstance* last_mouse_lock_owner = mouse_lock_owner_;
+ mouse_lock_owner_ = NULL;
+
+ last_mouse_lock_owner->OnMouseLockLost();
+ }
+}
+
+bool PepperPluginDelegateImpl::DispatchLockedMouseEvent(
+ const WebKit::WebMouseEvent& event) {
+ if (mouse_locked_) {
+ if (mouse_lock_owner_) {
+ // |cursor_info| is ignored since it is hidden when the mouse is locked.
+ WebKit::WebCursorInfo cursor_info;
+ mouse_lock_owner_->HandleInputEvent(event, &cursor_info);
+ }
+
+ // If the mouse is locked, only the current owner of the mouse lock can
+ // process mouse events.
+ return true;
+ }
+ return false;
+}
+
bool PepperPluginDelegateImpl::OpenFileSystem(
const GURL& url,
fileapi::FileSystemType type,
@@ -1490,6 +1565,58 @@ ppapi::Preferences PepperPluginDelegateImpl::GetPreferences() {
return ppapi::Preferences(render_view_->webkit_preferences());
}
+void PepperPluginDelegateImpl::LockMouse(
+ webkit::ppapi::PluginInstance* instance) {
+ DCHECK(instance);
+ if (!MouseLockedOrPending()) {
+ DCHECK(!mouse_lock_owner_);
+ pending_lock_request_ = true;
+ mouse_lock_owner_ = instance;
+
+ render_view_->Send(
+ new ViewHostMsg_LockMouse(render_view_->routing_id()));
+ } else if (instance != mouse_lock_owner_) {
+ // Another plugin instance is using mouse lock. Fail immediately.
+ instance->OnLockMouseACK(PP_ERROR_FAILED);
+ } else {
+ if (mouse_locked_) {
+ instance->OnLockMouseACK(PP_OK);
+ } else if (pending_lock_request_) {
+ instance->OnLockMouseACK(PP_ERROR_INPROGRESS);
+ } else {
+ // The only case left here is
+ // !mouse_locked_ && !pending_lock_request_ && pending_unlock_request_,
+ // which is not possible.
+ NOTREACHED();
+ instance->OnLockMouseACK(PP_ERROR_FAILED);
+ }
+ }
+}
+
+void PepperPluginDelegateImpl::UnlockMouse(
+ webkit::ppapi::PluginInstance* instance) {
+ DCHECK(instance);
+
+ // If no one is using mouse lock or the user is not |instance|, ignore
+ // the unlock request.
+ if (MouseLockedOrPending() && mouse_lock_owner_ == instance) {
+ if (mouse_locked_ || pending_lock_request_) {
+ DCHECK(!mouse_locked_ || !pending_lock_request_);
+ if (!pending_unlock_request_) {
+ pending_unlock_request_ = true;
+
+ render_view_->Send(
+ new ViewHostMsg_UnlockMouse(render_view_->routing_id()));
+ }
+ } else {
+ // The only case left here is
+ // !mouse_locked_ && !pending_lock_request_ && pending_unlock_request_,
+ // which is not possible.
+ NOTREACHED();
+ }
+ }
+}
+
int PepperPluginDelegateImpl::GetRoutingId() const {
return render_view_->routing_id();
}
diff --git a/content/renderer/pepper_plugin_delegate_impl.h b/content/renderer/pepper_plugin_delegate_impl.h
index cf8d2c3..f8dcd56 100644
--- a/content/renderer/pepper_plugin_delegate_impl.h
+++ b/content/renderer/pepper_plugin_delegate_impl.h
@@ -45,6 +45,7 @@ class PluginModule;
namespace WebKit {
class WebFileChooserCompletion;
+class WebMouseEvent;
struct WebFileChooserParams;
}
@@ -168,6 +169,15 @@ class PepperPluginDelegateImpl
// Returns whether or not a Pepper plugin is focused.
bool IsPluginFocused() const;
+ // Notification that the request to lock the mouse has completed.
+ void OnLockMouseACK(bool succeeded);
+ // Notification that the plugin instance has lost the mouse lock.
+ void OnMouseLockLost();
+ // Dispatches mouse events directly to the owner of the mouse lock.
+ // True indicates currently the mouse is locked and the event has been
+ // dispatched to the owner.
+ bool DispatchLockedMouseEvent(const WebKit::WebMouseEvent& event);
+
// PluginDelegate implementation.
virtual void PluginFocusChanged(bool focused) OVERRIDE;
virtual void PluginCrashed(webkit::ppapi::PluginInstance* instance);
@@ -305,6 +315,8 @@ class PepperPluginDelegateImpl
virtual base::SharedMemory* CreateAnonymousSharedMemory(uint32_t size)
OVERRIDE;
virtual ::ppapi::Preferences GetPreferences() OVERRIDE;
+ virtual void LockMouse(webkit::ppapi::PluginInstance* instance) OVERRIDE;
+ virtual void UnlockMouse(webkit::ppapi::PluginInstance* instance) OVERRIDE;
CONTENT_EXPORT int GetRoutingId() const;
@@ -317,6 +329,10 @@ class PepperPluginDelegateImpl
scoped_refptr<PpapiBrokerImpl> CreatePpapiBroker(
webkit::ppapi::PluginModule* plugin_module);
+ bool MouseLockedOrPending() const {
+ return mouse_locked_ || pending_lock_request_ || pending_unlock_request_;
+ }
+
// Pointer to the RenderView that owns us.
RenderView* render_view_;
@@ -347,6 +363,21 @@ class PepperPluginDelegateImpl
// been updated.
std::set<webkit::ppapi::PluginInstance*> subscribed_to_policy_updates_;
+ // |mouse_lock_owner_| is not owned by this class. We can know about when it
+ // is destroyed via InstanceDeleted().
+ // |mouse_lock_owner_| being non-NULL doesn't indicate that currently the
+ // mouse has been locked. It is possible that a request to lock the mouse has
+ // been sent, but the response hasn't arrived yet.
+ webkit::ppapi::PluginInstance* mouse_lock_owner_;
+ bool mouse_locked_;
+ // If both |pending_lock_request_| and |pending_unlock_request_| are true,
+ // it means a lock request was sent before an unlock request and we haven't
+ // received responses for them.
+ // The logic in LockMouse() makes sure that a lock request won't be sent when
+ // there is a pending unlock request.
+ bool pending_lock_request_;
+ bool pending_unlock_request_;
+
DISALLOW_COPY_AND_ASSIGN(PepperPluginDelegateImpl);
};
diff --git a/content/renderer/render_view.cc b/content/renderer/render_view.cc
index aa45119..46e03c0 100644
--- a/content/renderer/render_view.cc
+++ b/content/renderer/render_view.cc
@@ -760,6 +760,8 @@ bool RenderView::OnMessageReceived(const IPC::Message& message) {
OnSetHistoryLengthAndPrune)
IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
IPC_MESSAGE_HANDLER(IntentsMsg_WebIntentReply, OnWebIntentReply);
+ IPC_MESSAGE_HANDLER(ViewMsg_LockMouse_ACK, OnLockMouseACK)
+ IPC_MESSAGE_HANDLER(ViewMsg_MouseLockLost, OnMouseLockLost)
// Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(handled = RenderWidget::OnMessageReceived(message))
@@ -4185,6 +4187,10 @@ void RenderView::DidHandleKeyEvent() {
edit_commands_.clear();
}
+bool RenderView::WillHandleMouseEvent(const WebKit::WebMouseEvent& event) {
+ return pepper_delegate_.DispatchLockedMouseEvent(event);
+}
+
void RenderView::DidHandleMouseEvent(const WebKit::WebMouseEvent& event) {
FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidHandleMouseEvent(event));
}
@@ -4636,3 +4642,12 @@ void RenderView::OnEnableViewSourceMode() {
return;
main_frame->enableViewSourceMode(true);
}
+
+void RenderView::OnLockMouseACK(bool succeeded) {
+ pepper_delegate_.OnLockMouseACK(succeeded);
+}
+
+void RenderView::OnMouseLockLost() {
+ pepper_delegate_.OnMouseLockLost();
+}
+
diff --git a/content/renderer/render_view.h b/content/renderer/render_view.h
index db207a4..8f95fb3 100644
--- a/content/renderer/render_view.h
+++ b/content/renderer/render_view.h
@@ -648,6 +648,8 @@ class RenderView : public RenderWidget,
gfx::Rect* clip);
virtual gfx::Point GetScrollOffset();
virtual void DidHandleKeyEvent();
+ virtual bool WillHandleMouseEvent(
+ const WebKit::WebMouseEvent& event) OVERRIDE;
virtual void DidHandleMouseEvent(const WebKit::WebMouseEvent& event);
virtual void OnSetFocus(bool enable);
virtual void OnWasHidden();
@@ -829,8 +831,10 @@ class RenderView : public RenderWidget,
const std::vector<GURL>& links,
const std::vector<FilePath>& local_paths,
const FilePath& local_directory_name);
+ void OnLockMouseACK(bool succeeded);
void OnMediaPlayerActionAt(const gfx::Point& location,
const WebKit::WebMediaPlayerAction& action);
+ void OnMouseLockLost();
void OnMoveOrResizeStarted();
void OnNavigate(const ViewMsg_Navigate_Params& params);
void OnPaste();
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 7b2f48a..3f02e07 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -446,10 +446,16 @@ void RenderWidget::OnHandleInputEvent(const IPC::Message& message) {
if (input_event->type == WebInputEvent::RawKeyDown)
message.ReadBool(&iter, &is_keyboard_shortcut);
- bool processed = false;
+ bool prevent_default = false;
+ if (WebInputEvent::isMouseEventType(input_event->type)) {
+ prevent_default = WillHandleMouseEvent(
+ *(static_cast<const WebMouseEvent*>(input_event)));
+ }
+
+ bool processed = prevent_default;
if (input_event->type != WebInputEvent::Char || !suppress_next_char_events_) {
suppress_next_char_events_ = false;
- if (webwidget_)
+ if (!processed && webwidget_)
processed = webwidget_->handleInputEvent(*input_event);
}
@@ -482,10 +488,12 @@ void RenderWidget::OnHandleInputEvent(const IPC::Message& message) {
handling_input_event_ = false;
- if (WebInputEvent::isKeyboardEventType(input_event->type))
- DidHandleKeyEvent();
- if (WebInputEvent::isMouseEventType(input_event->type))
- DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event)));
+ if (!prevent_default) {
+ if (WebInputEvent::isKeyboardEventType(input_event->type))
+ DidHandleKeyEvent();
+ if (WebInputEvent::isMouseEventType(input_event->type))
+ DidHandleMouseEvent(*(static_cast<const WebMouseEvent*>(input_event)));
+ }
}
void RenderWidget::OnMouseCaptureLost() {
@@ -1393,3 +1401,7 @@ void RenderWidget::CleanupWindowInPluginMoves(gfx::PluginWindowHandle window) {
}
}
}
+
+bool RenderWidget::WillHandleMouseEvent(const WebKit::WebMouseEvent& event) {
+ return false;
+}
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 05a7d5f..0980575 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -42,6 +42,7 @@ class PlatformCanvas;
}
namespace WebKit {
+class WebInputEvent;
class WebMouseEvent;
class WebWidget;
struct WebPopupMenuInfo;
@@ -300,6 +301,12 @@ class RenderWidget : public IPC::Channel::Listener,
// just handled.
virtual void DidHandleKeyEvent() {}
+ // Called by OnHandleInputEvent() to notify subclasses that a mouse event is
+ // about to be handled.
+ // Returns true if no further handling is needed. In that case, the event
+ // won't be sent to WebKit or trigger DidHandleMouseEvent().
+ virtual bool WillHandleMouseEvent(const WebKit::WebMouseEvent& event);
+
// Called by OnHandleInputEvent() to notify subclasses that a mouse event was
// just handled.
virtual void DidHandleMouseEvent(const WebKit::WebMouseEvent& event) {}