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_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 // See third_party/WebKit/Source/WebCore/dom/WheelEvent.h.
     52 const float kTickDivisor = 120.0f;
     53 
     54 class FullscreenMouseLockDispatcher : public MouseLockDispatcher {
     55  public:
     56   explicit FullscreenMouseLockDispatcher(RenderWidgetFullscreenPepper* widget);
     57   virtual ~FullscreenMouseLockDispatcher();
     58 
     59  private:
     60   // MouseLockDispatcher implementation.
     61   virtual void SendLockMouseRequest(bool unlocked_by_target) OVERRIDE;
     62   virtual void SendUnlockMouseRequest() OVERRIDE;
     63 
     64   RenderWidgetFullscreenPepper* widget_;
     65 
     66   DISALLOW_COPY_AND_ASSIGN(FullscreenMouseLockDispatcher);
     67 };
     68 
     69 WebMouseEvent WebMouseEventFromGestureEvent(const WebGestureEvent& gesture) {
     70   WebMouseEvent mouse;
     71 
     72   switch (gesture.type) {
     73     case WebInputEvent::GestureScrollBegin:
     74       mouse.type = WebInputEvent::MouseDown;
     75       break;
     76 
     77     case WebInputEvent::GestureScrollUpdate:
     78       mouse.type = WebInputEvent::MouseMove;
     79       break;
     80 
     81     case WebInputEvent::GestureFlingStart:
     82       if (gesture.sourceDevice == WebGestureEvent::Touchscreen) {
     83         // A scroll gesture on the touchscreen may end with a GestureScrollEnd
     84         // when there is no velocity, or a GestureFlingStart when it has a
     85         // velocity. In both cases, it should end the drag that was initiated by
     86         // the GestureScrollBegin (and subsequent GestureScrollUpdate) events.
     87         mouse.type = WebInputEvent::MouseUp;
     88         break;
     89       } else {
     90         return mouse;
     91       }
     92     case WebInputEvent::GestureScrollEnd:
     93       mouse.type = WebInputEvent::MouseUp;
     94       break;
     95 
     96     default:
     97       break;
     98   }
     99 
    100   if (mouse.type == WebInputEvent::Undefined)
    101     return mouse;
    102 
    103   mouse.timeStampSeconds = gesture.timeStampSeconds;
    104   mouse.modifiers = gesture.modifiers | WebInputEvent::LeftButtonDown;
    105   mouse.button = WebMouseEvent::ButtonLeft;
    106   mouse.clickCount = (mouse.type == WebInputEvent::MouseDown ||
    107                       mouse.type == WebInputEvent::MouseUp);
    108 
    109   mouse.x = gesture.x;
    110   mouse.y = gesture.y;
    111   mouse.windowX = gesture.globalX;
    112   mouse.windowY = gesture.globalY;
    113   mouse.globalX = gesture.globalX;
    114   mouse.globalY = gesture.globalY;
    115 
    116   return mouse;
    117 }
    118 
    119 FullscreenMouseLockDispatcher::FullscreenMouseLockDispatcher(
    120     RenderWidgetFullscreenPepper* widget) : widget_(widget) {
    121 }
    122 
    123 FullscreenMouseLockDispatcher::~FullscreenMouseLockDispatcher() {
    124 }
    125 
    126 void FullscreenMouseLockDispatcher::SendLockMouseRequest(
    127     bool unlocked_by_target) {
    128   widget_->Send(new ViewHostMsg_LockMouse(widget_->routing_id(), false,
    129                                           unlocked_by_target, true));
    130 }
    131 
    132 void FullscreenMouseLockDispatcher::SendUnlockMouseRequest() {
    133   widget_->Send(new ViewHostMsg_UnlockMouse(widget_->routing_id()));
    134 }
    135 
    136 // WebWidget that simply wraps the pepper plugin.
    137 class PepperWidget : public WebWidget {
    138  public:
    139   explicit PepperWidget(RenderWidgetFullscreenPepper* widget)
    140       : widget_(widget) {
    141   }
    142 
    143   virtual ~PepperWidget() {}
    144 
    145   // WebWidget API
    146   virtual void close() {
    147     delete this;
    148   }
    149 
    150   virtual WebSize size() {
    151     return size_;
    152   }
    153 
    154   virtual void willStartLiveResize() {
    155   }
    156 
    157   virtual void resize(const WebSize& size) {
    158     if (!widget_->plugin())
    159       return;
    160 
    161     size_ = size;
    162     WebRect plugin_rect(0, 0, size_.width, size_.height);
    163     widget_->plugin()->ViewChanged(plugin_rect, plugin_rect,
    164                                    std::vector<gfx::Rect>());
    165     widget_->Invalidate();
    166   }
    167 
    168   virtual void willEndLiveResize() {
    169   }
    170 
    171   virtual void animate(double frameBeginTime) {
    172   }
    173 
    174   virtual void layout() {
    175   }
    176 
    177   virtual void paint(WebCanvas* canvas, const WebRect& rect, PaintOptions) {
    178     if (!widget_->plugin())
    179       return;
    180 
    181     SkAutoCanvasRestore auto_restore(canvas, true);
    182     float canvas_scale = widget_->deviceScaleFactor();
    183     canvas->scale(canvas_scale, canvas_scale);
    184 
    185     WebRect plugin_rect(0, 0, size_.width, size_.height);
    186     widget_->plugin()->Paint(canvas, plugin_rect, rect);
    187   }
    188 
    189   virtual void setCompositorSurfaceReady() {
    190   }
    191 
    192   virtual void composite(bool finish) {
    193   }
    194 
    195   virtual void themeChanged() {
    196     NOTIMPLEMENTED();
    197   }
    198 
    199   virtual bool handleInputEvent(const WebInputEvent& event) {
    200     if (!widget_->plugin())
    201       return false;
    202 
    203     // This cursor info is ignored, we always set the cursor directly from
    204     // RenderWidgetFullscreenPepper::DidChangeCursor.
    205     WebCursorInfo cursor;
    206 
    207     // Pepper plugins do not accept gesture events. So do not send the gesture
    208     // events directly to the plugin. Instead, try to convert them to equivalent
    209     // mouse events, and then send to the plugin.
    210     if (WebInputEvent::isGestureEventType(event.type)) {
    211       bool result = false;
    212       const WebGestureEvent* gesture_event =
    213           static_cast<const WebGestureEvent*>(&event);
    214       switch (event.type) {
    215         case WebInputEvent::GestureTap: {
    216           WebMouseEvent mouse;
    217 
    218           mouse.timeStampSeconds = gesture_event->timeStampSeconds;
    219           mouse.type = WebInputEvent::MouseMove;
    220           mouse.modifiers = gesture_event->modifiers;
    221 
    222           mouse.x = gesture_event->x;
    223           mouse.y = gesture_event->y;
    224           mouse.windowX = gesture_event->globalX;
    225           mouse.windowY = gesture_event->globalY;
    226           mouse.globalX = gesture_event->globalX;
    227           mouse.globalY = gesture_event->globalY;
    228           mouse.movementX = 0;
    229           mouse.movementY = 0;
    230           result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
    231 
    232           mouse.type = WebInputEvent::MouseDown;
    233           mouse.button = WebMouseEvent::ButtonLeft;
    234           mouse.clickCount = gesture_event->data.tap.tapCount;
    235           result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
    236 
    237           mouse.type = WebInputEvent::MouseUp;
    238           result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
    239           break;
    240         }
    241 
    242         default: {
    243           WebMouseEvent mouse = WebMouseEventFromGestureEvent(*gesture_event);
    244           if (mouse.type != WebInputEvent::Undefined)
    245             result |= widget_->plugin()->HandleInputEvent(mouse, &cursor);
    246           break;
    247         }
    248       }
    249       return result;
    250     }
    251 
    252     bool result = widget_->plugin()->HandleInputEvent(event, &cursor);
    253 
    254     // For normal web pages, WebViewImpl does input event translations and
    255     // generates context menu events. Since we don't have a WebView, we need to
    256     // do the necessary translation ourselves.
    257     if (WebInputEvent::isMouseEventType(event.type)) {
    258       const WebMouseEvent& mouse_event =
    259           reinterpret_cast<const WebMouseEvent&>(event);
    260       bool send_context_menu_event = false;
    261       // On Mac/Linux, we handle it on mouse down.
    262       // On Windows, we handle it on mouse up.
    263 #if defined(OS_WIN)
    264       send_context_menu_event =
    265           mouse_event.type == WebInputEvent::MouseUp &&
    266           mouse_event.button == WebMouseEvent::ButtonRight;
    267 #elif defined(OS_MACOSX)
    268       send_context_menu_event =
    269           mouse_event.type == WebInputEvent::MouseDown &&
    270           (mouse_event.button == WebMouseEvent::ButtonRight ||
    271            (mouse_event.button == WebMouseEvent::ButtonLeft &&
    272             mouse_event.modifiers & WebMouseEvent::ControlKey));
    273 #else
    274       send_context_menu_event =
    275           mouse_event.type == WebInputEvent::MouseDown &&
    276           mouse_event.button == WebMouseEvent::ButtonRight;
    277 #endif
    278       if (send_context_menu_event) {
    279         WebMouseEvent context_menu_event(mouse_event);
    280         context_menu_event.type = WebInputEvent::ContextMenu;
    281         widget_->plugin()->HandleInputEvent(context_menu_event, &cursor);
    282       }
    283     }
    284     return result;
    285   }
    286 
    287   virtual void mouseCaptureLost() {
    288     NOTIMPLEMENTED();
    289   }
    290 
    291   virtual void setFocus(bool focus) {
    292     NOTIMPLEMENTED();
    293   }
    294 
    295   // TODO(piman): figure out IME and implement these if necessary.
    296   virtual bool setComposition(
    297       const WebString& text,
    298       const WebVector<WebCompositionUnderline>& underlines,
    299       int selectionStart,
    300       int selectionEnd) {
    301     return false;
    302   }
    303 
    304   virtual bool confirmComposition() {
    305     return false;
    306   }
    307 
    308   virtual bool compositionRange(size_t* location, size_t* length) {
    309     return false;
    310   }
    311 
    312   virtual bool confirmComposition(const WebString& text) {
    313     return false;
    314   }
    315 
    316   virtual WebTextInputType textInputType() {
    317     return WebKit::WebTextInputTypeNone;
    318   }
    319 
    320   virtual WebRect caretOrSelectionBounds() {
    321     return WebRect();
    322   }
    323 
    324   virtual bool selectionRange(WebPoint& start, WebPoint& end) const {
    325     return false;
    326   }
    327 
    328   virtual bool caretOrSelectionRange(size_t* location, size_t* length) {
    329     return false;
    330   }
    331 
    332   virtual void setTextDirection(WebTextDirection) {
    333   }
    334 
    335   virtual bool isAcceleratedCompositingActive() const {
    336     return widget_->plugin() && widget_->is_compositing();
    337   }
    338 
    339  private:
    340   RenderWidgetFullscreenPepper* widget_;
    341   WebSize size_;
    342 
    343   DISALLOW_COPY_AND_ASSIGN(PepperWidget);
    344 };
    345 
    346 }  // anonymous namespace
    347 
    348 // static
    349 RenderWidgetFullscreenPepper* RenderWidgetFullscreenPepper::Create(
    350     int32 opener_id,
    351     PepperPluginInstanceImpl* plugin,
    352     const GURL& active_url,
    353     const WebKit::WebScreenInfo& screen_info) {
    354   DCHECK_NE(MSG_ROUTING_NONE, opener_id);
    355   scoped_refptr<RenderWidgetFullscreenPepper> widget(
    356       new RenderWidgetFullscreenPepper(plugin, active_url, screen_info));
    357   widget->Init(opener_id);
    358   widget->AddRef();
    359   return widget.get();
    360 }
    361 
    362 RenderWidgetFullscreenPepper::RenderWidgetFullscreenPepper(
    363     PepperPluginInstanceImpl* plugin,
    364     const GURL& active_url,
    365     const WebKit::WebScreenInfo& screen_info)
    366     : RenderWidgetFullscreen(screen_info),
    367       active_url_(active_url),
    368       plugin_(plugin),
    369       layer_(NULL),
    370       mouse_lock_dispatcher_(new FullscreenMouseLockDispatcher(
    371           this)) {
    372 }
    373 
    374 RenderWidgetFullscreenPepper::~RenderWidgetFullscreenPepper() {
    375 }
    376 
    377 void RenderWidgetFullscreenPepper::Invalidate() {
    378   InvalidateRect(gfx::Rect(size_.width(), size_.height()));
    379 }
    380 
    381 void RenderWidgetFullscreenPepper::InvalidateRect(const WebKit::WebRect& rect) {
    382   didInvalidateRect(rect);
    383 }
    384 
    385 void RenderWidgetFullscreenPepper::ScrollRect(
    386     int dx, int dy, const WebKit::WebRect& rect) {
    387   didScrollRect(dx, dy, rect);
    388 }
    389 
    390 void RenderWidgetFullscreenPepper::Destroy() {
    391   // This function is called by the plugin instance as it's going away, so reset
    392   // plugin_ to NULL to avoid calling into a dangling pointer e.g. on Close().
    393   plugin_ = NULL;
    394 
    395   // After calling Destroy(), the plugin instance assumes that the layer is not
    396   // used by us anymore, so it may destroy the layer before this object goes
    397   // away.
    398   SetLayer(NULL);
    399 
    400   Send(new ViewHostMsg_Close(routing_id_));
    401   Release();
    402 }
    403 
    404 void RenderWidgetFullscreenPepper::DidChangeCursor(
    405     const WebKit::WebCursorInfo& cursor) {
    406   didChangeCursor(cursor);
    407 }
    408 
    409 void RenderWidgetFullscreenPepper::SetLayer(WebKit::WebLayer* layer) {
    410   layer_ = layer;
    411   bool compositing = !!layer_;
    412   if (compositing != is_accelerated_compositing_active_) {
    413     if (compositing) {
    414       initializeLayerTreeView();
    415       if (!layerTreeView())
    416         return;
    417       layer_->setBounds(WebKit::WebSize(size()));
    418       layer_->setDrawsContent(true);
    419       compositor_->setDeviceScaleFactor(device_scale_factor_);
    420       compositor_->setRootLayer(*layer_);
    421       didActivateCompositor(-1);
    422     } else {
    423       didDeactivateCompositor();
    424     }
    425   }
    426 }
    427 
    428 bool RenderWidgetFullscreenPepper::OnMessageReceived(const IPC::Message& msg) {
    429   bool handled = true;
    430   IPC_BEGIN_MESSAGE_MAP(RenderWidgetFullscreenPepper, msg)
    431     IPC_MESSAGE_FORWARD(ViewMsg_LockMouse_ACK,
    432                         mouse_lock_dispatcher_.get(),
    433                         MouseLockDispatcher::OnLockMouseACK)
    434     IPC_MESSAGE_FORWARD(ViewMsg_MouseLockLost,
    435                         mouse_lock_dispatcher_.get(),
    436                         MouseLockDispatcher::OnMouseLockLost)
    437     IPC_MESSAGE_UNHANDLED(handled = false)
    438   IPC_END_MESSAGE_MAP()
    439   if (handled)
    440     return true;
    441 
    442   return RenderWidgetFullscreen::OnMessageReceived(msg);
    443 }
    444 
    445 void RenderWidgetFullscreenPepper::WillInitiatePaint() {
    446   if (plugin_)
    447     plugin_->ViewWillInitiatePaint();
    448 }
    449 
    450 void RenderWidgetFullscreenPepper::DidInitiatePaint() {
    451   if (plugin_)
    452     plugin_->ViewInitiatedPaint();
    453 }
    454 
    455 void RenderWidgetFullscreenPepper::DidFlushPaint() {
    456   if (plugin_)
    457     plugin_->ViewFlushedPaint();
    458 }
    459 
    460 void RenderWidgetFullscreenPepper::Close() {
    461   // If the fullscreen window is closed (e.g. user pressed escape), reset to
    462   // normal mode.
    463   if (plugin_)
    464     plugin_->FlashSetFullscreen(false, false);
    465 
    466   // Call Close on the base class to destroy the WebWidget instance.
    467   RenderWidget::Close();
    468 }
    469 
    470 PepperPluginInstanceImpl*
    471     RenderWidgetFullscreenPepper::GetBitmapForOptimizedPluginPaint(
    472         const gfx::Rect& paint_bounds,
    473         TransportDIB** dib,
    474         gfx::Rect* location,
    475         gfx::Rect* clip,
    476         float* scale_factor) {
    477   if (plugin_ && plugin_->GetBitmapForOptimizedPluginPaint(
    478           paint_bounds, dib, location, clip, scale_factor)) {
    479     return plugin_;
    480   }
    481   return NULL;
    482 }
    483 
    484 void RenderWidgetFullscreenPepper::OnResize(
    485     const ViewMsg_Resize_Params& params) {
    486   if (layer_)
    487     layer_->setBounds(WebKit::WebSize(params.new_size));
    488   RenderWidget::OnResize(params);
    489 }
    490 
    491 WebWidget* RenderWidgetFullscreenPepper::CreateWebWidget() {
    492   return new PepperWidget(this);
    493 }
    494 
    495 GURL RenderWidgetFullscreenPepper::GetURLForGraphicsContext3D() {
    496   return active_url_;
    497 }
    498 
    499 void RenderWidgetFullscreenPepper::SetDeviceScaleFactor(
    500     float device_scale_factor) {
    501   RenderWidget::SetDeviceScaleFactor(device_scale_factor);
    502   if (compositor_)
    503     compositor_->setDeviceScaleFactor(device_scale_factor);
    504 }
    505 
    506 }  // namespace content
    507