Home | History | Annotate | Download | only in web_contents
      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 #ifndef CONTENT_BROWSER_WEB_CONTENTS_RENDER_VIEW_HOST_MANAGER_H_
      6 #define CONTENT_BROWSER_WEB_CONTENTS_RENDER_VIEW_HOST_MANAGER_H_
      7 
      8 #include "base/basictypes.h"
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/memory/weak_ptr.h"
     12 #include "content/browser/renderer_host/render_view_host_delegate.h"
     13 #include "content/browser/site_instance_impl.h"
     14 #include "content/common/content_export.h"
     15 #include "content/public/browser/notification_observer.h"
     16 #include "content/public/browser/notification_registrar.h"
     17 
     18 
     19 namespace content {
     20 class BrowserContext;
     21 class InterstitialPageImpl;
     22 class NavigationControllerImpl;
     23 class NavigationEntry;
     24 class NavigationEntryImpl;
     25 class RenderViewHost;
     26 class RenderViewHostImpl;
     27 class RenderViewHostManagerTest;
     28 class RenderWidgetHostDelegate;
     29 class RenderWidgetHostView;
     30 class TestWebContents;
     31 class WebUIImpl;
     32 
     33 // Manages RenderViewHosts for a WebContentsImpl. Normally there is only one and
     34 // it is easy to do. But we can also have transitions of processes (and hence
     35 // RenderViewHosts) that can get complex.
     36 class CONTENT_EXPORT RenderViewHostManager
     37     : public RenderViewHostDelegate::RendererManagement,
     38       public NotificationObserver {
     39  public:
     40   // Functions implemented by our owner that we need.
     41   //
     42   // TODO(brettw) Clean this up! These are all the functions in WebContentsImpl
     43   // that are required to run this class. The design should probably be better
     44   // such that these are more clear.
     45   //
     46   // There is additional complexity that some of the functions we need in
     47   // WebContentsImpl are inherited and non-virtual. These are named with
     48   // "RenderManager" so that the duplicate implementation of them will be clear.
     49   class CONTENT_EXPORT Delegate {
     50    public:
     51     // Initializes the given renderer if necessary and creates the view ID
     52     // corresponding to this view host. If this method is not called and the
     53     // process is not shared, then the WebContentsImpl will act as though the
     54     // renderer is not running (i.e., it will render "sad tab"). This method is
     55     // automatically called from LoadURL.
     56     //
     57     // If you are attaching to an already-existing RenderView, you should call
     58     // InitWithExistingID.
     59     virtual bool CreateRenderViewForRenderManager(
     60         RenderViewHost* render_view_host, int opener_route_id) = 0;
     61     virtual void BeforeUnloadFiredFromRenderManager(
     62         bool proceed, const base::TimeTicks& proceed_time,
     63         bool* proceed_to_fire_unload) = 0;
     64     virtual void RenderProcessGoneFromRenderManager(
     65         RenderViewHost* render_view_host) = 0;
     66     virtual void UpdateRenderViewSizeForRenderManager() = 0;
     67     virtual void NotifySwappedFromRenderManager(
     68         RenderViewHost* old_render_view_host) = 0;
     69     virtual NavigationControllerImpl&
     70         GetControllerForRenderManager() = 0;
     71 
     72     // Create swapped out RenderViews in the given SiteInstance for each tab in
     73     // the opener chain of this tab, if any.  This allows the current tab to
     74     // make cross-process script calls to its opener(s).  Returns the route ID
     75     // of the immediate opener, if one exists (otherwise MSG_ROUTING_NONE).
     76     virtual int CreateOpenerRenderViewsForRenderManager(
     77         SiteInstance* instance) = 0;
     78 
     79     // Creates a WebUI object for the given URL if one applies. Ownership of the
     80     // returned pointer will be passed to the caller. If no WebUI applies,
     81     // returns NULL.
     82     virtual WebUIImpl* CreateWebUIForRenderManager(const GURL& url) = 0;
     83 
     84     // Returns the navigation entry of the current navigation, or NULL if there
     85     // is none.
     86     virtual NavigationEntry*
     87         GetLastCommittedNavigationEntryForRenderManager() = 0;
     88 
     89     // Returns true if the location bar should be focused by default rather than
     90     // the page contents. The view calls this function when the tab is focused
     91     // to see what it should do.
     92     virtual bool FocusLocationBarByDefault() = 0;
     93 
     94     // Focuses the location bar.
     95     virtual void SetFocusToLocationBar(bool select_all) = 0;
     96 
     97     // Creates a view and sets the size for the specified RVH.
     98     virtual void CreateViewAndSetSizeForRVH(RenderViewHost* rvh) = 0;
     99 
    100    protected:
    101     virtual ~Delegate() {}
    102   };
    103 
    104   // All three delegate pointers must be non-NULL and are not owned by this
    105   // class.  They must outlive this class. The RenderViewHostDelegate and
    106   // RenderWidgetHostDelegate are what will be installed into all
    107   // RenderViewHosts that are created.
    108   //
    109   // You must call Init() before using this class.
    110   RenderViewHostManager(
    111       RenderViewHostDelegate* render_view_delegate,
    112       RenderWidgetHostDelegate* render_widget_delegate,
    113       Delegate* delegate);
    114   virtual ~RenderViewHostManager();
    115 
    116   // For arguments, see WebContentsImpl constructor.
    117   void Init(BrowserContext* browser_context,
    118             SiteInstance* site_instance,
    119             int routing_id,
    120             int main_frame_routing_id);
    121 
    122   // Returns the currently active RenderViewHost.
    123   //
    124   // This will be non-NULL between Init() and Shutdown(). You may want to NULL
    125   // check it in many cases, however. Windows can send us messages during the
    126   // destruction process after it has been shut down.
    127   RenderViewHostImpl* current_host() const;
    128 
    129   // Returns the view associated with the current RenderViewHost, or NULL if
    130   // there is no current one.
    131   RenderWidgetHostView* GetRenderWidgetHostView() const;
    132 
    133   // Returns the pending render view host, or NULL if there is no pending one.
    134   RenderViewHostImpl* pending_render_view_host() const;
    135 
    136   // Returns the current committed Web UI or NULL if none applies.
    137   WebUIImpl* web_ui() const { return web_ui_.get(); }
    138 
    139   // Returns the Web UI for the pending navigation, or NULL of none applies.
    140   WebUIImpl* pending_web_ui() const {
    141     return pending_web_ui_.get() ? pending_web_ui_.get() :
    142                                    pending_and_current_web_ui_.get();
    143   }
    144 
    145   // Sets the pending Web UI for the pending navigation, ensuring that the
    146   // bindings are appropriate for the given NavigationEntry.
    147   void SetPendingWebUI(const NavigationEntryImpl& entry);
    148 
    149   // Called when we want to instruct the renderer to navigate to the given
    150   // navigation entry. It may create a new RenderViewHost or re-use an existing
    151   // one. The RenderViewHost to navigate will be returned. Returns NULL if one
    152   // could not be created.
    153   RenderViewHostImpl* Navigate(const NavigationEntryImpl& entry);
    154 
    155   // Instructs the various live views to stop. Called when the user directed the
    156   // page to stop loading.
    157   void Stop();
    158 
    159   // Notifies the regular and pending RenderViewHosts that a load is or is not
    160   // happening. Even though the message is only for one of them, we don't know
    161   // which one so we tell both.
    162   void SetIsLoading(bool is_loading);
    163 
    164   // Whether to close the tab or not when there is a hang during an unload
    165   // handler. If we are mid-crosssite navigation, then we should proceed
    166   // with the navigation instead of closing the tab.
    167   bool ShouldCloseTabOnUnresponsiveRenderer();
    168 
    169   // The RenderViewHost has been swapped out, so we should resume the pending
    170   // network response and allow the pending RenderViewHost to commit.
    171   void SwappedOut(RenderViewHost* render_view_host);
    172 
    173   // Called when a renderer's main frame navigates.
    174   void DidNavigateMainFrame(RenderViewHost* render_view_host);
    175 
    176   // Called when a renderer sets its opener to null.
    177   void DidDisownOpener(RenderViewHost* render_view_host);
    178 
    179   // Helper method to create a RenderViewHost.  If |swapped_out| is true, it
    180   // will be initially placed on the swapped out hosts list.  Otherwise, it
    181   // will be used for a pending cross-site navigation.
    182   int CreateRenderView(SiteInstance* instance,
    183                        int opener_route_id,
    184                        bool swapped_out);
    185 
    186   // Called when a provisional load on the given renderer is aborted.
    187   void RendererAbortedProvisionalLoad(RenderViewHost* render_view_host);
    188 
    189   // Sets the passed passed interstitial as the currently showing interstitial.
    190   // |interstitial_page| should be non NULL (use the remove_interstitial_page
    191   // method to unset the interstitial) and no interstitial page should be set
    192   // when there is already a non NULL interstitial page set.
    193   void set_interstitial_page(InterstitialPageImpl* interstitial_page) {
    194     DCHECK(!interstitial_page_ && interstitial_page);
    195     interstitial_page_ = interstitial_page;
    196   }
    197 
    198   // Unsets the currently showing interstitial.
    199   void remove_interstitial_page() {
    200     DCHECK(interstitial_page_);
    201     interstitial_page_ = NULL;
    202   }
    203 
    204   // Returns the currently showing interstitial, NULL if no interstitial is
    205   // showing.
    206   InterstitialPageImpl* interstitial_page() const { return interstitial_page_; }
    207 
    208   // RenderViewHostDelegate::RendererManagement implementation.
    209   virtual void ShouldClosePage(
    210       bool for_cross_site_transition,
    211       bool proceed,
    212       const base::TimeTicks& proceed_time) OVERRIDE;
    213   virtual void OnCrossSiteResponse(
    214       RenderViewHost* pending_render_view_host,
    215       const GlobalRequestID& global_request_id) OVERRIDE;
    216 
    217   // NotificationObserver implementation.
    218   virtual void Observe(int type,
    219                        const NotificationSource& source,
    220                        const NotificationDetails& details) OVERRIDE;
    221 
    222   // Called when a RenderViewHost is about to be deleted.
    223   void RenderViewDeleted(RenderViewHost* rvh);
    224 
    225   // Returns whether the given RenderViewHost is on the list of swapped out
    226   // RenderViewHosts.
    227   bool IsOnSwappedOutList(RenderViewHost* rvh) const;
    228 
    229   // Returns the swapped out RenderViewHost for the given SiteInstance, if any.
    230   RenderViewHostImpl* GetSwappedOutRenderViewHost(SiteInstance* instance);
    231 
    232   // Runs the unload handler in the current page, when we know that a pending
    233   // cross-process navigation is going to commit.
    234   void SwapOutOldPage();
    235 
    236  private:
    237   friend class RenderViewHostManagerTest;
    238   friend class TestWebContents;
    239 
    240   // Tracks information about a navigation while a cross-process transition is
    241   // in progress.
    242   // TODO(creis): Add transfer navigation params for http://crbug.com/238331.
    243   struct PendingNavigationParams {
    244     PendingNavigationParams();
    245     explicit PendingNavigationParams(const GlobalRequestID& global_request_id);
    246 
    247     GlobalRequestID global_request_id;
    248   };
    249 
    250   // Returns whether this tab should transition to a new renderer for
    251   // cross-site URLs.  Enabled unless we see the --process-per-tab command line
    252   // switch.  Can be overridden in unit tests.
    253   bool ShouldTransitionCrossSite();
    254 
    255   // Returns true if the two navigation entries are incompatible in some way
    256   // other than site instances. Cases where this can happen include Web UI
    257   // to regular web pages. It will cause us to swap RenderViewHosts (and hence
    258   // RenderProcessHosts) even if the site instance would otherwise be the same.
    259   // As part of this, we'll also force new SiteInstances and BrowsingInstances.
    260   // Either of the entries may be NULL.
    261   bool ShouldSwapProcessesForNavigation(
    262       const NavigationEntry* curr_entry,
    263       const NavigationEntryImpl* new_entry) const;
    264 
    265   bool ShouldReuseWebUI(
    266       const NavigationEntry* curr_entry,
    267       const NavigationEntryImpl* new_entry) const;
    268 
    269   // Returns an appropriate SiteInstance object for the given NavigationEntry,
    270   // possibly reusing the current SiteInstance.
    271   // Never called if --process-per-tab is used.
    272   SiteInstance* GetSiteInstanceForEntry(
    273       const NavigationEntryImpl& entry,
    274       SiteInstance* curr_instance);
    275 
    276   // Sets up the necessary state for a new RenderViewHost with the given opener.
    277   bool InitRenderView(RenderViewHost* render_view_host, int opener_route_id);
    278 
    279   // Sets the pending RenderViewHost/WebUI to be the active one. Note that this
    280   // doesn't require the pending render_view_host_ pointer to be non-NULL, since
    281   // there could be Web UI switching as well. Call this for every commit.
    282   void CommitPending();
    283 
    284   // Shutdown all RenderViewHosts in a SiteInstance. This is called
    285   // to shutdown views when all the views in a SiteInstance are
    286   // confirmed to be swapped out.
    287   void ShutdownRenderViewHostsInSiteInstance(int32 site_instance_id);
    288 
    289   // Helper method to terminate the pending RenderViewHost.
    290   void CancelPending();
    291 
    292   RenderViewHostImpl* UpdateRendererStateForNavigate(
    293       const NavigationEntryImpl& entry);
    294 
    295   // Called when a renderer process is starting to close.  We should not
    296   // schedule new navigations in its swapped out RenderViewHosts after this.
    297   void RendererProcessClosing(RenderProcessHost* render_process_host);
    298 
    299   // Our delegate, not owned by us. Guaranteed non-NULL.
    300   Delegate* delegate_;
    301 
    302   // Whether a navigation requiring different RenderView's is pending. This is
    303   // either cross-site request is (in the new process model), or when required
    304   // for the view type (like view source versus not).
    305   bool cross_navigation_pending_;
    306 
    307   // Implemented by the owner of this class, these delegates are installed into
    308   // all the RenderViewHosts that we create.
    309   RenderViewHostDelegate* render_view_delegate_;
    310   RenderWidgetHostDelegate* render_widget_delegate_;
    311 
    312   // Our RenderView host and its associated Web UI (if any, will be NULL for
    313   // non-DOM-UI pages). This object is responsible for all communication with
    314   // a child RenderView instance.
    315   RenderViewHostImpl* render_view_host_;
    316   scoped_ptr<WebUIImpl> web_ui_;
    317 
    318   // A RenderViewHost used to load a cross-site page. This remains hidden
    319   // while a cross-site request is pending until it calls DidNavigate. It may
    320   // have an associated Web UI, in which case the Web UI pointer will be non-
    321   // NULL.
    322   //
    323   // The |pending_web_ui_| may be non-NULL even when the
    324   // |pending_render_view_host_| is NULL. This will happen when we're
    325   // transitioning between two Web UI pages: the RVH won't be swapped, so the
    326   // pending pointer will be unused, but there will be a pending Web UI
    327   // associated with the navigation.
    328   RenderViewHostImpl* pending_render_view_host_;
    329 
    330   // Tracks information about any current pending cross-process navigation.
    331   scoped_ptr<PendingNavigationParams> pending_nav_params_;
    332 
    333   // If either of these is non-NULL, the pending navigation is to a chrome:
    334   // page. The scoped_ptr is used if pending_web_ui_ != web_ui_, the WeakPtr is
    335   // used for when they reference the same object. If either is non-NULL, the
    336   // other should be NULL.
    337   scoped_ptr<WebUIImpl> pending_web_ui_;
    338   base::WeakPtr<WebUIImpl> pending_and_current_web_ui_;
    339 
    340   // A map of site instance ID to swapped out RenderViewHosts.  This may include
    341   // pending_render_view_host_ for navigations to existing entries.
    342   typedef base::hash_map<int32, RenderViewHostImpl*> RenderViewHostMap;
    343   RenderViewHostMap swapped_out_hosts_;
    344 
    345   // The intersitial page currently shown if any, not own by this class
    346   // (the InterstitialPage is self-owned, it deletes itself when hidden).
    347   InterstitialPageImpl* interstitial_page_;
    348 
    349   NotificationRegistrar registrar_;
    350 
    351   DISALLOW_COPY_AND_ASSIGN(RenderViewHostManager);
    352 };
    353 
    354 }  // namespace content
    355 
    356 #endif  // CONTENT_BROWSER_WEB_CONTENTS_RENDER_VIEW_HOST_MANAGER_H_
    357