Home | History | Annotate | Download | only in browser_plugin
      1 // Copyright 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/browser_plugin/browser_plugin.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/message_loop/message_loop.h"
      9 #include "base/strings/string_number_conversions.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "content/common/browser_plugin/browser_plugin_constants.h"
     12 #include "content/common/browser_plugin/browser_plugin_messages.h"
     13 #include "content/common/view_messages.h"
     14 #include "content/public/common/content_client.h"
     15 #include "content/public/common/content_switches.h"
     16 #include "content/public/renderer/content_renderer_client.h"
     17 #include "content/renderer/browser_plugin/browser_plugin_bindings.h"
     18 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
     19 #include "content/renderer/child_frame_compositing_helper.h"
     20 #include "content/renderer/cursor_utils.h"
     21 #include "content/renderer/drop_data_builder.h"
     22 #include "content/renderer/render_thread_impl.h"
     23 #include "content/renderer/sad_plugin.h"
     24 #include "third_party/WebKit/public/platform/WebRect.h"
     25 #include "third_party/WebKit/public/web/WebBindings.h"
     26 #include "third_party/WebKit/public/web/WebDocument.h"
     27 #include "third_party/WebKit/public/web/WebElement.h"
     28 #include "third_party/WebKit/public/web/WebInputEvent.h"
     29 #include "third_party/WebKit/public/web/WebPluginContainer.h"
     30 #include "third_party/WebKit/public/web/WebPluginParams.h"
     31 #include "third_party/WebKit/public/web/WebView.h"
     32 #include "third_party/skia/include/core/SkCanvas.h"
     33 #include "ui/events/keycodes/keyboard_codes.h"
     34 
     35 using blink::WebCanvas;
     36 using blink::WebPluginContainer;
     37 using blink::WebPluginParams;
     38 using blink::WebPoint;
     39 using blink::WebRect;
     40 using blink::WebURL;
     41 using blink::WebVector;
     42 
     43 namespace content {
     44 
     45 BrowserPlugin::BrowserPlugin(RenderViewImpl* render_view,
     46                              blink::WebFrame* frame,
     47                              bool auto_navigate)
     48     : guest_instance_id_(browser_plugin::kInstanceIDNone),
     49       attached_(false),
     50       render_view_(render_view->AsWeakPtr()),
     51       render_view_routing_id_(render_view->GetRoutingID()),
     52       container_(NULL),
     53       paint_ack_received_(true),
     54       last_device_scale_factor_(GetDeviceScaleFactor()),
     55       sad_guest_(NULL),
     56       guest_crashed_(false),
     57       is_auto_size_state_dirty_(false),
     58       content_window_routing_id_(MSG_ROUTING_NONE),
     59       plugin_focused_(false),
     60       visible_(true),
     61       auto_navigate_(auto_navigate),
     62       mouse_locked_(false),
     63       browser_plugin_manager_(render_view->GetBrowserPluginManager()),
     64       embedder_frame_url_(frame->document().url()),
     65       weak_ptr_factory_(this) {
     66 }
     67 
     68 BrowserPlugin::~BrowserPlugin() {
     69   // If the BrowserPlugin has never navigated then the browser process and
     70   // BrowserPluginManager don't know about it and so there is nothing to do
     71   // here.
     72   if (!HasGuestInstanceID())
     73     return;
     74   browser_plugin_manager()->RemoveBrowserPlugin(guest_instance_id_);
     75   browser_plugin_manager()->Send(
     76       new BrowserPluginHostMsg_PluginDestroyed(render_view_routing_id_,
     77                                                guest_instance_id_));
     78 }
     79 
     80 bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) {
     81   bool handled = true;
     82   IPC_BEGIN_MESSAGE_MAP(BrowserPlugin, message)
     83     IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus)
     84     IPC_MESSAGE_HANDLER(BrowserPluginMsg_Attach_ACK, OnAttachACK)
     85     IPC_MESSAGE_HANDLER(BrowserPluginMsg_BuffersSwapped, OnBuffersSwapped)
     86     IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginMsg_CompositorFrameSwapped,
     87                                 OnCompositorFrameSwapped(message))
     88     IPC_MESSAGE_HANDLER(BrowserPluginMsg_CopyFromCompositingSurface,
     89                         OnCopyFromCompositingSurface)
     90     IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestContentWindowReady,
     91                         OnGuestContentWindowReady)
     92     IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone)
     93     IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor)
     94     IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetMouseLock, OnSetMouseLock)
     95     IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents,
     96                         OnShouldAcceptTouchEvents)
     97     IPC_MESSAGE_HANDLER(BrowserPluginMsg_UpdateRect, OnUpdateRect)
     98     IPC_MESSAGE_UNHANDLED(handled = false)
     99   IPC_END_MESSAGE_MAP()
    100   return handled;
    101 }
    102 
    103 void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
    104                                        const std::string& attribute_value) {
    105   if (!container())
    106     return;
    107 
    108   blink::WebElement element = container()->element();
    109   blink::WebString web_attribute_name =
    110       blink::WebString::fromUTF8(attribute_name);
    111   if (!HasDOMAttribute(attribute_name) ||
    112       (std::string(element.getAttribute(web_attribute_name).utf8()) !=
    113           attribute_value)) {
    114     element.setAttribute(web_attribute_name,
    115         blink::WebString::fromUTF8(attribute_value));
    116   }
    117 }
    118 
    119 void BrowserPlugin::RemoveDOMAttribute(const std::string& attribute_name) {
    120   if (!container())
    121     return;
    122 
    123   container()->element().removeAttribute(
    124       blink::WebString::fromUTF8(attribute_name));
    125 }
    126 
    127 std::string BrowserPlugin::GetDOMAttributeValue(
    128     const std::string& attribute_name) const {
    129   if (!container())
    130     return std::string();
    131 
    132   return container()->element().getAttribute(
    133       blink::WebString::fromUTF8(attribute_name)).utf8();
    134 }
    135 
    136 bool BrowserPlugin::HasDOMAttribute(const std::string& attribute_name) const {
    137   if (!container())
    138     return false;
    139 
    140   return container()->element().hasAttribute(
    141       blink::WebString::fromUTF8(attribute_name));
    142 }
    143 
    144 bool BrowserPlugin::GetAllowTransparencyAttribute() const {
    145   return HasDOMAttribute(browser_plugin::kAttributeAllowTransparency);
    146 }
    147 
    148 bool BrowserPlugin::GetAutoSizeAttribute() const {
    149   return HasDOMAttribute(browser_plugin::kAttributeAutoSize);
    150 }
    151 
    152 int BrowserPlugin::GetMaxHeightAttribute() const {
    153   int max_height;
    154   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxHeight),
    155                     &max_height);
    156   return max_height;
    157 }
    158 
    159 int BrowserPlugin::GetMaxWidthAttribute() const {
    160   int max_width;
    161   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxWidth),
    162                     &max_width);
    163   return max_width;
    164 }
    165 
    166 int BrowserPlugin::GetMinHeightAttribute() const {
    167   int min_height;
    168   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinHeight),
    169                     &min_height);
    170   return min_height;
    171 }
    172 
    173 int BrowserPlugin::GetMinWidthAttribute() const {
    174   int min_width;
    175   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinWidth),
    176                     &min_width);
    177   return min_width;
    178 }
    179 
    180 int BrowserPlugin::GetAdjustedMaxHeight() const {
    181   int max_height = GetMaxHeightAttribute();
    182   return max_height ? max_height : height();
    183 }
    184 
    185 int BrowserPlugin::GetAdjustedMaxWidth() const {
    186   int max_width = GetMaxWidthAttribute();
    187   return max_width ? max_width : width();
    188 }
    189 
    190 int BrowserPlugin::GetAdjustedMinHeight() const {
    191   int min_height = GetMinHeightAttribute();
    192   // FrameView.cpp does not allow this value to be <= 0, so when the value is
    193   // unset (or set to 0), we set it to the container size.
    194   min_height = min_height ? min_height : height();
    195   // For autosize, minHeight should not be bigger than maxHeight.
    196   return std::min(min_height, GetAdjustedMaxHeight());
    197 }
    198 
    199 int BrowserPlugin::GetAdjustedMinWidth() const {
    200   int min_width = GetMinWidthAttribute();
    201   // FrameView.cpp does not allow this value to be <= 0, so when the value is
    202   // unset (or set to 0), we set it to the container size.
    203   min_width = min_width ? min_width : width();
    204   // For autosize, minWidth should not be bigger than maxWidth.
    205   return std::min(min_width, GetAdjustedMaxWidth());
    206 }
    207 
    208 void BrowserPlugin::ParseAllowTransparencyAttribute() {
    209   if (!HasGuestInstanceID())
    210     return;
    211 
    212   bool opaque = !GetAllowTransparencyAttribute();
    213 
    214   if (compositing_helper_)
    215     compositing_helper_->SetContentsOpaque(opaque);
    216 
    217   browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetContentsOpaque(
    218         render_view_routing_id_,
    219         guest_instance_id_,
    220         opaque));
    221 }
    222 
    223 void BrowserPlugin::ParseAutoSizeAttribute() {
    224   last_view_size_ = plugin_size();
    225   is_auto_size_state_dirty_ = true;
    226   UpdateGuestAutoSizeState(GetAutoSizeAttribute());
    227 }
    228 
    229 void BrowserPlugin::PopulateAutoSizeParameters(
    230     BrowserPluginHostMsg_AutoSize_Params* params, bool auto_size_enabled) {
    231   params->enable = auto_size_enabled;
    232   // No need to populate the params if autosize is off.
    233   if (auto_size_enabled) {
    234     params->max_size = gfx::Size(GetAdjustedMaxWidth(), GetAdjustedMaxHeight());
    235     params->min_size = gfx::Size(GetAdjustedMinWidth(), GetAdjustedMinHeight());
    236 
    237     if (max_auto_size_ != params->max_size)
    238       is_auto_size_state_dirty_ = true;
    239 
    240     max_auto_size_ = params->max_size;
    241   } else {
    242     max_auto_size_ = gfx::Size();
    243   }
    244 }
    245 
    246 void BrowserPlugin::UpdateGuestAutoSizeState(bool auto_size_enabled) {
    247   // If we haven't yet heard back from the guest about the last resize request,
    248   // then we don't issue another request until we do in
    249   // BrowserPlugin::OnUpdateRect.
    250   if (!HasGuestInstanceID() || !paint_ack_received_)
    251     return;
    252 
    253   BrowserPluginHostMsg_AutoSize_Params auto_size_params;
    254   BrowserPluginHostMsg_ResizeGuest_Params resize_guest_params;
    255   if (auto_size_enabled) {
    256     GetSizeParams(&auto_size_params, &resize_guest_params, true);
    257   } else {
    258     GetSizeParams(NULL, &resize_guest_params, true);
    259   }
    260   paint_ack_received_ = false;
    261   browser_plugin_manager()->Send(
    262       new BrowserPluginHostMsg_SetAutoSize(render_view_routing_id_,
    263                                            guest_instance_id_,
    264                                            auto_size_params,
    265                                            resize_guest_params));
    266 }
    267 
    268 void BrowserPlugin::Attach(int guest_instance_id,
    269                            scoped_ptr<base::DictionaryValue> extra_params) {
    270   CHECK(guest_instance_id != browser_plugin::kInstanceIDNone);
    271 
    272   // If this BrowserPlugin is already attached to a guest, then do nothing.
    273   if (HasGuestInstanceID())
    274     return;
    275 
    276   // This API may be called directly without setting the src attribute.
    277   // In that case, we need to make sure we don't allocate another instance ID.
    278   guest_instance_id_ = guest_instance_id;
    279   browser_plugin_manager()->AddBrowserPlugin(guest_instance_id, this);
    280 
    281   BrowserPluginHostMsg_Attach_Params attach_params;
    282   attach_params.focused = ShouldGuestBeFocused();
    283   attach_params.visible = visible_;
    284   attach_params.opaque = !GetAllowTransparencyAttribute();
    285   attach_params.embedder_frame_url = embedder_frame_url_;
    286   attach_params.origin = plugin_rect().origin();
    287   GetSizeParams(&attach_params.auto_size_params,
    288                 &attach_params.resize_guest_params,
    289                 false);
    290 
    291   browser_plugin_manager()->Send(
    292       new BrowserPluginHostMsg_Attach(render_view_routing_id_,
    293                                       guest_instance_id_, attach_params,
    294                                       *extra_params));
    295 }
    296 
    297 void BrowserPlugin::DidCommitCompositorFrame() {
    298   if (compositing_helper_.get())
    299     compositing_helper_->DidCommitCompositorFrame();
    300 }
    301 
    302 void BrowserPlugin::OnAdvanceFocus(int guest_instance_id, bool reverse) {
    303   DCHECK(render_view_.get());
    304   render_view_->GetWebView()->advanceFocus(reverse);
    305 }
    306 
    307 void BrowserPlugin::OnAttachACK(int guest_instance_id) {
    308   attached_ = true;
    309 }
    310 
    311 void BrowserPlugin::OnBuffersSwapped(
    312     int instance_id,
    313     const FrameMsg_BuffersSwapped_Params& params) {
    314   EnableCompositing(true);
    315 
    316   compositing_helper_->OnBuffersSwapped(params.size,
    317                                         params.mailbox,
    318                                         params.gpu_route_id,
    319                                         params.gpu_host_id,
    320                                         GetDeviceScaleFactor());
    321 }
    322 
    323 void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) {
    324   BrowserPluginMsg_CompositorFrameSwapped::Param param;
    325   if (!BrowserPluginMsg_CompositorFrameSwapped::Read(&message, &param))
    326     return;
    327   scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
    328   param.b.frame.AssignTo(frame.get());
    329 
    330   EnableCompositing(true);
    331   compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
    332                                                 param.b.producing_route_id,
    333                                                 param.b.output_surface_id,
    334                                                 param.b.producing_host_id,
    335                                                 param.b.shared_memory_handle);
    336 }
    337 
    338 void BrowserPlugin::OnCopyFromCompositingSurface(int guest_instance_id,
    339                                                  int request_id,
    340                                                  gfx::Rect source_rect,
    341                                                  gfx::Size dest_size) {
    342   if (!compositing_helper_) {
    343     browser_plugin_manager()->Send(
    344         new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck(
    345             render_view_routing_id_,
    346             guest_instance_id_,
    347             request_id,
    348             SkBitmap()));
    349     return;
    350   }
    351   compositing_helper_->CopyFromCompositingSurface(request_id, source_rect,
    352                                                   dest_size);
    353 }
    354 
    355 void BrowserPlugin::OnGuestContentWindowReady(int guest_instance_id,
    356                                               int content_window_routing_id) {
    357   DCHECK(content_window_routing_id != MSG_ROUTING_NONE);
    358   content_window_routing_id_ = content_window_routing_id;
    359 }
    360 
    361 void BrowserPlugin::OnGuestGone(int guest_instance_id) {
    362   guest_crashed_ = true;
    363 
    364   // Turn off compositing so we can display the sad graphic. Changes to
    365   // compositing state will show up at a later time after a layout and commit.
    366   EnableCompositing(false);
    367 
    368   // Queue up showing the sad graphic to give content embedders an opportunity
    369   // to fire their listeners and potentially overlay the webview with custom
    370   // behavior. If the BrowserPlugin is destroyed in the meantime, then the
    371   // task will not be executed.
    372   base::MessageLoop::current()->PostTask(
    373       FROM_HERE,
    374       base::Bind(&BrowserPlugin::ShowSadGraphic,
    375                  weak_ptr_factory_.GetWeakPtr()));
    376 }
    377 
    378 void BrowserPlugin::OnSetCursor(int guest_instance_id,
    379                                 const WebCursor& cursor) {
    380   cursor_ = cursor;
    381 }
    382 
    383 void BrowserPlugin::OnSetMouseLock(int guest_instance_id,
    384                                    bool enable) {
    385   if (enable) {
    386     if (mouse_locked_)
    387       return;
    388     render_view_->mouse_lock_dispatcher()->LockMouse(this);
    389   } else {
    390     if (!mouse_locked_) {
    391       OnLockMouseACK(false);
    392       return;
    393     }
    394     render_view_->mouse_lock_dispatcher()->UnlockMouse(this);
    395   }
    396 }
    397 
    398 void BrowserPlugin::OnShouldAcceptTouchEvents(int guest_instance_id,
    399                                               bool accept) {
    400   if (container()) {
    401     container()->requestTouchEventType(accept ?
    402         blink::WebPluginContainer::TouchEventRequestTypeRaw :
    403         blink::WebPluginContainer::TouchEventRequestTypeNone);
    404   }
    405 }
    406 
    407 void BrowserPlugin::OnUpdateRect(
    408     int guest_instance_id,
    409     const BrowserPluginMsg_UpdateRect_Params& params) {
    410   // Note that there is no need to send ACK for this message.
    411   // If the guest has updated pixels then it is no longer crashed.
    412   guest_crashed_ = false;
    413 
    414   bool auto_size = GetAutoSizeAttribute();
    415   // We receive a resize ACK in regular mode, but not in autosize.
    416   // In Compositing mode, we need to do it here so we can continue sending
    417   // resize messages when needed.
    418   if (params.is_resize_ack || (auto_size || is_auto_size_state_dirty_))
    419     paint_ack_received_ = true;
    420 
    421   bool was_auto_size_state_dirty = auto_size && is_auto_size_state_dirty_;
    422   is_auto_size_state_dirty_ = false;
    423 
    424   if ((!auto_size && (width() != params.view_size.width() ||
    425                       height() != params.view_size.height())) ||
    426       (auto_size && was_auto_size_state_dirty) ||
    427       GetDeviceScaleFactor() != params.scale_factor) {
    428     UpdateGuestAutoSizeState(auto_size);
    429     return;
    430   }
    431 
    432   if (auto_size && (params.view_size != last_view_size_))
    433     last_view_size_ = params.view_size;
    434 
    435   BrowserPluginHostMsg_AutoSize_Params auto_size_params;
    436   BrowserPluginHostMsg_ResizeGuest_Params resize_guest_params;
    437 
    438   // BrowserPluginHostMsg_UpdateRect_ACK is used by both the compositing and
    439   // software paths to piggyback updated autosize parameters.
    440   if (auto_size)
    441     PopulateAutoSizeParameters(&auto_size_params, auto_size);
    442 
    443   browser_plugin_manager()->Send(
    444       new BrowserPluginHostMsg_SetAutoSize(render_view_routing_id_,
    445                                            guest_instance_id_,
    446                                            auto_size_params,
    447                                            resize_guest_params));
    448 }
    449 
    450 void BrowserPlugin::ParseSizeContraintsChanged() {
    451   bool auto_size = GetAutoSizeAttribute();
    452   if (auto_size) {
    453     is_auto_size_state_dirty_ = true;
    454     UpdateGuestAutoSizeState(true);
    455   }
    456 }
    457 
    458 bool BrowserPlugin::InAutoSizeBounds(const gfx::Size& size) const {
    459   return size.width() <= GetAdjustedMaxWidth() &&
    460       size.height() <= GetAdjustedMaxHeight();
    461 }
    462 
    463 NPObject* BrowserPlugin::GetContentWindow() const {
    464   if (content_window_routing_id_ == MSG_ROUTING_NONE)
    465     return NULL;
    466   RenderViewImpl* guest_render_view = RenderViewImpl::FromRoutingID(
    467       content_window_routing_id_);
    468   if (!guest_render_view)
    469     return NULL;
    470   blink::WebFrame* guest_frame = guest_render_view->GetWebView()->mainFrame();
    471   return guest_frame->windowObject();
    472 }
    473 
    474 bool BrowserPlugin::HasGuestInstanceID() const {
    475   return guest_instance_id_ != browser_plugin::kInstanceIDNone;
    476 }
    477 
    478 void BrowserPlugin::ShowSadGraphic() {
    479   // If the BrowserPlugin is scheduled to be deleted, then container_ will be
    480   // NULL so we shouldn't attempt to access it.
    481   if (container_)
    482     container_->invalidate();
    483 }
    484 
    485 float BrowserPlugin::GetDeviceScaleFactor() const {
    486   if (!render_view_.get())
    487     return 1.0f;
    488   return render_view_->GetWebView()->deviceScaleFactor();
    489 }
    490 
    491 void BrowserPlugin::UpdateDeviceScaleFactor(float device_scale_factor) {
    492   if (last_device_scale_factor_ == device_scale_factor || !paint_ack_received_)
    493     return;
    494 
    495   BrowserPluginHostMsg_ResizeGuest_Params params;
    496   PopulateResizeGuestParameters(&params, plugin_size(), true);
    497   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
    498       render_view_routing_id_,
    499       guest_instance_id_,
    500       params));
    501 }
    502 
    503 void BrowserPlugin::UpdateGuestFocusState() {
    504   if (!HasGuestInstanceID())
    505     return;
    506   bool should_be_focused = ShouldGuestBeFocused();
    507   browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetFocus(
    508       render_view_routing_id_,
    509       guest_instance_id_,
    510       should_be_focused));
    511 }
    512 
    513 bool BrowserPlugin::ShouldGuestBeFocused() const {
    514   bool embedder_focused = false;
    515   if (render_view_.get())
    516     embedder_focused = render_view_->has_focus();
    517   return plugin_focused_ && embedder_focused;
    518 }
    519 
    520 blink::WebPluginContainer* BrowserPlugin::container() const {
    521   return container_;
    522 }
    523 
    524 bool BrowserPlugin::initialize(WebPluginContainer* container) {
    525   if (!container)
    526     return false;
    527 
    528   // Tell |container| to allow this plugin to use script objects.
    529   npp_.reset(new NPP_t);
    530   container->allowScriptObjects();
    531 
    532   bindings_.reset(new BrowserPluginBindings(this));
    533   container_ = container;
    534   container_->setWantsWheelEvents(true);
    535   // This is a way to notify observers of our attributes that we have the
    536   // bindings ready. This also means that this plugin is available in render
    537   // tree.
    538   UpdateDOMAttribute("internalbindings", "true");
    539   return true;
    540 }
    541 
    542 void BrowserPlugin::EnableCompositing(bool enable) {
    543   bool enabled = !!compositing_helper_;
    544   if (enabled == enable)
    545     return;
    546 
    547   if (enable) {
    548     DCHECK(!compositing_helper_.get());
    549     if (!compositing_helper_.get()) {
    550       compositing_helper_ =
    551           ChildFrameCompositingHelper::CreateCompositingHelperForBrowserPlugin(
    552               weak_ptr_factory_.GetWeakPtr());
    553     }
    554   }
    555   compositing_helper_->EnableCompositing(enable);
    556   compositing_helper_->SetContentsOpaque(!GetAllowTransparencyAttribute());
    557 
    558   if (!enable) {
    559     DCHECK(compositing_helper_.get());
    560     compositing_helper_->OnContainerDestroy();
    561     compositing_helper_ = NULL;
    562   }
    563 }
    564 
    565 void BrowserPlugin::destroy() {
    566   // If the plugin was initialized then it has a valid |npp_| identifier, and
    567   // the |container_| must clear references to the plugin's script objects.
    568   DCHECK(!npp_ || container_);
    569   if (container_)
    570     container_->clearScriptObjects();
    571 
    572   if (compositing_helper_.get())
    573     compositing_helper_->OnContainerDestroy();
    574   container_ = NULL;
    575   // Will be a no-op if the mouse is not currently locked.
    576   if (render_view_.get())
    577     render_view_->mouse_lock_dispatcher()->OnLockTargetDestroyed(this);
    578   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    579 }
    580 
    581 NPObject* BrowserPlugin::scriptableObject() {
    582   if (!bindings_)
    583     return NULL;
    584 
    585   NPObject* browser_plugin_np_object(bindings_->np_object());
    586   // The object is expected to be retained before it is returned.
    587   blink::WebBindings::retainObject(browser_plugin_np_object);
    588   return browser_plugin_np_object;
    589 }
    590 
    591 NPP BrowserPlugin::pluginNPP() {
    592   return npp_.get();
    593 }
    594 
    595 bool BrowserPlugin::supportsKeyboardFocus() const {
    596   return true;
    597 }
    598 
    599 bool BrowserPlugin::supportsEditCommands() const {
    600   return true;
    601 }
    602 
    603 bool BrowserPlugin::supportsInputMethod() const {
    604   return true;
    605 }
    606 
    607 bool BrowserPlugin::canProcessDrag() const {
    608   return true;
    609 }
    610 
    611 void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
    612   if (guest_crashed_) {
    613     if (!sad_guest_)  // Lazily initialize bitmap.
    614       sad_guest_ = content::GetContentClient()->renderer()->
    615           GetSadWebViewBitmap();
    616     // content_shell does not have the sad plugin bitmap, so we'll paint black
    617     // instead to make it clear that something went wrong.
    618     if (sad_guest_) {
    619       PaintSadPlugin(canvas, plugin_rect_, *sad_guest_);
    620       return;
    621     }
    622   }
    623   SkAutoCanvasRestore auto_restore(canvas, true);
    624   canvas->translate(plugin_rect_.x(), plugin_rect_.y());
    625   SkRect image_data_rect = SkRect::MakeXYWH(
    626       SkIntToScalar(0),
    627       SkIntToScalar(0),
    628       SkIntToScalar(plugin_rect_.width()),
    629       SkIntToScalar(plugin_rect_.height()));
    630   canvas->clipRect(image_data_rect);
    631   // Paint black or white in case we have nothing in our backing store or we
    632   // need to show a gutter.
    633   SkPaint paint;
    634   paint.setStyle(SkPaint::kFill_Style);
    635   paint.setColor(guest_crashed_ ? SK_ColorBLACK : SK_ColorWHITE);
    636   canvas->drawRect(image_data_rect, paint);
    637 }
    638 
    639 // static
    640 bool BrowserPlugin::ShouldForwardToBrowserPlugin(
    641     const IPC::Message& message) {
    642   switch (message.type()) {
    643     case BrowserPluginMsg_AdvanceFocus::ID:
    644     case BrowserPluginMsg_Attach_ACK::ID:
    645     case BrowserPluginMsg_BuffersSwapped::ID:
    646     case BrowserPluginMsg_CompositorFrameSwapped::ID:
    647     case BrowserPluginMsg_CopyFromCompositingSurface::ID:
    648     case BrowserPluginMsg_GuestContentWindowReady::ID:
    649     case BrowserPluginMsg_GuestGone::ID:
    650     case BrowserPluginMsg_SetCursor::ID:
    651     case BrowserPluginMsg_SetMouseLock::ID:
    652     case BrowserPluginMsg_ShouldAcceptTouchEvents::ID:
    653     case BrowserPluginMsg_UpdateRect::ID:
    654       return true;
    655     default:
    656       break;
    657   }
    658   return false;
    659 }
    660 
    661 void BrowserPlugin::updateGeometry(
    662     const WebRect& window_rect,
    663     const WebRect& clip_rect,
    664     const WebVector<WebRect>& cut_outs_rects,
    665     bool is_visible) {
    666   int old_width = width();
    667   int old_height = height();
    668   plugin_rect_ = window_rect;
    669   if (!attached())
    670     return;
    671 
    672   // In AutoSize mode, guests don't care when the BrowserPlugin container is
    673   // resized. If |!paint_ack_received_|, then we are still waiting on a
    674   // previous resize to be ACK'ed and so we don't issue additional resizes
    675   // until the previous one is ACK'ed.
    676   // TODO(mthiesse): Assess the performance of calling GetAutoSizeAttribute() on
    677   // resize.
    678   if (!paint_ack_received_ ||
    679       (old_width == window_rect.width && old_height == window_rect.height) ||
    680       GetAutoSizeAttribute()) {
    681     // Let the browser know about the updated view rect.
    682     browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateGeometry(
    683         render_view_routing_id_, guest_instance_id_, plugin_rect_));
    684     return;
    685   }
    686 
    687   BrowserPluginHostMsg_ResizeGuest_Params params;
    688   PopulateResizeGuestParameters(&params, plugin_size(), false);
    689   paint_ack_received_ = false;
    690   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
    691       render_view_routing_id_,
    692       guest_instance_id_,
    693       params));
    694 }
    695 
    696 void BrowserPlugin::PopulateResizeGuestParameters(
    697     BrowserPluginHostMsg_ResizeGuest_Params* params,
    698     const gfx::Size& view_size,
    699     bool needs_repaint) {
    700   params->size_changed = true;
    701   params->view_size = view_size;
    702   params->repaint = needs_repaint;
    703   params->scale_factor = GetDeviceScaleFactor();
    704   if (last_device_scale_factor_ != params->scale_factor){
    705     DCHECK(params->repaint);
    706     last_device_scale_factor_ = params->scale_factor;
    707   }
    708 }
    709 
    710 void BrowserPlugin::GetSizeParams(
    711     BrowserPluginHostMsg_AutoSize_Params* auto_size_params,
    712     BrowserPluginHostMsg_ResizeGuest_Params* resize_guest_params,
    713     bool needs_repaint) {
    714   if (auto_size_params) {
    715     PopulateAutoSizeParameters(auto_size_params, GetAutoSizeAttribute());
    716   } else {
    717     max_auto_size_ = gfx::Size();
    718   }
    719   gfx::Size view_size = (auto_size_params && auto_size_params->enable) ?
    720       auto_size_params->max_size : gfx::Size(width(), height());
    721   if (view_size.IsEmpty())
    722     return;
    723   paint_ack_received_ = false;
    724   PopulateResizeGuestParameters(resize_guest_params, view_size, needs_repaint);
    725 }
    726 
    727 void BrowserPlugin::updateFocus(bool focused) {
    728   plugin_focused_ = focused;
    729   UpdateGuestFocusState();
    730 }
    731 
    732 void BrowserPlugin::updateVisibility(bool visible) {
    733   if (visible_ == visible)
    734     return;
    735 
    736   visible_ = visible;
    737   if (!HasGuestInstanceID())
    738     return;
    739 
    740   if (compositing_helper_.get())
    741     compositing_helper_->UpdateVisibility(visible);
    742 
    743   browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetVisibility(
    744       render_view_routing_id_,
    745       guest_instance_id_,
    746       visible));
    747 }
    748 
    749 bool BrowserPlugin::acceptsInputEvents() {
    750   return true;
    751 }
    752 
    753 bool BrowserPlugin::handleInputEvent(const blink::WebInputEvent& event,
    754                                      blink::WebCursorInfo& cursor_info) {
    755   if (guest_crashed_ || !HasGuestInstanceID())
    756     return false;
    757 
    758   if (event.type == blink::WebInputEvent::ContextMenu)
    759     return true;
    760 
    761   const blink::WebInputEvent* modified_event = &event;
    762   scoped_ptr<blink::WebTouchEvent> touch_event;
    763   if (blink::WebInputEvent::isTouchEventType(event.type)) {
    764     const blink::WebTouchEvent* orig_touch_event =
    765         static_cast<const blink::WebTouchEvent*>(&event);
    766 
    767     touch_event.reset(new blink::WebTouchEvent());
    768     memcpy(touch_event.get(), orig_touch_event, sizeof(blink::WebTouchEvent));
    769 
    770     // TODO(bokan): Blink passes back a WebGestureEvent with a touches,
    771     // changedTouches, and targetTouches lists; however, it doesn't set
    772     // the state field on the touches which is what the RenderWidget uses
    773     // to create a WebCore::TouchEvent. crbug.com/358132 tracks removing
    774     // these multiple lists from WebTouchEvent since they lead to misuse
    775     // like this and are functionally unused. In the mean time we'll setup
    776     // the state field here manually to fix multi-touch BrowserPlugins.
    777     for (size_t i = 0; i < touch_event->touchesLength; ++i) {
    778       blink::WebTouchPoint& touch = touch_event->touches[i];
    779       touch.state = blink::WebTouchPoint::StateStationary;
    780       for (size_t j = 0; j < touch_event->changedTouchesLength; ++j) {
    781         blink::WebTouchPoint& changed_touch = touch_event->changedTouches[j];
    782         if (touch.id == changed_touch.id) {
    783           touch.state = changed_touch.state;
    784           break;
    785         }
    786       }
    787     }
    788 
    789     // For End and Cancel, Blink gives BrowserPlugin a list of touches that
    790     // are down, but the browser process expects a list of all touches. We
    791     // modify these events here to match these expectations.
    792     if (event.type == blink::WebInputEvent::TouchEnd ||
    793         event.type == blink::WebInputEvent::TouchCancel) {
    794       if (touch_event->changedTouchesLength > 0) {
    795         memcpy(&touch_event->touches[touch_event->touchesLength],
    796                &touch_event->changedTouches,
    797               touch_event->changedTouchesLength * sizeof(blink::WebTouchPoint));
    798         touch_event->touchesLength += touch_event->changedTouchesLength;
    799       }
    800     }
    801     modified_event = touch_event.get();
    802   }
    803 
    804   if (blink::WebInputEvent::isKeyboardEventType(event.type) &&
    805       !edit_commands_.empty()) {
    806     browser_plugin_manager()->Send(
    807         new BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent(
    808             render_view_routing_id_,
    809             guest_instance_id_,
    810             edit_commands_));
    811     edit_commands_.clear();
    812   }
    813 
    814   browser_plugin_manager()->Send(
    815       new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
    816                                                 guest_instance_id_,
    817                                                 plugin_rect_,
    818                                                 modified_event));
    819   GetWebKitCursorInfo(cursor_, &cursor_info);
    820   return true;
    821 }
    822 
    823 bool BrowserPlugin::handleDragStatusUpdate(blink::WebDragStatus drag_status,
    824                                            const blink::WebDragData& drag_data,
    825                                            blink::WebDragOperationsMask mask,
    826                                            const blink::WebPoint& position,
    827                                            const blink::WebPoint& screen) {
    828   if (guest_crashed_ || !HasGuestInstanceID())
    829     return false;
    830   browser_plugin_manager()->Send(
    831       new BrowserPluginHostMsg_DragStatusUpdate(
    832         render_view_routing_id_,
    833         guest_instance_id_,
    834         drag_status,
    835         DropDataBuilder::Build(drag_data),
    836         mask,
    837         position));
    838   return true;
    839 }
    840 
    841 void BrowserPlugin::didReceiveResponse(
    842     const blink::WebURLResponse& response) {
    843 }
    844 
    845 void BrowserPlugin::didReceiveData(const char* data, int data_length) {
    846   if (auto_navigate_) {
    847     std::string value(data, data_length);
    848     html_string_ += value;
    849   }
    850 }
    851 
    852 void BrowserPlugin::didFinishLoading() {
    853   if (auto_navigate_) {
    854     // TODO(lazyboy): Make |auto_navigate_| stuff work.
    855     UpdateDOMAttribute(content::browser_plugin::kAttributeSrc, html_string_);
    856   }
    857 }
    858 
    859 void BrowserPlugin::didFailLoading(const blink::WebURLError& error) {
    860 }
    861 
    862 void BrowserPlugin::didFinishLoadingFrameRequest(const blink::WebURL& url,
    863                                                  void* notify_data) {
    864 }
    865 
    866 void BrowserPlugin::didFailLoadingFrameRequest(
    867     const blink::WebURL& url,
    868     void* notify_data,
    869     const blink::WebURLError& error) {
    870 }
    871 
    872 bool BrowserPlugin::executeEditCommand(const blink::WebString& name) {
    873   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ExecuteEditCommand(
    874       render_view_routing_id_,
    875       guest_instance_id_,
    876       name.utf8()));
    877 
    878   // BrowserPlugin swallows edit commands.
    879   return true;
    880 }
    881 
    882 bool BrowserPlugin::executeEditCommand(const blink::WebString& name,
    883                                        const blink::WebString& value) {
    884   edit_commands_.push_back(EditCommand(name.utf8(), value.utf8()));
    885   // BrowserPlugin swallows edit commands.
    886   return true;
    887 }
    888 
    889 bool BrowserPlugin::setComposition(
    890     const blink::WebString& text,
    891     const blink::WebVector<blink::WebCompositionUnderline>& underlines,
    892     int selectionStart,
    893     int selectionEnd) {
    894   if (!HasGuestInstanceID())
    895     return false;
    896   std::vector<blink::WebCompositionUnderline> std_underlines;
    897   for (size_t i = 0; i < underlines.size(); ++i) {
    898     std_underlines.push_back(underlines[i]);
    899   }
    900   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeSetComposition(
    901       render_view_routing_id_,
    902       guest_instance_id_,
    903       text.utf8(),
    904       std_underlines,
    905       selectionStart,
    906       selectionEnd));
    907   // TODO(kochi): This assumes the IPC handling always succeeds.
    908   return true;
    909 }
    910 
    911 bool BrowserPlugin::confirmComposition(
    912     const blink::WebString& text,
    913     blink::WebWidget::ConfirmCompositionBehavior selectionBehavior) {
    914   if (!HasGuestInstanceID())
    915     return false;
    916   bool keep_selection = (selectionBehavior == blink::WebWidget::KeepSelection);
    917   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeConfirmComposition(
    918       render_view_routing_id_,
    919       guest_instance_id_,
    920       text.utf8(),
    921       keep_selection));
    922   // TODO(kochi): This assumes the IPC handling always succeeds.
    923   return true;
    924 }
    925 
    926 void BrowserPlugin::extendSelectionAndDelete(int before, int after) {
    927   if (!HasGuestInstanceID())
    928     return;
    929   browser_plugin_manager()->Send(
    930       new BrowserPluginHostMsg_ExtendSelectionAndDelete(
    931           render_view_routing_id_,
    932           guest_instance_id_,
    933           before,
    934           after));
    935 }
    936 
    937 void BrowserPlugin::OnLockMouseACK(bool succeeded) {
    938   mouse_locked_ = succeeded;
    939   browser_plugin_manager()->Send(new BrowserPluginHostMsg_LockMouse_ACK(
    940       render_view_routing_id_,
    941       guest_instance_id_,
    942       succeeded));
    943 }
    944 
    945 void BrowserPlugin::OnMouseLockLost() {
    946   mouse_locked_ = false;
    947   browser_plugin_manager()->Send(new BrowserPluginHostMsg_UnlockMouse_ACK(
    948       render_view_routing_id_,
    949       guest_instance_id_));
    950 }
    951 
    952 bool BrowserPlugin::HandleMouseLockedInputEvent(
    953     const blink::WebMouseEvent& event) {
    954   browser_plugin_manager()->Send(
    955       new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
    956                                                 guest_instance_id_,
    957                                                 plugin_rect_,
    958                                                 &event));
    959   return true;
    960 }
    961 
    962 }  // namespace content
    963