OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/tab_contents/render_view_host_manager.h" | 5 #include "content/browser/tab_contents/render_view_host_manager.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "chrome/browser/profiles/profile.h" | 9 #include "chrome/browser/profiles/profile.h" |
10 #include "chrome/common/chrome_switches.h" | 10 #include "chrome/common/chrome_switches.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 } | 42 } |
43 | 43 |
44 RenderViewHostManager::~RenderViewHostManager() { | 44 RenderViewHostManager::~RenderViewHostManager() { |
45 if (pending_render_view_host_) | 45 if (pending_render_view_host_) |
46 CancelPending(); | 46 CancelPending(); |
47 | 47 |
48 // We should always have a main RenderViewHost. | 48 // We should always have a main RenderViewHost. |
49 RenderViewHost* render_view_host = render_view_host_; | 49 RenderViewHost* render_view_host = render_view_host_; |
50 render_view_host_ = NULL; | 50 render_view_host_ = NULL; |
51 render_view_host->Shutdown(); | 51 render_view_host->Shutdown(); |
| 52 |
| 53 // Shut down any swapped out RenderViewHosts. |
| 54 for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin(); |
| 55 iter != swapped_out_hosts_.end(); |
| 56 ++iter) { |
| 57 iter->second->Shutdown(); |
| 58 } |
52 } | 59 } |
53 | 60 |
54 void RenderViewHostManager::Init(Profile* profile, | 61 void RenderViewHostManager::Init(Profile* profile, |
55 SiteInstance* site_instance, | 62 SiteInstance* site_instance, |
56 int routing_id) { | 63 int routing_id) { |
57 // Create a RenderViewHost, once we have an instance. It is important to | 64 // Create a RenderViewHost, once we have an instance. It is important to |
58 // immediately give this SiteInstance to a RenderViewHost so that it is | 65 // immediately give this SiteInstance to a RenderViewHost so that it is |
59 // ref counted. | 66 // ref counted. |
60 if (!site_instance) | 67 if (!site_instance) |
61 site_instance = SiteInstance::CreateSiteInstance(profile); | 68 site_instance = SiteInstance::CreateSiteInstance(profile); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 if (pending_request_id == -1) { | 152 if (pending_request_id == -1) { |
146 // Haven't gotten around to starting the request, because we're still | 153 // Haven't gotten around to starting the request, because we're still |
147 // waiting for the beforeunload handler to finish. We'll pretend that it | 154 // waiting for the beforeunload handler to finish. We'll pretend that it |
148 // did finish, to let the navigation proceed. Note that there's a danger | 155 // did finish, to let the navigation proceed. Note that there's a danger |
149 // that the beforeunload handler will later finish and possibly return | 156 // that the beforeunload handler will later finish and possibly return |
150 // false (meaning the navigation should not proceed), but we'll ignore it | 157 // false (meaning the navigation should not proceed), but we'll ignore it |
151 // in this case because it took too long. | 158 // in this case because it took too long. |
152 if (pending_render_view_host_->are_navigations_suspended()) | 159 if (pending_render_view_host_->are_navigations_suspended()) |
153 pending_render_view_host_->SetNavigationsSuspended(false); | 160 pending_render_view_host_->SetNavigationsSuspended(false); |
154 } else { | 161 } else { |
155 // The request has been started and paused, while we're waiting for the | 162 // The request has been started and paused while we're waiting for the |
156 // unload handler to finish. We'll pretend that it did, by notifying the | 163 // unload handler to finish. We'll pretend that it did, by notifying the |
157 // IO thread to let the response continue. The pending renderer will then | 164 // IO thread to let the response continue. The pending renderer will then |
158 // be swapped in as part of the usual DidNavigate logic. (If the unload | 165 // be swapped in as part of the usual DidNavigate logic. (If the unload |
159 // handler later finishes, this call will be ignored because the state in | 166 // handler later finishes, this call will be ignored because the state in |
160 // CrossSiteResourceHandler will already be cleaned up.) | 167 // CrossSiteResourceHandler will already be cleaned up.) |
161 ViewMsg_ClosePage_Params params; | 168 ViewMsg_SwapOut_Params params; |
162 params.closing_process_id = | |
163 render_view_host_->process()->id(); | |
164 params.closing_route_id = render_view_host_->routing_id(); | |
165 params.for_cross_site_transition = true; | |
166 params.new_render_process_host_id = | 169 params.new_render_process_host_id = |
167 pending_render_view_host_->process()->id(); | 170 pending_render_view_host_->process()->id(); |
168 params.new_request_id = pending_request_id; | 171 params.new_request_id = pending_request_id; |
169 current_host()->process()->CrossSiteClosePageACK(params); | 172 current_host()->process()->CrossSiteSwapOutACK(params); |
170 } | 173 } |
171 return false; | 174 return false; |
172 } | 175 } |
173 | 176 |
174 void RenderViewHostManager::DidNavigateMainFrame( | 177 void RenderViewHostManager::DidNavigateMainFrame( |
175 RenderViewHost* render_view_host) { | 178 RenderViewHost* render_view_host) { |
176 if (!cross_navigation_pending_) { | 179 if (!cross_navigation_pending_) { |
177 DCHECK(!pending_render_view_host_); | 180 DCHECK(!pending_render_view_host_); |
178 | 181 |
179 // We should only hear this from our current renderer. | 182 // We should only hear this from our current renderer. |
180 DCHECK(render_view_host == render_view_host_); | 183 DCHECK(render_view_host == render_view_host_); |
181 | 184 |
182 // Even when there is no pending RVH, there may be a pending Web UI. | 185 // Even when there is no pending RVH, there may be a pending Web UI. |
183 if (pending_web_ui_.get()) | 186 if (pending_web_ui_.get()) |
184 CommitPending(); | 187 CommitPending(); |
185 return; | 188 return; |
186 } | 189 } |
187 | 190 |
188 if (render_view_host == pending_render_view_host_) { | 191 if (render_view_host == pending_render_view_host_) { |
189 // The pending cross-site navigation completed, so show the renderer. | 192 // The pending cross-site navigation completed, so show the renderer. |
| 193 // If it committed without sending network requests (e.g., data URLs), |
| 194 // then we still need to swap out the old RVH first and run its unload |
| 195 // handler. OK for that to happen in the background. |
| 196 if (pending_render_view_host_->GetPendingRequestId() == -1) { |
| 197 OnCrossSiteResponse(pending_render_view_host_->process()->id(), |
| 198 pending_render_view_host_->routing_id()); |
| 199 } |
| 200 |
190 CommitPending(); | 201 CommitPending(); |
191 cross_navigation_pending_ = false; | 202 cross_navigation_pending_ = false; |
192 } else if (render_view_host == render_view_host_) { | 203 } else if (render_view_host == render_view_host_) { |
193 // A navigation in the original page has taken place. Cancel the pending | 204 // A navigation in the original page has taken place. Cancel the pending |
194 // one. | 205 // one. |
195 CancelPending(); | 206 CancelPending(); |
196 cross_navigation_pending_ = false; | 207 cross_navigation_pending_ = false; |
197 } else { | 208 } else { |
198 // No one else should be sending us DidNavigate in this state. | 209 // No one else should be sending us DidNavigate in this state. |
199 DCHECK(false); | 210 DCHECK(false); |
(...skipping 14 matching lines...) Expand all Loading... |
214 // (Navigate, DidNavigate, etc), which will clean it up properly. | 225 // (Navigate, DidNavigate, etc), which will clean it up properly. |
215 // TODO(creis): All of this will go away when we move the cross-site logic | 226 // TODO(creis): All of this will go away when we move the cross-site logic |
216 // to ResourceDispatcherHost, so that we intercept responses rather than | 227 // to ResourceDispatcherHost, so that we intercept responses rather than |
217 // navigation events. (That's necessary to support onunload anyway.) Once | 228 // navigation events. (That's necessary to support onunload anyway.) Once |
218 // we've made that change, we won't create a pending renderer until we know | 229 // we've made that change, we won't create a pending renderer until we know |
219 // the response is not a download. | 230 // the response is not a download. |
220 } | 231 } |
221 | 232 |
222 void RenderViewHostManager::RendererProcessClosing( | 233 void RenderViewHostManager::RendererProcessClosing( |
223 RenderProcessHost* render_process_host) { | 234 RenderProcessHost* render_process_host) { |
224 // TODO(creis): Don't schedule new navigations in RenderViewHosts of this | 235 // Remove any swapped out RVHs from this process, so that we don't try to |
225 // process. (Part of http://crbug.com/65953.) | 236 // swap them back in while the process is exiting. Start by finding them, |
| 237 // since there could be more than one. |
| 238 std::list<int> ids_to_remove; |
| 239 for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin(); |
| 240 iter != swapped_out_hosts_.end(); |
| 241 ++iter) { |
| 242 if (iter->second->process() == render_process_host) |
| 243 ids_to_remove.push_back(iter->first); |
| 244 } |
| 245 |
| 246 // Now delete them. |
| 247 while (!ids_to_remove.empty()) { |
| 248 swapped_out_hosts_[ids_to_remove.back()]->Shutdown(); |
| 249 swapped_out_hosts_.erase(ids_to_remove.back()); |
| 250 ids_to_remove.pop_back(); |
| 251 } |
226 } | 252 } |
227 | 253 |
228 void RenderViewHostManager::ShouldClosePage(bool for_cross_site_transition, | 254 void RenderViewHostManager::ShouldClosePage(bool for_cross_site_transition, |
229 bool proceed) { | 255 bool proceed) { |
230 if (for_cross_site_transition) { | 256 if (for_cross_site_transition) { |
231 // Ignore if we're not in a cross-site navigation. | 257 // Ignore if we're not in a cross-site navigation. |
232 if (!cross_navigation_pending_) | 258 if (!cross_navigation_pending_) |
233 return; | 259 return; |
234 | 260 |
235 if (proceed) { | 261 if (proceed) { |
(...skipping 11 matching lines...) Expand all Loading... |
247 cross_navigation_pending_ = false; | 273 cross_navigation_pending_ = false; |
248 } | 274 } |
249 } else { | 275 } else { |
250 // Non-cross site transition means closing the entire tab. | 276 // Non-cross site transition means closing the entire tab. |
251 bool proceed_to_fire_unload; | 277 bool proceed_to_fire_unload; |
252 delegate_->BeforeUnloadFiredFromRenderManager(proceed, | 278 delegate_->BeforeUnloadFiredFromRenderManager(proceed, |
253 &proceed_to_fire_unload); | 279 &proceed_to_fire_unload); |
254 | 280 |
255 if (proceed_to_fire_unload) { | 281 if (proceed_to_fire_unload) { |
256 // This is not a cross-site navigation, the tab is being closed. | 282 // This is not a cross-site navigation, the tab is being closed. |
257 render_view_host_->ClosePage(false, -1, -1); | 283 render_view_host_->ClosePage(); |
258 } | 284 } |
259 } | 285 } |
260 } | 286 } |
261 | 287 |
262 void RenderViewHostManager::OnCrossSiteResponse(int new_render_process_host_id, | 288 void RenderViewHostManager::OnCrossSiteResponse(int new_render_process_host_id, |
263 int new_request_id) { | 289 int new_request_id) { |
264 // Should only see this while we have a pending renderer. | 290 // Should only see this while we have a pending renderer. |
265 if (!cross_navigation_pending_) | 291 if (!cross_navigation_pending_) |
266 return; | 292 return; |
267 DCHECK(pending_render_view_host_); | 293 DCHECK(pending_render_view_host_); |
268 | 294 |
269 // Tell the old renderer to run its onunload handler. When it finishes, it | 295 // Tell the old renderer it is being swapped out. This will fire the unload |
270 // will send a ClosePage_ACK to the ResourceDispatcherHost with the given | 296 // handler (without firing the beforeunload handler a second time). When the |
271 // IDs (of the pending RVH's request), allowing the pending RVH's response to | 297 // unload handler finishes and the navigation completes, we will send a |
272 // resume. | 298 // message to the ResourceDispatcherHost with the given pending request IDs, |
273 render_view_host_->ClosePage(true, | 299 // allowing the pending RVH's response to resume. |
274 new_render_process_host_id, new_request_id); | 300 render_view_host_->SwapOut(new_render_process_host_id, new_request_id); |
275 | 301 |
276 // ResourceDispatcherHost has told us to run the onunload handler, which | 302 // ResourceDispatcherHost has told us to run the onunload handler, which |
277 // means it is not a download or unsafe page, and we are going to perform the | 303 // means it is not a download or unsafe page, and we are going to perform the |
278 // navigation. Thus, we no longer need to remember that the RenderViewHost | 304 // navigation. Thus, we no longer need to remember that the RenderViewHost |
279 // is part of a pending cross-site request. | 305 // is part of a pending cross-site request. |
280 pending_render_view_host_->SetHasPendingCrossSiteRequest(false, | 306 pending_render_view_host_->SetHasPendingCrossSiteRequest(false, |
281 new_request_id); | 307 new_request_id); |
282 } | 308 } |
283 | 309 |
284 void RenderViewHostManager::OnCrossSiteNavigationCanceled() { | 310 void RenderViewHostManager::OnCrossSiteNavigationCanceled() { |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
475 bool RenderViewHostManager::CreatePendingRenderView( | 501 bool RenderViewHostManager::CreatePendingRenderView( |
476 const NavigationEntry& entry, SiteInstance* instance) { | 502 const NavigationEntry& entry, SiteInstance* instance) { |
477 NavigationEntry* curr_entry = | 503 NavigationEntry* curr_entry = |
478 delegate_->GetControllerForRenderManager().GetLastCommittedEntry(); | 504 delegate_->GetControllerForRenderManager().GetLastCommittedEntry(); |
479 if (curr_entry) { | 505 if (curr_entry) { |
480 DCHECK(!curr_entry->content_state().empty()); | 506 DCHECK(!curr_entry->content_state().empty()); |
481 // TODO(creis): Should send a message to the RenderView to let it know | 507 // TODO(creis): Should send a message to the RenderView to let it know |
482 // we're about to switch away, so that it sends an UpdateState message. | 508 // we're about to switch away, so that it sends an UpdateState message. |
483 } | 509 } |
484 | 510 |
| 511 // Check if we've already created an RVH for this SiteInstance. |
| 512 CHECK(instance); |
| 513 RenderViewHostMap::iterator iter = |
| 514 swapped_out_hosts_.find(instance->id()); |
| 515 if (iter != swapped_out_hosts_.end()) { |
| 516 // Re-use the existing RenderViewHost, which has already been initialized. |
| 517 // We'll remove it from the list of swapped out hosts if it commits. |
| 518 pending_render_view_host_ = iter->second; |
| 519 |
| 520 // Prevent the process from exiting while we're trying to use it. |
| 521 pending_render_view_host_->process()->AddPendingView(); |
| 522 |
| 523 return true; |
| 524 } |
| 525 |
485 pending_render_view_host_ = RenderViewHostFactory::Create( | 526 pending_render_view_host_ = RenderViewHostFactory::Create( |
486 instance, render_view_delegate_, MSG_ROUTING_NONE, delegate_-> | 527 instance, render_view_delegate_, MSG_ROUTING_NONE, delegate_-> |
487 GetControllerForRenderManager().session_storage_namespace()); | 528 GetControllerForRenderManager().session_storage_namespace()); |
488 | 529 |
489 // Prevent the process from exiting while we're trying to use it. | 530 // Prevent the process from exiting while we're trying to use it. |
490 pending_render_view_host_->process()->AddPendingView(); | 531 pending_render_view_host_->process()->AddPendingView(); |
491 | 532 |
492 bool success = InitRenderView(pending_render_view_host_, entry); | 533 bool success = InitRenderView(pending_render_view_host_, entry); |
493 if (success) { | 534 if (success) { |
494 // Don't show the view until we get a DidNavigate from it. | 535 // Don't show the view until we get a DidNavigate from it. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 if (will_focus_location_bar) | 570 if (will_focus_location_bar) |
530 delegate_->SetFocusToLocationBar(false); | 571 delegate_->SetFocusToLocationBar(false); |
531 return; | 572 return; |
532 } | 573 } |
533 | 574 |
534 // Remember if the page was focused so we can focus the new renderer in | 575 // Remember if the page was focused so we can focus the new renderer in |
535 // that case. | 576 // that case. |
536 bool focus_render_view = !will_focus_location_bar && | 577 bool focus_render_view = !will_focus_location_bar && |
537 render_view_host_->view() && render_view_host_->view()->HasFocus(); | 578 render_view_host_->view() && render_view_host_->view()->HasFocus(); |
538 | 579 |
539 // Hide the current view and prepare to destroy it. | 580 // Swap in the pending view and make it active. |
540 // TODO(creis): Get the old RenderViewHost to send us an UpdateState message | |
541 // before we destroy it. | |
542 if (render_view_host_->view()) | |
543 render_view_host_->view()->Hide(); | |
544 RenderViewHost* old_render_view_host = render_view_host_; | 581 RenderViewHost* old_render_view_host = render_view_host_; |
545 | |
546 // Swap in the pending view and make it active. | |
547 render_view_host_ = pending_render_view_host_; | 582 render_view_host_ = pending_render_view_host_; |
548 pending_render_view_host_ = NULL; | 583 pending_render_view_host_ = NULL; |
549 | 584 |
550 // The process will no longer try to exit, so we can decrement the count. | 585 // The process will no longer try to exit, so we can decrement the count. |
551 render_view_host_->process()->RemovePendingView(); | 586 render_view_host_->process()->RemovePendingView(); |
552 | 587 |
553 // If the view is gone, then this RenderViewHost died while it was hidden. | 588 // If the view is gone, then this RenderViewHost died while it was hidden. |
554 // We ignored the RenderViewGone call at the time, so we should send it now | 589 // We ignored the RenderViewGone call at the time, so we should send it now |
555 // to make sure the sad tab shows up, etc. | 590 // to make sure the sad tab shows up, etc. |
556 if (render_view_host_->view()) | 591 if (render_view_host_->view()) |
557 render_view_host_->view()->Show(); | 592 render_view_host_->view()->Show(); |
558 else | 593 else |
559 delegate_->RenderViewGoneFromRenderManager(render_view_host_); | 594 delegate_->RenderViewGoneFromRenderManager(render_view_host_); |
560 | 595 |
| 596 // Hide the old view now that the new one is visible. |
| 597 if (old_render_view_host->view()) { |
| 598 old_render_view_host->view()->Hide(); |
| 599 old_render_view_host->WasSwappedOut(); |
| 600 } |
| 601 |
561 // Make sure the size is up to date. (Fix for bug 1079768.) | 602 // Make sure the size is up to date. (Fix for bug 1079768.) |
562 delegate_->UpdateRenderViewSizeForRenderManager(); | 603 delegate_->UpdateRenderViewSizeForRenderManager(); |
563 | 604 |
564 if (will_focus_location_bar) | 605 if (will_focus_location_bar) |
565 delegate_->SetFocusToLocationBar(false); | 606 delegate_->SetFocusToLocationBar(false); |
566 else if (focus_render_view && render_view_host_->view()) | 607 else if (focus_render_view && render_view_host_->view()) |
567 render_view_host_->view()->Focus(); | 608 render_view_host_->view()->Focus(); |
568 | 609 |
569 RenderViewHostSwitchedDetails details; | 610 RenderViewHostSwitchedDetails details; |
570 details.new_host = render_view_host_; | 611 details.new_host = render_view_host_; |
571 details.old_host = old_render_view_host; | 612 details.old_host = old_render_view_host; |
572 NotificationService::current()->Notify( | 613 NotificationService::current()->Notify( |
573 NotificationType::RENDER_VIEW_HOST_CHANGED, | 614 NotificationType::RENDER_VIEW_HOST_CHANGED, |
574 Source<NavigationController>(&delegate_->GetControllerForRenderManager()), | 615 Source<NavigationController>(&delegate_->GetControllerForRenderManager()), |
575 Details<RenderViewHostSwitchedDetails>(&details)); | 616 Details<RenderViewHostSwitchedDetails>(&details)); |
576 | 617 |
577 old_render_view_host->Shutdown(); | 618 // If the pending view was on the swapped out list, we can remove it. |
| 619 swapped_out_hosts_.erase(render_view_host_->site_instance()->id()); |
| 620 |
| 621 // If the old RVH is live, we are swapping it out and should keep track of it |
| 622 // in case we navigate back to it. |
| 623 if (old_render_view_host->IsRenderViewLive()) { |
| 624 DCHECK(old_render_view_host->is_swapped_out()); |
| 625 swapped_out_hosts_[old_render_view_host->site_instance()->id()] = |
| 626 old_render_view_host; |
| 627 } else { |
| 628 old_render_view_host->Shutdown(); |
| 629 } |
578 | 630 |
579 // Let the task manager know that we've swapped RenderViewHosts, since it | 631 // Let the task manager know that we've swapped RenderViewHosts, since it |
580 // might need to update its process groupings. | 632 // might need to update its process groupings. |
581 delegate_->NotifySwappedFromRenderManager(); | 633 delegate_->NotifySwappedFromRenderManager(); |
582 } | 634 } |
583 | 635 |
584 RenderViewHost* RenderViewHostManager::UpdateRendererStateForNavigate( | 636 RenderViewHost* RenderViewHostManager::UpdateRendererStateForNavigate( |
585 const NavigationEntry& entry) { | 637 const NavigationEntry& entry) { |
586 // If we are cross-navigating, then we want to get back to normal and navigate | 638 // If we are cross-navigating, then we want to get back to normal and navigate |
587 // as usual. | 639 // as usual. |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
677 } | 729 } |
678 | 730 |
679 // Same SiteInstance can be used. Navigate render_view_host_ if we are not | 731 // Same SiteInstance can be used. Navigate render_view_host_ if we are not |
680 // cross navigating. | 732 // cross navigating. |
681 DCHECK(!cross_navigation_pending_); | 733 DCHECK(!cross_navigation_pending_); |
682 return render_view_host_; | 734 return render_view_host_; |
683 } | 735 } |
684 | 736 |
685 void RenderViewHostManager::CancelPending() { | 737 void RenderViewHostManager::CancelPending() { |
686 RenderViewHost* pending_render_view_host = pending_render_view_host_; | 738 RenderViewHost* pending_render_view_host = pending_render_view_host_; |
| 739 pending_render_view_host_ = NULL; |
687 | 740 |
688 // We no longer need to prevent the process from exiting. | 741 // We no longer need to prevent the process from exiting. |
689 pending_render_view_host->process()->RemovePendingView(); | 742 pending_render_view_host->process()->RemovePendingView(); |
690 | 743 |
691 pending_render_view_host_ = NULL; | 744 // The pending RVH may already be on the swapped out list if we started to |
692 pending_render_view_host->Shutdown(); | 745 // swap it back in and then canceled. If so, make sure it gets swapped out |
| 746 // again. If it's not on the swapped out list (e.g., aborting a pending |
| 747 // load), then it's safe to shut down. |
| 748 if (IsSwappedOut(pending_render_view_host)) { |
| 749 // Any currently suspended navigations are no longer needed. |
| 750 pending_render_view_host->CancelSuspendedNavigations(); |
| 751 |
| 752 // We can pass -1,-1 because there is no pending response in the |
| 753 // ResourceDispatcherHost to unpause. |
| 754 pending_render_view_host->SwapOut(-1, -1); |
| 755 } else { |
| 756 // We won't be coming back, so shut this one down. |
| 757 pending_render_view_host->Shutdown(); |
| 758 } |
693 | 759 |
694 pending_web_ui_.reset(); | 760 pending_web_ui_.reset(); |
695 } | 761 } |
696 | 762 |
697 void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) { | 763 void RenderViewHostManager::RenderViewDeleted(RenderViewHost* rvh) { |
698 // We are doing this in order to work around and to track a crasher | 764 // We are doing this in order to work around and to track a crasher |
699 // (http://crbug.com/23411) where it seems that pending_render_view_host_ is | 765 // (http://crbug.com/23411) where it seems that pending_render_view_host_ is |
700 // deleted (not sure from where) but not NULLed. | 766 // deleted (not sure from where) but not NULLed. |
701 if (rvh == pending_render_view_host_) { | 767 if (rvh == pending_render_view_host_) { |
702 // If you hit this NOTREACHED, please report it in the following bug | 768 // If you hit this NOTREACHED, please report it in the following bug |
703 // http://crbug.com/23411 Make sure to include what you were doing when it | 769 // http://crbug.com/23411 Make sure to include what you were doing when it |
704 // happened (navigating to a new page, closing a tab...) and if you can | 770 // happened (navigating to a new page, closing a tab...) and if you can |
705 // reproduce. | 771 // reproduce. |
706 NOTREACHED(); | 772 NOTREACHED(); |
707 pending_render_view_host_ = NULL; | 773 pending_render_view_host_ = NULL; |
708 } | 774 } |
| 775 |
| 776 // Make sure deleted RVHs are not kept in the swapped out list while we are |
| 777 // still alive. (If render_view_host_ is null, we're already being deleted.) |
| 778 if (!render_view_host_) |
| 779 return; |
| 780 // We can't look it up by SiteInstance ID, which may no longer be valid. |
| 781 for (RenderViewHostMap::iterator iter = swapped_out_hosts_.begin(); |
| 782 iter != swapped_out_hosts_.end(); |
| 783 ++iter) { |
| 784 if (iter->second == rvh) { |
| 785 swapped_out_hosts_.erase(iter); |
| 786 break; |
| 787 } |
| 788 } |
709 } | 789 } |
710 | 790 |
711 void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) { | 791 void RenderViewHostManager::SwapInRenderViewHost(RenderViewHost* rvh) { |
| 792 // TODO(creis): Abstract out the common code between this and CommitPending. |
712 web_ui_.reset(); | 793 web_ui_.reset(); |
713 | 794 |
714 // Hide the current view and prepare to destroy it. | 795 // Make sure the current RVH is swapped out so that it filters out any |
715 if (render_view_host_->view()) | 796 // disruptive messages from the renderer. We can pass -1,-1 because there is |
716 render_view_host_->view()->Hide(); | 797 // no pending response in the ResourceDispatcherHost to unpause. |
717 RenderViewHost* old_render_view_host = render_view_host_; | 798 render_view_host_->SwapOut(-1, -1); |
718 | 799 |
719 // Swap in the new view and make it active. | 800 // Swap in the new view and make it active. |
| 801 RenderViewHost* old_render_view_host = render_view_host_; |
720 render_view_host_ = rvh; | 802 render_view_host_ = rvh; |
721 render_view_host_->set_delegate(render_view_delegate_); | 803 render_view_host_->set_delegate(render_view_delegate_); |
722 // Remove old RenderWidgetHostView with mocked out methods so it can be | 804 // Remove old RenderWidgetHostView with mocked out methods so it can be |
723 // replaced with a new one that's a child of |delegate_|'s view. | 805 // replaced with a new one that's a child of |delegate_|'s view. |
724 scoped_ptr<RenderWidgetHostView> old_view(render_view_host_->view()); | 806 scoped_ptr<RenderWidgetHostView> old_view(render_view_host_->view()); |
725 render_view_host_->set_view(NULL); | 807 render_view_host_->set_view(NULL); |
726 delegate_->CreateViewAndSetSizeForRVH(render_view_host_); | 808 delegate_->CreateViewAndSetSizeForRVH(render_view_host_); |
727 render_view_host_->ActivateDeferredPluginHandles(); | 809 render_view_host_->ActivateDeferredPluginHandles(); |
728 // If the view is gone, then this RenderViewHost died while it was hidden. | 810 // If the view is gone, then this RenderViewHost died while it was hidden. |
729 // We ignored the RenderViewGone call at the time, so we should send it now | 811 // We ignored the RenderViewGone call at the time, so we should send it now |
730 // to make sure the sad tab shows up, etc. | 812 // to make sure the sad tab shows up, etc. |
731 if (render_view_host_->view()) { | 813 if (render_view_host_->view()) { |
732 // The Hide() is needed to sync the state of |render_view_host_|, which is | 814 // The Hide() is needed to sync the state of |render_view_host_|, which is |
733 // hidden, with the newly created view, which does not know the | 815 // hidden, with the newly created view, which does not know the |
734 // RenderViewHost is hidden. | 816 // RenderViewHost is hidden. |
735 // TODO(tburkard,cbentzel): Figure out if this hack can be removed | 817 // TODO(tburkard,cbentzel): Figure out if this hack can be removed |
736 // (http://crbug.com/79891). | 818 // (http://crbug.com/79891). |
737 render_view_host_->view()->Hide(); | 819 render_view_host_->view()->Hide(); |
738 render_view_host_->view()->Show(); | 820 render_view_host_->view()->Show(); |
739 } | 821 } |
740 | 822 |
| 823 // Hide the current view and prepare to swap it out. |
| 824 if (old_render_view_host->view()) { |
| 825 old_render_view_host->view()->Hide(); |
| 826 old_render_view_host->WasSwappedOut(); |
| 827 } |
| 828 |
741 delegate_->UpdateRenderViewSizeForRenderManager(); | 829 delegate_->UpdateRenderViewSizeForRenderManager(); |
742 | 830 |
743 RenderViewHostSwitchedDetails details; | 831 RenderViewHostSwitchedDetails details; |
744 details.new_host = render_view_host_; | 832 details.new_host = render_view_host_; |
745 details.old_host = old_render_view_host; | 833 details.old_host = old_render_view_host; |
746 NotificationService::current()->Notify( | 834 NotificationService::current()->Notify( |
747 NotificationType::RENDER_VIEW_HOST_CHANGED, | 835 NotificationType::RENDER_VIEW_HOST_CHANGED, |
748 Source<NavigationController>(&delegate_->GetControllerForRenderManager()), | 836 Source<NavigationController>(&delegate_->GetControllerForRenderManager()), |
749 Details<RenderViewHostSwitchedDetails>(&details)); | 837 Details<RenderViewHostSwitchedDetails>(&details)); |
750 | 838 |
751 // This will cause the old RenderViewHost to delete itself. | 839 // If the given RVH was on the swapped out list, we can remove it. |
752 old_render_view_host->Shutdown(); | 840 swapped_out_hosts_.erase(render_view_host_->site_instance()->id()); |
| 841 |
| 842 // If the old RVH is live, we are swapping it out and should keep track of it |
| 843 // in case we navigate back to it. |
| 844 if (old_render_view_host->IsRenderViewLive()) { |
| 845 DCHECK(old_render_view_host->is_swapped_out()); |
| 846 swapped_out_hosts_[old_render_view_host->site_instance()->id()] = |
| 847 old_render_view_host; |
| 848 } else { |
| 849 old_render_view_host->Shutdown(); |
| 850 } |
753 | 851 |
754 // Let the task manager know that we've swapped RenderViewHosts, since it | 852 // Let the task manager know that we've swapped RenderViewHosts, since it |
755 // might need to update its process groupings. | 853 // might need to update its process groupings. |
756 delegate_->NotifySwappedFromRenderManager(); | 854 delegate_->NotifySwappedFromRenderManager(); |
757 } | 855 } |
| 856 |
| 857 bool RenderViewHostManager::IsSwappedOut(RenderViewHost* rvh) { |
| 858 if (!rvh->site_instance()) |
| 859 return false; |
| 860 |
| 861 return swapped_out_hosts_.find(rvh->site_instance()->id()) != |
| 862 swapped_out_hosts_.end(); |
| 863 } |
OLD | NEW |