Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / printing / background_printing_manager.cc
index f0aa96a..1e5c58d 100644 (file)
 #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(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
 BackgroundPrintingManager::~BackgroundPrintingManager() {
   DCHECK(CalledOnValidThread());
-  // The might be some WebContentses still in |printing_contents_set_| at this
-  // point. E.g. when the last remaining tab closes and there is still a print
-  // preview WebContents trying to print. In which case it will fail to print.
+  // 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(
@@ -38,30 +67,13 @@ void BackgroundPrintingManager::OwnPrintPreviewDialog(
   DCHECK(PrintPreviewDialogController::IsPrintPreviewDialog(preview_dialog));
   CHECK(!HasPrintPreviewDialog(preview_dialog));
 
-  printing_contents_set_.insert(preview_dialog);
+  printing_contents_map_[preview_dialog] = new Observer(this, preview_dialog);
 
-  content::Source<WebContents> preview_source(preview_dialog);
-  registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, preview_source);
-
-  // OwnInitiatorWebContents() may have already added this notification.
-  if (!registrar_.IsRegistered(this,
-      content::NOTIFICATION_WEB_CONTENTS_DESTROYED, preview_source)) {
-    registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-                   preview_source);
-  }
-
-  // If a WebContents that is printing crashes, the user cannot destroy it since
-  // it is hidden. Thus listen for crashes here and delete it.
-  //
-  // Multiple sites may share the same RenderProcessHost, so check if this
-  // notification has already been added.
-  content::Source<content::RenderProcessHost> rph_source(
-      preview_dialog->GetRenderProcessHost());
-  if (!registrar_.IsRegistered(this,
-      content::NOTIFICATION_RENDERER_PROCESS_CLOSED, rph_source)) {
-    registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
-                   rph_source);
-  }
+  // 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 =
@@ -78,110 +90,45 @@ void BackgroundPrintingManager::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 == chrome::NOTIFICATION_PRINT_JOB_RELEASED) {
-    OnPrintJobReleased(content::Source<WebContents>(source).ptr());
-  } else {
-    DCHECK_EQ(content::NOTIFICATION_WEB_CONTENTS_DESTROYED, type);
-    OnWebContentsDestroyed(content::Source<WebContents>(source).ptr());
-  }
-}
-
-void BackgroundPrintingManager::OnRendererProcessClosed(
-    content::RenderProcessHost* rph) {
-  WebContentsSet printing_contents_pending_deletion_set;
-  WebContentsSet::const_iterator it;
-  for (it = begin(); it != end(); ++it) {
-    WebContents* preview_contents = *it;
-    if (preview_contents->GetRenderProcessHost() == rph) {
-      printing_contents_pending_deletion_set.insert(preview_contents);
-    }
-  }
-  for (it = printing_contents_pending_deletion_set.begin();
-       it != printing_contents_pending_deletion_set.end();
-       ++it) {
-    DeletePreviewContents(*it);
-  }
+  DCHECK_EQ(chrome::NOTIFICATION_PRINT_JOB_RELEASED, type);
+  DeletePreviewContents(content::Source<WebContents>(source).ptr());
 }
 
-void BackgroundPrintingManager::OnPrintJobReleased(
-    WebContents* preview_contents) {
-  DeletePreviewContents(preview_contents);
-}
-
-void BackgroundPrintingManager::OnWebContentsDestroyed(
+void BackgroundPrintingManager::DeletePreviewContents(
     WebContents* preview_contents) {
-  // Always need to remove this notification since the WebContents is gone.
-  content::Source<WebContents> preview_source(preview_contents);
-  registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-                    preview_source);
-
-  if (!HasPrintPreviewDialog(preview_contents)) {
-    NOTREACHED();
+  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;
   }
 
-  // Remove NOTIFICATION_RENDERER_PROCESS_CLOSED if |preview_contents| is the
-  // last WebContents associated with |rph|.
-  bool shared_rph =
-      (HasSharedRenderProcessHost(printing_contents_set_, preview_contents) ||
-       HasSharedRenderProcessHost(printing_contents_pending_deletion_set_,
-                                  preview_contents));
-  if (!shared_rph) {
-    content::RenderProcessHost* rph = preview_contents->GetRenderProcessHost();
-    registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
-                      content::Source<content::RenderProcessHost>(rph));
-  }
-
-  // Remove other notifications and remove the WebContents from its
-  // WebContentsSet.
-  if (printing_contents_set_.erase(preview_contents) == 1) {
-    registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
-                      preview_source);
-  } else {
-    // DeletePreviewContents already deleted the notification.
-    printing_contents_pending_deletion_set_.erase(preview_contents);
-  }
-}
-
-void BackgroundPrintingManager::DeletePreviewContents(
-    WebContents* preview_contents) {
+  // Stop all observation ...
   registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
                     content::Source<WebContents>(preview_contents));
-  printing_contents_set_.erase(preview_contents);
-  printing_contents_pending_deletion_set_.insert(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);
 }
 
-bool BackgroundPrintingManager::HasSharedRenderProcessHost(
-    const WebContentsSet& set, WebContents* preview_contents) {
-  content::RenderProcessHost* rph = preview_contents->GetRenderProcessHost();
-  for (WebContentsSet::const_iterator it = set.begin(); it != set.end(); ++it) {
-    WebContents* iter_contents = *it;
-    if (iter_contents == preview_contents)
-      continue;
-    if (iter_contents->GetRenderProcessHost() == rph)
-      return true;
+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 false;
-}
-
-BackgroundPrintingManager::WebContentsSet::const_iterator
-    BackgroundPrintingManager::begin() {
-  return printing_contents_set_.begin();
-}
-
-BackgroundPrintingManager::WebContentsSet::const_iterator
-    BackgroundPrintingManager::end() {
-  return printing_contents_set_.end();
+  return result;
 }
 
 bool BackgroundPrintingManager::HasPrintPreviewDialog(
     WebContents* preview_dialog) {
-  return (ContainsKey(printing_contents_set_, preview_dialog) ||
-          ContainsKey(printing_contents_pending_deletion_set_, preview_dialog));
+  return ContainsKey(printing_contents_map_, preview_dialog);
 }
 
 }  // namespace printing