| 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 "chrome/browser/ui/search/instant_controller.h" | 5 #include "chrome/browser/ui/search/instant_controller.h" |
| 6 | 6 |
| 7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
| 8 #include "base/string_util.h" | 8 #include "base/string_util.h" |
| 9 #include "base/stringprintf.h" | 9 #include "base/stringprintf.h" |
| 10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 UTF16ToUTF8(user_text).c_str(), UTF16ToUTF8(full_text).c_str(), | 261 UTF16ToUTF8(user_text).c_str(), UTF16ToUTF8(full_text).c_str(), |
| 262 static_cast<int>(selection_start), static_cast<int>(selection_end), | 262 static_cast<int>(selection_start), static_cast<int>(selection_end), |
| 263 verbatim, user_input_in_progress, omnibox_popup_is_open, escape_pressed, | 263 verbatim, user_input_in_progress, omnibox_popup_is_open, escape_pressed, |
| 264 is_keyword_search)); | 264 is_keyword_search)); |
| 265 | 265 |
| 266 // TODO(dhollowa): Complete keyword match UI. For now just hide suggestions. | 266 // TODO(dhollowa): Complete keyword match UI. For now just hide suggestions. |
| 267 // http://crbug.com/153932. Note, this early escape is happens prior to the | 267 // http://crbug.com/153932. Note, this early escape is happens prior to the |
| 268 // DCHECKs below because |user_text| and |full_text| have different semantics | 268 // DCHECKs below because |user_text| and |full_text| have different semantics |
| 269 // when keyword search is in effect. | 269 // when keyword search is in effect. |
| 270 if (is_keyword_search) { | 270 if (is_keyword_search) { |
| 271 if (UseInstantTabToShowSuggestions()) | 271 if (instant_tab_) |
| 272 instant_tab_->Update(string16(), 0, 0, true); | 272 instant_tab_->Update(string16(), 0, 0, true); |
| 273 else | 273 else |
| 274 HideOverlay(); | 274 HideOverlay(); |
| 275 last_match_was_search_ = false; | 275 last_match_was_search_ = false; |
| 276 return false; | 276 return false; |
| 277 } | 277 } |
| 278 | 278 |
| 279 // Ignore spurious updates when the omnibox is blurred; otherwise click | 279 // Ignore spurious updates when the omnibox is blurred; otherwise click |
| 280 // targets on the page may vanish before a click event arrives. | 280 // targets on the page may vanish before a click event arrives. |
| 281 if (omnibox_focus_state_ == OMNIBOX_FOCUS_NONE) | 281 if (omnibox_focus_state_ == OMNIBOX_FOCUS_NONE) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 // In non extended mode, Instant is disabled for URLs and keyword mode. | 314 // In non extended mode, Instant is disabled for URLs and keyword mode. |
| 315 if (!extended_enabled_ && | 315 if (!extended_enabled_ && |
| 316 (!last_match_was_search_ || | 316 (!last_match_was_search_ || |
| 317 match.type == AutocompleteMatch::SEARCH_OTHER_ENGINE)) { | 317 match.type == AutocompleteMatch::SEARCH_OTHER_ENGINE)) { |
| 318 HideOverlay(); | 318 HideOverlay(); |
| 319 return false; | 319 return false; |
| 320 } | 320 } |
| 321 | 321 |
| 322 // If we have an |instant_tab_| use it, else ensure we have an overlay that is | 322 // If we have an |instant_tab_| use it, else ensure we have an overlay that is |
| 323 // current or is using the local overlay. | 323 // current or is using the local overlay. |
| 324 if (!UseInstantTabToShowSuggestions() && | 324 if (!instant_tab_ && !(overlay_ && overlay_->IsLocal()) && |
| 325 !(overlay_ && overlay_->IsLocalOverlay()) && | |
| 326 !EnsureOverlayIsCurrent(false)) { | 325 !EnsureOverlayIsCurrent(false)) { |
| 327 HideOverlay(); | 326 HideOverlay(); |
| 328 return false; | 327 return false; |
| 329 } | 328 } |
| 330 | 329 |
| 331 if (extended_enabled_) { | 330 if (extended_enabled_) { |
| 332 if (!omnibox_popup_is_open) { | 331 if (!omnibox_popup_is_open) { |
| 333 if (!user_input_in_progress) { | 332 if (!user_input_in_progress) { |
| 334 // If the user isn't typing and the omnibox popup is closed, it means a | 333 // If the user isn't typing and the omnibox popup is closed, it means a |
| 335 // regular navigation, tab-switch or the user hitting Escape. | 334 // regular navigation, tab-switch or the user hitting Escape. |
| 336 if (UseInstantTabToShowSuggestions()) { | 335 if (instant_tab_) { |
| 337 // The user is on a search results page. It may be showing results for | 336 // The user is on a search results page. It may be showing results for |
| 338 // a partial query the user typed before they hit Escape. Send the | 337 // a partial query the user typed before they hit Escape. Send the |
| 339 // omnibox text to the page to restore the original results. | 338 // omnibox text to the page to restore the original results. |
| 340 // | 339 // |
| 341 // In a tab switch, |instant_tab_| won't have updated yet, so it may | 340 // In a tab switch, |instant_tab_| won't have updated yet, so it may |
| 342 // be pointing to the previous tab (which was a search results page). | 341 // be pointing to the previous tab (which was a search results page). |
| 343 // Ensure we don't send the omnibox text to a random webpage (the new | 342 // Ensure we don't send the omnibox text to a random webpage (the new |
| 344 // tab), by comparing the old and new WebContents. | 343 // tab), by comparing the old and new WebContents. |
| 345 if (escape_pressed && | 344 if (escape_pressed && |
| 346 instant_tab_->contents() == browser_->GetActiveWebContents()) { | 345 instant_tab_->contents() == browser_->GetActiveWebContents()) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 359 // If |full_text| is empty, the user is on the NTP. The overlay may | 358 // If |full_text| is empty, the user is on the NTP. The overlay may |
| 360 // be showing custom NTP content; hide only if that's not the case. | 359 // be showing custom NTP content; hide only if that's not the case. |
| 361 HideOverlay(); | 360 HideOverlay(); |
| 362 } | 361 } |
| 363 } else if (full_text.empty()) { | 362 } else if (full_text.empty()) { |
| 364 // The user is typing, and backspaced away all omnibox text. Clear | 363 // The user is typing, and backspaced away all omnibox text. Clear |
| 365 // |last_omnibox_text_| so that we don't attempt to set suggestions. | 364 // |last_omnibox_text_| so that we don't attempt to set suggestions. |
| 366 last_omnibox_text_.clear(); | 365 last_omnibox_text_.clear(); |
| 367 last_user_text_.clear(); | 366 last_user_text_.clear(); |
| 368 last_suggestion_ = InstantSuggestion(); | 367 last_suggestion_ = InstantSuggestion(); |
| 369 if (UseInstantTabToShowSuggestions()) { | 368 if (instant_tab_) { |
| 370 // On a search results page, tell it to clear old results. | 369 // On a search results page, tell it to clear old results. |
| 371 instant_tab_->Update(string16(), 0, 0, true); | 370 instant_tab_->Update(string16(), 0, 0, true); |
| 372 } else if (search_mode_.is_origin_ntp()) { | 371 } else if (search_mode_.is_origin_ntp()) { |
| 373 // On the NTP, tell the overlay to clear old results. Don't hide the | 372 // On the NTP, tell the overlay to clear old results. Don't hide the |
| 374 // overlay so it can show a blank page or logo if it wants. | 373 // overlay so it can show a blank page or logo if it wants. |
| 375 overlay_->Update(string16(), 0, 0, true); | 374 overlay_->Update(string16(), 0, 0, true); |
| 376 } else { | 375 } else { |
| 377 HideOverlay(); | 376 HideOverlay(); |
| 378 } | 377 } |
| 379 } else { | 378 } else { |
| 380 // The user switched to a tab with partial text already in the omnibox. | 379 // The user switched to a tab with partial text already in the omnibox. |
| 381 HideOverlay(); | 380 HideOverlay(); |
| 382 | 381 |
| 383 // The new tab may or may not be a search results page; we don't know | 382 // The new tab may or may not be a search results page; we don't know |
| 384 // since SearchModeChanged() hasn't been called yet. If it later turns | 383 // since SearchModeChanged() hasn't been called yet. If it later turns |
| 385 // out to be, we should store |full_text| now, so that if the user hits | 384 // out to be, we should store |full_text| now, so that if the user hits |
| 386 // Enter, we'll send the correct query to instant_tab_->Submit(). If the | 385 // Enter, we'll send the correct query to instant_tab_->Submit(). If the |
| 387 // partial text is not a query (|last_match_was_search_| is false), we | 386 // partial text is not a query (|last_match_was_search_| is false), we |
| 388 // won't Submit(), so no need to worry about that. | 387 // won't Submit(), so no need to worry about that. |
| 389 last_omnibox_text_ = full_text; | 388 last_omnibox_text_ = full_text; |
| 390 last_user_text_ = user_text; | 389 last_user_text_ = user_text; |
| 391 last_suggestion_ = InstantSuggestion(); | 390 last_suggestion_ = InstantSuggestion(); |
| 392 } | 391 } |
| 393 return false; | 392 return false; |
| 394 } else if (full_text.empty()) { | 393 } else if (full_text.empty()) { |
| 395 // The user typed a solitary "?". Same as the backspace case above. | 394 // The user typed a solitary "?". Same as the backspace case above. |
| 396 last_omnibox_text_.clear(); | 395 last_omnibox_text_.clear(); |
| 397 last_user_text_.clear(); | 396 last_user_text_.clear(); |
| 398 last_suggestion_ = InstantSuggestion(); | 397 last_suggestion_ = InstantSuggestion(); |
| 399 if (UseInstantTabToShowSuggestions()) | 398 if (instant_tab_) |
| 400 instant_tab_->Update(string16(), 0, 0, true); | 399 instant_tab_->Update(string16(), 0, 0, true); |
| 401 else if (search_mode_.is_origin_ntp()) | 400 else if (search_mode_.is_origin_ntp()) |
| 402 overlay_->Update(string16(), 0, 0, true); | 401 overlay_->Update(string16(), 0, 0, true); |
| 403 else | 402 else |
| 404 HideOverlay(); | 403 HideOverlay(); |
| 405 return false; | 404 return false; |
| 406 } | 405 } |
| 407 } else if (!omnibox_popup_is_open || full_text.empty()) { | 406 } else if (!omnibox_popup_is_open || full_text.empty()) { |
| 408 // In the non-extended case, hide the overlay as long as the user isn't | 407 // In the non-extended case, hide the overlay as long as the user isn't |
| 409 // actively typing a non-empty query. | 408 // actively typing a non-empty query. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 last_verbatim_ = verbatim; | 443 last_verbatim_ = verbatim; |
| 445 | 444 |
| 446 last_transition_type_ = match.transition; | 445 last_transition_type_ = match.transition; |
| 447 url_for_history_ = match.destination_url; | 446 url_for_history_ = match.destination_url; |
| 448 | 447 |
| 449 // Allow search suggestions. In extended mode, SearchModeChanged() will set | 448 // Allow search suggestions. In extended mode, SearchModeChanged() will set |
| 450 // this, but it's not called in non-extended mode, so fake it. | 449 // this, but it's not called in non-extended mode, so fake it. |
| 451 if (!extended_enabled_) | 450 if (!extended_enabled_) |
| 452 search_mode_.mode = SearchMode::MODE_SEARCH_SUGGESTIONS; | 451 search_mode_.mode = SearchMode::MODE_SEARCH_SUGGESTIONS; |
| 453 | 452 |
| 454 if (UseInstantTabToShowSuggestions()) { | 453 if (instant_tab_) { |
| 455 // If we have an |instant_tab_| but it doesn't support Instant yet, sever | 454 // If we have an |instant_tab_| but it doesn't support Instant yet, sever |
| 456 // the connection to it so we use the overlay instead. This ensures that the | 455 // the connection to it so we use the overlay instead. This ensures that the |
| 457 // user interaction will be responsive and handles cases where | 456 // user interaction will be responsive and handles cases where |
| 458 // |instant_tab_| never responds about whether it supports Instant. | 457 // |instant_tab_| never responds about whether it supports Instant. |
| 459 if (instant_tab_->supports_instant()) | 458 if (instant_tab_->supports_instant()) |
| 460 instant_tab_->Update(user_text, selection_start, selection_end, verbatim); | 459 instant_tab_->Update(user_text, selection_start, selection_end, verbatim); |
| 461 else | 460 else |
| 462 instant_tab_.reset(); | 461 instant_tab_.reset(); |
| 463 } | 462 } |
| 464 | 463 |
| 465 if (!UseInstantTabToShowSuggestions()) { | 464 if (!instant_tab_) { |
| 466 if (first_interaction_time_.is_null()) | 465 if (first_interaction_time_.is_null()) |
| 467 first_interaction_time_ = base::Time::Now(); | 466 first_interaction_time_ = base::Time::Now(); |
| 468 allow_overlay_to_show_search_suggestions_ = true; | 467 allow_overlay_to_show_search_suggestions_ = true; |
| 469 | 468 |
| 470 // For extended mode, if the loader is not ready at this point, switch over | 469 // For extended mode, if the loader is not ready at this point, switch over |
| 471 // to a backup loader. | 470 // to a backup loader. |
| 472 if (extended_enabled_ && !overlay_->supports_instant() && | 471 if (extended_enabled_ && !overlay_->supports_instant() && |
| 473 !overlay_->IsLocalOverlay() && browser_->GetActiveWebContents()) { | 472 !overlay_->IsLocal() && browser_->GetActiveWebContents()) { |
| 474 CreateOverlay(chrome::kChromeSearchLocalOmniboxPopupURL, | 473 CreateOverlay(chrome::GetLocalInstantURL(browser_->profile()).spec(), |
| 475 browser_->GetActiveWebContents()); | 474 browser_->GetActiveWebContents()); |
| 476 } | 475 } |
| 477 | 476 |
| 478 overlay_->Update(extended_enabled_ ? user_text : full_text, | 477 overlay_->Update(extended_enabled_ ? user_text : full_text, |
| 479 selection_start, selection_end, verbatim); | 478 selection_start, selection_end, verbatim); |
| 480 } | 479 } |
| 481 | 480 |
| 482 content::NotificationService::current()->Notify( | 481 content::NotificationService::current()->Notify( |
| 483 chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, | 482 chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, |
| 484 content::Source<InstantController>(this), | 483 content::Source<InstantController>(this), |
| 485 content::NotificationService::NoDetails()); | 484 content::NotificationService::NoDetails()); |
| 486 | 485 |
| 487 // We don't have new suggestions yet, but we can either reuse the existing | 486 // We don't have new suggestions yet, but we can either reuse the existing |
| 488 // suggestion or reset the existing "gray text". | 487 // suggestion or reset the existing "gray text". |
| 489 browser_->SetInstantSuggestion(last_suggestion_); | 488 browser_->SetInstantSuggestion(last_suggestion_); |
| 490 | 489 |
| 491 return true; | 490 return true; |
| 492 } | 491 } |
| 493 | 492 |
| 494 scoped_ptr<content::WebContents> InstantController::ReleaseNTPContents() { | 493 scoped_ptr<content::WebContents> InstantController::ReleaseNTPContents() { |
| 495 if (!extended_enabled_ || !browser_->profile() || | 494 if (!extended_enabled_ || !browser_->profile() || |
| 496 browser_->profile()->IsOffTheRecord()) | 495 browser_->profile()->IsOffTheRecord()) |
| 497 return scoped_ptr<content::WebContents>(NULL); | 496 return scoped_ptr<content::WebContents>(NULL); |
| 498 | 497 |
| 499 LOG_INSTANT_DEBUG_EVENT(this, "ReleaseNTPContents"); | 498 LOG_INSTANT_DEBUG_EVENT(this, "ReleaseNTPContents"); |
| 500 | 499 |
| 501 // Switch to the local NTP unless we're already using one. | 500 // TODO(jeremycho): Add tests for this logic. |
| 502 if (!ntp_ || (ShouldSwitchToLocalNTP() && !ntp_->IsLocalNTP())) | 501 if (ShouldSwitchToLocalNTP()) |
| 503 ResetNTP(false, true); | 502 ResetNTP(false, true); |
| 504 | 503 |
| 505 scoped_ptr<content::WebContents> ntp_contents = ntp_->ReleaseContents(); | 504 scoped_ptr<content::WebContents> ntp_contents = ntp_->ReleaseContents(); |
| 506 | 505 |
| 507 // Override the blacklist on an explicit user action. | 506 // Override the blacklist on an explicit user action. |
| 508 ResetNTP(true, false); | 507 ResetNTP(true, false); |
| 509 return ntp_contents.Pass(); | 508 return ntp_contents.Pass(); |
| 510 } | 509 } |
| 511 | 510 |
| 512 // TODO(tonyg): This method only fires when the omnibox bounds change. It also | 511 // TODO(tonyg): This method only fires when the omnibox bounds change. It also |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 554 // as it stops autocomplete. Ignore these. | 553 // as it stops autocomplete. Ignore these. |
| 555 if (omnibox_focus_state_ == OMNIBOX_FOCUS_NONE) | 554 if (omnibox_focus_state_ == OMNIBOX_FOCUS_NONE) |
| 556 return; | 555 return; |
| 557 | 556 |
| 558 DVLOG(1) << "AutocompleteResults:"; | 557 DVLOG(1) << "AutocompleteResults:"; |
| 559 std::vector<InstantAutocompleteResult> results; | 558 std::vector<InstantAutocompleteResult> results; |
| 560 for (ACProviders::const_iterator provider = providers.begin(); | 559 for (ACProviders::const_iterator provider = providers.begin(); |
| 561 provider != providers.end(); ++provider) { | 560 provider != providers.end(); ++provider) { |
| 562 const bool from_search_provider = | 561 const bool from_search_provider = |
| 563 (*provider)->type() == AutocompleteProvider::TYPE_SEARCH; | 562 (*provider)->type() == AutocompleteProvider::TYPE_SEARCH; |
| 564 // Unless we are talking to the local overlay, skip SearchProvider, since | 563 const bool using_local_page = |
| 565 // it only echoes suggestions. | 564 (instant_tab_ && instant_tab_->IsLocal()) || overlay_->IsLocal(); |
| 566 if (from_search_provider && | 565 // Unless we are talking to a local page, skip SearchProvider, since it only |
| 567 (UseInstantTabToShowSuggestions() || !overlay_->IsLocalOverlay())) | 566 // echoes suggestions. |
| 567 if (from_search_provider && !using_local_page) |
| 568 continue; | 568 continue; |
| 569 // Only send autocomplete results when all the providers are done. Skip | 569 // Only send autocomplete results when all the providers are done. Skip |
| 570 // this check for the SearchProvider, since it isn't done until the page | 570 // this check for the SearchProvider, since it isn't done until the page |
| 571 // calls SetSuggestions (causing SearchProvider::FinalizeInstantQuery() to | 571 // calls SetSuggestions (causing SearchProvider::FinalizeInstantQuery() to |
| 572 // be called), which makes it a chicken-and-egg thing. | 572 // be called), which makes it a chicken-and-egg thing. |
| 573 if (!from_search_provider && !(*provider)->done()) { | 573 if (!from_search_provider && !(*provider)->done()) { |
| 574 DVLOG(1) << "Waiting for " << (*provider)->GetName(); | 574 DVLOG(1) << "Waiting for " << (*provider)->GetName(); |
| 575 return; | 575 return; |
| 576 } | 576 } |
| 577 for (ACMatches::const_iterator match = (*provider)->matches().begin(); | 577 for (ACMatches::const_iterator match = (*provider)->matches().begin(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 589 << result.provider << " " << result.destination_url << " '" | 589 << result.provider << " " << result.destination_url << " '" |
| 590 << result.description << "' '" << result.search_query << "' " | 590 << result.description << "' '" << result.search_query << "' " |
| 591 << result.transition; | 591 << result.transition; |
| 592 results.push_back(result); | 592 results.push_back(result); |
| 593 } | 593 } |
| 594 } | 594 } |
| 595 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 595 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
| 596 "HandleAutocompleteResults: total_results=%d", | 596 "HandleAutocompleteResults: total_results=%d", |
| 597 static_cast<int>(results.size()))); | 597 static_cast<int>(results.size()))); |
| 598 | 598 |
| 599 if (UseInstantTabToShowSuggestions()) | 599 if (instant_tab_) |
| 600 instant_tab_->SendAutocompleteResults(results); | 600 instant_tab_->SendAutocompleteResults(results); |
| 601 else | 601 else |
| 602 overlay_->SendAutocompleteResults(results); | 602 overlay_->SendAutocompleteResults(results); |
| 603 } | 603 } |
| 604 | 604 |
| 605 bool InstantController::OnUpOrDownKeyPressed(int count) { | 605 bool InstantController::OnUpOrDownKeyPressed(int count) { |
| 606 if (!extended_enabled_) | 606 if (!extended_enabled_) |
| 607 return false; | 607 return false; |
| 608 | 608 |
| 609 if (!instant_tab_ && !overlay_) | 609 if (!instant_tab_ && !overlay_) |
| 610 return false; | 610 return false; |
| 611 | 611 |
| 612 if (UseInstantTabToShowSuggestions()) | 612 if (instant_tab_) |
| 613 instant_tab_->UpOrDownKeyPressed(count); | 613 instant_tab_->UpOrDownKeyPressed(count); |
| 614 else | 614 else |
| 615 overlay_->UpOrDownKeyPressed(count); | 615 overlay_->UpOrDownKeyPressed(count); |
| 616 | 616 |
| 617 return true; | 617 return true; |
| 618 } | 618 } |
| 619 | 619 |
| 620 void InstantController::OnCancel(const AutocompleteMatch& match, | 620 void InstantController::OnCancel(const AutocompleteMatch& match, |
| 621 const string16& user_text, | 621 const string16& user_text, |
| 622 const string16& full_text) { | 622 const string16& full_text) { |
| 623 if (!extended_enabled_) | 623 if (!extended_enabled_) |
| 624 return; | 624 return; |
| 625 | 625 |
| 626 if (!instant_tab_ && !overlay_) | 626 if (!instant_tab_ && !overlay_) |
| 627 return; | 627 return; |
| 628 | 628 |
| 629 // We manually reset the state here since the JS is not expected to do it. | 629 // We manually reset the state here since the JS is not expected to do it. |
| 630 // TODO(sreeram): Handle the case where user_text is now a URL | 630 // TODO(sreeram): Handle the case where user_text is now a URL |
| 631 last_match_was_search_ = AutocompleteMatch::IsSearchType(match.type) && | 631 last_match_was_search_ = AutocompleteMatch::IsSearchType(match.type) && |
| 632 !full_text.empty(); | 632 !full_text.empty(); |
| 633 last_omnibox_text_ = full_text; | 633 last_omnibox_text_ = full_text; |
| 634 last_user_text_ = user_text; | 634 last_user_text_ = user_text; |
| 635 last_suggestion_ = InstantSuggestion(); | 635 last_suggestion_ = InstantSuggestion(); |
| 636 | 636 |
| 637 // Say |full_text| is "amazon.com" and |user_text| is "ama". This means the | 637 // Say |full_text| is "amazon.com" and |user_text| is "ama". This means the |
| 638 // inline autocompletion is "zon.com"; so the selection should span from | 638 // inline autocompletion is "zon.com"; so the selection should span from |
| 639 // user_text.size() to full_text.size(). The selection bounds are inverted | 639 // user_text.size() to full_text.size(). The selection bounds are inverted |
| 640 // because the caret is at the end of |user_text|, not |full_text|. | 640 // because the caret is at the end of |user_text|, not |full_text|. |
| 641 if (UseInstantTabToShowSuggestions()) { | 641 if (instant_tab_) { |
| 642 instant_tab_->CancelSelection(user_text, full_text.size(), user_text.size(), | 642 instant_tab_->CancelSelection(user_text, full_text.size(), user_text.size(), |
| 643 last_verbatim_); | 643 last_verbatim_); |
| 644 } else { | 644 } else { |
| 645 overlay_->CancelSelection(user_text, full_text.size(), user_text.size(), | 645 overlay_->CancelSelection(user_text, full_text.size(), user_text.size(), |
| 646 last_verbatim_); | 646 last_verbatim_); |
| 647 } | 647 } |
| 648 } | 648 } |
| 649 | 649 |
| 650 void InstantController::OmniboxNavigateToURL() { | 650 void InstantController::OmniboxNavigateToURL() { |
| 651 if (!extended_enabled_) | 651 if (!extended_enabled_) |
| (...skipping 18 matching lines...) Expand all Loading... |
| 670 return false; | 670 return false; |
| 671 | 671 |
| 672 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 672 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
| 673 "CommitIfPossible: type=%d last_omnibox_text_='%s' " | 673 "CommitIfPossible: type=%d last_omnibox_text_='%s' " |
| 674 "last_match_was_search_=%d instant_tab_=%d", type, | 674 "last_match_was_search_=%d instant_tab_=%d", type, |
| 675 UTF16ToUTF8(last_omnibox_text_).c_str(), last_match_was_search_, | 675 UTF16ToUTF8(last_omnibox_text_).c_str(), last_match_was_search_, |
| 676 instant_tab_ != NULL)); | 676 instant_tab_ != NULL)); |
| 677 | 677 |
| 678 // If we are on an already committed search results page, send a submit event | 678 // If we are on an already committed search results page, send a submit event |
| 679 // to the page, but otherwise, nothing else to do. | 679 // to the page, but otherwise, nothing else to do. |
| 680 if (UseInstantTabToShowSuggestions()) { | 680 if (instant_tab_) { |
| 681 if (type == INSTANT_COMMIT_PRESSED_ENTER && | 681 if (type == INSTANT_COMMIT_PRESSED_ENTER && |
| 682 !instant_tab_->IsLocal() && |
| 682 (last_match_was_search_ || | 683 (last_match_was_search_ || |
| 683 last_suggestion_.behavior == INSTANT_COMPLETE_NEVER)) { | 684 last_suggestion_.behavior == INSTANT_COMPLETE_NEVER)) { |
| 684 last_suggestion_.text.clear(); | 685 last_suggestion_.text.clear(); |
| 685 instant_tab_->Submit(last_omnibox_text_); | 686 instant_tab_->Submit(last_omnibox_text_); |
| 686 instant_tab_->contents()->GetView()->Focus(); | 687 instant_tab_->contents()->GetView()->Focus(); |
| 687 EnsureSearchTermsAreSet(instant_tab_->contents(), last_omnibox_text_); | 688 EnsureSearchTermsAreSet(instant_tab_->contents(), last_omnibox_text_); |
| 688 return true; | 689 return true; |
| 689 } | 690 } |
| 690 return false; | 691 return false; |
| 691 } | 692 } |
| 692 | 693 |
| 693 // If the overlay is not showing at all, don't commit it. | 694 // If the overlay is not showing at all, don't commit it. |
| 694 if (!model_.mode().is_search_suggestions()) | 695 if (!model_.mode().is_search_suggestions()) |
| 695 return false; | 696 return false; |
| 696 | 697 |
| 697 // If the overlay is showing at full height (with results), commit it. | 698 // If the overlay is showing at full height (with results), commit it. |
| 698 // If it's showing at parial height, commit if it's navigating. | 699 // If it's showing at parial height, commit if it's navigating. |
| 699 if (!IsOverlayingSearchResults() && type != INSTANT_COMMIT_NAVIGATED) | 700 if (!IsOverlayingSearchResults() && type != INSTANT_COMMIT_NAVIGATED) |
| 700 return false; | 701 return false; |
| 701 | 702 |
| 702 // There may re-entrance here, from the call to browser_->CommitInstant below, | 703 // There may re-entrance here, from the call to browser_->CommitInstant below, |
| 703 // which can cause a TabDeactivated notification which gets back here. | 704 // which can cause a TabDeactivated notification which gets back here. |
| 704 // In this case, overlay_->ReleaseContents() was called already. | 705 // In this case, overlay_->ReleaseContents() was called already. |
| 705 if (!GetOverlayContents()) | 706 if (!GetOverlayContents()) |
| 706 return false; | 707 return false; |
| 707 | 708 |
| 708 // Never commit the local overlay. | 709 // Never commit the local overlay. |
| 709 if (overlay_->IsLocalOverlay()) | 710 if (overlay_->IsLocal()) |
| 710 return false; | 711 return false; |
| 711 | 712 |
| 712 if (type == INSTANT_COMMIT_FOCUS_LOST) { | 713 if (type == INSTANT_COMMIT_FOCUS_LOST) { |
| 713 // Extended mode doesn't need or use the Cancel message. | 714 // Extended mode doesn't need or use the Cancel message. |
| 714 if (!extended_enabled_) | 715 if (!extended_enabled_) |
| 715 overlay_->Cancel(last_omnibox_text_); | 716 overlay_->Cancel(last_omnibox_text_); |
| 716 } else if (type != INSTANT_COMMIT_NAVIGATED) { | 717 } else if (type != INSTANT_COMMIT_NAVIGATED) { |
| 717 overlay_->Submit(last_omnibox_text_); | 718 overlay_->Submit(last_omnibox_text_); |
| 718 } | 719 } |
| 719 | 720 |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 931 #if defined(USE_AURA) | 932 #if defined(USE_AURA) |
| 932 // On aura the omnibox only receives a focus lost if we initiate the focus | 933 // On aura the omnibox only receives a focus lost if we initiate the focus |
| 933 // change. This does that. | 934 // change. This does that. |
| 934 if (!model_.mode().is_default()) | 935 if (!model_.mode().is_default()) |
| 935 browser_->InstantOverlayFocused(); | 936 browser_->InstantOverlayFocused(); |
| 936 #endif | 937 #endif |
| 937 } | 938 } |
| 938 | 939 |
| 939 void InstantController::ReloadOverlayIfStale() { | 940 void InstantController::ReloadOverlayIfStale() { |
| 940 // The local overlay is never stale. | 941 // The local overlay is never stale. |
| 941 if (overlay_ && overlay_->IsLocalOverlay()) | 942 if (overlay_ && overlay_->IsLocal()) |
| 942 return; | 943 return; |
| 943 | 944 |
| 944 // If the overlay is showing or the omnibox has focus, don't delete the | 945 // If the overlay is showing or the omnibox has focus, don't delete the |
| 945 // overlay. It will get refreshed the next time the overlay is hidden or the | 946 // overlay. It will get refreshed the next time the overlay is hidden or the |
| 946 // omnibox loses focus. | 947 // omnibox loses focus. |
| 947 if ((!overlay_ || overlay_->is_stale()) && | 948 if ((!overlay_ || overlay_->is_stale()) && |
| 948 omnibox_focus_state_ == OMNIBOX_FOCUS_NONE && | 949 omnibox_focus_state_ == OMNIBOX_FOCUS_NONE && |
| 949 model_.mode().is_default()) { | 950 model_.mode().is_default()) { |
| 950 overlay_.reset(); | 951 overlay_.reset(); |
| 951 EnsureOverlayIsCurrent(false); | 952 EnsureOverlayIsCurrent(false); |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1121 } | 1122 } |
| 1122 | 1123 |
| 1123 void InstantController::SetSuggestions( | 1124 void InstantController::SetSuggestions( |
| 1124 const content::WebContents* contents, | 1125 const content::WebContents* contents, |
| 1125 const std::vector<InstantSuggestion>& suggestions) { | 1126 const std::vector<InstantSuggestion>& suggestions) { |
| 1126 LOG_INSTANT_DEBUG_EVENT(this, "SetSuggestions"); | 1127 LOG_INSTANT_DEBUG_EVENT(this, "SetSuggestions"); |
| 1127 | 1128 |
| 1128 // Ignore if the message is from an unexpected source. | 1129 // Ignore if the message is from an unexpected source. |
| 1129 if (IsContentsFrom(ntp(), contents)) | 1130 if (IsContentsFrom(ntp(), contents)) |
| 1130 return; | 1131 return; |
| 1131 if (UseInstantTabToShowSuggestions() && | 1132 if (instant_tab_ && !IsContentsFrom(instant_tab(), contents)) |
| 1132 !IsContentsFrom(instant_tab(), contents)) | |
| 1133 return; | 1133 return; |
| 1134 if (IsContentsFrom(overlay(), contents) && | 1134 if (IsContentsFrom(overlay(), contents) && |
| 1135 !allow_overlay_to_show_search_suggestions_) | 1135 !allow_overlay_to_show_search_suggestions_) |
| 1136 return; | 1136 return; |
| 1137 | 1137 |
| 1138 InstantSuggestion suggestion; | 1138 InstantSuggestion suggestion; |
| 1139 if (!suggestions.empty()) | 1139 if (!suggestions.empty()) |
| 1140 suggestion = suggestions[0]; | 1140 suggestion = suggestions[0]; |
| 1141 | 1141 |
| 1142 // TODO(samarth): allow InstantTabs to call SetSuggestions() from the NTP once | 1142 // TODO(samarth): allow InstantTabs to call SetSuggestions() from the NTP once |
| 1143 // that is better supported. | 1143 // that is better supported. |
| 1144 bool can_use_instant_tab = UseInstantTabToShowSuggestions() && | 1144 bool can_use_instant_tab = instant_tab_ && search_mode_.is_search(); |
| 1145 search_mode_.is_search(); | |
| 1146 bool can_use_overlay = search_mode_.is_search_suggestions() && | 1145 bool can_use_overlay = search_mode_.is_search_suggestions() && |
| 1147 !last_omnibox_text_.empty(); | 1146 !last_omnibox_text_.empty(); |
| 1148 if (!can_use_instant_tab && !can_use_overlay) | 1147 if (!can_use_instant_tab && !can_use_overlay) |
| 1149 return; | 1148 return; |
| 1150 | 1149 |
| 1151 if (suggestion.behavior == INSTANT_COMPLETE_REPLACE) { | 1150 if (suggestion.behavior == INSTANT_COMPLETE_REPLACE) { |
| 1152 // We don't get an Update() when changing the omnibox due to a REPLACE | 1151 // We don't get an Update() when changing the omnibox due to a REPLACE |
| 1153 // suggestion (so that we don't inadvertently cause the overlay to change | 1152 // suggestion (so that we don't inadvertently cause the overlay to change |
| 1154 // what it's showing, as the user arrows up/down through the page-provided | 1153 // what it's showing, as the user arrows up/down through the page-provided |
| 1155 // suggestions). So, update these state variables here. | 1154 // suggestions). So, update these state variables here. |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1270 else if (!IsViewInContents(GetViewGainingFocus(view_gaining_focus), | 1269 else if (!IsViewInContents(GetViewGainingFocus(view_gaining_focus), |
| 1271 overlay_->contents())) | 1270 overlay_->contents())) |
| 1272 HideOverlay(); | 1271 HideOverlay(); |
| 1273 #endif | 1272 #endif |
| 1274 } | 1273 } |
| 1275 | 1274 |
| 1276 void InstantController::ResetNTP(bool ignore_blacklist, bool use_local_ntp) { | 1275 void InstantController::ResetNTP(bool ignore_blacklist, bool use_local_ntp) { |
| 1277 std::string instant_url; | 1276 std::string instant_url; |
| 1278 if (use_local_ntp || | 1277 if (use_local_ntp || |
| 1279 !GetInstantURL(browser_->profile(), ignore_blacklist, &instant_url)) | 1278 !GetInstantURL(browser_->profile(), ignore_blacklist, &instant_url)) |
| 1280 instant_url = chrome::kChromeSearchLocalNtpUrl; | 1279 instant_url = chrome::GetLocalInstantURL(browser_->profile()).spec(); |
| 1281 ntp_.reset(new InstantNTP(this, instant_url)); | 1280 ntp_.reset(new InstantNTP(this, instant_url)); |
| 1282 ntp_->InitContents(browser_->profile(), browser_->GetActiveWebContents(), | 1281 ntp_->InitContents(browser_->profile(), browser_->GetActiveWebContents(), |
| 1283 base::Bind(&InstantController::ResetNTP, | 1282 base::Bind(&InstantController::ResetNTP, |
| 1284 base::Unretained(this), false, false)); | 1283 base::Unretained(this), false, false)); |
| 1285 } | 1284 } |
| 1286 | 1285 |
| 1287 bool InstantController::EnsureOverlayIsCurrent(bool ignore_blacklist) { | 1286 bool InstantController::EnsureOverlayIsCurrent(bool ignore_blacklist) { |
| 1288 // If there's no active tab, the browser is closing. | 1287 // If there's no active tab, the browser is closing. |
| 1289 const content::WebContents* active_tab = browser_->GetActiveWebContents(); | 1288 const content::WebContents* active_tab = browser_->GetActiveWebContents(); |
| 1290 if (!active_tab) | 1289 if (!active_tab) |
| 1291 return false; | 1290 return false; |
| 1292 | 1291 |
| 1293 Profile* profile = Profile::FromBrowserContext( | 1292 Profile* profile = Profile::FromBrowserContext( |
| 1294 active_tab->GetBrowserContext()); | 1293 active_tab->GetBrowserContext()); |
| 1295 std::string instant_url; | 1294 std::string instant_url; |
| 1296 if (!GetInstantURL(profile, ignore_blacklist, &instant_url)) { | 1295 if (!GetInstantURL(profile, ignore_blacklist, &instant_url)) { |
| 1297 // If we are in extended mode, fallback to the local overlay. | 1296 // If we are in extended mode, fallback to the local overlay. |
| 1298 if (extended_enabled_) | 1297 if (extended_enabled_) |
| 1299 instant_url = chrome::kChromeSearchLocalOmniboxPopupURL; | 1298 instant_url = chrome::GetLocalInstantURL(browser_->profile()).spec(); |
| 1300 else | 1299 else |
| 1301 return false; | 1300 return false; |
| 1302 } | 1301 } |
| 1303 | 1302 |
| 1304 if (!overlay_ || overlay_->instant_url() != instant_url) | 1303 if (!overlay_ || overlay_->instant_url() != instant_url) |
| 1305 CreateOverlay(instant_url, active_tab); | 1304 CreateOverlay(instant_url, active_tab); |
| 1306 | 1305 |
| 1307 return true; | 1306 return true; |
| 1308 } | 1307 } |
| 1309 | 1308 |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1371 // Send a message asking the overlay to clear out old results. | 1370 // Send a message asking the overlay to clear out old results. |
| 1372 overlay_->Update(string16(), 0, 0, true); | 1371 overlay_->Update(string16(), 0, 0, true); |
| 1373 } | 1372 } |
| 1374 | 1373 |
| 1375 // Clear the first interaction timestamp for later use. | 1374 // Clear the first interaction timestamp for later use. |
| 1376 first_interaction_time_ = base::Time(); | 1375 first_interaction_time_ = base::Time(); |
| 1377 } | 1376 } |
| 1378 | 1377 |
| 1379 void InstantController::ShowOverlay(int height, InstantSizeUnits units) { | 1378 void InstantController::ShowOverlay(int height, InstantSizeUnits units) { |
| 1380 // If we are on a committed search results page, the |overlay_| is not in use. | 1379 // If we are on a committed search results page, the |overlay_| is not in use. |
| 1381 if (UseInstantTabToShowSuggestions()) | 1380 if (instant_tab_) |
| 1382 return; | 1381 return; |
| 1383 | 1382 |
| 1384 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 1383 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
| 1385 "Show: height=%d units=%d", height, units)); | 1384 "Show: height=%d units=%d", height, units)); |
| 1386 | 1385 |
| 1387 // Must have updated omnibox after the last HideOverlay() to show suggestions. | 1386 // Must have updated omnibox after the last HideOverlay() to show suggestions. |
| 1388 if (!allow_overlay_to_show_search_suggestions_) | 1387 if (!allow_overlay_to_show_search_suggestions_) |
| 1389 return; | 1388 return; |
| 1390 | 1389 |
| 1391 // The page is trying to hide itself. Hide explicitly (i.e., don't use | 1390 // The page is trying to hide itself. Hide explicitly (i.e., don't use |
| 1392 // HideOverlay()) so that it can change its mind. | 1391 // HideOverlay()) so that it can change its mind. |
| 1393 if (height == 0) { | 1392 if (height == 0) { |
| 1394 model_.SetOverlayState(SearchMode(), 0, INSTANT_SIZE_PERCENT); | 1393 model_.SetOverlayState(SearchMode(), 0, INSTANT_SIZE_PERCENT); |
| 1395 return; | 1394 return; |
| 1396 } | 1395 } |
| 1397 | 1396 |
| 1398 // If the overlay is being shown for the first time since the user started | 1397 // If the overlay is being shown for the first time since the user started |
| 1399 // typing, record a histogram value. | 1398 // typing, record a histogram value. |
| 1400 if (!first_interaction_time_.is_null() && model_.mode().is_default()) { | 1399 if (!first_interaction_time_.is_null() && model_.mode().is_default()) { |
| 1401 base::TimeDelta delta = base::Time::Now() - first_interaction_time_; | 1400 base::TimeDelta delta = base::Time::Now() - first_interaction_time_; |
| 1402 UMA_HISTOGRAM_TIMES("Instant.TimeToFirstShow", delta); | 1401 UMA_HISTOGRAM_TIMES("Instant.TimeToFirstShow", delta); |
| 1403 } | 1402 } |
| 1404 | 1403 |
| 1405 // Show at 100% height except in the following cases: | 1404 // Show at 100% height except in the following cases: |
| 1406 // - The local overlay (omnibox popup) is being loaded. | 1405 // - The local overlay (omnibox popup) is being loaded. |
| 1407 // - Instant is disabled. The page needs to be able to show only a dropdown. | 1406 // - Instant is disabled. The page needs to be able to show only a dropdown. |
| 1408 // - The page is over a website other than search or an NTP, and is not | 1407 // - The page is over a website other than search or an NTP, and is not |
| 1409 // already showing at 100% height. | 1408 // already showing at 100% height. |
| 1410 if (overlay_->IsLocalOverlay() || !instant_enabled_ || | 1409 if (overlay_->IsLocal() || !instant_enabled_ || |
| 1411 (search_mode_.is_origin_default() && !IsFullHeight(model_))) | 1410 (search_mode_.is_origin_default() && !IsFullHeight(model_))) |
| 1412 model_.SetOverlayState(search_mode_, height, units); | 1411 model_.SetOverlayState(search_mode_, height, units); |
| 1413 else | 1412 else |
| 1414 model_.SetOverlayState(search_mode_, 100, INSTANT_SIZE_PERCENT); | 1413 model_.SetOverlayState(search_mode_, 100, INSTANT_SIZE_PERCENT); |
| 1415 | 1414 |
| 1416 // If the overlay is being shown at full height and the omnibox is not | 1415 // If the overlay is being shown at full height and the omnibox is not |
| 1417 // focused, commit right away. | 1416 // focused, commit right away. |
| 1418 if (IsFullHeight(model_) && omnibox_focus_state_ == OMNIBOX_FOCUS_NONE) | 1417 if (IsFullHeight(model_) && omnibox_focus_state_ == OMNIBOX_FOCUS_NONE) |
| 1419 CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST); | 1418 CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST); |
| 1420 } | 1419 } |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1616 // suggest 'nstant'. Otherwise, the user text really isn't a prefix, so | 1615 // suggest 'nstant'. Otherwise, the user text really isn't a prefix, so |
| 1617 // suggest nothing. | 1616 // suggest nothing. |
| 1618 // TODO(samarth|jered): revisit this logic. http://crbug.com/196572. | 1617 // TODO(samarth|jered): revisit this logic. http://crbug.com/196572. |
| 1619 return true; | 1618 return true; |
| 1620 } | 1619 } |
| 1621 } | 1620 } |
| 1622 | 1621 |
| 1623 return false; | 1622 return false; |
| 1624 } | 1623 } |
| 1625 | 1624 |
| 1626 bool InstantController::UseInstantTabToShowSuggestions() const { | 1625 bool InstantController::ShouldSwitchToLocalNTP() const { |
| 1627 return instant_tab_ && !instant_tab_->IsLocalNTP(); | 1626 if (!ntp_) |
| 1628 } | 1627 return true; |
| 1629 | 1628 |
| 1630 bool InstantController::ShouldSwitchToLocalNTP() const { | 1629 // Don't switch if already using the correct local NTP. |
| 1630 if (ntp_->instant_url() == chrome::GetLocalInstantURL( |
| 1631 browser_->profile()).spec()) { |
| 1632 return false; |
| 1633 } |
| 1634 |
| 1631 // If there is no Instant URL or the NTP is stale, switch. | 1635 // If there is no Instant URL or the NTP is stale, switch. |
| 1632 std::string instant_url; | 1636 std::string instant_url; |
| 1633 if (!GetInstantURL(browser_->profile(), false, &instant_url) || | 1637 if (!GetInstantURL(browser_->profile(), false, &instant_url) || |
| 1634 !chrome::MatchesOriginAndPath(GURL(ntp_->instant_url()), | 1638 !chrome::MatchesOriginAndPath(GURL(ntp_->instant_url()), |
| 1635 GURL(instant_url))) { | 1639 GURL(instant_url))) { |
| 1636 return true; | 1640 return true; |
| 1637 } | 1641 } |
| 1638 | 1642 |
| 1639 if (ntp_->supports_instant()) | 1643 if (ntp_->supports_instant()) |
| 1640 return false; | 1644 return false; |
| 1641 | 1645 |
| 1642 // If this is not window startup, switch. | 1646 // If this is not window startup, switch. |
| 1643 // TODO(shishir): This is not completely reliable. Find a better way to detect | 1647 // TODO(shishir): This is not completely reliable. Find a better way to detect |
| 1644 // startup time. | 1648 // startup time. |
| 1645 if (browser_->GetActiveWebContents()) | 1649 if (browser_->GetActiveWebContents()) |
| 1646 return true; | 1650 return true; |
| 1647 | 1651 |
| 1648 return chrome::IsAggressiveLocalNTPFallbackEnabled(); | 1652 return chrome::IsAggressiveLocalNTPFallbackEnabled(); |
| 1649 } | 1653 } |
| OLD | NEW |