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 29using blink::WebCanvas; 30using blink::WebCompositionUnderline; 31using blink::WebCursorInfo; 32using blink::WebGestureEvent; 33using blink::WebInputEvent; 34using blink::WebMouseEvent; 35using blink::WebMouseWheelEvent; 36using blink::WebPoint; 37using blink::WebRect; 38using blink::WebSize; 39using blink::WebString; 40using blink::WebTextDirection; 41using blink::WebTextInputType; 42using blink::WebVector; 43using blink::WebWidget; 44using blink::WGC3Dintptr; 45 46namespace content { 47 48namespace { 49 50class FullscreenMouseLockDispatcher : public MouseLockDispatcher { 51 public: 52 explicit FullscreenMouseLockDispatcher(RenderWidgetFullscreenPepper* widget); 53 virtual ~FullscreenMouseLockDispatcher(); 54 55 private: 56 // MouseLockDispatcher implementation. 57 virtual void SendLockMouseRequest(bool unlocked_by_target) OVERRIDE; 58 virtual void SendUnlockMouseRequest() OVERRIDE; 59 60 RenderWidgetFullscreenPepper* widget_; 61 62 DISALLOW_COPY_AND_ASSIGN(FullscreenMouseLockDispatcher); 63}; 64 65WebMouseEvent 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 115FullscreenMouseLockDispatcher::FullscreenMouseLockDispatcher( 116 RenderWidgetFullscreenPepper* widget) : widget_(widget) { 117} 118 119FullscreenMouseLockDispatcher::~FullscreenMouseLockDispatcher() { 120} 121 122void FullscreenMouseLockDispatcher::SendLockMouseRequest( 123 bool unlocked_by_target) { 124 widget_->Send(new ViewHostMsg_LockMouse(widget_->routing_id(), false, 125 unlocked_by_target, true)); 126} 127 128void 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. 135class 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 265RenderWidgetFullscreenPepper* 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 278RenderWidgetFullscreenPepper::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 290RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() { 291} 292 293void RenderWidgetFullscreenPepper::Invalidate() { 294 InvalidateRect(gfx::Rect(size_.width(), size_.height())); 295} 296 297void RenderWidgetFullscreenPepper::InvalidateRect(const blink::WebRect& rect) { 298 didInvalidateRect(rect); 299} 300 301void RenderWidgetFullscreenPepper::ScrollRect( 302 int dx, int dy, const blink::WebRect& rect) { 303} 304 305void 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 319void RenderWidgetFullscreenPepper::DidChangeCursor( 320 const blink::WebCursorInfo& cursor) { 321 didChangeCursor(cursor); 322} 323 324void 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 339bool 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 356void RenderWidgetFullscreenPepper::DidInitiatePaint() { 357 if (plugin_) 358 plugin_->ViewInitiatedPaint(); 359} 360 361void RenderWidgetFullscreenPepper::DidFlushPaint() { 362 if (plugin_) 363 plugin_->ViewFlushedPaint(); 364} 365 366void 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 376void 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 383WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() { 384 return new PepperWidget(this); 385} 386 387GURL RenderWidgetFullscreenPepper::GetURLForGraphicsContext3D() { 388 return active_url_; 389} 390 391void 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 399