OLD | NEW |
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/autocomplete/autocomplete_controller.h" | 5 #include "chrome/browser/autocomplete/autocomplete_controller.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/format_macros.h" | 10 #include "base/format_macros.h" |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 search_provider_ = new SearchProvider(this, profile); | 203 search_provider_ = new SearchProvider(this, profile); |
204 providers_.push_back(search_provider_); | 204 providers_.push_back(search_provider_); |
205 } | 205 } |
206 if (provider_types & AutocompleteProvider::TYPE_SHORTCUTS) | 206 if (provider_types & AutocompleteProvider::TYPE_SHORTCUTS) |
207 providers_.push_back(new ShortcutsProvider(this, profile)); | 207 providers_.push_back(new ShortcutsProvider(this, profile)); |
208 if (provider_types & AutocompleteProvider::TYPE_ZERO_SUGGEST) { | 208 if (provider_types & AutocompleteProvider::TYPE_ZERO_SUGGEST) { |
209 zero_suggest_provider_ = ZeroSuggestProvider::Create(this, profile); | 209 zero_suggest_provider_ = ZeroSuggestProvider::Create(this, profile); |
210 if (zero_suggest_provider_) | 210 if (zero_suggest_provider_) |
211 providers_.push_back(zero_suggest_provider_); | 211 providers_.push_back(zero_suggest_provider_); |
212 } | 212 } |
213 | |
214 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) | |
215 (*i)->AddRef(); | |
216 } | 213 } |
217 | 214 |
218 AutocompleteController::~AutocompleteController() { | 215 AutocompleteController::~AutocompleteController() { |
219 // The providers may have tasks outstanding that hold refs to them. We need | 216 // The providers may have tasks outstanding that hold refs to them. We need |
220 // to ensure they won't call us back if they outlive us. (Practically, | 217 // to ensure they won't call us back if they outlive us. (Practically, |
221 // calling Stop() should also cancel those tasks and make it so that we hold | 218 // calling Stop() should also cancel those tasks and make it so that we hold |
222 // the only refs.) We also don't want to bother notifying anyone of our | 219 // the only refs.) We also don't want to bother notifying anyone of our |
223 // result changes here, because the notification observer is in the midst of | 220 // result changes here, because the notification observer is in the midst of |
224 // shutdown too, so we don't ask Stop() to clear |result_| (and notify). | 221 // shutdown too, so we don't ask Stop() to clear |result_| (and notify). |
225 result_.Reset(); // Not really necessary. | 222 result_.Reset(); // Not really necessary. |
226 Stop(false); | 223 Stop(false); |
227 | |
228 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); ++i) | |
229 (*i)->Release(); | |
230 | |
231 providers_.clear(); // Not really necessary. | |
232 } | 224 } |
233 | 225 |
234 void AutocompleteController::Start(const AutocompleteInput& input) { | 226 void AutocompleteController::Start(const AutocompleteInput& input) { |
235 const base::string16 old_input_text(input_.text()); | 227 const base::string16 old_input_text(input_.text()); |
236 const bool old_want_asynchronous_matches = input_.want_asynchronous_matches(); | 228 const bool old_want_asynchronous_matches = input_.want_asynchronous_matches(); |
237 input_ = input; | 229 input_ = input; |
238 | 230 |
239 // See if we can avoid rerunning autocomplete when the query hasn't changed | 231 // See if we can avoid rerunning autocomplete when the query hasn't changed |
240 // much. When the user presses or releases the ctrl key, the desired_tld | 232 // much. When the user presses or releases the ctrl key, the desired_tld |
241 // changes, and when the user finishes an IME composition, inline autocomplete | 233 // changes, and when the user finishes an IME composition, inline autocomplete |
242 // may no longer be prevented. In both these cases the text itself hasn't | 234 // may no longer be prevented. In both these cases the text itself hasn't |
243 // changed since the last query, and some providers can do much less work (and | 235 // changed since the last query, and some providers can do much less work (and |
244 // get matches back more quickly). Taking advantage of this reduces flicker. | 236 // get matches back more quickly). Taking advantage of this reduces flicker. |
245 // | 237 // |
246 // NOTE: This comes after constructing |input_| above since that construction | 238 // NOTE: This comes after constructing |input_| above since that construction |
247 // can change the text string (e.g. by stripping off a leading '?'). | 239 // can change the text string (e.g. by stripping off a leading '?'). |
248 const bool minimal_changes = (input_.text() == old_input_text) && | 240 const bool minimal_changes = (input_.text() == old_input_text) && |
249 (input_.want_asynchronous_matches() == old_want_asynchronous_matches); | 241 (input_.want_asynchronous_matches() == old_want_asynchronous_matches); |
250 | 242 |
251 expire_timer_.Stop(); | 243 expire_timer_.Stop(); |
252 stop_timer_.Stop(); | 244 stop_timer_.Stop(); |
253 | 245 |
254 // Start the new query. | 246 // Start the new query. |
255 in_start_ = true; | 247 in_start_ = true; |
256 base::TimeTicks start_time = base::TimeTicks::Now(); | 248 base::TimeTicks start_time = base::TimeTicks::Now(); |
257 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); | 249 for (Providers::iterator i(providers_.begin()); i != providers_.end(); ++i) { |
258 ++i) { | |
259 // TODO(mpearson): Remove timing code once bugs 178705 / 237703 / 168933 | 250 // TODO(mpearson): Remove timing code once bugs 178705 / 237703 / 168933 |
260 // are resolved. | 251 // are resolved. |
261 base::TimeTicks provider_start_time = base::TimeTicks::Now(); | 252 base::TimeTicks provider_start_time = base::TimeTicks::Now(); |
262 | 253 |
263 // Call Start() on ZeroSuggestProvider with an INVALID AutocompleteInput | 254 // Call Start() on ZeroSuggestProvider with an INVALID AutocompleteInput |
264 // to clear out zero-suggest |matches_|. | 255 // to clear out zero-suggest |matches_|. |
265 if (*i == zero_suggest_provider_) | 256 if (*i == zero_suggest_provider_) |
266 (*i)->Start(AutocompleteInput(), minimal_changes); | 257 (*i)->Start(AutocompleteInput(), minimal_changes); |
267 else | 258 else |
268 (*i)->Start(input_, minimal_changes); | 259 (*i)->Start(input_, minimal_changes); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 // need the edit model to update the display. | 292 // need the edit model to update the display. |
302 UpdateResult(false, true); | 293 UpdateResult(false, true); |
303 | 294 |
304 if (!done_) { | 295 if (!done_) { |
305 StartExpireTimer(); | 296 StartExpireTimer(); |
306 StartStopTimer(); | 297 StartStopTimer(); |
307 } | 298 } |
308 } | 299 } |
309 | 300 |
310 void AutocompleteController::Stop(bool clear_result) { | 301 void AutocompleteController::Stop(bool clear_result) { |
311 for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); | 302 for (Providers::const_iterator i(providers_.begin()); i != providers_.end(); |
312 ++i) { | 303 ++i) { |
313 (*i)->Stop(clear_result); | 304 (*i)->Stop(clear_result); |
314 } | 305 } |
315 | 306 |
316 expire_timer_.Stop(); | 307 expire_timer_.Stop(); |
317 stop_timer_.Stop(); | 308 stop_timer_.Stop(); |
318 done_ = true; | 309 done_ = true; |
319 if (clear_result && !result_.empty()) { | 310 if (clear_result && !result_.empty()) { |
320 result_.Reset(); | 311 result_.Reset(); |
321 // NOTE: We pass in false since we're trying to only clear the popup, not | 312 // NOTE: We pass in false since we're trying to only clear the popup, not |
322 // touch the edit... this is all a mess and should be cleaned up :( | 313 // touch the edit... this is all a mess and should be cleaned up :( |
323 NotifyChanged(false); | 314 NotifyChanged(false); |
324 } | 315 } |
325 } | 316 } |
326 | 317 |
327 void AutocompleteController::StartZeroSuggest(const AutocompleteInput& input) { | 318 void AutocompleteController::StartZeroSuggest(const AutocompleteInput& input) { |
328 if (zero_suggest_provider_ == NULL) | 319 if (zero_suggest_provider_ == NULL) |
329 return; | 320 return; |
330 | 321 |
331 DCHECK(!in_start_); // We should not be already running a query. | 322 DCHECK(!in_start_); // We should not be already running a query. |
332 | 323 |
333 // Call Start() on all prefix-based providers with an INVALID | 324 // Call Start() on all prefix-based providers with an INVALID |
334 // AutocompleteInput to clear out cached |matches_|, which ensures that | 325 // AutocompleteInput to clear out cached |matches_|, which ensures that |
335 // they aren't used with zero suggest. | 326 // they aren't used with zero suggest. |
336 for (ACProviders::iterator i(providers_.begin()); i != providers_.end(); | 327 for (Providers::iterator i(providers_.begin()); i != providers_.end(); ++i) { |
337 ++i) { | |
338 if (*i == zero_suggest_provider_) | 328 if (*i == zero_suggest_provider_) |
339 (*i)->Start(input, false); | 329 (*i)->Start(input, false); |
340 else | 330 else |
341 (*i)->Start(AutocompleteInput(), false); | 331 (*i)->Start(AutocompleteInput(), false); |
342 } | 332 } |
343 | 333 |
344 if (!zero_suggest_provider_->matches().empty()) | 334 if (!zero_suggest_provider_->matches().empty()) |
345 UpdateResult(false, false); | 335 UpdateResult(false, false); |
346 } | 336 } |
347 | 337 |
(...skipping 28 matching lines...) Expand all Loading... |
376 CheckIfDone(); | 366 CheckIfDone(); |
377 // Multiple providers may provide synchronous results, so we only update the | 367 // Multiple providers may provide synchronous results, so we only update the |
378 // results if we're not in Start(). | 368 // results if we're not in Start(). |
379 if (!in_start_ && (updated_matches || done_)) | 369 if (!in_start_ && (updated_matches || done_)) |
380 UpdateResult(false, false); | 370 UpdateResult(false, false); |
381 } | 371 } |
382 | 372 |
383 void AutocompleteController::AddProvidersInfo( | 373 void AutocompleteController::AddProvidersInfo( |
384 ProvidersInfo* provider_info) const { | 374 ProvidersInfo* provider_info) const { |
385 provider_info->clear(); | 375 provider_info->clear(); |
386 for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); | 376 for (Providers::const_iterator i(providers_.begin()); i != providers_.end(); |
387 ++i) { | 377 ++i) { |
388 // Add per-provider info, if any. | 378 // Add per-provider info, if any. |
389 (*i)->AddProviderInfo(provider_info); | 379 (*i)->AddProviderInfo(provider_info); |
390 | 380 |
391 // This is also a good place to put code to add info that you want to | 381 // This is also a good place to put code to add info that you want to |
392 // add for every provider. | 382 // add for every provider. |
393 } | 383 } |
394 } | 384 } |
395 | 385 |
396 void AutocompleteController::ResetSession() { | 386 void AutocompleteController::ResetSession() { |
397 for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); | 387 for (Providers::const_iterator i(providers_.begin()); i != providers_.end(); |
398 ++i) | 388 ++i) |
399 (*i)->ResetSession(); | 389 (*i)->ResetSession(); |
400 } | 390 } |
401 | 391 |
402 void AutocompleteController::UpdateMatchDestinationURL( | 392 void AutocompleteController::UpdateMatchDestinationURL( |
403 base::TimeDelta query_formulation_time, | 393 base::TimeDelta query_formulation_time, |
404 AutocompleteMatch* match) const { | 394 AutocompleteMatch* match) const { |
405 TemplateURL* template_url = match->GetTemplateURL( | 395 TemplateURL* template_url = match->GetTemplateURL( |
406 template_url_service_, false); | 396 template_url_service_, false); |
407 if (!template_url || !match->search_terms_args.get() || | 397 if (!template_url || !match->search_terms_args.get() || |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 last_default_associated_keyword = | 429 last_default_associated_keyword = |
440 result_.default_match()->associated_keyword->keyword; | 430 result_.default_match()->associated_keyword->keyword; |
441 } | 431 } |
442 | 432 |
443 if (regenerate_result) | 433 if (regenerate_result) |
444 result_.Reset(); | 434 result_.Reset(); |
445 | 435 |
446 AutocompleteResult last_result; | 436 AutocompleteResult last_result; |
447 last_result.Swap(&result_); | 437 last_result.Swap(&result_); |
448 | 438 |
449 for (ACProviders::const_iterator i(providers_.begin()); | 439 for (Providers::const_iterator i(providers_.begin()); |
450 i != providers_.end(); ++i) | 440 i != providers_.end(); ++i) |
451 result_.AppendMatches((*i)->matches()); | 441 result_.AppendMatches((*i)->matches()); |
452 | 442 |
453 // Sort the matches and trim to a small number of "best" matches. | 443 // Sort the matches and trim to a small number of "best" matches. |
454 result_.SortAndCull(input_, template_url_service_); | 444 result_.SortAndCull(input_, template_url_service_); |
455 | 445 |
456 // Need to validate before invoking CopyOldMatches as the old matches are not | 446 // Need to validate before invoking CopyOldMatches as the old matches are not |
457 // valid against the current input. | 447 // valid against the current input. |
458 #ifndef NDEBUG | 448 #ifndef NDEBUG |
459 result_.Validate(); | 449 result_.Validate(); |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 delegate_->OnResultChanged(notify_default_match); | 609 delegate_->OnResultChanged(notify_default_match); |
620 if (done_) { | 610 if (done_) { |
621 content::NotificationService::current()->Notify( | 611 content::NotificationService::current()->Notify( |
622 chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY, | 612 chrome::NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY, |
623 content::Source<AutocompleteController>(this), | 613 content::Source<AutocompleteController>(this), |
624 content::NotificationService::NoDetails()); | 614 content::NotificationService::NoDetails()); |
625 } | 615 } |
626 } | 616 } |
627 | 617 |
628 void AutocompleteController::CheckIfDone() { | 618 void AutocompleteController::CheckIfDone() { |
629 for (ACProviders::const_iterator i(providers_.begin()); i != providers_.end(); | 619 for (Providers::const_iterator i(providers_.begin()); i != providers_.end(); |
630 ++i) { | 620 ++i) { |
631 if (!(*i)->done()) { | 621 if (!(*i)->done()) { |
632 done_ = false; | 622 done_ = false; |
633 return; | 623 return; |
634 } | 624 } |
635 } | 625 } |
636 done_ = true; | 626 done_ = true; |
637 } | 627 } |
638 | 628 |
639 void AutocompleteController::StartExpireTimer() { | 629 void AutocompleteController::StartExpireTimer() { |
640 // Amount of time (in ms) between when the user stops typing and | 630 // Amount of time (in ms) between when the user stops typing and |
641 // when we remove any copied entries. We do this from the time the | 631 // when we remove any copied entries. We do this from the time the |
642 // user stopped typing as some providers (such as SearchProvider) | 632 // user stopped typing as some providers (such as SearchProvider) |
643 // wait for the user to stop typing before they initiate a query. | 633 // wait for the user to stop typing before they initiate a query. |
644 const int kExpireTimeMS = 500; | 634 const int kExpireTimeMS = 500; |
645 | 635 |
646 if (result_.HasCopiedMatches()) | 636 if (result_.HasCopiedMatches()) |
647 expire_timer_.Start(FROM_HERE, | 637 expire_timer_.Start(FROM_HERE, |
648 base::TimeDelta::FromMilliseconds(kExpireTimeMS), | 638 base::TimeDelta::FromMilliseconds(kExpireTimeMS), |
649 this, &AutocompleteController::ExpireCopiedEntries); | 639 this, &AutocompleteController::ExpireCopiedEntries); |
650 } | 640 } |
651 | 641 |
652 void AutocompleteController::StartStopTimer() { | 642 void AutocompleteController::StartStopTimer() { |
653 stop_timer_.Start(FROM_HERE, | 643 stop_timer_.Start(FROM_HERE, |
654 stop_timer_duration_, | 644 stop_timer_duration_, |
655 base::Bind(&AutocompleteController::Stop, | 645 base::Bind(&AutocompleteController::Stop, |
656 base::Unretained(this), | 646 base::Unretained(this), |
657 false)); | 647 false)); |
658 } | 648 } |
OLD | NEW |