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 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 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 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 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 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 127 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 136 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 144 bool BrowserPlugin::GetAllowTransparencyAttribute() const { 145 return HasDOMAttribute(browser_plugin::kAttributeAllowTransparency); 146 } 147 148 bool BrowserPlugin::GetAutoSizeAttribute() const { 149 return HasDOMAttribute(browser_plugin::kAttributeAutoSize); 150 } 151 152 int BrowserPlugin::GetMaxHeightAttribute() const { 153 int max_height; 154 base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxHeight), 155 &max_height); 156 return max_height; 157 } 158 159 int BrowserPlugin::GetMaxWidthAttribute() const { 160 int max_width; 161 base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMaxWidth), 162 &max_width); 163 return max_width; 164 } 165 166 int BrowserPlugin::GetMinHeightAttribute() const { 167 int min_height; 168 base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinHeight), 169 &min_height); 170 return min_height; 171 } 172 173 int BrowserPlugin::GetMinWidthAttribute() const { 174 int min_width; 175 base::StringToInt(GetDOMAttributeValue(browser_plugin::kAttributeMinWidth), 176 &min_width); 177 return min_width; 178 } 179 180 int BrowserPlugin::GetAdjustedMaxHeight() const { 181 int max_height = GetMaxHeightAttribute(); 182 return max_height ? max_height : height(); 183 } 184 185 int BrowserPlugin::GetAdjustedMaxWidth() const { 186 int max_width = GetMaxWidthAttribute(); 187 return max_width ? max_width : width(); 188 } 189 190 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 199 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 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 223 void BrowserPlugin::ParseAutoSizeAttribute() { 224 last_view_size_ = plugin_size(); 225 is_auto_size_state_dirty_ = true; 226 UpdateGuestAutoSizeState(GetAutoSizeAttribute()); 227 } 228 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 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 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 297 void BrowserPlugin::DidCommitCompositorFrame() { 298 if (compositing_helper_.get()) 299 compositing_helper_->DidCommitCompositorFrame(); 300 } 301 302 void BrowserPlugin::OnAdvanceFocus(int guest_instance_id, bool reverse) { 303 DCHECK(render_view_.get()); 304 render_view_->GetWebView()->advanceFocus(reverse); 305 } 306 307 void BrowserPlugin::OnAttachACK(int guest_instance_id) { 308 attached_ = true; 309 } 310 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 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 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 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 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 378 void BrowserPlugin::OnSetCursor(int guest_instance_id, 379 const WebCursor& cursor) { 380 cursor_ = cursor; 381 } 382 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 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 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 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 458 bool BrowserPlugin::InAutoSizeBounds(const gfx::Size& size) const { 459 return size.width() <= GetAdjustedMaxWidth() && 460 size.height() <= GetAdjustedMaxHeight(); 461 } 462 463 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 474 bool BrowserPlugin::HasGuestInstanceID() const { 475 return guest_instance_id_ != browser_plugin::kInstanceIDNone; 476 } 477 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 485 float BrowserPlugin::GetDeviceScaleFactor() const { 486 if (!render_view_.get()) 487 return 1.0f; 488 return render_view_->GetWebView()->deviceScaleFactor(); 489 } 490 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 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 513 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 520 blink::WebPluginContainer* BrowserPlugin::container() const { 521 return container_; 522 } 523 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 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 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 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 591 NPP BrowserPlugin::pluginNPP() { 592 return npp_.get(); 593 } 594 595 bool BrowserPlugin::supportsKeyboardFocus() const { 596 return true; 597 } 598 599 bool BrowserPlugin::supportsEditCommands() const { 600 return true; 601 } 602 603 bool BrowserPlugin::supportsInputMethod() const { 604 return true; 605 } 606 607 bool BrowserPlugin::canProcessDrag() const { 608 return true; 609 } 610 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 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 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 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 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 727 void BrowserPlugin::updateFocus(bool focused) { 728 plugin_focused_ = focused; 729 UpdateGuestFocusState(); 730 } 731 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 749 bool BrowserPlugin::acceptsInputEvents() { 750 return true; 751 } 752 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 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 841 void BrowserPlugin::didReceiveResponse( 842 const blink::WebURLResponse& response) { 843 } 844 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 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 859 void BrowserPlugin::didFailLoading(const blink::WebURLError& error) { 860 } 861 862 void BrowserPlugin::didFinishLoadingFrameRequest(const blink::WebURL& url, 863 void* notify_data) { 864 } 865 866 void BrowserPlugin::didFailLoadingFrameRequest( 867 const blink::WebURL& url, 868 void* notify_data, 869 const blink::WebURLError& error) { 870 } 871 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 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 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 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 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 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 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 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