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_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"
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;
51 class FullscreenMouseLockDispatcher : public MouseLockDispatcher {
53 explicit FullscreenMouseLockDispatcher(RenderWidgetFullscreenPepper* widget);
54 virtual ~FullscreenMouseLockDispatcher();
57 // MouseLockDispatcher implementation.
58 virtual void SendLockMouseRequest(bool unlocked_by_target) OVERRIDE;
59 virtual void SendUnlockMouseRequest() OVERRIDE;
61 RenderWidgetFullscreenPepper* widget_;
63 DISALLOW_COPY_AND_ASSIGN(FullscreenMouseLockDispatcher);
66 WebMouseEvent WebMouseEventFromGestureEvent(const WebGestureEvent& gesture) {
69 switch (gesture.type) {
70 case WebInputEvent::GestureScrollBegin:
71 mouse.type = WebInputEvent::MouseDown;
74 case WebInputEvent::GestureScrollUpdate:
75 mouse.type = WebInputEvent::MouseMove;
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;
89 case WebInputEvent::GestureScrollEnd:
90 mouse.type = WebInputEvent::MouseUp;
97 if (mouse.type == WebInputEvent::Undefined)
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);
108 mouse.windowX = gesture.globalX;
109 mouse.windowY = gesture.globalY;
110 mouse.globalX = gesture.globalX;
111 mouse.globalY = gesture.globalY;
116 FullscreenMouseLockDispatcher::FullscreenMouseLockDispatcher(
117 RenderWidgetFullscreenPepper* widget) : widget_(widget) {
120 FullscreenMouseLockDispatcher::~FullscreenMouseLockDispatcher() {
123 void FullscreenMouseLockDispatcher::SendLockMouseRequest(
124 bool unlocked_by_target) {
125 widget_->Send(new ViewHostMsg_LockMouse(widget_->routing_id(), false,
126 unlocked_by_target, true));
129 void FullscreenMouseLockDispatcher::SendUnlockMouseRequest() {
130 widget_->Send(new ViewHostMsg_UnlockMouse(widget_->routing_id()));
133 // WebWidget that simply wraps the pepper plugin.
134 class PepperWidget : public WebWidget {
136 explicit PepperWidget(RenderWidgetFullscreenPepper* widget)
140 virtual ~PepperWidget() {}
143 virtual void close() {
147 virtual WebSize size() {
151 virtual void willStartLiveResize() {
154 virtual void resize(const WebSize& size) {
155 if (!widget_->plugin())
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();
165 virtual void willEndLiveResize() {
168 virtual void animate(double frameBeginTime) {
171 virtual void layout() {
174 virtual void paint(WebCanvas* canvas, const WebRect& rect, PaintOptions) {
175 if (!widget_->plugin())
178 SkAutoCanvasRestore auto_restore(canvas, true);
179 float canvas_scale = widget_->deviceScaleFactor();
180 canvas->scale(canvas_scale, canvas_scale);
182 WebRect plugin_rect(0, 0, size_.width, size_.height);
183 widget_->plugin()->Paint(canvas, plugin_rect, rect);
186 virtual void setCompositorSurfaceReady() {
189 virtual void composite(bool finish) {
192 virtual void themeChanged() {
196 virtual bool handleInputEvent(const WebInputEvent& event) {
197 if (!widget_->plugin())
200 // This cursor info is ignored, we always set the cursor directly from
201 // RenderWidgetFullscreenPepper::DidChangeCursor.
202 WebCursorInfo cursor;
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)) {
209 const WebGestureEvent* gesture_event =
210 static_cast<const WebGestureEvent*>(&event);
211 switch (event.type) {
212 case WebInputEvent::GestureTap: {
215 mouse.timeStampSeconds = gesture_event->timeStampSeconds;
216 mouse.type = WebInputEvent::MouseMove;
217 mouse.modifiers = gesture_event->modifiers;
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;
227 result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
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);
234 mouse.type = WebInputEvent::MouseUp;
235 result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
240 WebMouseEvent mouse = WebMouseEventFromGestureEvent(*gesture_event);
241 if (mouse.type != WebInputEvent::Undefined)
242 result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
249 bool result = widget_->plugin()->HandleInputEvent(event, &cursor);
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.
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));
271 send_context_menu_event =
272 mouse_event.type == WebInputEvent::MouseDown &&
273 mouse_event.button == WebMouseEvent::ButtonRight;
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);
284 virtual void mouseCaptureLost() {
287 virtual void setFocus(bool focus) {
290 // TODO(piman): figure out IME and implement these if necessary.
291 virtual bool setComposition(
292 const WebString& text,
293 const WebVector<WebCompositionUnderline>& underlines,
299 virtual bool confirmComposition() {
303 virtual bool compositionRange(size_t* location, size_t* length) {
307 virtual bool confirmComposition(const WebString& text) {
311 virtual WebTextInputType textInputType() {
312 return WebKit::WebTextInputTypeNone;
315 virtual WebRect caretOrSelectionBounds() {
319 virtual bool selectionRange(WebPoint& start, WebPoint& end) const {
323 virtual bool caretOrSelectionRange(size_t* location, size_t* length) {
327 virtual void setTextDirection(WebTextDirection) {
330 virtual bool isAcceleratedCompositingActive() const {
331 return widget_->plugin() && widget_->is_compositing();
335 RenderWidgetFullscreenPepper* widget_;
338 DISALLOW_COPY_AND_ASSIGN(PepperWidget);
341 } // anonymous namespace
344 RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create(
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);
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),
365 mouse_lock_dispatcher_(new FullscreenMouseLockDispatcher(
369 RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() {
372 void RenderWidgetFullscreenPepper::Invalidate() {
373 InvalidateRect(gfx::Rect(size_.width(), size_.height()));
376 void RenderWidgetFullscreenPepper::InvalidateRect(const WebKit::WebRect& rect) {
377 didInvalidateRect(rect);
380 void RenderWidgetFullscreenPepper::ScrollRect(
381 int dx, int dy, const WebKit::WebRect& rect) {
382 didScrollRect(dx, dy, rect);
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().
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
395 Send(new ViewHostMsg_Close(routing_id_));
399 void RenderWidgetFullscreenPepper::DidChangeCursor(
400 const WebKit::WebCursorInfo& cursor) {
401 didChangeCursor(cursor);
404 void RenderWidgetFullscreenPepper::SetLayer(WebKit::WebLayer* layer) {
406 bool compositing = !!layer_;
407 if (compositing != is_accelerated_compositing_active_) {
409 if (!layerTreeView())
410 initializeLayerTreeView();
411 if (!layerTreeView())
413 layer_->setBounds(WebKit::WebSize(size()));
414 layer_->setDrawsContent(true);
415 compositor_->setDeviceScaleFactor(device_scale_factor_);
416 compositor_->setRootLayer(*layer_);
417 didActivateCompositor(-1);
419 didDeactivateCompositor();
424 bool RenderWidgetFullscreenPepper::OnMessageReceived(const IPC::Message& msg) {
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()
438 return RenderWidgetFullscreen::OnMessageReceived(msg);
441 void RenderWidgetFullscreenPepper::DidInitiatePaint() {
443 plugin_->ViewInitiatedPaint();
446 void RenderWidgetFullscreenPepper::DidFlushPaint() {
448 plugin_->ViewFlushedPaint();
451 void RenderWidgetFullscreenPepper::Close() {
452 // If the fullscreen window is closed (e.g. user pressed escape), reset to
455 plugin_->FlashSetFullscreen(false, false);
457 // Call Close on the base class to destroy the WebWidget instance.
458 RenderWidget::Close();
461 PepperPluginInstanceImpl*
462 RenderWidgetFullscreenPepper::GetBitmapForOptimizedPluginPaint(
463 const gfx::Rect& paint_bounds,
467 float* scale_factor) {
468 if (plugin_ && plugin_->GetBitmapForOptimizedPluginPaint(
469 paint_bounds, dib, location, clip, scale_factor)) {
475 void RenderWidgetFullscreenPepper::OnResize(
476 const ViewMsg_Resize_Params& params) {
478 layer_->setBounds(WebKit::WebSize(params.new_size));
479 RenderWidget::OnResize(params);
482 WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() {
483 return new PepperWidget(this);
486 GURL RenderWidgetFullscreenPepper::GetURLForGraphicsContext3D() {
490 void RenderWidgetFullscreenPepper::SetDeviceScaleFactor(
491 float device_scale_factor) {
492 RenderWidget::SetDeviceScaleFactor(device_scale_factor);
494 compositor_->setDeviceScaleFactor(device_scale_factor);
497 } // namespace content