Update To 11.40.268.0
[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_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"
28
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;
45
46 namespace content {
47
48 namespace {
49
50 class FullscreenMouseLockDispatcher : public MouseLockDispatcher {
51  public:
52   explicit FullscreenMouseLockDispatcher(RenderWidgetFullscreenPepper* widget);
53   ~FullscreenMouseLockDispatcher() override;
54
55  private:
56   // MouseLockDispatcher implementation.
57   void SendLockMouseRequest(bool unlocked_by_target) override;
58   void SendUnlockMouseRequest() override;
59
60   RenderWidgetFullscreenPepper* widget_;
61
62   DISALLOW_COPY_AND_ASSIGN(FullscreenMouseLockDispatcher);
63 };
64
65 WebMouseEvent WebMouseEventFromGestureEvent(const WebGestureEvent& gesture) {
66   WebMouseEvent mouse;
67
68   switch (gesture.type) {
69     case WebInputEvent::GestureScrollBegin:
70       mouse.type = WebInputEvent::MouseDown;
71       break;
72
73     case WebInputEvent::GestureScrollUpdate:
74       mouse.type = WebInputEvent::MouseMove;
75       break;
76
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;
87       }
88     case WebInputEvent::GestureScrollEnd:
89       mouse.type = WebInputEvent::MouseUp;
90       break;
91
92     default:
93       break;
94   }
95
96   if (mouse.type == WebInputEvent::Undefined)
97     return mouse;
98
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);
104
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;
111
112   return mouse;
113 }
114
115 FullscreenMouseLockDispatcher::FullscreenMouseLockDispatcher(
116     RenderWidgetFullscreenPepper* widget) : widget_(widget) {
117 }
118
119 FullscreenMouseLockDispatcher::~FullscreenMouseLockDispatcher() {
120 }
121
122 void FullscreenMouseLockDispatcher::SendLockMouseRequest(
123     bool unlocked_by_target) {
124   widget_->Send(new ViewHostMsg_LockMouse(widget_->routing_id(), false,
125                                           unlocked_by_target, true));
126 }
127
128 void FullscreenMouseLockDispatcher::SendUnlockMouseRequest() {
129   widget_->Send(new ViewHostMsg_UnlockMouse(widget_->routing_id()));
130 }
131
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) {
139   }
140
141   virtual ~PepperWidget() {}
142
143   // WebWidget API
144   virtual void close() {
145     delete this;
146   }
147
148   virtual WebSize size() {
149     return size_;
150   }
151
152   virtual void resize(const WebSize& size) {
153     if (!widget_->plugin())
154       return;
155
156     size_ = size;
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();
161   }
162
163   virtual void themeChanged() {
164     NOTIMPLEMENTED();
165   }
166
167   virtual bool handleInputEvent(const WebInputEvent& event) {
168     if (!widget_->plugin())
169       return false;
170
171     // This cursor info is ignored, we always set the cursor directly from
172     // RenderWidgetFullscreenPepper::DidChangeCursor.
173     WebCursorInfo cursor;
174
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;
185
186           mouse.timeStampSeconds = gesture_event->timeStampSeconds;
187           mouse.type = WebInputEvent::MouseMove;
188           mouse.modifiers = gesture_event->modifiers;
189
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);
199
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);
204
205           mouse.type = WebInputEvent::MouseUp;
206           result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
207           break;
208         }
209
210         default: {
211           WebMouseEvent mouse = WebMouseEventFromGestureEvent(*gesture_event);
212           if (mouse.type != WebInputEvent::Undefined)
213             result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
214           break;
215         }
216       }
217       return result;
218     }
219
220     bool result = widget_->plugin()->HandleInputEvent(event, &cursor);
221
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);
250       }
251     }
252     return result;
253   }
254
255  private:
256   RenderWidgetFullscreenPepper* widget_;
257   WebSize size_;
258
259   DISALLOW_COPY_AND_ASSIGN(PepperWidget);
260 };
261
262 }  // anonymous namespace
263
264 // static
265 RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create(
266     int32 opener_id,
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);
274   widget->AddRef();
275   return widget.get();
276 }
277
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),
284       plugin_(plugin),
285       layer_(NULL),
286       mouse_lock_dispatcher_(new FullscreenMouseLockDispatcher(
287           this)) {
288 }
289
290 RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() {
291 }
292
293 void RenderWidgetFullscreenPepper::Invalidate() {
294   InvalidateRect(gfx::Rect(size_.width(), size_.height()));
295 }
296
297 void RenderWidgetFullscreenPepper::InvalidateRect(const blink::WebRect& rect) {
298   didInvalidateRect(rect);
299 }
300
301 void RenderWidgetFullscreenPepper::ScrollRect(
302     int dx, int dy, const blink::WebRect& rect) {
303 }
304
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().
308   plugin_ = NULL;
309
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
312   // away.
313   SetLayer(NULL);
314
315   Send(new ViewHostMsg_Close(routing_id_));
316   Release();
317 }
318
319 void RenderWidgetFullscreenPepper::DidChangeCursor(
320     const blink::WebCursorInfo& cursor) {
321   didChangeCursor(cursor);
322 }
323
324 void RenderWidgetFullscreenPepper::SetLayer(blink::WebLayer* layer) {
325   layer_ = layer;
326   if (!layer_) {
327     if (compositor_)
328       compositor_->clearRootLayer();
329     return;
330   }
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_);
337 }
338
339 bool RenderWidgetFullscreenPepper::OnMessageReceived(const IPC::Message& msg) {
340   bool handled = true;
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()
350   if (handled)
351     return true;
352
353   return RenderWidgetFullscreen::OnMessageReceived(msg);
354 }
355
356 void RenderWidgetFullscreenPepper::DidInitiatePaint() {
357   if (plugin_)
358     plugin_->ViewInitiatedPaint();
359 }
360
361 void RenderWidgetFullscreenPepper::DidFlushPaint() {
362   if (plugin_)
363     plugin_->ViewFlushedPaint();
364 }
365
366 void RenderWidgetFullscreenPepper::Close() {
367   // If the fullscreen window is closed (e.g. user pressed escape), reset to
368   // normal mode.
369   if (plugin_)
370     plugin_->FlashSetFullscreen(false, false);
371
372   // Call Close on the base class to destroy the WebWidget instance.
373   RenderWidget::Close();
374 }
375
376 void RenderWidgetFullscreenPepper::OnResize(
377     const ViewMsg_Resize_Params& params) {
378   if (layer_)
379     layer_->setBounds(blink::WebSize(params.new_size));
380   RenderWidget::OnResize(params);
381 }
382
383 WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() {
384   return new PepperWidget(this);
385 }
386
387 GURL RenderWidgetFullscreenPepper::GetURLForGraphicsContext3D() {
388   return active_url_;
389 }
390
391 void RenderWidgetFullscreenPepper::SetDeviceScaleFactor(
392     float device_scale_factor) {
393   RenderWidget::SetDeviceScaleFactor(device_scale_factor);
394   if (compositor_)
395     compositor_->setDeviceScaleFactor(device_scale_factor);
396 }
397
398 }  // namespace content