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