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