| 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/instant/instant_controller.h" | 5 #include "chrome/browser/instant/instant_controller.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/i18n/case_conversion.h" | 8 #include "base/i18n/case_conversion.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| 11 #include "chrome/browser/autocomplete/autocomplete_provider.h" | 11 #include "chrome/browser/autocomplete/autocomplete_provider.h" |
| 12 #include "chrome/browser/favicon/favicon_service_factory.h" | 12 #include "chrome/browser/favicon/favicon_service_factory.h" |
| 13 #include "chrome/browser/history/history.h" | 13 #include "chrome/browser/history/history.h" |
| 14 #include "chrome/browser/history/history_service_factory.h" | 14 #include "chrome/browser/history/history_service_factory.h" |
| 15 #include "chrome/browser/history/history_tab_helper.h" | 15 #include "chrome/browser/history/history_tab_helper.h" |
| 16 #include "chrome/browser/instant/instant_controller_delegate.h" | 16 #include "chrome/browser/instant/instant_controller_delegate.h" |
| 17 #include "chrome/browser/instant/instant_loader.h" | 17 #include "chrome/browser/instant/instant_loader.h" |
| 18 #include "chrome/browser/platform_util.h" | 18 #include "chrome/browser/platform_util.h" |
| 19 #include "chrome/browser/prefs/pref_service.h" | 19 #include "chrome/browser/prefs/pref_service.h" |
| 20 #include "chrome/browser/search_engines/template_url_service.h" | 20 #include "chrome/browser/search_engines/template_url_service.h" |
| 21 #include "chrome/browser/search_engines/template_url_service_factory.h" | 21 #include "chrome/browser/search_engines/template_url_service_factory.h" |
| 22 #include "chrome/browser/ui/search/search.h" |
| 22 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 23 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
| 23 #include "chrome/common/chrome_notification_types.h" | 24 #include "chrome/common/chrome_notification_types.h" |
| 24 #include "chrome/common/chrome_switches.h" | 25 #include "chrome/common/chrome_switches.h" |
| 25 #include "chrome/common/pref_names.h" | 26 #include "chrome/common/pref_names.h" |
| 26 #include "content/public/browser/favicon_status.h" | 27 #include "content/public/browser/favicon_status.h" |
| 27 #include "content/public/browser/navigation_entry.h" | 28 #include "content/public/browser/navigation_entry.h" |
| 28 #include "content/public/browser/notification_service.h" | 29 #include "content/public/browser/notification_service.h" |
| 29 #include "content/public/browser/render_widget_host_view.h" | 30 #include "content/public/browser/render_widget_host_view.h" |
| 30 #include "content/public/browser/web_contents.h" | 31 #include "content/public/browser/web_contents.h" |
| 31 #include "ui/gfx/codec/png_codec.h" | 32 #include "ui/gfx/codec/png_codec.h" |
| (...skipping 21 matching lines...) Expand all Loading... |
| 53 // The maximum number of times we'll load a non-Instant-supporting search engine | 54 // The maximum number of times we'll load a non-Instant-supporting search engine |
| 54 // before we give up and blacklist it for the rest of the browsing session. | 55 // before we give up and blacklist it for the rest of the browsing session. |
| 55 const int kMaxInstantSupportFailures = 10; | 56 const int kMaxInstantSupportFailures = 10; |
| 56 | 57 |
| 57 // If an Instant page has not been used in these many milliseconds, it is | 58 // If an Instant page has not been used in these many milliseconds, it is |
| 58 // reloaded so that the page does not become stale. | 59 // reloaded so that the page does not become stale. |
| 59 const int kStaleLoaderTimeoutMS = 3 * 3600 * 1000; | 60 const int kStaleLoaderTimeoutMS = 3 * 3600 * 1000; |
| 60 | 61 |
| 61 std::string ModeToString(InstantController::Mode mode) { | 62 std::string ModeToString(InstantController::Mode mode) { |
| 62 switch (mode) { | 63 switch (mode) { |
| 64 case InstantController::EXTENDED: return "_Extended"; |
| 63 case InstantController::INSTANT: return "_Instant"; | 65 case InstantController::INSTANT: return "_Instant"; |
| 64 case InstantController::SUGGEST: return "_Suggest"; | 66 case InstantController::SUGGEST: return "_Suggest"; |
| 65 case InstantController::HIDDEN: return "_Hidden"; | 67 case InstantController::HIDDEN: return "_Hidden"; |
| 66 case InstantController::SILENT: return "_Silent"; | 68 case InstantController::SILENT: return "_Silent"; |
| 67 case InstantController::EXTENDED: return "_Extended"; | 69 case InstantController::DISABLED: return "_Disabled"; |
| 68 } | 70 } |
| 69 | 71 |
| 70 NOTREACHED(); | 72 NOTREACHED(); |
| 71 return std::string(); | 73 return std::string(); |
| 72 } | 74 } |
| 73 | 75 |
| 74 void AddPreviewUsageForHistogram(InstantController::Mode mode, | 76 void AddPreviewUsageForHistogram(InstantController::Mode mode, |
| 75 PreviewUsageType usage) { | 77 PreviewUsageType usage) { |
| 76 DCHECK(0 <= usage && usage < PREVIEW_NUM_TYPES) << usage; | 78 DCHECK(0 <= usage && usage < PREVIEW_NUM_TYPES) << usage; |
| 77 base::Histogram* histogram = base::LinearHistogram::FactoryGet( | 79 base::Histogram* histogram = base::LinearHistogram::FactoryGet( |
| (...skipping 24 matching lines...) Expand all Loading... |
| 102 ++it1, ++it2) { | 104 ++it1, ++it2) { |
| 103 if (it1->first != it2->first || it1->second != it2->second) { | 105 if (it1->first != it2->first || it1->second != it2->second) { |
| 104 is_session_storage_the_same = false; | 106 is_session_storage_the_same = false; |
| 105 break; | 107 break; |
| 106 } | 108 } |
| 107 } | 109 } |
| 108 } | 110 } |
| 109 histogram->AddBoolean(is_session_storage_the_same); | 111 histogram->AddBoolean(is_session_storage_the_same); |
| 110 } | 112 } |
| 111 | 113 |
| 114 InstantController::Mode GetModeForProfile(Profile* profile) { |
| 115 if (!profile || profile->IsOffTheRecord() || !profile->GetPrefs() || |
| 116 !profile->GetPrefs()->GetBoolean(prefs::kInstantEnabled)) |
| 117 return InstantController::DISABLED; |
| 118 |
| 119 return chrome::search::IsInstantExtendedAPIEnabled(profile) ? |
| 120 InstantController::EXTENDED : InstantController::INSTANT; |
| 121 } |
| 122 |
| 112 } // namespace | 123 } // namespace |
| 113 | 124 |
| 114 InstantController::InstantController(InstantControllerDelegate* delegate, | |
| 115 Mode mode) | |
| 116 : delegate_(delegate), | |
| 117 mode_(mode), | |
| 118 last_active_tab_(NULL), | |
| 119 last_verbatim_(false), | |
| 120 last_transition_type_(content::PAGE_TRANSITION_LINK), | |
| 121 is_showing_(false), | |
| 122 loader_processed_last_update_(false) { | |
| 123 } | |
| 124 | |
| 125 InstantController::~InstantController() { | 125 InstantController::~InstantController() { |
| 126 if (GetPreviewContents()) | 126 if (GetPreviewContents()) |
| 127 AddPreviewUsageForHistogram(mode_, PREVIEW_DELETED); | 127 AddPreviewUsageForHistogram(mode_, PREVIEW_DELETED); |
| 128 } | 128 } |
| 129 | 129 |
| 130 // static | 130 // static |
| 131 InstantController* InstantController::CreateInstant( |
| 132 Profile* profile, |
| 133 InstantControllerDelegate* delegate) { |
| 134 const Mode mode = GetModeForProfile(profile); |
| 135 return mode == DISABLED ? NULL : new InstantController(delegate, mode); |
| 136 } |
| 137 |
| 138 // static |
| 139 bool InstantController::IsExtendedAPIEnabled(Profile* profile) { |
| 140 return GetModeForProfile(profile) == EXTENDED; |
| 141 } |
| 142 |
| 143 // static |
| 144 bool InstantController::IsInstantEnabled(Profile* profile) { |
| 145 const Mode mode = GetModeForProfile(profile); |
| 146 return mode == EXTENDED || mode == INSTANT; |
| 147 } |
| 148 |
| 149 // static |
| 150 bool InstantController::IsSuggestEnabled(Profile* profile) { |
| 151 const Mode mode = GetModeForProfile(profile); |
| 152 return mode == EXTENDED || mode == INSTANT || mode == SUGGEST; |
| 153 } |
| 154 |
| 155 // static |
| 131 void InstantController::RegisterUserPrefs(PrefService* prefs) { | 156 void InstantController::RegisterUserPrefs(PrefService* prefs) { |
| 132 prefs->RegisterBooleanPref(prefs::kInstantConfirmDialogShown, false, | 157 prefs->RegisterBooleanPref(prefs::kInstantConfirmDialogShown, false, |
| 133 PrefService::SYNCABLE_PREF); | 158 PrefService::SYNCABLE_PREF); |
| 134 prefs->RegisterBooleanPref(prefs::kInstantEnabled, false, | 159 prefs->RegisterBooleanPref(prefs::kInstantEnabled, false, |
| 135 PrefService::SYNCABLE_PREF); | 160 PrefService::SYNCABLE_PREF); |
| 136 | 161 |
| 137 // TODO(jamescook): Move this to search controller. | 162 // TODO(jamescook): Move this to search controller. |
| 138 prefs->RegisterDoublePref(prefs::kInstantAnimationScaleFactor, | 163 prefs->RegisterDoublePref(prefs::kInstantAnimationScaleFactor, 1.0, |
| 139 1.0, | |
| 140 PrefService::UNSYNCABLE_PREF); | 164 PrefService::UNSYNCABLE_PREF); |
| 141 } | 165 } |
| 142 | 166 |
| 143 // static | |
| 144 bool InstantController::IsEnabled(Profile* profile) { | |
| 145 const PrefService* prefs = profile ? profile->GetPrefs() : NULL; | |
| 146 return prefs && prefs->GetBoolean(prefs::kInstantEnabled); | |
| 147 } | |
| 148 | |
| 149 bool InstantController::Update(const AutocompleteMatch& match, | 167 bool InstantController::Update(const AutocompleteMatch& match, |
| 150 const string16& user_text, | 168 const string16& user_text, |
| 151 const string16& full_text, | 169 const string16& full_text, |
| 152 bool verbatim) { | 170 bool verbatim) { |
| 153 const TabContents* active_tab = delegate_->GetActiveTabContents(); | 171 const TabContents* active_tab = delegate_->GetActiveTabContents(); |
| 154 | 172 |
| 155 // We could get here with no active tab if the Browser is closing. | 173 // We could get here with no active tab if the Browser is closing. |
| 156 if (!active_tab) { | 174 if (!active_tab) { |
| 157 Hide(); | 175 Hide(); |
| 158 return false; | 176 return false; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 175 ResetLoader(instant_url, active_tab); | 193 ResetLoader(instant_url, active_tab); |
| 176 last_active_tab_ = active_tab; | 194 last_active_tab_ = active_tab; |
| 177 | 195 |
| 178 // Track the non-Instant search URL for this query. | 196 // Track the non-Instant search URL for this query. |
| 179 url_for_history_ = match.destination_url; | 197 url_for_history_ = match.destination_url; |
| 180 last_transition_type_ = match.transition; | 198 last_transition_type_ = match.transition; |
| 181 | 199 |
| 182 // In EXTENDED mode, we send only |user_text| as the query text. In all other | 200 // In EXTENDED mode, we send only |user_text| as the query text. In all other |
| 183 // modes, we use the entire |full_text|. | 201 // modes, we use the entire |full_text|. |
| 184 const string16& query_text = mode_ == EXTENDED ? user_text : full_text; | 202 const string16& query_text = mode_ == EXTENDED ? user_text : full_text; |
| 185 string16 last_query_text = | 203 string16 last_query_text = mode_ == EXTENDED ? |
| 186 mode_ == EXTENDED ? last_user_text_ : last_full_text_; | 204 last_user_text_ : last_full_text_; |
| 187 last_user_text_ = user_text; | 205 last_user_text_ = user_text; |
| 188 last_full_text_ = full_text; | 206 last_full_text_ = full_text; |
| 189 | 207 |
| 190 // Don't send an update to the loader if the query text hasn't changed. | 208 // Don't send an update to the loader if the query text hasn't changed. |
| 191 if (query_text == last_query_text && verbatim == last_verbatim_) { | 209 if (query_text == last_query_text && verbatim == last_verbatim_) { |
| 192 // Reuse the last suggestion, as it's still valid. | 210 // Reuse the last suggestion, as it's still valid. |
| 193 delegate_->SetSuggestedText(last_suggestion_.text, | 211 delegate_->SetSuggestedText(last_suggestion_.text, |
| 194 last_suggestion_.behavior); | 212 last_suggestion_.behavior); |
| 195 | 213 |
| 196 // We need to call Show() here because of this: | 214 // We need to call Show() here because of this: |
| 197 // 1. User has typed a query (say Q). Instant overlay is showing results. | 215 // 1. User has typed a query (say Q). Instant overlay is showing results. |
| 198 // 2. User arrows-down to a URL entry or erases all omnibox text. Both of | 216 // 2. User arrows-down to a URL entry or erases all omnibox text. Both of |
| 199 // these cause the overlay to Hide(). | 217 // these cause the overlay to Hide(). |
| 200 // 3. User arrows-up to Q or types Q again. The last text we processed is | 218 // 3. User arrows-up to Q or types Q again. The last text we processed is |
| 201 // still Q, so we don't Update() the loader, but we do need to Show(). | 219 // still Q, so we don't Update() the loader, but we do need to Show(). |
| 202 if (loader_processed_last_update_ && | 220 if (loader_processed_last_update_ && |
| 203 (mode_ == INSTANT || mode_ == EXTENDED)) { | 221 (mode_ == INSTANT || mode_ == EXTENDED)) |
| 204 Show(); | 222 Show(); |
| 205 } | |
| 206 return true; | 223 return true; |
| 207 } | 224 } |
| 208 | 225 |
| 209 last_verbatim_ = verbatim; | 226 last_verbatim_ = verbatim; |
| 210 loader_processed_last_update_ = false; | 227 loader_processed_last_update_ = false; |
| 211 last_suggestion_ = InstantSuggestion(); | 228 last_suggestion_ = InstantSuggestion(); |
| 212 | 229 |
| 213 if (mode_ != SILENT) { | 230 if (mode_ != SILENT) { |
| 214 loader_->Update(query_text, verbatim); | 231 loader_->Update(query_text, verbatim); |
| 215 | 232 |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 | 475 |
| 459 loader_processed_last_update_ = true; | 476 loader_processed_last_update_ = true; |
| 460 | 477 |
| 461 InstantSuggestion suggestion; | 478 InstantSuggestion suggestion; |
| 462 if (!suggestions.empty()) | 479 if (!suggestions.empty()) |
| 463 suggestion = suggestions[0]; | 480 suggestion = suggestions[0]; |
| 464 | 481 |
| 465 string16 suggestion_lower = base::i18n::ToLower(suggestion.text); | 482 string16 suggestion_lower = base::i18n::ToLower(suggestion.text); |
| 466 string16 user_text_lower = base::i18n::ToLower(last_user_text_); | 483 string16 user_text_lower = base::i18n::ToLower(last_user_text_); |
| 467 if (user_text_lower.size() >= suggestion_lower.size() || | 484 if (user_text_lower.size() >= suggestion_lower.size() || |
| 468 suggestion_lower.compare(0, user_text_lower.size(), user_text_lower)) { | 485 suggestion_lower.compare(0, user_text_lower.size(), user_text_lower)) |
| 469 suggestion.text.clear(); | 486 suggestion.text.clear(); |
| 470 } else { | 487 else |
| 471 suggestion.text.erase(0, last_user_text_.size()); | 488 suggestion.text.erase(0, last_user_text_.size()); |
| 472 } | |
| 473 | 489 |
| 474 last_suggestion_ = suggestion; | 490 last_suggestion_ = suggestion; |
| 475 if (!last_verbatim_) | 491 if (!last_verbatim_) |
| 476 delegate_->SetSuggestedText(suggestion.text, suggestion.behavior); | 492 delegate_->SetSuggestedText(suggestion.text, suggestion.behavior); |
| 477 | 493 |
| 478 if (mode_ != SUGGEST) | 494 if (mode_ != SUGGEST) |
| 479 Show(); | 495 Show(); |
| 480 } | 496 } |
| 481 | 497 |
| 482 void InstantController::CommitInstantLoader(InstantLoader* loader) { | 498 void InstantController::CommitInstantLoader(InstantLoader* loader) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 DCHECK_EQ(loader_.get(), loader); | 543 DCHECK_EQ(loader_.get(), loader); |
| 528 DCHECK(is_showing_ && !IsOutOfDate()) << is_showing_; | 544 DCHECK(is_showing_ && !IsOutOfDate()) << is_showing_; |
| 529 #if defined(USE_AURA) | 545 #if defined(USE_AURA) |
| 530 // On aura the omnibox only receives a focus lost if we initiate the focus | 546 // On aura the omnibox only receives a focus lost if we initiate the focus |
| 531 // change. This does that. | 547 // change. This does that. |
| 532 if (is_showing_ && !IsOutOfDate()) | 548 if (is_showing_ && !IsOutOfDate()) |
| 533 delegate_->InstantPreviewFocused(); | 549 delegate_->InstantPreviewFocused(); |
| 534 #endif | 550 #endif |
| 535 } | 551 } |
| 536 | 552 |
| 553 InstantController::InstantController(InstantControllerDelegate* delegate, |
| 554 Mode mode) |
| 555 : delegate_(delegate), |
| 556 mode_(mode), |
| 557 last_active_tab_(NULL), |
| 558 last_verbatim_(false), |
| 559 last_transition_type_(content::PAGE_TRANSITION_LINK), |
| 560 is_showing_(false), |
| 561 loader_processed_last_update_(false) { |
| 562 } |
| 563 |
| 537 void InstantController::ResetLoader(const std::string& instant_url, | 564 void InstantController::ResetLoader(const std::string& instant_url, |
| 538 const TabContents* active_tab) { | 565 const TabContents* active_tab) { |
| 539 if (GetPreviewContents() && loader_->instant_url() != instant_url) | 566 if (GetPreviewContents() && loader_->instant_url() != instant_url) |
| 540 DeleteLoader(); | 567 DeleteLoader(); |
| 541 | 568 |
| 542 if (!GetPreviewContents()) { | 569 if (!GetPreviewContents()) { |
| 543 DCHECK(!loader_.get()); | 570 DCHECK(!loader_.get()); |
| 544 loader_.reset(new InstantLoader(this, instant_url, active_tab)); | 571 loader_.reset(new InstantLoader(this, instant_url, active_tab)); |
| 545 loader_->Init(); | 572 loader_->Init(); |
| 546 AddPreviewUsageForHistogram(mode_, PREVIEW_CREATED); | 573 AddPreviewUsageForHistogram(mode_, PREVIEW_CREATED); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 void InstantController::Show() { | 630 void InstantController::Show() { |
| 604 if (!is_showing_) { | 631 if (!is_showing_) { |
| 605 is_showing_ = true; | 632 is_showing_ = true; |
| 606 delegate_->ShowInstant(); | 633 delegate_->ShowInstant(); |
| 607 AddPreviewUsageForHistogram(mode_, PREVIEW_SHOWED); | 634 AddPreviewUsageForHistogram(mode_, PREVIEW_SHOWED); |
| 608 } | 635 } |
| 609 } | 636 } |
| 610 | 637 |
| 611 void InstantController::SendBoundsToPage() { | 638 void InstantController::SendBoundsToPage() { |
| 612 if (last_omnibox_bounds_ == omnibox_bounds_ || IsOutOfDate() || | 639 if (last_omnibox_bounds_ == omnibox_bounds_ || IsOutOfDate() || |
| 613 !GetPreviewContents() || loader_->IsPointerDownFromActivate()) { | 640 !GetPreviewContents() || loader_->IsPointerDownFromActivate()) |
| 614 return; | 641 return; |
| 615 } | |
| 616 | 642 |
| 617 last_omnibox_bounds_ = omnibox_bounds_; | 643 last_omnibox_bounds_ = omnibox_bounds_; |
| 618 gfx::Rect preview_bounds = delegate_->GetInstantBounds(); | 644 gfx::Rect preview_bounds = delegate_->GetInstantBounds(); |
| 619 gfx::Rect intersection = omnibox_bounds_.Intersect(preview_bounds); | 645 gfx::Rect intersection = omnibox_bounds_.Intersect(preview_bounds); |
| 620 | 646 |
| 621 // Translate into window coordinates. | 647 // Translate into window coordinates. |
| 622 if (!intersection.IsEmpty()) { | 648 if (!intersection.IsEmpty()) { |
| 623 intersection.Offset(-preview_bounds.origin().x(), | 649 intersection.Offset(-preview_bounds.origin().x(), |
| 624 -preview_bounds.origin().y()); | 650 -preview_bounds.origin().y()); |
| 625 } | 651 } |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 675 if (!url_obj.is_valid()) | 701 if (!url_obj.is_valid()) |
| 676 return false; | 702 return false; |
| 677 | 703 |
| 678 *instant_url = url_obj.spec(); | 704 *instant_url = url_obj.spec(); |
| 679 } | 705 } |
| 680 } | 706 } |
| 681 | 707 |
| 682 std::map<std::string, int>::const_iterator iter = | 708 std::map<std::string, int>::const_iterator iter = |
| 683 blacklisted_urls_.find(*instant_url); | 709 blacklisted_urls_.find(*instant_url); |
| 684 if (iter != blacklisted_urls_.end() && | 710 if (iter != blacklisted_urls_.end() && |
| 685 iter->second > kMaxInstantSupportFailures) { | 711 iter->second > kMaxInstantSupportFailures) |
| 686 return false; | 712 return false; |
| 687 } | |
| 688 | 713 |
| 689 return true; | 714 return true; |
| 690 } | 715 } |
| 691 | 716 |
| 692 bool InstantController::IsOutOfDate() const { | 717 bool InstantController::IsOutOfDate() const { |
| 693 return !last_active_tab_ || | 718 return !last_active_tab_ || |
| 694 last_active_tab_ != delegate_->GetActiveTabContents(); | 719 last_active_tab_ != delegate_->GetActiveTabContents(); |
| 695 } | 720 } |
| OLD | NEW |