Index: chrome/browser/printing/print_preview_dialog_controller.cc |
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc |
index 1f0769c9dc86554ddc0120d255eaa2a3d4085c10..e190f01be432ef9ea56a5327c3e6c14d5a1c2669 100644 |
--- a/chrome/browser/printing/print_preview_dialog_controller.cc |
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc |
@@ -6,7 +6,6 @@ |
#include <algorithm> |
#include <string> |
-#include <vector> |
#include "base/auto_reset.h" |
#include "base/path_service.h" |
@@ -31,14 +30,14 @@ |
#include "content/public/browser/navigation_controller.h" |
#include "content/public/browser/navigation_details.h" |
#include "content/public/browser/navigation_entry.h" |
-#include "content/public/browser/notification_details.h" |
-#include "content/public/browser/notification_source.h" |
#include "content/public/browser/plugin_service.h" |
#include "content/public/browser/render_frame_host.h" |
#include "content/public/browser/render_process_host.h" |
+#include "content/public/browser/render_process_host_observer.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" |
#include "content/public/browser/web_contents_view.h" |
#include "content/public/common/webplugininfo.h" |
#include "ui/web_dialogs/web_dialog_delegate.h" |
@@ -46,6 +45,7 @@ |
using content::NativeWebKeyboardEvent; |
using content::NavigationController; |
+using content::RenderProcessHost; |
using content::WebContents; |
using content::WebUIMessageHandler; |
using ui::WebDialogDelegate; |
@@ -209,6 +209,97 @@ void PrintPreviewWebContentDelegate::HandleKeyboardEvent( |
namespace printing { |
+struct PrintPreviewDialogController::Operation { |
+ class Observer : public content::WebContentsObserver, |
+ public content::RenderProcessHostObserver { |
+ public: |
+ Observer(); |
+ virtual ~Observer(); |
+ |
+ void StartObserving(PrintPreviewDialogController* owner, |
+ WebContents* web_contents); |
+ void StopObserving(); |
+ |
+ private: |
+ // content::WebContentsObserver |
+ virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE; |
+ virtual void NavigationEntryCommitted( |
+ const content::LoadCommittedDetails& load_details) OVERRIDE; |
+ // content::RenderProcessHostObserver |
+ virtual void RenderProcessExited(RenderProcessHost* host, |
+ base::ProcessHandle handle, |
+ base::TerminationStatus status, |
+ int exit_code) OVERRIDE; |
+ virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE; |
+ |
+ PrintPreviewDialogController* owner_; |
+ RenderProcessHost* host_; |
+ }; |
+ |
+ Operation(); |
+ |
+ WebContents* preview_dialog; |
+ WebContents* initiator; |
+ Observer preview_dialog_observer; |
+ Observer initiator_observer; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(Operation); |
+}; |
+ |
+PrintPreviewDialogController::Operation::Operation() : preview_dialog(NULL), |
+ initiator(NULL) { |
+} |
+ |
+PrintPreviewDialogController::Operation::Observer::Observer() : owner_(NULL), |
+ host_(NULL) { |
+} |
+ |
+PrintPreviewDialogController::Operation::Observer::~Observer() { |
+ StopObserving(); |
+} |
+ |
+void PrintPreviewDialogController::Operation::Observer::StartObserving( |
+ PrintPreviewDialogController* owner, |
+ WebContents* web_contents) { |
+ owner_ = owner; |
+ Observe(web_contents); |
+ host_ = web_contents->GetRenderProcessHost(); |
+ host_->AddObserver(this); |
+} |
+ |
+void PrintPreviewDialogController::Operation::Observer::StopObserving() { |
+ Observe(NULL); |
+ if (host_) { |
+ host_->RemoveObserver(this); |
+ host_ = NULL; |
+ } |
+} |
+ |
+void PrintPreviewDialogController::Operation::Observer::WebContentsDestroyed( |
+ WebContents* web_contents) { |
+ owner_->OnWebContentsDestroyed(web_contents); |
+} |
+ |
+void |
+PrintPreviewDialogController::Operation::Observer::NavigationEntryCommitted( |
+ const content::LoadCommittedDetails& load_details) { |
+ owner_->OnNavigationEntryCommitted(web_contents(), &load_details); |
+} |
+ |
+void PrintPreviewDialogController::Operation::Observer::RenderProcessExited( |
+ RenderProcessHost* host, |
+ base::ProcessHandle handle, |
+ base::TerminationStatus status, |
+ int exit_code) { |
+ owner_->OnRenderProcessExited(host); |
+} |
+ |
+void |
+PrintPreviewDialogController::Operation::Observer::RenderProcessHostDestroyed( |
+ RenderProcessHost* host) { |
+ host_ = NULL; |
+} |
+ |
PrintPreviewDialogController::PrintPreviewDialogController() |
: waiting_for_new_preview_page_(false), |
is_creating_print_preview_dialog_(false) { |
@@ -249,19 +340,11 @@ WebContents* PrintPreviewDialogController::GetOrCreatePreviewDialog( |
WebContents* PrintPreviewDialogController::GetPrintPreviewForContents( |
WebContents* contents) const { |
- // |preview_dialog_map_| is keyed by the preview dialog, so if find() |
- // succeeds, then |contents| is the preview dialog. |
- PrintPreviewDialogMap::const_iterator it = preview_dialog_map_.find(contents); |
- if (it != preview_dialog_map_.end()) |
- return contents; |
- |
- for (it = preview_dialog_map_.begin(); |
- it != preview_dialog_map_.end(); |
- ++it) { |
- // If |contents| is an initiator. |
- if (contents == it->second) { |
- // Return the associated preview dialog. |
- return it->first; |
+ for (size_t i = 0; i < preview_operations_.size(); ++i) { |
+ Operation* operation = preview_operations_[i]; |
+ if (operation->preview_dialog == contents || |
+ operation->initiator == contents) { |
+ return operation->preview_dialog; |
} |
} |
return NULL; |
@@ -269,27 +352,12 @@ WebContents* PrintPreviewDialogController::GetPrintPreviewForContents( |
WebContents* PrintPreviewDialogController::GetInitiator( |
WebContents* preview_dialog) { |
- PrintPreviewDialogMap::iterator it = preview_dialog_map_.find(preview_dialog); |
- return (it != preview_dialog_map_.end()) ? it->second : NULL; |
-} |
- |
-void PrintPreviewDialogController::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 == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { |
- OnWebContentsDestroyed(content::Source<WebContents>(source).ptr()); |
- } else { |
- DCHECK_EQ(content::NOTIFICATION_NAV_ENTRY_COMMITTED, type); |
- WebContents* contents = |
- content::Source<NavigationController>(source)->GetWebContents(); |
- OnNavEntryCommitted( |
- contents, |
- content::Details<content::LoadCommittedDetails>(details).ptr()); |
+ for (size_t i = 0; i < preview_operations_.size(); ++i) { |
+ Operation* operation = preview_operations_[i]; |
+ if (operation->preview_dialog == preview_dialog) |
+ return operation->initiator; |
} |
+ return NULL; |
} |
// static |
@@ -305,26 +373,30 @@ bool PrintPreviewDialogController::IsPrintPreviewURL(const GURL& url) { |
void PrintPreviewDialogController::EraseInitiatorInfo( |
WebContents* preview_dialog) { |
- PrintPreviewDialogMap::iterator it = preview_dialog_map_.find(preview_dialog); |
- if (it == preview_dialog_map_.end()) |
- return; |
- |
- RemoveObservers(it->second); |
- preview_dialog_map_[preview_dialog] = NULL; |
+ for (size_t i = 0; i < preview_operations_.size(); ++i) { |
+ Operation* operation = preview_operations_[i]; |
+ if (operation->preview_dialog == preview_dialog) { |
+ operation->initiator_observer.StopObserving(); |
+ operation->initiator = NULL; |
+ return; |
+ } |
+ } |
} |
-PrintPreviewDialogController::~PrintPreviewDialogController() {} |
+PrintPreviewDialogController::~PrintPreviewDialogController() { |
+ DCHECK_EQ(0U, preview_operations_.size()); |
+} |
-void PrintPreviewDialogController::OnRendererProcessClosed( |
- content::RenderProcessHost* rph) { |
+void PrintPreviewDialogController::OnRenderProcessExited( |
+ RenderProcessHost* rph) { |
// Store contents in a vector and deal with them after iterating through |
- // |preview_dialog_map_| because RemoveFoo() can change |preview_dialog_map_|. |
+ // |preview_operations_| because RemoveFoo() can change |preview_operations_|. |
std::vector<WebContents*> closed_initiators; |
std::vector<WebContents*> closed_preview_dialogs; |
- for (PrintPreviewDialogMap::iterator iter = preview_dialog_map_.begin(); |
- iter != preview_dialog_map_.end(); ++iter) { |
- WebContents* preview_dialog = iter->first; |
- WebContents* initiator = iter->second; |
+ for (size_t i = 0; i < preview_operations_.size(); ++i) { |
+ Operation* operation = preview_operations_[i]; |
+ WebContents* preview_dialog = operation->preview_dialog; |
+ WebContents* initiator = operation->initiator; |
if (preview_dialog->GetRenderProcessHost() == rph) { |
closed_preview_dialogs.push_back(preview_dialog); |
} else if (initiator && |
@@ -359,8 +431,8 @@ void PrintPreviewDialogController::OnWebContentsDestroyed( |
RemoveInitiator(contents); |
} |
-void PrintPreviewDialogController::OnNavEntryCommitted( |
- WebContents* contents, content::LoadCommittedDetails* details) { |
+void PrintPreviewDialogController::OnNavigationEntryCommitted( |
+ WebContents* contents, const content::LoadCommittedDetails* details) { |
WebContents* preview_dialog = GetPrintPreviewForContents(contents); |
if (!preview_dialog) { |
NOTREACHED(); |
@@ -420,12 +492,15 @@ WebContents* PrintPreviewDialogController::CreatePrintPreviewDialog( |
EnableInternalPDFPluginForContents(preview_dialog); |
PrintViewManager::CreateForWebContents(preview_dialog); |
- // Add an entry to the map. |
- preview_dialog_map_[preview_dialog] = initiator; |
waiting_for_new_preview_page_ = true; |
- AddObservers(initiator); |
- AddObservers(preview_dialog); |
+ // Add an entry to the map. |
+ Operation* operation = new Operation; |
+ operation->preview_dialog = preview_dialog; |
+ operation->initiator = initiator; |
+ operation->preview_dialog_observer.StartObserving(this, preview_dialog); |
+ operation->initiator_observer.StartObserving(this, initiator); |
+ preview_operations_.push_back(operation); |
return preview_dialog; |
} |
@@ -441,49 +516,15 @@ void PrintPreviewDialogController::SaveInitiatorTitle( |
} |
} |
-void PrintPreviewDialogController::AddObservers(WebContents* contents) { |
- registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
- content::Source<WebContents>(contents)); |
- registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
- content::Source<NavigationController>(&contents->GetController())); |
- |
- // Multiple sites may share the same RenderProcessHost, so check if this |
- // notification has already been added. |
- content::Source<content::RenderProcessHost> rph_source( |
- contents->GetRenderProcessHost()); |
- if (!registrar_.IsRegistered(this, |
- content::NOTIFICATION_RENDERER_PROCESS_CLOSED, rph_source)) { |
- registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
- rph_source); |
- } |
-} |
- |
-void PrintPreviewDialogController::RemoveObservers(WebContents* contents) { |
- registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
- content::Source<WebContents>(contents)); |
- registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, |
- content::Source<NavigationController>(&contents->GetController())); |
- |
- // Multiple sites may share the same RenderProcessHost, so check if this |
- // notification has already been added. |
- content::Source<content::RenderProcessHost> rph_source( |
- contents->GetRenderProcessHost()); |
- if (registrar_.IsRegistered(this, |
- content::NOTIFICATION_RENDERER_PROCESS_CLOSED, rph_source)) { |
- registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
- rph_source); |
- } |
-} |
- |
void PrintPreviewDialogController::RemoveInitiator( |
WebContents* initiator) { |
WebContents* preview_dialog = GetPrintPreviewForContents(initiator); |
DCHECK(preview_dialog); |
+ |
// Update the map entry first, so when the print preview dialog gets destroyed |
// and reaches RemovePreviewDialog(), it does not attempt to also remove the |
// initiator's observers. |
- preview_dialog_map_[preview_dialog] = NULL; |
- RemoveObservers(initiator); |
+ EraseInitiatorInfo(preview_dialog); |
PrintViewManager::FromWebContents(initiator)->PrintPreviewDone(); |
@@ -496,22 +537,30 @@ void PrintPreviewDialogController::RemoveInitiator( |
void PrintPreviewDialogController::RemovePreviewDialog( |
WebContents* preview_dialog) { |
- // Remove the initiator's observers before erasing the mapping. |
- WebContents* initiator = GetInitiator(preview_dialog); |
- if (initiator) { |
- RemoveObservers(initiator); |
- PrintViewManager::FromWebContents(initiator)->PrintPreviewDone(); |
- } |
+ for (size_t i = 0; i < preview_operations_.size(); ++i) { |
+ Operation* operation = preview_operations_[i]; |
+ if (operation->preview_dialog == preview_dialog) { |
+ // Remove the initiator's observers before erasing the mapping. |
+ if (operation->initiator) { |
+ operation->initiator_observer.StopObserving(); |
+ PrintViewManager::FromWebContents(operation->initiator)-> |
+ PrintPreviewDone(); |
+ } |
- // Print preview WebContents is destroyed. Notify |PrintPreviewUI| to abort |
- // the initiator preview request. |
- PrintPreviewUI* print_preview_ui = |
- static_cast<PrintPreviewUI*>(preview_dialog->GetWebUI()->GetController()); |
- if (print_preview_ui) |
- print_preview_ui->OnPrintPreviewDialogDestroyed(); |
+ // Print preview WebContents is destroyed. Notify |PrintPreviewUI| to |
+ // abort the initiator preview request. |
+ PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>( |
+ preview_dialog->GetWebUI()->GetController()); |
+ if (print_preview_ui) |
+ print_preview_ui->OnPrintPreviewDialogDestroyed(); |
+ |
+ preview_operations_.erase(preview_operations_.begin() + i); |
+ delete operation; |
- preview_dialog_map_.erase(preview_dialog); |
- RemoveObservers(preview_dialog); |
+ return; |
+ } |
+ } |
+ NOTREACHED(); |
} |
} // namespace printing |