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.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_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/Source/Platform/chromium/public/WebCanvas.h"
21 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
22 #include "third_party/WebKit/Source/Platform/chromium/public/WebLayer.h"
23 #include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h"
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebWidget.h"
26 #include "ui/gfx/size_conversions.h"
27 #include "ui/gl/gpu_preference.h"
28 #include "webkit/plugins/ppapi/plugin_delegate.h"
29 #include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
31 using WebKit::WebCanvas
;
32 using WebKit::WebCompositionUnderline
;
33 using WebKit::WebCursorInfo
;
34 using WebKit::WebGestureEvent
;
35 using WebKit::WebInputEvent
;
36 using WebKit::WebMouseEvent
;
37 using WebKit::WebMouseWheelEvent
;
38 using WebKit::WebPoint
;
39 using WebKit::WebRect
;
40 using WebKit::WebSize
;
41 using WebKit::WebString
;
42 using WebKit::WebTextDirection
;
43 using WebKit::WebTextInputType
;
44 using WebKit::WebVector
;
45 using WebKit::WebWidget
;
46 using WebKit::WGC3Dintptr
;
52 // See third_party/WebKit/Source/WebCore/dom/WheelEvent.h.
53 const float kTickDivisor
= 120.0f
;
55 class FullscreenMouseLockDispatcher
: public MouseLockDispatcher
{
57 explicit FullscreenMouseLockDispatcher(RenderWidgetFullscreenPepper
* widget
);
58 virtual ~FullscreenMouseLockDispatcher();
61 // MouseLockDispatcher implementation.
62 virtual void SendLockMouseRequest(bool unlocked_by_target
) OVERRIDE
;
63 virtual void SendUnlockMouseRequest() OVERRIDE
;
65 RenderWidgetFullscreenPepper
* widget_
;
67 DISALLOW_COPY_AND_ASSIGN(FullscreenMouseLockDispatcher
);
70 WebMouseEvent
WebMouseEventFromGestureEvent(const WebGestureEvent
& gesture
) {
73 switch (gesture
.type
) {
74 case WebInputEvent::GestureScrollBegin
:
75 mouse
.type
= WebInputEvent::MouseDown
;
78 case WebInputEvent::GestureScrollUpdate
:
79 mouse
.type
= WebInputEvent::MouseMove
;
82 case WebInputEvent::GestureFlingStart
:
83 if (gesture
.sourceDevice
== WebGestureEvent::Touchscreen
) {
84 // A scroll gesture on the touchscreen may end with a GestureScrollEnd
85 // when there is no velocity, or a GestureFlingStart when it has a
86 // velocity. In both cases, it should end the drag that was initiated by
87 // the GestureScrollBegin (and subsequent GestureScrollUpdate) events.
88 mouse
.type
= WebInputEvent::MouseUp
;
93 case WebInputEvent::GestureScrollEnd
:
94 mouse
.type
= WebInputEvent::MouseUp
;
101 if (mouse
.type
== WebInputEvent::Undefined
)
104 mouse
.timeStampSeconds
= gesture
.timeStampSeconds
;
105 mouse
.modifiers
= gesture
.modifiers
| WebInputEvent::LeftButtonDown
;
106 mouse
.button
= WebMouseEvent::ButtonLeft
;
107 mouse
.clickCount
= (mouse
.type
== WebInputEvent::MouseDown
||
108 mouse
.type
== WebInputEvent::MouseUp
);
112 mouse
.windowX
= gesture
.globalX
;
113 mouse
.windowY
= gesture
.globalY
;
114 mouse
.globalX
= gesture
.globalX
;
115 mouse
.globalY
= gesture
.globalY
;
120 FullscreenMouseLockDispatcher::FullscreenMouseLockDispatcher(
121 RenderWidgetFullscreenPepper
* widget
) : widget_(widget
) {
124 FullscreenMouseLockDispatcher::~FullscreenMouseLockDispatcher() {
127 void FullscreenMouseLockDispatcher::SendLockMouseRequest(
128 bool unlocked_by_target
) {
129 widget_
->Send(new ViewHostMsg_LockMouse(widget_
->routing_id(), false,
130 unlocked_by_target
, true));
133 void FullscreenMouseLockDispatcher::SendUnlockMouseRequest() {
134 widget_
->Send(new ViewHostMsg_UnlockMouse(widget_
->routing_id()));
137 // WebWidget that simply wraps the pepper plugin.
138 class PepperWidget
: public WebWidget
{
140 explicit PepperWidget(RenderWidgetFullscreenPepper
* widget
)
144 virtual ~PepperWidget() {}
147 virtual void close() {
151 virtual WebSize
size() {
155 virtual void willStartLiveResize() {
158 virtual void resize(const WebSize
& size
) {
159 if (!widget_
->plugin())
163 WebRect
plugin_rect(0, 0, size_
.width
, size_
.height
);
164 widget_
->plugin()->ViewChanged(plugin_rect
, plugin_rect
,
165 std::vector
<gfx::Rect
>());
166 widget_
->Invalidate();
169 virtual void willEndLiveResize() {
172 virtual void animate(double frameBeginTime
) {
175 virtual void layout() {
178 virtual void paint(WebCanvas
* canvas
, const WebRect
& rect
, PaintOptions
) {
179 if (!widget_
->plugin())
182 SkAutoCanvasRestore
auto_restore(canvas
, true);
183 float canvas_scale
= widget_
->deviceScaleFactor();
184 canvas
->scale(canvas_scale
, canvas_scale
);
186 WebRect
plugin_rect(0, 0, size_
.width
, size_
.height
);
187 widget_
->plugin()->Paint(canvas
, plugin_rect
, rect
);
190 virtual void setCompositorSurfaceReady() {
193 virtual void composite(bool finish
) {
196 virtual void themeChanged() {
200 virtual bool handleInputEvent(const WebInputEvent
& event
) {
201 if (!widget_
->plugin())
204 // This cursor info is ignored, we always set the cursor directly from
205 // RenderWidgetFullscreenPepper::DidChangeCursor.
206 WebCursorInfo cursor
;
208 // Pepper plugins do not accept gesture events. So do not send the gesture
209 // events directly to the plugin. Instead, try to convert them to equivalent
210 // mouse events, and then send to the plugin.
211 if (WebInputEvent::isGestureEventType(event
.type
)) {
213 const WebGestureEvent
* gesture_event
=
214 static_cast<const WebGestureEvent
*>(&event
);
215 switch (event
.type
) {
216 case WebInputEvent::GestureTap
: {
219 mouse
.timeStampSeconds
= gesture_event
->timeStampSeconds
;
220 mouse
.type
= WebInputEvent::MouseMove
;
221 mouse
.modifiers
= gesture_event
->modifiers
;
223 mouse
.x
= gesture_event
->x
;
224 mouse
.y
= gesture_event
->y
;
225 mouse
.windowX
= gesture_event
->globalX
;
226 mouse
.windowY
= gesture_event
->globalY
;
227 mouse
.globalX
= gesture_event
->globalX
;
228 mouse
.globalY
= gesture_event
->globalY
;
231 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
233 mouse
.type
= WebInputEvent::MouseDown
;
234 mouse
.button
= WebMouseEvent::ButtonLeft
;
235 mouse
.clickCount
= gesture_event
->data
.tap
.tapCount
;
236 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
238 mouse
.type
= WebInputEvent::MouseUp
;
239 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
244 WebMouseEvent mouse
= WebMouseEventFromGestureEvent(*gesture_event
);
245 if (mouse
.type
!= WebInputEvent::Undefined
)
246 result
|= widget_
->plugin()->HandleInputEvent(mouse
, &cursor
);
253 bool result
= widget_
->plugin()->HandleInputEvent(event
, &cursor
);
255 // For normal web pages, WebViewImpl does input event translations and
256 // generates context menu events. Since we don't have a WebView, we need to
257 // do the necessary translation ourselves.
258 if (WebInputEvent::isMouseEventType(event
.type
)) {
259 const WebMouseEvent
& mouse_event
=
260 reinterpret_cast<const WebMouseEvent
&>(event
);
261 bool send_context_menu_event
= false;
262 // On Mac/Linux, we handle it on mouse down.
263 // On Windows, we handle it on mouse up.
265 send_context_menu_event
=
266 mouse_event
.type
== WebInputEvent::MouseUp
&&
267 mouse_event
.button
== WebMouseEvent::ButtonRight
;
268 #elif defined(OS_MACOSX)
269 send_context_menu_event
=
270 mouse_event
.type
== WebInputEvent::MouseDown
&&
271 (mouse_event
.button
== WebMouseEvent::ButtonRight
||
272 (mouse_event
.button
== WebMouseEvent::ButtonLeft
&&
273 mouse_event
.modifiers
& WebMouseEvent::ControlKey
));
275 send_context_menu_event
=
276 mouse_event
.type
== WebInputEvent::MouseDown
&&
277 mouse_event
.button
== WebMouseEvent::ButtonRight
;
279 if (send_context_menu_event
) {
280 WebMouseEvent
context_menu_event(mouse_event
);
281 context_menu_event
.type
= WebInputEvent::ContextMenu
;
282 widget_
->plugin()->HandleInputEvent(context_menu_event
, &cursor
);
288 virtual void mouseCaptureLost() {
292 virtual void setFocus(bool focus
) {
296 // TODO(piman): figure out IME and implement these if necessary.
297 virtual bool setComposition(
298 const WebString
& text
,
299 const WebVector
<WebCompositionUnderline
>& underlines
,
305 virtual bool confirmComposition() {
309 virtual bool compositionRange(size_t* location
, size_t* length
) {
313 virtual bool confirmComposition(const WebString
& text
) {
317 virtual WebTextInputType
textInputType() {
318 return WebKit::WebTextInputTypeNone
;
321 virtual WebRect
caretOrSelectionBounds() {
325 virtual bool selectionRange(WebPoint
& start
, WebPoint
& end
) const {
329 virtual bool caretOrSelectionRange(size_t* location
, size_t* length
) {
333 virtual void setTextDirection(WebTextDirection
) {
336 virtual bool isAcceleratedCompositingActive() const {
337 return widget_
->plugin() && widget_
->is_compositing();
341 RenderWidgetFullscreenPepper
* widget_
;
344 DISALLOW_COPY_AND_ASSIGN(PepperWidget
);
347 } // anonymous namespace
350 RenderWidgetFullscreenPepper
* RenderWidgetFullscreenPepper::Create(
351 int32 opener_id
, webkit::ppapi::PluginInstance
* plugin
,
352 const GURL
& active_url
,
353 const WebKit::WebScreenInfo
& screen_info
) {
354 DCHECK_NE(MSG_ROUTING_NONE
, opener_id
);
355 scoped_refptr
<RenderWidgetFullscreenPepper
> widget(
356 new RenderWidgetFullscreenPepper(plugin
, active_url
, screen_info
));
357 widget
->Init(opener_id
);
362 RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper(
363 webkit::ppapi::PluginInstance
* plugin
,
364 const GURL
& active_url
,
365 const WebKit::WebScreenInfo
& screen_info
)
366 : RenderWidgetFullscreen(screen_info
),
367 active_url_(active_url
),
370 mouse_lock_dispatcher_(new FullscreenMouseLockDispatcher(
371 ALLOW_THIS_IN_INITIALIZER_LIST(this))) {
374 RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() {
377 void RenderWidgetFullscreenPepper::Invalidate() {
378 InvalidateRect(gfx::Rect(size_
.width(), size_
.height()));
381 void RenderWidgetFullscreenPepper::InvalidateRect(const WebKit::WebRect
& rect
) {
382 didInvalidateRect(rect
);
385 void RenderWidgetFullscreenPepper::ScrollRect(
386 int dx
, int dy
, const WebKit::WebRect
& rect
) {
387 didScrollRect(dx
, dy
, rect
);
390 void RenderWidgetFullscreenPepper::Destroy() {
391 // This function is called by the plugin instance as it's going away, so reset
392 // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close().
394 Send(new ViewHostMsg_Close(routing_id_
));
398 void RenderWidgetFullscreenPepper::DidChangeCursor(
399 const WebKit::WebCursorInfo
& cursor
) {
400 didChangeCursor(cursor
);
403 webkit::ppapi::PluginDelegate::PlatformContext3D
*
404 RenderWidgetFullscreenPepper::CreateContext3D() {
405 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
406 if (command_line
->HasSwitch(switches::kDisableFlashFullscreen3d
))
408 return new PlatformContext3DImpl
;
411 void RenderWidgetFullscreenPepper::ReparentContext(
412 webkit::ppapi::PluginDelegate::PlatformContext3D
* context
) {
413 PlatformContext3DImpl
* context_impl
=
414 static_cast<PlatformContext3DImpl
*>(context
);
416 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
417 if (command_line
->HasSwitch(switches::kDisableFlashFullscreen3d
))
418 context_impl
->DestroyParentContextProviderAndBackingTexture();
420 context_impl
->SetParentAndCreateBackingTextureIfNeeded();
423 void RenderWidgetFullscreenPepper::SetLayer(WebKit::WebLayer
* layer
) {
425 bool compositing
= !!layer_
;
426 if (compositing
!= is_accelerated_compositing_active_
) {
428 initializeLayerTreeView();
429 if (!layerTreeView())
431 layer_
->setBounds(WebKit::WebSize(size()));
432 layer_
->setDrawsContent(true);
433 compositor_
->setDeviceScaleFactor(device_scale_factor_
);
434 compositor_
->setRootLayer(*layer_
);
435 didActivateCompositor(-1);
437 didDeactivateCompositor();
442 bool RenderWidgetFullscreenPepper::OnMessageReceived(const IPC::Message
& msg
) {
444 IPC_BEGIN_MESSAGE_MAP(RenderWidgetFullscreenPepper
, msg
)
445 IPC_MESSAGE_FORWARD(ViewMsg_LockMouse_ACK
,
446 mouse_lock_dispatcher_
.get(),
447 MouseLockDispatcher::OnLockMouseACK
)
448 IPC_MESSAGE_FORWARD(ViewMsg_MouseLockLost
,
449 mouse_lock_dispatcher_
.get(),
450 MouseLockDispatcher::OnMouseLockLost
)
451 IPC_MESSAGE_UNHANDLED(handled
= false)
452 IPC_END_MESSAGE_MAP()
456 return RenderWidgetFullscreen::OnMessageReceived(msg
);
459 void RenderWidgetFullscreenPepper::WillInitiatePaint() {
461 plugin_
->ViewWillInitiatePaint();
464 void RenderWidgetFullscreenPepper::DidInitiatePaint() {
466 plugin_
->ViewInitiatedPaint();
469 void RenderWidgetFullscreenPepper::DidFlushPaint() {
471 plugin_
->ViewFlushedPaint();
474 void RenderWidgetFullscreenPepper::Close() {
475 // If the fullscreen window is closed (e.g. user pressed escape), reset to
478 plugin_
->FlashSetFullscreen(false, false);
480 // Call Close on the base class to destroy the WebWidget instance.
481 RenderWidget::Close();
484 webkit::ppapi::PluginInstance
*
485 RenderWidgetFullscreenPepper::GetBitmapForOptimizedPluginPaint(
486 const gfx::Rect
& paint_bounds
,
490 float* scale_factor
) {
491 if (plugin_
&& plugin_
->GetBitmapForOptimizedPluginPaint(
492 paint_bounds
, dib
, location
, clip
, scale_factor
)) {
498 void RenderWidgetFullscreenPepper::OnResize(const gfx::Size
& size
,
499 const gfx::Size
& physical_backing_size
,
500 float overdraw_bottom_height
,
501 const gfx::Rect
& resizer_rect
,
502 bool is_fullscreen
) {
504 layer_
->setBounds(WebKit::WebSize(size
));
505 RenderWidget::OnResize(size
, physical_backing_size
, overdraw_bottom_height
,
506 resizer_rect
, is_fullscreen
);
509 WebWidget
* RenderWidgetFullscreenPepper::CreateWebWidget() {
510 return new PepperWidget(this);
513 GURL
RenderWidgetFullscreenPepper::GetURLForGraphicsContext3D() {
517 void RenderWidgetFullscreenPepper::SetDeviceScaleFactor(
518 float device_scale_factor
) {
519 RenderWidget::SetDeviceScaleFactor(device_scale_factor
);
521 compositor_
->setDeviceScaleFactor(device_scale_factor
);
524 } // namespace content