• 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/message_loop/message_loop.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/common/browser_plugin/browser_plugin_constants.h"
12 #include "content/common/browser_plugin/browser_plugin_messages.h"
13 #include "content/common/view_messages.h"
14 #include "content/public/common/content_client.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/renderer/content_renderer_client.h"
17 #include "content/renderer/browser_plugin/browser_plugin_bindings.h"
18 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
19 #include "content/renderer/child_frame_compositing_helper.h"
20 #include "content/renderer/cursor_utils.h"
21 #include "content/renderer/drop_data_builder.h"
22 #include "content/renderer/render_thread_impl.h"
23 #include "content/renderer/sad_plugin.h"
24 #include "third_party/WebKit/public/platform/WebRect.h"
25 #include "third_party/WebKit/public/web/WebBindings.h"
26 #include "third_party/WebKit/public/web/WebDocument.h"
27 #include "third_party/WebKit/public/web/WebElement.h"
28 #include "third_party/WebKit/public/web/WebInputEvent.h"
29 #include "third_party/WebKit/public/web/WebPluginContainer.h"
30 #include "third_party/WebKit/public/web/WebPluginParams.h"
31 #include "third_party/WebKit/public/web/WebView.h"
32 #include "third_party/skia/include/core/SkCanvas.h"
33 #include "ui/events/keycodes/keyboard_codes.h"
34 
35 using blink::WebCanvas;
36 using blink::WebPluginContainer;
37 using blink::WebPluginParams;
38 using blink::WebPoint;
39 using blink::WebRect;
40 using blink::WebURL;
41 using blink::WebVector;
42 
43 namespace content {
44 
BrowserPlugin(RenderViewImpl * render_view,blink::WebFrame * frame,bool auto_navigate)45 BrowserPlugin::BrowserPlugin(RenderViewImpl* render_view,
46                              blink::WebFrame* frame,
47                              bool auto_navigate)
48     : guest_instance_id_(browser_plugin::kInstanceIDNone),
49       attached_(false),
50       render_view_(render_view->AsWeakPtr()),
51       render_view_routing_id_(render_view->GetRoutingID()),
52       container_(NULL),
53       paint_ack_received_(true),
54       last_device_scale_factor_(GetDeviceScaleFactor()),
55       sad_guest_(NULL),
56       guest_crashed_(false),
57       is_auto_size_state_dirty_(false),
58       content_window_routing_id_(MSG_ROUTING_NONE),
59       plugin_focused_(false),
60       visible_(true),
61       auto_navigate_(auto_navigate),
62       mouse_locked_(false),
63       browser_plugin_manager_(render_view->GetBrowserPluginManager()),
64       embedder_frame_url_(frame->document().url()),
65       weak_ptr_factory_(this) {
66 }
67 
~BrowserPlugin()68 BrowserPlugin::~BrowserPlugin() {
69   // If the BrowserPlugin has never navigated then the browser process and
70   // BrowserPluginManager don't know about it and so there is nothing to do
71   // here.
72   if (!HasGuestInstanceID())
73     return;
74   browser_plugin_manager()->RemoveBrowserPlugin(guest_instance_id_);
75   browser_plugin_manager()->Send(
76       new BrowserPluginHostMsg_PluginDestroyed(render_view_routing_id_,
77                                                guest_instance_id_));
78 }
79 
OnMessageReceived(const IPC::Message & message)80 bool BrowserPlugin::OnMessageReceived(const IPC::Message& message) {
81   bool handled = true;
82   IPC_BEGIN_MESSAGE_MAP(BrowserPlugin, message)
83     IPC_MESSAGE_HANDLER(BrowserPluginMsg_AdvanceFocus, OnAdvanceFocus)
84     IPC_MESSAGE_HANDLER(BrowserPluginMsg_Attach_ACK, OnAttachACK)
85     IPC_MESSAGE_HANDLER(BrowserPluginMsg_BuffersSwapped, OnBuffersSwapped)
86     IPC_MESSAGE_HANDLER_GENERIC(BrowserPluginMsg_CompositorFrameSwapped,
87                                 OnCompositorFrameSwapped(message))
88     IPC_MESSAGE_HANDLER(BrowserPluginMsg_CopyFromCompositingSurface,
89                         OnCopyFromCompositingSurface)
90     IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestContentWindowReady,
91                         OnGuestContentWindowReady)
92     IPC_MESSAGE_HANDLER(BrowserPluginMsg_GuestGone, OnGuestGone)
93     IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetCursor, OnSetCursor)
94     IPC_MESSAGE_HANDLER(BrowserPluginMsg_SetMouseLock, OnSetMouseLock)
95     IPC_MESSAGE_HANDLER(BrowserPluginMsg_ShouldAcceptTouchEvents,
96                         OnShouldAcceptTouchEvents)
97     IPC_MESSAGE_HANDLER(BrowserPluginMsg_UpdateRect, OnUpdateRect)
98     IPC_MESSAGE_UNHANDLED(handled = false)
99   IPC_END_MESSAGE_MAP()
100   return handled;
101 }
102 
UpdateDOMAttribute(const std::string & attribute_name,const std::string & attribute_value)103 void BrowserPlugin::UpdateDOMAttribute(const std::string& attribute_name,
104                                        const std::string& attribute_value) {
105   if (!container())
106     return;
107 
108   blink::WebElement element = container()->element();
109   blink::WebString web_attribute_name =
110       blink::WebString::fromUTF8(attribute_name);
111   if (!HasDOMAttribute(attribute_name) ||
112       (std::string(element.getAttribute(web_attribute_name).utf8()) !=
113           attribute_value)) {
114     element.setAttribute(web_attribute_name,
115         blink::WebString::fromUTF8(attribute_value));
116   }
117 }
118 
RemoveDOMAttribute(const std::string & attribute_name)119 void BrowserPlugin::RemoveDOMAttribute(const std::string& attribute_name) {
120   if (!container())
121     return;
122 
123   container()->element().removeAttribute(
124       blink::WebString::fromUTF8(attribute_name));
125 }
126 
GetDOMAttributeValue(const std::string & attribute_name) const127 std::string BrowserPlugin::GetDOMAttributeValue(
128     const std::string& attribute_name) const {
129   if (!container())
130     return std::string();
131 
132   return container()->element().getAttribute(
133       blink::WebString::fromUTF8(attribute_name)).utf8();
134 }
135 
HasDOMAttribute(const std::string & attribute_name) const136 bool BrowserPlugin::HasDOMAttribute(const std::string& attribute_name) const {
137   if (!container())
138     return false;
139 
140   return container()->element().hasAttribute(
141       blink::WebString::fromUTF8(attribute_name));
142 }
143 
GetAllowTransparencyAttribute() const144 bool BrowserPlugin::GetAllowTransparencyAttribute() const {
145   return HasDOMAttribute(browser_plugin::kAttributeAllowTransparency);
146 }
147 
GetAutoSizeAttribute() const148 bool BrowserPlugin::GetAutoSizeAttribute() const {
149   return HasDOMAttribute(browser_plugin::kAttributeAutoSize);
150 }
151 
GetMaxHeightAttribute() const152 int BrowserPlugin::GetMaxHeightAttribute() const {
153   int max_height;
154   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxHeight),
155                     &max_height);
156   return max_height;
157 }
158 
GetMaxWidthAttribute() const159 int BrowserPlugin::GetMaxWidthAttribute() const {
160   int max_width;
161   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxWidth),
162                     &max_width);
163   return max_width;
164 }
165 
GetMinHeightAttribute() const166 int BrowserPlugin::GetMinHeightAttribute() const {
167   int min_height;
168   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinHeight),
169                     &min_height);
170   return min_height;
171 }
172 
GetMinWidthAttribute() const173 int BrowserPlugin::GetMinWidthAttribute() const {
174   int min_width;
175   base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinWidth),
176                     &min_width);
177   return min_width;
178 }
179 
GetAdjustedMaxHeight() const180 int BrowserPlugin::GetAdjustedMaxHeight() const {
181   int max_height = GetMaxHeightAttribute();
182   return max_height ? max_height : height();
183 }
184 
GetAdjustedMaxWidth() const185 int BrowserPlugin::GetAdjustedMaxWidth() const {
186   int max_width = GetMaxWidthAttribute();
187   return max_width ? max_width : width();
188 }
189 
GetAdjustedMinHeight() const190 int BrowserPlugin::GetAdjustedMinHeight() const {
191   int min_height = GetMinHeightAttribute();
192   // FrameView.cpp does not allow this value to be <= 0, so when the value is
193   // unset (or set to 0), we set it to the container size.
194   min_height = min_height ? min_height : height();
195   // For autosize, minHeight should not be bigger than maxHeight.
196   return std::min(min_height, GetAdjustedMaxHeight());
197 }
198 
GetAdjustedMinWidth() const199 int BrowserPlugin::GetAdjustedMinWidth() const {
200   int min_width = GetMinWidthAttribute();
201   // FrameView.cpp does not allow this value to be <= 0, so when the value is
202   // unset (or set to 0), we set it to the container size.
203   min_width = min_width ? min_width : width();
204   // For autosize, minWidth should not be bigger than maxWidth.
205   return std::min(min_width, GetAdjustedMaxWidth());
206 }
207 
ParseAllowTransparencyAttribute()208 void BrowserPlugin::ParseAllowTransparencyAttribute() {
209   if (!HasGuestInstanceID())
210     return;
211 
212   bool opaque = !GetAllowTransparencyAttribute();
213 
214   if (compositing_helper_)
215     compositing_helper_->SetContentsOpaque(opaque);
216 
217   browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetContentsOpaque(
218         render_view_routing_id_,
219         guest_instance_id_,
220         opaque));
221 }
222 
ParseAutoSizeAttribute()223 void BrowserPlugin::ParseAutoSizeAttribute() {
224   last_view_size_ = plugin_size();
225   is_auto_size_state_dirty_ = true;
226   UpdateGuestAutoSizeState(GetAutoSizeAttribute());
227 }
228 
PopulateAutoSizeParameters(BrowserPluginHostMsg_AutoSize_Params * params,bool auto_size_enabled)229 void BrowserPlugin::PopulateAutoSizeParameters(
230     BrowserPluginHostMsg_AutoSize_Params* params, bool auto_size_enabled) {
231   params->enable = auto_size_enabled;
232   // No need to populate the params if autosize is off.
233   if (auto_size_enabled) {
234     params->max_size = gfx::Size(GetAdjustedMaxWidth(), GetAdjustedMaxHeight());
235     params->min_size = gfx::Size(GetAdjustedMinWidth(), GetAdjustedMinHeight());
236 
237     if (max_auto_size_ != params->max_size)
238       is_auto_size_state_dirty_ = true;
239 
240     max_auto_size_ = params->max_size;
241   } else {
242     max_auto_size_ = gfx::Size();
243   }
244 }
245 
UpdateGuestAutoSizeState(bool auto_size_enabled)246 void BrowserPlugin::UpdateGuestAutoSizeState(bool auto_size_enabled) {
247   // If we haven't yet heard back from the guest about the last resize request,
248   // then we don't issue another request until we do in
249   // BrowserPlugin::OnUpdateRect.
250   if (!HasGuestInstanceID() || !paint_ack_received_)
251     return;
252 
253   BrowserPluginHostMsg_AutoSize_Params auto_size_params;
254   BrowserPluginHostMsg_ResizeGuest_Params resize_guest_params;
255   if (auto_size_enabled) {
256     GetSizeParams(&auto_size_params, &resize_guest_params, true);
257   } else {
258     GetSizeParams(NULL, &resize_guest_params, true);
259   }
260   paint_ack_received_ = false;
261   browser_plugin_manager()->Send(
262       new BrowserPluginHostMsg_SetAutoSize(render_view_routing_id_,
263                                            guest_instance_id_,
264                                            auto_size_params,
265                                            resize_guest_params));
266 }
267 
Attach(int guest_instance_id,scoped_ptr<base::DictionaryValue> extra_params)268 void BrowserPlugin::Attach(int guest_instance_id,
269                            scoped_ptr<base::DictionaryValue> extra_params) {
270   CHECK(guest_instance_id != browser_plugin::kInstanceIDNone);
271 
272   // If this BrowserPlugin is already attached to a guest, then do nothing.
273   if (HasGuestInstanceID())
274     return;
275 
276   // This API may be called directly without setting the src attribute.
277   // In that case, we need to make sure we don't allocate another instance ID.
278   guest_instance_id_ = guest_instance_id;
279   browser_plugin_manager()->AddBrowserPlugin(guest_instance_id, this);
280 
281   BrowserPluginHostMsg_Attach_Params attach_params;
282   attach_params.focused = ShouldGuestBeFocused();
283   attach_params.visible = visible_;
284   attach_params.opaque = !GetAllowTransparencyAttribute();
285   attach_params.embedder_frame_url = embedder_frame_url_;
286   attach_params.origin = plugin_rect().origin();
287   GetSizeParams(&attach_params.auto_size_params,
288                 &attach_params.resize_guest_params,
289                 false);
290 
291   browser_plugin_manager()->Send(
292       new BrowserPluginHostMsg_Attach(render_view_routing_id_,
293                                       guest_instance_id_, attach_params,
294                                       *extra_params));
295 }
296 
DidCommitCompositorFrame()297 void BrowserPlugin::DidCommitCompositorFrame() {
298   if (compositing_helper_.get())
299     compositing_helper_->DidCommitCompositorFrame();
300 }
301 
OnAdvanceFocus(int guest_instance_id,bool reverse)302 void BrowserPlugin::OnAdvanceFocus(int guest_instance_id, bool reverse) {
303   DCHECK(render_view_.get());
304   render_view_->GetWebView()->advanceFocus(reverse);
305 }
306 
OnAttachACK(int guest_instance_id)307 void BrowserPlugin::OnAttachACK(int guest_instance_id) {
308   attached_ = true;
309 }
310 
OnBuffersSwapped(int instance_id,const FrameMsg_BuffersSwapped_Params & params)311 void BrowserPlugin::OnBuffersSwapped(
312     int instance_id,
313     const FrameMsg_BuffersSwapped_Params& params) {
314   EnableCompositing(true);
315 
316   compositing_helper_->OnBuffersSwapped(params.size,
317                                         params.mailbox,
318                                         params.gpu_route_id,
319                                         params.gpu_host_id,
320                                         GetDeviceScaleFactor());
321 }
322 
OnCompositorFrameSwapped(const IPC::Message & message)323 void BrowserPlugin::OnCompositorFrameSwapped(const IPC::Message& message) {
324   BrowserPluginMsg_CompositorFrameSwapped::Param param;
325   if (!BrowserPluginMsg_CompositorFrameSwapped::Read(&message, &param))
326     return;
327   scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
328   param.b.frame.AssignTo(frame.get());
329 
330   EnableCompositing(true);
331   compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
332                                                 param.b.producing_route_id,
333                                                 param.b.output_surface_id,
334                                                 param.b.producing_host_id,
335                                                 param.b.shared_memory_handle);
336 }
337 
OnCopyFromCompositingSurface(int guest_instance_id,int request_id,gfx::Rect source_rect,gfx::Size dest_size)338 void BrowserPlugin::OnCopyFromCompositingSurface(int guest_instance_id,
339                                                  int request_id,
340                                                  gfx::Rect source_rect,
341                                                  gfx::Size dest_size) {
342   if (!compositing_helper_) {
343     browser_plugin_manager()->Send(
344         new BrowserPluginHostMsg_CopyFromCompositingSurfaceAck(
345             render_view_routing_id_,
346             guest_instance_id_,
347             request_id,
348             SkBitmap()));
349     return;
350   }
351   compositing_helper_->CopyFromCompositingSurface(request_id, source_rect,
352                                                   dest_size);
353 }
354 
OnGuestContentWindowReady(int guest_instance_id,int content_window_routing_id)355 void BrowserPlugin::OnGuestContentWindowReady(int guest_instance_id,
356                                               int content_window_routing_id) {
357   DCHECK(content_window_routing_id != MSG_ROUTING_NONE);
358   content_window_routing_id_ = content_window_routing_id;
359 }
360 
OnGuestGone(int guest_instance_id)361 void BrowserPlugin::OnGuestGone(int guest_instance_id) {
362   guest_crashed_ = true;
363 
364   // Turn off compositing so we can display the sad graphic. Changes to
365   // compositing state will show up at a later time after a layout and commit.
366   EnableCompositing(false);
367 
368   // Queue up showing the sad graphic to give content embedders an opportunity
369   // to fire their listeners and potentially overlay the webview with custom
370   // behavior. If the BrowserPlugin is destroyed in the meantime, then the
371   // task will not be executed.
372   base::MessageLoop::current()->PostTask(
373       FROM_HERE,
374       base::Bind(&BrowserPlugin::ShowSadGraphic,
375                  weak_ptr_factory_.GetWeakPtr()));
376 }
377 
OnSetCursor(int guest_instance_id,const WebCursor & cursor)378 void BrowserPlugin::OnSetCursor(int guest_instance_id,
379                                 const WebCursor& cursor) {
380   cursor_ = cursor;
381 }
382 
OnSetMouseLock(int guest_instance_id,bool enable)383 void BrowserPlugin::OnSetMouseLock(int guest_instance_id,
384                                    bool enable) {
385   if (enable) {
386     if (mouse_locked_)
387       return;
388     render_view_->mouse_lock_dispatcher()->LockMouse(this);
389   } else {
390     if (!mouse_locked_) {
391       OnLockMouseACK(false);
392       return;
393     }
394     render_view_->mouse_lock_dispatcher()->UnlockMouse(this);
395   }
396 }
397 
OnShouldAcceptTouchEvents(int guest_instance_id,bool accept)398 void BrowserPlugin::OnShouldAcceptTouchEvents(int guest_instance_id,
399                                               bool accept) {
400   if (container()) {
401     container()->requestTouchEventType(accept ?
402         blink::WebPluginContainer::TouchEventRequestTypeRaw :
403         blink::WebPluginContainer::TouchEventRequestTypeNone);
404   }
405 }
406 
OnUpdateRect(int guest_instance_id,const BrowserPluginMsg_UpdateRect_Params & params)407 void BrowserPlugin::OnUpdateRect(
408     int guest_instance_id,
409     const BrowserPluginMsg_UpdateRect_Params& params) {
410   // Note that there is no need to send ACK for this message.
411   // If the guest has updated pixels then it is no longer crashed.
412   guest_crashed_ = false;
413 
414   bool auto_size = GetAutoSizeAttribute();
415   // We receive a resize ACK in regular mode, but not in autosize.
416   // In Compositing mode, we need to do it here so we can continue sending
417   // resize messages when needed.
418   if (params.is_resize_ack || (auto_size || is_auto_size_state_dirty_))
419     paint_ack_received_ = true;
420 
421   bool was_auto_size_state_dirty = auto_size && is_auto_size_state_dirty_;
422   is_auto_size_state_dirty_ = false;
423 
424   if ((!auto_size && (width() != params.view_size.width() ||
425                       height() != params.view_size.height())) ||
426       (auto_size && was_auto_size_state_dirty) ||
427       GetDeviceScaleFactor() != params.scale_factor) {
428     UpdateGuestAutoSizeState(auto_size);
429     return;
430   }
431 
432   if (auto_size && (params.view_size != last_view_size_))
433     last_view_size_ = params.view_size;
434 
435   BrowserPluginHostMsg_AutoSize_Params auto_size_params;
436   BrowserPluginHostMsg_ResizeGuest_Params resize_guest_params;
437 
438   // BrowserPluginHostMsg_UpdateRect_ACK is used by both the compositing and
439   // software paths to piggyback updated autosize parameters.
440   if (auto_size)
441     PopulateAutoSizeParameters(&auto_size_params, auto_size);
442 
443   browser_plugin_manager()->Send(
444       new BrowserPluginHostMsg_SetAutoSize(render_view_routing_id_,
445                                            guest_instance_id_,
446                                            auto_size_params,
447                                            resize_guest_params));
448 }
449 
ParseSizeContraintsChanged()450 void BrowserPlugin::ParseSizeContraintsChanged() {
451   bool auto_size = GetAutoSizeAttribute();
452   if (auto_size) {
453     is_auto_size_state_dirty_ = true;
454     UpdateGuestAutoSizeState(true);
455   }
456 }
457 
InAutoSizeBounds(const gfx::Size & size) const458 bool BrowserPlugin::InAutoSizeBounds(const gfx::Size& size) const {
459   return size.width() <= GetAdjustedMaxWidth() &&
460       size.height() <= GetAdjustedMaxHeight();
461 }
462 
GetContentWindow() const463 NPObject* BrowserPlugin::GetContentWindow() const {
464   if (content_window_routing_id_ == MSG_ROUTING_NONE)
465     return NULL;
466   RenderViewImpl* guest_render_view = RenderViewImpl::FromRoutingID(
467       content_window_routing_id_);
468   if (!guest_render_view)
469     return NULL;
470   blink::WebFrame* guest_frame = guest_render_view->GetWebView()->mainFrame();
471   return guest_frame->windowObject();
472 }
473 
HasGuestInstanceID() const474 bool BrowserPlugin::HasGuestInstanceID() const {
475   return guest_instance_id_ != browser_plugin::kInstanceIDNone;
476 }
477 
ShowSadGraphic()478 void BrowserPlugin::ShowSadGraphic() {
479   // If the BrowserPlugin is scheduled to be deleted, then container_ will be
480   // NULL so we shouldn't attempt to access it.
481   if (container_)
482     container_->invalidate();
483 }
484 
GetDeviceScaleFactor() const485 float BrowserPlugin::GetDeviceScaleFactor() const {
486   if (!render_view_.get())
487     return 1.0f;
488   return render_view_->GetWebView()->deviceScaleFactor();
489 }
490 
UpdateDeviceScaleFactor(float device_scale_factor)491 void BrowserPlugin::UpdateDeviceScaleFactor(float device_scale_factor) {
492   if (last_device_scale_factor_ == device_scale_factor || !paint_ack_received_)
493     return;
494 
495   BrowserPluginHostMsg_ResizeGuest_Params params;
496   PopulateResizeGuestParameters(&params, plugin_size(), true);
497   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
498       render_view_routing_id_,
499       guest_instance_id_,
500       params));
501 }
502 
UpdateGuestFocusState()503 void BrowserPlugin::UpdateGuestFocusState() {
504   if (!HasGuestInstanceID())
505     return;
506   bool should_be_focused = ShouldGuestBeFocused();
507   browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetFocus(
508       render_view_routing_id_,
509       guest_instance_id_,
510       should_be_focused));
511 }
512 
ShouldGuestBeFocused() const513 bool BrowserPlugin::ShouldGuestBeFocused() const {
514   bool embedder_focused = false;
515   if (render_view_.get())
516     embedder_focused = render_view_->has_focus();
517   return plugin_focused_ && embedder_focused;
518 }
519 
container() const520 blink::WebPluginContainer* BrowserPlugin::container() const {
521   return container_;
522 }
523 
initialize(WebPluginContainer * container)524 bool BrowserPlugin::initialize(WebPluginContainer* container) {
525   if (!container)
526     return false;
527 
528   // Tell |container| to allow this plugin to use script objects.
529   npp_.reset(new NPP_t);
530   container->allowScriptObjects();
531 
532   bindings_.reset(new BrowserPluginBindings(this));
533   container_ = container;
534   container_->setWantsWheelEvents(true);
535   // This is a way to notify observers of our attributes that we have the
536   // bindings ready. This also means that this plugin is available in render
537   // tree.
538   UpdateDOMAttribute("internalbindings", "true");
539   return true;
540 }
541 
EnableCompositing(bool enable)542 void BrowserPlugin::EnableCompositing(bool enable) {
543   bool enabled = !!compositing_helper_;
544   if (enabled == enable)
545     return;
546 
547   if (enable) {
548     DCHECK(!compositing_helper_.get());
549     if (!compositing_helper_.get()) {
550       compositing_helper_ =
551           ChildFrameCompositingHelper::CreateCompositingHelperForBrowserPlugin(
552               weak_ptr_factory_.GetWeakPtr());
553     }
554   }
555   compositing_helper_->EnableCompositing(enable);
556   compositing_helper_->SetContentsOpaque(!GetAllowTransparencyAttribute());
557 
558   if (!enable) {
559     DCHECK(compositing_helper_.get());
560     compositing_helper_->OnContainerDestroy();
561     compositing_helper_ = NULL;
562   }
563 }
564 
destroy()565 void BrowserPlugin::destroy() {
566   // If the plugin was initialized then it has a valid |npp_| identifier, and
567   // the |container_| must clear references to the plugin's script objects.
568   DCHECK(!npp_ || container_);
569   if (container_)
570     container_->clearScriptObjects();
571 
572   if (compositing_helper_.get())
573     compositing_helper_->OnContainerDestroy();
574   container_ = NULL;
575   // Will be a no-op if the mouse is not currently locked.
576   if (render_view_.get())
577     render_view_->mouse_lock_dispatcher()->OnLockTargetDestroyed(this);
578   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
579 }
580 
scriptableObject()581 NPObject* BrowserPlugin::scriptableObject() {
582   if (!bindings_)
583     return NULL;
584 
585   NPObject* browser_plugin_np_object(bindings_->np_object());
586   // The object is expected to be retained before it is returned.
587   blink::WebBindings::retainObject(browser_plugin_np_object);
588   return browser_plugin_np_object;
589 }
590 
pluginNPP()591 NPP BrowserPlugin::pluginNPP() {
592   return npp_.get();
593 }
594 
supportsKeyboardFocus() const595 bool BrowserPlugin::supportsKeyboardFocus() const {
596   return true;
597 }
598 
supportsEditCommands() const599 bool BrowserPlugin::supportsEditCommands() const {
600   return true;
601 }
602 
supportsInputMethod() const603 bool BrowserPlugin::supportsInputMethod() const {
604   return true;
605 }
606 
canProcessDrag() const607 bool BrowserPlugin::canProcessDrag() const {
608   return true;
609 }
610 
paint(WebCanvas * canvas,const WebRect & rect)611 void BrowserPlugin::paint(WebCanvas* canvas, const WebRect& rect) {
612   if (guest_crashed_) {
613     if (!sad_guest_)  // Lazily initialize bitmap.
614       sad_guest_ = content::GetContentClient()->renderer()->
615           GetSadWebViewBitmap();
616     // content_shell does not have the sad plugin bitmap, so we'll paint black
617     // instead to make it clear that something went wrong.
618     if (sad_guest_) {
619       PaintSadPlugin(canvas, plugin_rect_, *sad_guest_);
620       return;
621     }
622   }
623   SkAutoCanvasRestore auto_restore(canvas, true);
624   canvas->translate(plugin_rect_.x(), plugin_rect_.y());
625   SkRect image_data_rect = SkRect::MakeXYWH(
626       SkIntToScalar(0),
627       SkIntToScalar(0),
628       SkIntToScalar(plugin_rect_.width()),
629       SkIntToScalar(plugin_rect_.height()));
630   canvas->clipRect(image_data_rect);
631   // Paint black or white in case we have nothing in our backing store or we
632   // need to show a gutter.
633   SkPaint paint;
634   paint.setStyle(SkPaint::kFill_Style);
635   paint.setColor(guest_crashed_ ? SK_ColorBLACK : SK_ColorWHITE);
636   canvas->drawRect(image_data_rect, paint);
637 }
638 
639 // static
ShouldForwardToBrowserPlugin(const IPC::Message & message)640 bool BrowserPlugin::ShouldForwardToBrowserPlugin(
641     const IPC::Message& message) {
642   switch (message.type()) {
643     case BrowserPluginMsg_AdvanceFocus::ID:
644     case BrowserPluginMsg_Attach_ACK::ID:
645     case BrowserPluginMsg_BuffersSwapped::ID:
646     case BrowserPluginMsg_CompositorFrameSwapped::ID:
647     case BrowserPluginMsg_CopyFromCompositingSurface::ID:
648     case BrowserPluginMsg_GuestContentWindowReady::ID:
649     case BrowserPluginMsg_GuestGone::ID:
650     case BrowserPluginMsg_SetCursor::ID:
651     case BrowserPluginMsg_SetMouseLock::ID:
652     case BrowserPluginMsg_ShouldAcceptTouchEvents::ID:
653     case BrowserPluginMsg_UpdateRect::ID:
654       return true;
655     default:
656       break;
657   }
658   return false;
659 }
660 
updateGeometry(const WebRect & window_rect,const WebRect & clip_rect,const WebVector<WebRect> & cut_outs_rects,bool is_visible)661 void BrowserPlugin::updateGeometry(
662     const WebRect& window_rect,
663     const WebRect& clip_rect,
664     const WebVector<WebRect>& cut_outs_rects,
665     bool is_visible) {
666   int old_width = width();
667   int old_height = height();
668   plugin_rect_ = window_rect;
669   if (!attached())
670     return;
671 
672   // In AutoSize mode, guests don't care when the BrowserPlugin container is
673   // resized. If |!paint_ack_received_|, then we are still waiting on a
674   // previous resize to be ACK'ed and so we don't issue additional resizes
675   // until the previous one is ACK'ed.
676   // TODO(mthiesse): Assess the performance of calling GetAutoSizeAttribute() on
677   // resize.
678   if (!paint_ack_received_ ||
679       (old_width == window_rect.width && old_height == window_rect.height) ||
680       GetAutoSizeAttribute()) {
681     // Let the browser know about the updated view rect.
682     browser_plugin_manager()->Send(new BrowserPluginHostMsg_UpdateGeometry(
683         render_view_routing_id_, guest_instance_id_, plugin_rect_));
684     return;
685   }
686 
687   BrowserPluginHostMsg_ResizeGuest_Params params;
688   PopulateResizeGuestParameters(&params, plugin_size(), false);
689   paint_ack_received_ = false;
690   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ResizeGuest(
691       render_view_routing_id_,
692       guest_instance_id_,
693       params));
694 }
695 
PopulateResizeGuestParameters(BrowserPluginHostMsg_ResizeGuest_Params * params,const gfx::Size & view_size,bool needs_repaint)696 void BrowserPlugin::PopulateResizeGuestParameters(
697     BrowserPluginHostMsg_ResizeGuest_Params* params,
698     const gfx::Size& view_size,
699     bool needs_repaint) {
700   params->size_changed = true;
701   params->view_size = view_size;
702   params->repaint = needs_repaint;
703   params->scale_factor = GetDeviceScaleFactor();
704   if (last_device_scale_factor_ != params->scale_factor){
705     DCHECK(params->repaint);
706     last_device_scale_factor_ = params->scale_factor;
707   }
708 }
709 
GetSizeParams(BrowserPluginHostMsg_AutoSize_Params * auto_size_params,BrowserPluginHostMsg_ResizeGuest_Params * resize_guest_params,bool needs_repaint)710 void BrowserPlugin::GetSizeParams(
711     BrowserPluginHostMsg_AutoSize_Params* auto_size_params,
712     BrowserPluginHostMsg_ResizeGuest_Params* resize_guest_params,
713     bool needs_repaint) {
714   if (auto_size_params) {
715     PopulateAutoSizeParameters(auto_size_params, GetAutoSizeAttribute());
716   } else {
717     max_auto_size_ = gfx::Size();
718   }
719   gfx::Size view_size = (auto_size_params && auto_size_params->enable) ?
720       auto_size_params->max_size : gfx::Size(width(), height());
721   if (view_size.IsEmpty())
722     return;
723   paint_ack_received_ = false;
724   PopulateResizeGuestParameters(resize_guest_params, view_size, needs_repaint);
725 }
726 
updateFocus(bool focused)727 void BrowserPlugin::updateFocus(bool focused) {
728   plugin_focused_ = focused;
729   UpdateGuestFocusState();
730 }
731 
updateVisibility(bool visible)732 void BrowserPlugin::updateVisibility(bool visible) {
733   if (visible_ == visible)
734     return;
735 
736   visible_ = visible;
737   if (!HasGuestInstanceID())
738     return;
739 
740   if (compositing_helper_.get())
741     compositing_helper_->UpdateVisibility(visible);
742 
743   browser_plugin_manager()->Send(new BrowserPluginHostMsg_SetVisibility(
744       render_view_routing_id_,
745       guest_instance_id_,
746       visible));
747 }
748 
acceptsInputEvents()749 bool BrowserPlugin::acceptsInputEvents() {
750   return true;
751 }
752 
handleInputEvent(const blink::WebInputEvent & event,blink::WebCursorInfo & cursor_info)753 bool BrowserPlugin::handleInputEvent(const blink::WebInputEvent& event,
754                                      blink::WebCursorInfo& cursor_info) {
755   if (guest_crashed_ || !HasGuestInstanceID())
756     return false;
757 
758   if (event.type == blink::WebInputEvent::ContextMenu)
759     return true;
760 
761   const blink::WebInputEvent* modified_event = &event;
762   scoped_ptr<blink::WebTouchEvent> touch_event;
763   if (blink::WebInputEvent::isTouchEventType(event.type)) {
764     const blink::WebTouchEvent* orig_touch_event =
765         static_cast<const blink::WebTouchEvent*>(&event);
766 
767     touch_event.reset(new blink::WebTouchEvent());
768     memcpy(touch_event.get(), orig_touch_event, sizeof(blink::WebTouchEvent));
769 
770     // TODO(bokan): Blink passes back a WebGestureEvent with a touches,
771     // changedTouches, and targetTouches lists; however, it doesn't set
772     // the state field on the touches which is what the RenderWidget uses
773     // to create a WebCore::TouchEvent. crbug.com/358132 tracks removing
774     // these multiple lists from WebTouchEvent since they lead to misuse
775     // like this and are functionally unused. In the mean time we'll setup
776     // the state field here manually to fix multi-touch BrowserPlugins.
777     for (size_t i = 0; i < touch_event->touchesLength; ++i) {
778       blink::WebTouchPoint& touch = touch_event->touches[i];
779       touch.state = blink::WebTouchPoint::StateStationary;
780       for (size_t j = 0; j < touch_event->changedTouchesLength; ++j) {
781         blink::WebTouchPoint& changed_touch = touch_event->changedTouches[j];
782         if (touch.id == changed_touch.id) {
783           touch.state = changed_touch.state;
784           break;
785         }
786       }
787     }
788 
789     // For End and Cancel, Blink gives BrowserPlugin a list of touches that
790     // are down, but the browser process expects a list of all touches. We
791     // modify these events here to match these expectations.
792     if (event.type == blink::WebInputEvent::TouchEnd ||
793         event.type == blink::WebInputEvent::TouchCancel) {
794       if (touch_event->changedTouchesLength > 0) {
795         memcpy(&touch_event->touches[touch_event->touchesLength],
796                &touch_event->changedTouches,
797               touch_event->changedTouchesLength * sizeof(blink::WebTouchPoint));
798         touch_event->touchesLength += touch_event->changedTouchesLength;
799       }
800     }
801     modified_event = touch_event.get();
802   }
803 
804   if (blink::WebInputEvent::isKeyboardEventType(event.type) &&
805       !edit_commands_.empty()) {
806     browser_plugin_manager()->Send(
807         new BrowserPluginHostMsg_SetEditCommandsForNextKeyEvent(
808             render_view_routing_id_,
809             guest_instance_id_,
810             edit_commands_));
811     edit_commands_.clear();
812   }
813 
814   browser_plugin_manager()->Send(
815       new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
816                                                 guest_instance_id_,
817                                                 plugin_rect_,
818                                                 modified_event));
819   GetWebKitCursorInfo(cursor_, &cursor_info);
820   return true;
821 }
822 
handleDragStatusUpdate(blink::WebDragStatus drag_status,const blink::WebDragData & drag_data,blink::WebDragOperationsMask mask,const blink::WebPoint & position,const blink::WebPoint & screen)823 bool BrowserPlugin::handleDragStatusUpdate(blink::WebDragStatus drag_status,
824                                            const blink::WebDragData& drag_data,
825                                            blink::WebDragOperationsMask mask,
826                                            const blink::WebPoint& position,
827                                            const blink::WebPoint& screen) {
828   if (guest_crashed_ || !HasGuestInstanceID())
829     return false;
830   browser_plugin_manager()->Send(
831       new BrowserPluginHostMsg_DragStatusUpdate(
832         render_view_routing_id_,
833         guest_instance_id_,
834         drag_status,
835         DropDataBuilder::Build(drag_data),
836         mask,
837         position));
838   return true;
839 }
840 
didReceiveResponse(const blink::WebURLResponse & response)841 void BrowserPlugin::didReceiveResponse(
842     const blink::WebURLResponse& response) {
843 }
844 
didReceiveData(const char * data,int data_length)845 void BrowserPlugin::didReceiveData(const char* data, int data_length) {
846   if (auto_navigate_) {
847     std::string value(data, data_length);
848     html_string_ += value;
849   }
850 }
851 
didFinishLoading()852 void BrowserPlugin::didFinishLoading() {
853   if (auto_navigate_) {
854     // TODO(lazyboy): Make |auto_navigate_| stuff work.
855     UpdateDOMAttribute(content::browser_plugin::kAttributeSrc, html_string_);
856   }
857 }
858 
didFailLoading(const blink::WebURLError & error)859 void BrowserPlugin::didFailLoading(const blink::WebURLError& error) {
860 }
861 
didFinishLoadingFrameRequest(const blink::WebURL & url,void * notify_data)862 void BrowserPlugin::didFinishLoadingFrameRequest(const blink::WebURL& url,
863                                                  void* notify_data) {
864 }
865 
didFailLoadingFrameRequest(const blink::WebURL & url,void * notify_data,const blink::WebURLError & error)866 void BrowserPlugin::didFailLoadingFrameRequest(
867     const blink::WebURL& url,
868     void* notify_data,
869     const blink::WebURLError& error) {
870 }
871 
executeEditCommand(const blink::WebString & name)872 bool BrowserPlugin::executeEditCommand(const blink::WebString& name) {
873   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ExecuteEditCommand(
874       render_view_routing_id_,
875       guest_instance_id_,
876       name.utf8()));
877 
878   // BrowserPlugin swallows edit commands.
879   return true;
880 }
881 
executeEditCommand(const blink::WebString & name,const blink::WebString & value)882 bool BrowserPlugin::executeEditCommand(const blink::WebString& name,
883                                        const blink::WebString& value) {
884   edit_commands_.push_back(EditCommand(name.utf8(), value.utf8()));
885   // BrowserPlugin swallows edit commands.
886   return true;
887 }
888 
setComposition(const blink::WebString & text,const blink::WebVector<blink::WebCompositionUnderline> & underlines,int selectionStart,int selectionEnd)889 bool BrowserPlugin::setComposition(
890     const blink::WebString& text,
891     const blink::WebVector<blink::WebCompositionUnderline>& underlines,
892     int selectionStart,
893     int selectionEnd) {
894   if (!HasGuestInstanceID())
895     return false;
896   std::vector<blink::WebCompositionUnderline> std_underlines;
897   for (size_t i = 0; i < underlines.size(); ++i) {
898     std_underlines.push_back(underlines[i]);
899   }
900   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeSetComposition(
901       render_view_routing_id_,
902       guest_instance_id_,
903       text.utf8(),
904       std_underlines,
905       selectionStart,
906       selectionEnd));
907   // TODO(kochi): This assumes the IPC handling always succeeds.
908   return true;
909 }
910 
confirmComposition(const blink::WebString & text,blink::WebWidget::ConfirmCompositionBehavior selectionBehavior)911 bool BrowserPlugin::confirmComposition(
912     const blink::WebString& text,
913     blink::WebWidget::ConfirmCompositionBehavior selectionBehavior) {
914   if (!HasGuestInstanceID())
915     return false;
916   bool keep_selection = (selectionBehavior == blink::WebWidget::KeepSelection);
917   browser_plugin_manager()->Send(new BrowserPluginHostMsg_ImeConfirmComposition(
918       render_view_routing_id_,
919       guest_instance_id_,
920       text.utf8(),
921       keep_selection));
922   // TODO(kochi): This assumes the IPC handling always succeeds.
923   return true;
924 }
925 
extendSelectionAndDelete(int before,int after)926 void BrowserPlugin::extendSelectionAndDelete(int before, int after) {
927   if (!HasGuestInstanceID())
928     return;
929   browser_plugin_manager()->Send(
930       new BrowserPluginHostMsg_ExtendSelectionAndDelete(
931           render_view_routing_id_,
932           guest_instance_id_,
933           before,
934           after));
935 }
936 
OnLockMouseACK(bool succeeded)937 void BrowserPlugin::OnLockMouseACK(bool succeeded) {
938   mouse_locked_ = succeeded;
939   browser_plugin_manager()->Send(new BrowserPluginHostMsg_LockMouse_ACK(
940       render_view_routing_id_,
941       guest_instance_id_,
942       succeeded));
943 }
944 
OnMouseLockLost()945 void BrowserPlugin::OnMouseLockLost() {
946   mouse_locked_ = false;
947   browser_plugin_manager()->Send(new BrowserPluginHostMsg_UnlockMouse_ACK(
948       render_view_routing_id_,
949       guest_instance_id_));
950 }
951 
HandleMouseLockedInputEvent(const blink::WebMouseEvent & event)952 bool BrowserPlugin::HandleMouseLockedInputEvent(
953     const blink::WebMouseEvent& event) {
954   browser_plugin_manager()->Send(
955       new BrowserPluginHostMsg_HandleInputEvent(render_view_routing_id_,
956                                                 guest_instance_id_,
957                                                 plugin_rect_,
958                                                 &event));
959   return true;
960 }
961 
962 }  // namespace content
963