Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: chrome/browser/printing/background_printing_manager.cc

Issue 133013002: Remove render process and WebContents notifications from background printing. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/printing/background_printing_manager.h" 5 #include "chrome/browser/printing/background_printing_manager.h"
6 6
7 #include "base/stl_util.h" 7 #include "base/stl_util.h"
8 #include "chrome/browser/chrome_notification_types.h" 8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/printing/print_job.h" 9 #include "chrome/browser/printing/print_job.h"
10 #include "chrome/browser/printing/print_preview_dialog_controller.h" 10 #include "chrome/browser/printing/print_preview_dialog_controller.h"
11 #include "content/public/browser/browser_thread.h" 11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/notification_details.h" 12 #include "content/public/browser/notification_details.h"
13 #include "content/public/browser/notification_source.h" 13 #include "content/public/browser/notification_source.h"
14 #include "content/public/browser/render_view_host.h" 14 #include "content/public/browser/render_view_host.h"
15 #include "content/public/browser/web_contents.h" 15 #include "content/public/browser/web_contents.h"
16 #include "content/public/browser/web_contents_delegate.h" 16 #include "content/public/browser/web_contents_delegate.h"
17 #include "content/public/browser/web_contents_observer.h"
17 18
18 using content::BrowserThread; 19 using content::BrowserThread;
19 using content::WebContents; 20 using content::WebContents;
20 21
21 namespace printing { 22 namespace printing {
22 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(WebContents* web_contents) 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 WebContents* web_contents) {
48 manager_->DeletePreviewContents(web_contents);
49 }
50
23 BackgroundPrintingManager::BackgroundPrintingManager() { 51 BackgroundPrintingManager::BackgroundPrintingManager() {
24 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 52 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
25 } 53 }
26 54
27 BackgroundPrintingManager::~BackgroundPrintingManager() { 55 BackgroundPrintingManager::~BackgroundPrintingManager() {
28 DCHECK(CalledOnValidThread()); 56 DCHECK(CalledOnValidThread());
29 // The might be some WebContentses still in |printing_contents_set_| at this 57 // The might be some WebContentses still in |printing_contents_set_| at this
Lei Zhang 2014/01/11 02:35:22 |printing_contents_set_| -> |printing_contents_map
Avi (use Gerrit) 2014/01/11 19:12:49 Done.
30 // point. E.g. when the last remaining tab closes and there is still a print 58 // point (e.g. when the last remaining tab closes and there is still a print
31 // preview WebContents trying to print. In which case it will fail to print. 59 // preview WebContents trying to print). In such a case it will fail to print,
60 // but we should at least clean up the observers.
32 // TODO(thestig): Handle this case better. 61 // TODO(thestig): Handle this case better.
62 STLDeleteValues(&printing_contents_map_);
33 } 63 }
34 64
35 void BackgroundPrintingManager::OwnPrintPreviewDialog( 65 void BackgroundPrintingManager::OwnPrintPreviewDialog(
36 WebContents* preview_dialog) { 66 WebContents* preview_dialog) {
37 DCHECK(CalledOnValidThread()); 67 DCHECK(CalledOnValidThread());
38 DCHECK(PrintPreviewDialogController::IsPrintPreviewDialog(preview_dialog)); 68 DCHECK(PrintPreviewDialogController::IsPrintPreviewDialog(preview_dialog));
39 CHECK(!HasPrintPreviewDialog(preview_dialog)); 69 CHECK(!HasPrintPreviewDialog(preview_dialog));
40 70
41 printing_contents_set_.insert(preview_dialog); 71 Observer* observer = new Observer(this, preview_dialog);
Lei Zhang 2014/01/11 02:35:22 nit: no need for the |observer| variable
Avi (use Gerrit) 2014/01/11 19:12:49 Done.
72 printing_contents_map_[preview_dialog] = observer;
42 73
43 content::Source<WebContents> preview_source(preview_dialog); 74 // Watch for print jobs finishing. Everything else is watched for by the
44 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, preview_source); 75 // Observer. TODO(avi, cait): finish the job of removing this last
45 76 // notification.
46 // OwnInitiatorWebContents() may have already added this notification. 77 registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
47 if (!registrar_.IsRegistered(this, 78 content::Source<WebContents>(preview_dialog));
48 content::NOTIFICATION_WEB_CONTENTS_DESTROYED, preview_source)) {
49 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
50 preview_source);
51 }
52
53 // If a WebContents that is printing crashes, the user cannot destroy it since
54 // it is hidden. Thus listen for crashes here and delete it.
55 //
56 // Multiple sites may share the same RenderProcessHost, so check if this
57 // notification has already been added.
58 content::Source<content::RenderProcessHost> rph_source(
59 preview_dialog->GetRenderProcessHost());
60 if (!registrar_.IsRegistered(this,
61 content::NOTIFICATION_RENDERER_PROCESS_CLOSED, rph_source)) {
62 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
63 rph_source);
64 }
65 79
66 // Activate the initiator. 80 // Activate the initiator.
67 PrintPreviewDialogController* dialog_controller = 81 PrintPreviewDialogController* dialog_controller =
68 PrintPreviewDialogController::GetInstance(); 82 PrintPreviewDialogController::GetInstance();
69 if (!dialog_controller) 83 if (!dialog_controller)
70 return; 84 return;
71 WebContents* initiator = dialog_controller->GetInitiator(preview_dialog); 85 WebContents* initiator = dialog_controller->GetInitiator(preview_dialog);
72 if (!initiator) 86 if (!initiator)
73 return; 87 return;
74 initiator->GetDelegate()->ActivateContents(initiator); 88 initiator->GetDelegate()->ActivateContents(initiator);
75 } 89 }
76 90
77 void BackgroundPrintingManager::Observe( 91 void BackgroundPrintingManager::Observe(
78 int type, 92 int type,
79 const content::NotificationSource& source, 93 const content::NotificationSource& source,
80 const content::NotificationDetails& details) { 94 const content::NotificationDetails& details) {
81 if (type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED) { 95 DCHECK_EQ(chrome::NOTIFICATION_PRINT_JOB_RELEASED, type);
82 OnRendererProcessClosed( 96 DeletePreviewContents(content::Source<WebContents>(source).ptr());
83 content::Source<content::RenderProcessHost>(source).ptr());
84 } else if (type == chrome::NOTIFICATION_PRINT_JOB_RELEASED) {
85 OnPrintJobReleased(content::Source<WebContents>(source).ptr());
86 } else {
87 DCHECK_EQ(content::NOTIFICATION_WEB_CONTENTS_DESTROYED, type);
88 OnWebContentsDestroyed(content::Source<WebContents>(source).ptr());
89 }
90 }
91
92 void BackgroundPrintingManager::OnRendererProcessClosed(
93 content::RenderProcessHost* rph) {
94 WebContentsSet printing_contents_pending_deletion_set;
95 WebContentsSet::const_iterator it;
96 for (it = begin(); it != end(); ++it) {
97 WebContents* preview_contents = *it;
98 if (preview_contents->GetRenderProcessHost() == rph) {
99 printing_contents_pending_deletion_set.insert(preview_contents);
100 }
101 }
102 for (it = printing_contents_pending_deletion_set.begin();
103 it != printing_contents_pending_deletion_set.end();
104 ++it) {
105 DeletePreviewContents(*it);
106 }
107 }
108
109 void BackgroundPrintingManager::OnPrintJobReleased(
110 WebContents* preview_contents) {
111 DeletePreviewContents(preview_contents);
112 }
113
114 void BackgroundPrintingManager::OnWebContentsDestroyed(
115 WebContents* preview_contents) {
116 // Always need to remove this notification since the WebContents is gone.
117 content::Source<WebContents> preview_source(preview_contents);
118 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
119 preview_source);
120
121 if (!HasPrintPreviewDialog(preview_contents)) {
122 NOTREACHED();
123 return;
124 }
125
126 // Remove NOTIFICATION_RENDERER_PROCESS_CLOSED if |preview_contents| is the
127 // last WebContents associated with |rph|.
128 bool shared_rph =
129 (HasSharedRenderProcessHost(printing_contents_set_, preview_contents) ||
130 HasSharedRenderProcessHost(printing_contents_pending_deletion_set_,
131 preview_contents));
132 if (!shared_rph) {
133 content::RenderProcessHost* rph = preview_contents->GetRenderProcessHost();
134 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
135 content::Source<content::RenderProcessHost>(rph));
136 }
137
138 // Remove other notifications and remove the WebContents from its
139 // WebContentsSet.
140 if (printing_contents_set_.erase(preview_contents) == 1) {
141 registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
142 preview_source);
143 } else {
144 // DeletePreviewContents already deleted the notification.
145 printing_contents_pending_deletion_set_.erase(preview_contents);
146 }
147 } 97 }
148 98
149 void BackgroundPrintingManager::DeletePreviewContents( 99 void BackgroundPrintingManager::DeletePreviewContents(
150 WebContents* preview_contents) { 100 WebContents* preview_contents) {
101 if (!ContainsKey(printing_contents_map_, preview_contents)) {
Lei Zhang 2014/01/11 02:35:22 If you save the iterator here instead, you can re-
Avi (use Gerrit) 2014/01/11 19:12:49 Done.
102 // This is a reasonable case, hit when the release of the print job races
103 // deletion of the render process. In this case, everything is already torn
104 // down and there is no need to continue. <http://crbug.com/100806>
105 return;
106 }
107
108 // Stop all observation ...
151 registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, 109 registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
152 content::Source<WebContents>(preview_contents)); 110 content::Source<WebContents>(preview_contents));
153 printing_contents_set_.erase(preview_contents); 111 Observer* observer = printing_contents_map_[preview_contents];
154 printing_contents_pending_deletion_set_.insert(preview_contents); 112 printing_contents_map_.erase(preview_contents);
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.)
155 base::MessageLoop::current()->DeleteSoon(FROM_HERE, preview_contents); 117 base::MessageLoop::current()->DeleteSoon(FROM_HERE, preview_contents);
156 } 118 }
157 119
158 bool BackgroundPrintingManager::HasSharedRenderProcessHost( 120 std::set<content::WebContents*> BackgroundPrintingManager::CurrentContentSet() {
159 const WebContentsSet& set, WebContents* preview_contents) { 121 std::set<content::WebContents*> result;
160 content::RenderProcessHost* rph = preview_contents->GetRenderProcessHost(); 122 for (WebContentsObserverMap::iterator i = printing_contents_map_.begin();
161 for (WebContentsSet::const_iterator it = set.begin(); it != set.end(); ++it) { 123 i != printing_contents_map_.end(); ++i) {
162 WebContents* iter_contents = *it; 124 result.insert(i->first);
163 if (iter_contents == preview_contents)
164 continue;
165 if (iter_contents->GetRenderProcessHost() == rph)
166 return true;
167 } 125 }
168 return false; 126 return result;
169 }
170
171 BackgroundPrintingManager::WebContentsSet::const_iterator
172 BackgroundPrintingManager::begin() {
173 return printing_contents_set_.begin();
174 }
175
176 BackgroundPrintingManager::WebContentsSet::const_iterator
177 BackgroundPrintingManager::end() {
178 return printing_contents_set_.end();
179 } 127 }
180 128
181 bool BackgroundPrintingManager::HasPrintPreviewDialog( 129 bool BackgroundPrintingManager::HasPrintPreviewDialog(
182 WebContents* preview_dialog) { 130 WebContents* preview_dialog) {
183 return (ContainsKey(printing_contents_set_, preview_dialog) || 131 return ContainsKey(printing_contents_map_, preview_dialog);
184 ContainsKey(printing_contents_pending_deletion_set_, preview_dialog));
185 } 132 }
186 133
187 } // namespace printing 134 } // namespace printing
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698