| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 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 "components/omnibox/browser/omnibox_edit_model.h" | 5 #include "components/omnibox/browser/omnibox_edit_model.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <utility> | 9 #include <utility> |
| 10 | 10 |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 // between focusing and opening an omnibox match. | 82 // between focusing and opening an omnibox match. |
| 83 const char kFocusToOpenTimeHistogram[] = | 83 const char kFocusToOpenTimeHistogram[] = |
| 84 "Omnibox.FocusToOpenTimeAnyPopupState2"; | 84 "Omnibox.FocusToOpenTimeAnyPopupState2"; |
| 85 | 85 |
| 86 // Split the percentage match histograms into buckets based on the width of the | 86 // Split the percentage match histograms into buckets based on the width of the |
| 87 // omnibox. | 87 // omnibox. |
| 88 const int kPercentageMatchHistogramWidthBuckets[] = { 400, 700, 1200 }; | 88 const int kPercentageMatchHistogramWidthBuckets[] = { 400, 700, 1200 }; |
| 89 | 89 |
| 90 void RecordPercentageMatchHistogram(const base::string16& old_text, | 90 void RecordPercentageMatchHistogram(const base::string16& old_text, |
| 91 const base::string16& new_text, | 91 const base::string16& new_text, |
| 92 bool url_replacement_active, | |
| 93 ui::PageTransition transition, | 92 ui::PageTransition transition, |
| 94 int omnibox_width) { | 93 int omnibox_width) { |
| 95 size_t avg_length = (old_text.length() + new_text.length()) / 2; | 94 size_t avg_length = (old_text.length() + new_text.length()) / 2; |
| 96 | 95 |
| 97 int percent = 0; | 96 int percent = 0; |
| 98 if (!old_text.empty() && !new_text.empty()) { | 97 if (!old_text.empty() && !new_text.empty()) { |
| 99 size_t shorter_length = std::min(old_text.length(), new_text.length()); | 98 size_t shorter_length = std::min(old_text.length(), new_text.length()); |
| 100 base::string16::const_iterator end(old_text.begin() + shorter_length); | 99 base::string16::const_iterator end(old_text.begin() + shorter_length); |
| 101 base::string16::const_iterator mismatch( | 100 base::string16::const_iterator mismatch( |
| 102 std::mismatch(old_text.begin(), end, new_text.begin()).first); | 101 std::mismatch(old_text.begin(), end, new_text.begin()).first); |
| 103 size_t matching_characters = mismatch - old_text.begin(); | 102 size_t matching_characters = mismatch - old_text.begin(); |
| 104 percent = static_cast<float>(matching_characters) / avg_length * 100; | 103 percent = static_cast<float>(matching_characters) / avg_length * 100; |
| 105 } | 104 } |
| 106 | 105 |
| 106 // TODO(treib,mpearson): Do we want to keep these histograms? Most of the |
| 107 // previously-logged cases don't exist anymore. crbug.com/627747 |
| 107 std::string histogram_name; | 108 std::string histogram_name; |
| 108 if (url_replacement_active) { | 109 if (ui::PageTransitionTypeIncludingQualifiersIs( |
| 109 if (ui::PageTransitionTypeIncludingQualifiersIs( | 110 transition, ui::PAGE_TRANSITION_TYPED)) { |
| 110 transition, ui::PAGE_TRANSITION_TYPED)) { | 111 histogram_name = "InstantExtended.PercentageMatchV2_URLtoURL"; |
| 111 histogram_name = "InstantExtended.PercentageMatchV2_QuerytoURL"; | 112 UMA_HISTOGRAM_PERCENTAGE(histogram_name, percent); |
| 112 UMA_HISTOGRAM_PERCENTAGE(histogram_name, percent); | |
| 113 } else { | |
| 114 histogram_name = "InstantExtended.PercentageMatchV2_QuerytoQuery"; | |
| 115 UMA_HISTOGRAM_PERCENTAGE(histogram_name, percent); | |
| 116 } | |
| 117 } else { | 113 } else { |
| 118 if (ui::PageTransitionTypeIncludingQualifiersIs( | 114 histogram_name = "InstantExtended.PercentageMatchV2_URLtoQuery"; |
| 119 transition, ui::PAGE_TRANSITION_TYPED)) { | 115 UMA_HISTOGRAM_PERCENTAGE(histogram_name, percent); |
| 120 histogram_name = "InstantExtended.PercentageMatchV2_URLtoURL"; | |
| 121 UMA_HISTOGRAM_PERCENTAGE(histogram_name, percent); | |
| 122 } else { | |
| 123 histogram_name = "InstantExtended.PercentageMatchV2_URLtoQuery"; | |
| 124 UMA_HISTOGRAM_PERCENTAGE(histogram_name, percent); | |
| 125 } | |
| 126 } | 116 } |
| 127 | 117 |
| 128 std::string suffix = "large"; | 118 std::string suffix = "large"; |
| 129 for (size_t i = 0; i < arraysize(kPercentageMatchHistogramWidthBuckets); | 119 for (size_t i = 0; i < arraysize(kPercentageMatchHistogramWidthBuckets); |
| 130 ++i) { | 120 ++i) { |
| 131 if (omnibox_width < kPercentageMatchHistogramWidthBuckets[i]) { | 121 if (omnibox_width < kPercentageMatchHistogramWidthBuckets[i]) { |
| 132 suffix = base::IntToString(kPercentageMatchHistogramWidthBuckets[i]); | 122 suffix = base::IntToString(kPercentageMatchHistogramWidthBuckets[i]); |
| 133 break; | 123 break; |
| 134 } | 124 } |
| 135 } | 125 } |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 controller_->GetToolbarModel()->url_replacement_enabled(), | 216 controller_->GetToolbarModel()->url_replacement_enabled(), |
| 227 focus_state_, focus_source_, input_); | 217 focus_state_, focus_source_, input_); |
| 228 } | 218 } |
| 229 | 219 |
| 230 void OmniboxEditModel::RestoreState(const State* state) { | 220 void OmniboxEditModel::RestoreState(const State* state) { |
| 231 // We need to update the permanent text correctly and revert the view | 221 // We need to update the permanent text correctly and revert the view |
| 232 // regardless of whether there is saved state. | 222 // regardless of whether there is saved state. |
| 233 bool url_replacement_enabled = !state || state->url_replacement_enabled; | 223 bool url_replacement_enabled = !state || state->url_replacement_enabled; |
| 234 controller_->GetToolbarModel()->set_url_replacement_enabled( | 224 controller_->GetToolbarModel()->set_url_replacement_enabled( |
| 235 url_replacement_enabled); | 225 url_replacement_enabled); |
| 236 permanent_text_ = controller_->GetToolbarModel()->GetText(); | 226 permanent_text_ = controller_->GetToolbarModel()->GetFormattedURL(nullptr); |
| 237 // Don't muck with the search term replacement state, as we've just set it | 227 // Don't muck with the search term replacement state, as we've just set it |
| 238 // correctly. | 228 // correctly. |
| 239 view_->RevertWithoutResettingSearchTermReplacement(); | 229 view_->RevertWithoutResettingSearchTermReplacement(); |
| 240 // Restore the autocomplete controller's input, or clear it if this is a new | 230 // Restore the autocomplete controller's input, or clear it if this is a new |
| 241 // tab. | 231 // tab. |
| 242 input_ = state ? state->autocomplete_input : AutocompleteInput(); | 232 input_ = state ? state->autocomplete_input : AutocompleteInput(); |
| 243 if (!state) | 233 if (!state) |
| 244 return; | 234 return; |
| 245 | 235 |
| 246 SetFocusState(state->focus_state, OMNIBOX_FOCUS_CHANGE_TAB_SWITCH); | 236 SetFocusState(state->focus_state, OMNIBOX_FOCUS_CHANGE_TAB_SWITCH); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 // always safe to change the text; this also prevents someone toggling "Show | 274 // always safe to change the text; this also prevents someone toggling "Show |
| 285 // URL" (which sounds as if it might be persistent) from seeing just that URL | 275 // URL" (which sounds as if it might be persistent) from seeing just that URL |
| 286 // forever afterwards. | 276 // forever afterwards. |
| 287 // | 277 // |
| 288 // If the page is auto-committing gray text, however, we generally don't want | 278 // If the page is auto-committing gray text, however, we generally don't want |
| 289 // to make any change to the edit. While auto-commits modify the underlying | 279 // to make any change to the edit. While auto-commits modify the underlying |
| 290 // permanent URL, they're intended to have no effect on the user's editing | 280 // permanent URL, they're intended to have no effect on the user's editing |
| 291 // process -- before and after the auto-commit, the omnibox should show the | 281 // process -- before and after the auto-commit, the omnibox should show the |
| 292 // same user text and the same instant suggestion, even if the auto-commit | 282 // same user text and the same instant suggestion, even if the auto-commit |
| 293 // happens while the edit doesn't have focus. | 283 // happens while the edit doesn't have focus. |
| 294 base::string16 new_permanent_text = controller_->GetToolbarModel()->GetText(); | 284 base::string16 new_permanent_text = |
| 285 controller_->GetToolbarModel()->GetFormattedURL(nullptr); |
| 295 base::string16 gray_text = view_->GetGrayTextAutocompletion(); | 286 base::string16 gray_text = view_->GetGrayTextAutocompletion(); |
| 296 const bool visibly_changed_permanent_text = | 287 const bool visibly_changed_permanent_text = |
| 297 (permanent_text_ != new_permanent_text) && | 288 (permanent_text_ != new_permanent_text) && |
| 298 (!has_focus() || | 289 (!has_focus() || |
| 299 (!user_input_in_progress_ && !PopupIsOpen() && | 290 (!user_input_in_progress_ && !PopupIsOpen() && |
| 300 controller_->GetToolbarModel()->url_replacement_enabled())) && | 291 controller_->GetToolbarModel()->url_replacement_enabled())) && |
| 301 (gray_text.empty() || | 292 (gray_text.empty() || |
| 302 new_permanent_text != user_text_ + gray_text); | 293 new_permanent_text != user_text_ + gray_text); |
| 303 | 294 |
| 304 permanent_text_ = new_permanent_text; | 295 permanent_text_ = new_permanent_text; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 base::string16* title, | 343 base::string16* title, |
| 353 gfx::Image* favicon) { | 344 gfx::Image* favicon) { |
| 354 *url = CurrentMatch(nullptr).destination_url; | 345 *url = CurrentMatch(nullptr).destination_url; |
| 355 if (*url == client_->GetURL()) { | 346 if (*url == client_->GetURL()) { |
| 356 *title = client_->GetTitle(); | 347 *title = client_->GetTitle(); |
| 357 *favicon = client_->GetFavicon(); | 348 *favicon = client_->GetFavicon(); |
| 358 } | 349 } |
| 359 } | 350 } |
| 360 | 351 |
| 361 bool OmniboxEditModel::CurrentTextIsURL() const { | 352 bool OmniboxEditModel::CurrentTextIsURL() const { |
| 362 if (controller_->GetToolbarModel()->WouldReplaceURL()) | 353 // If !user_input_in_progress_, then permanent text is showing and should be a |
| 363 return false; | |
| 364 | |
| 365 // If current text is not composed of replaced search terms and | |
| 366 // !user_input_in_progress_, then permanent text is showing and should be a | |
| 367 // URL, so no further checking is needed. By avoiding checking in this case, | 354 // URL, so no further checking is needed. By avoiding checking in this case, |
| 368 // we avoid calling into the autocomplete providers, and thus initializing the | 355 // we avoid calling into the autocomplete providers, and thus initializing the |
| 369 // history system, as long as possible, which speeds startup. | 356 // history system, as long as possible, which speeds startup. |
| 370 if (!user_input_in_progress_) | 357 if (!user_input_in_progress_) |
| 371 return true; | 358 return true; |
| 372 | 359 |
| 373 return !AutocompleteMatch::IsSearchType(CurrentMatch(nullptr).type); | 360 return !AutocompleteMatch::IsSearchType(CurrentMatch(nullptr).type); |
| 374 } | 361 } |
| 375 | 362 |
| 376 AutocompleteMatch::Type OmniboxEditModel::CurrentTextType() const { | 363 AutocompleteMatch::Type OmniboxEditModel::CurrentTextType() const { |
| 377 return CurrentMatch(nullptr).type; | 364 return CurrentMatch(nullptr).type; |
| 378 } | 365 } |
| 379 | 366 |
| 380 void OmniboxEditModel::AdjustTextForCopy(int sel_min, | 367 void OmniboxEditModel::AdjustTextForCopy(int sel_min, |
| 381 bool is_all_selected, | 368 bool is_all_selected, |
| 382 base::string16* text, | 369 base::string16* text, |
| 383 GURL* url, | 370 GURL* url, |
| 384 bool* write_url) { | 371 bool* write_url) { |
| 385 *write_url = false; | 372 *write_url = false; |
| 386 | 373 |
| 387 // Do not adjust if selection did not start at the beginning of the field, or | 374 // Do not adjust if selection did not start at the beginning of the field. |
| 388 // if the URL was omitted. | 375 if (sel_min != 0) |
| 389 if ((sel_min != 0) || controller_->GetToolbarModel()->WouldReplaceURL()) | |
| 390 return; | 376 return; |
| 391 | 377 |
| 392 // Check whether the user is trying to copy the current page's URL by | 378 // Check whether the user is trying to copy the current page's URL by |
| 393 // selecting the whole thing without editing it. | 379 // selecting the whole thing without editing it. |
| 394 // | 380 // |
| 395 // This is complicated by ZeroSuggest. When ZeroSuggest is active, the user | 381 // This is complicated by ZeroSuggest. When ZeroSuggest is active, the user |
| 396 // may be selecting different items and thus changing the address bar text, | 382 // may be selecting different items and thus changing the address bar text, |
| 397 // even though !user_input_in_progress_; and the permanent URL may change | 383 // even though !user_input_in_progress_; and the permanent URL may change |
| 398 // without updating the visible text, just like when user input is in | 384 // without updating the visible text, just like when user input is in |
| 399 // progress. In these cases, we don't want to copy the underlying URL, we | 385 // progress. In these cases, we don't want to copy the underlying URL, we |
| (...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 773 | 759 |
| 774 // Get the current text before we call RevertAll() which will clear it. | 760 // Get the current text before we call RevertAll() which will clear it. |
| 775 base::string16 current_text = view_->GetText(); | 761 base::string16 current_text = view_->GetText(); |
| 776 | 762 |
| 777 if (disposition != NEW_BACKGROUND_TAB) { | 763 if (disposition != NEW_BACKGROUND_TAB) { |
| 778 base::AutoReset<bool> tmp(&in_revert_, true); | 764 base::AutoReset<bool> tmp(&in_revert_, true); |
| 779 view_->RevertAll(); // Revert the box to its unedited state. | 765 view_->RevertAll(); // Revert the box to its unedited state. |
| 780 } | 766 } |
| 781 | 767 |
| 782 RecordPercentageMatchHistogram( | 768 RecordPercentageMatchHistogram( |
| 783 permanent_text_, current_text, | 769 permanent_text_, current_text, match.transition, view_->GetWidth()); |
| 784 controller_->GetToolbarModel()->WouldReplaceURL(), | |
| 785 match.transition, view_->GetWidth()); | |
| 786 | 770 |
| 787 // Track whether the destination URL sends us to a search results page | 771 // Track whether the destination URL sends us to a search results page |
| 788 // using the default search provider. | 772 // using the default search provider. |
| 789 TemplateURLService* template_url_service = client_->GetTemplateURLService(); | 773 TemplateURLService* template_url_service = client_->GetTemplateURLService(); |
| 790 if (template_url_service && | 774 if (template_url_service && |
| 791 template_url_service->IsSearchResultsPageFromDefaultSearchProvider( | 775 template_url_service->IsSearchResultsPageFromDefaultSearchProvider( |
| 792 match.destination_url)) { | 776 match.destination_url)) { |
| 793 base::RecordAction( | 777 base::RecordAction( |
| 794 base::UserMetricsAction("OmniboxDestinationURLIsSearchOnDSP")); | 778 base::UserMetricsAction("OmniboxDestinationURLIsSearchOnDSP")); |
| 795 } | 779 } |
| (...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1377 | 1361 |
| 1378 base::string16 OmniboxEditModel::MaybePrependKeyword( | 1362 base::string16 OmniboxEditModel::MaybePrependKeyword( |
| 1379 const base::string16& text) const { | 1363 const base::string16& text) const { |
| 1380 return is_keyword_selected() ? (keyword_ + base::char16(' ') + text) : text; | 1364 return is_keyword_selected() ? (keyword_ + base::char16(' ') + text) : text; |
| 1381 } | 1365 } |
| 1382 | 1366 |
| 1383 void OmniboxEditModel::GetInfoForCurrentText(AutocompleteMatch* match, | 1367 void OmniboxEditModel::GetInfoForCurrentText(AutocompleteMatch* match, |
| 1384 GURL* alternate_nav_url) const { | 1368 GURL* alternate_nav_url) const { |
| 1385 DCHECK(match); | 1369 DCHECK(match); |
| 1386 | 1370 |
| 1387 if (controller_->GetToolbarModel()->WouldPerformSearchTermReplacement( | 1371 if (query_in_progress() || PopupIsOpen()) { |
| 1388 false)) { | |
| 1389 // Any time the user hits enter on the unchanged omnibox, we should reload. | |
| 1390 // When we're not extracting search terms, AcceptInput() will take care of | |
| 1391 // this (see code referring to PAGE_TRANSITION_RELOAD there), but when we're | |
| 1392 // extracting search terms, the conditionals there won't fire, so we | |
| 1393 // explicitly set up a match that will reload here. | |
| 1394 | |
| 1395 // It's important that we fetch the current visible URL to reload instead of | |
| 1396 // just getting a "search what you typed" URL from | |
| 1397 // SearchProvider::CreateSearchSuggestion(), since the user may be in a | |
| 1398 // non-default search mode such as image search. | |
| 1399 match->type = AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED; | |
| 1400 match->provider = autocomplete_controller()->search_provider(); | |
| 1401 match->destination_url = client_->GetURL(); | |
| 1402 match->transition = ui::PAGE_TRANSITION_RELOAD; | |
| 1403 } else if (query_in_progress() || PopupIsOpen()) { | |
| 1404 if (query_in_progress()) { | 1372 if (query_in_progress()) { |
| 1405 // It's technically possible for |result| to be empty if no provider | 1373 // It's technically possible for |result| to be empty if no provider |
| 1406 // returns a synchronous result but the query has not completed | 1374 // returns a synchronous result but the query has not completed |
| 1407 // synchronously; pratically, however, that should never actually happen. | 1375 // synchronously; pratically, however, that should never actually happen. |
| 1408 if (result().empty()) | 1376 if (result().empty()) |
| 1409 return; | 1377 return; |
| 1410 // The user cannot have manually selected a match, or the query would have | 1378 // The user cannot have manually selected a match, or the query would have |
| 1411 // stopped. So the default match must be the desired selection. | 1379 // stopped. So the default match must be the desired selection. |
| 1412 *match = *result().default_match(); | 1380 *match = *result().default_match(); |
| 1413 } else { | 1381 } else { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1505 const GURL& gurl = client_->GetURL(); | 1473 const GURL& gurl = client_->GetURL(); |
| 1506 if (!gurl.is_valid()) | 1474 if (!gurl.is_valid()) |
| 1507 return OmniboxEventProto::INVALID_SPEC; | 1475 return OmniboxEventProto::INVALID_SPEC; |
| 1508 const std::string& url = gurl.spec(); | 1476 const std::string& url = gurl.spec(); |
| 1509 if (client_->IsNewTabPage(url)) | 1477 if (client_->IsNewTabPage(url)) |
| 1510 return OmniboxEventProto::NTP; | 1478 return OmniboxEventProto::NTP; |
| 1511 if (url == url::kAboutBlankURL) | 1479 if (url == url::kAboutBlankURL) |
| 1512 return OmniboxEventProto::BLANK; | 1480 return OmniboxEventProto::BLANK; |
| 1513 if (client_->IsHomePage(url)) | 1481 if (client_->IsHomePage(url)) |
| 1514 return OmniboxEventProto::HOME_PAGE; | 1482 return OmniboxEventProto::HOME_PAGE; |
| 1515 if (controller_->GetToolbarModel()->WouldPerformSearchTermReplacement(true)) | |
| 1516 return OmniboxEventProto::SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT; | |
| 1517 if (client_->IsSearchResultsPage()) | 1483 if (client_->IsSearchResultsPage()) |
| 1518 return OmniboxEventProto::SEARCH_RESULT_PAGE_NO_SEARCH_TERM_REPLACEMENT; | 1484 return OmniboxEventProto::SEARCH_RESULT_PAGE_NO_SEARCH_TERM_REPLACEMENT; |
| 1519 return OmniboxEventProto::OTHER; | 1485 return OmniboxEventProto::OTHER; |
| 1520 } | 1486 } |
| 1521 | 1487 |
| 1522 void OmniboxEditModel::ClassifyStringForPasteAndGo( | 1488 void OmniboxEditModel::ClassifyStringForPasteAndGo( |
| 1523 const base::string16& text, | 1489 const base::string16& text, |
| 1524 AutocompleteMatch* match, | 1490 AutocompleteMatch* match, |
| 1525 GURL* alternate_nav_url) const { | 1491 GURL* alternate_nav_url) const { |
| 1526 DCHECK(match); | 1492 DCHECK(match); |
| 1527 client_->GetAutocompleteClassifier()->Classify( | 1493 client_->GetAutocompleteClassifier()->Classify( |
| 1528 text, false, false, ClassifyPage(), match, alternate_nav_url); | 1494 text, false, false, ClassifyPage(), match, alternate_nav_url); |
| 1529 } | 1495 } |
| 1530 | 1496 |
| 1531 void OmniboxEditModel::SetFocusState(OmniboxFocusState state, | 1497 void OmniboxEditModel::SetFocusState(OmniboxFocusState state, |
| 1532 OmniboxFocusChangeReason reason) { | 1498 OmniboxFocusChangeReason reason) { |
| 1533 if (state == focus_state_) | 1499 if (state == focus_state_) |
| 1534 return; | 1500 return; |
| 1535 | 1501 |
| 1536 // Update state and notify view if the omnibox has focus and the caret | 1502 // Update state and notify view if the omnibox has focus and the caret |
| 1537 // visibility changed. | 1503 // visibility changed. |
| 1538 const bool was_caret_visible = is_caret_visible(); | 1504 const bool was_caret_visible = is_caret_visible(); |
| 1539 focus_state_ = state; | 1505 focus_state_ = state; |
| 1540 if (focus_state_ != OMNIBOX_FOCUS_NONE && | 1506 if (focus_state_ != OMNIBOX_FOCUS_NONE && |
| 1541 is_caret_visible() != was_caret_visible) | 1507 is_caret_visible() != was_caret_visible) |
| 1542 view_->ApplyCaretVisibility(); | 1508 view_->ApplyCaretVisibility(); |
| 1543 | 1509 |
| 1544 client_->OnFocusChanged(focus_state_, reason); | 1510 client_->OnFocusChanged(focus_state_, reason); |
| 1545 } | 1511 } |
| OLD | NEW |