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/stringprintf.h" | 10 #include "base/stringprintf.h" |
11 #include "base/utf_string_conversions.h" | 11 #include "base/utf_string_conversions.h" |
12 #include "chrome/browser/autocomplete/autocomplete_provider.h" | 12 #include "chrome/browser/autocomplete/autocomplete_provider.h" |
13 #include "chrome/browser/google/google_util.h" | 13 #include "chrome/browser/google/google_util.h" |
14 #include "chrome/browser/history/history_service.h" | 14 #include "chrome/browser/history/history_service.h" |
15 #include "chrome/browser/history/history_service_factory.h" | 15 #include "chrome/browser/history/history_service_factory.h" |
16 #include "chrome/browser/history/history_tab_helper.h" | 16 #include "chrome/browser/history/history_tab_helper.h" |
17 #include "chrome/browser/instant/instant_loader.h" | 17 #include "chrome/browser/instant/instant_ntp.h" |
| 18 #include "chrome/browser/instant/instant_overlay.h" |
18 #include "chrome/browser/instant/instant_tab.h" | 19 #include "chrome/browser/instant/instant_tab.h" |
19 #include "chrome/browser/platform_util.h" | 20 #include "chrome/browser/platform_util.h" |
20 #include "chrome/browser/search_engines/template_url_service.h" | 21 #include "chrome/browser/search_engines/template_url_service.h" |
21 #include "chrome/browser/search_engines/template_url_service_factory.h" | 22 #include "chrome/browser/search_engines/template_url_service_factory.h" |
22 #include "chrome/browser/ui/browser_instant_controller.h" | 23 #include "chrome/browser/ui/browser_instant_controller.h" |
23 #include "chrome/browser/ui/search/search_tab_helper.h" | 24 #include "chrome/browser/ui/search/search_tab_helper.h" |
24 #include "chrome/common/chrome_notification_types.h" | 25 #include "chrome/common/chrome_notification_types.h" |
25 #include "chrome/common/chrome_switches.h" | 26 #include "chrome/common/chrome_switches.h" |
| 27 #include "chrome/common/url_constants.h" |
26 #include "content/public/browser/navigation_entry.h" | 28 #include "content/public/browser/navigation_entry.h" |
27 #include "content/public/browser/notification_service.h" | 29 #include "content/public/browser/notification_service.h" |
28 #include "content/public/browser/render_widget_host_view.h" | 30 #include "content/public/browser/render_widget_host_view.h" |
29 #include "content/public/browser/web_contents.h" | 31 #include "content/public/browser/web_contents.h" |
30 #include "net/base/escape.h" | 32 #include "net/base/escape.h" |
31 #include "third_party/icu/public/common/unicode/normalizer2.h" | 33 #include "third_party/icu/public/common/unicode/normalizer2.h" |
32 | 34 |
33 #if defined(TOOLKIT_VIEWS) | 35 #if defined(TOOLKIT_VIEWS) |
34 #include "ui/views/widget/widget.h" | 36 #include "ui/views/widget/widget.h" |
35 #endif | 37 #endif |
36 | 38 |
37 namespace { | 39 namespace { |
38 | 40 |
39 // An artificial delay (in milliseconds) we introduce before telling the Instant | 41 // An artificial delay (in milliseconds) we introduce before telling the Instant |
40 // page about the new omnibox bounds, in cases where the bounds shrink. This is | 42 // page about the new omnibox bounds, in cases where the bounds shrink. This is |
41 // to avoid the page jumping up/down very fast in response to bounds changes. | 43 // to avoid the page jumping up/down very fast in response to bounds changes. |
42 const int kUpdateBoundsDelayMS = 1000; | 44 const int kUpdateBoundsDelayMS = 1000; |
43 | 45 |
44 // The maximum number of times we'll load a non-Instant-supporting search engine | 46 // The maximum number of times we'll load a non-Instant-supporting search engine |
45 // before we give up and blacklist it for the rest of the browsing session. | 47 // before we give up and blacklist it for the rest of the browsing session. |
46 const int kMaxInstantSupportFailures = 10; | 48 const int kMaxInstantSupportFailures = 10; |
47 | 49 |
48 // If an Instant page has not been used in these many milliseconds, it is | |
49 // reloaded so that the page does not become stale. | |
50 const int kStaleLoaderTimeoutMS = 3 * 3600 * 1000; | |
51 | |
52 // For reporting events of interest. | 50 // For reporting events of interest. |
53 enum InstantControllerEvent { | 51 enum InstantControllerEvent { |
54 INSTANT_CONTROLLER_EVENT_URL_ADDED_TO_BLACKLIST = 0, | 52 INSTANT_CONTROLLER_EVENT_URL_ADDED_TO_BLACKLIST = 0, |
55 INSTANT_CONTROLLER_EVENT_URL_REMOVED_FROM_BLACKLIST = 1, | 53 INSTANT_CONTROLLER_EVENT_URL_REMOVED_FROM_BLACKLIST = 1, |
56 INSTANT_CONTROLLER_EVENT_URL_BLOCKED_BY_BLACKLIST = 2, | 54 INSTANT_CONTROLLER_EVENT_URL_BLOCKED_BY_BLACKLIST = 2, |
57 INSTANT_CONTROLLER_EVENT_MAX = 3, | 55 INSTANT_CONTROLLER_EVENT_MAX = 3, |
58 }; | 56 }; |
59 | 57 |
60 void RecordEventHistogram(InstantControllerEvent event) { | 58 void RecordEventHistogram(InstantControllerEvent event) { |
61 UMA_HISTOGRAM_ENUMERATION("Instant.InstantControllerEvent", | 59 UMA_HISTOGRAM_ENUMERATION("Instant.InstantControllerEvent", |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
153 return true; | 151 return true; |
154 } | 152 } |
155 | 153 |
156 return false; | 154 return false; |
157 } | 155 } |
158 | 156 |
159 bool IsFullHeight(const InstantModel& model) { | 157 bool IsFullHeight(const InstantModel& model) { |
160 return model.height() == 100 && model.height_units() == INSTANT_SIZE_PERCENT; | 158 return model.height() == 100 && model.height_units() == INSTANT_SIZE_PERCENT; |
161 } | 159 } |
162 | 160 |
| 161 bool IsContentsFrom(const InstantPage* page, |
| 162 const content::WebContents* contents) { |
| 163 return page && (page->contents() == contents); |
| 164 } |
| 165 |
163 } // namespace | 166 } // namespace |
164 | 167 |
165 // static | 168 // static |
166 const char* InstantController::kLocalOmniboxPopupURL = | 169 const char* InstantController::kLocalOmniboxPopupURL = |
167 "chrome://local-omnibox-popup/local-omnibox-popup.html"; | 170 "chrome://local-omnibox-popup/local-omnibox-popup.html"; |
168 | 171 |
169 InstantController::InstantController(chrome::BrowserInstantController* browser, | 172 InstantController::InstantController(chrome::BrowserInstantController* browser, |
170 bool extended_enabled) | 173 bool extended_enabled) |
171 : browser_(browser), | 174 : browser_(browser), |
172 extended_enabled_(extended_enabled), | 175 extended_enabled_(extended_enabled), |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 is_keyword_search)); | 213 is_keyword_search)); |
211 | 214 |
212 // TODO(dhollowa): Complete keyword match UI. For now just hide suggestions. | 215 // TODO(dhollowa): Complete keyword match UI. For now just hide suggestions. |
213 // http://crbug.com/153932. Note, this early escape is happens prior to the | 216 // http://crbug.com/153932. Note, this early escape is happens prior to the |
214 // DCHECKs below because |user_text| and |full_text| have different semantics | 217 // DCHECKs below because |user_text| and |full_text| have different semantics |
215 // when keyword search is in effect. | 218 // when keyword search is in effect. |
216 if (is_keyword_search) { | 219 if (is_keyword_search) { |
217 if (instant_tab_) | 220 if (instant_tab_) |
218 instant_tab_->Update(string16(), 0, 0, true); | 221 instant_tab_->Update(string16(), 0, 0, true); |
219 else | 222 else |
220 HideLoader(); | 223 HideOverlay(); |
221 last_match_was_search_ = false; | 224 last_match_was_search_ = false; |
222 return false; | 225 return false; |
223 } | 226 } |
224 | 227 |
225 // If the popup is open, the user has to be typing. | 228 // If the popup is open, the user has to be typing. |
226 DCHECK(!omnibox_popup_is_open || user_input_in_progress); | 229 DCHECK(!omnibox_popup_is_open || user_input_in_progress); |
227 | 230 |
228 // If the popup is closed, there should be no inline autocompletion. | 231 // If the popup is closed, there should be no inline autocompletion. |
229 DCHECK(omnibox_popup_is_open || user_text.empty() || user_text == full_text) | 232 DCHECK(omnibox_popup_is_open || user_text.empty() || user_text == full_text) |
230 << user_text << "|" << full_text; | 233 << user_text << "|" << full_text; |
231 | 234 |
232 // If there's no text in the omnibox, the user can't have typed any. | 235 // If there's no text in the omnibox, the user can't have typed any. |
233 DCHECK(!full_text.empty() || user_text.empty()) << user_text; | 236 DCHECK(!full_text.empty() || user_text.empty()) << user_text; |
234 | 237 |
235 // If the user isn't typing, and the popup is closed, there can't be any | 238 // If the user isn't typing, and the popup is closed, there can't be any |
236 // user-typed text. | 239 // user-typed text. |
237 DCHECK(user_input_in_progress || omnibox_popup_is_open || user_text.empty()) | 240 DCHECK(user_input_in_progress || omnibox_popup_is_open || user_text.empty()) |
238 << user_text; | 241 << user_text; |
239 | 242 |
240 // The preview is being clicked and will commit soon. Don't change anything. | 243 // The preview is being clicked and will commit soon. Don't change anything. |
241 // TODO(sreeram): Add a browser test for this. | 244 // TODO(sreeram): Add a browser test for this. |
242 if (loader_ && loader_->is_pointer_down_from_activate()) | 245 if (overlay_ && overlay_->is_pointer_down_from_activate()) |
243 return false; | 246 return false; |
244 | 247 |
245 // In non-extended mode, SearchModeChanged() is never called, so fake it. The | 248 // In non-extended mode, SearchModeChanged() is never called, so fake it. The |
246 // mode is set to "disallow suggestions" here, so that if one of the early | 249 // mode is set to "disallow suggestions" here, so that if one of the early |
247 // "return false" conditions is hit, suggestions will be disallowed. If the | 250 // "return false" conditions is hit, suggestions will be disallowed. If the |
248 // query is sent to the loader, the mode is set to "allow" further below. | 251 // query is sent to the overlay, the mode is set to "allow" further below. |
249 if (!extended_enabled_) | 252 if (!extended_enabled_) |
250 search_mode_.mode = chrome::search::Mode::MODE_DEFAULT; | 253 search_mode_.mode = chrome::search::Mode::MODE_DEFAULT; |
251 | 254 |
252 last_match_was_search_ = AutocompleteMatch::IsSearchType(match.type) && | 255 last_match_was_search_ = AutocompleteMatch::IsSearchType(match.type) && |
253 !user_text.empty(); | 256 !user_text.empty(); |
254 | 257 |
255 // In non extended mode, Instant is disabled for URLs and keyword mode. | 258 // In non extended mode, Instant is disabled for URLs and keyword mode. |
256 if (!extended_enabled_ && | 259 if (!extended_enabled_ && |
257 (!last_match_was_search_ || | 260 (!last_match_was_search_ || |
258 match.type == AutocompleteMatch::SEARCH_OTHER_ENGINE)) { | 261 match.type == AutocompleteMatch::SEARCH_OTHER_ENGINE)) { |
259 HideLoader(); | 262 HideOverlay(); |
260 return false; | 263 return false; |
261 } | 264 } |
262 | 265 |
263 // If we have an |instant_tab_| use it, else ensure we have a loader that is | 266 // If we have an |instant_tab_| use it, else ensure we have a overlay that is |
264 // current or is using local preview. | 267 // current or is using local preview. |
265 if (!instant_tab_ && !(loader_ && loader_->IsUsingLocalPreview()) && | 268 if (!instant_tab_ && !(overlay_ && overlay_->IsUsingLocalPreview()) && |
266 !EnsureLoaderIsCurrent(false)) { | 269 !EnsureOverlayIsCurrent(false)) { |
267 HideLoader(); | 270 HideOverlay(); |
268 return false; | 271 return false; |
269 } | 272 } |
270 | 273 |
271 if (extended_enabled_) { | 274 if (extended_enabled_) { |
272 if (!omnibox_popup_is_open) { | 275 if (!omnibox_popup_is_open) { |
273 if (!user_input_in_progress) { | 276 if (!user_input_in_progress) { |
274 // If the user isn't typing and the omnibox popup is closed, it means a | 277 // If the user isn't typing and the omnibox popup is closed, it means a |
275 // regular navigation, tab-switch or the user hitting Escape. | 278 // regular navigation, tab-switch or the user hitting Escape. |
276 if (instant_tab_) { | 279 if (instant_tab_) { |
277 // The user is on a search results page. It may be showing results for | 280 // The user is on a search results page. It may be showing results for |
278 // a partial query the user typed before they hit Escape. Send the | 281 // a partial query the user typed before they hit Escape. Send the |
279 // omnibox text to the page to restore the original results. | 282 // omnibox text to the page to restore the original results. |
280 // | 283 // |
281 // In a tab switch, |instant_tab_| won't have updated yet, so it may | 284 // In a tab switch, |instant_tab_| won't have updated yet, so it may |
282 // be pointing to the previous tab (which was a search results page). | 285 // be pointing to the previous tab (which was a search results page). |
283 // Ensure we don't send the omnibox text to a random webpage (the new | 286 // Ensure we don't send the omnibox text to a random webpage (the new |
284 // tab), by comparing the old and new WebContents. | 287 // tab), by comparing the old and new WebContents. |
285 if (escape_pressed && | 288 if (escape_pressed && |
286 instant_tab_->contents() == browser_->GetActiveWebContents()) { | 289 instant_tab_->contents() == browser_->GetActiveWebContents()) { |
287 instant_tab_->Submit(full_text); | 290 instant_tab_->Submit(full_text); |
288 } | 291 } |
289 } else if (!full_text.empty()) { | 292 } else if (!full_text.empty()) { |
290 // If |full_text| is empty, the user is on the NTP. The preview may | 293 // If |full_text| is empty, the user is on the NTP. The preview may |
291 // be showing custom NTP content; hide only if that's not the case. | 294 // be showing custom NTP content; hide only if that's not the case. |
292 HideLoader(); | 295 HideOverlay(); |
293 } | 296 } |
294 } else if (full_text.empty()) { | 297 } else if (full_text.empty()) { |
295 // The user is typing, and backspaced away all omnibox text. Clear | 298 // The user is typing, and backspaced away all omnibox text. Clear |
296 // |last_omnibox_text_| so that we don't attempt to set suggestions. | 299 // |last_omnibox_text_| so that we don't attempt to set suggestions. |
297 last_omnibox_text_.clear(); | 300 last_omnibox_text_.clear(); |
298 last_suggestion_ = InstantSuggestion(); | 301 last_suggestion_ = InstantSuggestion(); |
299 if (instant_tab_) { | 302 if (instant_tab_) { |
300 // On a search results page, tell it to clear old results. | 303 // On a search results page, tell it to clear old results. |
301 instant_tab_->Update(string16(), 0, 0, true); | 304 instant_tab_->Update(string16(), 0, 0, true); |
302 } else if (search_mode_.is_origin_ntp()) { | 305 } else if (search_mode_.is_origin_ntp()) { |
303 // On the NTP, tell the preview to clear old results. Don't hide the | 306 // On the NTP, tell the preview to clear old results. Don't hide the |
304 // preview so it can show a blank page or logo if it wants. | 307 // preview so it can show a blank page or logo if it wants. |
305 loader_->Update(string16(), 0, 0, true); | 308 overlay_->Update(string16(), 0, 0, true); |
306 } else { | 309 } else { |
307 HideLoader(); | 310 HideOverlay(); |
308 } | 311 } |
309 } else { | 312 } else { |
310 // The user switched to a tab with partial text already in the omnibox. | 313 // The user switched to a tab with partial text already in the omnibox. |
311 HideLoader(); | 314 HideOverlay(); |
312 | 315 |
313 // The new tab may or may not be a search results page; we don't know | 316 // The new tab may or may not be a search results page; we don't know |
314 // since SearchModeChanged() hasn't been called yet. If it later turns | 317 // since SearchModeChanged() hasn't been called yet. If it later turns |
315 // out to be, we should store |full_text| now, so that if the user hits | 318 // out to be, we should store |full_text| now, so that if the user hits |
316 // Enter, we'll send the correct query to instant_tab_->Submit(). If the | 319 // Enter, we'll send the correct query to instant_tab_->Submit(). If the |
317 // partial text is not a query (|last_match_was_search_| is false), we | 320 // partial text is not a query (|last_match_was_search_| is false), we |
318 // won't Submit(), so no need to worry about that. | 321 // won't Submit(), so no need to worry about that. |
319 last_omnibox_text_ = full_text; | 322 last_omnibox_text_ = full_text; |
320 last_suggestion_ = InstantSuggestion(); | 323 last_suggestion_ = InstantSuggestion(); |
321 } | 324 } |
322 return false; | 325 return false; |
323 } else if (full_text.empty()) { | 326 } else if (full_text.empty()) { |
324 // The user typed a solitary "?". Same as the backspace case above. | 327 // The user typed a solitary "?". Same as the backspace case above. |
325 last_omnibox_text_.clear(); | 328 last_omnibox_text_.clear(); |
326 last_suggestion_ = InstantSuggestion(); | 329 last_suggestion_ = InstantSuggestion(); |
327 if (instant_tab_) | 330 if (instant_tab_) |
328 instant_tab_->Update(string16(), 0, 0, true); | 331 instant_tab_->Update(string16(), 0, 0, true); |
329 else if (search_mode_.is_origin_ntp()) | 332 else if (search_mode_.is_origin_ntp()) |
330 loader_->Update(string16(), 0, 0, true); | 333 overlay_->Update(string16(), 0, 0, true); |
331 else | 334 else |
332 HideLoader(); | 335 HideOverlay(); |
333 return false; | 336 return false; |
334 } | 337 } |
335 } else if (!omnibox_popup_is_open || full_text.empty()) { | 338 } else if (!omnibox_popup_is_open || full_text.empty()) { |
336 // In the non-extended case, hide the preview as long as the user isn't | 339 // In the non-extended case, hide the preview as long as the user isn't |
337 // actively typing a non-empty query. | 340 // actively typing a non-empty query. |
338 HideLoader(); | 341 HideOverlay(); |
339 return false; | 342 return false; |
340 } | 343 } |
341 | 344 |
342 last_omnibox_text_has_inline_autocompletion_ = user_text != full_text; | 345 last_omnibox_text_has_inline_autocompletion_ = user_text != full_text; |
343 | 346 |
344 // If the user continues typing the same query as the suggested text is | 347 // If the user continues typing the same query as the suggested text is |
345 // showing, reuse the suggestion (but only for INSTANT_COMPLETE_NEVER). | 348 // showing, reuse the suggestion (but only for INSTANT_COMPLETE_NEVER). |
346 bool reused_suggestion = false; | 349 bool reused_suggestion = false; |
347 if (last_suggestion_.behavior == INSTANT_COMPLETE_NEVER && | 350 if (last_suggestion_.behavior == INSTANT_COMPLETE_NEVER && |
348 !last_omnibox_text_has_inline_autocompletion_) { | 351 !last_omnibox_text_has_inline_autocompletion_) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 | 383 |
381 if (instant_tab_) { | 384 if (instant_tab_) { |
382 instant_tab_->Update(user_text, selection_start, selection_end, verbatim); | 385 instant_tab_->Update(user_text, selection_start, selection_end, verbatim); |
383 } else { | 386 } else { |
384 if (first_interaction_time_.is_null()) | 387 if (first_interaction_time_.is_null()) |
385 first_interaction_time_ = base::Time::Now(); | 388 first_interaction_time_ = base::Time::Now(); |
386 allow_preview_to_show_search_suggestions_ = true; | 389 allow_preview_to_show_search_suggestions_ = true; |
387 | 390 |
388 // For extended mode, if the loader is not ready at this point, switch over | 391 // For extended mode, if the loader is not ready at this point, switch over |
389 // to a backup loader. | 392 // to a backup loader. |
390 if (extended_enabled_ && !loader_->supports_instant() && | 393 if (extended_enabled_ && !overlay_->supports_instant() && |
391 !loader_->IsUsingLocalPreview() && browser_->GetActiveWebContents()) { | 394 !overlay_->IsUsingLocalPreview() && browser_->GetActiveWebContents()) { |
392 CreateLoader(kLocalOmniboxPopupURL, browser_->GetActiveWebContents()); | 395 CreateOverlay(kLocalOmniboxPopupURL, browser_->GetActiveWebContents()); |
393 } | 396 } |
394 | 397 |
395 loader_->Update(extended_enabled_ ? user_text : full_text, | 398 overlay_->Update(extended_enabled_ ? user_text : full_text, |
396 selection_start, selection_end, verbatim); | 399 selection_start, selection_end, verbatim); |
397 } | 400 } |
398 | 401 |
399 content::NotificationService::current()->Notify( | 402 content::NotificationService::current()->Notify( |
400 chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, | 403 chrome::NOTIFICATION_INSTANT_CONTROLLER_UPDATED, |
401 content::Source<InstantController>(this), | 404 content::Source<InstantController>(this), |
402 content::NotificationService::NoDetails()); | 405 content::NotificationService::NoDetails()); |
403 | 406 |
404 // We don't have new suggestions yet, but we can either reuse the existing | 407 // We don't have new suggestions yet, but we can either reuse the existing |
405 // suggestion or reset the existing "gray text". | 408 // suggestion or reset the existing "gray text". |
406 browser_->SetInstantSuggestion(last_suggestion_); | 409 browser_->SetInstantSuggestion(last_suggestion_); |
407 | 410 |
408 return true; | 411 return true; |
409 } | 412 } |
410 | 413 |
| 414 scoped_ptr<content::WebContents> InstantController::ReleaseNTPContents() { |
| 415 if (!extended_enabled_ || !ntp_) |
| 416 return scoped_ptr<content::WebContents>(NULL); |
| 417 |
| 418 LOG_INSTANT_DEBUG_EVENT(this, "ReleaseNTPContents"); |
| 419 |
| 420 scoped_ptr<content::WebContents> ntp_contents = ntp_->ReleaseContents(); |
| 421 ntp_.reset(); |
| 422 ResetNTP(); |
| 423 return ntp_contents.Pass(); |
| 424 } |
| 425 |
411 // TODO(tonyg): This method only fires when the omnibox bounds change. It also | 426 // TODO(tonyg): This method only fires when the omnibox bounds change. It also |
412 // needs to fire when the preview bounds change (e.g.: open/close info bar). | 427 // needs to fire when the preview bounds change (e.g.: open/close info bar). |
413 void InstantController::SetPopupBounds(const gfx::Rect& bounds) { | 428 void InstantController::SetPopupBounds(const gfx::Rect& bounds) { |
414 if (!extended_enabled_ && !instant_enabled_) | 429 if (!extended_enabled_ && !instant_enabled_) |
415 return; | 430 return; |
416 | 431 |
417 if (popup_bounds_ == bounds) | 432 if (popup_bounds_ == bounds) |
418 return; | 433 return; |
419 | 434 |
420 popup_bounds_ = bounds; | 435 popup_bounds_ = bounds; |
421 if (popup_bounds_.height() > last_popup_bounds_.height()) { | 436 if (popup_bounds_.height() > last_popup_bounds_.height()) { |
422 update_bounds_timer_.Stop(); | 437 update_bounds_timer_.Stop(); |
423 SendPopupBoundsToPage(); | 438 SendPopupBoundsToPage(); |
424 } else if (!update_bounds_timer_.IsRunning()) { | 439 } else if (!update_bounds_timer_.IsRunning()) { |
425 update_bounds_timer_.Start(FROM_HERE, | 440 update_bounds_timer_.Start(FROM_HERE, |
426 base::TimeDelta::FromMilliseconds(kUpdateBoundsDelayMS), this, | 441 base::TimeDelta::FromMilliseconds(kUpdateBoundsDelayMS), this, |
427 &InstantController::SendPopupBoundsToPage); | 442 &InstantController::SendPopupBoundsToPage); |
428 } | 443 } |
429 } | 444 } |
430 | 445 |
431 void InstantController::SetMarginSize(int start, int end) { | 446 void InstantController::SetMarginSize(int start, int end) { |
432 if (!extended_enabled_ || (start_margin_ == start && end_margin_ == end)) | 447 if (!extended_enabled_ || (start_margin_ == start && end_margin_ == end)) |
433 return; | 448 return; |
434 | 449 |
435 start_margin_ = start; | 450 start_margin_ = start; |
436 end_margin_ = end; | 451 end_margin_ = end; |
437 if (loader_) | 452 if (overlay_) |
438 loader_->SetMarginSize(start_margin_, end_margin_); | 453 overlay_->SetMarginSize(start_margin_, end_margin_); |
| 454 if (ntp_) |
| 455 ntp_->SetMarginSize(start_margin_, end_margin_); |
439 if (instant_tab_) | 456 if (instant_tab_) |
440 instant_tab_->SetMarginSize(start_margin_, end_margin_); | 457 instant_tab_->SetMarginSize(start_margin_, end_margin_); |
441 } | 458 } |
442 | 459 |
443 void InstantController::HandleAutocompleteResults( | 460 void InstantController::HandleAutocompleteResults( |
444 const std::vector<AutocompleteProvider*>& providers) { | 461 const std::vector<AutocompleteProvider*>& providers) { |
445 if (!extended_enabled_) | 462 if (!extended_enabled_) |
446 return; | 463 return; |
447 | 464 |
448 if (!instant_tab_ && !loader_) | 465 if (!instant_tab_ && !overlay_) |
449 return; | 466 return; |
450 | 467 |
451 DVLOG(1) << "AutocompleteResults:"; | 468 DVLOG(1) << "AutocompleteResults:"; |
452 std::vector<InstantAutocompleteResult> results; | 469 std::vector<InstantAutocompleteResult> results; |
453 for (ACProviders::const_iterator provider = providers.begin(); | 470 for (ACProviders::const_iterator provider = providers.begin(); |
454 provider != providers.end(); ++provider) { | 471 provider != providers.end(); ++provider) { |
455 for (ACMatches::const_iterator match = (*provider)->matches().begin(); | 472 for (ACMatches::const_iterator match = (*provider)->matches().begin(); |
456 match != (*provider)->matches().end(); ++match) { | 473 match != (*provider)->matches().end(); ++match) { |
457 InstantAutocompleteResult result; | 474 InstantAutocompleteResult result; |
458 result.provider = UTF8ToUTF16((*provider)->GetName()); | 475 result.provider = UTF8ToUTF16((*provider)->GetName()); |
459 result.type = UTF8ToUTF16(AutocompleteMatch::TypeToString(match->type)); | 476 result.type = UTF8ToUTF16(AutocompleteMatch::TypeToString(match->type)); |
460 result.description = match->description; | 477 result.description = match->description; |
461 result.destination_url = UTF8ToUTF16(match->destination_url.spec()); | 478 result.destination_url = UTF8ToUTF16(match->destination_url.spec()); |
462 result.transition = match->transition; | 479 result.transition = match->transition; |
463 result.relevance = match->relevance; | 480 result.relevance = match->relevance; |
464 DVLOG(1) << " " << result.relevance << " " << result.type << " " | 481 DVLOG(1) << " " << result.relevance << " " << result.type << " " |
465 << result.provider << " " << result.destination_url << " '" | 482 << result.provider << " " << result.destination_url << " '" |
466 << result.description << "' " << result.transition; | 483 << result.description << "' " << result.transition; |
467 results.push_back(result); | 484 results.push_back(result); |
468 } | 485 } |
469 } | 486 } |
470 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 487 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
471 "HandleAutocompleteResults: total_results=%d", | 488 "HandleAutocompleteResults: total_results=%d", |
472 static_cast<int>(results.size()))); | 489 static_cast<int>(results.size()))); |
473 | 490 |
474 if (instant_tab_) | 491 if (instant_tab_) |
475 instant_tab_->SendAutocompleteResults(results); | 492 instant_tab_->SendAutocompleteResults(results); |
476 else | 493 else |
477 loader_->SendAutocompleteResults(results); | 494 overlay_->SendAutocompleteResults(results); |
478 } | 495 } |
479 | 496 |
480 bool InstantController::OnUpOrDownKeyPressed(int count) { | 497 bool InstantController::OnUpOrDownKeyPressed(int count) { |
481 if (!extended_enabled_) | 498 if (!extended_enabled_) |
482 return false; | 499 return false; |
483 | 500 |
484 if (!instant_tab_ && !loader_) | 501 if (!instant_tab_ && !overlay_) |
485 return false; | 502 return false; |
486 | 503 |
487 if (instant_tab_) | 504 if (instant_tab_) |
488 instant_tab_->UpOrDownKeyPressed(count); | 505 instant_tab_->UpOrDownKeyPressed(count); |
489 else | 506 else |
490 loader_->UpOrDownKeyPressed(count); | 507 overlay_->UpOrDownKeyPressed(count); |
491 | 508 |
492 return true; | 509 return true; |
493 } | 510 } |
494 | 511 |
495 content::WebContents* InstantController::GetPreviewContents() const { | 512 content::WebContents* InstantController::GetPreviewContents() const { |
496 return loader_ ? loader_->contents() : NULL; | 513 return overlay_ ? overlay_->contents() : NULL; |
497 } | 514 } |
498 | 515 |
499 bool InstantController::IsPreviewingSearchResults() const { | 516 bool InstantController::IsPreviewingSearchResults() const { |
500 return model_.mode().is_search_suggestions() && IsFullHeight(model_) && | 517 return model_.mode().is_search_suggestions() && IsFullHeight(model_) && |
501 (last_match_was_search_ || | 518 (last_match_was_search_ || |
502 last_suggestion_.behavior == INSTANT_COMPLETE_NEVER); | 519 last_suggestion_.behavior == INSTANT_COMPLETE_NEVER); |
503 } | 520 } |
504 | 521 |
505 bool InstantController::CommitIfPossible(InstantCommitType type) { | 522 bool InstantController::CommitIfPossible(InstantCommitType type) { |
506 if (!extended_enabled_ && !instant_enabled_) | 523 if (!extended_enabled_ && !instant_enabled_) |
(...skipping 16 matching lines...) Expand all Loading... |
523 return true; | 540 return true; |
524 } | 541 } |
525 return false; | 542 return false; |
526 } | 543 } |
527 | 544 |
528 if (!IsPreviewingSearchResults() && type != INSTANT_COMMIT_NAVIGATED) | 545 if (!IsPreviewingSearchResults() && type != INSTANT_COMMIT_NAVIGATED) |
529 return false; | 546 return false; |
530 | 547 |
531 // There may re-entrance here, from the call to browser_->CommitInstant below, | 548 // There may re-entrance here, from the call to browser_->CommitInstant below, |
532 // which can cause a TabDeactivated notification which gets back here. | 549 // which can cause a TabDeactivated notification which gets back here. |
533 // In this case, loader_->ReleaseContents() was called already. | 550 // In this case, overlay_->ReleaseContents() was called already. |
534 if (!GetPreviewContents()) | 551 if (!GetPreviewContents()) |
535 return false; | 552 return false; |
536 | 553 |
537 // Never commit the local omnibox. | 554 // Never commit the local omnibox. |
538 if (loader_->IsUsingLocalPreview()) | 555 if (overlay_->IsUsingLocalPreview()) |
539 return false; | 556 return false; |
540 | 557 |
541 if (type == INSTANT_COMMIT_FOCUS_LOST) | 558 if (type == INSTANT_COMMIT_FOCUS_LOST) |
542 loader_->Cancel(last_omnibox_text_); | 559 overlay_->Cancel(last_omnibox_text_); |
543 else if (type != INSTANT_COMMIT_NAVIGATED && | 560 else if (type != INSTANT_COMMIT_NAVIGATED && |
544 type != INSTANT_COMMIT_CLICKED_QUERY_SUGGESTION) | 561 type != INSTANT_COMMIT_CLICKED_QUERY_SUGGESTION) |
545 loader_->Submit(last_omnibox_text_); | 562 overlay_->Submit(last_omnibox_text_); |
546 | 563 |
547 content::WebContents* preview = loader_->ReleaseContents(); | 564 scoped_ptr<content::WebContents> preview = overlay_->ReleaseContents(); |
548 | 565 |
549 if (extended_enabled_) { | 566 if (extended_enabled_) { |
550 // Consider what's happening: | 567 // Consider what's happening: |
551 // 1. The user has typed a query in the omnibox and committed it (either | 568 // 1. The user has typed a query in the omnibox and committed it (either |
552 // by pressing Enter or clicking on the preview). | 569 // by pressing Enter or clicking on the preview). |
553 // 2. We commit the preview to the tab strip, and tell the page. | 570 // 2. We commit the preview to the tab strip, and tell the page. |
554 // 3. The page will update the URL hash fragment with the query terms. | 571 // 3. The page will update the URL hash fragment with the query terms. |
555 // After steps 1 and 3, the omnibox will show the query terms. However, if | 572 // After steps 1 and 3, the omnibox will show the query terms. However, if |
556 // the URL we are committing at step 2 doesn't already have query terms, it | 573 // the URL we are committing at step 2 doesn't already have query terms, it |
557 // will flash for a brief moment as a plain URL. So, avoid that flicker by | 574 // will flash for a brief moment as a plain URL. So, avoid that flicker by |
(...skipping 12 matching lines...) Expand all Loading... |
570 std::string query(UTF16ToUTF8(last_omnibox_text_)); | 587 std::string query(UTF16ToUTF8(last_omnibox_text_)); |
571 if (type != INSTANT_COMMIT_PRESSED_ENTER) { | 588 if (type != INSTANT_COMMIT_PRESSED_ENTER) { |
572 query += UTF16ToUTF8(last_suggestion_.text); | 589 query += UTF16ToUTF8(last_suggestion_.text); |
573 // Update |last_omnibox_text_| so that the controller commits the proper | 590 // Update |last_omnibox_text_| so that the controller commits the proper |
574 // query if the user focuses the omnibox and presses Enter. | 591 // query if the user focuses the omnibox and presses Enter. |
575 last_omnibox_text_ += last_suggestion_.text; | 592 last_omnibox_text_ += last_suggestion_.text; |
576 } | 593 } |
577 entry->SetVirtualURL(GURL( | 594 entry->SetVirtualURL(GURL( |
578 url + "#q=" + | 595 url + "#q=" + |
579 net::EscapeQueryParamValue(query, true))); | 596 net::EscapeQueryParamValue(query, true))); |
580 chrome::search::SearchTabHelper::FromWebContents(preview)-> | 597 chrome::search::SearchTabHelper::FromWebContents(preview.get())-> |
581 NavigationEntryUpdated(); | 598 NavigationEntryUpdated(); |
582 } | 599 } |
583 } | 600 } |
584 | 601 |
585 // If the preview page has navigated since the last Update(), we need to add | 602 // If the preview page has navigated since the last Update(), we need to add |
586 // the navigation to history ourselves. Else, the page will navigate after | 603 // the navigation to history ourselves. Else, the page will navigate after |
587 // commit, and it will be added to history in the usual manner. | 604 // commit, and it will be added to history in the usual manner. |
588 const history::HistoryAddPageArgs& last_navigation = | 605 const history::HistoryAddPageArgs& last_navigation = |
589 loader_->last_navigation(); | 606 overlay_->last_navigation(); |
590 if (!last_navigation.url.is_empty()) { | 607 if (!last_navigation.url.is_empty()) { |
591 content::NavigationEntry* entry = preview->GetController().GetActiveEntry(); | 608 content::NavigationEntry* entry = preview->GetController().GetActiveEntry(); |
592 | 609 |
593 // The last navigation should be the same as the active entry if the loader | 610 // The last navigation should be the same as the active entry if the overlay |
594 // is in search mode. During navigation, the active entry could have | 611 // is in search mode. During navigation, the active entry could have |
595 // changed since DidCommitProvisionalLoadForFrame is called after the entry | 612 // changed since DidCommitProvisionalLoadForFrame is called after the entry |
596 // is changed. | 613 // is changed. |
597 // TODO(shishir): Should we commit the last navigation for | 614 // TODO(shishir): Should we commit the last navigation for |
598 // INSTANT_COMMIT_NAVIGATED. | 615 // INSTANT_COMMIT_NAVIGATED. |
599 DCHECK(type == INSTANT_COMMIT_NAVIGATED || | 616 DCHECK(type == INSTANT_COMMIT_NAVIGATED || |
600 last_navigation.url == entry->GetURL()); | 617 last_navigation.url == entry->GetURL()); |
601 | 618 |
602 // Add the page to history. | 619 // Add the page to history. |
603 HistoryTabHelper* history_tab_helper = | 620 HistoryTabHelper* history_tab_helper = |
604 HistoryTabHelper::FromWebContents(preview); | 621 HistoryTabHelper::FromWebContents(preview.get()); |
605 history_tab_helper->UpdateHistoryForNavigation(last_navigation); | 622 history_tab_helper->UpdateHistoryForNavigation(last_navigation); |
606 | 623 |
607 // Update the page title. | 624 // Update the page title. |
608 history_tab_helper->UpdateHistoryPageTitle(*entry); | 625 history_tab_helper->UpdateHistoryPageTitle(*entry); |
609 } | 626 } |
610 | 627 |
611 // Add a fake history entry with a non-Instant search URL, so that search | 628 // Add a fake history entry with a non-Instant search URL, so that search |
612 // terms extraction (for autocomplete history matches) works. | 629 // terms extraction (for autocomplete history matches) works. |
613 HistoryService* history = HistoryServiceFactory::GetForProfile( | 630 HistoryService* history = HistoryServiceFactory::GetForProfile( |
614 Profile::FromBrowserContext(preview->GetBrowserContext()), | 631 Profile::FromBrowserContext(preview->GetBrowserContext()), |
615 Profile::EXPLICIT_ACCESS); | 632 Profile::EXPLICIT_ACCESS); |
616 if (history) { | 633 if (history) { |
617 history->AddPage(url_for_history_, base::Time::Now(), NULL, 0, GURL(), | 634 history->AddPage(url_for_history_, base::Time::Now(), NULL, 0, GURL(), |
618 history::RedirectList(), last_transition_type_, | 635 history::RedirectList(), last_transition_type_, |
619 history::SOURCE_BROWSED, false); | 636 history::SOURCE_BROWSED, false); |
620 } | 637 } |
621 | 638 |
622 preview->GetController().PruneAllButActive(); | 639 preview->GetController().PruneAllButActive(); |
623 | 640 |
624 if (type != INSTANT_COMMIT_PRESSED_ALT_ENTER) { | 641 if (type != INSTANT_COMMIT_PRESSED_ALT_ENTER) { |
625 content::WebContents* active_tab = browser_->GetActiveWebContents(); | 642 content::WebContents* active_tab = browser_->GetActiveWebContents(); |
626 AddSessionStorageHistogram(extended_enabled_, active_tab, preview); | 643 AddSessionStorageHistogram(extended_enabled_, active_tab, preview.get()); |
627 preview->GetController().CopyStateFromAndPrune( | 644 preview->GetController().CopyStateFromAndPrune( |
628 &active_tab->GetController()); | 645 &active_tab->GetController()); |
629 } | 646 } |
630 | 647 |
631 // Browser takes ownership of the preview. | 648 // Save notification source before we release the preview. |
632 browser_->CommitInstant(preview, type == INSTANT_COMMIT_PRESSED_ALT_ENTER); | 649 const content::NotificationSource& notification_source = |
| 650 content::Source<content::WebContents>(preview.get()); |
| 651 |
| 652 browser_->CommitInstant(preview.Pass(), |
| 653 type == INSTANT_COMMIT_PRESSED_ALT_ENTER); |
633 | 654 |
634 content::NotificationService::current()->Notify( | 655 content::NotificationService::current()->Notify( |
635 chrome::NOTIFICATION_INSTANT_COMMITTED, | 656 chrome::NOTIFICATION_INSTANT_COMMITTED, |
636 content::Source<content::WebContents>(preview), | 657 notification_source, |
637 content::NotificationService::NoDetails()); | 658 content::NotificationService::NoDetails()); |
638 | 659 |
639 // Hide explicitly. See comments in HideLoader() for why. | 660 // Hide explicitly. See comments in HideOverlay() for why. |
640 model_.SetPreviewState(chrome::search::Mode(), 0, INSTANT_SIZE_PERCENT); | 661 model_.SetPreviewState(chrome::search::Mode(), 0, INSTANT_SIZE_PERCENT); |
641 | 662 |
642 // Delay deletion as we could've gotten here from an InstantLoader method. | 663 // Delay deletion as we could've gotten here from an InstantOverlay method. |
643 MessageLoop::current()->DeleteSoon(FROM_HERE, loader_.release()); | 664 MessageLoop::current()->DeleteSoon(FROM_HERE, overlay_.release()); |
644 | 665 |
645 // Try to create another loader immediately so that it is ready for the next | 666 // Try to create another overlay immediately so that it is ready for the next |
646 // user interaction. | 667 // user interaction. |
647 EnsureLoaderIsCurrent(false); | 668 EnsureOverlayIsCurrent(false); |
648 | 669 |
649 LOG_INSTANT_DEBUG_EVENT(this, "Committed"); | 670 LOG_INSTANT_DEBUG_EVENT(this, "Committed"); |
650 return true; | 671 return true; |
651 } | 672 } |
652 | 673 |
653 void InstantController::OmniboxFocusChanged( | 674 void InstantController::OmniboxFocusChanged( |
654 OmniboxFocusState state, | 675 OmniboxFocusState state, |
655 OmniboxFocusChangeReason reason, | 676 OmniboxFocusChangeReason reason, |
656 gfx::NativeView view_gaining_focus) { | 677 gfx::NativeView view_gaining_focus) { |
657 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 678 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
658 "OmniboxFocusChanged: %d to %d for reason %d", omnibox_focus_state_, | 679 "OmniboxFocusChanged: %d to %d for reason %d", omnibox_focus_state_, |
659 state, reason)); | 680 state, reason)); |
660 | 681 |
661 OmniboxFocusState old_focus_state = omnibox_focus_state_; | 682 OmniboxFocusState old_focus_state = omnibox_focus_state_; |
662 omnibox_focus_state_ = state; | 683 omnibox_focus_state_ = state; |
663 if (!extended_enabled_ && !instant_enabled_) | 684 if (!extended_enabled_ && !instant_enabled_) |
664 return; | 685 return; |
665 | 686 |
666 // Tell the page if the key capture mode changed unless the focus state | 687 // Tell the page if the key capture mode changed unless the focus state |
667 // changed because of TYPING. This is because in that case, the browser hasn't | 688 // changed because of TYPING. This is because in that case, the browser hasn't |
668 // really stopped capturing key strokes. | 689 // really stopped capturing key strokes. |
669 // | 690 // |
670 // (More practically, if we don't do this check, the page would receive | 691 // (More practically, if we don't do this check, the page would receive |
671 // onkeycapturechange before the corresponding onchange, and the page would | 692 // onkeycapturechange before the corresponding onchange, and the page would |
672 // have no way of telling whether the keycapturechange happened because of | 693 // have no way of telling whether the keycapturechange happened because of |
673 // some actual user action or just because they started typing.) | 694 // some actual user action or just because they started typing.) |
674 if (extended_enabled_ && GetPreviewContents() && | 695 if (extended_enabled_ && GetPreviewContents() && |
675 reason != OMNIBOX_FOCUS_CHANGE_TYPING) | 696 reason != OMNIBOX_FOCUS_CHANGE_TYPING) { |
676 loader_->KeyCaptureChanged(omnibox_focus_state_ == OMNIBOX_FOCUS_INVISIBLE); | 697 const bool is_key_capture_enabled = |
| 698 omnibox_focus_state_ == OMNIBOX_FOCUS_INVISIBLE; |
| 699 if (overlay_) |
| 700 overlay_->KeyCaptureChanged(is_key_capture_enabled); |
| 701 if (instant_tab_) |
| 702 instant_tab_->KeyCaptureChanged(is_key_capture_enabled); |
| 703 } |
677 | 704 |
678 // If focus went from outside the omnibox to the omnibox, preload the default | 705 // If focus went from outside the omnibox to the omnibox, preload the default |
679 // search engine, in anticipation of the user typing a query. If the reverse | 706 // search engine, in anticipation of the user typing a query. If the reverse |
680 // happened, commit or discard the preview. | 707 // happened, commit or discard the preview. |
681 if (state != OMNIBOX_FOCUS_NONE && old_focus_state == OMNIBOX_FOCUS_NONE) { | 708 if (state != OMNIBOX_FOCUS_NONE && old_focus_state == OMNIBOX_FOCUS_NONE) { |
682 // On explicit user actions, ignore the Instant blacklist. | 709 // On explicit user actions, ignore the Instant blacklist. |
683 EnsureLoaderIsCurrent(reason == OMNIBOX_FOCUS_CHANGE_EXPLICIT); | 710 EnsureOverlayIsCurrent(reason == OMNIBOX_FOCUS_CHANGE_EXPLICIT); |
684 } else if (state == OMNIBOX_FOCUS_NONE && | 711 } else if (state == OMNIBOX_FOCUS_NONE && |
685 old_focus_state != OMNIBOX_FOCUS_NONE) { | 712 old_focus_state != OMNIBOX_FOCUS_NONE) { |
686 OmniboxLostFocus(view_gaining_focus); | 713 OmniboxLostFocus(view_gaining_focus); |
687 } | 714 } |
688 } | 715 } |
689 | 716 |
690 void InstantController::SearchModeChanged( | 717 void InstantController::SearchModeChanged( |
691 const chrome::search::Mode& old_mode, | 718 const chrome::search::Mode& old_mode, |
692 const chrome::search::Mode& new_mode) { | 719 const chrome::search::Mode& new_mode) { |
693 if (!extended_enabled_) | 720 if (!extended_enabled_) |
694 return; | 721 return; |
695 | 722 |
696 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 723 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
697 "SearchModeChanged: [origin:mode] %d:%d to %d:%d", old_mode.origin, | 724 "SearchModeChanged: [origin:mode] %d:%d to %d:%d", old_mode.origin, |
698 old_mode.mode, new_mode.origin, new_mode.mode)); | 725 old_mode.mode, new_mode.origin, new_mode.mode)); |
699 | 726 |
700 search_mode_ = new_mode; | 727 search_mode_ = new_mode; |
701 if (!new_mode.is_search_suggestions()) | 728 if (!new_mode.is_search_suggestions()) |
702 HideLoader(); | 729 HideOverlay(); |
703 | 730 |
704 if (loader_) | 731 if (overlay_) |
705 loader_->SearchModeChanged(new_mode); | 732 overlay_->SearchModeChanged(new_mode); |
706 | 733 |
707 ResetInstantTab(); | 734 ResetInstantTab(); |
708 } | 735 } |
709 | 736 |
710 void InstantController::ActiveTabChanged() { | 737 void InstantController::ActiveTabChanged() { |
711 if (!extended_enabled_ && !instant_enabled_) | 738 if (!extended_enabled_ && !instant_enabled_) |
712 return; | 739 return; |
713 | 740 |
714 LOG_INSTANT_DEBUG_EVENT(this, "ActiveTabChanged"); | 741 LOG_INSTANT_DEBUG_EVENT(this, "ActiveTabChanged"); |
715 | 742 |
716 // When switching tabs, always hide the preview, except if it's showing NTP | 743 // When switching tabs, always hide the preview. |
717 // content, and the new tab is also an NTP. | 744 HideOverlay(); |
718 if (!search_mode_.is_ntp() || !model_.mode().is_ntp()) | |
719 HideLoader(); | |
720 | 745 |
721 if (extended_enabled_) | 746 if (extended_enabled_) |
722 ResetInstantTab(); | 747 ResetInstantTab(); |
723 } | 748 } |
724 | 749 |
725 void InstantController::TabDeactivated(content::WebContents* contents) { | 750 void InstantController::TabDeactivated(content::WebContents* contents) { |
726 LOG_INSTANT_DEBUG_EVENT(this, "TabDeactivated"); | 751 LOG_INSTANT_DEBUG_EVENT(this, "TabDeactivated"); |
727 if (extended_enabled_ && !contents->IsBeingDestroyed()) | 752 if (extended_enabled_ && !contents->IsBeingDestroyed()) |
728 CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST); | 753 CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST); |
729 } | 754 } |
730 | 755 |
731 void InstantController::SetInstantEnabled(bool instant_enabled, | 756 void InstantController::SetInstantEnabled(bool instant_enabled, |
732 bool use_local_preview_only) { | 757 bool use_local_preview_only) { |
733 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 758 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
734 "SetInstantEnabled: instant_enabled=%d, use_local_preview_only=%d", | 759 "SetInstantEnabled: instant_enabled=%d, use_local_preview_only=%d", |
735 instant_enabled, use_local_preview_only)); | 760 instant_enabled, use_local_preview_only)); |
736 | 761 |
737 // Non extended mode does not care about |use_local_preview_only|. | 762 // Non extended mode does not care about |use_local_preview_only|. |
738 if (instant_enabled == instant_enabled_ && | 763 if (instant_enabled == instant_enabled_ && |
739 (!extended_enabled_ || | 764 (!extended_enabled_ || |
740 use_local_preview_only == use_local_preview_only_)) { | 765 use_local_preview_only == use_local_preview_only_)) { |
741 return; | 766 return; |
742 } | 767 } |
743 | 768 |
744 instant_enabled_ = instant_enabled; | 769 instant_enabled_ = instant_enabled; |
745 use_local_preview_only_ = use_local_preview_only; | 770 use_local_preview_only_ = use_local_preview_only; |
746 HideInternal(); | 771 HideInternal(); |
747 loader_.reset(); | 772 overlay_.reset(); |
748 if (extended_enabled_ || instant_enabled_) | 773 if (extended_enabled_ || instant_enabled_) |
749 EnsureLoaderIsCurrent(false); | 774 EnsureOverlayIsCurrent(false); |
| 775 if (extended_enabled_) |
| 776 ResetNTP(); |
750 if (instant_tab_) | 777 if (instant_tab_) |
751 instant_tab_->SetDisplayInstantResults(instant_enabled_); | 778 instant_tab_->SetDisplayInstantResults(instant_enabled_); |
752 } | 779 } |
753 | 780 |
754 void InstantController::ThemeChanged(const ThemeBackgroundInfo& theme_info) { | 781 void InstantController::ThemeChanged(const ThemeBackgroundInfo& theme_info) { |
755 if (!extended_enabled_) | 782 if (!extended_enabled_) |
756 return; | 783 return; |
757 | 784 |
758 if (loader_) | 785 if (overlay_) |
759 loader_->SendThemeBackgroundInfo(theme_info); | 786 overlay_->SendThemeBackgroundInfo(theme_info); |
| 787 if (ntp_) |
| 788 ntp_->SendThemeBackgroundInfo(theme_info); |
760 } | 789 } |
761 | 790 |
762 void InstantController::ThemeAreaHeightChanged(int height) { | 791 void InstantController::ThemeAreaHeightChanged(int height) { |
763 if (!extended_enabled_) | 792 if (!extended_enabled_) |
764 return; | 793 return; |
765 | 794 |
766 if (loader_) | 795 if (overlay_) |
767 loader_->SendThemeAreaHeight(height); | 796 overlay_->SendThemeAreaHeight(height); |
| 797 if (ntp_) |
| 798 ntp_->SendThemeAreaHeight(height); |
| 799 } |
| 800 |
| 801 void InstantController::SwappedOverlayContents() { |
| 802 model_.SetPreviewContents(GetPreviewContents()); |
| 803 } |
| 804 |
| 805 void InstantController::FocusedOverlayContents() { |
| 806 #if defined(USE_AURA) |
| 807 // On aura the omnibox only receives a focus lost if we initiate the focus |
| 808 // change. This does that. |
| 809 if (!model_.mode().is_default()) |
| 810 browser_->InstantPreviewFocused(); |
| 811 #endif |
| 812 } |
| 813 |
| 814 void InstantController::ReloadOverlayIfStale() { |
| 815 // The local popup is never stale. |
| 816 if (overlay_ && overlay_->IsUsingLocalPreview()) |
| 817 return; |
| 818 |
| 819 // If the preview is showing or the omnibox has focus, don't delete the |
| 820 // overlay. It will get refreshed the next time the preview is hidden or the |
| 821 // omnibox loses focus. |
| 822 if ((!overlay_ || overlay_->is_stale()) && |
| 823 omnibox_focus_state_ == OMNIBOX_FOCUS_NONE && |
| 824 model_.mode().is_default()) { |
| 825 overlay_.reset(); |
| 826 EnsureOverlayIsCurrent(false); |
| 827 } |
| 828 } |
| 829 |
| 830 void InstantController::LogDebugEvent(const std::string& info) const { |
| 831 DVLOG(1) << info; |
| 832 |
| 833 debug_events_.push_front(std::make_pair( |
| 834 base::Time::Now().ToInternalValue(), info)); |
| 835 static const size_t kMaxDebugEventSize = 2000; |
| 836 if (debug_events_.size() > kMaxDebugEventSize) |
| 837 debug_events_.pop_back(); |
| 838 } |
| 839 |
| 840 void InstantController::InstantPageRenderViewCreated( |
| 841 const content::WebContents* contents) { |
| 842 if (!extended_enabled_) |
| 843 return; |
| 844 |
| 845 // Ensure the searchbox API has the correct initial state. |
| 846 if (IsContentsFrom(overlay(), contents)) { |
| 847 overlay_->SetDisplayInstantResults(instant_enabled_); |
| 848 overlay_->SearchModeChanged(search_mode_); |
| 849 overlay_->KeyCaptureChanged( |
| 850 omnibox_focus_state_ == OMNIBOX_FOCUS_INVISIBLE); |
| 851 overlay_->SetMarginSize(start_margin_, end_margin_); |
| 852 overlay_->InitializeFonts(); |
| 853 } else if (IsContentsFrom(ntp(), contents)) { |
| 854 ntp_->SetDisplayInstantResults(instant_enabled_); |
| 855 ntp_->SetMarginSize(start_margin_, end_margin_); |
| 856 ntp_->InitializeFonts(); |
| 857 } |
| 858 } |
| 859 |
| 860 void InstantController::InstantSupportDetermined( |
| 861 const content::WebContents* contents, |
| 862 bool supports_instant) { |
| 863 if (IsContentsFrom(instant_tab(), contents)) { |
| 864 if (!supports_instant) |
| 865 MessageLoop::current()->DeleteSoon(FROM_HERE, instant_tab_.release()); |
| 866 } else if (IsContentsFrom(ntp(), contents)) { |
| 867 if (supports_instant) |
| 868 RemoveFromBlacklist(ntp_->instant_url()); |
| 869 else |
| 870 BlacklistAndResetNTP(); |
| 871 |
| 872 content::NotificationService::current()->Notify( |
| 873 chrome::NOTIFICATION_INSTANT_NTP_SUPPORT_DETERMINED, |
| 874 content::Source<InstantController>(this), |
| 875 content::NotificationService::NoDetails()); |
| 876 |
| 877 } else if (IsContentsFrom(overlay(), contents)) { |
| 878 if (supports_instant) |
| 879 RemoveFromBlacklist(overlay_->instant_url()); |
| 880 else |
| 881 BlacklistAndResetOverlay(); |
| 882 |
| 883 content::NotificationService::current()->Notify( |
| 884 chrome::NOTIFICATION_INSTANT_OVERLAY_SUPPORT_DETERMINED, |
| 885 content::Source<InstantController>(this), |
| 886 content::NotificationService::NoDetails()); |
| 887 } |
| 888 } |
| 889 |
| 890 void InstantController::InstantPageRenderViewGone( |
| 891 const content::WebContents* contents) { |
| 892 if (IsContentsFrom(overlay(), contents)) |
| 893 BlacklistAndResetOverlay(); |
| 894 else if (IsContentsFrom(ntp(), contents)) |
| 895 BlacklistAndResetNTP(); |
| 896 } |
| 897 |
| 898 void InstantController::InstantPageAboutToNavigateMainFrame( |
| 899 const content::WebContents* contents, |
| 900 const GURL& url) { |
| 901 if (!IsContentsFrom(overlay(), contents)) |
| 902 return; |
| 903 |
| 904 // If the page does not yet support instant, we allow redirects and other |
| 905 // navigations to go through since the instant URL can redirect - e.g. to |
| 906 // country specific pages. |
| 907 if (!overlay_->supports_instant()) |
| 908 return; |
| 909 |
| 910 GURL instant_url(overlay_->instant_url()); |
| 911 |
| 912 // If we are navigating to the instant URL, do nothing. |
| 913 if (url == instant_url) |
| 914 return; |
| 915 |
| 916 // Commit the navigation if either: |
| 917 // - The page is in NTP mode (so it could only navigate on a user click) or |
| 918 // - The page is not in NTP mode and we are navigating to a URL with a |
| 919 // different host or path than the instant URL. This enables the instant |
| 920 // page when it is showing search results to change the query parameters |
| 921 // and fragments of the URL without it navigating. |
| 922 if (model_.mode().is_ntp() || |
| 923 (url.host() != instant_url.host() || url.path() != instant_url.path())) { |
| 924 CommitIfPossible(INSTANT_COMMIT_NAVIGATED); |
| 925 } |
768 } | 926 } |
769 | 927 |
770 void InstantController::SetSuggestions( | 928 void InstantController::SetSuggestions( |
771 const content::WebContents* contents, | 929 const content::WebContents* contents, |
772 const std::vector<InstantSuggestion>& suggestions) { | 930 const std::vector<InstantSuggestion>& suggestions) { |
773 LOG_INSTANT_DEBUG_EVENT(this, "SetSuggestions"); | 931 LOG_INSTANT_DEBUG_EVENT(this, "SetSuggestions"); |
774 | 932 |
775 // Ignore if the message is from an unexpected source. | 933 // Ignore if the message is from an unexpected source. |
776 if (instant_tab_) { | 934 if (IsContentsFrom(ntp(), contents)) |
777 if (instant_tab_->contents() != contents) | |
778 return; | |
779 } else if (!loader_ || loader_->contents() != contents || | |
780 !allow_preview_to_show_search_suggestions_) { | |
781 return; | 935 return; |
782 } | 936 if (instant_tab_ && !IsContentsFrom(instant_tab(), contents)) |
| 937 return; |
| 938 if (IsContentsFrom(overlay(), contents) && |
| 939 !allow_preview_to_show_search_suggestions_) |
| 940 return; |
783 | 941 |
784 InstantSuggestion suggestion; | 942 InstantSuggestion suggestion; |
785 if (!suggestions.empty()) | 943 if (!suggestions.empty()) |
786 suggestion = suggestions[0]; | 944 suggestion = suggestions[0]; |
787 | 945 |
788 if (instant_tab_ && search_mode_.is_search_results() && | 946 if (instant_tab_ && search_mode_.is_search_results() && |
789 suggestion.behavior == INSTANT_COMPLETE_REPLACE) { | 947 suggestion.behavior == INSTANT_COMPLETE_REPLACE) { |
790 // Update |last_omnibox_text_| so that the controller commits the proper | 948 // Update |last_omnibox_text_| so that the controller commits the proper |
791 // query if the user focuses the omnibox and presses Enter. | 949 // query if the user focuses the omnibox and presses Enter. |
792 last_omnibox_text_ = suggestion.text; | 950 last_omnibox_text_ = suggestion.text; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
853 last_suggestion_ = suggestion; | 1011 last_suggestion_ = suggestion; |
854 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 1012 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
855 "SetInstantSuggestion: text='%s' behavior=%d", | 1013 "SetInstantSuggestion: text='%s' behavior=%d", |
856 UTF16ToUTF8(suggestion.text).c_str(), suggestion.behavior)); | 1014 UTF16ToUTF8(suggestion.text).c_str(), suggestion.behavior)); |
857 browser_->SetInstantSuggestion(suggestion); | 1015 browser_->SetInstantSuggestion(suggestion); |
858 } else { | 1016 } else { |
859 last_suggestion_ = InstantSuggestion(); | 1017 last_suggestion_ = InstantSuggestion(); |
860 } | 1018 } |
861 } | 1019 } |
862 | 1020 |
863 // Extended mode pages will call ShowLoader() when they are ready. | 1021 // Extended mode pages will call ShowOverlay() when they are ready. |
864 if (!extended_enabled_) | 1022 if (!extended_enabled_) |
865 ShowLoader(INSTANT_SHOWN_QUERY_SUGGESTIONS, 100, INSTANT_SIZE_PERCENT); | 1023 ShowOverlay(INSTANT_SHOWN_QUERY_SUGGESTIONS, 100, INSTANT_SIZE_PERCENT); |
866 } | 1024 } |
867 | 1025 |
868 void InstantController::InstantSupportDetermined( | 1026 void InstantController::ShowInstantPreview(const content::WebContents* contents, |
869 const content::WebContents* contents, | 1027 InstantShownReason reason, |
870 bool supports_instant) { | 1028 int height, |
871 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 1029 InstantSizeUnits units) { |
872 "InstantSupportDetermined: supports_instant=%d", supports_instant)); | 1030 if (extended_enabled_ && IsContentsFrom(overlay(), contents)) |
| 1031 ShowOverlay(reason, height, units); |
| 1032 } |
873 | 1033 |
874 if (instant_tab_ && instant_tab_->contents() == contents) { | 1034 void InstantController::StartCapturingKeyStrokes( |
875 if (!supports_instant) | 1035 const content::WebContents* contents) { |
876 MessageLoop::current()->DeleteSoon(FROM_HERE, instant_tab_.release()); | 1036 if (!extended_enabled_) |
877 return; | 1037 return; |
878 } | |
879 | 1038 |
880 if (loader_ && loader_->contents() == contents) { | 1039 // Only honor the call if it comes from an active InstantTab or from an |
881 if (supports_instant) { | 1040 // InstantOverlay that is being shown. |
882 if (blacklisted_urls_.erase(loader_->instant_url())) { | 1041 if (IsContentsFrom(instant_tab(), contents) || |
883 RecordEventHistogram( | 1042 (IsContentsFrom(overlay(), contents) && !model_.mode().is_default())) { |
884 INSTANT_CONTROLLER_EVENT_URL_REMOVED_FROM_BLACKLIST); | 1043 browser_->FocusOmniboxInvisibly(); |
885 } | |
886 } else { | |
887 ++blacklisted_urls_[loader_->instant_url()]; | |
888 RecordEventHistogram(INSTANT_CONTROLLER_EVENT_URL_ADDED_TO_BLACKLIST); | |
889 HideInternal(); | |
890 delete loader_->ReleaseContents(); | |
891 MessageLoop::current()->DeleteSoon(FROM_HERE, loader_.release()); | |
892 EnsureLoaderIsCurrent(false); | |
893 } | |
894 content::NotificationService::current()->Notify( | |
895 chrome::NOTIFICATION_INSTANT_SUPPORT_DETERMINED, | |
896 content::Source<InstantController>(this), | |
897 content::NotificationService::NoDetails()); | |
898 } | 1044 } |
899 } | 1045 } |
900 | 1046 |
901 void InstantController::ShowInstantPreview(InstantShownReason reason, | 1047 void InstantController::StopCapturingKeyStrokes( |
902 int height, | 1048 content::WebContents* contents) { |
903 InstantSizeUnits units) { | 1049 // Nothing to do if omnibox doesn't have invisible focus. |
904 if (extended_enabled_) | 1050 if (!extended_enabled_ || omnibox_focus_state_ != OMNIBOX_FOCUS_INVISIBLE) |
905 ShowLoader(reason, height, units); | |
906 } | |
907 | |
908 void InstantController::StartCapturingKeyStrokes() { | |
909 // Ignore unless the loader is active and on the NTP. | |
910 if (extended_enabled_ && !instant_tab_ && model_.mode().is_ntp()) | |
911 browser_->FocusOmniboxInvisibly(); | |
912 } | |
913 | |
914 void InstantController::StopCapturingKeyStrokes() { | |
915 // Ignore unless the loader is active and on the NTP, and the omnibox has | |
916 // invisible focus. | |
917 if (extended_enabled_ && !instant_tab_ && model_.mode().is_ntp() && | |
918 omnibox_focus_state_ == OMNIBOX_FOCUS_INVISIBLE) | |
919 loader_->contents()->Focus(); | |
920 } | |
921 | |
922 void InstantController::SwappedWebContents() { | |
923 model_.SetPreviewContents(GetPreviewContents()); | |
924 } | |
925 | |
926 void InstantController::InstantLoaderContentsFocused() { | |
927 #if defined(USE_AURA) | |
928 // On aura the omnibox only receives a focus lost if we initiate the focus | |
929 // change. This does that. | |
930 if (!model_.mode().is_default()) | |
931 browser_->InstantPreviewFocused(); | |
932 #endif | |
933 } | |
934 | |
935 void InstantController::InstantLoaderRenderViewGone() { | |
936 ++blacklisted_urls_[loader_->instant_url()]; | |
937 HideInternal(); | |
938 delete loader_->ReleaseContents(); | |
939 // Delay deletion as we have gotten here from an InstantLoader method. | |
940 MessageLoop::current()->DeleteSoon(FROM_HERE, loader_.release()); | |
941 EnsureLoaderIsCurrent(false); | |
942 } | |
943 | |
944 void InstantController::InstantLoaderAboutToNavigateMainFrame(const GURL& url) { | |
945 // If the page does not yet support instant, we allow redirects and other | |
946 // navigations to go through since the instant URL can redirect - e.g. to | |
947 // country specific pages. | |
948 if (!loader_->supports_instant()) | |
949 return; | 1051 return; |
950 | 1052 |
951 GURL instant_url(loader_->instant_url()); | 1053 // Only honor the call if it comes from an active InstantTab or from an |
952 | 1054 // InstantOverlay that is being shown. |
953 // If we are navigating to the instant URL, do nothing. | 1055 if (IsContentsFrom(instant_tab(), contents) || |
954 if (url == instant_url) | 1056 (IsContentsFrom(overlay(), contents) && !model_.mode().is_default())) { |
955 return; | 1057 contents->Focus(); |
956 | |
957 // Commit the navigation if either: | |
958 // - The page is in NTP mode (so it could only navigate on a user click) or | |
959 // - The page is not in NTP mode and we are navigating to a URL with a | |
960 // different host or path than the instant URL. This enables the instant | |
961 // page when it is showing search results to change the query parameters | |
962 // and fragments of the URL without it navigating. | |
963 if (model_.mode().is_ntp() || | |
964 (url.host() != instant_url.host() || url.path() != instant_url.path())) { | |
965 CommitIfPossible(INSTANT_COMMIT_NAVIGATED); | |
966 } | 1058 } |
967 } | 1059 } |
968 | 1060 |
969 void InstantController::InstantLoaderRenderViewCreated() { | 1061 void InstantController::NavigateToURL(const content::WebContents* contents, |
| 1062 const GURL& url, |
| 1063 content::PageTransition transition) { |
| 1064 // TODO(samarth): handle case where contents are no longer "active" (e.g. user |
| 1065 // has switched tabs). |
970 if (!extended_enabled_) | 1066 if (!extended_enabled_) |
971 return; | 1067 return; |
972 | 1068 if (overlay_) |
973 // Ensure the searchbox API has the correct initial state. | 1069 HideOverlay(); |
974 loader_->SetDisplayInstantResults(instant_enabled_); | 1070 browser_->OpenURLInCurrentTab(url, transition); |
975 loader_->SearchModeChanged(search_mode_); | |
976 loader_->KeyCaptureChanged(omnibox_focus_state_ == OMNIBOX_FOCUS_INVISIBLE); | |
977 loader_->SetMarginSize(start_margin_, end_margin_); | |
978 loader_->InitializeFonts(); | |
979 } | 1071 } |
980 | 1072 |
981 void InstantController::OmniboxLostFocus(gfx::NativeView view_gaining_focus) { | 1073 void InstantController::OmniboxLostFocus(gfx::NativeView view_gaining_focus) { |
982 // If the preview is showing custom NTP content, don't hide it, commit it | 1074 // If the preview is showing custom NTP content, don't hide it, commit it |
983 // (no matter where the user clicked) or try to recreate it. | 1075 // (no matter where the user clicked) or try to recreate it. |
984 if (model_.mode().is_ntp()) | 1076 if (model_.mode().is_ntp()) |
985 return; | 1077 return; |
986 | 1078 |
987 // If the preview is not showing at all, recreate it if it's stale. | 1079 // If the preview is not showing at all, recreate it if it's stale. |
988 if (model_.mode().is_default()) { | 1080 if (model_.mode().is_default()) { |
989 OnStaleLoader(); | 1081 ReloadOverlayIfStale(); |
990 MaybeSwitchToRemoteLoader(); | 1082 MaybeSwitchToRemoteOverlay(); |
991 return; | 1083 return; |
992 } | 1084 } |
993 | 1085 |
994 // The preview is showing search suggestions. If GetPreviewContents() is NULL, | 1086 // The preview is showing search suggestions. If GetPreviewContents() is NULL, |
995 // we are in the commit path. Don't do anything. | 1087 // we are in the commit path. Don't do anything. |
996 if (!GetPreviewContents()) | 1088 if (!GetPreviewContents()) |
997 return; | 1089 return; |
998 | 1090 |
999 #if defined(OS_MACOSX) | 1091 #if defined(OS_MACOSX) |
1000 // TODO(sreeram): See if Mac really needs this special treatment. | 1092 // TODO(sreeram): See if Mac really needs this special treatment. |
1001 if (!loader_->is_pointer_down_from_activate()) | 1093 if (!overlay_->is_pointer_down_from_activate()) |
1002 HideLoader(); | 1094 HideOverlay(); |
1003 #else | 1095 #else |
1004 if (IsViewInContents(GetViewGainingFocus(view_gaining_focus), | 1096 if (IsViewInContents(GetViewGainingFocus(view_gaining_focus), |
1005 loader_->contents())) | 1097 overlay_->contents())) |
1006 CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST); | 1098 CommitIfPossible(INSTANT_COMMIT_FOCUS_LOST); |
1007 else | 1099 else |
1008 HideLoader(); | 1100 HideOverlay(); |
1009 #endif | 1101 #endif |
1010 } | 1102 } |
1011 | 1103 |
1012 void InstantController::NavigateToURL(const GURL& url, | 1104 void InstantController::ResetNTP() { |
1013 content::PageTransition transition) { | 1105 ntp_.reset(); |
1014 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 1106 std::string instant_url; |
1015 "NavigateToURL: url='%s'", url.spec().c_str())); | 1107 if (!GetInstantURL(browser_->profile(), false, &instant_url)) |
| 1108 return; |
1016 | 1109 |
1017 if (!extended_enabled_) | 1110 ntp_.reset(new InstantNTP(this, instant_url)); |
1018 return; | 1111 ntp_->InitContents(browser_->profile(), browser_->GetActiveWebContents(), |
1019 if (loader_) | 1112 base::Bind(&InstantController::ResetNTP, |
1020 HideLoader(); | 1113 base::Unretained(this))); |
1021 browser_->OpenURLInCurrentTab(url, transition); | |
1022 } | 1114 } |
1023 | 1115 |
1024 void InstantController::LogDebugEvent(const std::string& info) const { | 1116 bool InstantController::EnsureOverlayIsCurrent(bool ignore_blacklist) { |
1025 DVLOG(1) << info; | |
1026 | |
1027 debug_events_.push_front(std::make_pair( | |
1028 base::Time::Now().ToInternalValue(), info)); | |
1029 static const size_t kMaxDebugEventSize = 2000; | |
1030 if (debug_events_.size() > kMaxDebugEventSize) | |
1031 debug_events_.pop_back(); | |
1032 } | |
1033 | |
1034 bool InstantController::EnsureLoaderIsCurrent(bool ignore_blacklist) { | |
1035 // If there's no active tab, the browser is closing. | 1117 // If there's no active tab, the browser is closing. |
1036 const content::WebContents* active_tab = browser_->GetActiveWebContents(); | 1118 const content::WebContents* active_tab = browser_->GetActiveWebContents(); |
1037 if (!active_tab) | 1119 if (!active_tab) |
1038 return false; | 1120 return false; |
1039 | 1121 |
| 1122 Profile* profile = Profile::FromBrowserContext( |
| 1123 active_tab->GetBrowserContext()); |
1040 std::string instant_url; | 1124 std::string instant_url; |
1041 if (!GetInstantURL(active_tab, ignore_blacklist, &instant_url)) { | 1125 if (!GetInstantURL(profile, ignore_blacklist, &instant_url)) { |
1042 // If we are in extended mode, fallback to the local popup. | 1126 // If we are in extended mode, fallback to the local popup. |
1043 if (extended_enabled_) | 1127 if (extended_enabled_) |
1044 instant_url = kLocalOmniboxPopupURL; | 1128 instant_url = kLocalOmniboxPopupURL; |
1045 else | 1129 else |
1046 return false; | 1130 return false; |
1047 } | 1131 } |
1048 | 1132 |
1049 if (!loader_ || loader_->instant_url() != instant_url) | 1133 if (!overlay_ || overlay_->instant_url() != instant_url) |
1050 CreateLoader(instant_url, active_tab); | 1134 CreateOverlay(instant_url, active_tab); |
1051 | 1135 |
1052 return true; | 1136 return true; |
1053 } | 1137 } |
1054 | 1138 |
1055 void InstantController::CreateLoader(const std::string& instant_url, | 1139 void InstantController::CreateOverlay(const std::string& instant_url, |
1056 const content::WebContents* active_tab) { | 1140 const content::WebContents* active_tab) { |
1057 // Update theme info so that the loader picks up the correct fonts. | 1141 // Update theme info so that the loader picks up the correct fonts. |
1058 if (extended_enabled_) | 1142 if (extended_enabled_) |
1059 browser_->UpdateThemeInfoForPreview(); | 1143 browser_->UpdateThemeInfoForPreview(); |
1060 | 1144 |
1061 HideInternal(); | 1145 HideInternal(); |
1062 loader_.reset(new InstantLoader(this, instant_url)); | 1146 overlay_.reset(new InstantOverlay(this, instant_url)); |
1063 loader_->InitContents(active_tab); | 1147 overlay_->InitContents(browser_->profile(), active_tab); |
1064 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 1148 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
1065 "CreateLoader: instant_url='%s'", instant_url.c_str())); | 1149 "CreateOverlay: instant_url='%s'", instant_url.c_str())); |
1066 | |
1067 // Restart the stale loader timer. | |
1068 stale_loader_timer_.Start(FROM_HERE, | |
1069 base::TimeDelta::FromMilliseconds(kStaleLoaderTimeoutMS), this, | |
1070 &InstantController::OnStaleLoader); | |
1071 } | 1150 } |
1072 | 1151 |
1073 void InstantController::OnStaleLoader() { | 1152 void InstantController::MaybeSwitchToRemoteOverlay() { |
1074 // The local popup is never stale. | 1153 if (!overlay_ || omnibox_focus_state_ != OMNIBOX_FOCUS_NONE || |
1075 if (loader_ && loader_->IsUsingLocalPreview()) | |
1076 return; | |
1077 | |
1078 // If the preview is showing or the omnibox has focus, don't delete the | |
1079 // loader. It will get refreshed the next time the preview is hidden or the | |
1080 // omnibox loses focus. | |
1081 if (!stale_loader_timer_.IsRunning() && | |
1082 omnibox_focus_state_ == OMNIBOX_FOCUS_NONE && | |
1083 model_.mode().is_default()) { | |
1084 loader_.reset(); | |
1085 EnsureLoaderIsCurrent(false); | |
1086 } | |
1087 } | |
1088 | |
1089 void InstantController::MaybeSwitchToRemoteLoader() { | |
1090 if (!loader_ || omnibox_focus_state_ != OMNIBOX_FOCUS_NONE || | |
1091 !model_.mode().is_default()) { | 1154 !model_.mode().is_default()) { |
1092 return; | 1155 return; |
1093 } | 1156 } |
1094 | 1157 |
1095 EnsureLoaderIsCurrent(false); | 1158 EnsureOverlayIsCurrent(false); |
1096 } | 1159 } |
1097 | 1160 |
1098 void InstantController::ResetInstantTab() { | 1161 void InstantController::ResetInstantTab() { |
1099 // Do not wire up the InstantTab if instant should only use local previews, to | 1162 // Do not wire up the InstantTab if instant should only use local previews, to |
1100 // prevent it from sending data to the page. | 1163 // prevent it from sending data to the page. |
1101 if (search_mode_.is_origin_search() && !use_local_preview_only_) { | 1164 if (!search_mode_.is_origin_default() && !use_local_preview_only_) { |
1102 content::WebContents* active_tab = browser_->GetActiveWebContents(); | 1165 content::WebContents* active_tab = browser_->GetActiveWebContents(); |
1103 if (!instant_tab_ || active_tab != instant_tab_->contents()) { | 1166 if (!instant_tab_ || active_tab != instant_tab_->contents()) { |
1104 instant_tab_.reset(new InstantTab(this, active_tab)); | 1167 instant_tab_.reset(new InstantTab(this)); |
1105 instant_tab_->Init(); | 1168 instant_tab_->Init(active_tab); |
1106 instant_tab_->SetDisplayInstantResults(instant_enabled_); | 1169 instant_tab_->SetDisplayInstantResults(instant_enabled_); |
1107 instant_tab_->SetMarginSize(start_margin_, end_margin_); | 1170 instant_tab_->SetMarginSize(start_margin_, end_margin_); |
1108 instant_tab_->InitializeFonts(); | 1171 instant_tab_->InitializeFonts(); |
| 1172 instant_tab_->KeyCaptureChanged( |
| 1173 omnibox_focus_state_ == OMNIBOX_FOCUS_INVISIBLE); |
1109 } | 1174 } |
1110 | 1175 |
1111 // Hide the |loader_| since we are now using |instant_tab_| instead. | 1176 // Hide the |overlay_| since we are now using |instant_tab_| instead. |
1112 HideLoader(); | 1177 HideOverlay(); |
1113 } else { | 1178 } else { |
1114 instant_tab_.reset(); | 1179 instant_tab_.reset(); |
1115 } | 1180 } |
1116 } | 1181 } |
1117 | 1182 |
1118 void InstantController::HideLoader() { | 1183 void InstantController::HideOverlay() { |
1119 HideInternal(); | 1184 HideInternal(); |
1120 OnStaleLoader(); | 1185 ReloadOverlayIfStale(); |
1121 MaybeSwitchToRemoteLoader(); | 1186 MaybeSwitchToRemoteOverlay(); |
1122 } | 1187 } |
1123 | 1188 |
1124 void InstantController::HideInternal() { | 1189 void InstantController::HideInternal() { |
1125 LOG_INSTANT_DEBUG_EVENT(this, "Hide"); | 1190 LOG_INSTANT_DEBUG_EVENT(this, "Hide"); |
1126 | 1191 |
1127 // If GetPreviewContents() returns NULL, either we're already in the desired | 1192 // If GetPreviewContents() returns NULL, either we're already in the desired |
1128 // MODE_DEFAULT state, or we're in the commit path. For the latter, don't | 1193 // MODE_DEFAULT state, or we're in the commit path. For the latter, don't |
1129 // change the state just yet; else we may hide the preview unnecessarily. | 1194 // change the state just yet; else we may hide the preview unnecessarily. |
1130 // Instead, the state will be set correctly after the commit is done. | 1195 // Instead, the state will be set correctly after the commit is done. |
1131 if (GetPreviewContents()) { | 1196 if (GetPreviewContents()) { |
1132 model_.SetPreviewState(chrome::search::Mode(), 0, INSTANT_SIZE_PERCENT); | 1197 model_.SetPreviewState(chrome::search::Mode(), 0, INSTANT_SIZE_PERCENT); |
1133 allow_preview_to_show_search_suggestions_ = false; | 1198 allow_preview_to_show_search_suggestions_ = false; |
1134 | 1199 |
1135 // Send a message asking the preview to clear out old results. | 1200 // Send a message asking the preview to clear out old results. |
1136 loader_->Update(string16(), 0, 0, true); | 1201 overlay_->Update(string16(), 0, 0, true); |
1137 } | 1202 } |
1138 | 1203 |
1139 // Clear the first interaction timestamp for later use. | 1204 // Clear the first interaction timestamp for later use. |
1140 first_interaction_time_ = base::Time(); | 1205 first_interaction_time_ = base::Time(); |
1141 } | 1206 } |
1142 | 1207 |
1143 void InstantController::ShowLoader(InstantShownReason reason, | 1208 void InstantController::ShowOverlay(InstantShownReason reason, |
1144 int height, | 1209 int height, |
1145 InstantSizeUnits units) { | 1210 InstantSizeUnits units) { |
1146 // If we are on a committed search results page, the |loader_| is not in use. | 1211 // If we are on a committed search results page, the |overlay_| is not in use. |
1147 if (instant_tab_) | 1212 if (instant_tab_) |
1148 return; | 1213 return; |
1149 | 1214 |
1150 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 1215 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
1151 "Show: reason=%d height=%d units=%d", reason, height, units)); | 1216 "Show: reason=%d height=%d units=%d", reason, height, units)); |
1152 | 1217 |
1153 // Must be on NTP to show NTP content. | 1218 // INSTANT_SHOWN_CUSTOM_NTP_CONTENT is no longer supported. |
1154 if (reason == INSTANT_SHOWN_CUSTOM_NTP_CONTENT && !search_mode_.is_ntp()) | 1219 // TODO(samarth): remove once the server has been updated. |
| 1220 if (reason == INSTANT_SHOWN_CUSTOM_NTP_CONTENT) |
1155 return; | 1221 return; |
1156 | 1222 |
1157 // Must have updated omnibox after the last HideLoader() to show suggestions. | 1223 // Must have updated omnibox after the last HideOverlay() to show suggestions. |
1158 if ((reason == INSTANT_SHOWN_QUERY_SUGGESTIONS || | 1224 if ((reason == INSTANT_SHOWN_QUERY_SUGGESTIONS || |
1159 reason == INSTANT_SHOWN_CLICKED_QUERY_SUGGESTION) && | 1225 reason == INSTANT_SHOWN_CLICKED_QUERY_SUGGESTION) && |
1160 !allow_preview_to_show_search_suggestions_) | 1226 !allow_preview_to_show_search_suggestions_) |
1161 return; | 1227 return; |
1162 | 1228 |
1163 // The page is trying to hide itself. Hide explicitly (i.e., don't use | 1229 // The page is trying to hide itself. Hide explicitly (i.e., don't use |
1164 // HideLoader()) so that it can change its mind. | 1230 // HideOverlay()) so that it can change its mind. |
1165 if (height == 0) { | 1231 if (height == 0) { |
1166 model_.SetPreviewState(chrome::search::Mode(), 0, INSTANT_SIZE_PERCENT); | 1232 model_.SetPreviewState(chrome::search::Mode(), 0, INSTANT_SIZE_PERCENT); |
1167 return; | 1233 return; |
1168 } | 1234 } |
1169 | 1235 |
1170 // If the preview is being shown for the first time since the user started | 1236 // If the preview is being shown for the first time since the user started |
1171 // typing, record a histogram value. | 1237 // typing, record a histogram value. |
1172 if (!first_interaction_time_.is_null() && model_.mode().is_default()) { | 1238 if (!first_interaction_time_.is_null() && model_.mode().is_default()) { |
1173 base::TimeDelta delta = base::Time::Now() - first_interaction_time_; | 1239 base::TimeDelta delta = base::Time::Now() - first_interaction_time_; |
1174 UMA_HISTOGRAM_TIMES("Instant.TimeToFirstShow", delta); | 1240 UMA_HISTOGRAM_TIMES("Instant.TimeToFirstShow", delta); |
1175 } | 1241 } |
1176 | 1242 |
1177 // Show at 100% height except in the following cases: | 1243 // Show at 100% height except in the following cases: |
1178 // - The local omnibox popup is being loaded. | 1244 // - The local omnibox popup is being loaded. |
1179 // - Instant is disabled. The page needs to be able to show only a dropdown. | 1245 // - Instant is disabled. The page needs to be able to show only a dropdown. |
1180 // - The page wants to show custom NTP content. | 1246 // - The page wants to show custom NTP content. |
1181 // - The page is over a website other than search or an NTP, and is not | 1247 // - The page is over a website other than search or an NTP, and is not |
1182 // already showing at 100% height. | 1248 // already showing at 100% height. |
1183 if (loader_->IsUsingLocalPreview() || !instant_enabled_ || | 1249 if (overlay_->IsUsingLocalPreview() || !instant_enabled_ || |
1184 reason == INSTANT_SHOWN_CUSTOM_NTP_CONTENT || | 1250 reason == INSTANT_SHOWN_CUSTOM_NTP_CONTENT || |
1185 (search_mode_.is_origin_default() && !IsFullHeight(model_))) | 1251 (search_mode_.is_origin_default() && !IsFullHeight(model_))) |
1186 model_.SetPreviewState(search_mode_, height, units); | 1252 model_.SetPreviewState(search_mode_, height, units); |
1187 else | 1253 else |
1188 model_.SetPreviewState(search_mode_, 100, INSTANT_SIZE_PERCENT); | 1254 model_.SetPreviewState(search_mode_, 100, INSTANT_SIZE_PERCENT); |
1189 | 1255 |
1190 // If the user clicked on a query suggestion, also go ahead and commit the | 1256 // If the user clicked on a query suggestion, also go ahead and commit the |
1191 // overlay. This is necessary because if the overlay was partially visible | 1257 // overlay. This is necessary because if the overlay was partially visible |
1192 // when the suggestion was clicked, the click itself would not commit the | 1258 // when the suggestion was clicked, the click itself would not commit the |
1193 // overlay (because we're not full height). | 1259 // overlay (because we're not full height). |
1194 if (reason == INSTANT_SHOWN_CLICKED_QUERY_SUGGESTION) | 1260 if (reason == INSTANT_SHOWN_CLICKED_QUERY_SUGGESTION) |
1195 CommitIfPossible(INSTANT_COMMIT_CLICKED_QUERY_SUGGESTION); | 1261 CommitIfPossible(INSTANT_COMMIT_CLICKED_QUERY_SUGGESTION); |
1196 } | 1262 } |
1197 | 1263 |
1198 void InstantController::SendPopupBoundsToPage() { | 1264 void InstantController::SendPopupBoundsToPage() { |
1199 if (last_popup_bounds_ == popup_bounds_ || !loader_ || | 1265 if (last_popup_bounds_ == popup_bounds_ || !overlay_ || |
1200 loader_->is_pointer_down_from_activate()) | 1266 overlay_->is_pointer_down_from_activate()) |
1201 return; | 1267 return; |
1202 | 1268 |
1203 last_popup_bounds_ = popup_bounds_; | 1269 last_popup_bounds_ = popup_bounds_; |
1204 gfx::Rect preview_bounds = browser_->GetInstantBounds(); | 1270 gfx::Rect preview_bounds = browser_->GetInstantBounds(); |
1205 gfx::Rect intersection = gfx::IntersectRects(popup_bounds_, preview_bounds); | 1271 gfx::Rect intersection = gfx::IntersectRects(popup_bounds_, preview_bounds); |
1206 | 1272 |
1207 // Translate into window coordinates. | 1273 // Translate into window coordinates. |
1208 if (!intersection.IsEmpty()) { | 1274 if (!intersection.IsEmpty()) { |
1209 intersection.Offset(-preview_bounds.origin().x(), | 1275 intersection.Offset(-preview_bounds.origin().x(), |
1210 -preview_bounds.origin().y()); | 1276 -preview_bounds.origin().y()); |
1211 } | 1277 } |
1212 | 1278 |
1213 // In the current Chrome UI, these must always be true so they sanity check | 1279 // In the current Chrome UI, these must always be true so they sanity check |
1214 // the above operations. In a future UI, these may be removed or adjusted. | 1280 // the above operations. In a future UI, these may be removed or adjusted. |
1215 // There is no point in sanity-checking |intersection.y()| because the omnibox | 1281 // There is no point in sanity-checking |intersection.y()| because the omnibox |
1216 // can be placed anywhere vertically relative to the preview (for example, in | 1282 // can be placed anywhere vertically relative to the preview (for example, in |
1217 // Mac fullscreen mode, the omnibox is fully enclosed by the preview bounds). | 1283 // Mac fullscreen mode, the omnibox is fully enclosed by the preview bounds). |
1218 DCHECK_LE(0, intersection.x()); | 1284 DCHECK_LE(0, intersection.x()); |
1219 DCHECK_LE(0, intersection.width()); | 1285 DCHECK_LE(0, intersection.width()); |
1220 DCHECK_LE(0, intersection.height()); | 1286 DCHECK_LE(0, intersection.height()); |
1221 | 1287 |
1222 loader_->SetPopupBounds(intersection); | 1288 overlay_->SetPopupBounds(intersection); |
1223 } | 1289 } |
1224 | 1290 |
1225 bool InstantController::GetInstantURL(const content::WebContents* active_tab, | 1291 bool InstantController::GetInstantURL(Profile* profile, |
1226 bool ignore_blacklist, | 1292 bool ignore_blacklist, |
1227 std::string* instant_url) const { | 1293 std::string* instant_url) const { |
1228 DCHECK(active_tab); | 1294 DCHECK(profile); |
1229 instant_url->clear(); | 1295 instant_url->clear(); |
1230 | 1296 |
1231 if (extended_enabled_ && use_local_preview_only_) { | 1297 if (extended_enabled_ && use_local_preview_only_) { |
1232 *instant_url = kLocalOmniboxPopupURL; | 1298 *instant_url = kLocalOmniboxPopupURL; |
1233 return true; | 1299 return true; |
1234 } | 1300 } |
1235 | 1301 |
1236 const TemplateURL* template_url = TemplateURLServiceFactory::GetForProfile( | 1302 const TemplateURL* template_url = TemplateURLServiceFactory::GetForProfile( |
1237 Profile::FromBrowserContext(active_tab->GetBrowserContext()))-> | 1303 profile)->GetDefaultSearchProvider(); |
1238 GetDefaultSearchProvider(); | |
1239 | 1304 |
1240 if (!template_url) { | 1305 if (!template_url) { |
1241 LOG_INSTANT_DEBUG_EVENT(this, "GetInstantURL: No template URL"); | 1306 LOG_INSTANT_DEBUG_EVENT(this, "GetInstantURL: No template URL"); |
1242 return false; | 1307 return false; |
1243 } | 1308 } |
1244 | 1309 |
1245 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 1310 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
1246 if (command_line->HasSwitch(switches::kInstantURL)) | 1311 if (command_line->HasSwitch(switches::kInstantURL)) |
1247 *instant_url = command_line->GetSwitchValueASCII(switches::kInstantURL); | 1312 *instant_url = command_line->GetSwitchValueASCII(switches::kInstantURL); |
1248 | 1313 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1309 RecordEventHistogram(INSTANT_CONTROLLER_EVENT_URL_BLOCKED_BY_BLACKLIST); | 1374 RecordEventHistogram(INSTANT_CONTROLLER_EVENT_URL_BLOCKED_BY_BLACKLIST); |
1310 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( | 1375 LOG_INSTANT_DEBUG_EVENT(this, base::StringPrintf( |
1311 "GetInstantURL: Instant URL blacklisted: url=%s", | 1376 "GetInstantURL: Instant URL blacklisted: url=%s", |
1312 instant_url->c_str())); | 1377 instant_url->c_str())); |
1313 return false; | 1378 return false; |
1314 } | 1379 } |
1315 } | 1380 } |
1316 | 1381 |
1317 return true; | 1382 return true; |
1318 } | 1383 } |
| 1384 |
| 1385 void InstantController::BlacklistAndResetNTP() { |
| 1386 ++blacklisted_urls_[ntp_->instant_url()]; |
| 1387 RecordEventHistogram(INSTANT_CONTROLLER_EVENT_URL_ADDED_TO_BLACKLIST); |
| 1388 ignore_result(ntp_->ReleaseContents()); |
| 1389 MessageLoop::current()->DeleteSoon(FROM_HERE, ntp_.release()); |
| 1390 ResetNTP(); |
| 1391 } |
| 1392 |
| 1393 void InstantController::BlacklistAndResetOverlay() { |
| 1394 ++blacklisted_urls_[overlay_->instant_url()]; |
| 1395 RecordEventHistogram(INSTANT_CONTROLLER_EVENT_URL_ADDED_TO_BLACKLIST); |
| 1396 HideInternal(); |
| 1397 ignore_result(overlay_->ReleaseContents()); |
| 1398 MessageLoop::current()->DeleteSoon(FROM_HERE, overlay_.release()); |
| 1399 EnsureOverlayIsCurrent(false); |
| 1400 } |
| 1401 |
| 1402 void InstantController::RemoveFromBlacklist(const std::string& url) { |
| 1403 if (blacklisted_urls_.erase(url)) { |
| 1404 RecordEventHistogram(INSTANT_CONTROLLER_EVENT_URL_REMOVED_FROM_BLACKLIST); |
| 1405 } |
| 1406 } |
OLD | NEW |