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