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/json/json_string_value_serializer.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/strings/string_util.h"
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "content/common/browser_plugin/browser_plugin_constants.h"
     14 #include "content/common/browser_plugin/browser_plugin_messages.h"
     15 #include "content/common/view_messages.h"
     16 #include "content/public/common/content_client.h"
     17 #include "content/public/common/content_switches.h"
     18 #include "content/public/renderer/content_renderer_client.h"
     19 #include "content/renderer/browser_plugin/browser_plugin_bindings.h"
     20 #include "content/renderer/browser_plugin/browser_plugin_compositing_helper.h"
     21 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
     22 #include "content/renderer/cursor_utils.h"
     23 #include "content/renderer/drop_data_builder.h"
     24 #include "content/renderer/render_process_impl.h"
     25 #include "content/renderer/render_thread_impl.h"
     26 #include "content/renderer/sad_plugin.h"
     27 #include "content/renderer/v8_value_converter_impl.h"
     28 #include "skia/ext/platform_canvas.h"
     29 #include "third_party/WebKit/public/platform/WebRect.h"
     30 #include "third_party/WebKit/public/web/WebBindings.h"
     31 #include "third_party/WebKit/public/web/WebDOMCustomEvent.h"
     32 #include "third_party/WebKit/public/web/WebDocument.h"
     33 #include "third_party/WebKit/public/web/WebElement.h"
     34 #include "third_party/WebKit/public/web/WebFrame.h"
     35 #include "third_party/WebKit/public/web/WebInputEvent.h"
     36 #include "third_party/WebKit/public/web/WebPluginContainer.h"
     37 #include "third_party/WebKit/public/web/WebPluginParams.h"
     38 #include "third_party/WebKit/public/web/WebScriptSource.h"
     39 #include "third_party/WebKit/public/web/WebView.h"
     40 #include "ui/events/keycodes/keyboard_codes.h"
     41 
     42 #if defined (OS_WIN)
     43 #include "base/sys_info.h"
     44 #endif
     45 
     46 using blink::WebCanvas;
     47 using blink::WebPluginContainer;
     48 using blink::WebPluginParams;
     49 using blink::WebPoint;
     50 using blink::WebRect;
     51 using blink::WebURL;
     52 using blink::WebVector;
     53 
     54 namespace content {
     55 
     56 namespace {
     57 
     58 static std::string GetInternalEventName(const char* event_name) {
     59   return base::StringPrintf("-internal-%s", event_name);
     60 }
     61 
     62 typedef std::map<blink::WebPluginContainer*,
     63                  BrowserPlugin*> PluginContainerMap;
     64 static base::LazyInstance<PluginContainerMap> g_plugin_container_map =
     65     LAZY_INSTANCE_INITIALIZER;
     66 
     67 }  // namespace
     68 
     69 BrowserPlugin::BrowserPlugin(RenderViewImpl* render_view,
     70                              blink::WebFrame* frame)
     71     : guest_instance_id_(browser_plugin::kInstanceIDNone),
     72       attached_(false),
     73       render_view_(render_view->AsWeakPtr()),
     74       render_view_routing_id_(render_view->GetRoutingID()),
     75       container_(NULL),
     76       damage_buffer_sequence_id_(0),
     77       paint_ack_received_(true),
     78       last_device_scale_factor_(1.0f),
     79       sad_guest_(NULL),
     80       guest_crashed_(false),
     81       is_auto_size_state_dirty_(false),
     82       persist_storage_(false),
     83       valid_partition_id_(true),
     84       content_window_routing_id_(MSG_ROUTING_NONE),
     85       plugin_focused_(false),
     86       visible_(true),
     87       before_first_navigation_(true),
     88       mouse_locked_(false),
     89       browser_plugin_manager_(render_view->GetBrowserPluginManager()),
     90       compositing_enabled_(false),
     91       embedder_frame_url_(frame->document().url()),
     92       weak_ptr_factory_(this) {
     93 }
     94 
     95 BrowserPlugin::~BrowserPlugin() {
     96   // If the BrowserPlugin has never navigated then the browser process and
     97   // BrowserPluginManager don't know about it and so there is nothing to do
     98   // here.
     99   if (!HasGuestInstanceID())
    100     return;
    101   browser_plugin_manager()->RemoveBrowserPlugin(guest_instance_id_);
    102   browser_plugin_manager()->Send(
    103       new BrowserPluginHostMsg_PluginDestroyed(render_view_routing_id_,
    104                                                guest_instance_id_));
    105 }
    106 
    107 /*static*/
    108 BrowserPlugin* BrowserPlugin::FromContainer(
    109     blink::WebPluginContainer* container) {
    110   PluginContainerMap* browser_plugins = g_plugin_container_map.Pointer();
    111   PluginContainerMap::iterator it = browser_plugins->find(container);
    112   return it == browser_plugins->end() ? NULL : it->second;
    113 }
    114 
    115 bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) {
    116   bool handled = true;
    117   IPC_BEGIN_MESSAGE_MAP(BrowserPlugin, message)
    118     IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus)
    119     IPC_MESSAGE_HANDLER(BrowserPluginMsg_Attach_ACK, OnAttachACK)
    120     IPC_MESSAGE_HANDLER(BrowserPluginMsg_BuffersSwapped, OnBuffersSwapped)
    121     IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginMsg_CompositorFrameSwapped,
    122                                 OnCompositorFrameSwapped(message))
    123     IPC_MESSAGE_HANDLER(BrowserPluginMsg_CopyFromCompositingSurface,
    124                         OnCopyFromCompositingSurface)
    125     IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestContentWindowReady,
    126                         OnGuestContentWindowReady)
    127     IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone)
    128     IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor)
    129     IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetMouseLock, OnSetMouseLock)
    130     IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents,
    131                         OnShouldAcceptTouchEvents)
    132     IPC_MESSAGE_HANDLER(BrowserPluginMsg_UpdatedName, OnUpdatedName)
    133     IPC_MESSAGE_HANDLER(BrowserPluginMsg_UpdateRect, OnUpdateRect)
    134     IPC_MESSAGE_UNHANDLED(handled = false)
    135   IPC_END_MESSAGE_MAP()
    136   return handled;
    137 }
    138 
    139 void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
    140                                        const std::string& attribute_value) {
    141   if (!container())
    142     return;
    143 
    144   blink::WebElement element = container()->element();
    145   blink::WebString web_attribute_name =
    146       blink::WebString::fromUTF8(attribute_name);
    147   if (!HasDOMAttribute(attribute_name) ||
    148       (std::string(element.getAttribute(web_attribute_name).utf8()) !=
    149           attribute_value)) {
    150     element.setAttribute(web_attribute_name,
    151         blink::WebString::fromUTF8(attribute_value));
    152   }
    153 }
    154 
    155 void BrowserPlugin::RemoveDOMAttribute(const std::string& attribute_name) {
    156   if (!container())
    157     return;
    158 
    159   container()->element().removeAttribute(
    160       blink::WebString::fromUTF8(attribute_name));
    161 }
    162 
    163 std::string BrowserPlugin::GetDOMAttributeValue(
    164     const std::string& attribute_name) const {
    165   if (!container())
    166     return std::string();
    167 
    168   return container()->element().getAttribute(
    169       blink::WebString::fromUTF8(attribute_name)).utf8();
    170 }
    171 
    172 bool BrowserPlugin::HasDOMAttribute(const std::string& attribute_name) const {
    173   if (!container())
    174     return false;
    175 
    176   return container()->element().hasAttribute(
    177       blink::WebString::fromUTF8(attribute_name));
    178 }
    179 
    180 std::string BrowserPlugin::GetNameAttribute() const {
    181   return GetDOMAttributeValue(browser_plugin::kAttributeName);
    182 }
    183 
    184 bool BrowserPlugin::GetAllowTransparencyAttribute() const {
    185   return HasDOMAttribute(browser_plugin::kAttributeAllowTransparency);
    186 }
    187 
    188 std::string BrowserPlugin::GetSrcAttribute() const {
    189   return GetDOMAttributeValue(browser_plugin::kAttributeSrc);
    190 }
    191 
    192 bool BrowserPlugin::GetAutoSizeAttribute() const {
    193   return HasDOMAttribute(browser_plugin::kAttributeAutoSize);
    194 }
    195 
    196 int BrowserPlugin::GetMaxHeightAttribute() const {
    197   int max_height;
    198   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxHeight),
    199                     &max_height);
    200   return max_height;
    201 }
    202 
    203 int BrowserPlugin::GetMaxWidthAttribute() const {
    204   int max_width;
    205   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxWidth),
    206                     &max_width);
    207   return max_width;
    208 }
    209 
    210 int BrowserPlugin::GetMinHeightAttribute() const {
    211   int min_height;
    212   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinHeight),
    213                     &min_height);
    214   return min_height;
    215 }
    216 
    217 int BrowserPlugin::GetMinWidthAttribute() const {
    218   int min_width;
    219   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinWidth),
    220                     &min_width);
    221   return min_width;
    222 }
    223 
    224 int BrowserPlugin::GetAdjustedMaxHeight() const {
    225   int max_height = GetMaxHeightAttribute();
    226   return max_height ? max_height : height();
    227 }
    228 
    229 int BrowserPlugin::GetAdjustedMaxWidth() const {
    230   int max_width = GetMaxWidthAttribute();
    231   return max_width ? max_width : width();
    232 }
    233 
    234 int BrowserPlugin::GetAdjustedMinHeight() const {
    235   int min_height = GetMinHeightAttribute();
    236   // FrameView.cpp does not allow this value to be <= 0, so when the value is
    237   // unset (or set to 0), we set it to the container size.
    238   min_height = min_height ? min_height : height();
    239   // For autosize, minHeight should not be bigger than maxHeight.
    240   return std::min(min_height, GetAdjustedMaxHeight());
    241 }
    242 
    243 int BrowserPlugin::GetAdjustedMinWidth() const {
    244   int min_width = GetMinWidthAttribute();
    245   // FrameView.cpp does not allow this value to be <= 0, so when the value is
    246   // unset (or set to 0), we set it to the container size.
    247   min_width = min_width ? min_width : width();
    248   // For autosize, minWidth should not be bigger than maxWidth.
    249   return std::min(min_width, GetAdjustedMaxWidth());
    250 }
    251 
    252 std::string BrowserPlugin::GetPartitionAttribute() const {
    253   return GetDOMAttributeValue(browser_plugin::kAttributePartition);
    254 }
    255 
    256 void BrowserPlugin::ParseNameAttribute() {
    257   if (!HasGuestInstanceID())
    258     return;
    259   browser_plugin_manager()->Send(
    260       new BrowserPluginHostMsg_SetName(render_view_routing_id_,
    261                                        guest_instance_id_,
    262                                        GetNameAttribute()));
    263 }
    264 
    265 void BrowserPlugin::ParseAllowTransparencyAttribute() {
    266   if (!HasGuestInstanceID())
    267     return;
    268 
    269   bool opaque = !GetAllowTransparencyAttribute();
    270 
    271   if (compositing_helper_)
    272     compositing_helper_->SetContentsOpaque(opaque);
    273 
    274   browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetContentsOpaque(
    275         render_view_routing_id_,
    276         guest_instance_id_,
    277         opaque));
    278 }
    279 
    280 bool BrowserPlugin::ParseSrcAttribute(std::string* error_message) {
    281   if (!valid_partition_id_) {
    282     *error_message = browser_plugin::kErrorInvalidPartition;
    283     return false;
    284   }
    285   std::string src = GetSrcAttribute();
    286   if (src.empty())
    287     return true;
    288 
    289   // If we haven't created the guest yet, do so now. We will navigate it right
    290   // after creation. If |src| is empty, we can delay the creation until we
    291   // actually need it.
    292   if (!HasGuestInstanceID()) {
    293     // On initial navigation, we request an instance ID from the browser
    294     // process. We essentially ignore all subsequent calls to SetSrcAttribute
    295     // until we receive an instance ID. |before_first_navigation_|
    296     // prevents BrowserPlugin from allocating more than one instance ID.
    297     // Upon receiving an instance ID from the browser process, we continue
    298     // the process of navigation by populating the
    299     // BrowserPluginHostMsg_Attach_Params with the current state of
    300     // BrowserPlugin and sending a BrowserPluginHostMsg_CreateGuest to the
    301     // browser process in order to create a new guest.
    302     if (before_first_navigation_) {
    303       browser_plugin_manager()->AllocateInstanceID(
    304           weak_ptr_factory_.GetWeakPtr());
    305       before_first_navigation_ = false;
    306     }
    307     return true;
    308   }
    309 
    310   browser_plugin_manager()->Send(
    311       new BrowserPluginHostMsg_NavigateGuest(render_view_routing_id_,
    312                                              guest_instance_id_,
    313                                              src));
    314   return true;
    315 }
    316 
    317 void BrowserPlugin::ParseAutoSizeAttribute() {
    318   last_view_size_ = plugin_rect_.size();
    319   is_auto_size_state_dirty_ = true;
    320   UpdateGuestAutoSizeState(GetAutoSizeAttribute());
    321 }
    322 
    323 void BrowserPlugin::PopulateAutoSizeParameters(
    324     BrowserPluginHostMsg_AutoSize_Params* params, bool auto_size_enabled) {
    325   params->enable = auto_size_enabled;
    326   // No need to populate the params if autosize is off.
    327   if (auto_size_enabled) {
    328     params->max_size = gfx::Size(GetAdjustedMaxWidth(), GetAdjustedMaxHeight());
    329     params->min_size = gfx::Size(GetAdjustedMinWidth(), GetAdjustedMinHeight());
    330 
    331     if (max_auto_size_ != params->max_size)
    332       is_auto_size_state_dirty_ = true;
    333 
    334     max_auto_size_ = params->max_size;
    335   } else {
    336     max_auto_size_ = gfx::Size();
    337   }
    338 }
    339 
    340 void BrowserPlugin::UpdateGuestAutoSizeState(bool auto_size_enabled) {
    341   // If we haven't yet heard back from the guest about the last resize request,
    342   // then we don't issue another request until we do in
    343   // BrowserPlugin::UpdateRect.
    344   if (!HasGuestInstanceID() || !paint_ack_received_)
    345     return;
    346 
    347   BrowserPluginHostMsg_AutoSize_Params auto_size_params;
    348   BrowserPluginHostMsg_ResizeGuest_Params resize_guest_params;
    349   if (auto_size_enabled) {
    350     GetDamageBufferWithSizeParams(&auto_size_params,
    351                                   &resize_guest_params,
    352                                   true);
    353   } else {
    354     GetDamageBufferWithSizeParams(NULL, &resize_guest_params, true);
    355   }
    356   paint_ack_received_ = false;
    357   browser_plugin_manager()->Send(
    358       new BrowserPluginHostMsg_SetAutoSize(render_view_routing_id_,
    359                                            guest_instance_id_,
    360                                            auto_size_params,
    361                                            resize_guest_params));
    362 }
    363 
    364 // static
    365 bool BrowserPlugin::UsesDamageBuffer(
    366     const BrowserPluginMsg_UpdateRect_Params& params) {
    367   return params.damage_buffer_sequence_id != 0 || params.needs_ack;
    368 }
    369 
    370 bool BrowserPlugin::UsesPendingDamageBuffer(
    371     const BrowserPluginMsg_UpdateRect_Params& params) {
    372   if (!pending_damage_buffer_)
    373     return false;
    374   return damage_buffer_sequence_id_ == params.damage_buffer_sequence_id;
    375 }
    376 
    377 void BrowserPlugin::OnInstanceIDAllocated(int guest_instance_id) {
    378   CHECK(guest_instance_id != browser_plugin::kInstanceIDNone);
    379   before_first_navigation_ = false;
    380   guest_instance_id_ = guest_instance_id;
    381   browser_plugin_manager()->AddBrowserPlugin(guest_instance_id, this);
    382 
    383   std::map<std::string, base::Value*> props;
    384   props[browser_plugin::kWindowID] =
    385       new base::FundamentalValue(guest_instance_id);
    386   TriggerEvent(browser_plugin::kEventInternalInstanceIDAllocated, &props);
    387 }
    388 
    389 void BrowserPlugin::Attach(scoped_ptr<base::DictionaryValue> extra_params) {
    390   BrowserPluginHostMsg_Attach_Params attach_params;
    391   attach_params.focused = ShouldGuestBeFocused();
    392   attach_params.visible = visible_;
    393   attach_params.opaque = !GetAllowTransparencyAttribute();
    394   attach_params.name = GetNameAttribute();
    395   attach_params.storage_partition_id = storage_partition_id_;
    396   attach_params.persist_storage = persist_storage_;
    397   attach_params.src = GetSrcAttribute();
    398   attach_params.embedder_frame_url = embedder_frame_url_;
    399   GetDamageBufferWithSizeParams(&attach_params.auto_size_params,
    400                                 &attach_params.resize_guest_params,
    401                                 false);
    402 
    403   browser_plugin_manager()->Send(
    404       new BrowserPluginHostMsg_Attach(render_view_routing_id_,
    405                                       guest_instance_id_, attach_params,
    406                                       *extra_params));
    407 }
    408 
    409 void BrowserPlugin::DidCommitCompositorFrame() {
    410   if (compositing_helper_.get())
    411     compositing_helper_->DidCommitCompositorFrame();
    412 }
    413 
    414 void BrowserPlugin::OnAdvanceFocus(int guest_instance_id, bool reverse) {
    415   DCHECK(render_view_.get());
    416   render_view_->GetWebView()->advanceFocus(reverse);
    417 }
    418 
    419 void BrowserPlugin::OnAttachACK(
    420     int guest_instance_id,
    421     const BrowserPluginMsg_Attach_ACK_Params& params) {
    422   // Update BrowserPlugin attributes to match the state of the guest.
    423   if (!params.name.empty())
    424     OnUpdatedName(guest_instance_id, params.name);
    425   if (!params.storage_partition_id.empty()) {
    426     std::string partition_name =
    427         (params.persist_storage ? browser_plugin::kPersistPrefix : "") +
    428             params.storage_partition_id;
    429     UpdateDOMAttribute(browser_plugin::kAttributePartition, partition_name);
    430   }
    431   attached_ = true;
    432 }
    433 
    434 void BrowserPlugin::OnBuffersSwapped(
    435     int guest_instance_id,
    436     const BrowserPluginMsg_BuffersSwapped_Params& params) {
    437   DCHECK(guest_instance_id == guest_instance_id_);
    438   EnableCompositing(true);
    439 
    440   compositing_helper_->OnBuffersSwapped(params.size,
    441                                         params.mailbox_name,
    442                                         params.route_id,
    443                                         params.host_id,
    444                                         GetDeviceScaleFactor());
    445 }
    446 
    447 void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) {
    448   BrowserPluginMsg_CompositorFrameSwapped::Param param;
    449   if (!BrowserPluginMsg_CompositorFrameSwapped::Read(&message, &param))
    450     return;
    451   scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
    452   param.b.AssignTo(frame.get());
    453 
    454   EnableCompositing(true);
    455   compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
    456                                                 param.c /* route_id */,
    457                                                 param.d /* output_surface_id */,
    458                                                 param.e /* host_id */);
    459 }
    460 
    461 void BrowserPlugin::OnCopyFromCompositingSurface(int guest_instance_id,
    462                                                  int request_id,
    463                                                  gfx::Rect source_rect,
    464                                                  gfx::Size dest_size) {
    465   if (!compositing_enabled_) {
    466     browser_plugin_manager()->Send(
    467         new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck(
    468             render_view_routing_id_,
    469             guest_instance_id_,
    470             request_id,
    471             SkBitmap()));
    472     return;
    473   }
    474   compositing_helper_->CopyFromCompositingSurface(request_id, source_rect,
    475                                                   dest_size);
    476 }
    477 
    478 void BrowserPlugin::OnGuestContentWindowReady(int guest_instance_id,
    479                                               int content_window_routing_id) {
    480   DCHECK(content_window_routing_id != MSG_ROUTING_NONE);
    481   content_window_routing_id_ = content_window_routing_id;
    482 }
    483 
    484 void BrowserPlugin::OnGuestGone(int guest_instance_id) {
    485   guest_crashed_ = true;
    486 
    487   // Turn off compositing so we can display the sad graphic. Changes to
    488   // compositing state will show up at a later time after a layout and commit.
    489   EnableCompositing(false);
    490   if (compositing_helper_) {
    491     compositing_helper_->OnContainerDestroy();
    492     compositing_helper_ = NULL;
    493   }
    494 
    495   // Queue up showing the sad graphic to give content embedders an opportunity
    496   // to fire their listeners and potentially overlay the webview with custom
    497   // behavior. If the BrowserPlugin is destroyed in the meantime, then the
    498   // task will not be executed.
    499   base::MessageLoop::current()->PostTask(
    500       FROM_HERE,
    501       base::Bind(&BrowserPlugin::ShowSadGraphic,
    502                  weak_ptr_factory_.GetWeakPtr()));
    503 }
    504 
    505 void BrowserPlugin::OnSetCursor(int guest_instance_id,
    506                                 const WebCursor& cursor) {
    507   cursor_ = cursor;
    508 }
    509 
    510 void BrowserPlugin::OnSetMouseLock(int guest_instance_id,
    511                                    bool enable) {
    512   if (enable) {
    513     if (mouse_locked_)
    514       return;
    515     render_view_->mouse_lock_dispatcher()->LockMouse(this);
    516   } else {
    517     if (!mouse_locked_) {
    518       OnLockMouseACK(false);
    519       return;
    520     }
    521     render_view_->mouse_lock_dispatcher()->UnlockMouse(this);
    522   }
    523 }
    524 
    525 void BrowserPlugin::OnShouldAcceptTouchEvents(int guest_instance_id,
    526                                               bool accept) {
    527   if (container()) {
    528     container()->requestTouchEventType(accept ?
    529         blink::WebPluginContainer::TouchEventRequestTypeRaw :
    530         blink::WebPluginContainer::TouchEventRequestTypeNone);
    531   }
    532 }
    533 
    534 void BrowserPlugin::OnUpdatedName(int guest_instance_id,
    535                                   const std::string& name) {
    536   UpdateDOMAttribute(browser_plugin::kAttributeName, name);
    537 }
    538 
    539 void BrowserPlugin::OnUpdateRect(
    540     int guest_instance_id,
    541     const BrowserPluginMsg_UpdateRect_Params& params) {
    542   // If the guest has updated pixels then it is no longer crashed.
    543   guest_crashed_ = false;
    544 
    545   bool use_new_damage_buffer = !backing_store_;
    546   BrowserPluginHostMsg_AutoSize_Params auto_size_params;
    547   BrowserPluginHostMsg_ResizeGuest_Params resize_guest_params;
    548   // If we have a pending damage buffer, and the guest has begun to use the
    549   // damage buffer then we know the guest will no longer use the current
    550   // damage buffer. At this point, we drop the current damage buffer, and
    551   // mark the pending damage buffer as the current damage buffer.
    552   if (UsesPendingDamageBuffer(params)) {
    553     SwapDamageBuffers();
    554     use_new_damage_buffer = true;
    555   }
    556 
    557   bool auto_size = GetAutoSizeAttribute();
    558   // We receive a resize ACK in regular mode, but not in autosize.
    559   // In SW, |paint_ack_received_| is reset in SwapDamageBuffers().
    560   // In HW mode, we need to do it here so we can continue sending
    561   // resize messages when needed.
    562   if (params.is_resize_ack ||
    563       (!params.needs_ack && (auto_size || is_auto_size_state_dirty_))) {
    564     paint_ack_received_ = true;
    565   }
    566 
    567   bool was_auto_size_state_dirty = auto_size && is_auto_size_state_dirty_;
    568   is_auto_size_state_dirty_ = false;
    569 
    570   if ((!auto_size && (width() != params.view_size.width() ||
    571                       height() != params.view_size.height())) ||
    572       (auto_size && was_auto_size_state_dirty) ||
    573       GetDeviceScaleFactor() != params.scale_factor) {
    574     // We are HW accelerated, render widget does not expect an ack,
    575     // but we still need to update the size.
    576     if (!params.needs_ack) {
    577       UpdateGuestAutoSizeState(auto_size);
    578       return;
    579     }
    580 
    581     if (!paint_ack_received_) {
    582       // The guest has not yet responded to the last resize request, and
    583       // so we don't want to do anything at this point other than ACK the guest.
    584       if (auto_size)
    585         PopulateAutoSizeParameters(&auto_size_params, auto_size);
    586     } else {
    587       // If we have no pending damage buffer, then the guest has not caught up
    588       // with the BrowserPlugin container. We now tell the guest about the new
    589       // container size.
    590       if (auto_size) {
    591         GetDamageBufferWithSizeParams(&auto_size_params,
    592                                       &resize_guest_params,
    593                                       was_auto_size_state_dirty);
    594       } else {
    595         GetDamageBufferWithSizeParams(NULL,
    596                                       &resize_guest_params,
    597                                       was_auto_size_state_dirty);
    598       }
    599     }
    600     browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateRect_ACK(
    601         render_view_routing_id_,
    602         guest_instance_id_,
    603         true,
    604         auto_size_params,
    605         resize_guest_params));
    606     return;
    607   }
    608 
    609   if (auto_size && (params.view_size != last_view_size_)) {
    610     if (backing_store_)
    611       backing_store_->Clear(SK_ColorWHITE);
    612     last_view_size_ = params.view_size;
    613   }
    614 
    615   if (UsesDamageBuffer(params)) {
    616 
    617     // If we are seeing damage buffers, HW compositing should be turned off.
    618     EnableCompositing(false);
    619 
    620     // If we are now using a new damage buffer, then that means that the guest
    621     // has updated its size state in response to a resize request. We change
    622     // the backing store's size to accomodate the new damage buffer size.
    623     if (use_new_damage_buffer) {
    624       int backing_store_width = auto_size ? GetAdjustedMaxWidth() : width();
    625       int backing_store_height = auto_size ? GetAdjustedMaxHeight(): height();
    626       backing_store_.reset(
    627           new BrowserPluginBackingStore(
    628               gfx::Size(backing_store_width, backing_store_height),
    629               params.scale_factor));
    630     }
    631 
    632     // If we just transitioned from the compositing path to the software path
    633     // then we might not yet have a damage buffer.
    634     if (current_damage_buffer_) {
    635       // Update the backing store.
    636       if (!params.scroll_rect.IsEmpty()) {
    637         backing_store_->ScrollBackingStore(params.scroll_delta,
    638                                           params.scroll_rect,
    639                                           params.view_size);
    640       }
    641       backing_store_->PaintToBackingStore(params.bitmap_rect,
    642                                           params.copy_rects,
    643                                           current_damage_buffer_->memory());
    644       // Invalidate the container.
    645       // If the BrowserPlugin is scheduled to be deleted, then container_ will
    646       // be NULL so we shouldn't attempt to access it.
    647       if (container_)
    648         container_->invalidate();
    649     }
    650   }
    651 
    652   // BrowserPluginHostMsg_UpdateRect_ACK is used by both the compositing and
    653   // software paths to piggyback updated autosize parameters.
    654   if (auto_size)
    655     PopulateAutoSizeParameters(&auto_size_params, auto_size);
    656   browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateRect_ACK(
    657       render_view_routing_id_,
    658       guest_instance_id_,
    659       UsesDamageBuffer(params),
    660       auto_size_params,
    661       resize_guest_params));
    662 }
    663 
    664 void BrowserPlugin::ParseSizeContraintsChanged() {
    665   bool auto_size = GetAutoSizeAttribute();
    666   if (auto_size) {
    667     is_auto_size_state_dirty_ = true;
    668     UpdateGuestAutoSizeState(true);
    669   }
    670 }
    671 
    672 bool BrowserPlugin::InAutoSizeBounds(const gfx::Size& size) const {
    673   return size.width() <= GetAdjustedMaxWidth() &&
    674       size.height() <= GetAdjustedMaxHeight();
    675 }
    676 
    677 NPObject* BrowserPlugin::GetContentWindow() const {
    678   if (content_window_routing_id_ == MSG_ROUTING_NONE)
    679     return NULL;
    680   RenderViewImpl* guest_render_view = RenderViewImpl::FromRoutingID(
    681       content_window_routing_id_);
    682   if (!guest_render_view)
    683     return NULL;
    684   blink::WebFrame* guest_frame = guest_render_view->GetWebView()->mainFrame();
    685   return guest_frame->windowObject();
    686 }
    687 
    688 // static
    689 bool BrowserPlugin::AttachWindowTo(const blink::WebNode& node, int window_id) {
    690   if (node.isNull())
    691     return false;
    692 
    693   if (!node.isElementNode())
    694     return false;
    695 
    696   blink::WebElement shim_element = node.toConst<blink::WebElement>();
    697   // The shim containing the BrowserPlugin must be attached to a document.
    698   if (shim_element.document().isNull())
    699     return false;
    700 
    701   blink::WebNode shadow_root = shim_element.shadowRoot();
    702   if (shadow_root.isNull() || !shadow_root.hasChildNodes())
    703     return false;
    704 
    705   blink::WebNode plugin_element = shadow_root.firstChild();
    706   blink::WebPluginContainer* plugin_container =
    707       plugin_element.pluginContainer();
    708   if (!plugin_container)
    709     return false;
    710 
    711   BrowserPlugin* browser_plugin =
    712       BrowserPlugin::FromContainer(plugin_container);
    713   if (!browser_plugin)
    714     return false;
    715 
    716   // If the BrowserPlugin has already begun to navigate then we shouldn't allow
    717   // attaching a different guest.
    718   //
    719   // Navigation happens in two stages.
    720   // 1. BrowserPlugin requests an instance ID from the browser process.
    721   // 2. The browser process returns an instance ID and BrowserPlugin is
    722   //    "Attach"ed to that instance ID.
    723   // If the instance ID is new then a new guest will be created.
    724   // If the instance ID corresponds to an unattached guest then BrowserPlugin
    725   // is attached to that guest.
    726   //
    727   // Between step 1, and step 2, BrowserPlugin::AttachWindowTo may be called.
    728   // The check below ensures that BrowserPlugin:Attach does not get called with
    729   // a different instance ID after step 1 has happened.
    730   // TODO(fsamuel): We may wish to support reattaching guests in the future:
    731   // http://crbug.com/156219.
    732   if (browser_plugin->HasNavigated())
    733     return false;
    734 
    735   browser_plugin->OnInstanceIDAllocated(window_id);
    736   return true;
    737 }
    738 
    739 bool BrowserPlugin::HasNavigated() const {
    740   return !before_first_navigation_;
    741 }
    742 
    743 bool BrowserPlugin::HasGuestInstanceID() const {
    744   return guest_instance_id_ != browser_plugin::kInstanceIDNone;
    745 }
    746 
    747 bool BrowserPlugin::ParsePartitionAttribute(std::string* error_message) {
    748   if (HasNavigated()) {
    749     *error_message = browser_plugin::kErrorAlreadyNavigated;
    750     return false;
    751   }
    752 
    753   std::string input = GetPartitionAttribute();
    754 
    755   // Since the "persist:" prefix is in ASCII, StartsWith will work fine on
    756   // UTF-8 encoded |partition_id|. If the prefix is a match, we can safely
    757   // remove the prefix without splicing in the middle of a multi-byte codepoint.
    758   // We can use the rest of the string as UTF-8 encoded one.
    759   if (StartsWithASCII(input, browser_plugin::kPersistPrefix, true)) {
    760     size_t index = input.find(":");
    761     CHECK(index != std::string::npos);
    762     // It is safe to do index + 1, since we tested for the full prefix above.
    763     input = input.substr(index + 1);
    764     if (input.empty()) {
    765       valid_partition_id_ = false;
    766       *error_message = browser_plugin::kErrorInvalidPartition;
    767       return false;
    768     }
    769     persist_storage_ = true;
    770   } else {
    771     persist_storage_ = false;
    772   }
    773 
    774   valid_partition_id_ = true;
    775   storage_partition_id_ = input;
    776   return true;
    777 }
    778 
    779 bool BrowserPlugin::CanRemovePartitionAttribute(std::string* error_message) {
    780   if (HasGuestInstanceID())
    781     *error_message = browser_plugin::kErrorCannotRemovePartition;
    782   return !HasGuestInstanceID();
    783 }
    784 
    785 void BrowserPlugin::ShowSadGraphic() {
    786   // We won't paint the contents of the current backing store again so we might
    787   // as well toss it out and save memory.
    788   backing_store_.reset();
    789   // If the BrowserPlugin is scheduled to be deleted, then container_ will be
    790   // NULL so we shouldn't attempt to access it.
    791   if (container_)
    792     container_->invalidate();
    793 }
    794 
    795 void BrowserPlugin::ParseAttributes() {
    796   // TODO(mthiesse): Handle errors here?
    797   std::string error;
    798   ParsePartitionAttribute(&error);
    799 
    800   // Parse the 'src' attribute last, as it will set the has_navigated_ flag to
    801   // true, which prevents changing the 'partition' attribute.
    802   ParseSrcAttribute(&error);
    803 }
    804 
    805 float BrowserPlugin::GetDeviceScaleFactor() const {
    806   if (!render_view_.get())
    807     return 1.0f;
    808   return render_view_->GetWebView()->deviceScaleFactor();
    809 }
    810 
    811 void BrowserPlugin::UpdateDeviceScaleFactor(float device_scale_factor) {
    812   if (last_device_scale_factor_ == device_scale_factor || !paint_ack_received_)
    813     return;
    814 
    815   BrowserPluginHostMsg_ResizeGuest_Params params;
    816   PopulateResizeGuestParameters(&params, plugin_rect(), false);
    817   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
    818       render_view_routing_id_,
    819       guest_instance_id_,
    820       params));
    821 }
    822 
    823 void BrowserPlugin::TriggerEvent(const std::string& event_name,
    824                                  std::map<std::string, base::Value*>* props) {
    825   if (!container())
    826     return;
    827 
    828   blink::WebFrame* frame = container()->element().document().frame();
    829   if (!frame)
    830     return;
    831 
    832   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
    833   v8::Local<v8::Context> context = frame->mainWorldScriptContext();
    834   v8::Context::Scope context_scope(context);
    835 
    836   std::string json_string;
    837   if (props) {
    838     base::DictionaryValue dict;
    839     for (std::map<std::string, base::Value*>::iterator iter = props->begin(),
    840              end = props->end(); iter != end; ++iter) {
    841       dict.Set(iter->first, iter->second);
    842     }
    843 
    844     JSONStringValueSerializer serializer(&json_string);
    845     if (!serializer.Serialize(dict))
    846       return;
    847   }
    848 
    849   blink::WebDOMEvent dom_event = frame->document().createEvent("CustomEvent");
    850   blink::WebDOMCustomEvent event = dom_event.to<blink::WebDOMCustomEvent>();
    851 
    852   // The events triggered directly from the plugin <object> are internal events
    853   // whose implementation details can (and likely will) change over time. The
    854   // wrapper/shim (e.g. <webview> tag) should receive these events, and expose a
    855   // more appropriate (and stable) event to the consumers as part of the API.
    856   event.initCustomEvent(
    857       blink::WebString::fromUTF8(GetInternalEventName(event_name.c_str())),
    858       false,
    859       false,
    860       blink::WebSerializedScriptValue::serialize(
    861           v8::String::NewFromUtf8(context->GetIsolate(),
    862                                   json_string.c_str(),
    863                                   v8::String::kNormalString,
    864                                   json_string.size())));
    865   container()->element().dispatchEvent(event);
    866 }
    867 
    868 void BrowserPlugin::UpdateGuestFocusState() {
    869   if (!HasGuestInstanceID())
    870     return;
    871   bool should_be_focused = ShouldGuestBeFocused();
    872   browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetFocus(
    873       render_view_routing_id_,
    874       guest_instance_id_,
    875       should_be_focused));
    876 }
    877 
    878 bool BrowserPlugin::ShouldGuestBeFocused() const {
    879   bool embedder_focused = false;
    880   if (render_view_.get())
    881     embedder_focused = render_view_->has_focus();
    882   return plugin_focused_ && embedder_focused;
    883 }
    884 
    885 blink::WebPluginContainer* BrowserPlugin::container() const {
    886   return container_;
    887 }
    888 
    889 bool BrowserPlugin::initialize(WebPluginContainer* container) {
    890   if (!container)
    891     return false;
    892 
    893   if (!GetContentClient()->renderer()->AllowBrowserPlugin(container))
    894     return false;
    895 
    896   // Tell |container| to allow this plugin to use script objects.
    897   npp_.reset(new NPP_t);
    898   container->allowScriptObjects();
    899 
    900   bindings_.reset(new BrowserPluginBindings(this));
    901   container_ = container;
    902   container_->setWantsWheelEvents(true);
    903   ParseAttributes();
    904   g_plugin_container_map.Get().insert(std::make_pair(container_, this));
    905   return true;
    906 }
    907 
    908 void BrowserPlugin::EnableCompositing(bool enable) {
    909   if (compositing_enabled_ == enable)
    910     return;
    911 
    912   compositing_enabled_ = enable;
    913   if (enable) {
    914     // No need to keep the backing store and damage buffer around if we're now
    915     // compositing.
    916     backing_store_.reset();
    917     current_damage_buffer_.reset();
    918     if (!compositing_helper_.get()) {
    919       compositing_helper_ =
    920           new BrowserPluginCompositingHelper(container_,
    921                                              browser_plugin_manager(),
    922                                              guest_instance_id_,
    923                                              render_view_routing_id_);
    924     }
    925   } else {
    926     if (paint_ack_received_) {
    927       // We're switching back to the software path. We create a new damage
    928       // buffer that can accommodate the current size of the container.
    929       BrowserPluginHostMsg_ResizeGuest_Params params;
    930       // Request a full repaint from the guest even if its size is not actually
    931       // changing.
    932       PopulateResizeGuestParameters(&params,
    933                                     plugin_rect(),
    934                                     true /* needs_repaint */);
    935       paint_ack_received_ = false;
    936       browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
    937           render_view_routing_id_,
    938           guest_instance_id_,
    939           params));
    940     }
    941   }
    942   compositing_helper_->EnableCompositing(enable);
    943   compositing_helper_->SetContentsOpaque(!GetAllowTransparencyAttribute());
    944 }
    945 
    946 void BrowserPlugin::destroy() {
    947   // If the plugin was initialized then it has a valid |npp_| identifier, and
    948   // the |container_| must clear references to the plugin's script objects.
    949   DCHECK(!npp_ || container_);
    950   if (container_)
    951     container_->clearScriptObjects();
    952 
    953   // The BrowserPlugin's WebPluginContainer is deleted immediately after this
    954   // call returns, so let's not keep a reference to it around.
    955   g_plugin_container_map.Get().erase(container_);
    956   container_ = NULL;
    957   if (compositing_helper_.get())
    958     compositing_helper_->OnContainerDestroy();
    959   // Will be a no-op if the mouse is not currently locked.
    960   if (render_view_.get())
    961     render_view_->mouse_lock_dispatcher()->OnLockTargetDestroyed(this);
    962   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    963 }
    964 
    965 NPObject* BrowserPlugin::scriptableObject() {
    966   if (!bindings_)
    967     return NULL;
    968 
    969   NPObject* browser_plugin_np_object(bindings_->np_object());
    970   // The object is expected to be retained before it is returned.
    971   blink::WebBindings::retainObject(browser_plugin_np_object);
    972   return browser_plugin_np_object;
    973 }
    974 
    975 NPP BrowserPlugin::pluginNPP() {
    976   return npp_.get();
    977 }
    978 
    979 bool BrowserPlugin::supportsKeyboardFocus() const {
    980   return true;
    981 }
    982 
    983 bool BrowserPlugin::supportsEditCommands() const {
    984   return true;
    985 }
    986 
    987 bool BrowserPlugin::supportsInputMethod() const {
    988   return true;
    989 }
    990 
    991 bool BrowserPlugin::canProcessDrag() const {
    992   return true;
    993 }
    994 
    995 void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
    996   if (guest_crashed_) {
    997     if (!sad_guest_)  // Lazily initialize bitmap.
    998       sad_guest_ = content::GetContentClient()->renderer()->
    999           GetSadWebViewBitmap();
   1000     // content_shell does not have the sad plugin bitmap, so we'll paint black
   1001     // instead to make it clear that something went wrong.
   1002     if (sad_guest_) {
   1003       PaintSadPlugin(canvas, plugin_rect_, *sad_guest_);
   1004       return;
   1005     }
   1006   }
   1007   SkAutoCanvasRestore auto_restore(canvas, true);
   1008   canvas->translate(plugin_rect_.x(), plugin_rect_.y());
   1009   SkRect image_data_rect = SkRect::MakeXYWH(
   1010       SkIntToScalar(0),
   1011       SkIntToScalar(0),
   1012       SkIntToScalar(plugin_rect_.width()),
   1013       SkIntToScalar(plugin_rect_.height()));
   1014   canvas->clipRect(image_data_rect);
   1015   // Paint black or white in case we have nothing in our backing store or we
   1016   // need to show a gutter.
   1017   SkPaint paint;
   1018   paint.setStyle(SkPaint::kFill_Style);
   1019   paint.setColor(guest_crashed_ ? SK_ColorBLACK : SK_ColorWHITE);
   1020   canvas->drawRect(image_data_rect, paint);
   1021   // Stay a solid color if we have never set a non-empty src, or we don't have a
   1022   // backing store.
   1023   if (!backing_store_.get() || !HasGuestInstanceID())
   1024     return;
   1025   float inverse_scale_factor =  1.0f / backing_store_->GetScaleFactor();
   1026   canvas->scale(inverse_scale_factor, inverse_scale_factor);
   1027   canvas->drawBitmap(backing_store_->GetBitmap(), 0, 0);
   1028 }
   1029 
   1030 bool BrowserPlugin::InBounds(const gfx::Point& position) const {
   1031   // Note that even for plugins that are rotated using rotate transformations,
   1032   // we use the the |plugin_rect_| provided by updateGeometry, which means we
   1033   // will be off if |position| is within the plugin rect but does not fall
   1034   // within the actual plugin boundary. Not supporting such edge case is OK
   1035   // since this function should not be used for making security-sensitive
   1036   // decisions.
   1037   // This also does not take overlapping plugins into account.
   1038   bool result = position.x() >= plugin_rect_.x() &&
   1039       position.x() < plugin_rect_.x() + plugin_rect_.width() &&
   1040       position.y() >= plugin_rect_.y() &&
   1041       position.y() < plugin_rect_.y() + plugin_rect_.height();
   1042   return result;
   1043 }
   1044 
   1045 gfx::Point BrowserPlugin::ToLocalCoordinates(const gfx::Point& point) const {
   1046   if (container_)
   1047     return container_->windowToLocalPoint(blink::WebPoint(point));
   1048   return gfx::Point(point.x() - plugin_rect_.x(), point.y() - plugin_rect_.y());
   1049 }
   1050 
   1051 // static
   1052 bool BrowserPlugin::ShouldForwardToBrowserPlugin(
   1053     const IPC::Message& message) {
   1054   switch (message.type()) {
   1055     case BrowserPluginMsg_AdvanceFocus::ID:
   1056     case BrowserPluginMsg_Attach_ACK::ID:
   1057     case BrowserPluginMsg_BuffersSwapped::ID:
   1058     case BrowserPluginMsg_CompositorFrameSwapped::ID:
   1059     case BrowserPluginMsg_CopyFromCompositingSurface::ID:
   1060     case BrowserPluginMsg_GuestContentWindowReady::ID:
   1061     case BrowserPluginMsg_GuestGone::ID:
   1062     case BrowserPluginMsg_SetCursor::ID:
   1063     case BrowserPluginMsg_SetMouseLock::ID:
   1064     case BrowserPluginMsg_ShouldAcceptTouchEvents::ID:
   1065     case BrowserPluginMsg_UpdatedName::ID:
   1066     case BrowserPluginMsg_UpdateRect::ID:
   1067       return true;
   1068     default:
   1069       break;
   1070   }
   1071   return false;
   1072 }
   1073 
   1074 void BrowserPlugin::updateGeometry(
   1075     const WebRect& window_rect,
   1076     const WebRect& clip_rect,
   1077     const WebVector<WebRect>& cut_outs_rects,
   1078     bool is_visible) {
   1079   int old_width = width();
   1080   int old_height = height();
   1081   plugin_rect_ = window_rect;
   1082   if (!attached())
   1083     return;
   1084 
   1085   // In AutoSize mode, guests don't care when the BrowserPlugin container is
   1086   // resized. If |!paint_ack_received_|, then we are still waiting on a
   1087   // previous resize to be ACK'ed and so we don't issue additional resizes
   1088   // until the previous one is ACK'ed.
   1089   // TODO(mthiesse): Assess the performance of calling GetAutoSizeAttribute() on
   1090   // resize.
   1091   if (!paint_ack_received_ ||
   1092       (old_width == window_rect.width && old_height == window_rect.height) ||
   1093       GetAutoSizeAttribute()) {
   1094     // Let the browser know about the updated view rect.
   1095     browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateGeometry(
   1096         render_view_routing_id_, guest_instance_id_, plugin_rect_));
   1097     return;
   1098   }
   1099 
   1100   BrowserPluginHostMsg_ResizeGuest_Params params;
   1101   PopulateResizeGuestParameters(&params, plugin_rect(), false);
   1102   paint_ack_received_ = false;
   1103   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
   1104       render_view_routing_id_,
   1105       guest_instance_id_,
   1106       params));
   1107 }
   1108 
   1109 void BrowserPlugin::SwapDamageBuffers() {
   1110   current_damage_buffer_.reset(pending_damage_buffer_.release());
   1111   paint_ack_received_ = true;
   1112 }
   1113 
   1114 void BrowserPlugin::PopulateResizeGuestParameters(
   1115     BrowserPluginHostMsg_ResizeGuest_Params* params,
   1116     const gfx::Rect& view_rect,
   1117     bool needs_repaint) {
   1118   params->size_changed = true;
   1119   params->view_rect = view_rect;
   1120   params->repaint = needs_repaint;
   1121   params->scale_factor = GetDeviceScaleFactor();
   1122   if (last_device_scale_factor_ != params->scale_factor){
   1123     params->repaint = true;
   1124     last_device_scale_factor_ = params->scale_factor;
   1125   }
   1126 
   1127   // In HW compositing mode, we do not need a damage buffer.
   1128   if (compositing_enabled_)
   1129     return;
   1130 
   1131   const size_t stride = skia::PlatformCanvasStrideForWidth(view_rect.width());
   1132   // Make sure the size of the damage buffer is at least four bytes so that we
   1133   // can fit in a magic word to verify that the memory is shared correctly.
   1134   size_t size =
   1135       std::max(sizeof(unsigned int),
   1136                static_cast<size_t>(view_rect.height() *
   1137                                    stride *
   1138                                    GetDeviceScaleFactor() *
   1139                                    GetDeviceScaleFactor()));
   1140 
   1141   params->damage_buffer_size = size;
   1142   pending_damage_buffer_.reset(
   1143       CreateDamageBuffer(size, &params->damage_buffer_handle));
   1144   if (!pending_damage_buffer_)
   1145     NOTREACHED();
   1146   params->damage_buffer_sequence_id = ++damage_buffer_sequence_id_;
   1147 }
   1148 
   1149 void BrowserPlugin::GetDamageBufferWithSizeParams(
   1150     BrowserPluginHostMsg_AutoSize_Params* auto_size_params,
   1151     BrowserPluginHostMsg_ResizeGuest_Params* resize_guest_params,
   1152     bool needs_repaint) {
   1153   if (auto_size_params) {
   1154     PopulateAutoSizeParameters(auto_size_params, GetAutoSizeAttribute());
   1155   } else {
   1156     max_auto_size_ = gfx::Size();
   1157   }
   1158   gfx::Size view_size = (auto_size_params && auto_size_params->enable) ?
   1159       auto_size_params->max_size : gfx::Size(width(), height());
   1160   if (view_size.IsEmpty())
   1161     return;
   1162   paint_ack_received_ = false;
   1163   gfx::Rect view_rect = gfx::Rect(plugin_rect_.origin(), view_size);
   1164   PopulateResizeGuestParameters(resize_guest_params, view_rect, needs_repaint);
   1165 }
   1166 
   1167 #if defined(OS_POSIX)
   1168 base::SharedMemory* BrowserPlugin::CreateDamageBuffer(
   1169     const size_t size,
   1170     base::SharedMemoryHandle* damage_buffer_handle) {
   1171   scoped_ptr<base::SharedMemory> shared_buf(
   1172       content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
   1173           size).release());
   1174 
   1175   if (shared_buf) {
   1176     if (shared_buf->Map(size)) {
   1177       // Insert the magic word.
   1178       *static_cast<unsigned int*>(shared_buf->memory()) = 0xdeadbeef;
   1179       shared_buf->ShareToProcess(base::GetCurrentProcessHandle(),
   1180                                  damage_buffer_handle);
   1181       return shared_buf.release();
   1182     }
   1183   }
   1184   NOTREACHED();
   1185   return NULL;
   1186 }
   1187 #elif defined(OS_WIN)
   1188 base::SharedMemory* BrowserPlugin::CreateDamageBuffer(
   1189     const size_t size,
   1190     base::SharedMemoryHandle* damage_buffer_handle) {
   1191   scoped_ptr<base::SharedMemory> shared_buf(new base::SharedMemory());
   1192 
   1193   if (!shared_buf->CreateAndMapAnonymous(size)) {
   1194     NOTREACHED() << "Buffer allocation failed";
   1195     return NULL;
   1196   }
   1197 
   1198   // Insert the magic word.
   1199   *static_cast<unsigned int*>(shared_buf->memory()) = 0xdeadbeef;
   1200   if (shared_buf->ShareToProcess(base::GetCurrentProcessHandle(),
   1201                                  damage_buffer_handle))
   1202     return shared_buf.release();
   1203   NOTREACHED();
   1204   return NULL;
   1205 }
   1206 #endif
   1207 
   1208 void BrowserPlugin::updateFocus(bool focused) {
   1209   if (plugin_focused_ == focused)
   1210     return;
   1211 
   1212   bool old_guest_focus_state = ShouldGuestBeFocused();
   1213   plugin_focused_ = focused;
   1214 
   1215   if (ShouldGuestBeFocused() != old_guest_focus_state)
   1216     UpdateGuestFocusState();
   1217 }
   1218 
   1219 void BrowserPlugin::updateVisibility(bool visible) {
   1220   if (visible_ == visible)
   1221     return;
   1222 
   1223   visible_ = visible;
   1224   if (!HasGuestInstanceID())
   1225     return;
   1226 
   1227   if (compositing_helper_.get())
   1228     compositing_helper_->UpdateVisibility(visible);
   1229 
   1230   browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetVisibility(
   1231       render_view_routing_id_,
   1232       guest_instance_id_,
   1233       visible));
   1234 }
   1235 
   1236 bool BrowserPlugin::acceptsInputEvents() {
   1237   return true;
   1238 }
   1239 
   1240 bool BrowserPlugin::handleInputEvent(const blink::WebInputEvent& event,
   1241                                      blink::WebCursorInfo& cursor_info) {
   1242   if (guest_crashed_ || !HasGuestInstanceID())
   1243     return false;
   1244 
   1245   if (event.type == blink::WebInputEvent::ContextMenu)
   1246     return true;
   1247 
   1248   const blink::WebInputEvent* modified_event = &event;
   1249   scoped_ptr<blink::WebTouchEvent> touch_event;
   1250   // WebKit gives BrowserPlugin a list of touches that are down, but the browser
   1251   // process expects a list of all touches. We modify the TouchEnd event here to
   1252   // match these expectations.
   1253   if (event.type == blink::WebInputEvent::TouchEnd) {
   1254     const blink::WebTouchEvent* orig_touch_event =
   1255         static_cast<const blink::WebTouchEvent*>(&event);
   1256     touch_event.reset(new blink::WebTouchEvent());
   1257     memcpy(touch_event.get(), orig_touch_event, sizeof(blink::WebTouchEvent));
   1258     if (touch_event->changedTouchesLength > 0) {
   1259       memcpy(&touch_event->touches[touch_event->touchesLength],
   1260              &touch_event->changedTouches,
   1261             touch_event->changedTouchesLength * sizeof(blink::WebTouchPoint));
   1262     }
   1263     touch_event->touchesLength += touch_event->changedTouchesLength;
   1264     modified_event = touch_event.get();
   1265   }
   1266 
   1267   if (blink::WebInputEvent::isKeyboardEventType(event.type) &&
   1268       !edit_commands_.empty()) {
   1269     browser_plugin_manager()->Send(
   1270         new BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent(
   1271             render_view_routing_id_,
   1272             guest_instance_id_,
   1273             edit_commands_));
   1274     edit_commands_.clear();
   1275   }
   1276 
   1277   browser_plugin_manager()->Send(
   1278       new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
   1279                                                 guest_instance_id_,
   1280                                                 plugin_rect_,
   1281                                                 modified_event));
   1282   GetWebKitCursorInfo(cursor_, &cursor_info);
   1283   return true;
   1284 }
   1285 
   1286 bool BrowserPlugin::handleDragStatusUpdate(blink::WebDragStatus drag_status,
   1287                                            const blink::WebDragData& drag_data,
   1288                                            blink::WebDragOperationsMask mask,
   1289                                            const blink::WebPoint& position,
   1290                                            const blink::WebPoint& screen) {
   1291   if (guest_crashed_ || !HasGuestInstanceID())
   1292     return false;
   1293   browser_plugin_manager()->Send(
   1294       new BrowserPluginHostMsg_DragStatusUpdate(
   1295         render_view_routing_id_,
   1296         guest_instance_id_,
   1297         drag_status,
   1298         DropDataBuilder::Build(drag_data),
   1299         mask,
   1300         position));
   1301   return true;
   1302 }
   1303 
   1304 void BrowserPlugin::didReceiveResponse(
   1305     const blink::WebURLResponse& response) {
   1306 }
   1307 
   1308 void BrowserPlugin::didReceiveData(const char* data, int data_length) {
   1309 }
   1310 
   1311 void BrowserPlugin::didFinishLoading() {
   1312 }
   1313 
   1314 void BrowserPlugin::didFailLoading(const blink::WebURLError& error) {
   1315 }
   1316 
   1317 void BrowserPlugin::didFinishLoadingFrameRequest(const blink::WebURL& url,
   1318                                                  void* notify_data) {
   1319 }
   1320 
   1321 void BrowserPlugin::didFailLoadingFrameRequest(
   1322     const blink::WebURL& url,
   1323     void* notify_data,
   1324     const blink::WebURLError& error) {
   1325 }
   1326 
   1327 bool BrowserPlugin::executeEditCommand(const blink::WebString& name) {
   1328   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ExecuteEditCommand(
   1329       render_view_routing_id_,
   1330       guest_instance_id_,
   1331       name.utf8()));
   1332 
   1333   // BrowserPlugin swallows edit commands.
   1334   return true;
   1335 }
   1336 
   1337 bool BrowserPlugin::executeEditCommand(const blink::WebString& name,
   1338                                        const blink::WebString& value) {
   1339   edit_commands_.push_back(EditCommand(name.utf8(), value.utf8()));
   1340   // BrowserPlugin swallows edit commands.
   1341   return true;
   1342 }
   1343 
   1344 bool BrowserPlugin::setComposition(
   1345     const blink::WebString& text,
   1346     const blink::WebVector<blink::WebCompositionUnderline>& underlines,
   1347     int selectionStart,
   1348     int selectionEnd) {
   1349   if (!HasGuestInstanceID())
   1350     return false;
   1351   std::vector<blink::WebCompositionUnderline> std_underlines;
   1352   for (size_t i = 0; i < underlines.size(); ++i) {
   1353     std_underlines.push_back(underlines[i]);
   1354   }
   1355   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeSetComposition(
   1356       render_view_routing_id_,
   1357       guest_instance_id_,
   1358       text.utf8(),
   1359       std_underlines,
   1360       selectionStart,
   1361       selectionEnd));
   1362   // TODO(kochi): This assumes the IPC handling always succeeds.
   1363   return true;
   1364 }
   1365 
   1366 bool BrowserPlugin::confirmComposition(
   1367     const blink::WebString& text,
   1368     blink::WebWidget::ConfirmCompositionBehavior selectionBehavior) {
   1369   if (!HasGuestInstanceID())
   1370     return false;
   1371   bool keep_selection = (selectionBehavior == blink::WebWidget::KeepSelection);
   1372   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeConfirmComposition(
   1373       render_view_routing_id_,
   1374       guest_instance_id_,
   1375       text.utf8(),
   1376       keep_selection));
   1377   // TODO(kochi): This assumes the IPC handling always succeeds.
   1378   return true;
   1379 }
   1380 
   1381 void BrowserPlugin::extendSelectionAndDelete(int before, int after) {
   1382   if (!HasGuestInstanceID())
   1383     return;
   1384   browser_plugin_manager()->Send(
   1385       new BrowserPluginHostMsg_ExtendSelectionAndDelete(
   1386           render_view_routing_id_,
   1387           guest_instance_id_,
   1388           before,
   1389           after));
   1390 }
   1391 
   1392 void BrowserPlugin::OnLockMouseACK(bool succeeded) {
   1393   mouse_locked_ = succeeded;
   1394   browser_plugin_manager()->Send(new BrowserPluginHostMsg_LockMouse_ACK(
   1395       render_view_routing_id_,
   1396       guest_instance_id_,
   1397       succeeded));
   1398 }
   1399 
   1400 void BrowserPlugin::OnMouseLockLost() {
   1401   mouse_locked_ = false;
   1402   browser_plugin_manager()->Send(new BrowserPluginHostMsg_UnlockMouse_ACK(
   1403       render_view_routing_id_,
   1404       guest_instance_id_));
   1405 }
   1406 
   1407 bool BrowserPlugin::HandleMouseLockedInputEvent(
   1408     const blink::WebMouseEvent& event) {
   1409   browser_plugin_manager()->Send(
   1410       new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
   1411                                                 guest_instance_id_,
   1412                                                 plugin_rect_,
   1413                                                 &event));
   1414   return true;
   1415 }
   1416 
   1417 }  // namespace content
   1418