Home | History | Annotate | Download | only in renderer
      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   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 
     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   didScrollRect(dx, dy, rect);
    304 }
    305 
    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;
    310 
    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);
    315 
    316   Send(new ViewHostMsg_Close(routing_id_));
    317   Release();
    318 }
    319 
    320 void RenderWidgetFullscreenPepper::DidChangeCursor(
    321     const blink::WebCursorInfo& cursor) {
    322   didChangeCursor(cursor);
    323 }
    324 
    325 void RenderWidgetFullscreenPepper::SetLayer(blink::WebLayer* layer) {
    326   layer_ = layer;
    327   if (!layer_) {
    328     if (compositor_)
    329       compositor_->clearRootLayer();
    330     return;
    331   }
    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_);
    338 }
    339 
    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;
    353 
    354   return RenderWidgetFullscreen::OnMessageReceived(msg);
    355 }
    356 
    357 void RenderWidgetFullscreenPepper::DidInitiatePaint() {
    358   if (plugin_)
    359     plugin_->ViewInitiatedPaint();
    360 }
    361 
    362 void RenderWidgetFullscreenPepper::DidFlushPaint() {
    363   if (plugin_)
    364     plugin_->ViewFlushedPaint();
    365 }
    366 
    367 void RenderWidgetFullscreenPepper::Close() {
    368   // If the fullscreen window is closed (e.g. user pressed escape), reset to
    369   // normal mode.
    370   if (plugin_)
    371     plugin_->FlashSetFullscreen(false, false);
    372 
    373   // Call Close on the base class to destroy the WebWidget instance.
    374   RenderWidget::Close();
    375 }
    376 
    377 void RenderWidgetFullscreenPepper::OnResize(
    378     const ViewMsg_Resize_Params& params) {
    379   if (layer_)
    380     layer_->setBounds(blink::WebSize(params.new_size));
    381   RenderWidget::OnResize(params);
    382 }
    383 
    384 WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() {
    385   return new PepperWidget(this);
    386 }
    387 
    388 GURL RenderWidgetFullscreenPepper::GetURLForGraphicsContext3D() {
    389   return active_url_;
    390 }
    391 
    392 void RenderWidgetFullscreenPepper::SetDeviceScaleFactor(
    393     float device_scale_factor) {
    394   RenderWidget::SetDeviceScaleFactor(device_scale_factor);
    395   if (compositor_)
    396     compositor_->setDeviceScaleFactor(device_scale_factor);
    397 }
    398 
    399 }  // namespace content
    400