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