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