Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / render_widget_fullscreen_pepper.cc
blob29bc75950cbfba5d1f56530c9c1a068c734df181
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"
7 #include <vector>
9 #include "base/bind.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;
37 using blink::WebRect;
38 using blink::WebSize;
39 using blink::WebString;
40 using blink::WebTextDirection;
41 using blink::WebTextInputType;
42 using blink::WebVector;
43 using blink::WebWidget;
44 using blink::WGC3Dintptr;
46 namespace content {
48 namespace {
50 class FullscreenMouseLockDispatcher : public MouseLockDispatcher {
51 public:
52 explicit FullscreenMouseLockDispatcher(RenderWidgetFullscreenPepper* widget);
53 ~FullscreenMouseLockDispatcher() override;
55 private:
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) {
66 WebMouseEvent mouse;
68 switch (gesture.type) {
69 case WebInputEvent::GestureScrollBegin:
70 mouse.type = WebInputEvent::MouseDown;
71 break;
73 case WebInputEvent::GestureScrollUpdate:
74 mouse.type = WebInputEvent::MouseMove;
75 break;
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;
84 break;
85 } else {
86 return mouse;
88 case WebInputEvent::GestureScrollEnd:
89 mouse.type = WebInputEvent::MouseUp;
90 break;
92 default:
93 break;
96 if (mouse.type == WebInputEvent::Undefined)
97 return mouse;
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);
105 mouse.x = gesture.x;
106 mouse.y = gesture.y;
107 mouse.windowX = gesture.globalX;
108 mouse.windowY = gesture.globalY;
109 mouse.globalX = gesture.globalX;
110 mouse.globalY = gesture.globalY;
112 return mouse;
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
134 // necessary.
135 class PepperWidget : public WebWidget {
136 public:
137 explicit PepperWidget(RenderWidgetFullscreenPepper* widget)
138 : widget_(widget) {
141 virtual ~PepperWidget() {}
143 // WebWidget API
144 virtual void close() {
145 delete this;
148 virtual WebSize size() {
149 return size_;
152 virtual void resize(const WebSize& size) {
153 if (!widget_->plugin())
154 return;
156 size_ = size;
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() {
164 NOTIMPLEMENTED();
167 virtual bool handleInputEvent(const WebInputEvent& event) {
168 if (!widget_->plugin())
169 return false;
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)) {
179 bool result = false;
180 const WebGestureEvent* gesture_event =
181 static_cast<const WebGestureEvent*>(&event);
182 switch (event.type) {
183 case WebInputEvent::GestureTap: {
184 WebMouseEvent mouse;
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;
196 mouse.movementX = 0;
197 mouse.movementY = 0;
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);
207 break;
210 default: {
211 WebMouseEvent mouse = WebMouseEventFromGestureEvent(*gesture_event);
212 if (mouse.type != WebInputEvent::Undefined)
213 result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
214 break;
217 return result;
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.
231 #if defined(OS_WIN)
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));
241 #else
242 send_context_menu_event =
243 mouse_event.type == WebInputEvent::MouseDown &&
244 mouse_event.button == WebMouseEvent::ButtonRight;
245 #endif
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);
252 return result;
255 private:
256 RenderWidgetFullscreenPepper* widget_;
257 WebSize size_;
259 DISALLOW_COPY_AND_ASSIGN(PepperWidget);
262 } // anonymous namespace
264 // static
265 RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create(
266 int32 opener_id,
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(plugin, active_url, screen_info));
274 widget->Init(opener_id, compositor_deps);
275 widget->AddRef();
276 return widget.get();
279 RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper(
280 PepperPluginInstanceImpl* plugin,
281 const GURL& active_url,
282 const blink::WebScreenInfo& screen_info)
283 : RenderWidgetFullscreen(screen_info),
284 active_url_(active_url),
285 plugin_(plugin),
286 layer_(NULL),
287 mouse_lock_dispatcher_(new FullscreenMouseLockDispatcher(
288 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().
309 plugin_ = NULL;
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
313 // away.
314 SetLayer(NULL);
316 Send(new ViewHostMsg_Close(routing_id_));
317 Release();
320 void RenderWidgetFullscreenPepper::DidChangeCursor(
321 const blink::WebCursorInfo& cursor) {
322 didChangeCursor(cursor);
325 void RenderWidgetFullscreenPepper::SetLayer(blink::WebLayer* layer) {
326 layer_ = layer;
327 if (!layer_) {
328 if (compositor_)
329 compositor_->clearRootLayer();
330 return;
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) {
341 bool handled = true;
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()
351 if (handled)
352 return true;
354 return RenderWidgetFullscreen::OnMessageReceived(msg);
357 void RenderWidgetFullscreenPepper::DidInitiatePaint() {
358 if (plugin_)
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
367 // normal mode.
368 if (plugin_)
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) {
377 if (layer_)
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() {
387 return active_url_;
390 void RenderWidgetFullscreenPepper::SetDeviceScaleFactor(
391 float device_scale_factor) {
392 RenderWidget::SetDeviceScaleFactor(device_scale_factor);
393 if (compositor_)
394 compositor_->setDeviceScaleFactor(device_scale_factor);
397 } // namespace content