- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / render_widget_fullscreen_pepper.cc
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.
4
5 #include "content/renderer/render_widget_fullscreen_pepper.h"
6
7 #include <vector>
8
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_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"
29
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;
46
47 namespace content {
48
49 namespace {
50
51 class FullscreenMouseLockDispatcher : public MouseLockDispatcher {
52  public:
53   explicit FullscreenMouseLockDispatcher(RenderWidgetFullscreenPepper* widget);
54   virtual ~FullscreenMouseLockDispatcher();
55
56  private:
57   // MouseLockDispatcher implementation.
58   virtual void SendLockMouseRequest(bool unlocked_by_target) OVERRIDE;
59   virtual void SendUnlockMouseRequest() OVERRIDE;
60
61   RenderWidgetFullscreenPepper* widget_;
62
63   DISALLOW_COPY_AND_ASSIGN(FullscreenMouseLockDispatcher);
64 };
65
66 WebMouseEvent WebMouseEventFromGestureEvent(const WebGestureEvent& gesture) {
67   WebMouseEvent mouse;
68
69   switch (gesture.type) {
70     case WebInputEvent::GestureScrollBegin:
71       mouse.type = WebInputEvent::MouseDown;
72       break;
73
74     case WebInputEvent::GestureScrollUpdate:
75       mouse.type = WebInputEvent::MouseMove;
76       break;
77
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;
85         break;
86       } else {
87         return mouse;
88       }
89     case WebInputEvent::GestureScrollEnd:
90       mouse.type = WebInputEvent::MouseUp;
91       break;
92
93     default:
94       break;
95   }
96
97   if (mouse.type == WebInputEvent::Undefined)
98     return mouse;
99
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);
105
106   mouse.x = gesture.x;
107   mouse.y = gesture.y;
108   mouse.windowX = gesture.globalX;
109   mouse.windowY = gesture.globalY;
110   mouse.globalX = gesture.globalX;
111   mouse.globalY = gesture.globalY;
112
113   return mouse;
114 }
115
116 FullscreenMouseLockDispatcher::FullscreenMouseLockDispatcher(
117     RenderWidgetFullscreenPepper* widget) : widget_(widget) {
118 }
119
120 FullscreenMouseLockDispatcher::~FullscreenMouseLockDispatcher() {
121 }
122
123 void FullscreenMouseLockDispatcher::SendLockMouseRequest(
124     bool unlocked_by_target) {
125   widget_->Send(new ViewHostMsg_LockMouse(widget_->routing_id(), false,
126                                           unlocked_by_target, true));
127 }
128
129 void FullscreenMouseLockDispatcher::SendUnlockMouseRequest() {
130   widget_->Send(new ViewHostMsg_UnlockMouse(widget_->routing_id()));
131 }
132
133 // WebWidget that simply wraps the pepper plugin.
134 class PepperWidget : public WebWidget {
135  public:
136   explicit PepperWidget(RenderWidgetFullscreenPepper* widget)
137       : widget_(widget) {
138   }
139
140   virtual ~PepperWidget() {}
141
142   // WebWidget API
143   virtual void close() {
144     delete this;
145   }
146
147   virtual WebSize size() {
148     return size_;
149   }
150
151   virtual void willStartLiveResize() {
152   }
153
154   virtual void resize(const WebSize& size) {
155     if (!widget_->plugin())
156       return;
157
158     size_ = size;
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();
163   }
164
165   virtual void willEndLiveResize() {
166   }
167
168   virtual void animate(double frameBeginTime) {
169   }
170
171   virtual void layout() {
172   }
173
174   virtual void paint(WebCanvas* canvas, const WebRect& rect, PaintOptions) {
175     if (!widget_->plugin())
176       return;
177
178     SkAutoCanvasRestore auto_restore(canvas, true);
179     float canvas_scale = widget_->deviceScaleFactor();
180     canvas->scale(canvas_scale, canvas_scale);
181
182     WebRect plugin_rect(0, 0, size_.width, size_.height);
183     widget_->plugin()->Paint(canvas, plugin_rect, rect);
184   }
185
186   virtual void setCompositorSurfaceReady() {
187   }
188
189   virtual void composite(bool finish) {
190   }
191
192   virtual void themeChanged() {
193     NOTIMPLEMENTED();
194   }
195
196   virtual bool handleInputEvent(const WebInputEvent& event) {
197     if (!widget_->plugin())
198       return false;
199
200     // This cursor info is ignored, we always set the cursor directly from
201     // RenderWidgetFullscreenPepper::DidChangeCursor.
202     WebCursorInfo cursor;
203
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)) {
208       bool result = false;
209       const WebGestureEvent* gesture_event =
210           static_cast<const WebGestureEvent*>(&event);
211       switch (event.type) {
212         case WebInputEvent::GestureTap: {
213           WebMouseEvent mouse;
214
215           mouse.timeStampSeconds = gesture_event->timeStampSeconds;
216           mouse.type = WebInputEvent::MouseMove;
217           mouse.modifiers = gesture_event->modifiers;
218
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;
225           mouse.movementX = 0;
226           mouse.movementY = 0;
227           result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
228
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);
233
234           mouse.type = WebInputEvent::MouseUp;
235           result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
236           break;
237         }
238
239         default: {
240           WebMouseEvent mouse = WebMouseEventFromGestureEvent(*gesture_event);
241           if (mouse.type != WebInputEvent::Undefined)
242             result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
243           break;
244         }
245       }
246       return result;
247     }
248
249     bool result = widget_->plugin()->HandleInputEvent(event, &cursor);
250
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.
260 #if defined(OS_WIN)
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));
270 #else
271       send_context_menu_event =
272           mouse_event.type == WebInputEvent::MouseDown &&
273           mouse_event.button == WebMouseEvent::ButtonRight;
274 #endif
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);
279       }
280     }
281     return result;
282   }
283
284   virtual void mouseCaptureLost() {
285   }
286
287   virtual void setFocus(bool focus) {
288   }
289
290   // TODO(piman): figure out IME and implement these if necessary.
291   virtual bool setComposition(
292       const WebString& text,
293       const WebVector<WebCompositionUnderline>& underlines,
294       int selectionStart,
295       int selectionEnd) {
296     return false;
297   }
298
299   virtual bool confirmComposition() {
300     return false;
301   }
302
303   virtual bool compositionRange(size_t* location, size_t* length) {
304     return false;
305   }
306
307   virtual bool confirmComposition(const WebString& text) {
308     return false;
309   }
310
311   virtual WebTextInputType textInputType() {
312     return WebKit::WebTextInputTypeNone;
313   }
314
315   virtual WebRect caretOrSelectionBounds() {
316     return WebRect();
317   }
318
319   virtual bool selectionRange(WebPoint& start, WebPoint& end) const {
320     return false;
321   }
322
323   virtual bool caretOrSelectionRange(size_t* location, size_t* length) {
324     return false;
325   }
326
327   virtual void setTextDirection(WebTextDirection) {
328   }
329
330   virtual bool isAcceleratedCompositingActive() const {
331     return widget_->plugin() && widget_->is_compositing();
332   }
333
334  private:
335   RenderWidgetFullscreenPepper* widget_;
336   WebSize size_;
337
338   DISALLOW_COPY_AND_ASSIGN(PepperWidget);
339 };
340
341 }  // anonymous namespace
342
343 // static
344 RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create(
345     int32 opener_id,
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);
353   widget->AddRef();
354   return widget.get();
355 }
356
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),
363       plugin_(plugin),
364       layer_(NULL),
365       mouse_lock_dispatcher_(new FullscreenMouseLockDispatcher(
366           this)) {
367 }
368
369 RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() {
370 }
371
372 void RenderWidgetFullscreenPepper::Invalidate() {
373   InvalidateRect(gfx::Rect(size_.width(), size_.height()));
374 }
375
376 void RenderWidgetFullscreenPepper::InvalidateRect(const WebKit::WebRect& rect) {
377   didInvalidateRect(rect);
378 }
379
380 void RenderWidgetFullscreenPepper::ScrollRect(
381     int dx, int dy, const WebKit::WebRect& rect) {
382   didScrollRect(dx, dy, rect);
383 }
384
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().
388   plugin_ = NULL;
389
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
392   // away.
393   SetLayer(NULL);
394
395   Send(new ViewHostMsg_Close(routing_id_));
396   Release();
397 }
398
399 void RenderWidgetFullscreenPepper::DidChangeCursor(
400     const WebKit::WebCursorInfo& cursor) {
401   didChangeCursor(cursor);
402 }
403
404 void RenderWidgetFullscreenPepper::SetLayer(WebKit::WebLayer* layer) {
405   layer_ = layer;
406   bool compositing = !!layer_;
407   if (compositing != is_accelerated_compositing_active_) {
408     if (compositing) {
409       if (!layerTreeView())
410         initializeLayerTreeView();
411       if (!layerTreeView())
412         return;
413       layer_->setBounds(WebKit::WebSize(size()));
414       layer_->setDrawsContent(true);
415       compositor_->setDeviceScaleFactor(device_scale_factor_);
416       compositor_->setRootLayer(*layer_);
417       didActivateCompositor(-1);
418     } else {
419       didDeactivateCompositor();
420     }
421   }
422 }
423
424 bool RenderWidgetFullscreenPepper::OnMessageReceived(const IPC::Message& msg) {
425   bool handled = true;
426   IPC_BEGIN_MESSAGE_MAP(RenderWidgetFullscreenPepper, msg)
427     IPC_MESSAGE_FORWARD(ViewMsg_LockMouse_ACK,
428                         mouse_lock_dispatcher_.get(),
429                         MouseLockDispatcher::OnLockMouseACK)
430     IPC_MESSAGE_FORWARD(ViewMsg_MouseLockLost,
431                         mouse_lock_dispatcher_.get(),
432                         MouseLockDispatcher::OnMouseLockLost)
433     IPC_MESSAGE_UNHANDLED(handled = false)
434   IPC_END_MESSAGE_MAP()
435   if (handled)
436     return true;
437
438   return RenderWidgetFullscreen::OnMessageReceived(msg);
439 }
440
441 void RenderWidgetFullscreenPepper::DidInitiatePaint() {
442   if (plugin_)
443     plugin_->ViewInitiatedPaint();
444 }
445
446 void RenderWidgetFullscreenPepper::DidFlushPaint() {
447   if (plugin_)
448     plugin_->ViewFlushedPaint();
449 }
450
451 void RenderWidgetFullscreenPepper::Close() {
452   // If the fullscreen window is closed (e.g. user pressed escape), reset to
453   // normal mode.
454   if (plugin_)
455     plugin_->FlashSetFullscreen(false, false);
456
457   // Call Close on the base class to destroy the WebWidget instance.
458   RenderWidget::Close();
459 }
460
461 PepperPluginInstanceImpl*
462     RenderWidgetFullscreenPepper::GetBitmapForOptimizedPluginPaint(
463         const gfx::Rect& paint_bounds,
464         TransportDIB** dib,
465         gfx::Rect* location,
466         gfx::Rect* clip,
467         float* scale_factor) {
468   if (plugin_ && plugin_->GetBitmapForOptimizedPluginPaint(
469           paint_bounds, dib, location, clip, scale_factor)) {
470     return plugin_;
471   }
472   return NULL;
473 }
474
475 void RenderWidgetFullscreenPepper::OnResize(
476     const ViewMsg_Resize_Params& params) {
477   if (layer_)
478     layer_->setBounds(WebKit::WebSize(params.new_size));
479   RenderWidget::OnResize(params);
480 }
481
482 WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() {
483   return new PepperWidget(this);
484 }
485
486 GURL RenderWidgetFullscreenPepper::GetURLForGraphicsContext3D() {
487   return active_url_;
488 }
489
490 void RenderWidgetFullscreenPepper::SetDeviceScaleFactor(
491     float device_scale_factor) {
492   RenderWidget::SetDeviceScaleFactor(device_scale_factor);
493   if (compositor_)
494     compositor_->setDeviceScaleFactor(device_scale_factor);
495 }
496
497 }  // namespace content