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