1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/render_widget_fullscreen_pepper.h"
10 #include "base/command_line.h"
11 #include "base/message_loop/message_loop.h"
12 #include "content/common/gpu/client/gpu_channel_host.h"
13 #include "content/common/view_messages.h"
14 #include "content/public/common/content_switches.h"
15 #include "content/renderer/gpu/render_widget_compositor.h"
16 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
17 #include "content/renderer/render_thread_impl.h"
18 #include "gpu/command_buffer/client/gles2_implementation.h"
19 #include "skia/ext/platform_canvas.h"
20 #include "third_party/WebKit/public/platform/WebCanvas.h"
21 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
22 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
23 #include "third_party/WebKit/public/platform/WebLayer.h"
24 #include "third_party/WebKit/public/platform/WebSize.h"
25 #include "third_party/WebKit/public/web/WebWidget.h"
26 #include "ui/gfx/geometry/size_conversions.h"
27 #include "ui/gl/gpu_preference.h"
29 using blink::WebCanvas
;
30 using blink::WebCompositionUnderline
;
31 using blink::WebCursorInfo
;
32 using blink::WebGestureEvent
;
33 using blink::WebInputEvent
;
34 using blink::WebMouseEvent
;
35 using blink::WebMouseWheelEvent
;
36 using blink::WebPoint
;
39 using blink::WebString
;
40 using blink::WebTextDirection
;
41 using blink::WebTextInputType
;
42 using blink::WebVector
;
43 using blink::WebWidget
;
44 using blink::WGC3Dintptr
;
50 class FullscreenMouseLockDispatcher
: public MouseLockDispatcher
{
52 explicit FullscreenMouseLockDispatcher(RenderWidgetFullscreenPepper
* widget
);
53 ~FullscreenMouseLockDispatcher() override
;
56 // MouseLockDispatcher implementation.
57 void SendLockMouseRequest(bool unlocked_by_target
) override
;
58 void SendUnlockMouseRequest() override
;
60 RenderWidgetFullscreenPepper
* widget_
;
62 DISALLOW_COPY_AND_ASSIGN(FullscreenMouseLockDispatcher
);
65 WebMouseEvent
WebMouseEventFromGestureEvent(const WebGestureEvent
& gesture
) {
68 switch (gesture
.type
) {
69 case WebInputEvent::GestureScrollBegin
:
70 mouse
.type
= WebInputEvent::MouseDown
;
73 case WebInputEvent::GestureScrollUpdate
:
74 mouse
.type
= WebInputEvent::MouseMove
;
77 case WebInputEvent::GestureFlingStart
:
78 if (gesture
.sourceDevice
== blink::WebGestureDeviceTouchscreen
) {
79 // A scroll gesture on the touchscreen may end with a GestureScrollEnd
80 // when there is no velocity, or a GestureFlingStart when it has a
81 // velocity. In both cases, it should end the drag that was initiated by
82 // the GestureScrollBegin (and subsequent GestureScrollUpdate) events.
83 mouse
.type
= WebInputEvent::MouseUp
;
88 case WebInputEvent::GestureScrollEnd
:
89 mouse
.type
= WebInputEvent::MouseUp
;
96 if (mouse
.type
== WebInputEvent::Undefined
)
99 mouse
.timeStampSeconds
= gesture
.timeStampSeconds
;
100 mouse
.modifiers
= gesture
.modifiers
| WebInputEvent::LeftButtonDown
;
101 mouse
.button
= WebMouseEvent::ButtonLeft
;
102 mouse
.clickCount
= (mouse
.type
== WebInputEvent::MouseDown
||
103 mouse
.type
== WebInputEvent::MouseUp
);
107 mouse
.windowX
= gesture
.x
;
108 mouse
.windowY
= gesture
.y
;
109 mouse
.globalX
= gesture
.globalX
;
110 mouse
.globalY
= gesture
.globalY
;
115 FullscreenMouseLockDispatcher::FullscreenMouseLockDispatcher(
116 RenderWidgetFullscreenPepper
* widget
) : widget_(widget
) {
119 FullscreenMouseLockDispatcher::~FullscreenMouseLockDispatcher() {
122 void FullscreenMouseLockDispatcher::SendLockMouseRequest(
123 bool unlocked_by_target
) {
124 widget_
->Send(new ViewHostMsg_LockMouse(widget_
->routing_id(), false,
125 unlocked_by_target
, true));
128 void FullscreenMouseLockDispatcher::SendUnlockMouseRequest() {
129 widget_
->Send(new ViewHostMsg_UnlockMouse(widget_
->routing_id()));
132 // WebWidget that simply wraps the pepper plugin.
133 // TODO(piman): figure out IME and implement setComposition and friends if
135 class PepperWidget
: public WebWidget
{
137 explicit PepperWidget(RenderWidgetFullscreenPepper
* widget
)
141 virtual ~PepperWidget() {}
144 virtual void close() {
148 virtual WebSize
size() {
152 virtual void resize(const WebSize
& size
) {
153 if (!widget_
->plugin())
157 WebRect
plugin_rect(0, 0, size_
.width
, size_
.height
);
158 widget_
->plugin()->ViewChanged(plugin_rect
, plugin_rect
, plugin_rect
,
159 std::vector
<gfx::Rect
>());
160 widget_
->Invalidate();
163 virtual void themeChanged() {
167 virtual bool handleInputEvent(const WebInputEvent
& event
) {
168 if (!widget_
->plugin())
171 // This cursor info is ignored, we always set the cursor directly from
172 // RenderWidgetFullscreenPepper::DidChangeCursor.
173 WebCursorInfo cursor
;
175 // Pepper plugins do not accept gesture events. So do not send the gesture
176 // events directly to the plugin. Instead, try to convert them to equivalent
177 // mouse events, and then send to the plugin.
178 if (WebInputEvent::isGestureEventType(event
.type
)) {
180 const WebGestureEvent
* gesture_event
=
181 static_cast<const WebGestureEvent
*>(&event
);
182 switch (event
.type
) {
183 case WebInputEvent::GestureTap
: {
186 mouse
.timeStampSeconds
= gesture_event
->timeStampSeconds
;
187 mouse
.type
= WebInputEvent::MouseMove
;
188 mouse
.modifiers
= gesture_event
->modifiers
;
190 mouse
.x
= gesture_event
->x
;
191 mouse
.y
= gesture_event
->y
;
192 mouse
.windowX
= gesture_event
->x
;
193 mouse
.windowY
= gesture_event
->y
;
194 mouse
.globalX
= gesture_event
->globalX
;
195 mouse
.globalY
= gesture_event
->globalY
;
198 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
200 mouse
.type
= WebInputEvent::MouseDown
;
201 mouse
.button
= WebMouseEvent::ButtonLeft
;
202 mouse
.clickCount
= gesture_event
->data
.tap
.tapCount
;
203 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
205 mouse
.type
= WebInputEvent::MouseUp
;
206 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
211 WebMouseEvent mouse
= WebMouseEventFromGestureEvent(*gesture_event
);
212 if (mouse
.type
!= WebInputEvent::Undefined
)
213 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
220 bool result
= widget_
->plugin()->HandleInputEvent(event
, &cursor
);
222 // For normal web pages, WebViewImpl does input event translations and
223 // generates context menu events. Since we don't have a WebView, we need to
224 // do the necessary translation ourselves.
225 if (WebInputEvent::isMouseEventType(event
.type
)) {
226 const WebMouseEvent
& mouse_event
=
227 reinterpret_cast<const WebMouseEvent
&>(event
);
228 bool send_context_menu_event
= false;
229 // On Mac/Linux, we handle it on mouse down.
230 // On Windows, we handle it on mouse up.
232 send_context_menu_event
=
233 mouse_event
.type
== WebInputEvent::MouseUp
&&
234 mouse_event
.button
== WebMouseEvent::ButtonRight
;
235 #elif defined(OS_MACOSX)
236 send_context_menu_event
=
237 mouse_event
.type
== WebInputEvent::MouseDown
&&
238 (mouse_event
.button
== WebMouseEvent::ButtonRight
||
239 (mouse_event
.button
== WebMouseEvent::ButtonLeft
&&
240 mouse_event
.modifiers
& WebMouseEvent::ControlKey
));
242 send_context_menu_event
=
243 mouse_event
.type
== WebInputEvent::MouseDown
&&
244 mouse_event
.button
== WebMouseEvent::ButtonRight
;
246 if (send_context_menu_event
) {
247 WebMouseEvent
context_menu_event(mouse_event
);
248 context_menu_event
.type
= WebInputEvent::ContextMenu
;
249 widget_
->plugin()->HandleInputEvent(context_menu_event
, &cursor
);
256 RenderWidgetFullscreenPepper
* widget_
;
259 DISALLOW_COPY_AND_ASSIGN(PepperWidget
);
262 } // anonymous namespace
265 RenderWidgetFullscreenPepper
* RenderWidgetFullscreenPepper::Create(
267 CompositorDependencies
* compositor_deps
,
268 PepperPluginInstanceImpl
* plugin
,
269 const GURL
& active_url
,
270 const blink::WebScreenInfo
& screen_info
) {
271 DCHECK_NE(MSG_ROUTING_NONE
, opener_id
);
272 scoped_refptr
<RenderWidgetFullscreenPepper
> widget(
273 new RenderWidgetFullscreenPepper(compositor_deps
, plugin
, active_url
,
275 widget
->Init(opener_id
);
280 RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper(
281 CompositorDependencies
* compositor_deps
,
282 PepperPluginInstanceImpl
* plugin
,
283 const GURL
& active_url
,
284 const blink::WebScreenInfo
& screen_info
)
285 : RenderWidgetFullscreen(compositor_deps
, screen_info
),
286 active_url_(active_url
),
289 mouse_lock_dispatcher_(new FullscreenMouseLockDispatcher(this)) {}
291 RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() {
294 void RenderWidgetFullscreenPepper::Invalidate() {
295 InvalidateRect(gfx::Rect(size_
.width(), size_
.height()));
298 void RenderWidgetFullscreenPepper::InvalidateRect(const blink::WebRect
& rect
) {
299 didInvalidateRect(rect
);
302 void RenderWidgetFullscreenPepper::ScrollRect(
303 int dx
, int dy
, const blink::WebRect
& rect
) {
306 void RenderWidgetFullscreenPepper::Destroy() {
307 // This function is called by the plugin instance as it's going away, so reset
308 // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close().
311 // After calling Destroy(), the plugin instance assumes that the layer is not
312 // used by us anymore, so it may destroy the layer before this object goes
316 Send(new ViewHostMsg_Close(routing_id_
));
320 void RenderWidgetFullscreenPepper::DidChangeCursor(
321 const blink::WebCursorInfo
& cursor
) {
322 didChangeCursor(cursor
);
325 void RenderWidgetFullscreenPepper::SetLayer(blink::WebLayer
* layer
) {
329 compositor_
->clearRootLayer();
332 if (!layerTreeView())
333 initializeLayerTreeView();
334 layer_
->setBounds(blink::WebSize(size()));
335 layer_
->setDrawsContent(true);
336 compositor_
->setDeviceScaleFactor(device_scale_factor_
);
337 compositor_
->setRootLayer(*layer_
);
340 bool RenderWidgetFullscreenPepper::OnMessageReceived(const IPC::Message
& msg
) {
342 IPC_BEGIN_MESSAGE_MAP(RenderWidgetFullscreenPepper
, msg
)
343 IPC_MESSAGE_FORWARD(ViewMsg_LockMouse_ACK
,
344 mouse_lock_dispatcher_
.get(),
345 MouseLockDispatcher::OnLockMouseACK
)
346 IPC_MESSAGE_FORWARD(ViewMsg_MouseLockLost
,
347 mouse_lock_dispatcher_
.get(),
348 MouseLockDispatcher::OnMouseLockLost
)
349 IPC_MESSAGE_UNHANDLED(handled
= false)
350 IPC_END_MESSAGE_MAP()
354 return RenderWidgetFullscreen::OnMessageReceived(msg
);
357 void RenderWidgetFullscreenPepper::DidInitiatePaint() {
359 plugin_
->ViewInitiatedPaint();
362 void RenderWidgetFullscreenPepper::DidFlushPaint() {
365 void RenderWidgetFullscreenPepper::Close() {
366 // If the fullscreen window is closed (e.g. user pressed escape), reset to
369 plugin_
->FlashSetFullscreen(false, false);
371 // Call Close on the base class to destroy the WebWidget instance.
372 RenderWidget::Close();
375 void RenderWidgetFullscreenPepper::OnResize(
376 const ViewMsg_Resize_Params
& params
) {
378 layer_
->setBounds(blink::WebSize(params
.new_size
));
379 RenderWidget::OnResize(params
);
382 WebWidget
* RenderWidgetFullscreenPepper::CreateWebWidget() {
383 return new PepperWidget(this);
386 GURL
RenderWidgetFullscreenPepper::GetURLForGraphicsContext3D() {
390 void RenderWidgetFullscreenPepper::SetDeviceScaleFactor(
391 float device_scale_factor
) {
392 RenderWidget::SetDeviceScaleFactor(device_scale_factor
);
394 compositor_
->setDeviceScaleFactor(device_scale_factor
);
397 } // namespace content