1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/printing/background_printing_manager.h" 6 7 #include "base/stl_util.h" 8 #include "chrome/browser/chrome_notification_types.h" 9 #include "chrome/browser/printing/print_job.h" 10 #include "chrome/browser/printing/print_preview_dialog_controller.h" 11 #include "content/public/browser/browser_thread.h" 12 #include "content/public/browser/notification_details.h" 13 #include "content/public/browser/notification_source.h" 14 #include "content/public/browser/render_view_host.h" 15 #include "content/public/browser/web_contents.h" 16 #include "content/public/browser/web_contents_delegate.h" 17 #include "content/public/browser/web_contents_observer.h" 18 19 using content::BrowserThread; 20 using content::WebContents; 21 22 namespace printing { 23 24 class BackgroundPrintingManager::Observer 25 : public content::WebContentsObserver { 26 public: 27 Observer(BackgroundPrintingManager* manager, WebContents* web_contents); 28 29 private: 30 virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE; 31 virtual void WebContentsDestroyed() OVERRIDE; 32 33 BackgroundPrintingManager* manager_; 34 }; 35 36 BackgroundPrintingManager::Observer::Observer( 37 BackgroundPrintingManager* manager, WebContents* web_contents) 38 : content::WebContentsObserver(web_contents), 39 manager_(manager) { 40 } 41 42 void BackgroundPrintingManager::Observer::RenderProcessGone( 43 base::TerminationStatus status) { 44 manager_->DeletePreviewContents(web_contents()); 45 } 46 void BackgroundPrintingManager::Observer::WebContentsDestroyed() { 47 manager_->DeletePreviewContents(web_contents()); 48 } 49 50 BackgroundPrintingManager::BackgroundPrintingManager() { 51 DCHECK_CURRENTLY_ON(BrowserThread::UI); 52 } 53 54 BackgroundPrintingManager::~BackgroundPrintingManager() { 55 DCHECK(CalledOnValidThread()); 56 // The might be some WebContentses still in |printing_contents_map_| at this 57 // point (e.g. when the last remaining tab closes and there is still a print 58 // preview WebContents trying to print). In such a case it will fail to print, 59 // but we should at least clean up the observers. 60 // TODO(thestig): Handle this case better. 61 STLDeleteValues(&printing_contents_map_); 62 } 63 64 void BackgroundPrintingManager::OwnPrintPreviewDialog( 65 WebContents* preview_dialog) { 66 DCHECK(CalledOnValidThread()); 67 DCHECK(PrintPreviewDialogController::IsPrintPreviewDialog(preview_dialog)); 68 CHECK(!HasPrintPreviewDialog(preview_dialog)); 69 70 printing_contents_map_[preview_dialog] = new Observer(this, preview_dialog); 71 72 // Watch for print jobs finishing. Everything else is watched for by the 73 // Observer. TODO(avi, cait): finish the job of removing this last 74 // notification. 75 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, 76 content::Source<WebContents>(preview_dialog)); 77 78 // Activate the initiator. 79 PrintPreviewDialogController* dialog_controller = 80 PrintPreviewDialogController::GetInstance(); 81 if (!dialog_controller) 82 return; 83 WebContents* initiator = dialog_controller->GetInitiator(preview_dialog); 84 if (!initiator) 85 return; 86 initiator->GetDelegate()->ActivateContents(initiator); 87 } 88 89 void BackgroundPrintingManager::Observe( 90 int type, 91 const content::NotificationSource& source, 92 const content::NotificationDetails& details) { 93 DCHECK_EQ(chrome::NOTIFICATION_PRINT_JOB_RELEASED, type); 94 DeletePreviewContents(content::Source<WebContents>(source).ptr()); 95 } 96 97 void BackgroundPrintingManager::DeletePreviewContents( 98 WebContents* preview_contents) { 99 WebContentsObserverMap::iterator i = 100 printing_contents_map_.find(preview_contents); 101 if (i == printing_contents_map_.end()) { 102 // Everyone is racing to be the first to delete the |preview_contents|. If 103 // this case is hit, someone else won the race, so there is no need to 104 // continue. <http://crbug.com/100806> 105 return; 106 } 107 108 // Stop all observation ... 109 registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, 110 content::Source<WebContents>(preview_contents)); 111 Observer* observer = i->second; 112 printing_contents_map_.erase(i); 113 delete observer; 114 115 // ... and mortally wound the contents. (Deletion immediately is not a good 116 // idea in case this was called from RenderViewGone.) 117 base::MessageLoop::current()->DeleteSoon(FROM_HERE, preview_contents); 118 } 119 120 std::set<content::WebContents*> BackgroundPrintingManager::CurrentContentSet() { 121 std::set<content::WebContents*> result; 122 for (WebContentsObserverMap::iterator i = printing_contents_map_.begin(); 123 i != printing_contents_map_.end(); ++i) { 124 result.insert(i->first); 125 } 126 return result; 127 } 128 129 bool BackgroundPrintingManager::HasPrintPreviewDialog( 130 WebContents* preview_dialog) { 131 return ContainsKey(printing_contents_map_, preview_dialog); 132 } 133 134 } // namespace printing 135