Index: chrome/browser/printing/background_printing_manager.cc |
diff --git a/chrome/browser/printing/background_printing_manager.cc b/chrome/browser/printing/background_printing_manager.cc |
index f0aa96a0022fe09eb4226bdc1d77a630dac23c66..e619fc966e683994e15cf474685d70613352118d 100644 |
--- a/chrome/browser/printing/background_printing_manager.cc |
+++ b/chrome/browser/printing/background_printing_manager.cc |
@@ -14,22 +14,52 @@ |
#include "content/public/browser/render_view_host.h" |
#include "content/public/browser/web_contents.h" |
#include "content/public/browser/web_contents_delegate.h" |
+#include "content/public/browser/web_contents_observer.h" |
using content::BrowserThread; |
using content::WebContents; |
namespace printing { |
+class BackgroundPrintingManager::Observer |
+ : public content::WebContentsObserver { |
+ public: |
+ Observer(BackgroundPrintingManager* manager, WebContents* web_contents); |
+ |
+ private: |
+ virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE; |
+ virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE; |
+ |
+ BackgroundPrintingManager* manager_; |
+}; |
+ |
+BackgroundPrintingManager::Observer::Observer( |
+ BackgroundPrintingManager* manager, WebContents* web_contents) |
+ : content::WebContentsObserver(web_contents), |
+ manager_(manager) { |
+} |
+ |
+void BackgroundPrintingManager::Observer::RenderProcessGone( |
+ base::TerminationStatus status) { |
+ manager_->DeletePreviewContents(web_contents()); |
+} |
+void BackgroundPrintingManager::Observer::WebContentsDestroyed( |
+ WebContents* web_contents) { |
+ manager_->DeletePreviewContents(web_contents); |
+} |
+ |
BackgroundPrintingManager::BackgroundPrintingManager() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
} |
BackgroundPrintingManager::~BackgroundPrintingManager() { |
DCHECK(CalledOnValidThread()); |
- // The might be some WebContentses still in |printing_contents_set_| at this |
- // point. E.g. when the last remaining tab closes and there is still a print |
- // preview WebContents trying to print. In which case it will fail to print. |
+ // The might be some WebContentses still in |printing_contents_map_| at this |
+ // point (e.g. when the last remaining tab closes and there is still a print |
+ // preview WebContents trying to print). In such a case it will fail to print, |
+ // but we should at least clean up the observers. |
// TODO(thestig): Handle this case better. |
+ STLDeleteValues(&printing_contents_map_); |
} |
void BackgroundPrintingManager::OwnPrintPreviewDialog( |
@@ -38,30 +68,13 @@ void BackgroundPrintingManager::OwnPrintPreviewDialog( |
DCHECK(PrintPreviewDialogController::IsPrintPreviewDialog(preview_dialog)); |
CHECK(!HasPrintPreviewDialog(preview_dialog)); |
- printing_contents_set_.insert(preview_dialog); |
+ printing_contents_map_[preview_dialog] = new Observer(this, preview_dialog); |
- content::Source<WebContents> preview_source(preview_dialog); |
- registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, preview_source); |
- |
- // OwnInitiatorWebContents() may have already added this notification. |
- if (!registrar_.IsRegistered(this, |
- content::NOTIFICATION_WEB_CONTENTS_DESTROYED, preview_source)) { |
- registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
- preview_source); |
- } |
- |
- // If a WebContents that is printing crashes, the user cannot destroy it since |
- // it is hidden. Thus listen for crashes here and delete it. |
- // |
- // Multiple sites may share the same RenderProcessHost, so check if this |
- // notification has already been added. |
- content::Source<content::RenderProcessHost> rph_source( |
- preview_dialog->GetRenderProcessHost()); |
- if (!registrar_.IsRegistered(this, |
- content::NOTIFICATION_RENDERER_PROCESS_CLOSED, rph_source)) { |
- registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
- rph_source); |
- } |
+ // Watch for print jobs finishing. Everything else is watched for by the |
+ // Observer. TODO(avi, cait): finish the job of removing this last |
+ // notification. |
+ registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, |
+ content::Source<WebContents>(preview_dialog)); |
// Activate the initiator. |
PrintPreviewDialogController* dialog_controller = |
@@ -78,110 +91,45 @@ void BackgroundPrintingManager::Observe( |
int type, |
const content::NotificationSource& source, |
const content::NotificationDetails& details) { |
- if (type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED) { |
- OnRendererProcessClosed( |
- content::Source<content::RenderProcessHost>(source).ptr()); |
- } else if (type == chrome::NOTIFICATION_PRINT_JOB_RELEASED) { |
- OnPrintJobReleased(content::Source<WebContents>(source).ptr()); |
- } else { |
- DCHECK_EQ(content::NOTIFICATION_WEB_CONTENTS_DESTROYED, type); |
- OnWebContentsDestroyed(content::Source<WebContents>(source).ptr()); |
- } |
-} |
- |
-void BackgroundPrintingManager::OnRendererProcessClosed( |
- content::RenderProcessHost* rph) { |
- WebContentsSet printing_contents_pending_deletion_set; |
- WebContentsSet::const_iterator it; |
- for (it = begin(); it != end(); ++it) { |
- WebContents* preview_contents = *it; |
- if (preview_contents->GetRenderProcessHost() == rph) { |
- printing_contents_pending_deletion_set.insert(preview_contents); |
- } |
- } |
- for (it = printing_contents_pending_deletion_set.begin(); |
- it != printing_contents_pending_deletion_set.end(); |
- ++it) { |
- DeletePreviewContents(*it); |
- } |
+ DCHECK_EQ(chrome::NOTIFICATION_PRINT_JOB_RELEASED, type); |
+ DeletePreviewContents(content::Source<WebContents>(source).ptr()); |
} |
-void BackgroundPrintingManager::OnPrintJobReleased( |
- WebContents* preview_contents) { |
- DeletePreviewContents(preview_contents); |
-} |
- |
-void BackgroundPrintingManager::OnWebContentsDestroyed( |
+void BackgroundPrintingManager::DeletePreviewContents( |
WebContents* preview_contents) { |
- // Always need to remove this notification since the WebContents is gone. |
- content::Source<WebContents> preview_source(preview_contents); |
- registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
- preview_source); |
- |
- if (!HasPrintPreviewDialog(preview_contents)) { |
- NOTREACHED(); |
+ WebContentsObserverMap::iterator i = |
+ printing_contents_map_.find(preview_contents); |
+ if (i == printing_contents_map_.end()) { |
+ // Everyone is racing to be the first to delete the |preview_contents|. If |
+ // this case is hit, someone else won the race, so there is no need to |
+ // continue. <http://crbug.com/100806> |
return; |
} |
- // Remove NOTIFICATION_RENDERER_PROCESS_CLOSED if |preview_contents| is the |
- // last WebContents associated with |rph|. |
- bool shared_rph = |
- (HasSharedRenderProcessHost(printing_contents_set_, preview_contents) || |
- HasSharedRenderProcessHost(printing_contents_pending_deletion_set_, |
- preview_contents)); |
- if (!shared_rph) { |
- content::RenderProcessHost* rph = preview_contents->GetRenderProcessHost(); |
- registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
- content::Source<content::RenderProcessHost>(rph)); |
- } |
- |
- // Remove other notifications and remove the WebContents from its |
- // WebContentsSet. |
- if (printing_contents_set_.erase(preview_contents) == 1) { |
- registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, |
- preview_source); |
- } else { |
- // DeletePreviewContents already deleted the notification. |
- printing_contents_pending_deletion_set_.erase(preview_contents); |
- } |
-} |
- |
-void BackgroundPrintingManager::DeletePreviewContents( |
- WebContents* preview_contents) { |
+ // Stop all observation ... |
registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, |
content::Source<WebContents>(preview_contents)); |
- printing_contents_set_.erase(preview_contents); |
- printing_contents_pending_deletion_set_.insert(preview_contents); |
+ Observer* observer = i->second; |
+ printing_contents_map_.erase(i); |
+ delete observer; |
+ |
+ // ... and mortally wound the contents. (Deletion immediately is not a good |
+ // idea in case this was called from RenderViewGone.) |
base::MessageLoop::current()->DeleteSoon(FROM_HERE, preview_contents); |
} |
-bool BackgroundPrintingManager::HasSharedRenderProcessHost( |
- const WebContentsSet& set, WebContents* preview_contents) { |
- content::RenderProcessHost* rph = preview_contents->GetRenderProcessHost(); |
- for (WebContentsSet::const_iterator it = set.begin(); it != set.end(); ++it) { |
- WebContents* iter_contents = *it; |
- if (iter_contents == preview_contents) |
- continue; |
- if (iter_contents->GetRenderProcessHost() == rph) |
- return true; |
+std::set<content::WebContents*> BackgroundPrintingManager::CurrentContentSet() { |
+ std::set<content::WebContents*> result; |
+ for (WebContentsObserverMap::iterator i = printing_contents_map_.begin(); |
+ i != printing_contents_map_.end(); ++i) { |
+ result.insert(i->first); |
} |
- return false; |
-} |
- |
-BackgroundPrintingManager::WebContentsSet::const_iterator |
- BackgroundPrintingManager::begin() { |
- return printing_contents_set_.begin(); |
-} |
- |
-BackgroundPrintingManager::WebContentsSet::const_iterator |
- BackgroundPrintingManager::end() { |
- return printing_contents_set_.end(); |
+ return result; |
} |
bool BackgroundPrintingManager::HasPrintPreviewDialog( |
WebContents* preview_dialog) { |
- return (ContainsKey(printing_contents_set_, preview_dialog) || |
- ContainsKey(printing_contents_pending_deletion_set_, preview_dialog)); |
+ return ContainsKey(printing_contents_map_, preview_dialog); |
} |
} // namespace printing |