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
48struct BrowserPluginHostMsg_AutoSize_Params;
49struct BrowserPluginHostMsg_Attach_Params;
50struct BrowserPluginHostMsg_ResizeGuest_Params;
51struct ViewHostMsg_CreateWindow_Params;
52#if defined(OS_MACOSX)
53struct ViewHostMsg_ShowPopup_Params;
54#endif
55struct ViewHostMsg_UpdateRect_Params;
56class WebCursor;
57
58namespace cc {
59class CompositorFrameAck;
60}
61
62namespace WebKit {
63class WebInputEvent;
64}
65
66namespace content {
67
68class BrowserPluginHostFactory;
69class BrowserPluginEmbedder;
70class BrowserPluginGuestManager;
71class RenderProcessHost;
72class RenderWidgetHostView;
73struct DropData;
74struct 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.
86class 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