// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/printing/background_printing_manager.h" #include "base/stl_util.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/printing/print_job.h" #include "chrome/browser/printing/print_preview_dialog_controller.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_source.h" #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() 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() { manager_->DeletePreviewContents(web_contents()); } BackgroundPrintingManager::BackgroundPrintingManager() { DCHECK_CURRENTLY_ON(BrowserThread::UI); } BackgroundPrintingManager::~BackgroundPrintingManager() { DCHECK(CalledOnValidThread()); // 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( WebContents* preview_dialog) { DCHECK(CalledOnValidThread()); DCHECK(PrintPreviewDialogController::IsPrintPreviewDialog(preview_dialog)); CHECK(!HasPrintPreviewDialog(preview_dialog)); printing_contents_map_[preview_dialog] = new Observer(this, preview_dialog); // 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 = PrintPreviewDialogController::GetInstance(); if (!dialog_controller) return; WebContents* initiator = dialog_controller->GetInitiator(preview_dialog); if (!initiator) return; initiator->GetDelegate()->ActivateContents(initiator); } void BackgroundPrintingManager::Observe( int type, const content::NotificationSource& source, const content::NotificationDetails& details) { DCHECK_EQ(chrome::NOTIFICATION_PRINT_JOB_RELEASED, type); DeletePreviewContents(content::Source<WebContents>(source).ptr()); } void BackgroundPrintingManager::DeletePreviewContents( WebContents* preview_contents) { 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; } // Stop all observation ... registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, content::Source<WebContents>(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); } 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 result; } bool BackgroundPrintingManager::HasPrintPreviewDialog( WebContents* preview_dialog) { return ContainsKey(printing_contents_map_, preview_dialog); } } // namespace printing