OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/web_contents/render_view_host_manager.h" | 5 #include "content/browser/web_contents/render_view_host_manager.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 | 199 |
200 void RenderViewHostManager::DidNavigateMainFrame( | 200 void RenderViewHostManager::DidNavigateMainFrame( |
201 RenderViewHost* render_view_host) { | 201 RenderViewHost* render_view_host) { |
202 if (!cross_navigation_pending_) { | 202 if (!cross_navigation_pending_) { |
203 DCHECK(!pending_render_view_host_); | 203 DCHECK(!pending_render_view_host_); |
204 | 204 |
205 // We should only hear this from our current renderer. | 205 // We should only hear this from our current renderer. |
206 DCHECK(render_view_host == render_view_host_); | 206 DCHECK(render_view_host == render_view_host_); |
207 | 207 |
208 // Even when there is no pending RVH, there may be a pending Web UI. | 208 // Even when there is no pending RVH, there may be a pending Web UI. |
209 if (pending_web_ui_.get()) | 209 if (pending_web_ui()) |
210 CommitPending(); | 210 CommitPending(); |
211 return; | 211 return; |
212 } | 212 } |
213 | 213 |
214 if (render_view_host == pending_render_view_host_) { | 214 if (render_view_host == pending_render_view_host_) { |
215 // The pending cross-site navigation completed, so show the renderer. | 215 // The pending cross-site navigation completed, so show the renderer. |
216 // If it committed without sending network requests (e.g., data URLs), | 216 // If it committed without sending network requests (e.g., data URLs), |
217 // then we still need to swap out the old RVH first and run its unload | 217 // then we still need to swap out the old RVH first and run its unload |
218 // handler. OK for that to happen in the background. | 218 // handler. OK for that to happen in the background. |
219 if (pending_render_view_host_->GetPendingRequestId() == -1) { | 219 if (pending_render_view_host_->GetPendingRequestId() == -1) { |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 } | 351 } |
352 } | 352 } |
353 | 353 |
354 bool RenderViewHostManager::ShouldTransitionCrossSite() { | 354 bool RenderViewHostManager::ShouldTransitionCrossSite() { |
355 // True if we are using process-per-site-instance (default) or | 355 // True if we are using process-per-site-instance (default) or |
356 // process-per-site (kProcessPerSite). | 356 // process-per-site (kProcessPerSite). |
357 return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab); | 357 return !CommandLine::ForCurrentProcess()->HasSwitch(switches::kProcessPerTab); |
358 } | 358 } |
359 | 359 |
360 bool RenderViewHostManager::ShouldSwapProcessesForNavigation( | 360 bool RenderViewHostManager::ShouldSwapProcessesForNavigation( |
361 const NavigationEntry* cur_entry, | 361 const NavigationEntry* curr_entry, |
362 const NavigationEntryImpl* new_entry) const { | 362 const NavigationEntryImpl* new_entry) const { |
363 DCHECK(new_entry); | 363 DCHECK(new_entry); |
364 | 364 |
365 // Check for reasons to swap processes even if we are in a process model that | 365 // Check for reasons to swap processes even if we are in a process model that |
366 // doesn't usually swap (e.g., process-per-tab). | 366 // doesn't usually swap (e.g., process-per-tab). |
367 | 367 |
368 // For security, we should transition between processes when one is a Web UI | 368 // For security, we should transition between processes when one is a Web UI |
369 // page and one isn't. If there's no cur_entry, check the current RVH's | 369 // page and one isn't. If there's no curr_entry, check the current RVH's |
370 // site, which might already be committed to a Web UI URL (such as the NTP). | 370 // site, which might already be committed to a Web UI URL (such as the NTP). |
371 const GURL& current_url = (cur_entry) ? cur_entry->GetURL() : | 371 const GURL& current_url = (curr_entry) ? curr_entry->GetURL() : |
372 render_view_host_->GetSiteInstance()->GetSite(); | 372 render_view_host_->GetSiteInstance()->GetSite(); |
373 content::BrowserContext* browser_context = | 373 content::BrowserContext* browser_context = |
374 delegate_->GetControllerForRenderManager().GetBrowserContext(); | 374 delegate_->GetControllerForRenderManager().GetBrowserContext(); |
375 const WebUIControllerFactory* web_ui_factory = | 375 const WebUIControllerFactory* web_ui_factory = |
376 content::GetContentClient()->browser()->GetWebUIControllerFactory(); | 376 content::GetContentClient()->browser()->GetWebUIControllerFactory(); |
377 if (web_ui_factory) { | 377 if (web_ui_factory) { |
378 if (web_ui_factory->UseWebUIForURL(browser_context, current_url)) { | 378 if (web_ui_factory->UseWebUIForURL(browser_context, current_url)) { |
379 // Force swap if it's not an acceptable URL for Web UI. | 379 // Force swap if it's not an acceptable URL for Web UI. |
380 // Here, data URLs are never allowed. | 380 // Here, data URLs are never allowed. |
381 if (!web_ui_factory->IsURLAcceptableForWebUI(browser_context, | 381 if (!web_ui_factory->IsURLAcceptableForWebUI(browser_context, |
382 new_entry->GetURL(), false)) | 382 new_entry->GetURL(), false)) |
383 return true; | 383 return true; |
384 } else { | 384 } else { |
385 // Force swap if it's a Web UI URL. | 385 // Force swap if it's a Web UI URL. |
386 if (web_ui_factory->UseWebUIForURL(browser_context, new_entry->GetURL())) | 386 if (web_ui_factory->UseWebUIForURL(browser_context, new_entry->GetURL())) |
387 return true; | 387 return true; |
388 } | 388 } |
389 } | 389 } |
390 | 390 |
391 if (content::GetContentClient()->browser()->ShouldSwapProcessesForNavigation( | 391 if (content::GetContentClient()->browser()->ShouldSwapProcessesForNavigation( |
392 cur_entry ? cur_entry->GetURL() : GURL(), new_entry->GetURL())) { | 392 curr_entry ? curr_entry->GetURL() : GURL(), new_entry->GetURL())) { |
393 return true; | 393 return true; |
394 } | 394 } |
395 | 395 |
396 if (!cur_entry) | 396 if (!curr_entry) |
397 return false; | 397 return false; |
398 | 398 |
399 // We can't switch a RenderView between view source and non-view source mode | 399 // We can't switch a RenderView between view source and non-view source mode |
400 // without screwing up the session history sometimes (when navigating between | 400 // without screwing up the session history sometimes (when navigating between |
401 // "view-source:http://foo.com/" and "http://foo.com/", WebKit doesn't treat | 401 // "view-source:http://foo.com/" and "http://foo.com/", WebKit doesn't treat |
402 // it as a new navigation). So require a view switch. | 402 // it as a new navigation). So require a view switch. |
403 if (cur_entry->IsViewSourceMode() != new_entry->IsViewSourceMode()) | 403 if (curr_entry->IsViewSourceMode() != new_entry->IsViewSourceMode()) |
404 return true; | 404 return true; |
405 | 405 |
406 return false; | 406 return false; |
407 } | 407 } |
408 | 408 |
| 409 bool RenderViewHostManager::ShouldReuseWebUI( |
| 410 const NavigationEntry* curr_entry, |
| 411 const NavigationEntryImpl* new_entry) const { |
| 412 NavigationControllerImpl& controller = |
| 413 delegate_->GetControllerForRenderManager(); |
| 414 WebUIControllerFactory* factory = |
| 415 content::GetContentClient()->browser()->GetWebUIControllerFactory(); |
| 416 return curr_entry && web_ui_.get() && |
| 417 (factory->GetWebUIType(controller.GetBrowserContext(), |
| 418 curr_entry->GetURL()) == |
| 419 factory->GetWebUIType(controller.GetBrowserContext(), |
| 420 new_entry->GetURL())); |
| 421 } |
| 422 |
409 SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry( | 423 SiteInstance* RenderViewHostManager::GetSiteInstanceForEntry( |
410 const NavigationEntryImpl& entry, | 424 const NavigationEntryImpl& entry, |
411 SiteInstance* curr_instance) { | 425 SiteInstance* curr_instance) { |
412 // NOTE: This is only called when ShouldTransitionCrossSite is true. | 426 // NOTE: This is only called when ShouldTransitionCrossSite is true. |
413 | 427 |
414 const GURL& dest_url = entry.GetURL(); | 428 const GURL& dest_url = entry.GetURL(); |
415 NavigationControllerImpl& controller = | 429 NavigationControllerImpl& controller = |
416 delegate_->GetControllerForRenderManager(); | 430 delegate_->GetControllerForRenderManager(); |
417 content::BrowserContext* browser_context = controller.GetBrowserContext(); | 431 content::BrowserContext* browser_context = controller.GetBrowserContext(); |
418 | 432 |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
574 } else { | 588 } else { |
575 CancelPending(); | 589 CancelPending(); |
576 } | 590 } |
577 return success; | 591 return success; |
578 } | 592 } |
579 | 593 |
580 bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host, | 594 bool RenderViewHostManager::InitRenderView(RenderViewHost* render_view_host, |
581 const NavigationEntryImpl& entry) { | 595 const NavigationEntryImpl& entry) { |
582 // If the pending navigation is to a WebUI, tell the RenderView about any | 596 // If the pending navigation is to a WebUI, tell the RenderView about any |
583 // bindings it will need enabled. | 597 // bindings it will need enabled. |
584 if (pending_web_ui_.get()) | 598 if (pending_web_ui()) |
585 render_view_host->AllowBindings(pending_web_ui_->GetBindings()); | 599 render_view_host->AllowBindings(pending_web_ui()->GetBindings()); |
586 | 600 |
587 return delegate_->CreateRenderViewForRenderManager(render_view_host); | 601 return delegate_->CreateRenderViewForRenderManager(render_view_host); |
588 } | 602 } |
589 | 603 |
590 void RenderViewHostManager::CommitPending() { | 604 void RenderViewHostManager::CommitPending() { |
591 // First check whether we're going to want to focus the location bar after | 605 // First check whether we're going to want to focus the location bar after |
592 // this commit. We do this now because the navigation hasn't formally | 606 // this commit. We do this now because the navigation hasn't formally |
593 // committed yet, so if we've already cleared |pending_web_ui_| the call chain | 607 // committed yet, so if we've already cleared |pending_web_ui_| the call chain |
594 // this triggers won't be able to figure out what's going on. | 608 // this triggers won't be able to figure out what's going on. |
595 bool will_focus_location_bar = delegate_->FocusLocationBarByDefault(); | 609 bool will_focus_location_bar = delegate_->FocusLocationBarByDefault(); |
596 | 610 |
597 // Next commit the Web UI, if any. | 611 // Next commit the Web UI, if any. Either replace |web_ui_| with |
598 web_ui_.swap(pending_web_ui_); | 612 // |pending_web_ui_|, or clear |web_ui_| if there is no pending WebUI, or |
599 if (web_ui_.get() && pending_web_ui_.get() && !pending_render_view_host_) | 613 // leave |web_ui_| as is if reusing it. |
600 web_ui_->GetController()->DidBecomeActiveForReusedRenderView(); | 614 DCHECK(!(pending_web_ui_.get() && pending_and_current_web_ui_.get())); |
601 pending_web_ui_.reset(); | 615 if (pending_web_ui_.get()) |
| 616 web_ui_.reset(pending_web_ui_.release()); |
| 617 else if (!pending_and_current_web_ui_.get()) |
| 618 web_ui_.reset(); |
602 | 619 |
603 // It's possible for the pending_render_view_host_ to be NULL when we aren't | 620 // It's possible for the pending_render_view_host_ to be NULL when we aren't |
604 // crossing process boundaries. If so, we just needed to handle the Web UI | 621 // crossing process boundaries. If so, we just needed to handle the Web UI |
605 // committing above and we're done. | 622 // committing above and we're done. |
606 if (!pending_render_view_host_) { | 623 if (!pending_render_view_host_) { |
607 if (will_focus_location_bar) | 624 if (will_focus_location_bar) |
608 delegate_->SetFocusToLocationBar(false); | 625 delegate_->SetFocusToLocationBar(false); |
609 return; | 626 return; |
610 } | 627 } |
611 | 628 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate( | 702 RenderViewHostImpl* RenderViewHostManager::UpdateRendererStateForNavigate( |
686 const NavigationEntryImpl& entry) { | 703 const NavigationEntryImpl& entry) { |
687 // If we are cross-navigating, then we want to get back to normal and navigate | 704 // If we are cross-navigating, then we want to get back to normal and navigate |
688 // as usual. | 705 // as usual. |
689 if (cross_navigation_pending_) { | 706 if (cross_navigation_pending_) { |
690 if (pending_render_view_host_) | 707 if (pending_render_view_host_) |
691 CancelPending(); | 708 CancelPending(); |
692 cross_navigation_pending_ = false; | 709 cross_navigation_pending_ = false; |
693 } | 710 } |
694 | 711 |
695 // This will possibly create (set to NULL) a Web UI object for the pending | |
696 // page. We'll use this later to give the page special access. This must | |
697 // happen before the new renderer is created below so it will get bindings. | |
698 // It must also happen after the above conditional call to CancelPending(), | |
699 // otherwise CancelPending may clear the pending_web_ui_ and the page will | |
700 // not have it's bindings set appropriately. | |
701 pending_web_ui_.reset(delegate_->CreateWebUIForRenderManager(entry.GetURL())); | |
702 | |
703 // render_view_host_ will not be deleted before the end of this method, so we | 712 // render_view_host_ will not be deleted before the end of this method, so we |
704 // don't have to worry about this SiteInstance's ref count dropping to zero. | 713 // don't have to worry about this SiteInstance's ref count dropping to zero. |
705 SiteInstance* curr_instance = render_view_host_->GetSiteInstance(); | 714 SiteInstance* curr_instance = render_view_host_->GetSiteInstance(); |
706 | 715 |
707 // Determine if we need a new SiteInstance for this entry. | 716 // Determine if we need a new SiteInstance for this entry. |
708 // Again, new_instance won't be deleted before the end of this method, so it | 717 // Again, new_instance won't be deleted before the end of this method, so it |
709 // is safe to use a normal pointer here. | 718 // is safe to use a normal pointer here. |
710 SiteInstance* new_instance = curr_instance; | 719 SiteInstance* new_instance = curr_instance; |
711 bool force_swap = ShouldSwapProcessesForNavigation( | 720 const content::NavigationEntry* curr_entry = |
712 delegate_->GetLastCommittedNavigationEntryForRenderManager(), &entry); | 721 delegate_->GetLastCommittedNavigationEntryForRenderManager(); |
| 722 bool force_swap = ShouldSwapProcessesForNavigation(curr_entry, &entry); |
713 if (ShouldTransitionCrossSite() || force_swap) | 723 if (ShouldTransitionCrossSite() || force_swap) |
714 new_instance = GetSiteInstanceForEntry(entry, curr_instance); | 724 new_instance = GetSiteInstanceForEntry(entry, curr_instance); |
715 | 725 |
716 if (new_instance != curr_instance || force_swap) { | 726 if (new_instance != curr_instance || force_swap) { |
717 // New SiteInstance. | 727 // New SiteInstance. |
718 DCHECK(!cross_navigation_pending_); | 728 DCHECK(!cross_navigation_pending_); |
719 | 729 |
| 730 // This will possibly create (set to NULL) a Web UI object for the pending |
| 731 // page. We'll use this later to give the page special access. This must |
| 732 // happen before the new renderer is created below so it will get bindings. |
| 733 // It must also happen after the above conditional call to CancelPending(), |
| 734 // otherwise CancelPending may clear the pending_web_ui_ and the page will |
| 735 // not have its bindings set appropriately. |
| 736 pending_web_ui_.reset( |
| 737 delegate_->CreateWebUIForRenderManager(entry.GetURL())); |
| 738 pending_and_current_web_ui_.reset(); |
| 739 |
720 // Create a pending RVH and navigate it. | 740 // Create a pending RVH and navigate it. |
721 bool success = CreatePendingRenderView(entry, new_instance); | 741 bool success = CreatePendingRenderView(entry, new_instance); |
722 if (!success) | 742 if (!success) |
723 return NULL; | 743 return NULL; |
724 | 744 |
725 // Check if our current RVH is live before we set up a transition. | 745 // Check if our current RVH is live before we set up a transition. |
726 if (!render_view_host_->IsRenderViewLive()) { | 746 if (!render_view_host_->IsRenderViewLive()) { |
727 if (!cross_navigation_pending_) { | 747 if (!cross_navigation_pending_) { |
728 // The current RVH is not live. There's no reason to sit around with a | 748 // The current RVH is not live. There's no reason to sit around with a |
729 // sad tab or a newly created RVH while we wait for the pending RVH to | 749 // sad tab or a newly created RVH while we wait for the pending RVH to |
(...skipping 29 matching lines...) Expand all Loading... |
759 DCHECK(!cross_navigation_pending_); | 779 DCHECK(!cross_navigation_pending_); |
760 cross_navigation_pending_ = true; | 780 cross_navigation_pending_ = true; |
761 | 781 |
762 // Tell the old render view to run its onbeforeunload handler, since it | 782 // Tell the old render view to run its onbeforeunload handler, since it |
763 // doesn't otherwise know that the cross-site request is happening. This | 783 // doesn't otherwise know that the cross-site request is happening. This |
764 // will trigger a call to ShouldClosePage with the reply. | 784 // will trigger a call to ShouldClosePage with the reply. |
765 render_view_host_->FirePageBeforeUnload(true); | 785 render_view_host_->FirePageBeforeUnload(true); |
766 | 786 |
767 return pending_render_view_host_; | 787 return pending_render_view_host_; |
768 } else { | 788 } else { |
769 if (pending_web_ui_.get() && render_view_host_->IsRenderViewLive()) | 789 if (ShouldReuseWebUI(curr_entry, &entry)) { |
770 pending_web_ui_->GetController()->RenderViewReused(render_view_host_); | 790 pending_web_ui_.reset(); |
| 791 pending_and_current_web_ui_ = web_ui_->AsWeakPtr(); |
| 792 } else { |
| 793 pending_and_current_web_ui_.reset(); |
| 794 pending_web_ui_.reset( |
| 795 delegate_->CreateWebUIForRenderManager(entry.GetURL())); |
| 796 } |
| 797 |
| 798 if (pending_web_ui() && render_view_host_->IsRenderViewLive()) |
| 799 pending_web_ui()->GetController()->RenderViewReused(render_view_host_); |
771 | 800 |
772 // The renderer can exit view source mode when any error or cancellation | 801 // The renderer can exit view source mode when any error or cancellation |
773 // happen. We must overwrite to recover the mode. | 802 // happen. We must overwrite to recover the mode. |
774 if (entry.IsViewSourceMode()) { | 803 if (entry.IsViewSourceMode()) { |
775 render_view_host_->Send( | 804 render_view_host_->Send( |
776 new ViewMsg_EnableViewSourceMode(render_view_host_->GetRoutingID())); | 805 new ViewMsg_EnableViewSourceMode(render_view_host_->GetRoutingID())); |
777 } | 806 } |
778 } | 807 } |
779 | 808 |
780 // Same SiteInstance can be used. Navigate render_view_host_ if we are not | 809 // Same SiteInstance can be used. Navigate render_view_host_ if we are not |
(...skipping 23 matching lines...) Expand all Loading... |
804 | 833 |
805 // We can pass -1,-1 because there is no pending response in the | 834 // We can pass -1,-1 because there is no pending response in the |
806 // ResourceDispatcherHost to unpause. | 835 // ResourceDispatcherHost to unpause. |
807 pending_render_view_host->SwapOut(-1, -1); | 836 pending_render_view_host->SwapOut(-1, -1); |
808 } else { | 837 } else { |
809 // We won't be coming back, so shut this one down. | 838 // We won't be coming back, so shut this one down. |
810 pending_render_view_host->Shutdown(); | 839 pending_render_view_host->Shutdown(); |
811 } | 840 } |
812 | 841 |
813 pending_web_ui_.reset(); | 842 pending_web_ui_.reset(); |
| 843 pending_and_current_web_ui_.reset(); |
814 } | 844 } |
815 | 845 |
816 void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) { | 846 void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) { |
817 // We are doing this in order to work around and to track a crasher | 847 // We are doing this in order to work around and to track a crasher |
818 // (http://crbug.com/23411) where it seems that pending_render_view_host_ is | 848 // (http://crbug.com/23411) where it seems that pending_render_view_host_ is |
819 // deleted (not sure from where) but not NULLed. | 849 // deleted (not sure from where) but not NULLed. |
820 if (rvh == pending_render_view_host_) { | 850 if (rvh == pending_render_view_host_) { |
821 // If you hit this NOTREACHED, please report it in the following bug | 851 // If you hit this NOTREACHED, please report it in the following bug |
822 // http://crbug.com/23411 Make sure to include what you were doing when it | 852 // http://crbug.com/23411 Make sure to include what you were doing when it |
823 // happened (navigating to a new page, closing a tab...) and if you can | 853 // happened (navigating to a new page, closing a tab...) and if you can |
(...skipping 17 matching lines...) Expand all Loading... |
841 } | 871 } |
842 } | 872 } |
843 | 873 |
844 bool RenderViewHostManager::IsSwappedOut(RenderViewHost* rvh) { | 874 bool RenderViewHostManager::IsSwappedOut(RenderViewHost* rvh) { |
845 if (!rvh->GetSiteInstance()) | 875 if (!rvh->GetSiteInstance()) |
846 return false; | 876 return false; |
847 | 877 |
848 return swapped_out_hosts_.find(rvh->GetSiteInstance()->GetId()) != | 878 return swapped_out_hosts_.find(rvh->GetSiteInstance()->GetId()) != |
849 swapped_out_hosts_.end(); | 879 swapped_out_hosts_.end(); |
850 } | 880 } |
OLD | NEW |