Chromium Code Reviews| Index: chrome/browser/printing/background_printing_manager.cc |
| =================================================================== |
| --- chrome/browser/printing/background_printing_manager.cc (revision 99671) |
| +++ chrome/browser/printing/background_printing_manager.cc (working copy) |
| @@ -12,6 +12,7 @@ |
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| #include "chrome/common/chrome_notification_types.h" |
| #include "content/browser/browser_thread.h" |
| +#include "content/browser/renderer_host/render_view_host.h" |
| #include "content/common/notification_details.h" |
| #include "content/common/notification_source.h" |
| @@ -39,17 +40,31 @@ |
| registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, |
| Source<TabContentsWrapper>(preview_tab)); |
| - registrar_.Add(this, content::NOTIFICATION_TAB_CONTENTS_DESTROYED, |
| - Source<TabContents>(preview_tab->tab_contents())); |
| - // Detach |preview_tab| from its tab strip. |
| - Browser* browser = BrowserList::FindBrowserWithID( |
| - preview_tab->restore_tab_helper()->window_id().id()); |
| - DCHECK(browser); |
| + // OwnInitiatorTabContents() may have already added this notification. |
| + TabContents* preview_contents = preview_tab->tab_contents(); |
| + if (!registrar_.IsRegistered(this, |
| + content::NOTIFICATION_TAB_CONTENTS_DESTROYED, |
| + Source<TabContents>(preview_contents))) { |
| + registrar_.Add(this, content::NOTIFICATION_TAB_CONTENTS_DESTROYED, |
| + Source<TabContents>(preview_contents)); |
| + } |
| - TabStripModel* tabstrip = browser->tabstrip_model(); |
| - tabstrip->DetachTabContentsAt(tabstrip->GetIndexOfTabContents(preview_tab)); |
| + // If a tab that is printing crashes, the user cannot destroy it since it is |
| + // not in any tab strip. Thus listen for crashes here and delete the tab. |
| + // |
| + // Multiple sites may share the same RenderProcessHost, so check if this |
| + // notification has already been added. |
| + RenderProcessHost* rph = preview_tab->render_view_host()->process(); |
| + if (!registrar_.IsRegistered(this, |
| + content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
| + Source<RenderProcessHost>(rph))) { |
| + registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
| + Source<RenderProcessHost>(rph)); |
| + } |
| + RemoveFromTabStrip(preview_tab); |
| + |
| // Activate the initiator tab. |
| PrintPreviewTabController* tab_controller = |
| PrintPreviewTabController::GetInstance(); |
| @@ -63,32 +78,53 @@ |
| initiator_tab->tab_contents())->Activate(); |
| } |
| +bool BackgroundPrintingManager::OwnInitiatorTab( |
| + TabContentsWrapper* initiator_tab) { |
| + DCHECK(CalledOnValidThread()); |
| + DCHECK(!PrintPreviewTabController::IsPrintPreviewTab(initiator_tab)); |
| + CHECK(initiator_tabs_.find(initiator_tab) == initiator_tabs_.end()); |
| + |
| + PrintPreviewTabController* tab_controller = |
| + PrintPreviewTabController::GetInstance(); |
| + if (!tab_controller) |
| + return false; |
| + TabContentsWrapper* preview_tab = |
| + tab_controller->GetPrintPreviewForTab(initiator_tab); |
| + if (!preview_tab) |
| + return false; |
| + |
| + initiator_tabs_.insert(initiator_tab); |
| + map_[preview_tab] = initiator_tab; |
| + |
| + // OwnPrintPreviewTab() may have already added this notification. |
| + TabContents* preview_contents = preview_tab->tab_contents(); |
| + if (!registrar_.IsRegistered(this, |
| + content::NOTIFICATION_TAB_CONTENTS_DESTROYED, |
| + Source<TabContents>(preview_contents))) { |
| + registrar_.Add(this, content::NOTIFICATION_TAB_CONTENTS_DESTROYED, |
| + Source<TabContents>(preview_contents)); |
| + } |
| + |
| + RemoveFromTabStrip(initiator_tab); |
| + return true; |
| +} |
| + |
| void BackgroundPrintingManager::Observe(int type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| switch (type) { |
| + case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { |
| + OnRendererProcessClosed(Source<RenderProcessHost>(source).ptr()); |
| + break; |
| + } |
| case chrome::NOTIFICATION_PRINT_JOB_RELEASED: { |
| - TabContentsWrapper* tab = Source<TabContentsWrapper>(source).ptr(); |
| - registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, |
| - Source<TabContentsWrapper>(tab)); |
| - |
| - // This might be happening in the middle of a RenderViewGone() loop. |
| - // Deleting |contents| later so the RenderViewGone() loop can finish. |
| - MessageLoop::current()->DeleteSoon(FROM_HERE, tab); |
| + OnPrintJobReleased(Source<TabContentsWrapper>(source).ptr()); |
| break; |
| } |
| case content::NOTIFICATION_TAB_CONTENTS_DESTROYED: { |
| - TabContentsWrapper* tab = |
| + OnTabContentsDestroyed( |
| TabContentsWrapper::GetCurrentWrapperForContents( |
| - Source<TabContents>(source).ptr()); |
| - if (registrar_.IsRegistered(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, |
| - Source<TabContentsWrapper>(tab))) { |
| - registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, |
| - Source<TabContentsWrapper>(tab)); |
| - } |
| - registrar_.Remove(this, content::NOTIFICATION_TAB_CONTENTS_DESTROYED, |
| - Source<TabContents>(tab->tab_contents())); |
| - printing_tabs_.erase(tab); |
| + Source<TabContents>(source).ptr())); |
| break; |
| } |
| default: { |
| @@ -98,6 +134,89 @@ |
| } |
| } |
| +void BackgroundPrintingManager::OnRendererProcessClosed( |
| + RenderProcessHost* rph) { |
| + TabContentsWrapperSet::const_iterator it; |
| + for (it = begin(); it != end(); ++it) { |
| + TabContentsWrapper* tab = *it; |
| + if (tab->render_view_host()->process() == rph) |
| + MessageLoop::current()->DeleteSoon(FROM_HERE, tab); |
|
kmadhusu
2011/09/07 23:21:10
When exactly multiple preview tabs share the same
Lei Zhang
2011/09/07 23:41:16
This happens quite often. For example, open two ta
|
| + } |
| +} |
| + |
| +void BackgroundPrintingManager::OnPrintJobReleased( |
| + TabContentsWrapper* preview_tab) { |
| + registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, |
| + Source<TabContentsWrapper>(preview_tab)); |
| + |
| + // This might be happening in the middle of a RenderViewGone() loop. |
| + // Deleting |contents| later so the RenderViewGone() loop can finish. |
| + MessageLoop::current()->DeleteSoon(FROM_HERE, preview_tab); |
| +} |
| + |
| +void BackgroundPrintingManager::OnTabContentsDestroyed( |
| + TabContentsWrapper* preview_tab) { |
| + bool is_owned_printing_tab = |
| + (printing_tabs_.find(preview_tab) != printing_tabs_.end()); |
|
kmadhusu
2011/09/07 23:21:10
= HasPrintPreviewTab(preview_tab);
Lei Zhang
2011/09/07 23:41:16
Done.
|
| + bool is_preview_tab_for_owned_initator_tab = |
| + (map_.find(preview_tab) != map_.end()); |
| + DCHECK(is_owned_printing_tab || is_preview_tab_for_owned_initator_tab); |
| + |
| + // Always need to remove this notification since the tab is gone. |
| + registrar_.Remove(this, content::NOTIFICATION_TAB_CONTENTS_DESTROYED, |
| + Source<TabContents>(preview_tab->tab_contents())); |
| + |
| + // Delete the associated initiator tab if one exists. |
| + if (is_preview_tab_for_owned_initator_tab) { |
| + TabContentsWrapper* initiator_tab = map_[preview_tab]; |
| + initiator_tabs_.erase(initiator_tab); |
| + MessageLoop::current()->DeleteSoon(FROM_HERE, initiator_tab); |
| + } |
| + |
| + // If |preview_tab| is not owned, then we are done. |
| + if (!is_owned_printing_tab) |
| + return; |
| + |
| + // Remove NOTIFICATION_RENDERER_PROCESS_CLOSED if |tab| is the last |
| + // TabContents associated with |rph|. |
| + bool shared_rph = false; |
| + RenderProcessHost* rph = preview_tab->render_view_host()->process(); |
| + TabContentsWrapperSet::const_iterator it; |
| + for (it = begin(); it != end(); ++it) { |
| + TabContentsWrapper* iter_tab = *it; |
| + if (iter_tab == preview_tab) |
| + continue; |
| + if (iter_tab->render_view_host()->process() == rph) { |
| + shared_rph = true; |
| + break; |
| + } |
| + } |
| + if (!shared_rph) { |
| + registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
| + Source<RenderProcessHost>(rph)); |
| + } |
| + |
| + // Remove other notifications and remove the tab from |printing_tabs_|. |
| + if (registrar_.IsRegistered(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, |
| + Source<TabContentsWrapper>(preview_tab))) { |
| + registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, |
| + Source<TabContentsWrapper>(preview_tab)); |
| + } |
| + printing_tabs_.erase(preview_tab); |
| +} |
| + |
| +void BackgroundPrintingManager::RemoveFromTabStrip(TabContentsWrapper* tab) { |
| + Browser* browser = BrowserList::FindBrowserWithID( |
| + tab->restore_tab_helper()->window_id().id()); |
| + DCHECK(browser); |
| + |
| + TabStripModel* tabstrip = browser->tabstrip_model(); |
| + int index = tabstrip->GetIndexOfTabContents(tab); |
| + if (index == TabStripModel::kNoTab) |
| + return; |
| + tabstrip->DetachTabContentsAt(index); |
| +} |
| + |
| BackgroundPrintingManager::TabContentsWrapperSet::const_iterator |
| BackgroundPrintingManager::begin() { |
| return printing_tabs_.begin(); |