Index: chrome/browser/geolocation/chrome_geolocation_permission_context.cc |
diff --git a/chrome/browser/geolocation/chrome_geolocation_permission_context.cc b/chrome/browser/geolocation/chrome_geolocation_permission_context.cc |
index aa28177e23f4b49a4464c1935bbad0e8db47a2a5..caefc2c19fcb8aba38575fab4e968472a6455020 100644 |
--- a/chrome/browser/geolocation/chrome_geolocation_permission_context.cc |
+++ b/chrome/browser/geolocation/chrome_geolocation_permission_context.cc |
@@ -14,17 +14,20 @@ |
#include "chrome/browser/content_settings/tab_specific_content_settings.h" |
#include "chrome/browser/extensions/extension_service.h" |
#include "chrome/browser/google/google_util.h" |
+#include "chrome/browser/infobars/infobar.h" |
#include "chrome/browser/infobars/infobar_tab_helper.h" |
#include "chrome/browser/prefs/pref_service.h" |
#include "chrome/browser/profiles/profile.h" |
#include "chrome/browser/tab_contents/confirm_infobar_delegate.h" |
#include "chrome/browser/tab_contents/tab_util.h" |
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
+#include "chrome/common/chrome_notification_types.h" |
#include "chrome/common/extensions/extension.h" |
#include "chrome/common/pref_names.h" |
#include "content/public/browser/browser_thread.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_registrar.h" |
#include "content/public/browser/notification_source.h" |
#include "content/public/browser/notification_types.h" |
@@ -78,12 +81,6 @@ class GeolocationInfoBarQueueController : content::NotificationObserver { |
int render_view_id, |
int bridge_id); |
- // Called by the InfoBarDelegate to notify it's closed. It'll display a new |
- // InfoBar if there's any request pending for this tab. |
- void OnInfoBarClosed(int render_process_id, |
- int render_view_id, |
- int bridge_id); |
- |
// Called by the InfoBarDelegate to notify permission has been set. |
// It'll notify and dismiss any other pending InfoBar request for the same |
// |requesting_frame| and embedder. |
@@ -97,7 +94,7 @@ class GeolocationInfoBarQueueController : content::NotificationObserver { |
// content::NotificationObserver |
virtual void Observe(int type, |
const content::NotificationSource& source, |
- const content::NotificationDetails& details); |
+ const content::NotificationDetails& details) OVERRIDE; |
private: |
struct PendingInfoBarRequest; |
@@ -106,11 +103,19 @@ class GeolocationInfoBarQueueController : content::NotificationObserver { |
typedef std::vector<PendingInfoBarRequest> PendingInfoBarRequests; |
// Shows the first pending infobar for this tab. |
- void ShowQueuedInfoBar(int render_process_id, int render_view_id); |
+ void ShowQueuedInfoBar(int render_process_id, int render_view_id, |
+ InfoBarTabHelper* helper); |
// Cancels an InfoBar request and returns the next iterator position. |
PendingInfoBarRequests::iterator CancelInfoBarRequestInternal( |
- PendingInfoBarRequests::iterator i); |
+ PendingInfoBarRequests::iterator i, |
+ bool remove_showing_infobar); |
+ |
+ // Removes any pending requests for a given dead tab. |
+ void ClearInfoBarRequestsFromTab(int render_process_id, int render_view_id); |
bulach
2012/03/22 17:01:46
nit: maybe ClearPendingInfoBarRequestsFromTab, to
John Knottenbelt
2012/03/22 18:09:02
Done.
|
+ |
+ InfoBarTabHelper* GetInfoBarHelper(int render_process_id, int render_view_id); |
+ bool AlreadyShowingQueuedInfoBar(int render_process_id, int render_view_id); |
bulach
2012/03/22 17:01:46
nit: and in this case the could probably remove th
John Knottenbelt
2012/03/22 18:09:02
Done.
|
content::NotificationRegistrar registrar_; |
@@ -135,8 +140,10 @@ class GeolocationConfirmInfoBarDelegate : public ConfirmInfoBarDelegate { |
const GURL& requesting_frame_url, |
const std::string& display_languages); |
+ int render_process_id() const { return render_process_id_; } |
+ int render_view_id() const { return render_view_id_; } |
+ |
private: |
- virtual ~GeolocationConfirmInfoBarDelegate(); |
// ConfirmInfoBarDelegate: |
virtual bool ShouldExpire( |
@@ -185,11 +192,6 @@ GeolocationConfirmInfoBarDelegate::GeolocationConfirmInfoBarDelegate( |
committed_entry->GetUniqueID() : 0; |
} |
-GeolocationConfirmInfoBarDelegate::~GeolocationConfirmInfoBarDelegate() { |
- controller_->OnInfoBarClosed(render_process_id_, render_view_id_, |
- bridge_id_); |
-} |
- |
bool GeolocationConfirmInfoBarDelegate::ShouldExpire( |
const content::LoadCommittedDetails& details) const { |
if (details.did_replace_entry || !details.is_navigation_to_different_page()) |
@@ -283,7 +285,8 @@ struct GeolocationInfoBarQueueController::PendingInfoBarRequest { |
GURL requesting_frame; |
GURL embedder; |
base::Callback<void(bool)> callback; |
- InfoBarDelegate* infobar_delegate; |
+ GeolocationConfirmInfoBarDelegate* infobar_delegate; |
+ bool notified; |
bulach
2012/03/22 17:01:46
unused?
John Knottenbelt
2012/03/22 18:09:02
Removed.
On 2012/03/22 17:01:46, bulach wrote:
|
}; |
GeolocationInfoBarQueueController::PendingInfoBarRequest::PendingInfoBarRequest( |
@@ -299,7 +302,8 @@ GeolocationInfoBarQueueController::PendingInfoBarRequest::PendingInfoBarRequest( |
requesting_frame(requesting_frame), |
embedder(embedder), |
callback(callback), |
- infobar_delegate(NULL) { |
+ infobar_delegate(NULL), |
+ notified(false) { |
} |
bool GeolocationInfoBarQueueController::PendingInfoBarRequest::IsForTab( |
@@ -354,7 +358,6 @@ bool GeolocationInfoBarQueueController::RequestEquals::operator()( |
return request.Equals(render_process_id_, render_view_id_, bridge_id_); |
} |
- |
// GeolocationInfoBarQueueController ------------------------------------------ |
GeolocationInfoBarQueueController::GeolocationInfoBarQueueController( |
@@ -384,7 +387,15 @@ void GeolocationInfoBarQueueController::CreateInfoBarRequest( |
pending_infobar_requests_.push_back(PendingInfoBarRequest(render_process_id, |
render_view_id, bridge_id, requesting_frame, embedder, callback)); |
- ShowQueuedInfoBar(render_process_id, render_view_id); |
+ |
+ InfoBarTabHelper* helper = GetInfoBarHelper(render_process_id, |
+ render_view_id); |
+ if (!helper) { |
bulach
2012/03/22 17:01:46
maybe move 388 after this and add a comment saying
John Knottenbelt
2012/03/22 18:09:02
Done.
|
+ ClearInfoBarRequestsFromTab(render_process_id, render_view_id); |
+ return; |
+ } |
+ if (!AlreadyShowingQueuedInfoBar(render_process_id, render_view_id)) |
+ ShowQueuedInfoBar(render_process_id, render_view_id, helper); |
} |
void GeolocationInfoBarQueueController::CancelInfoBarRequest( |
@@ -398,21 +409,7 @@ void GeolocationInfoBarQueueController::CancelInfoBarRequest( |
RequestEquals(render_process_id, render_view_id, bridge_id)); |
// TODO(pkasting): Can this conditional become a DCHECK()? |
if (i != pending_infobar_requests_.end()) |
- CancelInfoBarRequestInternal(i); |
-} |
- |
-void GeolocationInfoBarQueueController::OnInfoBarClosed(int render_process_id, |
- int render_view_id, |
- int bridge_id) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
- |
- PendingInfoBarRequests::iterator i = std::find_if( |
- pending_infobar_requests_.begin(), pending_infobar_requests_.end(), |
- RequestEquals(render_process_id, render_view_id, bridge_id)); |
- if (i != pending_infobar_requests_.end()) |
- pending_infobar_requests_.erase(i); |
- |
- ShowQueuedInfoBar(render_process_id, render_view_id); |
+ CancelInfoBarRequestInternal(i, true); |
} |
void GeolocationInfoBarQueueController::OnPermissionSet( |
@@ -433,108 +430,142 @@ void GeolocationInfoBarQueueController::OnPermissionSet( |
std::string(), |
content_setting); |
+ // Cancel this request first, then notify listeners. TODO(pkasting): Why |
+ // is this order important? |
+ PendingInfoBarRequests requests_to_notify; |
for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); |
i != pending_infobar_requests_.end(); ) { |
if (i->IsForPair(requesting_frame, embedder)) { |
- // Cancel this request first, then notify listeners. TODO(pkasting): Why |
- // is this order important? |
- // NOTE: If the pending request had an infobar, TabContents will close it |
- // either synchronously or asynchronously, which will then pump the queue |
- // via OnInfoBarClosed(). |
- PendingInfoBarRequest copied_request = *i; |
+ requests_to_notify.push_back(*i); |
// Don't let CancelInfoBarRequestInternal() call RemoveInfoBar() with the |
// delegate that's currently calling us. That delegate is in either |
// Accept() or Cancel(), so its owning InfoBar will call RemoveInfoBar() |
// later on in this callstack anyway; and if we do it here, and it causes |
// the delegate to be deleted, our GURL& args will point to garbage and we |
// may also cause other problems during stack unwinding. |
- if (i->Equals(render_process_id, render_view_id, bridge_id)) |
- i->infobar_delegate = NULL; |
- i = CancelInfoBarRequestInternal(i); |
- |
- geolocation_permission_context_->NotifyPermissionSet( |
- copied_request.render_process_id, copied_request.render_view_id, |
- copied_request.bridge_id, copied_request.requesting_frame, |
- copied_request.callback, allowed); |
- } else { |
- ++i; |
+ if (!i->Equals(render_process_id, render_view_id, bridge_id)) { |
+ i = CancelInfoBarRequestInternal(i, true); |
+ continue; |
+ } |
} |
+ ++i; |
+ } |
+ |
+ for (PendingInfoBarRequests::iterator i = requests_to_notify.begin(); |
+ i != requests_to_notify.end(); ++i ) { |
+ geolocation_permission_context_->NotifyPermissionSet( |
+ i->render_process_id, i->render_view_id, |
+ i->bridge_id, i->requesting_frame, |
+ i->callback, allowed); |
} |
} |
void GeolocationInfoBarQueueController::Observe( |
- int type, const content::NotificationSource& source, |
+ int type, |
+ const content::NotificationSource& source, |
const content::NotificationDetails& details) { |
- registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
- source); |
- WebContents* web_contents = content::Source<WebContents>(source).ptr(); |
+ DCHECK_EQ(chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, type); |
+ // We will receive this notification for all infobar closures, so we need to |
+ // check whether this is the geolocation infobar we're tracking. |
+ InfoBarDelegate* delegate = |
+ content::Details<InfoBarRemovedDetails>(details)->first; |
+ for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); |
+ i != pending_infobar_requests_.end(); ++i) { |
+ GeolocationConfirmInfoBarDelegate* confirm_delegate = i->infobar_delegate; |
+ if (confirm_delegate == delegate) { |
+ // We're being called from InfoBarTabHelper, so pass in false to |
+ // stop CancelInfoBarRequestInternal calling helper->RemoveInfoBar. |
+ CancelInfoBarRequestInternal(i, false); |
bulach
2012/03/22 17:01:46
see below, I think it'd be nicer to ShowQueuedInfo
|
+ return; |
+ } |
+ } |
+} |
+ |
+void GeolocationInfoBarQueueController::ClearInfoBarRequestsFromTab( |
+ int render_process_id, |
+ int render_view_id) { |
for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); |
- i != pending_infobar_requests_.end();) { |
- if (i->infobar_delegate == NULL && |
- web_contents == tab_util::GetWebContentsByID(i->render_process_id, |
- i->render_view_id)) { |
+ i != pending_infobar_requests_.end(); ) { |
+ if (i->IsForTab(render_process_id, render_view_id)) |
i = pending_infobar_requests_.erase(i); |
- } else { |
+ else |
++i; |
- } |
} |
} |
-void GeolocationInfoBarQueueController::ShowQueuedInfoBar(int render_process_id, |
- int render_view_id) { |
+InfoBarTabHelper* GeolocationInfoBarQueueController::GetInfoBarHelper( |
+ int render_process_id, |
+ int render_view_id) { |
WebContents* tab_contents = |
tab_util::GetWebContentsByID(render_process_id, render_view_id); |
- TabContentsWrapper* wrapper = NULL; |
- if (tab_contents) |
- wrapper = TabContentsWrapper::GetCurrentWrapperForContents(tab_contents); |
+ if (!tab_contents) |
+ return NULL; |
+ TabContentsWrapper* wrapper = |
+ TabContentsWrapper::GetCurrentWrapperForContents(tab_contents); |
+ if (!wrapper) |
+ return NULL; |
+ return wrapper->infobar_tab_helper(); |
+} |
+ |
+bool GeolocationInfoBarQueueController::AlreadyShowingQueuedInfoBar( |
+ int render_process_id, |
+ int render_view_id) { |
for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); |
- i != pending_infobar_requests_.end(); ) { |
- if (i->IsForTab(render_process_id, render_view_id)) { |
- if (!wrapper) { |
- i = pending_infobar_requests_.erase(i); |
- continue; |
- } |
+ i != pending_infobar_requests_.end(); ++i) { |
+ if (i->IsForTab(render_process_id, render_view_id) && i->infobar_delegate) |
+ return true; |
+ } |
+ return false; |
+} |
- if (!i->infobar_delegate) { |
- if (!registrar_.IsRegistered( |
- this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
- content::Source<WebContents>(tab_contents))) { |
- registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
- content::Source<WebContents>(tab_contents)); |
- } |
+void GeolocationInfoBarQueueController::ShowQueuedInfoBar( |
+ int render_process_id, |
+ int render_view_id, |
+ InfoBarTabHelper* helper) { |
+ DCHECK(helper); |
+ DCHECK(!AlreadyShowingQueuedInfoBar(render_process_id, render_view_id)); |
+ for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin(); |
+ i != pending_infobar_requests_.end(); ++i) { |
+ if (i->IsForTab(render_process_id, render_view_id) && |
+ !i->infobar_delegate) { |
+ DCHECK(!registrar_.IsRegistered( |
+ this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, |
+ content::Source<InfoBarTabHelper>(helper))); |
+ registrar_.Add( |
+ this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, |
+ content::Source<InfoBarTabHelper>(helper)); |
i->infobar_delegate = new GeolocationConfirmInfoBarDelegate( |
- wrapper->infobar_tab_helper(), this, render_process_id, |
+ helper, this, render_process_id, |
render_view_id, i->bridge_id, i->requesting_frame, |
profile_->GetPrefs()->GetString(prefs::kAcceptLanguages)); |
- wrapper->infobar_tab_helper()->AddInfoBar(i->infobar_delegate); |
- } |
- break; |
+ helper->AddInfoBar(i->infobar_delegate); |
+ break; |
} |
- ++i; |
} |
} |
GeolocationInfoBarQueueController::PendingInfoBarRequests::iterator |
GeolocationInfoBarQueueController::CancelInfoBarRequestInternal( |
- PendingInfoBarRequests::iterator i) { |
+ PendingInfoBarRequests::iterator i, |
+ bool remove_showing_infobar) { |
InfoBarDelegate* delegate = i->infobar_delegate; |
if (!delegate) |
return pending_infobar_requests_.erase(i); |
- |
- WebContents* web_contents = |
- tab_util::GetWebContentsByID(i->render_process_id, i->render_view_id); |
- if (!web_contents) |
+ InfoBarTabHelper* helper = GetInfoBarHelper(i->render_process_id, |
+ i->render_view_id); |
+ if (!helper) |
return pending_infobar_requests_.erase(i); |
- |
- // WebContents will destroy the InfoBar, which will remove from our vector |
- // asynchronously. |
- TabContentsWrapper* wrapper = |
- TabContentsWrapper::GetCurrentWrapperForContents(web_contents); |
- wrapper->infobar_tab_helper()->RemoveInfoBar(i->infobar_delegate); |
- return ++i; |
+ registrar_.Remove(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, |
+ content::Source<InfoBarTabHelper>(helper)); |
+ if (remove_showing_infobar) |
+ helper->RemoveInfoBar(delegate); |
+ int render_process_id = i->render_process_id; |
+ int render_view_id = i->render_view_id; |
+ PendingInfoBarRequests::iterator next = pending_infobar_requests_.erase(i); |
+ ShowQueuedInfoBar(render_process_id, render_view_id, helper); |
bulach
2012/03/22 17:01:46
hmm.. I'm not sure we want to create the infobar h
|
+ return next; |
} |
- |
// GeolocationPermissionContext ----------------------------------------------- |
ChromeGeolocationPermissionContext::ChromeGeolocationPermissionContext( |