| 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 |