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