1 // Copyright (c) 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 // A BrowserPluginGuest is the browser side of a browser <--> embedder 6 // renderer channel. A BrowserPlugin (a WebPlugin) is on the embedder 7 // renderer side of browser <--> embedder renderer communication. 8 // 9 // BrowserPluginGuest lives on the UI thread of the browser process. It has a 10 // helper, BrowserPluginGuestHelper, which is a RenderViewHostObserver. The 11 // helper object intercepts messages (ViewHostMsg_*) directed at the browser 12 // process and redirects them to this class. Any messages about the guest render 13 // process that the embedder might be interested in receiving should be listened 14 // for here. 15 // 16 // BrowserPluginGuest is a WebContentsDelegate and WebContentsObserver for the 17 // guest WebContents. BrowserPluginGuest operates under the assumption that the 18 // guest will be accessible through only one RenderViewHost for the lifetime of 19 // the guest WebContents. Thus, cross-process navigation is not supported. 20 21 #ifndef CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_GUEST_H_ 22 #define CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_GUEST_H_ 23 24 #include <map> 25 #include <queue> 26 27 #include "base/compiler_specific.h" 28 #include "base/id_map.h" 29 #include "base/memory/shared_memory.h" 30 #include "base/memory/weak_ptr.h" 31 #include "base/values.h" 32 #include "content/common/edit_command.h" 33 #include "content/port/common/input_event_ack_state.h" 34 #include "content/public/browser/browser_plugin_guest_delegate.h" 35 #include "content/public/browser/javascript_dialog_manager.h" 36 #include "content/public/browser/notification_observer.h" 37 #include "content/public/browser/notification_registrar.h" 38 #include "content/public/browser/render_view_host_observer.h" 39 #include "content/public/browser/web_contents_delegate.h" 40 #include "content/public/browser/web_contents_observer.h" 41 #include "content/public/common/browser_plugin_permission_type.h" 42 #include "third_party/WebKit/public/web/WebDragOperation.h" 43 #include "third_party/WebKit/public/web/WebDragStatus.h" 44 #include "third_party/WebKit/public/web/WebInputEvent.h" 45 #include "ui/gfx/rect.h" 46 #include "ui/surface/transport_dib.h" 47 48 struct BrowserPluginHostMsg_AutoSize_Params; 49 struct BrowserPluginHostMsg_Attach_Params; 50 struct BrowserPluginHostMsg_ResizeGuest_Params; 51 struct ViewHostMsg_CreateWindow_Params; 52 #if defined(OS_MACOSX) 53 struct ViewHostMsg_ShowPopup_Params; 54 #endif 55 struct ViewHostMsg_UpdateRect_Params; 56 class WebCursor; 57 58 namespace cc { 59 class CompositorFrameAck; 60 } 61 62 namespace WebKit { 63 class WebInputEvent; 64 } 65 66 namespace content { 67 68 class BrowserPluginHostFactory; 69 class BrowserPluginEmbedder; 70 class BrowserPluginGuestManager; 71 class RenderProcessHost; 72 class RenderWidgetHostView; 73 struct DropData; 74 struct MediaStreamRequest; 75 76 // A browser plugin guest provides functionality for WebContents to operate in 77 // the guest role and implements guest-specific overrides for ViewHostMsg_* 78 // messages. 79 // 80 // When a guest is initially created, it is in an unattached state. That is, 81 // it is not visible anywhere and has no embedder WebContents assigned. 82 // A BrowserPluginGuest is said to be "attached" if it has an embedder. 83 // A BrowserPluginGuest can also create a new unattached guest via 84 // CreateNewWindow. The newly created guest will live in the same partition, 85 // which means it can share storage and can script this guest. 86 class CONTENT_EXPORT BrowserPluginGuest 87 : public JavaScriptDialogManager, 88 public NotificationObserver, 89 public WebContentsDelegate, 90 public WebContentsObserver, 91 public base::SupportsWeakPtr<BrowserPluginGuest> { 92 public: 93 typedef base::Callback<void(bool)> GeolocationCallback; 94 virtual ~BrowserPluginGuest(); 95 96 static BrowserPluginGuest* Create( 97 int instance_id, 98 WebContentsImpl* web_contents, 99 scoped_ptr<base::DictionaryValue> extra_params); 100 101 static BrowserPluginGuest* CreateWithOpener( 102 int instance_id, 103 WebContentsImpl* web_contents, 104 BrowserPluginGuest* opener, 105 bool has_render_view); 106 107 // Destroys the guest WebContents and all its associated state, including 108 // this BrowserPluginGuest, and its new unattached windows. 109 void Destroy(); 110 111 // Returns the identifier that uniquely identifies a browser plugin guest 112 // within an embedder. 113 int instance_id() const { return instance_id_; } 114 115 // Overrides factory for testing. Default (NULL) value indicates regular 116 // (non-test) environment. 117 static void set_factory_for_testing(BrowserPluginHostFactory* factory) { 118 BrowserPluginGuest::factory_ = factory; 119 } 120 121 bool OnMessageReceivedFromEmbedder(const IPC::Message& message); 122 123 void Initialize(WebContentsImpl* embedder_web_contents, 124 const BrowserPluginHostMsg_Attach_Params& params); 125 126 void set_guest_hang_timeout_for_testing(const base::TimeDelta& timeout) { 127 guest_hang_timeout_ = timeout; 128 } 129 130 WebContentsImpl* embedder_web_contents() const { 131 return embedder_web_contents_; 132 } 133 134 RenderWidgetHostView* GetEmbedderRenderWidgetHostView(); 135 136 bool focused() const { return focused_; } 137 bool visible() const { return guest_visible_; } 138 void clear_damage_buffer() { damage_buffer_.reset(); } 139 bool is_in_destruction() { return is_in_destruction_; } 140 141 BrowserPluginGuest* opener() const { return opener_.get(); } 142 143 // Returns whether the mouse pointer was unlocked. 144 bool UnlockMouseIfNecessary(const NativeWebKeyboardEvent& event); 145 146 void UpdateVisibility(); 147 148 // NotificationObserver implementation. 149 virtual void Observe(int type, 150 const NotificationSource& source, 151 const NotificationDetails& details) OVERRIDE; 152 153 // WebContentsObserver implementation. 154 virtual void DidCommitProvisionalLoadForFrame( 155 int64 frame_id, 156 bool is_main_frame, 157 const GURL& url, 158 PageTransition transition_type, 159 RenderViewHost* render_view_host) OVERRIDE; 160 virtual void DidStopLoading(RenderViewHost* render_view_host) OVERRIDE; 161 162 virtual void RenderViewReady() OVERRIDE; 163 virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE; 164 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 165 166 // WebContentsDelegate implementation. 167 virtual bool AddMessageToConsole(WebContents* source, 168 int32 level, 169 const string16& message, 170 int32 line_no, 171 const string16& source_id) OVERRIDE; 172 // If a new window is created with target="_blank" and rel="noreferrer", then 173 // this method is called, indicating that the new WebContents is ready to be 174 // attached. 175 virtual void AddNewContents(WebContents* source, 176 WebContents* new_contents, 177 WindowOpenDisposition disposition, 178 const gfx::Rect& initial_pos, 179 bool user_gesture, 180 bool* was_blocked) OVERRIDE; 181 virtual void CanDownload(RenderViewHost* render_view_host, 182 int request_id, 183 const std::string& request_method, 184 const base::Callback<void(bool)>& callback) OVERRIDE; 185 virtual void CloseContents(WebContents* source) OVERRIDE; 186 virtual JavaScriptDialogManager* GetJavaScriptDialogManager() OVERRIDE; 187 virtual bool HandleContextMenu(const ContextMenuParams& params) OVERRIDE; 188 virtual void HandleKeyboardEvent( 189 WebContents* source, 190 const NativeWebKeyboardEvent& event) OVERRIDE; 191 virtual WebContents* OpenURLFromTab(WebContents* source, 192 const OpenURLParams& params) OVERRIDE; 193 virtual void WebContentsCreated(WebContents* source_contents, 194 int64 source_frame_id, 195 const string16& frame_name, 196 const GURL& target_url, 197 WebContents* new_contents) OVERRIDE; 198 virtual void RendererUnresponsive(WebContents* source) OVERRIDE; 199 virtual void RendererResponsive(WebContents* source) OVERRIDE; 200 virtual void RunFileChooser(WebContents* web_contents, 201 const FileChooserParams& params) OVERRIDE; 202 virtual bool ShouldFocusPageAfterCrash() OVERRIDE; 203 virtual void RequestMediaAccessPermission( 204 WebContents* web_contents, 205 const MediaStreamRequest& request, 206 const MediaResponseCallback& callback) OVERRIDE; 207 208 // JavaScriptDialogManager implementation. 209 virtual void RunJavaScriptDialog( 210 WebContents* web_contents, 211 const GURL& origin_url, 212 const std::string& accept_lang, 213 JavaScriptMessageType javascript_message_type, 214 const string16& message_text, 215 const string16& default_prompt_text, 216 const DialogClosedCallback& callback, 217 bool* did_suppress_message) OVERRIDE; 218 virtual void RunBeforeUnloadDialog( 219 WebContents* web_contents, 220 const string16& message_text, 221 bool is_reload, 222 const DialogClosedCallback& callback) OVERRIDE; 223 virtual bool HandleJavaScriptDialog(WebContents* web_contents, 224 bool accept, 225 const string16* prompt_override) OVERRIDE; 226 virtual void CancelActiveAndPendingDialogs( 227 WebContents* web_contents) OVERRIDE; 228 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE; 229 230 // Exposes the protected web_contents() from WebContentsObserver. 231 WebContentsImpl* GetWebContents(); 232 233 // Overridden in tests. 234 virtual void SetDamageBuffer( 235 const BrowserPluginHostMsg_ResizeGuest_Params& params); 236 237 gfx::Point GetScreenCoordinates(const gfx::Point& relative_position) const; 238 239 // Helper to send messages to embedder. This methods fills the message with 240 // the correct routing id. 241 // Overridden in test implementation since we want to intercept certain 242 // messages for testing. 243 virtual void SendMessageToEmbedder(IPC::Message* msg); 244 245 // Returns whether the guest is attached to an embedder. 246 bool attached() const { return !!embedder_web_contents_; } 247 248 // Attaches this BrowserPluginGuest to the provided |embedder_web_contents| 249 // and initializes the guest with the provided |params|. Attaching a guest 250 // to an embedder implies that this guest's lifetime is no longer managed 251 // by its opener, and it can begin loading resources. 252 void Attach(WebContentsImpl* embedder_web_contents, 253 BrowserPluginHostMsg_Attach_Params params); 254 255 // Requests geolocation permission through Embedder JavaScript API. 256 void AskEmbedderForGeolocationPermission(int bridge_id, 257 const GURL& requesting_frame, 258 const GeolocationCallback& callback); 259 // Cancels pending geolocation request. 260 void CancelGeolocationRequest(int bridge_id); 261 262 // Allow the embedder to call this for unhandled messages when 263 // BrowserPluginGuest is already destroyed. 264 static void AcknowledgeBufferPresent(int route_id, 265 int gpu_host_id, 266 const std::string& mailbox_name, 267 uint32 sync_point); 268 269 // Returns whether BrowserPluginGuest is interested in receiving the given 270 // |message|. 271 static bool ShouldForwardToBrowserPluginGuest(const IPC::Message& message); 272 gfx::Rect ToGuestRect(const gfx::Rect& rect); 273 274 void DragSourceEndedAt(int client_x, int client_y, int screen_x, 275 int screen_y, WebKit::WebDragOperation operation); 276 277 void DragSourceMovedTo(int client_x, int client_y, 278 int screen_x, int screen_y); 279 280 // Called when the drag started by this guest ends at an OS-level. 281 void EndSystemDrag(); 282 283 // |this| takes ownership of |delegate|. 284 void SetDelegate(BrowserPluginGuestDelegate* delegate); 285 286 void RespondToPermissionRequest(int request_id, 287 bool should_allow, 288 const std::string& user_input); 289 290 private: 291 class EmbedderRenderViewHostObserver; 292 friend class TestBrowserPluginGuest; 293 294 class DownloadRequest; 295 class GeolocationRequest; 296 class JavaScriptDialogRequest; 297 // MediaRequest because of naming conflicts with MediaStreamRequest. 298 class MediaRequest; 299 class NewWindowRequest; 300 class PermissionRequest; 301 class PointerLockRequest; 302 303 BrowserPluginGuest(int instance_id, 304 WebContentsImpl* web_contents, 305 BrowserPluginGuest* opener, 306 bool has_render_view); 307 308 // Destroy unattached new windows that have been opened by this 309 // BrowserPluginGuest. 310 void DestroyUnattachedWindows(); 311 312 // Bridge IDs correspond to a geolocation request. This method will remove 313 // the bookkeeping for a particular geolocation request associated with the 314 // provided |bridge_id|. It returns the request ID of the geolocation request. 315 int RemoveBridgeID(int bridge_id); 316 317 // Returns the |request_id| generated for the |request| provided. 318 int RequestPermission( 319 BrowserPluginPermissionType permission_type, 320 scoped_refptr<BrowserPluginGuest::PermissionRequest> request, 321 const base::DictionaryValue& request_info); 322 323 base::SharedMemory* damage_buffer() const { return damage_buffer_.get(); } 324 const gfx::Size& damage_view_size() const { return damage_view_size_; } 325 float damage_buffer_scale_factor() const { 326 return damage_buffer_scale_factor_; 327 } 328 // Returns the damage buffer corresponding to the handle in resize |params|. 329 base::SharedMemory* GetDamageBufferFromEmbedder( 330 const BrowserPluginHostMsg_ResizeGuest_Params& params); 331 332 bool InAutoSizeBounds(const gfx::Size& size) const; 333 334 void RequestNewWindowPermission(WebContentsImpl* new_contents, 335 WindowOpenDisposition disposition, 336 const gfx::Rect& initial_bounds, 337 bool user_gesture); 338 339 // Message handlers for messages from embedder. 340 341 void OnCompositorFrameACK(int instance_id, 342 int route_id, 343 uint32 output_surface_id, 344 int renderer_host_id, 345 const cc::CompositorFrameAck& ack); 346 347 // Handles drag events from the embedder. 348 // When dragging, the drag events go to the embedder first, and if the drag 349 // happens on the browser plugin, then the plugin sends a corresponding 350 // drag-message to the guest. This routes the drag-message to the guest 351 // renderer. 352 void OnDragStatusUpdate(int instance_id, 353 WebKit::WebDragStatus drag_status, 354 const DropData& drop_data, 355 WebKit::WebDragOperationsMask drag_mask, 356 const gfx::Point& location); 357 // Instructs the guest to execute an edit command decoded in the embedder. 358 void OnExecuteEditCommand(int instance_id, 359 const std::string& command); 360 // Overriden in tests. 361 virtual void OnHandleInputEvent(int instance_id, 362 const gfx::Rect& guest_window_rect, 363 const WebKit::WebInputEvent* event); 364 void OnLockMouse(bool user_gesture, 365 bool last_unlocked_by_target, 366 bool privileged); 367 void OnLockMouseAck(int instance_id, bool succeeded); 368 void OnNavigateGuest(int instance_id, const std::string& src); 369 void OnPluginDestroyed(int instance_id); 370 // Grab the new damage buffer from the embedder, and resize the guest's 371 // web contents. 372 void OnResizeGuest(int instance_id, 373 const BrowserPluginHostMsg_ResizeGuest_Params& params); 374 // Overriden in tests. 375 virtual void OnSetFocus(int instance_id, bool focused); 376 // Sets the name of the guest so that other guests in the same partition can 377 // access it. 378 void OnSetName(int instance_id, const std::string& name); 379 // Updates the size state of the guest. 380 void OnSetSize( 381 int instance_id, 382 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params, 383 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params); 384 void OnSetEditCommandsForNextKeyEvent( 385 int instance_id, 386 const std::vector<EditCommand>& edit_commands); 387 // The guest WebContents is visible if both its embedder is visible and 388 // the browser plugin element is visible. If either one is not then the 389 // WebContents is marked as hidden. A hidden WebContents will consume 390 // fewer GPU and CPU resources. 391 // 392 // When every WebContents in a RenderProcessHost is hidden, it will lower 393 // the priority of the process (see RenderProcessHostImpl::WidgetHidden). 394 // 395 // It will also send a message to the guest renderer process to cleanup 396 // resources such as dropping back buffers and adjusting memory limits (if in 397 // compositing mode, see CCLayerTreeHost::setVisible). 398 // 399 // Additionally, it will slow down Javascript execution and garbage 400 // collection. See RenderThreadImpl::IdleHandler (executed when hidden) and 401 // RenderThreadImpl::IdleHandlerInForegroundTab (executed when visible). 402 void OnSetVisibility(int instance_id, bool visible); 403 // Message from embedder acknowledging last HW buffer. 404 void OnSwapBuffersACK(int instance_id, 405 int route_id, 406 int gpu_host_id, 407 const std::string& mailbox_name, 408 uint32 sync_point); 409 void OnUnlockMouse(); 410 void OnUnlockMouseAck(int instance_id); 411 void OnUpdateGeometry(int instance_id, const gfx::Rect& view_rect); 412 void OnUpdateRectACK( 413 int instance_id, 414 bool needs_ack, 415 const BrowserPluginHostMsg_AutoSize_Params& auto_size_params, 416 const BrowserPluginHostMsg_ResizeGuest_Params& resize_guest_params); 417 418 419 // Message handlers for messages from guest. 420 421 void OnDragStopped(); 422 void OnHandleInputEventAck( 423 WebKit::WebInputEvent::Type event_type, 424 InputEventAckState ack_result); 425 void OnHasTouchEventHandlers(bool accept); 426 void OnSetCursor(const WebCursor& cursor); 427 // On MacOSX popups are painted by the browser process. We handle them here 428 // so that they are positioned correctly. 429 #if defined(OS_MACOSX) 430 void OnShowPopup(const ViewHostMsg_ShowPopup_Params& params); 431 #endif 432 void OnShowWidget(int route_id, const gfx::Rect& initial_pos); 433 // Overriden in tests. 434 virtual void OnTakeFocus(bool reverse); 435 void OnUpdateFrameName(int frame_id, 436 bool is_top_level, 437 const std::string& name); 438 void OnUpdateRect(const ViewHostMsg_UpdateRect_Params& params); 439 440 // Requests download permission through embedder JavaScript API after 441 // retrieving url information from IO thread. 442 void DidRetrieveDownloadURLFromRequestId( 443 const std::string& request_method, 444 const base::Callback<void(bool)>& callback, 445 const std::string& url); 446 447 // Embedder sets permission to allow or deny geolocation request. 448 void SetGeolocationPermission( 449 GeolocationCallback callback, int bridge_id, bool allowed); 450 451 // Forwards all messages from the |pending_messages_| queue to the embedder. 452 void SendQueuedMessages(); 453 454 // Weak pointer used to ask GeolocationPermissionContext about geolocation 455 // permission. 456 base::WeakPtrFactory<BrowserPluginGuest> weak_ptr_factory_; 457 458 // Static factory instance (always NULL for non-test). 459 static BrowserPluginHostFactory* factory_; 460 461 NotificationRegistrar notification_registrar_; 462 scoped_ptr<EmbedderRenderViewHostObserver> embedder_rvh_observer_; 463 WebContentsImpl* embedder_web_contents_; 464 465 std::map<int, int> bridge_id_to_request_id_map_; 466 467 // An identifier that uniquely identifies a browser plugin guest within an 468 // embedder. 469 int instance_id_; 470 scoped_ptr<base::SharedMemory> damage_buffer_; 471 // An identifier that uniquely identifies a damage buffer. 472 uint32 damage_buffer_sequence_id_; 473 size_t damage_buffer_size_; 474 gfx::Size damage_view_size_; 475 float damage_buffer_scale_factor_; 476 float guest_device_scale_factor_; 477 gfx::Rect guest_window_rect_; 478 gfx::Rect guest_screen_rect_; 479 base::TimeDelta guest_hang_timeout_; 480 bool focused_; 481 bool mouse_locked_; 482 bool pending_lock_request_; 483 bool guest_visible_; 484 bool embedder_visible_; 485 std::string name_; 486 bool auto_size_enabled_; 487 gfx::Size max_auto_size_; 488 gfx::Size min_auto_size_; 489 490 // Tracks the name, and target URL of the new window and whether or not it has 491 // changed since the WebContents has been created and before the new window 492 // has been attached to a BrowserPlugin. Once the first navigation commits, we 493 // no longer track this information. 494 struct NewWindowInfo { 495 bool changed; 496 GURL url; 497 std::string name; 498 NewWindowInfo(const GURL& url, const std::string& name) : 499 changed(false), 500 url(url), 501 name(name) {} 502 }; 503 typedef std::map<BrowserPluginGuest*, NewWindowInfo> PendingWindowMap; 504 PendingWindowMap pending_new_windows_; 505 base::WeakPtr<BrowserPluginGuest> opener_; 506 // A counter to generate a unique request id for a permission request. 507 // We only need the ids to be unique for a given BrowserPluginGuest. 508 int next_permission_request_id_; 509 510 // A map to store relevant info for a request keyed by the request's id. 511 typedef std::map<int, scoped_refptr<PermissionRequest> > RequestMap; 512 RequestMap permission_request_map_; 513 514 // Indicates that this BrowserPluginGuest has associated renderer-side state. 515 // This is used to determine whether or not to create a new RenderView when 516 // this guest is attached. 517 bool has_render_view_; 518 519 bool is_in_destruction_; 520 521 // This is a queue of messages that are destined to be sent to the embedder 522 // once the guest is attached to a particular embedder. 523 std::queue<IPC::Message*> pending_messages_; 524 525 scoped_ptr<BrowserPluginGuestDelegate> delegate_; 526 527 DISALLOW_COPY_AND_ASSIGN(BrowserPluginGuest); 528 }; 529 530 } // namespace content 531 532 #endif // CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_GUEST_H_ 533