diff options
-rw-r--r-- | chrome/browser/printing/background_printing_manager.cc | 177 | ||||
-rw-r--r-- | chrome/browser/printing/background_printing_manager.h | 27 | ||||
-rw-r--r-- | chrome/browser/ui/browser.cc | 14 |
3 files changed, 192 insertions, 26 deletions
diff --git a/chrome/browser/printing/background_printing_manager.cc b/chrome/browser/printing/background_printing_manager.cc index 01f3d36..f1e9c24 100644 --- a/chrome/browser/printing/background_printing_manager.cc +++ b/chrome/browser/printing/background_printing_manager.cc @@ -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" @@ -33,22 +34,36 @@ void BackgroundPrintingManager::OwnPrintPreviewTab( TabContentsWrapper* preview_tab) { DCHECK(CalledOnValidThread()); DCHECK(PrintPreviewTabController::IsPrintPreviewTab(preview_tab)); - CHECK(printing_tabs_.find(preview_tab) == printing_tabs_.end()); + CHECK(!HasPrintPreviewTab(preview_tab)); printing_tabs_.insert(preview_tab); 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 = @@ -63,32 +78,60 @@ void BackgroundPrintingManager::OwnPrintPreviewTab( initiator_tab->tab_contents())->Activate(); } +bool BackgroundPrintingManager::OwnInitiatorTab( + TabContentsWrapper* initiator_tab) { + DCHECK(CalledOnValidThread()); + DCHECK(!PrintPreviewTabController::IsPrintPreviewTab(initiator_tab)); + bool has_initiator_tab = false; + for (TabContentsWrapperMap::iterator it = map_.begin(); it != map_.end(); + ++it) { + if (it->second == initiator_tab) { + has_initiator_tab = true; + break; + } + } + CHECK(!has_initiator_tab); + + PrintPreviewTabController* tab_controller = + PrintPreviewTabController::GetInstance(); + if (!tab_controller) + return false; + TabContentsWrapper* preview_tab = + tab_controller->GetPrintPreviewForTab(initiator_tab); + if (!preview_tab) + return false; + + 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 +141,88 @@ void BackgroundPrintingManager::Observe(int type, } } +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); + } +} + +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 = HasPrintPreviewTab(preview_tab); + 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]; + map_.erase(preview_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(); diff --git a/chrome/browser/printing/background_printing_manager.h b/chrome/browser/printing/background_printing_manager.h index e580ed7..2ac37c7 100644 --- a/chrome/browser/printing/background_printing_manager.h +++ b/chrome/browser/printing/background_printing_manager.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_PRINTING_BACKGROUND_PRINTING_MANAGER_H_ #pragma once +#include <map> #include <set> #include "base/compiler_specific.h" @@ -13,6 +14,7 @@ #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" +class RenderProcessHost; class TabContentsWrapper; namespace printing { @@ -33,6 +35,13 @@ class BackgroundPrintingManager : public base::NonThreadSafe, // hides it from the user. void OwnPrintPreviewTab(TabContentsWrapper* preview_tab); + // Takes ownership of |initiator_tab| and deletes it when its preview tab is + // destroyed by either being canceled, closed or finishing printing. This + // removes the TabContentsWrapper from its TabStrip and hides it from the + // user. Returns true if content has an associated print preview tab, + // otherwise, returns false and does not take ownership of |initiator_tab|. + bool OwnInitiatorTab(TabContentsWrapper* initiator_tab); + // Let others iterate over the list of background printing tabs. TabContentsWrapperSet::const_iterator begin(); TabContentsWrapperSet::const_iterator end(); @@ -46,9 +55,27 @@ class BackgroundPrintingManager : public base::NonThreadSafe, const NotificationDetails& details) OVERRIDE; private: + typedef std::map<TabContentsWrapper*, TabContentsWrapper*> + TabContentsWrapperMap; + + // Notifications handlers. + void OnRendererProcessClosed(RenderProcessHost* rph); + void OnPrintJobReleased(TabContentsWrapper* preview_tab); + void OnTabContentsDestroyed(TabContentsWrapper* preview_tab); + + // Removes |tab| from its tab strip. + void RemoveFromTabStrip(TabContentsWrapper* tab); + // The set of print preview tabs managed by BackgroundPrintingManager. TabContentsWrapperSet printing_tabs_; + // 1:1 mapping between an initiator tab managed by BackgroundPrintingManager + // and its associated print preview tab. The print preview tab need not be in + // |printing_tabs_|. + // Key: print preview tab. + // Value: initiator tab. + TabContentsWrapperMap map_; + NotificationRegistrar registrar_; DISALLOW_COPY_AND_ASSIGN(BackgroundPrintingManager); diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index b872b83..d5b0b2f 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc @@ -62,6 +62,7 @@ #include "chrome/browser/prefs/incognito_mode_prefs.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prerender/prerender_tab_helper.h" +#include "chrome/browser/printing/background_printing_manager.h" #include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h" #include "chrome/browser/printing/print_preview_tab_controller.h" #include "chrome/browser/printing/print_view_manager.h" @@ -3487,6 +3488,19 @@ void Browser::CloseContents(TabContents* source) { return; } + // Various sites have a pattern which open a new window with output formatted + // for printing, then include a print button, which does window.print(); + // window.close(); An example is printing Virgin America boarding + // pass. Instead of closing, when a print tab is associated with this tab, + // tell the BackgroundPrintingManager to own it, which causes it to be + // hidden and eventually closed when the print window is closed. + TabContentsWrapper* source_wrapper = + TabContentsWrapper::GetCurrentWrapperForContents(source); + if (g_browser_process->background_printing_manager()-> + OwnInitiatorTab(source_wrapper)) { + return; + } + int index = tab_handler_->GetTabStripModel()->GetWrapperIndex(source); if (index == TabStripModel::kNoTab) { NOTREACHED() << "CloseContents called for tab not in our strip"; |