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/browser_plugin_delegate.h"
     17 #include "content/public/renderer/content_renderer_client.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/WebElement.h"
     26 #include "third_party/WebKit/public/web/WebInputEvent.h"
     27 #include "third_party/WebKit/public/web/WebPluginContainer.h"
     28 #include "third_party/WebKit/public/web/WebView.h"
     29 #include "third_party/skia/include/core/SkCanvas.h"
     30 #include "ui/events/keycodes/keyboard_codes.h"
     31 
     32 using blink::WebCanvas;
     33 using blink::WebPluginContainer;
     34 using blink::WebPoint;
     35 using blink::WebRect;
     36 using blink::WebURL;
     37 using blink::WebVector;
     38 
     39 namespace {
     40 typedef std::map<blink::WebPluginContainer*, content::BrowserPlugin*>
     41     PluginContainerMap;
     42 static base::LazyInstance<PluginContainerMap> g_plugin_container_map =
     43     LAZY_INSTANCE_INITIALIZER;
     44 }  // namespace
     45 
     46 namespace content {
     47 
     48 // static
     49 BrowserPlugin* BrowserPlugin::GetFromNode(blink::WebNode& node) {
     50   blink::WebPluginContainer* container = node.pluginContainer();
     51   if (!container)
     52     return NULL;
     53 
     54   PluginContainerMap* browser_plugins = g_plugin_container_map.Pointer();
     55   PluginContainerMap::iterator it = browser_plugins->find(container);
     56   return it == browser_plugins->end() ? NULL : it->second;
     57 }
     58 
     59 BrowserPlugin::BrowserPlugin(RenderViewImpl* render_view,
     60                              blink::WebFrame* frame,
     61                              scoped_ptr<BrowserPluginDelegate> delegate)
     62     : attached_(false),
     63       attach_pending_(false),
     64       render_view_(render_view->AsWeakPtr()),
     65       render_view_routing_id_(render_view->GetRoutingID()),
     66       container_(NULL),
     67       last_device_scale_factor_(GetDeviceScaleFactor()),
     68       sad_guest_(NULL),
     69       guest_crashed_(false),
     70       plugin_focused_(false),
     71       visible_(true),
     72       mouse_locked_(false),
     73       browser_plugin_manager_(render_view->GetBrowserPluginManager()),
     74       browser_plugin_instance_id_(browser_plugin::kInstanceIDNone),
     75       contents_opaque_(true),
     76       delegate_(delegate.Pass()),
     77       weak_ptr_factory_(this) {
     78   browser_plugin_instance_id_ = browser_plugin_manager()->GetNextInstanceID();
     79 
     80   if (delegate_)
     81     delegate_->SetElementInstanceID(browser_plugin_instance_id_);
     82 }
     83 
     84 BrowserPlugin::~BrowserPlugin() {
     85   browser_plugin_manager()->RemoveBrowserPlugin(browser_plugin_instance_id_);
     86 
     87   if (!ready())
     88     return;
     89 
     90   browser_plugin_manager()->Send(
     91       new BrowserPluginHostMsg_PluginDestroyed(render_view_routing_id_,
     92                                                browser_plugin_instance_id_));
     93 }
     94 
     95 bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) {
     96   bool handled = true;
     97   IPC_BEGIN_MESSAGE_MAP(BrowserPlugin, message)
     98     IPC_MESSAGE_HANDLER(BrowserPluginMsg_Attach_ACK, OnAttachACK)
     99     IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus)
    100     IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginMsg_CompositorFrameSwapped,
    101                                 OnCompositorFrameSwapped(message))
    102     IPC_MESSAGE_HANDLER(BrowserPluginMsg_CopyFromCompositingSurface,
    103                         OnCopyFromCompositingSurface)
    104     IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone)
    105     IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetContentsOpaque, OnSetContentsOpaque)
    106     IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor)
    107     IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetMouseLock, OnSetMouseLock)
    108     IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents,
    109                         OnShouldAcceptTouchEvents)
    110     IPC_MESSAGE_UNHANDLED(handled = false)
    111   IPC_END_MESSAGE_MAP()
    112   return handled;
    113 }
    114 
    115 void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
    116                                        const std::string& attribute_value) {
    117   if (!container())
    118     return;
    119 
    120   blink::WebElement element = container()->element();
    121   blink::WebString web_attribute_name =
    122       blink::WebString::fromUTF8(attribute_name);
    123   element.setAttribute(web_attribute_name,
    124       blink::WebString::fromUTF8(attribute_value));
    125 }
    126 
    127 void BrowserPlugin::Attach() {
    128   if (ready()) {
    129     attached_ = false;
    130     guest_crashed_ = false;
    131     EnableCompositing(false);
    132     if (compositing_helper_.get()) {
    133       compositing_helper_->OnContainerDestroy();
    134       compositing_helper_ = NULL;
    135     }
    136   }
    137 
    138   // TODO(fsamuel): Add support for reattachment.
    139   BrowserPluginHostMsg_Attach_Params attach_params;
    140   attach_params.focused = ShouldGuestBeFocused();
    141   attach_params.visible = visible_;
    142   attach_params.origin = plugin_rect().origin();
    143   gfx::Size view_size(width(), height());
    144   if (!view_size.IsEmpty()) {
    145     PopulateResizeGuestParameters(view_size,
    146                                   &attach_params.resize_guest_params);
    147   }
    148   browser_plugin_manager()->Send(new BrowserPluginHostMsg_Attach(
    149       render_view_routing_id_,
    150       browser_plugin_instance_id_,
    151       attach_params));
    152 
    153   attach_pending_ = true;
    154 }
    155 
    156 void BrowserPlugin::DidCommitCompositorFrame() {
    157   if (compositing_helper_.get())
    158     compositing_helper_->DidCommitCompositorFrame();
    159 }
    160 
    161 void BrowserPlugin::OnAdvanceFocus(int browser_plugin_instance_id,
    162                                    bool reverse) {
    163   DCHECK(render_view_);
    164   render_view_->GetWebView()->advanceFocus(reverse);
    165 }
    166 
    167 void BrowserPlugin::OnAttachACK(int browser_plugin_instance_id) {
    168   DCHECK(!attached());
    169   attached_ = true;
    170   attach_pending_ = false;
    171 }
    172 
    173 void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) {
    174   BrowserPluginMsg_CompositorFrameSwapped::Param param;
    175   if (!BrowserPluginMsg_CompositorFrameSwapped::Read(&message, &param))
    176     return;
    177 
    178   // Note that there is no need to send ACK for this message.
    179   // If the guest has updated pixels then it is no longer crashed.
    180   guest_crashed_ = false;
    181 
    182   scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
    183   param.b.frame.AssignTo(frame.get());
    184 
    185   EnableCompositing(true);
    186   compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
    187                                                 param.b.producing_route_id,
    188                                                 param.b.output_surface_id,
    189                                                 param.b.producing_host_id,
    190                                                 param.b.shared_memory_handle);
    191 }
    192 
    193 void BrowserPlugin::OnCopyFromCompositingSurface(int browser_plugin_instance_id,
    194                                                  int request_id,
    195                                                  gfx::Rect source_rect,
    196                                                  gfx::Size dest_size) {
    197   if (!compositing_helper_.get()) {
    198     browser_plugin_manager()->Send(
    199         new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck(
    200             render_view_routing_id_,
    201             browser_plugin_instance_id_,
    202             request_id,
    203             SkBitmap()));
    204     return;
    205   }
    206   compositing_helper_->CopyFromCompositingSurface(request_id, source_rect,
    207                                                   dest_size);
    208 }
    209 
    210 void BrowserPlugin::OnGuestGone(int browser_plugin_instance_id) {
    211   guest_crashed_ = true;
    212 
    213   // Turn off compositing so we can display the sad graphic. Changes to
    214   // compositing state will show up at a later time after a layout and commit.
    215   EnableCompositing(false);
    216 
    217   // Queue up showing the sad graphic to give content embedders an opportunity
    218   // to fire their listeners and potentially overlay the webview with custom
    219   // behavior. If the BrowserPlugin is destroyed in the meantime, then the
    220   // task will not be executed.
    221   base::MessageLoop::current()->PostTask(
    222       FROM_HERE,
    223       base::Bind(&BrowserPlugin::ShowSadGraphic,
    224                  weak_ptr_factory_.GetWeakPtr()));
    225 }
    226 
    227 void BrowserPlugin::OnSetContentsOpaque(int browser_plugin_instance_id,
    228                                         bool opaque) {
    229   if (contents_opaque_ == opaque)
    230     return;
    231   contents_opaque_ = opaque;
    232   if (compositing_helper_.get())
    233     compositing_helper_->SetContentsOpaque(opaque);
    234 }
    235 
    236 void BrowserPlugin::OnSetCursor(int browser_plugin_instance_id,
    237                                 const WebCursor& cursor) {
    238   cursor_ = cursor;
    239 }
    240 
    241 void BrowserPlugin::OnSetMouseLock(int browser_plugin_instance_id,
    242                                    bool enable) {
    243   if (enable) {
    244     if (mouse_locked_)
    245       return;
    246     render_view_->mouse_lock_dispatcher()->LockMouse(this);
    247   } else {
    248     if (!mouse_locked_) {
    249       OnLockMouseACK(false);
    250       return;
    251     }
    252     render_view_->mouse_lock_dispatcher()->UnlockMouse(this);
    253   }
    254 }
    255 
    256 void BrowserPlugin::OnShouldAcceptTouchEvents(int browser_plugin_instance_id,
    257                                               bool accept) {
    258   if (container()) {
    259     container()->requestTouchEventType(
    260         accept ? WebPluginContainer::TouchEventRequestTypeRaw
    261                : WebPluginContainer::TouchEventRequestTypeNone);
    262   }
    263 }
    264 
    265 void BrowserPlugin::ShowSadGraphic() {
    266   // If the BrowserPlugin is scheduled to be deleted, then container_ will be
    267   // NULL so we shouldn't attempt to access it.
    268   if (container_)
    269     container_->invalidate();
    270 }
    271 
    272 float BrowserPlugin::GetDeviceScaleFactor() const {
    273   if (!render_view_)
    274     return 1.0f;
    275   return render_view_->GetWebView()->deviceScaleFactor();
    276 }
    277 
    278 void BrowserPlugin::UpdateDeviceScaleFactor() {
    279   if (last_device_scale_factor_ == GetDeviceScaleFactor())
    280     return;
    281 
    282   BrowserPluginHostMsg_ResizeGuest_Params params;
    283   PopulateResizeGuestParameters(plugin_size(), &params);
    284   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
    285       render_view_routing_id_,
    286       browser_plugin_instance_id_,
    287       params));
    288 }
    289 
    290 void BrowserPlugin::UpdateGuestFocusState() {
    291   if (!ready())
    292     return;
    293   bool should_be_focused = ShouldGuestBeFocused();
    294   browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetFocus(
    295       render_view_routing_id_,
    296       browser_plugin_instance_id_,
    297       should_be_focused));
    298 }
    299 
    300 bool BrowserPlugin::ShouldGuestBeFocused() const {
    301   bool embedder_focused = false;
    302   if (render_view_)
    303     embedder_focused = render_view_->has_focus();
    304   return plugin_focused_ && embedder_focused;
    305 }
    306 
    307 WebPluginContainer* BrowserPlugin::container() const {
    308   return container_;
    309 }
    310 
    311 bool BrowserPlugin::initialize(WebPluginContainer* container) {
    312   if (!container)
    313     return false;
    314 
    315   container_ = container;
    316   container_->setWantsWheelEvents(true);
    317 
    318   g_plugin_container_map.Get().insert(std::make_pair(container_, this));
    319 
    320   // This is a way to notify observers of our attributes that this plugin is
    321   // available in render tree.
    322   // TODO(lazyboy): This should be done through the delegate instead. Perhaps
    323   // by firing an event from there.
    324   UpdateDOMAttribute("internalinstanceid",
    325                      base::IntToString(browser_plugin_instance_id_));
    326 
    327   browser_plugin_manager()->AddBrowserPlugin(browser_plugin_instance_id_, this);
    328   return true;
    329 }
    330 
    331 void BrowserPlugin::EnableCompositing(bool enable) {
    332   bool enabled = !!compositing_helper_.get();
    333   if (enabled == enable)
    334     return;
    335 
    336   if (enable) {
    337     DCHECK(!compositing_helper_.get());
    338     if (!compositing_helper_.get()) {
    339       compositing_helper_ = ChildFrameCompositingHelper::CreateForBrowserPlugin(
    340           weak_ptr_factory_.GetWeakPtr());
    341     }
    342   }
    343   compositing_helper_->EnableCompositing(enable);
    344   compositing_helper_->SetContentsOpaque(contents_opaque_);
    345 
    346   if (!enable) {
    347     DCHECK(compositing_helper_.get());
    348     compositing_helper_->OnContainerDestroy();
    349     compositing_helper_ = NULL;
    350   }
    351 }
    352 
    353 void BrowserPlugin::destroy() {
    354   if (container_) {
    355     //container_->clearScriptObjects();
    356 
    357     // The BrowserPlugin's WebPluginContainer is deleted immediately after this
    358     // call returns, so let's not keep a reference to it around.
    359     g_plugin_container_map.Get().erase(container_);
    360   }
    361 
    362   if (compositing_helper_.get())
    363     compositing_helper_->OnContainerDestroy();
    364   container_ = NULL;
    365   // Will be a no-op if the mouse is not currently locked.
    366   if (render_view_)
    367     render_view_->mouse_lock_dispatcher()->OnLockTargetDestroyed(this);
    368   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    369 }
    370 
    371 bool BrowserPlugin::supportsKeyboardFocus() const {
    372   return true;
    373 }
    374 
    375 bool BrowserPlugin::supportsEditCommands() const {
    376   return true;
    377 }
    378 
    379 bool BrowserPlugin::supportsInputMethod() const {
    380   return true;
    381 }
    382 
    383 bool BrowserPlugin::canProcessDrag() const {
    384   return true;
    385 }
    386 
    387 void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
    388   if (guest_crashed_) {
    389     if (!sad_guest_)  // Lazily initialize bitmap.
    390       sad_guest_ = content::GetContentClient()->renderer()->
    391           GetSadWebViewBitmap();
    392     // content_shell does not have the sad plugin bitmap, so we'll paint black
    393     // instead to make it clear that something went wrong.
    394     if (sad_guest_) {
    395       PaintSadPlugin(canvas, plugin_rect_, *sad_guest_);
    396       return;
    397     }
    398   }
    399   SkAutoCanvasRestore auto_restore(canvas, true);
    400   canvas->translate(plugin_rect_.x(), plugin_rect_.y());
    401   SkRect image_data_rect = SkRect::MakeXYWH(
    402       SkIntToScalar(0),
    403       SkIntToScalar(0),
    404       SkIntToScalar(plugin_rect_.width()),
    405       SkIntToScalar(plugin_rect_.height()));
    406   canvas->clipRect(image_data_rect);
    407   // Paint black or white in case we have nothing in our backing store or we
    408   // need to show a gutter.
    409   SkPaint paint;
    410   paint.setStyle(SkPaint::kFill_Style);
    411   paint.setColor(guest_crashed_ ? SK_ColorBLACK : SK_ColorWHITE);
    412   canvas->drawRect(image_data_rect, paint);
    413 }
    414 
    415 // static
    416 bool BrowserPlugin::ShouldForwardToBrowserPlugin(
    417     const IPC::Message& message) {
    418   switch (message.type()) {
    419     case BrowserPluginMsg_Attach_ACK::ID:
    420     case BrowserPluginMsg_AdvanceFocus::ID:
    421     case BrowserPluginMsg_CompositorFrameSwapped::ID:
    422     case BrowserPluginMsg_CopyFromCompositingSurface::ID:
    423     case BrowserPluginMsg_GuestGone::ID:
    424     case BrowserPluginMsg_SetContentsOpaque::ID:
    425     case BrowserPluginMsg_SetCursor::ID:
    426     case BrowserPluginMsg_SetMouseLock::ID:
    427     case BrowserPluginMsg_ShouldAcceptTouchEvents::ID:
    428       return true;
    429     default:
    430       break;
    431   }
    432   return false;
    433 }
    434 
    435 void BrowserPlugin::updateGeometry(
    436     const WebRect& window_rect,
    437     const WebRect& clip_rect,
    438     const WebVector<WebRect>& cut_outs_rects,
    439     bool is_visible) {
    440   int old_width = width();
    441   int old_height = height();
    442   plugin_rect_ = window_rect;
    443   if (!attached())
    444     return;
    445 
    446   if (old_width == window_rect.width && old_height == window_rect.height) {
    447     // Let the browser know about the updated view rect.
    448     browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateGeometry(
    449         render_view_routing_id_, browser_plugin_instance_id_, plugin_rect_));
    450     return;
    451   }
    452 
    453   BrowserPluginHostMsg_ResizeGuest_Params params;
    454   PopulateResizeGuestParameters(plugin_size(), &params);
    455   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
    456       render_view_routing_id_,
    457       browser_plugin_instance_id_,
    458       params));
    459 }
    460 
    461 void BrowserPlugin::PopulateResizeGuestParameters(
    462     const gfx::Size& view_size,
    463     BrowserPluginHostMsg_ResizeGuest_Params* params) {
    464   params->view_size = view_size;
    465   params->scale_factor = GetDeviceScaleFactor();
    466   if (last_device_scale_factor_ != params->scale_factor) {
    467     last_device_scale_factor_ = params->scale_factor;
    468     params->repaint = true;
    469   }
    470 }
    471 
    472 void BrowserPlugin::updateFocus(bool focused) {
    473   plugin_focused_ = focused;
    474   UpdateGuestFocusState();
    475 }
    476 
    477 void BrowserPlugin::updateVisibility(bool visible) {
    478   if (visible_ == visible)
    479     return;
    480 
    481   visible_ = visible;
    482   if (!ready())
    483     return;
    484 
    485   if (compositing_helper_.get())
    486     compositing_helper_->UpdateVisibility(visible);
    487 
    488   browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetVisibility(
    489       render_view_routing_id_,
    490       browser_plugin_instance_id_,
    491       visible));
    492 }
    493 
    494 bool BrowserPlugin::acceptsInputEvents() {
    495   return true;
    496 }
    497 
    498 bool BrowserPlugin::handleInputEvent(const blink::WebInputEvent& event,
    499                                      blink::WebCursorInfo& cursor_info) {
    500   if (guest_crashed_ || !ready())
    501     return false;
    502 
    503   if (event.type == blink::WebInputEvent::ContextMenu)
    504     return true;
    505 
    506   if (blink::WebInputEvent::isKeyboardEventType(event.type) &&
    507       !edit_commands_.empty()) {
    508     browser_plugin_manager()->Send(
    509         new BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent(
    510             render_view_routing_id_,
    511             browser_plugin_instance_id_,
    512             edit_commands_));
    513     edit_commands_.clear();
    514   }
    515 
    516   browser_plugin_manager()->Send(
    517       new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
    518                                                 browser_plugin_instance_id_,
    519                                                 plugin_rect_,
    520                                                 &event));
    521   GetWebKitCursorInfo(cursor_, &cursor_info);
    522   return true;
    523 }
    524 
    525 bool BrowserPlugin::handleDragStatusUpdate(blink::WebDragStatus drag_status,
    526                                            const blink::WebDragData& drag_data,
    527                                            blink::WebDragOperationsMask mask,
    528                                            const blink::WebPoint& position,
    529                                            const blink::WebPoint& screen) {
    530   if (guest_crashed_ || !ready())
    531     return false;
    532   browser_plugin_manager()->Send(
    533       new BrowserPluginHostMsg_DragStatusUpdate(
    534         render_view_routing_id_,
    535         browser_plugin_instance_id_,
    536         drag_status,
    537         DropDataBuilder::Build(drag_data),
    538         mask,
    539         position));
    540   return true;
    541 }
    542 
    543 void BrowserPlugin::didReceiveResponse(
    544     const blink::WebURLResponse& response) {
    545 }
    546 
    547 void BrowserPlugin::didReceiveData(const char* data, int data_length) {
    548   if (delegate_)
    549     delegate_->DidReceiveData(data, data_length);
    550 }
    551 
    552 void BrowserPlugin::didFinishLoading() {
    553   if (delegate_)
    554     delegate_->DidFinishLoading();
    555 }
    556 
    557 void BrowserPlugin::didFailLoading(const blink::WebURLError& error) {
    558 }
    559 
    560 void BrowserPlugin::didFinishLoadingFrameRequest(const blink::WebURL& url,
    561                                                  void* notify_data) {
    562 }
    563 
    564 void BrowserPlugin::didFailLoadingFrameRequest(
    565     const blink::WebURL& url,
    566     void* notify_data,
    567     const blink::WebURLError& error) {
    568 }
    569 
    570 bool BrowserPlugin::executeEditCommand(const blink::WebString& name) {
    571   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ExecuteEditCommand(
    572       render_view_routing_id_,
    573       browser_plugin_instance_id_,
    574       name.utf8()));
    575 
    576   // BrowserPlugin swallows edit commands.
    577   return true;
    578 }
    579 
    580 bool BrowserPlugin::executeEditCommand(const blink::WebString& name,
    581                                        const blink::WebString& value) {
    582   edit_commands_.push_back(EditCommand(name.utf8(), value.utf8()));
    583   // BrowserPlugin swallows edit commands.
    584   return true;
    585 }
    586 
    587 bool BrowserPlugin::setComposition(
    588     const blink::WebString& text,
    589     const blink::WebVector<blink::WebCompositionUnderline>& underlines,
    590     int selectionStart,
    591     int selectionEnd) {
    592   if (!ready())
    593     return false;
    594   std::vector<blink::WebCompositionUnderline> std_underlines;
    595   for (size_t i = 0; i < underlines.size(); ++i) {
    596     std_underlines.push_back(underlines[i]);
    597   }
    598   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeSetComposition(
    599       render_view_routing_id_,
    600       browser_plugin_instance_id_,
    601       text.utf8(),
    602       std_underlines,
    603       selectionStart,
    604       selectionEnd));
    605   // TODO(kochi): This assumes the IPC handling always succeeds.
    606   return true;
    607 }
    608 
    609 bool BrowserPlugin::confirmComposition(
    610     const blink::WebString& text,
    611     blink::WebWidget::ConfirmCompositionBehavior selectionBehavior) {
    612   if (!ready())
    613     return false;
    614   bool keep_selection = (selectionBehavior == blink::WebWidget::KeepSelection);
    615   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeConfirmComposition(
    616       render_view_routing_id_,
    617       browser_plugin_instance_id_,
    618       text.utf8(),
    619       keep_selection));
    620   // TODO(kochi): This assumes the IPC handling always succeeds.
    621   return true;
    622 }
    623 
    624 void BrowserPlugin::extendSelectionAndDelete(int before, int after) {
    625   if (!ready())
    626     return;
    627   browser_plugin_manager()->Send(
    628       new BrowserPluginHostMsg_ExtendSelectionAndDelete(
    629           render_view_routing_id_,
    630           browser_plugin_instance_id_,
    631           before,
    632           after));
    633 }
    634 
    635 void BrowserPlugin::OnLockMouseACK(bool succeeded) {
    636   mouse_locked_ = succeeded;
    637   browser_plugin_manager()->Send(new BrowserPluginHostMsg_LockMouse_ACK(
    638       render_view_routing_id_,
    639       browser_plugin_instance_id_,
    640       succeeded));
    641 }
    642 
    643 void BrowserPlugin::OnMouseLockLost() {
    644   mouse_locked_ = false;
    645   browser_plugin_manager()->Send(new BrowserPluginHostMsg_UnlockMouse_ACK(
    646       render_view_routing_id_,
    647       browser_plugin_instance_id_));
    648 }
    649 
    650 bool BrowserPlugin::HandleMouseLockedInputEvent(
    651     const blink::WebMouseEvent& event) {
    652   browser_plugin_manager()->Send(
    653       new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
    654                                                 browser_plugin_instance_id_,
    655                                                 plugin_rect_,
    656                                                 &event));
    657   return true;
    658 }
    659 
    660 }  // namespace content
    661