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