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

Side by Side Diff: chrome/browser/search_engines/util.cc

Issue 10409002: Make prepopulated-TemplateURL-de-duper heuristic smarter. Instead of blindly preserving the first U… (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: merge to TOT + fixes Created 8 years, 7 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 unified diff | Download patch
« no previous file with comments | « chrome/browser/search_engines/util.h ('k') | chrome/chrome_tests.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/search_engines/util.h" 5 #include "chrome/browser/search_engines/util.h"
6 6
7 #include <set> 7 #include <set>
8 #include <string> 8 #include <string>
9 #include <map>
9 #include <vector> 10 #include <vector>
10 11
11 #include "base/logging.h" 12 #include "base/logging.h"
12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/search_engines/template_url.h" 14 #include "chrome/browser/search_engines/template_url.h"
14 #include "chrome/browser/search_engines/template_url_prepopulate_data.h" 15 #include "chrome/browser/search_engines/template_url_prepopulate_data.h"
15 #include "chrome/browser/search_engines/template_url_service.h" 16 #include "chrome/browser/search_engines/template_url_service.h"
16 #include "chrome/browser/search_engines/template_url_service_factory.h" 17 #include "chrome/browser/search_engines/template_url_service_factory.h"
17 #include "content/public/browser/browser_thread.h" 18 #include "content/public/browser/browser_thread.h"
18 19
19 using content::BrowserThread; 20 using content::BrowserThread;
20 21
21 string16 GetDefaultSearchEngineName(Profile* profile) { 22 string16 GetDefaultSearchEngineName(Profile* profile) {
22 if (!profile) { 23 if (!profile) {
23 NOTREACHED(); 24 NOTREACHED();
24 return string16(); 25 return string16();
25 } 26 }
26 const TemplateURL* const default_provider = 27 const TemplateURL* const default_provider =
27 TemplateURLServiceFactory::GetForProfile(profile)-> 28 TemplateURLServiceFactory::GetForProfile(profile)->
28 GetDefaultSearchProvider(); 29 GetDefaultSearchProvider();
29 if (!default_provider) { 30 if (!default_provider) {
30 // TODO(cpu): bug 1187517. It is possible to have no default provider. 31 // TODO(cpu): bug 1187517. It is possible to have no default provider.
31 // returning an empty string is a stopgap measure for the crash 32 // returning an empty string is a stopgap measure for the crash
32 // http://code.google.com/p/chromium/issues/detail?id=2573 33 // http://code.google.com/p/chromium/issues/detail?id=2573
33 return string16(); 34 return string16();
34 } 35 }
35 return default_provider->short_name(); 36 return default_provider->short_name();
36 } 37 }
37 38
38 // Removes (and deletes) TemplateURLs from |urls| that have duplicate 39 // Removes (and deletes) TemplateURLs from |template_urls| and |service| if they
39 // prepopulate ids. Duplicate prepopulate ids are not allowed, but due to a 40 // have duplicate prepopulate ids. If |removed_keyword_guids| is not NULL, the
40 // bug it was possible get dups. This step is only called when the version 41 // Sync GUID of each item removed from the DB will be added to it.
41 // number changes. Only pass in a non-NULL value for |service| if the removed 42 void RemoveDuplicatePrepopulateIDs(
42 // items should be removed from the DB. If |removed_keyword_guids| is not NULL,
43 // the Sync GUID of each item removed from the DB will be added to it.
44 static void RemoveDuplicatePrepopulateIDs(
45 std::vector<TemplateURL*>* template_urls,
46 WebDataService* service, 43 WebDataService* service,
44 const std::vector<TemplateURL*>& prepopulated_urls,
45 TemplateURL* default_search_provider,
46 TemplateURLService::TemplateURLVector* template_urls,
47 std::set<std::string>* removed_keyword_guids) { 47 std::set<std::string>* removed_keyword_guids) {
48 DCHECK(service == NULL || BrowserThread::CurrentlyOn(BrowserThread::UI));
48 DCHECK(template_urls); 49 DCHECK(template_urls);
SteveT 2012/05/17 15:01:45 FYI you used to have a DCHECK(default_search_provi
Peter Kasting 2012/05/17 20:12:19 Yeah, this was a mistake. I was thinking one leve
49 DCHECK(service == NULL || BrowserThread::CurrentlyOn(BrowserThread::UI));
50 50
51 std::set<int> ids; 51 // For convenience construct an ID->TemplateURL* map from |prepopulated_urls|.
52 for (std::vector<TemplateURL*>::iterator i = template_urls->begin(); 52 typedef std::map<int, TemplateURL*> PrepopulatedURLMap;
53 i != template_urls->end(); ) { 53 PrepopulatedURLMap prepopulated_url_map;
54 int prepopulate_id = (*i)->prepopulate_id(); 54 for (std::vector<TemplateURL*>::const_iterator i(prepopulated_urls.begin());
55 if (prepopulate_id) { 55 i != prepopulated_urls.end(); ++i)
56 if (ids.find(prepopulate_id) != ids.end()) { 56 prepopulated_url_map[(*i)->prepopulate_id()] = *i;
57 if (service) { 57
58 service->RemoveKeyword((*i)->id()); 58 // Separate |template_urls| into prepopulated and non-prepopulated groups.
59 if (removed_keyword_guids) 59 typedef std::multimap<int, TemplateURL*> UncheckedURLMap;
60 removed_keyword_guids->insert((*i)->sync_guid()); 60 UncheckedURLMap unchecked_urls;
61 } 61 TemplateURLService::TemplateURLVector checked_urls;
62 delete *i; 62 for (TemplateURLService::TemplateURLVector::iterator i(
63 i = template_urls->erase(i); 63 template_urls->begin()); i != template_urls->end(); ++i) {
64 } else { 64 TemplateURL* turl = *i;
65 ids.insert(prepopulate_id); 65 int prepopulate_id = turl->prepopulate_id();
66 ++i; 66 if (prepopulate_id)
67 unchecked_urls.insert(std::make_pair(prepopulate_id, turl));
68 else
69 checked_urls.push_back(turl);
70 }
71
72 // For each group of prepopulated URLs with one ID, find the best URL to use
73 // and add it to the (initially all non-prepopulated) URLs we've already OKed.
74 // Delete the others from the service and from memory.
75 while (!unchecked_urls.empty()) {
76 // Find the best URL.
77 int prepopulate_id = unchecked_urls.begin()->first;
78 PrepopulatedURLMap::const_iterator prepopulated_url =
79 prepopulated_url_map.find(prepopulate_id);
80 UncheckedURLMap::iterator end = unchecked_urls.upper_bound(prepopulate_id);
81 UncheckedURLMap::iterator best = unchecked_urls.begin();
82 bool matched_keyword = false;
83 for (UncheckedURLMap::iterator i = unchecked_urls.begin(); i != end; ++i) {
84 // A URL is automatically the best if it's the default search engine.
85 if (i->second == default_search_provider) {
86 best = i;
87 break;
67 } 88 }
68 } else { 89
69 ++i; 90 // Otherwise, a URL is best if it matches the prepopulated data's keyword;
91 // if none match, just fall back to using the one with the lowest ID.
92 if (matched_keyword)
93 continue;
94 if ((prepopulated_url != prepopulated_url_map.end()) &&
95 i->second->HasSameKeywordAs(*prepopulated_url->second)) {
96 best = i;
97 matched_keyword = true;
98 } else if (i->second->id() < best->second->id()) {
99 best = i;
100 }
70 } 101 }
102
103 // Add it to the checked group; remove it from elsewhere.
104 checked_urls.push_back(best->second);
105 unchecked_urls.erase(best);
106 for (UncheckedURLMap::iterator i = unchecked_urls.begin(); i != end; ++i) {
107 if (service) {
108 service->RemoveKeyword(i->second->id());
109 if (removed_keyword_guids)
110 removed_keyword_guids->insert(i->second->sync_guid());
111 }
112 delete i->second;
113 }
114
115 // Done with this group.
116 unchecked_urls.erase(unchecked_urls.begin(), end);
71 } 117 }
118
119 // Return the checked URLs.
120 template_urls->swap(checked_urls);
72 } 121 }
73 122
74 // Returns the TemplateURL with id specified from the list of TemplateURLs. 123 // Returns the TemplateURL with id specified from the list of TemplateURLs.
75 // If not found, returns NULL. 124 // If not found, returns NULL.
76 TemplateURL* GetTemplateURLByID( 125 TemplateURL* GetTemplateURLByID(
77 const std::vector<TemplateURL*>& template_urls, 126 const TemplateURLService::TemplateURLVector& template_urls,
78 int64 id) { 127 int64 id) {
79 for (std::vector<TemplateURL*>::const_iterator i = template_urls.begin(); 128 for (TemplateURLService::TemplateURLVector::const_iterator i(
80 i != template_urls.end(); ++i) { 129 template_urls.begin()); i != template_urls.end(); ++i) {
81 if ((*i)->id() == id) { 130 if ((*i)->id() == id) {
82 return *i; 131 return *i;
83 } 132 }
84 } 133 }
85 return NULL; 134 return NULL;
86 } 135 }
87 136
88 // Loads engines from prepopulate data and merges them in with the existing 137 // Loads engines from prepopulate data and merges them in with the existing
89 // engines. This is invoked when the version of the prepopulate data changes. 138 // engines. This is invoked when the version of the prepopulate data changes.
90 // If |removed_keyword_guids| is not NULL, the Sync GUID of each item removed 139 // If |removed_keyword_guids| is not NULL, the Sync GUID of each item removed
91 // from the DB will be added to it. 140 // from the DB will be added to it.
92 void MergeEnginesFromPrepopulateData( 141 void MergeEnginesFromPrepopulateData(
93 Profile* profile, 142 Profile* profile,
94 WebDataService* service, 143 WebDataService* service,
95 std::vector<TemplateURL*>* template_urls, 144 const std::vector<TemplateURL*>& prepopulated_urls,
145 size_t default_search_index,
146 TemplateURLService::TemplateURLVector* template_urls,
96 TemplateURL** default_search_provider, 147 TemplateURL** default_search_provider,
97 std::set<std::string>* removed_keyword_guids) { 148 std::set<std::string>* removed_keyword_guids) {
98 DCHECK(service == NULL || BrowserThread::CurrentlyOn(BrowserThread::UI)); 149 DCHECK(service == NULL || BrowserThread::CurrentlyOn(BrowserThread::UI));
99 DCHECK(template_urls); 150 DCHECK(template_urls);
100 DCHECK(default_search_provider); 151 DCHECK(default_search_provider);
101 152
102 // Create a map to hold all provided |template_urls| that originally came from 153 // Create a map to hold all provided |template_urls| that originally came from
103 // prepopulate data (i.e. have a non-zero prepopulate_id()). 154 // prepopulate data (i.e. have a non-zero prepopulate_id()).
104 typedef std::map<int, TemplateURL*> IDMap; 155 typedef std::map<int, TemplateURL*> IDMap;
105 IDMap id_to_turl; 156 IDMap id_to_turl;
106 for (std::vector<TemplateURL*>::iterator i(template_urls->begin()); 157 for (TemplateURLService::TemplateURLVector::iterator i(
107 i != template_urls->end(); ++i) { 158 template_urls->begin()); i != template_urls->end(); ++i) {
108 int prepopulate_id = (*i)->prepopulate_id(); 159 int prepopulate_id = (*i)->prepopulate_id();
109 if (prepopulate_id > 0) 160 if (prepopulate_id > 0)
110 id_to_turl[prepopulate_id] = *i; 161 id_to_turl[prepopulate_id] = *i;
111 } 162 }
112 163
113 // Get the current set of prepopulatd URLs.
114 std::vector<TemplateURL*> prepopulated_urls;
115 size_t default_search_index;
116 TemplateURLPrepopulateData::GetPrepopulatedEngines(profile,
117 &prepopulated_urls, &default_search_index);
118
119 // For each current prepopulated URL, check whether |template_urls| contained 164 // For each current prepopulated URL, check whether |template_urls| contained
120 // a matching prepopulated URL. If so, update the passed-in URL to match the 165 // a matching prepopulated URL. If so, update the passed-in URL to match the
121 // current data. (If the passed-in URL was user-edited, we persist the user's 166 // current data. (If the passed-in URL was user-edited, we persist the user's
122 // name and keyword.) If not, add the prepopulated URL to |template_urls|. 167 // name and keyword.) If not, add the prepopulated URL to |template_urls|.
123 // Along the way, point |default_search_provider| at the default prepopulated 168 // Along the way, point |default_search_provider| at the default prepopulated
124 // URL, if the user hasn't already set another URL as default. 169 // URL, if the user hasn't already set another URL as default.
125 for (size_t i = 0; i < prepopulated_urls.size(); ++i) { 170 for (size_t i = 0; i < prepopulated_urls.size(); ++i) {
126 // We take ownership of |prepopulated_urls[i]|. 171 // We take ownership of |prepopulated_urls[i]|.
127 scoped_ptr<TemplateURL> prepopulated_url(prepopulated_urls[i]); 172 scoped_ptr<TemplateURL> prepopulated_url(prepopulated_urls[i]);
128 const int prepopulated_id = prepopulated_url->prepopulate_id(); 173 const int prepopulated_id = prepopulated_url->prepopulate_id();
(...skipping 10 matching lines...) Expand all
139 if (!existing_url->safe_for_autoreplace()) { 184 if (!existing_url->safe_for_autoreplace()) {
140 data.safe_for_autoreplace = false; 185 data.safe_for_autoreplace = false;
141 data.SetKeyword(existing_url->keyword()); 186 data.SetKeyword(existing_url->keyword());
142 data.short_name = existing_url->short_name(); 187 data.short_name = existing_url->short_name();
143 } 188 }
144 data.id = existing_url->id(); 189 data.id = existing_url->id();
145 if (service) 190 if (service)
146 service->UpdateKeyword(data); 191 service->UpdateKeyword(data);
147 192
148 // Replace the entry in |template_urls| with the updated one. 193 // Replace the entry in |template_urls| with the updated one.
149 std::vector<TemplateURL*>::iterator j = std::find(template_urls->begin(), 194 TemplateURLService::TemplateURLVector::iterator j = std::find(
150 template_urls->end(), existing_url.get()); 195 template_urls->begin(), template_urls->end(), existing_url.get());
151 *j = new TemplateURL(profile, data); 196 *j = new TemplateURL(profile, data);
152 url_in_vector = *j; 197 url_in_vector = *j;
153 if (*default_search_provider == existing_url.get()) 198 if (*default_search_provider == existing_url.get())
154 *default_search_provider = url_in_vector; 199 *default_search_provider = url_in_vector;
155 } else { 200 } else {
156 template_urls->push_back(prepopulated_url.release()); 201 template_urls->push_back(prepopulated_url.release());
157 url_in_vector = template_urls->back(); 202 url_in_vector = template_urls->back();
158 } 203 }
159 DCHECK(url_in_vector); 204 DCHECK(url_in_vector);
160 if (i == default_search_index && !*default_search_provider) 205 if (i == default_search_index && !*default_search_provider)
161 *default_search_provider = url_in_vector; 206 *default_search_provider = url_in_vector;
162 } 207 }
163 208
164 // The block above removed all the URLs from the |id_to_turl| map that were 209 // The block above removed all the URLs from the |id_to_turl| map that were
165 // found in the prepopulate data. Any remaining URLs that haven't been 210 // found in the prepopulate data. Any remaining URLs that haven't been
166 // user-edited or made default can be removed from the data store. 211 // user-edited or made default can be removed from the data store.
167 for (IDMap::iterator i(id_to_turl.begin()); i != id_to_turl.end(); ++i) { 212 for (IDMap::iterator i(id_to_turl.begin()); i != id_to_turl.end(); ++i) {
168 const TemplateURL* template_url = i->second; 213 const TemplateURL* template_url = i->second;
169 if ((template_url->safe_for_autoreplace()) && 214 if ((template_url->safe_for_autoreplace()) &&
170 (template_url != *default_search_provider)) { 215 (template_url != *default_search_provider)) {
171 std::vector<TemplateURL*>::iterator j = 216 TemplateURLService::TemplateURLVector::iterator j =
172 std::find(template_urls->begin(), template_urls->end(), template_url); 217 std::find(template_urls->begin(), template_urls->end(), template_url);
173 DCHECK(j != template_urls->end()); 218 DCHECK(j != template_urls->end());
174 template_urls->erase(j); 219 template_urls->erase(j);
175 if (service) { 220 if (service) {
176 service->RemoveKeyword(template_url->id()); 221 service->RemoveKeyword(template_url->id());
177 if (removed_keyword_guids) 222 if (removed_keyword_guids)
178 removed_keyword_guids->insert(template_url->sync_guid()); 223 removed_keyword_guids->insert(template_url->sync_guid());
179 } 224 }
180 delete template_url; 225 delete template_url;
181 } 226 }
182 } 227 }
183 } 228 }
184 229
185 void GetSearchProvidersUsingKeywordResult( 230 void GetSearchProvidersUsingKeywordResult(
186 const WDTypedResult& result, 231 const WDTypedResult& result,
187 WebDataService* service, 232 WebDataService* service,
188 Profile* profile, 233 Profile* profile,
189 std::vector<TemplateURL*>* template_urls, 234 TemplateURLService::TemplateURLVector* template_urls,
190 TemplateURL** default_search_provider, 235 TemplateURL** default_search_provider,
191 int* new_resource_keyword_version, 236 int* new_resource_keyword_version,
192 std::set<std::string>* removed_keyword_guids) { 237 std::set<std::string>* removed_keyword_guids) {
193 DCHECK(service == NULL || BrowserThread::CurrentlyOn(BrowserThread::UI)); 238 DCHECK(service == NULL || BrowserThread::CurrentlyOn(BrowserThread::UI));
194 DCHECK(template_urls); 239 DCHECK(template_urls);
195 DCHECK(template_urls->empty()); 240 DCHECK(template_urls->empty());
196 DCHECK(default_search_provider); 241 DCHECK(default_search_provider);
197 DCHECK(*default_search_provider == NULL); 242 DCHECK(*default_search_provider == NULL);
198 DCHECK_EQ(result.GetType(), KEYWORDS_RESULT); 243 DCHECK_EQ(result.GetType(), KEYWORDS_RESULT);
199 DCHECK(new_resource_keyword_version); 244 DCHECK(new_resource_keyword_version);
200 245
201 *new_resource_keyword_version = 0; 246 *new_resource_keyword_version = 0;
202 WDKeywordsResult keyword_result = reinterpret_cast< 247 WDKeywordsResult keyword_result = reinterpret_cast<
203 const WDResult<WDKeywordsResult>*>(&result)->GetValue(); 248 const WDResult<WDKeywordsResult>*>(&result)->GetValue();
204 249
205 for (KeywordTable::Keywords::const_iterator i( 250 for (KeywordTable::Keywords::const_iterator i(
206 keyword_result.keywords.begin()); i != keyword_result.keywords.end(); 251 keyword_result.keywords.begin()); i != keyword_result.keywords.end();
207 ++i) 252 ++i)
208 template_urls->push_back(new TemplateURL(profile, *i)); 253 template_urls->push_back(new TemplateURL(profile, *i));
209 254
210 const int resource_keyword_version =
211 TemplateURLPrepopulateData::GetDataVersion(
212 profile ? profile->GetPrefs() : NULL);
213 if (keyword_result.builtin_keyword_version != resource_keyword_version) {
214 // There should never be duplicate TemplateURLs. We had a bug such that
215 // duplicate TemplateURLs existed for one locale. As such we invoke
216 // RemoveDuplicatePrepopulateIDs to nuke the duplicates.
217 RemoveDuplicatePrepopulateIDs(template_urls, service,
218 removed_keyword_guids);
219 }
220
221 int64 default_search_provider_id = keyword_result.default_search_provider_id; 255 int64 default_search_provider_id = keyword_result.default_search_provider_id;
222 if (default_search_provider_id) { 256 if (default_search_provider_id) {
223 *default_search_provider = 257 *default_search_provider =
224 GetTemplateURLByID(*template_urls, default_search_provider_id); 258 GetTemplateURLByID(*template_urls, default_search_provider_id);
225 } 259 }
226 260
261 std::vector<TemplateURL*> prepopulated_urls;
262 size_t default_search_index;
263 TemplateURLPrepopulateData::GetPrepopulatedEngines(profile,
264 &prepopulated_urls, &default_search_index);
265 RemoveDuplicatePrepopulateIDs(service, prepopulated_urls,
266 *default_search_provider, template_urls,
267 removed_keyword_guids);
268
269 const int resource_keyword_version =
270 TemplateURLPrepopulateData::GetDataVersion(
271 profile ? profile->GetPrefs() : NULL);
227 if (keyword_result.builtin_keyword_version != resource_keyword_version) { 272 if (keyword_result.builtin_keyword_version != resource_keyword_version) {
228 MergeEnginesFromPrepopulateData(profile, service, template_urls, 273 MergeEnginesFromPrepopulateData(profile, service, prepopulated_urls,
229 default_search_provider, 274 default_search_index, template_urls, default_search_provider,
230 removed_keyword_guids); 275 removed_keyword_guids);
231 *new_resource_keyword_version = resource_keyword_version; 276 *new_resource_keyword_version = resource_keyword_version;
232 } 277 }
233 } 278 }
234 279
235 bool DidDefaultSearchProviderChange( 280 bool DidDefaultSearchProviderChange(
236 const WDTypedResult& result, 281 const WDTypedResult& result,
237 Profile* profile, 282 Profile* profile,
238 scoped_ptr<TemplateURL>* backup_default_search_provider) { 283 scoped_ptr<TemplateURL>* backup_default_search_provider) {
239 DCHECK(backup_default_search_provider); 284 DCHECK(backup_default_search_provider);
240 DCHECK(!backup_default_search_provider->get()); 285 DCHECK(!backup_default_search_provider->get());
241 DCHECK_EQ(result.GetType(), KEYWORDS_RESULT); 286 DCHECK_EQ(result.GetType(), KEYWORDS_RESULT);
242 287
243 WDKeywordsResult keyword_result = reinterpret_cast< 288 WDKeywordsResult keyword_result = reinterpret_cast<
244 const WDResult<WDKeywordsResult>*>(&result)->GetValue(); 289 const WDResult<WDKeywordsResult>*>(&result)->GetValue();
245 290
246 if (!keyword_result.did_default_search_provider_change) 291 if (!keyword_result.did_default_search_provider_change)
247 return false; 292 return false;
248 293
249 if (keyword_result.backup_valid) { 294 if (keyword_result.backup_valid) {
250 backup_default_search_provider->reset(new TemplateURL(profile, 295 backup_default_search_provider->reset(new TemplateURL(profile,
251 keyword_result.default_search_provider_backup)); 296 keyword_result.default_search_provider_backup));
252 } 297 }
253 return true; 298 return true;
254 } 299 }
300
301 namespace testing {
302
303 void TestRemoveDuplicatePrepopulateIDs(
304 WebDataService* service,
305 const std::vector<TemplateURL*>& prepopulated_urls,
306 TemplateURL* default_search_provider,
307 TemplateURLService::TemplateURLVector* template_urls,
308 std::set<std::string>* removed_keyword_guids) {
309 RemoveDuplicatePrepopulateIDs(service, prepopulated_urls,
310 default_search_provider, template_urls, removed_keyword_guids);
311 }
312
313 } // namespace testing
OLDNEW
« no previous file with comments | « chrome/browser/search_engines/util.h ('k') | chrome/chrome_tests.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698