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/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 virtual ~FullscreenMouseLockDispatcher();
56 // MouseLockDispatcher implementation.
57 virtual void SendLockMouseRequest(bool unlocked_by_target
) override
;
58 virtual 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
.globalX
;
108 mouse
.windowY
= gesture
.globalY
;
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
,
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
->globalX
;
193 mouse
.windowY
= gesture_event
->globalY
;
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 PepperPluginInstanceImpl
* plugin
,
268 const GURL
& active_url
,
269 const blink::WebScreenInfo
& screen_info
) {
270 DCHECK_NE(MSG_ROUTING_NONE
, opener_id
);
271 scoped_refptr
<RenderWidgetFullscreenPepper
> widget(
272 new RenderWidgetFullscreenPepper(plugin
, active_url
, screen_info
));
273 widget
->Init(opener_id
);
278 RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper(
279 PepperPluginInstanceImpl
* plugin
,
280 const GURL
& active_url
,
281 const blink::WebScreenInfo
& screen_info
)
282 : RenderWidgetFullscreen(screen_info
),
283 active_url_(active_url
),
286 mouse_lock_dispatcher_(new FullscreenMouseLockDispatcher(
290 RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() {
293 void RenderWidgetFullscreenPepper::Invalidate() {
294 InvalidateRect(gfx::Rect(size_
.width(), size_
.height()));
297 void RenderWidgetFullscreenPepper::InvalidateRect(const blink::WebRect
& rect
) {
298 didInvalidateRect(rect
);
301 void RenderWidgetFullscreenPepper::ScrollRect(
302 int dx
, int dy
, const blink::WebRect
& rect
) {
305 void RenderWidgetFullscreenPepper::Destroy() {
306 // This function is called by the plugin instance as it's going away, so reset
307 // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close().
310 // After calling Destroy(), the plugin instance assumes that the layer is not
311 // used by us anymore, so it may destroy the layer before this object goes
315 Send(new ViewHostMsg_Close(routing_id_
));
319 void RenderWidgetFullscreenPepper::DidChangeCursor(
320 const blink::WebCursorInfo
& cursor
) {
321 didChangeCursor(cursor
);
324 void RenderWidgetFullscreenPepper::SetLayer(blink::WebLayer
* layer
) {
328 compositor_
->clearRootLayer();
331 if (!layerTreeView())
332 initializeLayerTreeView();
333 layer_
->setBounds(blink::WebSize(size()));
334 layer_
->setDrawsContent(true);
335 compositor_
->setDeviceScaleFactor(device_scale_factor_
);
336 compositor_
->setRootLayer(*layer_
);
339 bool RenderWidgetFullscreenPepper::OnMessageReceived(const IPC::Message
& msg
) {
341 IPC_BEGIN_MESSAGE_MAP(RenderWidgetFullscreenPepper
, msg
)
342 IPC_MESSAGE_FORWARD(ViewMsg_LockMouse_ACK
,
343 mouse_lock_dispatcher_
.get(),
344 MouseLockDispatcher::OnLockMouseACK
)
345 IPC_MESSAGE_FORWARD(ViewMsg_MouseLockLost
,
346 mouse_lock_dispatcher_
.get(),
347 MouseLockDispatcher::OnMouseLockLost
)
348 IPC_MESSAGE_UNHANDLED(handled
= false)
349 IPC_END_MESSAGE_MAP()
353 return RenderWidgetFullscreen::OnMessageReceived(msg
);
356 void RenderWidgetFullscreenPepper::DidInitiatePaint() {
358 plugin_
->ViewInitiatedPaint();
361 void RenderWidgetFullscreenPepper::DidFlushPaint() {
363 plugin_
->ViewFlushedPaint();
366 void RenderWidgetFullscreenPepper::Close() {
367 // If the fullscreen window is closed (e.g. user pressed escape), reset to
370 plugin_
->FlashSetFullscreen(false, false);
372 // Call Close on the base class to destroy the WebWidget instance.
373 RenderWidget::Close();
376 void RenderWidgetFullscreenPepper::OnResize(
377 const ViewMsg_Resize_Params
& params
) {
379 layer_
->setBounds(blink::WebSize(params
.new_size
));
380 RenderWidget::OnResize(params
);
383 WebWidget
* RenderWidgetFullscreenPepper::CreateWebWidget() {
384 return new PepperWidget(this);
387 GURL
RenderWidgetFullscreenPepper::GetURLForGraphicsContext3D() {
391 void RenderWidgetFullscreenPepper::SetDeviceScaleFactor(
392 float device_scale_factor
) {
393 RenderWidget::SetDeviceScaleFactor(device_scale_factor
);
395 compositor_
->setDeviceScaleFactor(device_scale_factor
);
398 } // namespace content