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_platform_context_3d.h"
17 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
18 #include "content/renderer/render_thread_impl.h"
19 #include "gpu/command_buffer/client/gles2_implementation.h"
20 #include "skia/ext/platform_canvas.h"
21 #include "third_party/WebKit/public/platform/WebCanvas.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/WebCursorInfo.h"
26 #include "third_party/WebKit/public/web/WebWidget.h"
27 #include "ui/gfx/size_conversions.h"
28 #include "ui/gl/gpu_preference.h"
30 using WebKit::WebCanvas
;
31 using WebKit::WebCompositionUnderline
;
32 using WebKit::WebCursorInfo
;
33 using WebKit::WebGestureEvent
;
34 using WebKit::WebInputEvent
;
35 using WebKit::WebMouseEvent
;
36 using WebKit::WebMouseWheelEvent
;
37 using WebKit::WebPoint
;
38 using WebKit::WebRect
;
39 using WebKit::WebSize
;
40 using WebKit::WebString
;
41 using WebKit::WebTextDirection
;
42 using WebKit::WebTextInputType
;
43 using WebKit::WebVector
;
44 using WebKit::WebWidget
;
45 using WebKit::WGC3Dintptr
;
51 class FullscreenMouseLockDispatcher
: public MouseLockDispatcher
{
53 explicit FullscreenMouseLockDispatcher(RenderWidgetFullscreenPepper
* widget
);
54 virtual ~FullscreenMouseLockDispatcher();
57 // MouseLockDispatcher implementation.
58 virtual void SendLockMouseRequest(bool unlocked_by_target
) OVERRIDE
;
59 virtual void SendUnlockMouseRequest() OVERRIDE
;
61 RenderWidgetFullscreenPepper
* widget_
;
63 DISALLOW_COPY_AND_ASSIGN(FullscreenMouseLockDispatcher
);
66 WebMouseEvent
WebMouseEventFromGestureEvent(const WebGestureEvent
& gesture
) {
69 switch (gesture
.type
) {
70 case WebInputEvent::GestureScrollBegin
:
71 mouse
.type
= WebInputEvent::MouseDown
;
74 case WebInputEvent::GestureScrollUpdate
:
75 mouse
.type
= WebInputEvent::MouseMove
;
78 case WebInputEvent::GestureFlingStart
:
79 if (gesture
.sourceDevice
== WebGestureEvent::Touchscreen
) {
80 // A scroll gesture on the touchscreen may end with a GestureScrollEnd
81 // when there is no velocity, or a GestureFlingStart when it has a
82 // velocity. In both cases, it should end the drag that was initiated by
83 // the GestureScrollBegin (and subsequent GestureScrollUpdate) events.
84 mouse
.type
= WebInputEvent::MouseUp
;
89 case WebInputEvent::GestureScrollEnd
:
90 mouse
.type
= WebInputEvent::MouseUp
;
97 if (mouse
.type
== WebInputEvent::Undefined
)
100 mouse
.timeStampSeconds
= gesture
.timeStampSeconds
;
101 mouse
.modifiers
= gesture
.modifiers
| WebInputEvent::LeftButtonDown
;
102 mouse
.button
= WebMouseEvent::ButtonLeft
;
103 mouse
.clickCount
= (mouse
.type
== WebInputEvent::MouseDown
||
104 mouse
.type
== WebInputEvent::MouseUp
);
108 mouse
.windowX
= gesture
.globalX
;
109 mouse
.windowY
= gesture
.globalY
;
110 mouse
.globalX
= gesture
.globalX
;
111 mouse
.globalY
= gesture
.globalY
;
116 FullscreenMouseLockDispatcher::FullscreenMouseLockDispatcher(
117 RenderWidgetFullscreenPepper
* widget
) : widget_(widget
) {
120 FullscreenMouseLockDispatcher::~FullscreenMouseLockDispatcher() {
123 void FullscreenMouseLockDispatcher::SendLockMouseRequest(
124 bool unlocked_by_target
) {
125 widget_
->Send(new ViewHostMsg_LockMouse(widget_
->routing_id(), false,
126 unlocked_by_target
, true));
129 void FullscreenMouseLockDispatcher::SendUnlockMouseRequest() {
130 widget_
->Send(new ViewHostMsg_UnlockMouse(widget_
->routing_id()));
133 // WebWidget that simply wraps the pepper plugin.
134 class PepperWidget
: public WebWidget
{
136 explicit PepperWidget(RenderWidgetFullscreenPepper
* widget
)
140 virtual ~PepperWidget() {}
143 virtual void close() {
147 virtual WebSize
size() {
151 virtual void willStartLiveResize() {
154 virtual void resize(const WebSize
& size
) {
155 if (!widget_
->plugin())
159 WebRect
plugin_rect(0, 0, size_
.width
, size_
.height
);
160 widget_
->plugin()->ViewChanged(plugin_rect
, plugin_rect
,
161 std::vector
<gfx::Rect
>());
162 widget_
->Invalidate();
165 virtual void willEndLiveResize() {
168 virtual void animate(double frameBeginTime
) {
171 virtual void layout() {
174 virtual void paint(WebCanvas
* canvas
, const WebRect
& rect
, PaintOptions
) {
175 if (!widget_
->plugin())
178 SkAutoCanvasRestore
auto_restore(canvas
, true);
179 float canvas_scale
= widget_
->deviceScaleFactor();
180 canvas
->scale(canvas_scale
, canvas_scale
);
182 WebRect
plugin_rect(0, 0, size_
.width
, size_
.height
);
183 widget_
->plugin()->Paint(canvas
, plugin_rect
, rect
);
186 virtual void setCompositorSurfaceReady() {
189 virtual void composite(bool finish
) {
192 virtual void themeChanged() {
196 virtual bool handleInputEvent(const WebInputEvent
& event
) {
197 if (!widget_
->plugin())
200 // This cursor info is ignored, we always set the cursor directly from
201 // RenderWidgetFullscreenPepper::DidChangeCursor.
202 WebCursorInfo cursor
;
204 // Pepper plugins do not accept gesture events. So do not send the gesture
205 // events directly to the plugin. Instead, try to convert them to equivalent
206 // mouse events, and then send to the plugin.
207 if (WebInputEvent::isGestureEventType(event
.type
)) {
209 const WebGestureEvent
* gesture_event
=
210 static_cast<const WebGestureEvent
*>(&event
);
211 switch (event
.type
) {
212 case WebInputEvent::GestureTap
: {
215 mouse
.timeStampSeconds
= gesture_event
->timeStampSeconds
;
216 mouse
.type
= WebInputEvent::MouseMove
;
217 mouse
.modifiers
= gesture_event
->modifiers
;
219 mouse
.x
= gesture_event
->x
;
220 mouse
.y
= gesture_event
->y
;
221 mouse
.windowX
= gesture_event
->globalX
;
222 mouse
.windowY
= gesture_event
->globalY
;
223 mouse
.globalX
= gesture_event
->globalX
;
224 mouse
.globalY
= gesture_event
->globalY
;
227 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
229 mouse
.type
= WebInputEvent::MouseDown
;
230 mouse
.button
= WebMouseEvent::ButtonLeft
;
231 mouse
.clickCount
= gesture_event
->data
.tap
.tapCount
;
232 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
234 mouse
.type
= WebInputEvent::MouseUp
;
235 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
240 WebMouseEvent mouse
= WebMouseEventFromGestureEvent(*gesture_event
);
241 if (mouse
.type
!= WebInputEvent::Undefined
)
242 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
249 bool result
= widget_
->plugin()->HandleInputEvent(event
, &cursor
);
251 // For normal web pages, WebViewImpl does input event translations and
252 // generates context menu events. Since we don't have a WebView, we need to
253 // do the necessary translation ourselves.
254 if (WebInputEvent::isMouseEventType(event
.type
)) {
255 const WebMouseEvent
& mouse_event
=
256 reinterpret_cast<const WebMouseEvent
&>(event
);
257 bool send_context_menu_event
= false;
258 // On Mac/Linux, we handle it on mouse down.
259 // On Windows, we handle it on mouse up.
261 send_context_menu_event
=
262 mouse_event
.type
== WebInputEvent::MouseUp
&&
263 mouse_event
.button
== WebMouseEvent::ButtonRight
;
264 #elif defined(OS_MACOSX)
265 send_context_menu_event
=
266 mouse_event
.type
== WebInputEvent::MouseDown
&&
267 (mouse_event
.button
== WebMouseEvent::ButtonRight
||
268 (mouse_event
.button
== WebMouseEvent::ButtonLeft
&&
269 mouse_event
.modifiers
& WebMouseEvent::ControlKey
));
271 send_context_menu_event
=
272 mouse_event
.type
== WebInputEvent::MouseDown
&&
273 mouse_event
.button
== WebMouseEvent::ButtonRight
;
275 if (send_context_menu_event
) {
276 WebMouseEvent
context_menu_event(mouse_event
);
277 context_menu_event
.type
= WebInputEvent::ContextMenu
;
278 widget_
->plugin()->HandleInputEvent(context_menu_event
, &cursor
);
284 virtual void mouseCaptureLost() {
287 virtual void setFocus(bool focus
) {
290 // TODO(piman): figure out IME and implement these if necessary.
291 virtual bool setComposition(
292 const WebString
& text
,
293 const WebVector
<WebCompositionUnderline
>& underlines
,
299 virtual bool confirmComposition() {
303 virtual bool compositionRange(size_t* location
, size_t* length
) {
307 virtual bool confirmComposition(const WebString
& text
) {
311 virtual WebTextInputType
textInputType() {
312 return WebKit::WebTextInputTypeNone
;
315 virtual WebRect
caretOrSelectionBounds() {
319 virtual bool selectionRange(WebPoint
& start
, WebPoint
& end
) const {
323 virtual bool caretOrSelectionRange(size_t* location
, size_t* length
) {
327 virtual void setTextDirection(WebTextDirection
) {
330 virtual bool isAcceleratedCompositingActive() const {
331 return widget_
->plugin() && widget_
->is_compositing();
335 RenderWidgetFullscreenPepper
* widget_
;
338 DISALLOW_COPY_AND_ASSIGN(PepperWidget
);
341 } // anonymous namespace
344 RenderWidgetFullscreenPepper
* RenderWidgetFullscreenPepper::Create(
346 PepperPluginInstanceImpl
* plugin
,
347 const GURL
& active_url
,
348 const WebKit::WebScreenInfo
& screen_info
) {
349 DCHECK_NE(MSG_ROUTING_NONE
, opener_id
);
350 scoped_refptr
<RenderWidgetFullscreenPepper
> widget(
351 new RenderWidgetFullscreenPepper(plugin
, active_url
, screen_info
));
352 widget
->Init(opener_id
);
357 RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper(
358 PepperPluginInstanceImpl
* plugin
,
359 const GURL
& active_url
,
360 const WebKit::WebScreenInfo
& screen_info
)
361 : RenderWidgetFullscreen(screen_info
),
362 active_url_(active_url
),
365 mouse_lock_dispatcher_(new FullscreenMouseLockDispatcher(
369 RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() {
372 void RenderWidgetFullscreenPepper::Invalidate() {
373 InvalidateRect(gfx::Rect(size_
.width(), size_
.height()));
376 void RenderWidgetFullscreenPepper::InvalidateRect(const WebKit::WebRect
& rect
) {
377 didInvalidateRect(rect
);
380 void RenderWidgetFullscreenPepper::ScrollRect(
381 int dx
, int dy
, const WebKit::WebRect
& rect
) {
382 didScrollRect(dx
, dy
, rect
);
385 void RenderWidgetFullscreenPepper::Destroy() {
386 // This function is called by the plugin instance as it's going away, so reset
387 // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close().
390 // After calling Destroy(), the plugin instance assumes that the layer is not
391 // used by us anymore, so it may destroy the layer before this object goes
395 Send(new ViewHostMsg_Close(routing_id_
));
399 void RenderWidgetFullscreenPepper::DidChangeCursor(
400 const WebKit::WebCursorInfo
& cursor
) {
401 didChangeCursor(cursor
);
404 void RenderWidgetFullscreenPepper::SetLayer(WebKit::WebLayer
* layer
) {
406 bool compositing
= !!layer_
;
407 if (compositing
!= is_accelerated_compositing_active_
) {
409 initializeLayerTreeView();
410 if (!layerTreeView())
412 layer_
->setBounds(WebKit::WebSize(size()));
413 layer_
->setDrawsContent(true);
414 compositor_
->setDeviceScaleFactor(device_scale_factor_
);
415 compositor_
->setRootLayer(*layer_
);
416 didActivateCompositor(-1);
418 didDeactivateCompositor();
423 bool RenderWidgetFullscreenPepper::OnMessageReceived(const IPC::Message
& msg
) {
425 IPC_BEGIN_MESSAGE_MAP(RenderWidgetFullscreenPepper
, msg
)
426 IPC_MESSAGE_FORWARD(ViewMsg_LockMouse_ACK
,
427 mouse_lock_dispatcher_
.get(),
428 MouseLockDispatcher::OnLockMouseACK
)
429 IPC_MESSAGE_FORWARD(ViewMsg_MouseLockLost
,
430 mouse_lock_dispatcher_
.get(),
431 MouseLockDispatcher::OnMouseLockLost
)
432 IPC_MESSAGE_UNHANDLED(handled
= false)
433 IPC_END_MESSAGE_MAP()
437 return RenderWidgetFullscreen::OnMessageReceived(msg
);
440 void RenderWidgetFullscreenPepper::DidInitiatePaint() {
442 plugin_
->ViewInitiatedPaint();
445 void RenderWidgetFullscreenPepper::DidFlushPaint() {
447 plugin_
->ViewFlushedPaint();
450 void RenderWidgetFullscreenPepper::Close() {
451 // If the fullscreen window is closed (e.g. user pressed escape), reset to
454 plugin_
->FlashSetFullscreen(false, false);
456 // Call Close on the base class to destroy the WebWidget instance.
457 RenderWidget::Close();
460 PepperPluginInstanceImpl
*
461 RenderWidgetFullscreenPepper::GetBitmapForOptimizedPluginPaint(
462 const gfx::Rect
& paint_bounds
,
466 float* scale_factor
) {
467 if (plugin_
&& plugin_
->GetBitmapForOptimizedPluginPaint(
468 paint_bounds
, dib
, location
, clip
, scale_factor
)) {
474 void RenderWidgetFullscreenPepper::OnResize(
475 const ViewMsg_Resize_Params
& params
) {
477 layer_
->setBounds(WebKit::WebSize(params
.new_size
));
478 RenderWidget::OnResize(params
);
481 WebWidget
* RenderWidgetFullscreenPepper::CreateWebWidget() {
482 return new PepperWidget(this);
485 GURL
RenderWidgetFullscreenPepper::GetURLForGraphicsContext3D() {
489 void RenderWidgetFullscreenPepper::SetDeviceScaleFactor(
490 float device_scale_factor
) {
491 RenderWidget::SetDeviceScaleFactor(device_scale_factor
);
493 compositor_
->setDeviceScaleFactor(device_scale_factor
);
496 } // namespace content