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, ¶m))
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(¶ms, 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(¶ms, 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