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

Unified Diff: chrome/browser/google/google_url_tracker.cc

Issue 10753019: Merge 144201 - More comprehensive handling of NOTIFICATION_NAV_ENTRY_PENDING for GoogleURLTracker. (Closed) Base URL: svn://svn.chromium.org/chrome/branches/1180/src/
Patch Set: Created 8 years, 5 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/google/google_url_tracker.h ('k') | chrome/browser/google/google_url_tracker_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/google/google_url_tracker.cc
===================================================================
--- chrome/browser/google/google_url_tracker.cc (revision 145827)
+++ chrome/browser/google/google_url_tracker.cc (working copy)
@@ -23,6 +23,7 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#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_service.h"
#include "content/public/browser/web_contents.h"
@@ -38,11 +39,10 @@
GoogleURLTrackerInfoBarDelegate* CreateInfoBar(
InfoBarTabHelper* infobar_helper,
- const GURL& search_url,
GoogleURLTracker* google_url_tracker,
const GURL& new_google_url) {
- return new GoogleURLTrackerInfoBarDelegate(infobar_helper, search_url,
- google_url_tracker, new_google_url);
+ return new GoogleURLTrackerInfoBarDelegate(infobar_helper, google_url_tracker,
+ new_google_url);
}
string16 GetHost(const GURL& url) {
@@ -56,15 +56,14 @@
GoogleURLTrackerInfoBarDelegate::GoogleURLTrackerInfoBarDelegate(
InfoBarTabHelper* infobar_helper,
- const GURL& search_url,
GoogleURLTracker* google_url_tracker,
const GURL& new_google_url)
: ConfirmInfoBarDelegate(infobar_helper),
map_key_(infobar_helper),
- search_url_(search_url),
google_url_tracker_(google_url_tracker),
new_google_url_(new_google_url),
- showing_(false) {
+ showing_(false),
+ pending_id_(0) {
}
bool GoogleURLTrackerInfoBarDelegate::Accept() {
@@ -92,30 +91,30 @@
return false;
}
+bool GoogleURLTrackerInfoBarDelegate::ShouldExpireInternal(
+ const content::LoadCommittedDetails& details) const {
+ int unique_id = details.entry->GetUniqueID();
+ return (unique_id != contents_unique_id()) && (unique_id != pending_id_);
+}
+
void GoogleURLTrackerInfoBarDelegate::SetGoogleURL(const GURL& new_google_url) {
DCHECK_EQ(GetHost(new_google_url_), GetHost(new_google_url));
new_google_url_ = new_google_url;
}
-void GoogleURLTrackerInfoBarDelegate::Show() {
- showing_ = true;
- owner()->AddInfoBar(this); // May delete |this| on failure!
+void GoogleURLTrackerInfoBarDelegate::Show(const GURL& search_url) {
+ if (!owner())
+ return;
+ StoreActiveEntryUniqueID(owner());
+ search_url_ = search_url;
+ pending_id_ = 0;
+ if (!showing_) {
+ showing_ = true;
+ owner()->AddInfoBar(this); // May delete |this| on failure!
+ }
}
void GoogleURLTrackerInfoBarDelegate::Close(bool redo_search) {
- if (redo_search && owner()) {
- // Re-do the user's search on the new domain.
- url_canon::Replacements<char> replacements;
- const std::string& host(new_google_url_.host());
- replacements.SetHost(host.data(), url_parse::Component(0, host.length()));
- GURL new_search_url(search_url_.ReplaceComponents(replacements));
- if (new_search_url.is_valid()) {
- content::OpenURLParams params(new_search_url, content::Referrer(),
- CURRENT_TAB, content::PAGE_TRANSITION_GENERATED, false);
- owner()->web_contents()->OpenURL(params);
- }
- }
-
if (!showing_) {
// We haven't been added to a tab, so just delete ourselves.
delete this;
@@ -136,8 +135,24 @@
// subsequently reached here due to GoogleURLTracker::CloseAllInfoBars().
// This case will no longer happen once infobars are refactored to own their
// delegates.
- if (owner())
- owner()->RemoveInfoBar(this);
+ if (!owner())
+ return;
+
+ if (redo_search) {
+ // Re-do the user's search on the new domain.
+ DCHECK(search_url_.is_valid());
+ url_canon::Replacements<char> replacements;
+ const std::string& host(new_google_url_.host());
+ replacements.SetHost(host.data(), url_parse::Component(0, host.length()));
+ GURL new_search_url(search_url_.ReplaceComponents(replacements));
+ if (new_search_url.is_valid()) {
+ content::OpenURLParams params(new_search_url, content::Referrer(),
+ CURRENT_TAB, content::PAGE_TRANSITION_GENERATED, false);
+ owner()->web_contents()->OpenURL(params);
+ }
+ }
+
+ owner()->RemoveInfoBar(this);
}
GoogleURLTrackerInfoBarDelegate::~GoogleURLTrackerInfoBarDelegate() {
@@ -160,6 +175,30 @@
}
+// GoogleURLTracker::MapEntry -------------------------------------------------
+
+// Note that we have to initialize at least the NotificationSources explicitly
+// lest this not compile, because NotificationSource has no null constructor.
+GoogleURLTracker::MapEntry::MapEntry()
+ : navigation_controller_source(
+ content::Source<content::NavigationController>(NULL)),
+ tab_contents_source(content::Source<TabContents>(NULL)) {
+ NOTREACHED();
+}
+
+GoogleURLTracker::MapEntry::MapEntry(
+ GoogleURLTrackerInfoBarDelegate* infobar,
+ const content::NotificationSource& navigation_controller_source,
+ const content::NotificationSource& tab_contents_source)
+ : infobar(infobar),
+ navigation_controller_source(navigation_controller_source),
+ tab_contents_source(tab_contents_source) {
+}
+
+GoogleURLTracker::MapEntry::~MapEntry() {
+}
+
+
// GoogleURLTracker -----------------------------------------------------------
const char GoogleURLTracker::kDefaultGoogleHomepage[] =
@@ -177,7 +216,8 @@
in_startup_sleep_(true),
already_fetched_(false),
need_to_fetch_(false),
- need_to_prompt_(false) {
+ need_to_prompt_(false),
+ search_committed_(false) {
net::NetworkChangeNotifier::AddIPAddressObserver(this);
// Because this function can be called during startup, when kicking off a URL
@@ -299,7 +339,7 @@
} else if (fetched_google_url_ != url) {
for (InfoBarMap::iterator i(infobar_map_.begin());
i != infobar_map_.end(); ++i)
- i->second->SetGoogleURL(fetched_google_url_);
+ i->second.infobar->SetGoogleURL(fetched_google_url_);
}
}
}
@@ -313,29 +353,25 @@
content::Source<content::NavigationController>(source).ptr();
TabContents* tab_contents =
TabContents::FromWebContents(controller->GetWebContents());
- OnNavigationPending(source,
- content::Source<TabContents>(tab_contents),
+ OnNavigationPending(source, content::Source<TabContents>(tab_contents),
tab_contents->infobar_tab_helper(),
- controller->GetPendingEntry()->GetURL());
+ controller->GetPendingEntry()->GetUniqueID());
break;
}
case content::NOTIFICATION_NAV_ENTRY_COMMITTED: {
- TabContents* tab_contents = TabContents::FromWebContents(
- content::Source<content::NavigationController>(source)->
- GetWebContents());
- OnNavigationCommittedOrTabClosed(source,
- content::Source<TabContents>(tab_contents),
- tab_contents->infobar_tab_helper(), true);
+ content::NavigationController* controller =
+ content::Source<content::NavigationController>(source).ptr();
+ OnNavigationCommittedOrTabClosed(
+ TabContents::FromWebContents(controller->GetWebContents())->
+ infobar_tab_helper(),
+ controller->GetActiveEntry()->GetURL());
break;
}
case chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED: {
- TabContents* tab_contents = content::Source<TabContents>(source).ptr();
OnNavigationCommittedOrTabClosed(
- content::Source<content::NavigationController>(
- &tab_contents->web_contents()->GetController()), source,
- tab_contents->infobar_tab_helper(), false);
+ content::Source<TabContents>(source)->infobar_tab_helper(), GURL());
break;
}
@@ -344,12 +380,10 @@
content::WebContents* web_contents = tab_contents->web_contents();
content::Source<content::NavigationController> source(
&web_contents->GetController());
- content::Source<TabContents> tab_contents_source(tab_contents);
InfoBarTabHelper* infobar_helper = tab_contents->infobar_tab_helper();
- OnNavigationPending(source, tab_contents_source, infobar_helper,
- web_contents->GetURL());
- OnNavigationCommittedOrTabClosed(source, tab_contents_source,
- infobar_helper, true);
+ OnNavigationPending(source, content::Source<TabContents>(tab_contents),
+ infobar_helper, 0);
+ OnNavigationCommittedOrTabClosed(infobar_helper, web_contents->GetURL());
break;
}
@@ -393,9 +427,32 @@
}
void GoogleURLTracker::InfoBarClosed(const InfoBarTabHelper* infobar_helper) {
+ DCHECK(!search_committed_);
InfoBarMap::iterator i(infobar_map_.find(infobar_helper));
DCHECK(i != infobar_map_.end());
+ const MapEntry& map_entry = i->second;
+
+ UnregisterForEntrySpecificNotifications(map_entry, false);
infobar_map_.erase(i);
+
+ // Our global listeners for these other notifications should be in place iff
+ // we have any non-showing infobars.
+ for (InfoBarMap::const_iterator i(infobar_map_.begin());
+ i != infobar_map_.end(); ++i) {
+ if (!i->second.infobar->showing()) {
+ DCHECK(registrar_.IsRegistered(this,
+ content::NOTIFICATION_NAV_ENTRY_PENDING,
+ content::NotificationService::AllBrowserContextsAndSources()));
+ return;
+ }
+ }
+ if (registrar_.IsRegistered(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
+ content::NotificationService::AllBrowserContextsAndSources())) {
+ registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
+ content::NotificationService::AllBrowserContextsAndSources());
+ registrar_.Remove(this, chrome::NOTIFICATION_INSTANT_COMMITTED,
+ content::NotificationService::AllBrowserContextsAndSources());
+ }
}
void GoogleURLTracker::SetNeedToFetch() {
@@ -446,12 +503,16 @@
void GoogleURLTracker::SearchCommitted() {
if (need_to_prompt_) {
- // This notification will fire a bit later in the same call chain we're
+ search_committed_ = true;
+ // These notifications will fire a bit later in the same call chain we're
// currently in.
- registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
- content::NotificationService::AllBrowserContextsAndSources());
- registrar_.Add(this, chrome::NOTIFICATION_INSTANT_COMMITTED,
- content::NotificationService::AllBrowserContextsAndSources());
+ if (!registrar_.IsRegistered(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
+ content::NotificationService::AllBrowserContextsAndSources())) {
+ registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
+ content::NotificationService::AllBrowserContextsAndSources());
+ registrar_.Add(this, chrome::NOTIFICATION_INSTANT_COMMITTED,
+ content::NotificationService::AllBrowserContextsAndSources());
+ }
}
}
@@ -459,60 +520,110 @@
const content::NotificationSource& navigation_controller_source,
const content::NotificationSource& tab_contents_source,
InfoBarTabHelper* infobar_helper,
- const GURL& search_url) {
- registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_PENDING,
- content::NotificationService::AllBrowserContextsAndSources());
- registrar_.Remove(this, chrome::NOTIFICATION_INSTANT_COMMITTED,
- content::NotificationService::AllBrowserContextsAndSources());
+ int pending_id) {
+ InfoBarMap::iterator i(infobar_map_.find(infobar_helper));
- if (registrar_.IsRegistered(this,
- chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, tab_contents_source)) {
- // If the previous load hasn't committed and the user triggers a new load,
- // we don't need to re-register our listeners; just kill the old,
- // never-shown infobar (to be replaced by a new one below).
- InfoBarMap::iterator i(infobar_map_.find(infobar_helper));
- DCHECK(i != infobar_map_.end());
- i->second->Close(false);
+ if (search_committed_) {
+ search_committed_ = false;
+ // Whether there's an existing infobar or not, we need to listen for the
+ // load to commit, so we can show and/or update the infobar when it does.
+ // (We may already be registered for this if there is an existing infobar
+ // that had a previous pending search that hasn't yet committed.)
+ if (!registrar_.IsRegistered(this,
+ content::NOTIFICATION_NAV_ENTRY_COMMITTED,
+ navigation_controller_source)) {
+ registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
+ navigation_controller_source);
+ }
+ if (i == infobar_map_.end()) {
+ // This is a search on a tab that doesn't have one of our infobars, so add
+ // one. Note that we only listen for the tab's destruction on this path;
+ // if there was already an infobar, then either it's not yet showing and
+ // we're already registered for this, or it is showing and its owner will
+ // handle tearing it down when the tab is destroyed.
+ registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED,
+ tab_contents_source);
+ infobar_map_.insert(std::make_pair(infobar_helper, MapEntry(
+ (*infobar_creator_)(infobar_helper, this, fetched_google_url_),
+ navigation_controller_source, tab_contents_source)));
+ } else {
+ // This is a new search on a tab where we already have an infobar (which
+ // may or may not be showing).
+ i->second.infobar->set_pending_id(pending_id);
+ }
+ } else if (i != infobar_map_.end()){
+ if (i->second.infobar->showing()) {
+ // This is a non-search navigation on a tab with a visible infobar. If
+ // there was a previous pending search on this tab, this means it won't
+ // commit, so undo anything we did in response to seeing that. Note that
+ // if there was no pending search on this tab, these statements are
+ // effectively a no-op.
+ //
+ // If this navigation actually commits, that will trigger the infobar's
+ // owner to expire the infobar if need be. If it doesn't commit, then
+ // simply leaving the infobar as-is will have been the right thing.
+ UnregisterForEntrySpecificNotifications(i->second, false);
+ i->second.infobar->set_pending_id(0);
+ } else {
+ // Non-search navigation on a tab with a not-yet-shown infobar. This
+ // means the original search won't commit, so close the infobar.
+ i->second.infobar->Close(false);
+ }
} else {
- // Start listening for the commit notification. We also need to listen for
- // the tab close command since that means the load will never commit. Note
- // that in this case we don't need to close any previous infobar for this
- // tab since this navigation will close it.
- registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
- navigation_controller_source);
- registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED,
- tab_contents_source);
+ // Non-search navigation on a tab without one of our infobars. This is
+ // irrelevant to us.
}
-
- infobar_map_[infobar_helper] = (*infobar_creator_)(infobar_helper, search_url,
- this, fetched_google_url_);
}
void GoogleURLTracker::OnNavigationCommittedOrTabClosed(
- const content::NotificationSource& navigation_controller_source,
- const content::NotificationSource& tab_contents_source,
const InfoBarTabHelper* infobar_helper,
- bool navigated) {
- registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
- navigation_controller_source);
- registrar_.Remove(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED,
- tab_contents_source);
-
+ const GURL& search_url) {
InfoBarMap::iterator i(infobar_map_.find(infobar_helper));
DCHECK(i != infobar_map_.end());
- DCHECK(need_to_prompt_);
- if (navigated)
- i->second->Show();
- else
- i->second->Close(false); // Close manually since it's not added to a tab.
+ const MapEntry& map_entry = i->second;
+
+ if (!search_url.is_valid()) {
+ // Tab closed, or we somehow tried to navigate to an invalid URL (?!).
+ // InfoBarClosed() will take care of unregistering the notifications for
+ // this tab.
+ map_entry.infobar->Close(false);
+ return;
+ }
+
+ // We're getting called because of a commit notification, so pass true for
+ // |must_be_listening_for_commit|.
+ UnregisterForEntrySpecificNotifications(map_entry, true);
+ map_entry.infobar->Show(search_url);
}
void GoogleURLTracker::CloseAllInfoBars(bool redo_searches) {
// Close all infobars, whether they've been added to tabs or not.
while (!infobar_map_.empty())
- infobar_map_.begin()->second->Close(redo_searches);
+ infobar_map_.begin()->second.infobar->Close(redo_searches);
+}
- // Any registered listeners for NAV_ENTRY_COMMITTED and TAB_CLOSED are now
- // irrelevant as the associated infobars are gone.
- registrar_.RemoveAll();
+void GoogleURLTracker::UnregisterForEntrySpecificNotifications(
+ const MapEntry& map_entry,
+ bool must_be_listening_for_commit) {
+ // For tabs with non-showing infobars, we should always be listening for both
+ // these notifications. For tabs with showing infobars, we may be listening
+ // for NOTIFICATION_NAV_ENTRY_COMMITTED if the user has performed a new search
+ // on this tab.
+ if (registrar_.IsRegistered(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
+ map_entry.navigation_controller_source)) {
+ registrar_.Remove(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
+ map_entry.navigation_controller_source);
+ } else {
+ DCHECK(!must_be_listening_for_commit);
+ DCHECK(map_entry.infobar->showing());
+ }
+ const bool registered_for_tab_contents_destroyed =
+ registrar_.IsRegistered(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED,
+ map_entry.tab_contents_source);
+ DCHECK_NE(registered_for_tab_contents_destroyed,
+ map_entry.infobar->showing());
+ if (registered_for_tab_contents_destroyed) {
+ registrar_.Remove(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED,
+ map_entry.tab_contents_source);
+ }
}
« no previous file with comments | « chrome/browser/google/google_url_tracker.h ('k') | chrome/browser/google/google_url_tracker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698