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 6694af39666b622e31dfe77c4254730310c47bf7..27d365fb4fffb31f2eb155d8ddd25a582cfd4322 100644 |
--- a/chrome/browser/printing/print_preview_dialog_controller.cc |
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc |
@@ -6,6 +6,7 @@ |
#include <algorithm> |
#include <string> |
+#include <vector> |
#include "base/auto_reset.h" |
#include "base/path_service.h" |
@@ -31,14 +32,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,7 +47,6 @@ |
using content::NativeWebKeyboardEvent; |
using content::NavigationController; |
-using content::RenderProcessHost; |
using content::WebContents; |
using content::WebUIMessageHandler; |
using ui::WebDialogDelegate; |
@@ -210,97 +210,6 @@ 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) { |
@@ -341,11 +250,19 @@ WebContents* PrintPreviewDialogController::GetOrCreatePreviewDialog( |
WebContents* PrintPreviewDialogController::GetPrintPreviewForContents( |
WebContents* contents) const { |
- 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; |
+ // |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; |
} |
} |
return NULL; |
@@ -353,18 +270,35 @@ WebContents* PrintPreviewDialogController::GetPrintPreviewForContents( |
WebContents* PrintPreviewDialogController::GetInitiator( |
WebContents* preview_dialog) { |
- for (size_t i = 0; i < preview_operations_.size(); ++i) { |
- Operation* operation = preview_operations_[i]; |
- if (operation->preview_dialog == preview_dialog) |
- return operation->initiator; |
+ 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()); |
} |
- return NULL; |
} |
void PrintPreviewDialogController::ForEachPreviewDialog( |
base::Callback<void(content::WebContents*)> callback) { |
- for (size_t i = 0; i < preview_operations_.size(); ++i) { |
- callback.Run(preview_operations_[i]->preview_dialog); |
+ for (PrintPreviewDialogMap::const_iterator it = preview_dialog_map_.begin(); |
+ it != preview_dialog_map_.end(); |
+ ++it) { |
+ callback.Run(it->first); |
} |
} |
@@ -381,30 +315,26 @@ bool PrintPreviewDialogController::IsPrintPreviewURL(const GURL& url) { |
void PrintPreviewDialogController::EraseInitiatorInfo( |
WebContents* preview_dialog) { |
- 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; |
- } |
- } |
-} |
+ PrintPreviewDialogMap::iterator it = preview_dialog_map_.find(preview_dialog); |
+ if (it == preview_dialog_map_.end()) |
+ return; |
-PrintPreviewDialogController::~PrintPreviewDialogController() { |
- DCHECK_EQ(0U, preview_operations_.size()); |
+ RemoveObservers(it->second); |
+ preview_dialog_map_[preview_dialog] = NULL; |
} |
-void PrintPreviewDialogController::OnRenderProcessExited( |
- RenderProcessHost* rph) { |
+PrintPreviewDialogController::~PrintPreviewDialogController() {} |
+ |
+void PrintPreviewDialogController::OnRendererProcessClosed( |
+ content::RenderProcessHost* rph) { |
// Store contents in a vector and deal with them after iterating through |
- // |preview_operations_| because RemoveFoo() can change |preview_operations_|. |
+ // |preview_dialog_map_| because RemoveFoo() can change |preview_dialog_map_|. |
std::vector<WebContents*> closed_initiators; |
std::vector<WebContents*> closed_preview_dialogs; |
- 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; |
+ for (PrintPreviewDialogMap::iterator iter = preview_dialog_map_.begin(); |
+ iter != preview_dialog_map_.end(); ++iter) { |
+ WebContents* preview_dialog = iter->first; |
+ WebContents* initiator = iter->second; |
if (preview_dialog->GetRenderProcessHost() == rph) { |
closed_preview_dialogs.push_back(preview_dialog); |
} else if (initiator && |
@@ -441,8 +371,8 @@ void PrintPreviewDialogController::OnWebContentsDestroyed( |
RemoveInitiator(contents); |
} |
-void PrintPreviewDialogController::OnNavigationEntryCommitted( |
- WebContents* contents, const content::LoadCommittedDetails* details) { |
+void PrintPreviewDialogController::OnNavEntryCommitted( |
+ WebContents* contents, content::LoadCommittedDetails* details) { |
WebContents* preview_dialog = GetPrintPreviewForContents(contents); |
if (!preview_dialog) { |
NOTREACHED(); |
@@ -504,15 +434,12 @@ WebContents* PrintPreviewDialogController::CreatePrintPreviewDialog( |
extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( |
preview_dialog); |
+ // Add an entry to the map. |
+ preview_dialog_map_[preview_dialog] = initiator; |
waiting_for_new_preview_page_ = true; |
- // 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); |
+ AddObservers(initiator); |
+ AddObservers(preview_dialog); |
return preview_dialog; |
} |
@@ -528,15 +455,49 @@ 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. |
- EraseInitiatorInfo(preview_dialog); |
+ preview_dialog_map_[preview_dialog] = NULL; |
+ RemoveObservers(initiator); |
PrintViewManager::FromWebContents(initiator)->PrintPreviewDone(); |
@@ -551,32 +512,24 @@ void PrintPreviewDialogController::RemoveInitiator( |
void PrintPreviewDialogController::RemovePreviewDialog( |
WebContents* preview_dialog) { |
- 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. |
- if (content::WebUI* web_ui = preview_dialog->GetWebUI()) { |
- PrintPreviewUI* print_preview_ui = |
- static_cast<PrintPreviewUI*>(web_ui->GetController()); |
- if (print_preview_ui) |
- print_preview_ui->OnPrintPreviewDialogDestroyed(); |
- } |
- |
- preview_operations_.erase(preview_operations_.begin() + i); |
- delete operation; |
+ // Remove the initiator's observers before erasing the mapping. |
+ WebContents* initiator = GetInitiator(preview_dialog); |
+ if (initiator) { |
+ RemoveObservers(initiator); |
+ PrintViewManager::FromWebContents(initiator)->PrintPreviewDone(); |
+ } |
- return; |
- } |
+ // Print preview WebContents is destroyed. Notify |PrintPreviewUI| to abort |
+ // the initiator preview request. |
+ if (content::WebUI* web_ui = preview_dialog->GetWebUI()) { |
+ PrintPreviewUI* print_preview_ui = |
+ static_cast<PrintPreviewUI*>(web_ui->GetController()); |
+ if (print_preview_ui) |
+ print_preview_ui->OnPrintPreviewDialogDestroyed(); |
} |
- NOTREACHED(); |
+ |
+ preview_dialog_map_.erase(preview_dialog); |
+ RemoveObservers(preview_dialog); |
} |
} // namespace printing |