Chromium Code Reviews| 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/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/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 169 | 169 |
| 170 DVLOG(1) << "Update: " << AutocompleteMatch::TypeToString(match.type) | 170 DVLOG(1) << "Update: " << AutocompleteMatch::TypeToString(match.type) |
| 171 << " user_text='" << user_text << "' full_text='" << full_text << "'" | 171 << " user_text='" << user_text << "' full_text='" << full_text << "'" |
| 172 << " verbatim=" << verbatim << " typing=" << user_input_in_progress | 172 << " verbatim=" << verbatim << " typing=" << user_input_in_progress |
| 173 << " popup=" << omnibox_popup_is_open; | 173 << " popup=" << omnibox_popup_is_open; |
| 174 | 174 |
| 175 // If the popup is open, the user has to be typing. | 175 // If the popup is open, the user has to be typing. |
| 176 DCHECK(!omnibox_popup_is_open || user_input_in_progress); | 176 DCHECK(!omnibox_popup_is_open || user_input_in_progress); |
| 177 | 177 |
| 178 // If the popup is closed, there should be no inline autocompletion. | 178 // If the popup is closed, there should be no inline autocompletion. |
| 179 DCHECK(omnibox_popup_is_open || user_text == full_text) << user_text << "|" | 179 DCHECK(omnibox_popup_is_open || user_text.empty() || user_text == full_text) |
| 180 << full_text; | 180 << user_text << "|" << full_text; |
| 181 | 181 |
| 182 // If there's inline autocompletion, the query has to be verbatim. | 182 // If there's inline autocompletion, the query has to be verbatim. |
| 183 DCHECK(user_text == full_text || verbatim) << user_text << "|" << full_text; | 183 DCHECK(user_text.empty() || user_text == full_text || verbatim) |
| 184 << user_text << "|" << full_text; | |
| 184 | 185 |
| 185 // If there's no text in the omnibox, the user can't have typed any. | 186 // If there's no text in the omnibox, the user can't have typed any. |
| 186 DCHECK(!full_text.empty() || user_text.empty()) << user_text; | 187 DCHECK(!full_text.empty() || user_text.empty()) << user_text; |
| 187 | 188 |
| 188 // If the user isn't typing, and the popup is closed, there can't be any | 189 // If the user isn't typing, and the popup is closed, there can't be any |
| 189 // user-typed text. | 190 // user-typed text. |
| 190 DCHECK(user_input_in_progress || omnibox_popup_is_open || user_text.empty()) | 191 DCHECK(user_input_in_progress || omnibox_popup_is_open || user_text.empty()) |
| 191 << user_text; | 192 << user_text; |
| 192 | 193 |
| 193 // In non-extended mode, SearchModeChanged() is never called, so fake it. The | 194 // In non-extended mode, SearchModeChanged() is never called, so fake it. The |
| 194 // mode is set to "disallow suggestions" here, so that if one of the early | 195 // mode is set to "disallow suggestions" here, so that if one of the early |
| 195 // "return false" conditions is hit, suggestions will be disallowed. If the | 196 // "return false" conditions is hit, suggestions will be disallowed. If the |
| 196 // query is sent to the loader, the mode is set to "allow" further below. | 197 // query is sent to the loader, the mode is set to "allow" further below. |
| 197 if (!extended_enabled_) | 198 if (!extended_enabled_) |
| 198 search_mode_.mode = chrome::search::Mode::MODE_DEFAULT; | 199 search_mode_.mode = chrome::search::Mode::MODE_DEFAULT; |
| 199 | 200 |
| 200 // If there's no active tab, the browser is closing. | 201 // If there's no active tab, the browser is closing. |
| 201 const TabContents* const active_tab = browser_->GetActiveTabContents(); | 202 const TabContents* const active_tab = browser_->GetActiveTabContents(); |
| 202 if (!active_tab) { | 203 if (!active_tab) { |
| 203 Hide(true); | 204 Hide(true); |
| 204 return false; | 205 return false; |
| 205 } | 206 } |
| 206 | 207 |
| 208 // Ensure we have a loader that can process this match. First, try to use the | |
| 209 // TemplateURL of the |match|. If that's invalid, in non-extended mode, stop. | |
| 210 // In extended mode, try using the default search engine, but only when the | |
| 211 // match is for a URL (i.e., not some other kind of non-Instant search). | |
| 212 // A completely blank query shows up as a search, and we do want to allow | |
| 213 // that, hence the "!user_text.empty()" clause. | |
| 214 Profile* const profile = active_tab->profile(); | |
| 215 const bool match_is_search = AutocompleteMatch::IsSearchType(match.type); | |
| 216 if (!ResetLoader(match.GetTemplateURL(profile, false), active_tab) && | |
|
Jered
2012/11/27 19:21:57
Why reset the loader here if client_ is set?
sreeram
2012/11/29 07:33:19
Done.
| |
| 217 (!extended_enabled_ || (match_is_search && !user_text.empty()) || | |
| 218 (!client_ && !CreateDefaultLoader()))) { | |
| 219 Hide(true); | |
| 220 return false; | |
| 221 } | |
| 222 | |
| 207 // Legend: OPIO == |omnibox_popup_is_open|, UIIP = |user_input_in_progress|. | 223 // Legend: OPIO == |omnibox_popup_is_open|, UIIP = |user_input_in_progress|. |
| 208 // | 224 // |
| 209 // # OPIO UIIP full_text Notes | 225 // # OPIO UIIP full_text Notes |
| 210 // - ---- ---- --------- ----- | 226 // - ---- ---- --------- ----- |
| 211 // 1 no no blank } Navigation, or user hit Escape. |full_text| is | 227 // 1 no no blank } Navigation, or user hit Escape. |full_text| is |
| 212 // 2 no no non-blank } blank if the page is NTP, non-blank otherwise. | 228 // 2 no no non-blank } blank if the page is NTP, non-blank otherwise. |
| 213 // | 229 // |
| 214 // 3 no yes blank User backspaced away all omnibox text. | 230 // 3 no yes blank User backspaced away all omnibox text. |
| 215 // | 231 // |
| 216 // 4 no yes non-blank User switched to a tab with a partial query. | 232 // 4 no yes non-blank User switched to a tab with a partial query. |
| 217 // | 233 // |
| 218 // 5 yes no blank } Impossible. DCHECK()ed above. | 234 // 5 yes no blank } Impossible. DCHECK()ed above. |
| 219 // 6 yes no non-blank } | 235 // 6 yes no non-blank } |
| 220 // | 236 // |
| 221 // 7 yes yes blank User typed a "?" into the omnibox. | 237 // 7 yes yes blank User typed a "?" into the omnibox. |
| 222 // | 238 // |
| 223 // 8 yes yes non-blank User typed text into the omnibox. | 239 // 8 yes yes non-blank User typed text into the omnibox. |
| 224 // | 240 // |
| 225 // In non-extended mode, #1 to #7 call Hide(). #8 calls loader_->Update(). | 241 // In non-extended mode, #1 to #7 call Hide(). #8 calls loader_->Update(). |
| 226 // | 242 // |
| 227 // In extended mode, #2 and #4 call Hide(). #1 doesn't Hide() as the preview | 243 // In extended mode, #2 and #4 call Hide(). #1 doesn't Hide() as the preview |
| 228 // may be showing custom NTP content, but doesn't Update() either. #3 and #7 | 244 // may be showing custom NTP content, but doesn't Update() either. #3 and #7 |
| 229 // don't Hide(), but send a blank query to Update(). #8 calls Update(). | 245 // don't Hide(), and send a blank query to Update(). #8 calls Update(). |
| 230 | 246 |
| 231 if (extended_enabled_) { | 247 if (extended_enabled_) { |
| 232 if (!omnibox_popup_is_open) { | 248 if (!omnibox_popup_is_open) { |
| 233 if (!full_text.empty()) { | 249 if (!user_input_in_progress) { |
| 234 Hide(true); | 250 if (!full_text.empty()) { |
| 235 return false; | 251 Hide(true); // #2 |
|
samarth
2012/11/27 18:09:43
Mostly for my understanding: Hide() will be a no-o
sreeram
2012/11/29 07:33:19
No, Hide() won't be a no-op. For one, it will actu
| |
| 252 // If the user hit Escape when on a search results page, restore the | |
| 253 // original results by resending the query. If the user was not on a | |
| 254 // search results page, SearchModeChanged() would've caught it, and | |
| 255 // |client_| will be NULL, so we won't accidentally send non-query | |
| 256 // |full_text| to |client_|. Except if the user just switched tabs. | |
| 257 // Hence the comparison of WebContents, to catch that case as well. | |
| 258 if (client_ && client_->contents() == active_tab->web_contents()) | |
| 259 client_->Update(full_text, true); | |
| 260 } | |
| 261 return false; // #1 | |
| 262 } else { | |
| 263 if (!full_text.empty()) { | |
| 264 Hide(true); // #4 | |
| 265 if (match_is_search) { | |
| 266 // The user just switched to a tab with a partial query already in | |
| 267 // the omnibox. This tab may or may not be a search results page | |
| 268 // (SearchModeChanged() hasn't been called yet). So, assume that it | |
| 269 // could be, and store |full_text| so that if the user then hits | |
| 270 // Enter, we'll send the correct query in client_->Submit(). | |
| 271 last_full_text_ = full_text; | |
| 272 last_match_was_search_ = true; | |
| 273 } | |
| 274 return false; | |
| 275 } | |
| 236 } | 276 } |
| 237 if (!user_input_in_progress && full_text.empty()) | |
| 238 return false; | |
| 239 } | 277 } |
| 240 } else if (!omnibox_popup_is_open || full_text.empty()) { | 278 } else if (!omnibox_popup_is_open || full_text.empty()) { |
| 241 // Update() can be called if the user clicks the preview while composing | 279 // Update() can be called if the user clicks the preview while composing |
| 242 // text with an IME. If so, we should commit on mouse up, so don't Hide(). | 280 // text with an IME. If so, we should commit on mouse up, so don't Hide(). |
| 243 if (!GetPreviewContents() || !loader_->IsPointerDownFromActivate()) | 281 if (!loader_ || !loader_->IsPointerDownFromActivate()) |
| 244 Hide(true); | 282 Hide(true); |
| 245 return false; | 283 return false; |
| 246 } | 284 } |
| 247 | 285 |
| 248 // Ensure we have a loader that can process this match. First, try to use the | |
| 249 // TemplateURL of the |match|. If that's invalid, in non-extended mode, stop. | |
| 250 // In extended mode, try using the default search engine, but only when the | |
| 251 // match is for a URL (i.e., not some other kind of non-Instant search). | |
| 252 // A completely blank query shows up as a search, and we do want to allow | |
| 253 // that, hence the "!full_text.empty()" clause. | |
| 254 Profile* const profile = active_tab->profile(); | |
| 255 const bool match_is_search = AutocompleteMatch::IsSearchType(match.type); | |
| 256 if (!ResetLoader(match.GetTemplateURL(profile, false), active_tab) && | |
| 257 (!extended_enabled_ || (match_is_search && !full_text.empty()) || | |
| 258 !CreateDefaultLoader())) { | |
| 259 Hide(true); | |
| 260 return false; | |
| 261 } | |
| 262 | |
| 263 // If the user continues typing the same query as the suggested text is | 286 // If the user continues typing the same query as the suggested text is |
| 264 // showing, reuse the suggestion (but only for INSTANT_COMPLETE_NEVER). | 287 // showing, reuse the suggestion (but only for INSTANT_COMPLETE_NEVER). |
| 265 bool reused_suggestion = false; | 288 bool reused_suggestion = false; |
| 266 if (last_suggestion_.behavior == INSTANT_COMPLETE_NEVER) { | 289 if (last_suggestion_.behavior == INSTANT_COMPLETE_NEVER) { |
| 267 if (StartsWith(last_user_text_, user_text, false) && !user_text.empty()) { | 290 if (StartsWith(last_user_text_, user_text, false) && !user_text.empty()) { |
| 268 // The user is backspacing away characters. | 291 // The user is backspacing away characters. |
| 269 last_suggestion_.text.insert(0, last_user_text_, user_text.size(), | 292 last_suggestion_.text.insert(0, last_user_text_, user_text.size(), |
| 270 last_user_text_.size() - user_text.size()); | 293 last_user_text_.size() - user_text.size()); |
| 271 reused_suggestion = true; | 294 reused_suggestion = true; |
| 272 } else if (StartsWith(user_text, last_user_text_, false)) { | 295 } else if (StartsWith(user_text, last_user_text_, false)) { |
| 273 // The user is typing forward. Normalize any added characters. | 296 // The user is typing forward. Normalize any added characters. |
| 274 reused_suggestion = NormalizeAndStripPrefix(&last_suggestion_.text, | 297 reused_suggestion = NormalizeAndStripPrefix(&last_suggestion_.text, |
| 275 string16(user_text, last_user_text_.size())); | 298 string16(user_text, last_user_text_.size())); |
| 276 } | 299 } |
| 277 } | 300 } |
| 278 | 301 |
| 279 last_user_text_ = user_text; | 302 last_user_text_ = user_text; |
| 280 last_full_text_ = full_text; | 303 last_full_text_ = full_text; |
| 281 last_verbatim_ = verbatim; | 304 last_verbatim_ = verbatim; |
| 282 | 305 |
| 283 if (!reused_suggestion) | 306 if (!reused_suggestion) |
| 284 last_suggestion_ = InstantSuggestion(); | 307 last_suggestion_ = InstantSuggestion(); |
| 285 | 308 |
| 286 last_transition_type_ = match.transition; | 309 last_transition_type_ = match.transition; |
| 287 last_match_was_search_ = match_is_search; | 310 last_match_was_search_ = match_is_search; |
| 288 url_for_history_ = match.destination_url; | 311 url_for_history_ = match.destination_url; |
| 289 | 312 |
| 290 // Store the first interaction time for use with latency histograms. | 313 // Store the first interaction time for use with latency histograms. |
| 291 if (first_interaction_time_.is_null()) | 314 if (loader_ == CurrentClient() && first_interaction_time_.is_null()) |
|
Jered
2012/11/27 19:21:57
Please extract a method like IsCommitted() for loa
sreeram
2012/11/29 07:33:19
I've gone with the simpler "if (instant_tab_)" idi
| |
| 292 first_interaction_time_ = base::Time::Now(); | 315 first_interaction_time_ = base::Time::Now(); |
| 293 | 316 |
| 294 // Allow search suggestions. In extended mode, SearchModeChanged() will set | 317 // Allow search suggestions. In extended mode, SearchModeChanged() will set |
| 295 // this, but it's not called in non-extended mode, so fake it. | 318 // this, but it's not called in non-extended mode, so fake it. |
| 296 if (!extended_enabled_) | 319 if (!extended_enabled_) |
| 297 search_mode_.mode = chrome::search::Mode::MODE_SEARCH_SUGGESTIONS; | 320 search_mode_.mode = chrome::search::Mode::MODE_SEARCH_SUGGESTIONS; |
| 298 | 321 |
| 299 loader_->Update(extended_enabled_ ? user_text : full_text, verbatim); | 322 CurrentClient()->Update(extended_enabled_ ? user_text : full_text, verbatim); |
| 323 | |
| 324 if (loader_ == CurrentClient()) | |
| 325 loader_->DidNavigate(history::HistoryAddPageArgs()); | |
| 300 | 326 |
| 301 content::NotificationService::current()->Notify( | 327 content::NotificationService::current()->Notify( |
| 302 chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, | 328 chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, |
| 303 content::Source<InstantController>(this), | 329 content::Source<InstantController>(this), |
| 304 content::NotificationService::NoDetails()); | 330 content::NotificationService::NoDetails()); |
| 305 | 331 |
| 306 // We don't have new suggestions yet, but we can either reuse the existing | 332 // We don't have new suggestions yet, but we can either reuse the existing |
| 307 // suggestion or reset the existing "gray text". | 333 // suggestion or reset the existing "gray text". |
| 308 browser_->SetInstantSuggestion(last_suggestion_); | 334 browser_->SetInstantSuggestion(last_suggestion_); |
| 309 | 335 |
| 310 // Though we may have handled a URL match above, we return false here, so that | 336 // Though we may have handled a URL match above, we return false here, so that |
| 311 // omnibox prerendering can kick in. TODO(sreeram): Remove this (and always | 337 // omnibox prerendering can kick in. TODO(sreeram): Remove this (and always |
| 312 // return true) once we are able to commit URLs as well. | 338 // return true) once we are able to commit URLs as well. |
| 313 return match_is_search; | 339 return match_is_search; |
| 314 } | 340 } |
| 315 | 341 |
| 316 // TODO(tonyg): This method only fires when the omnibox bounds change. It also | 342 // TODO(tonyg): This method only fires when the omnibox bounds change. It also |
| 317 // needs to fire when the preview bounds change (e.g.: open/close info bar). | 343 // needs to fire when the preview bounds change (e.g.: open/close info bar). |
| 318 void InstantController::SetOmniboxBounds(const gfx::Rect& bounds) { | 344 void InstantController::SetOmniboxBounds(const gfx::Rect& bounds) { |
| 319 if (!extended_enabled_ && !instant_enabled_) | 345 if (!extended_enabled_ && !instant_enabled_) |
| 320 return; | 346 return; |
| 321 | 347 |
| 322 if (omnibox_bounds_ == bounds) | 348 if (omnibox_bounds_ == bounds) |
|
samarth
2012/11/28 06:31:15
This no longer works correctly. Well, we don't ca
sreeram
2012/11/29 07:33:19
As discussed offline, this does work correctly (be
| |
| 323 return; | 349 return; |
| 324 | 350 |
| 325 omnibox_bounds_ = bounds; | 351 omnibox_bounds_ = bounds; |
| 326 if (omnibox_bounds_.height() > last_omnibox_bounds_.height()) { | 352 if (omnibox_bounds_.height() > last_omnibox_bounds_.height()) { |
| 327 update_bounds_timer_.Stop(); | 353 update_bounds_timer_.Stop(); |
| 328 SendBoundsToPage(); | 354 SendBoundsToPage(); |
| 329 } else if (!update_bounds_timer_.IsRunning()) { | 355 } else if (!update_bounds_timer_.IsRunning()) { |
| 330 update_bounds_timer_.Start(FROM_HERE, | 356 update_bounds_timer_.Start(FROM_HERE, |
| 331 base::TimeDelta::FromMilliseconds(kUpdateBoundsDelayMS), this, | 357 base::TimeDelta::FromMilliseconds(kUpdateBoundsDelayMS), this, |
| 332 &InstantController::SendBoundsToPage); | 358 &InstantController::SendBoundsToPage); |
| 333 } | 359 } |
| 334 } | 360 } |
| 335 | 361 |
| 336 void InstantController::HandleAutocompleteResults( | 362 void InstantController::HandleAutocompleteResults( |
| 337 const std::vector<AutocompleteProvider*>& providers) { | 363 const std::vector<AutocompleteProvider*>& providers) { |
| 338 if (!extended_enabled_) | 364 if (!extended_enabled_) |
| 339 return; | 365 return; |
| 340 | 366 |
|
sky
2012/11/27 01:07:51
Shouldn't we early out if no client?
sreeram
2012/11/29 07:33:19
Done.
| |
| 341 if (!GetPreviewContents()) | |
| 342 return; | |
| 343 | |
| 344 DVLOG(1) << "AutocompleteResults:"; | 367 DVLOG(1) << "AutocompleteResults:"; |
| 345 std::vector<InstantAutocompleteResult> results; | 368 std::vector<InstantAutocompleteResult> results; |
| 346 for (ACProviders::const_iterator provider = providers.begin(); | 369 for (ACProviders::const_iterator provider = providers.begin(); |
| 347 provider != providers.end(); ++provider) { | 370 provider != providers.end(); ++provider) { |
| 348 for (ACMatches::const_iterator match = (*provider)->matches().begin(); | 371 for (ACMatches::const_iterator match = (*provider)->matches().begin(); |
| 349 match != (*provider)->matches().end(); ++match) { | 372 match != (*provider)->matches().end(); ++match) { |
| 350 InstantAutocompleteResult result; | 373 InstantAutocompleteResult result; |
| 351 result.provider = UTF8ToUTF16((*provider)->GetName()); | 374 result.provider = UTF8ToUTF16((*provider)->GetName()); |
| 352 result.type = UTF8ToUTF16(AutocompleteMatch::TypeToString(match->type)); | 375 result.type = UTF8ToUTF16(AutocompleteMatch::TypeToString(match->type)); |
| 353 result.description = match->description; | 376 result.description = match->description; |
| 354 result.destination_url = UTF8ToUTF16(match->destination_url.spec()); | 377 result.destination_url = UTF8ToUTF16(match->destination_url.spec()); |
| 355 result.relevance = match->relevance; | 378 result.relevance = match->relevance; |
| 356 DVLOG(1) << " " << result.relevance << " " << result.type << " " | 379 DVLOG(1) << " " << result.relevance << " " << result.type << " " |
| 357 << result.provider << " " << result.destination_url << " '" | 380 << result.provider << " " << result.destination_url << " '" |
| 358 << result.description << "'"; | 381 << result.description << "'"; |
| 359 results.push_back(result); | 382 results.push_back(result); |
| 360 } | 383 } |
| 361 } | 384 } |
| 362 | 385 |
| 363 loader_->SendAutocompleteResults(results); | 386 if (InstantClient* client = CurrentClient()) |
|
samarth
2012/11/27 18:09:43
nit: does the Chrome style guide allow this? I hav
sreeram
2012/11/29 07:33:19
The style guide doesn't mention it. @sky hates it.
| |
| 387 client->SendAutocompleteResults(results); | |
| 364 } | 388 } |
| 365 | 389 |
| 366 bool InstantController::OnUpOrDownKeyPressed(int count) { | 390 bool InstantController::OnUpOrDownKeyPressed(int count) { |
| 367 if (!extended_enabled_) | 391 if (!extended_enabled_) |
| 368 return false; | 392 return false; |
| 369 | 393 |
| 370 if (!GetPreviewContents()) | 394 if (InstantClient* client = CurrentClient()) { |
| 371 return false; | 395 client->UpOrDownKeyPressed(count); |
| 396 return true; | |
| 397 } | |
| 372 | 398 |
| 373 loader_->OnUpOrDownKeyPressed(count); | 399 return false; |
| 374 return true; | |
| 375 } | 400 } |
| 376 | 401 |
| 377 TabContents* InstantController::GetPreviewContents() const { | 402 TabContents* InstantController::GetPreviewContents() const { |
| 378 return loader_ ? loader_->preview_contents() : NULL; | 403 return loader_ ? loader_->preview_contents() : NULL; |
| 379 } | 404 } |
| 380 | 405 |
| 381 bool InstantController::IsCurrent() const { | 406 bool InstantController::IsCurrent() const { |
|
samarth
2012/11/27 18:09:43
What should IsCurrent return if client_ is set? Fo
sreeram
2012/11/29 07:33:19
If |instant_tab_| is non-NULL, IsCurrent() should
| |
| 382 return model_.mode().is_search_suggestions() && last_match_was_search_; | 407 return model_.mode().is_search_suggestions() && last_match_was_search_; |
| 383 } | 408 } |
| 384 | 409 |
| 385 bool InstantController::CommitIfCurrent(InstantCommitType type) { | 410 bool InstantController::CommitIfCurrent(InstantCommitType type) { |
| 386 if (!extended_enabled_ && !instant_enabled_) | 411 if (!extended_enabled_ && !instant_enabled_) |
| 387 return false; | 412 return false; |
| 388 | 413 |
| 414 if (client_ == CurrentClient() && last_match_was_search_ && | |
|
Jered
2012/11/27 19:21:57
I am very confused. Why doesn't this cancel someti
sreeram
2012/11/29 07:33:19
Cancel() isn't applicable in the case of a committ
| |
| 415 type == INSTANT_COMMIT_PRESSED_ENTER) { | |
| 416 client_->Submit(last_full_text_); | |
| 417 return true; | |
| 418 } | |
| 419 | |
| 389 if (!IsCurrent()) | 420 if (!IsCurrent()) |
| 390 return false; | 421 return false; |
| 391 | 422 |
| 392 DVLOG(1) << "CommitIfCurrent"; | 423 DVLOG(1) << "CommitIfCurrent"; |
| 393 TabContents* preview = loader_->ReleasePreviewContents(type, last_full_text_); | 424 |
| 425 if (type == INSTANT_COMMIT_FOCUS_LOST) | |
| 426 loader_->Cancel(last_full_text_); | |
| 427 else | |
| 428 loader_->Submit(last_full_text_); | |
| 429 loader_->CleanupPreviewContents(); | |
| 430 | |
| 431 TabContents* preview = loader_->release_preview_contents(); | |
| 394 | 432 |
| 395 if (extended_enabled_) { | 433 if (extended_enabled_) { |
| 396 // Consider what's happening: | 434 // Consider what's happening: |
| 397 // 1. The user has typed a query in the omnibox and committed it (either | 435 // 1. The user has typed a query in the omnibox and committed it (either |
| 398 // by pressing Enter or clicking on the preview). | 436 // by pressing Enter or clicking on the preview). |
| 399 // 2. We commit the preview to the tab strip, and tell the page. | 437 // 2. We commit the preview to the tab strip, and tell the page. |
| 400 // 3. The page will update the URL hash fragment with the query terms. | 438 // 3. The page will update the URL hash fragment with the query terms. |
| 401 // After steps 1 and 3, the omnibox will show the query terms. However, if | 439 // After steps 1 and 3, the omnibox will show the query terms. However, if |
| 402 // the URL we are committing at step 2 doesn't already have query terms, it | 440 // the URL we are committing at step 2 doesn't already have query terms, it |
| 403 // will flash for a brief moment as a plain URL. So, avoid that flicker by | 441 // will flash for a brief moment as a plain URL. So, avoid that flicker by |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 487 if (!IsCurrent() || !GetPreviewContents()) { | 525 if (!IsCurrent() || !GetPreviewContents()) { |
| 488 OnStaleLoader(); | 526 OnStaleLoader(); |
| 489 return; | 527 return; |
| 490 } | 528 } |
| 491 | 529 |
| 492 #if defined(OS_MACOSX) | 530 #if defined(OS_MACOSX) |
| 493 if (!loader_->IsPointerDownFromActivate()) | 531 if (!loader_->IsPointerDownFromActivate()) |
| 494 Hide(true); | 532 Hide(true); |
| 495 #else | 533 #else |
| 496 if (IsViewInContents(GetViewGainingFocus(view_gaining_focus), | 534 if (IsViewInContents(GetViewGainingFocus(view_gaining_focus), |
| 497 GetPreviewContents()->web_contents())) | 535 loader_->contents())) |
| 498 CommitIfCurrent(INSTANT_COMMIT_FOCUS_LOST); | 536 CommitIfCurrent(INSTANT_COMMIT_FOCUS_LOST); |
| 499 else | 537 else |
| 500 Hide(true); | 538 Hide(true); |
| 501 #endif | 539 #endif |
| 502 } | 540 } |
| 503 | 541 |
| 504 void InstantController::OmniboxGotFocus() { | 542 void InstantController::OmniboxGotFocus() { |
| 505 DVLOG(1) << "OmniboxGotFocus"; | 543 DVLOG(1) << "OmniboxGotFocus"; |
| 506 is_omnibox_focused_ = true; | 544 is_omnibox_focused_ = true; |
| 507 | 545 |
| 508 if (!extended_enabled_ && !instant_enabled_) | 546 if (!extended_enabled_ && !instant_enabled_) |
| 509 return; | 547 return; |
| 510 | 548 |
| 511 if (!GetPreviewContents()) | 549 if (!client_ && !loader_) |
| 512 CreateDefaultLoader(); | 550 CreateDefaultLoader(); |
| 513 } | 551 } |
| 514 | 552 |
| 515 void InstantController::SearchModeChanged( | 553 void InstantController::SearchModeChanged( |
| 516 const chrome::search::Mode& old_mode, | 554 const chrome::search::Mode& old_mode, |
| 517 const chrome::search::Mode& new_mode) { | 555 const chrome::search::Mode& new_mode) { |
| 518 if (!extended_enabled_) | 556 if (!extended_enabled_) |
| 519 return; | 557 return; |
| 520 | 558 |
| 521 DVLOG(1) << "SearchModeChanged: [origin:mode] " << old_mode.origin << ":" | 559 DVLOG(1) << "SearchModeChanged: [origin:mode] " << old_mode.origin << ":" |
| 522 << old_mode.mode << " to " << new_mode.origin << ":" | 560 << old_mode.mode << " to " << new_mode.origin << ":" |
| 523 << new_mode.mode; | 561 << new_mode.mode; |
| 524 search_mode_ = new_mode; | 562 search_mode_ = new_mode; |
| 525 | 563 |
| 526 if (new_mode.is_search_suggestions()) { | 564 if (new_mode.is_search_suggestions()) { |
|
samarth
2012/11/27 18:09:43
Is this code path relevant when client_ is set? In
sreeram
2012/11/29 07:33:19
I think there's a balance to be struck here. I don
| |
| 527 // The preview is showing NTP content, but it's not appropriate anymore. | 565 // The preview is showing NTP content, but it's not appropriate anymore. |
| 528 if (model_.mode().is_ntp() && !new_mode.is_origin_ntp()) | 566 if (model_.mode().is_ntp() && !new_mode.is_origin_ntp()) |
| 529 Hide(false); | 567 Hide(false); |
| 530 } else { | 568 } else { |
| 531 Hide(true); | 569 Hide(true); |
| 532 } | 570 } |
| 533 | 571 |
| 534 if (GetPreviewContents()) | 572 if (loader_) |
| 535 loader_->SearchModeChanged(new_mode); | 573 loader_->SearchModeChanged(new_mode); |
| 574 | |
| 575 ResetClient(); | |
| 536 } | 576 } |
| 537 | 577 |
| 538 void InstantController::ActiveTabChanged() { | 578 void InstantController::ActiveTabChanged() { |
| 539 if (!extended_enabled_ && !instant_enabled_) | 579 if (!extended_enabled_ && !instant_enabled_) |
| 540 return; | 580 return; |
| 541 | 581 |
| 542 DVLOG(1) << "ActiveTabChanged"; | 582 DVLOG(1) << "ActiveTabChanged"; |
| 543 | 583 |
| 544 // By this time, SearchModeChanged() should've been called, so we only need to | 584 // By this time, SearchModeChanged() should've been called, so we only need to |
| 545 // handle the case when the search mode does NOT change, as in the case of | 585 // handle the case when the search mode does NOT change, as in the case of |
| 546 // going from search_suggestions to search_suggestions (i.e., partial queries | 586 // going from search_suggestions to search_suggestions (i.e., partial queries |
| 547 // on both old and new tabs). | 587 // on both old and new tabs). |
| 548 if (search_mode_.is_search_suggestions() && | 588 if (search_mode_.is_search_suggestions() && |
| 549 model_.mode().is_search_suggestions()) | 589 model_.mode().is_search_suggestions()) |
| 550 Hide(false); | 590 Hide(false); |
| 591 | |
| 592 if (extended_enabled_) | |
| 593 ResetClient(); | |
| 551 } | 594 } |
| 552 | 595 |
| 553 void InstantController::SetInstantEnabled(bool instant_enabled) { | 596 void InstantController::SetInstantEnabled(bool instant_enabled) { |
| 554 instant_enabled_ = instant_enabled; | 597 instant_enabled_ = instant_enabled; |
| 555 if (!extended_enabled_ && !instant_enabled_) | 598 if (!extended_enabled_ && !instant_enabled_) |
| 556 DeleteLoader(); | 599 DeleteLoader(); |
| 557 } | 600 } |
| 558 | 601 |
| 559 void InstantController::ThemeChanged(const ThemeBackgroundInfo& theme_info) { | 602 void InstantController::ThemeChanged(const ThemeBackgroundInfo& theme_info) { |
| 560 if (!extended_enabled_) | 603 if (!extended_enabled_) |
| 561 return; | 604 return; |
| 562 | 605 |
| 563 if (GetPreviewContents()) | 606 if (loader_) |
| 564 loader_->SendThemeBackgroundInfo(theme_info); | 607 loader_->SendThemeBackgroundInfo(theme_info); |
| 565 } | 608 } |
| 566 | 609 |
| 567 void InstantController::ThemeAreaHeightChanged(int height) { | 610 void InstantController::ThemeAreaHeightChanged(int height) { |
| 568 if (!extended_enabled_) | 611 if (!extended_enabled_) |
| 569 return; | 612 return; |
| 570 | 613 |
| 571 if (GetPreviewContents()) | 614 if (loader_) |
| 572 loader_->SendThemeAreaHeight(height); | 615 loader_->SendThemeAreaHeight(height); |
| 573 } | 616 } |
| 574 | 617 |
| 575 void InstantController::SetSuggestions( | 618 void InstantController::SetSuggestions( |
| 576 InstantLoader* loader, | 619 InstantClient* client, |
| 577 const std::vector<InstantSuggestion>& suggestions) { | 620 const std::vector<InstantSuggestion>& suggestions) { |
| 578 DVLOG(1) << "SetSuggestions"; | 621 DVLOG(1) << "SetSuggestions"; |
| 579 if (loader_ != loader || !search_mode_.is_search_suggestions()) | 622 if (client != CurrentClient() || !search_mode_.is_search_suggestions()) |
| 580 return; | 623 return; |
| 581 | 624 |
| 582 InstantSuggestion suggestion; | 625 InstantSuggestion suggestion; |
| 583 if (!suggestions.empty()) | 626 if (!suggestions.empty()) |
| 584 suggestion = suggestions[0]; | 627 suggestion = suggestions[0]; |
| 585 | 628 |
| 586 if (suggestion.behavior == INSTANT_COMPLETE_REPLACE) { | 629 if (suggestion.behavior == INSTANT_COMPLETE_REPLACE) { |
| 587 // We don't get an Update() when changing the omnibox due to a REPLACE | 630 // We don't get an Update() when changing the omnibox due to a REPLACE |
| 588 // suggestion (so that we don't inadvertently cause the preview to change | 631 // suggestion (so that we don't inadvertently cause the preview to change |
| 589 // what it's showing, as the user arrows up/down through the page-provided | 632 // what it's showing, as the user arrows up/down through the page-provided |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 652 } | 695 } |
| 653 | 696 |
| 654 void InstantController::ShowInstantPreview(InstantLoader* loader, | 697 void InstantController::ShowInstantPreview(InstantLoader* loader, |
| 655 InstantShownReason reason, | 698 InstantShownReason reason, |
| 656 int height, | 699 int height, |
| 657 InstantSizeUnits units) { | 700 InstantSizeUnits units) { |
| 658 if (loader_ == loader && extended_enabled_) | 701 if (loader_ == loader && extended_enabled_) |
| 659 Show(reason, height, units); | 702 Show(reason, height, units); |
| 660 } | 703 } |
| 661 | 704 |
| 662 void InstantController::InstantSupportDetermined(InstantLoader* loader, | 705 void InstantController::InstantSupportDetermined(InstantClient* client, |
| 663 bool supports_instant) { | 706 bool supports_instant) { |
| 707 if (client_ == client) { | |
| 708 if (!supports_instant) { | |
| 709 // TODO(sreeram): This should be scheduled for later deletion, but we need | |
| 710 // to disconnect the observer before doing so. | |
| 711 client_.reset(); | |
| 712 } | |
| 713 return; | |
| 714 } | |
| 715 | |
| 716 InstantLoader* loader = static_cast<InstantLoader*>(client); | |
| 664 if (supports_instant) { | 717 if (supports_instant) { |
| 665 blacklisted_urls_.erase(loader->instant_url()); | 718 blacklisted_urls_.erase(loader->instant_url()); |
| 666 } else { | 719 } else { |
| 667 ++blacklisted_urls_[loader->instant_url()]; | 720 ++blacklisted_urls_[loader->instant_url()]; |
| 668 if (loader_ == loader) | 721 if (loader_ == loader) |
| 669 DeleteLoader(); | 722 DeleteLoader(); |
| 670 } | 723 } |
| 671 | 724 |
| 672 content::NotificationService::current()->Notify( | 725 content::NotificationService::current()->Notify( |
| 673 chrome::NOTIFICATION_INSTANT_SUPPORT_DETERMINED, | 726 chrome::NOTIFICATION_INSTANT_SUPPORT_DETERMINED, |
| 674 content::Source<InstantController>(this), | 727 content::Source<InstantController>(this), |
| 675 content::NotificationService::NoDetails()); | 728 content::NotificationService::NoDetails()); |
| 676 } | 729 } |
| 677 | 730 |
| 678 void InstantController::SwappedTabContents(InstantLoader* loader) { | 731 void InstantController::SwappedTabContents(InstantLoader* loader) { |
| 679 if (loader_ == loader) | 732 if (loader_ == loader) |
| 680 model_.SetPreviewContents(GetPreviewContents()); | 733 model_.SetPreviewContents(GetPreviewContents()); |
| 681 } | 734 } |
| 682 | 735 |
| 683 void InstantController::InstantLoaderContentsFocused(InstantLoader* loader) { | 736 void InstantController::InstantLoaderContentsFocused(InstantLoader* loader) { |
| 684 #if defined(USE_AURA) | 737 #if defined(USE_AURA) |
| 685 // On aura the omnibox only receives a focus lost if we initiate the focus | 738 // On aura the omnibox only receives a focus lost if we initiate the focus |
| 686 // change. This does that. | 739 // change. This does that. |
| 687 if (loader_ == loader && !model_.mode().is_default()) | 740 if (loader_ == loader && !model_.mode().is_default()) |
| 688 browser_->InstantPreviewFocused(); | 741 browser_->InstantPreviewFocused(); |
| 689 #endif | 742 #endif |
| 690 } | 743 } |
| 691 | 744 |
| 745 void InstantController::ResetClient() { | |
| 746 if (search_mode_.is_origin_search()) { | |
| 747 content::WebContents* contents = | |
| 748 browser_->GetActiveTabContents()->web_contents(); | |
| 749 if (!client_ || contents != client_->contents()) { | |
| 750 client_.reset(new InstantClient(this, contents)); | |
| 751 client_->DetermineIfPageSupportsInstant(); | |
| 752 } | |
| 753 // We are now using |client_| instead of |loader_|, so Hide() the latter. We | |
| 754 // want to call Hide(true) to clear old query results on the |loader_|, but | |
| 755 // that would also clear |last_full_text_|, which is bad if the user then | |
| 756 // immediately tries to commit the query on |client_|. | |
| 757 Hide(!search_mode_.is_search_suggestions()); | |
| 758 } else { | |
| 759 client_.reset(); | |
| 760 } | |
| 761 } | |
| 762 | |
| 692 bool InstantController::ResetLoader(const TemplateURL* template_url, | 763 bool InstantController::ResetLoader(const TemplateURL* template_url, |
| 693 const TabContents* active_tab) { | 764 const TabContents* active_tab) { |
| 694 std::string instant_url; | 765 std::string instant_url; |
| 695 if (!GetInstantURL(template_url, &instant_url)) | 766 if (!GetInstantURL(template_url, &instant_url)) |
| 696 return false; | 767 return false; |
| 697 | 768 |
| 698 if (GetPreviewContents() && loader_->instant_url() != instant_url) | 769 if (loader_ && loader_->instant_url() != instant_url) |
| 699 DeleteLoader(); | 770 DeleteLoader(); |
| 700 | 771 |
| 701 if (!GetPreviewContents()) { | 772 if (!loader_) { |
| 702 loader_.reset(new InstantLoader(this, instant_url, active_tab)); | 773 loader_.reset(new InstantLoader(this, instant_url, active_tab)); |
| 703 loader_->Init(); | 774 loader_->Init(); |
| 704 | 775 |
| 705 // Ensure the searchbox API has the correct theme-related info and context. | 776 // Ensure the searchbox API has the correct theme-related info and context. |
| 706 if (extended_enabled_) { | 777 if (extended_enabled_) { |
| 707 browser_->UpdateThemeInfoForPreview(); | 778 browser_->UpdateThemeInfoForPreview(); |
| 708 loader_->SearchModeChanged(search_mode_); | 779 loader_->SearchModeChanged(search_mode_); |
| 709 } | 780 } |
| 710 | 781 |
| 711 // Reset the loader timer. | 782 // Reset the loader timer. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 728 TemplateURLServiceFactory::GetForProfile(active_tab->profile())-> | 799 TemplateURLServiceFactory::GetForProfile(active_tab->profile())-> |
| 729 GetDefaultSearchProvider(); | 800 GetDefaultSearchProvider(); |
| 730 | 801 |
| 731 return ResetLoader(template_url, active_tab); | 802 return ResetLoader(template_url, active_tab); |
| 732 } | 803 } |
| 733 | 804 |
| 734 void InstantController::OnStaleLoader() { | 805 void InstantController::OnStaleLoader() { |
| 735 // If the preview is showing or the omnibox has focus, don't delete the | 806 // If the preview is showing or the omnibox has focus, don't delete the |
| 736 // loader. It will get refreshed the next time the preview is hidden or the | 807 // loader. It will get refreshed the next time the preview is hidden or the |
| 737 // omnibox loses focus. | 808 // omnibox loses focus. |
| 738 if (!stale_loader_timer_.IsRunning() && !is_omnibox_focused_ && | 809 if (!stale_loader_timer_.IsRunning() && !is_omnibox_focused_ && !client_ && |
| 739 model_.mode().is_default()) { | 810 model_.mode().is_default()) { |
| 740 DeleteLoader(); | 811 DeleteLoader(); |
| 741 CreateDefaultLoader(); | 812 CreateDefaultLoader(); |
| 742 } | 813 } |
| 743 } | 814 } |
| 744 | 815 |
| 745 void InstantController::DeleteLoader() { | 816 void InstantController::DeleteLoader() { |
| 746 // Clear all state, except |last_transition_type_| as it's used during commit. | 817 // Clear all state, except |last_transition_type_| as it's used during commit. |
| 747 last_user_text_.clear(); | 818 last_user_text_.clear(); |
| 748 last_full_text_.clear(); | 819 last_full_text_.clear(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 789 last_user_text_.clear(); | 860 last_user_text_.clear(); |
| 790 last_full_text_.clear(); | 861 last_full_text_.clear(); |
| 791 } | 862 } |
| 792 | 863 |
| 793 OnStaleLoader(); | 864 OnStaleLoader(); |
| 794 } | 865 } |
| 795 | 866 |
| 796 void InstantController::Show(InstantShownReason reason, | 867 void InstantController::Show(InstantShownReason reason, |
| 797 int height, | 868 int height, |
| 798 InstantSizeUnits units) { | 869 InstantSizeUnits units) { |
| 870 if (client_ == CurrentClient()) | |
| 871 return; | |
| 872 | |
| 799 DVLOG(1) << "Show: reason=" << reason << " height=" << height << " units=" | 873 DVLOG(1) << "Show: reason=" << reason << " height=" << height << " units=" |
| 800 << units; | 874 << units; |
| 801 | 875 |
| 802 // Must be on NTP to show NTP content. | 876 // Must be on NTP to show NTP content. |
| 803 if (reason == INSTANT_SHOWN_CUSTOM_NTP_CONTENT && !search_mode_.is_ntp()) | 877 if (reason == INSTANT_SHOWN_CUSTOM_NTP_CONTENT && !search_mode_.is_ntp()) |
| 804 return; | 878 return; |
| 805 | 879 |
| 806 // Must have updated omnibox after most recent Hide() to show suggestions. | 880 // Must have updated omnibox after most recent Hide() to show suggestions. |
| 807 if (reason == INSTANT_SHOWN_QUERY_SUGGESTIONS && | 881 if (reason == INSTANT_SHOWN_QUERY_SUGGESTIONS && |
| 808 !search_mode_.is_search_suggestions()) | 882 !search_mode_.is_search_suggestions()) |
| 809 return; | 883 return; |
| 810 | 884 |
| 811 // If the preview is being shown because of the first set of suggestions to | 885 // If the preview is being shown because of the first set of suggestions to |
| 812 // arrive for this query editing session, record a histogram value. | 886 // arrive for this query editing session, record a histogram value. |
| 813 if (!first_interaction_time_.is_null() && model_.mode().is_default()) { | 887 if (!first_interaction_time_.is_null() && model_.mode().is_default()) { |
| 814 base::TimeDelta delta = base::Time::Now() - first_interaction_time_; | 888 base::TimeDelta delta = base::Time::Now() - first_interaction_time_; |
| 815 UMA_HISTOGRAM_TIMES("Instant.TimeToFirstShow", delta); | 889 UMA_HISTOGRAM_TIMES("Instant.TimeToFirstShow", delta); |
| 816 } | 890 } |
| 817 | 891 |
| 818 model_.SetPreviewState(search_mode_, height, units); | 892 model_.SetPreviewState(search_mode_, height, units); |
| 819 } | 893 } |
| 820 | 894 |
| 821 void InstantController::SendBoundsToPage() { | 895 void InstantController::SendBoundsToPage() { |
| 822 if (last_omnibox_bounds_ == omnibox_bounds_ || | 896 if (last_omnibox_bounds_ == omnibox_bounds_ || !loader_ || |
| 823 !GetPreviewContents() || loader_->IsPointerDownFromActivate()) | 897 loader_->IsPointerDownFromActivate()) |
| 824 return; | 898 return; |
| 825 | 899 |
| 826 last_omnibox_bounds_ = omnibox_bounds_; | 900 last_omnibox_bounds_ = omnibox_bounds_; |
| 827 gfx::Rect preview_bounds = browser_->GetInstantBounds(); | 901 gfx::Rect preview_bounds = browser_->GetInstantBounds(); |
| 828 gfx::Rect intersection = gfx::IntersectRects(omnibox_bounds_, preview_bounds); | 902 gfx::Rect intersection = gfx::IntersectRects(omnibox_bounds_, preview_bounds); |
| 829 | 903 |
| 830 // Translate into window coordinates. | 904 // Translate into window coordinates. |
| 831 if (!intersection.IsEmpty()) { | 905 if (!intersection.IsEmpty()) { |
| 832 intersection.Offset(-preview_bounds.origin().x(), | 906 intersection.Offset(-preview_bounds.origin().x(), |
| 833 -preview_bounds.origin().y()); | 907 -preview_bounds.origin().y()); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 889 } | 963 } |
| 890 | 964 |
| 891 std::map<std::string, int>::const_iterator iter = | 965 std::map<std::string, int>::const_iterator iter = |
| 892 blacklisted_urls_.find(*instant_url); | 966 blacklisted_urls_.find(*instant_url); |
| 893 if (iter != blacklisted_urls_.end() && | 967 if (iter != blacklisted_urls_.end() && |
| 894 iter->second > kMaxInstantSupportFailures) | 968 iter->second > kMaxInstantSupportFailures) |
| 895 return false; | 969 return false; |
| 896 | 970 |
| 897 return true; | 971 return true; |
| 898 } | 972 } |
| 973 | |
| 974 InstantClient* InstantController::CurrentClient() const { | |
| 975 return client_ ? client_.get() : loader_.get(); | |
| 976 } | |
| OLD | NEW |