Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / chrome / renderer / searchbox / searchbox.cc
bloba00c7afb332a52e0ad5efd60cf57adb7e5ba32b4
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
3 // found in the LICENSE file.
5 #include "chrome/renderer/searchbox/searchbox.h"
7 #include <string>
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/favicon/fallback_icon_url_parser.h"
16 #include "chrome/common/favicon/favicon_url_parser.h"
17 #include "chrome/common/favicon/large_icon_url_parser.h"
18 #include "chrome/common/omnibox_focus_state.h"
19 #include "chrome/common/render_messages.h"
20 #include "chrome/common/url_constants.h"
21 #include "chrome/renderer/searchbox/searchbox_extension.h"
22 #include "components/favicon_base/favicon_types.h"
23 #include "content/public/renderer/render_frame.h"
24 #include "content/public/renderer/render_view.h"
25 #include "net/base/escape.h"
26 #include "third_party/WebKit/public/web/WebDocument.h"
27 #include "third_party/WebKit/public/web/WebFrame.h"
28 #include "third_party/WebKit/public/web/WebLocalFrame.h"
29 #include "third_party/WebKit/public/web/WebPerformance.h"
30 #include "third_party/WebKit/public/web/WebView.h"
31 #include "url/gurl.h"
33 namespace {
35 // The size of the InstantMostVisitedItem cache.
36 const size_t kMaxInstantMostVisitedItemCacheSize = 100;
38 // Returns true if items stored in |old_item_id_pairs| and |new_items| are
39 // equal.
40 bool AreMostVisitedItemsEqual(
41 const std::vector<InstantMostVisitedItemIDPair>& old_item_id_pairs,
42 const std::vector<InstantMostVisitedItem>& new_items) {
43 if (old_item_id_pairs.size() != new_items.size())
44 return false;
46 for (size_t i = 0; i < new_items.size(); ++i) {
47 if (new_items[i].url != old_item_id_pairs[i].second.url ||
48 new_items[i].title != old_item_id_pairs[i].second.title) {
49 return false;
52 return true;
55 const char* GetIconTypeUrlHost(SearchBox::ImageSourceType type) {
56 switch (type) {
57 case SearchBox::FAVICON:
58 return "favicon";
59 case SearchBox::LARGE_ICON:
60 return "large-icon";
61 case SearchBox::FALLBACK_ICON:
62 return "fallback-icon";
63 case SearchBox::THUMB:
64 return "thumb";
65 default:
66 NOTREACHED();
68 return nullptr;
71 // Given |path| from an image URL, returns starting index of the page URL,
72 // depending on |type| of image URL. Returns -1 if parse fails.
73 int GetImagePathStartOfPageURL(SearchBox::ImageSourceType type,
74 const std::string& path) {
75 // TODO(huangs): Refactor this: http://crbug.com/468320.
76 switch (type) {
77 case SearchBox::FAVICON: {
78 chrome::ParsedFaviconPath parsed;
79 return chrome::ParseFaviconPath(
80 path, favicon_base::FAVICON, &parsed) ? parsed.path_index : -1;
82 case SearchBox::LARGE_ICON: {
83 LargeIconUrlParser parser;
84 return parser.Parse(path) ? parser.path_index() : -1;
86 case SearchBox::FALLBACK_ICON: {
87 chrome::ParsedFallbackIconPath parser;
88 return parser.Parse(path) ? parser.path_index() : -1;
90 case SearchBox::THUMB: {
91 return 0;
93 default: {
94 NOTREACHED();
95 break;
98 return -1;
101 // Helper for SearchBox::GenerateImageURLFromTransientURL().
102 class SearchBoxIconURLHelper: public SearchBox::IconURLHelper {
103 public:
104 explicit SearchBoxIconURLHelper(const SearchBox* search_box);
105 ~SearchBoxIconURLHelper() override;
106 int GetViewID() const override;
107 std::string GetURLStringFromRestrictedID(InstantRestrictedID rid) const
108 override;
110 private:
111 const SearchBox* search_box_;
114 SearchBoxIconURLHelper::SearchBoxIconURLHelper(const SearchBox* search_box)
115 : search_box_(search_box) {
118 SearchBoxIconURLHelper::~SearchBoxIconURLHelper() {
121 int SearchBoxIconURLHelper::GetViewID() const {
122 return search_box_->render_view()->GetRoutingID();
125 std::string SearchBoxIconURLHelper::GetURLStringFromRestrictedID(
126 InstantRestrictedID rid) const {
127 InstantMostVisitedItem item;
128 if (!search_box_->GetMostVisitedItemWithID(rid, &item))
129 return std::string();
131 return item.url.spec();
134 } // namespace
136 namespace internal { // for testing
138 // Parses "<view_id>/<restricted_id>". If successful, assigns
139 // |*view_id| := "<view_id>", |*rid| := "<restricted_id>", and returns true.
140 bool ParseViewIdAndRestrictedId(const std::string id_part,
141 int* view_id_out,
142 InstantRestrictedID* rid_out) {
143 DCHECK(view_id_out);
144 DCHECK(rid_out);
145 // Check that the path is of Most visited item ID form.
146 std::vector<std::string> tokens;
147 if (Tokenize(id_part, "/", &tokens) != 2)
148 return false;
150 int view_id;
151 InstantRestrictedID rid;
152 if (!base::StringToInt(tokens[0], &view_id) || view_id < 0 ||
153 !base::StringToInt(tokens[1], &rid) || rid < 0)
154 return false;
156 *view_id_out = view_id;
157 *rid_out = rid;
158 return true;
161 // Takes icon |url| of given |type|, e.g., FAVICON looking like
163 // chrome-search://favicon/<view_id>/<restricted_id>
164 // chrome-search://favicon/<parameters>/<view_id>/<restricted_id>
166 // If successful, assigns |*param_part| := "" or "<parameters>/" (note trailing
167 // slash), |*view_id| := "<view_id>", |*rid| := "rid", and returns true.
168 bool ParseIconRestrictedUrl(const GURL& url,
169 SearchBox::ImageSourceType type,
170 std::string* param_part,
171 int* view_id,
172 InstantRestrictedID* rid) {
173 DCHECK(param_part);
174 DCHECK(view_id);
175 DCHECK(rid);
176 // Strip leading slash.
177 std::string raw_path = url.path();
178 DCHECK_GT(raw_path.length(), (size_t) 0);
179 DCHECK_EQ(raw_path[0], '/');
180 raw_path = raw_path.substr(1);
182 int path_index = GetImagePathStartOfPageURL(type, raw_path);
183 if (path_index < 0)
184 return false;
186 std::string id_part = raw_path.substr(path_index);
187 if (!ParseViewIdAndRestrictedId(id_part, view_id, rid))
188 return false;
190 *param_part = raw_path.substr(0, path_index);
191 return true;
194 bool TranslateIconRestrictedUrl(const GURL& transient_url,
195 SearchBox::ImageSourceType type,
196 const SearchBox::IconURLHelper& helper,
197 GURL* url) {
198 std::string params;
199 int view_id = -1;
200 InstantRestrictedID rid = -1;
202 if (!internal::ParseIconRestrictedUrl(
203 transient_url, type, &params, &view_id, &rid) ||
204 view_id != helper.GetViewID()) {
205 if (type == SearchBox::FAVICON) {
206 *url = GURL(base::StringPrintf("chrome-search://%s/",
207 GetIconTypeUrlHost(SearchBox::FAVICON)));
208 return true;
210 return false;
213 std::string item_url = helper.GetURLStringFromRestrictedID(rid);
214 *url = GURL(base::StringPrintf("chrome-search://%s/%s%s",
215 GetIconTypeUrlHost(type),
216 params.c_str(),
217 item_url.c_str()));
218 return true;
221 } // namespace internal
223 SearchBox::IconURLHelper::IconURLHelper() {
226 SearchBox::IconURLHelper::~IconURLHelper() {
229 SearchBox::SearchBox(content::RenderView* render_view)
230 : content::RenderViewObserver(render_view),
231 content::RenderViewObserverTracker<SearchBox>(render_view),
232 page_seq_no_(0),
233 app_launcher_enabled_(false),
234 is_focused_(false),
235 is_input_in_progress_(false),
236 is_key_capture_enabled_(false),
237 display_instant_results_(false),
238 most_visited_items_cache_(kMaxInstantMostVisitedItemCacheSize),
239 query_(),
240 start_margin_(0) {
243 SearchBox::~SearchBox() {
246 void SearchBox::LogEvent(NTPLoggingEventType event) {
247 // The main frame for the current RenderView may be out-of-process, in which
248 // case it won't have performance(). Use the default delta of 0 in this
249 // case.
250 base::TimeDelta delta;
251 if (render_view()->GetWebView()->mainFrame()->isWebLocalFrame()) {
252 // navigation_start in ms.
253 uint64 start = 1000 * (render_view()->GetMainRenderFrame()->GetWebFrame()->
254 performance().navigationStart());
255 uint64 now = (base::TimeTicks::Now() - base::TimeTicks::UnixEpoch())
256 .InMilliseconds();
257 DCHECK(now >= start);
258 delta = base::TimeDelta::FromMilliseconds(now - start);
260 render_view()->Send(new ChromeViewHostMsg_LogEvent(
261 render_view()->GetRoutingID(), page_seq_no_, event, delta));
264 void SearchBox::LogMostVisitedImpression(int position,
265 const base::string16& provider) {
266 render_view()->Send(new ChromeViewHostMsg_LogMostVisitedImpression(
267 render_view()->GetRoutingID(), page_seq_no_, position, provider));
270 void SearchBox::LogMostVisitedNavigation(int position,
271 const base::string16& provider) {
272 render_view()->Send(new ChromeViewHostMsg_LogMostVisitedNavigation(
273 render_view()->GetRoutingID(), page_seq_no_, position, provider));
276 void SearchBox::CheckIsUserSignedInToChromeAs(const base::string16& identity) {
277 render_view()->Send(new ChromeViewHostMsg_ChromeIdentityCheck(
278 render_view()->GetRoutingID(), page_seq_no_, identity));
281 void SearchBox::CheckIsUserSyncingHistory() {
282 render_view()->Send(new ChromeViewHostMsg_HistorySyncCheck(
283 render_view()->GetRoutingID(), page_seq_no_));
286 void SearchBox::DeleteMostVisitedItem(
287 InstantRestrictedID most_visited_item_id) {
288 render_view()->Send(new ChromeViewHostMsg_SearchBoxDeleteMostVisitedItem(
289 render_view()->GetRoutingID(),
290 page_seq_no_,
291 GetURLForMostVisitedItem(most_visited_item_id)));
294 bool SearchBox::GenerateImageURLFromTransientURL(const GURL& transient_url,
295 ImageSourceType type,
296 GURL* url) const {
297 SearchBoxIconURLHelper helper(this);
298 return internal::TranslateIconRestrictedUrl(transient_url, type, helper, url);
301 void SearchBox::GetMostVisitedItems(
302 std::vector<InstantMostVisitedItemIDPair>* items) const {
303 return most_visited_items_cache_.GetCurrentItems(items);
306 bool SearchBox::GetMostVisitedItemWithID(
307 InstantRestrictedID most_visited_item_id,
308 InstantMostVisitedItem* item) const {
309 return most_visited_items_cache_.GetItemWithRestrictedID(most_visited_item_id,
310 item);
313 const ThemeBackgroundInfo& SearchBox::GetThemeBackgroundInfo() {
314 return theme_info_;
317 const EmbeddedSearchRequestParams& SearchBox::GetEmbeddedSearchRequestParams() {
318 return embedded_search_request_params_;
321 void SearchBox::Focus() {
322 render_view()->Send(new ChromeViewHostMsg_FocusOmnibox(
323 render_view()->GetRoutingID(), page_seq_no_, OMNIBOX_FOCUS_VISIBLE));
326 void SearchBox::NavigateToURL(const GURL& url,
327 WindowOpenDisposition disposition,
328 bool is_most_visited_item_url) {
329 render_view()->Send(new ChromeViewHostMsg_SearchBoxNavigate(
330 render_view()->GetRoutingID(), page_seq_no_, url,
331 disposition, is_most_visited_item_url));
334 void SearchBox::Paste(const base::string16& text) {
335 render_view()->Send(new ChromeViewHostMsg_PasteAndOpenDropdown(
336 render_view()->GetRoutingID(), page_seq_no_, text));
339 void SearchBox::SetVoiceSearchSupported(bool supported) {
340 render_view()->Send(new ChromeViewHostMsg_SetVoiceSearchSupported(
341 render_view()->GetRoutingID(), page_seq_no_, supported));
344 void SearchBox::StartCapturingKeyStrokes() {
345 render_view()->Send(new ChromeViewHostMsg_FocusOmnibox(
346 render_view()->GetRoutingID(), page_seq_no_, OMNIBOX_FOCUS_INVISIBLE));
349 void SearchBox::StopCapturingKeyStrokes() {
350 render_view()->Send(new ChromeViewHostMsg_FocusOmnibox(
351 render_view()->GetRoutingID(), page_seq_no_, OMNIBOX_FOCUS_NONE));
354 void SearchBox::UndoAllMostVisitedDeletions() {
355 render_view()->Send(
356 new ChromeViewHostMsg_SearchBoxUndoAllMostVisitedDeletions(
357 render_view()->GetRoutingID(), page_seq_no_));
360 void SearchBox::UndoMostVisitedDeletion(
361 InstantRestrictedID most_visited_item_id) {
362 render_view()->Send(new ChromeViewHostMsg_SearchBoxUndoMostVisitedDeletion(
363 render_view()->GetRoutingID(), page_seq_no_,
364 GetURLForMostVisitedItem(most_visited_item_id)));
367 bool SearchBox::OnMessageReceived(const IPC::Message& message) {
368 bool handled = true;
369 IPC_BEGIN_MESSAGE_MAP(SearchBox, message)
370 IPC_MESSAGE_HANDLER(ChromeViewMsg_SetPageSequenceNumber,
371 OnSetPageSequenceNumber)
372 IPC_MESSAGE_HANDLER(ChromeViewMsg_ChromeIdentityCheckResult,
373 OnChromeIdentityCheckResult)
374 IPC_MESSAGE_HANDLER(ChromeViewMsg_DetermineIfPageSupportsInstant,
375 OnDetermineIfPageSupportsInstant)
376 IPC_MESSAGE_HANDLER(ChromeViewMsg_HistorySyncCheckResult,
377 OnHistorySyncCheckResult)
378 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxFocusChanged, OnFocusChanged)
379 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxMarginChange, OnMarginChange)
380 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxMostVisitedItemsChanged,
381 OnMostVisitedChanged)
382 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxPromoInformation,
383 OnPromoInformationReceived)
384 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSetDisplayInstantResults,
385 OnSetDisplayInstantResults)
386 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSetInputInProgress,
387 OnSetInputInProgress)
388 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSetSuggestionToPrefetch,
389 OnSetSuggestionToPrefetch)
390 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxSubmit, OnSubmit)
391 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxThemeChanged,
392 OnThemeChanged)
393 IPC_MESSAGE_HANDLER(ChromeViewMsg_SearchBoxToggleVoiceSearch,
394 OnToggleVoiceSearch)
395 IPC_MESSAGE_UNHANDLED(handled = false)
396 IPC_END_MESSAGE_MAP()
397 return handled;
400 void SearchBox::OnSetPageSequenceNumber(int page_seq_no) {
401 page_seq_no_ = page_seq_no;
404 void SearchBox::OnChromeIdentityCheckResult(const base::string16& identity,
405 bool identity_match) {
406 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
407 extensions_v8::SearchBoxExtension::DispatchChromeIdentityCheckResult(
408 render_view()->GetWebView()->mainFrame(), identity, identity_match);
412 void SearchBox::OnDetermineIfPageSupportsInstant() {
413 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
414 bool result = extensions_v8::SearchBoxExtension::PageSupportsInstant(
415 render_view()->GetWebView()->mainFrame());
416 DVLOG(1) << render_view() << " PageSupportsInstant: " << result;
417 render_view()->Send(new ChromeViewHostMsg_InstantSupportDetermined(
418 render_view()->GetRoutingID(), page_seq_no_, result));
422 void SearchBox::OnFocusChanged(OmniboxFocusState new_focus_state,
423 OmniboxFocusChangeReason reason) {
424 bool key_capture_enabled = new_focus_state == OMNIBOX_FOCUS_INVISIBLE;
425 if (key_capture_enabled != is_key_capture_enabled_) {
426 // Tell the page if the key capture mode changed unless the focus state
427 // changed because of TYPING. This is because in that case, the browser
428 // hasn't really stopped capturing key strokes.
430 // (More practically, if we don't do this check, the page would receive
431 // onkeycapturechange before the corresponding onchange, and the page would
432 // have no way of telling whether the keycapturechange happened because of
433 // some actual user action or just because they started typing.)
434 if (reason != OMNIBOX_FOCUS_CHANGE_TYPING &&
435 render_view()->GetWebView() &&
436 render_view()->GetWebView()->mainFrame()) {
437 is_key_capture_enabled_ = key_capture_enabled;
438 DVLOG(1) << render_view() << " OnKeyCaptureChange";
439 extensions_v8::SearchBoxExtension::DispatchKeyCaptureChange(
440 render_view()->GetWebView()->mainFrame());
443 bool is_focused = new_focus_state == OMNIBOX_FOCUS_VISIBLE;
444 if (is_focused != is_focused_) {
445 is_focused_ = is_focused;
446 DVLOG(1) << render_view() << " OnFocusChange";
447 if (render_view()->GetWebView() &&
448 render_view()->GetWebView()->mainFrame()) {
449 extensions_v8::SearchBoxExtension::DispatchFocusChange(
450 render_view()->GetWebView()->mainFrame());
455 void SearchBox::OnHistorySyncCheckResult(bool sync_history) {
456 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
457 extensions_v8::SearchBoxExtension::DispatchHistorySyncCheckResult(
458 render_view()->GetWebView()->mainFrame(), sync_history);
462 void SearchBox::OnMarginChange(int margin) {
463 start_margin_ = margin;
464 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
465 extensions_v8::SearchBoxExtension::DispatchMarginChange(
466 render_view()->GetWebView()->mainFrame());
470 void SearchBox::OnMostVisitedChanged(
471 const std::vector<InstantMostVisitedItem>& items) {
472 std::vector<InstantMostVisitedItemIDPair> last_known_items;
473 GetMostVisitedItems(&last_known_items);
475 if (AreMostVisitedItemsEqual(last_known_items, items))
476 return; // Do not send duplicate onmostvisitedchange events.
478 most_visited_items_cache_.AddItems(items);
479 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
480 extensions_v8::SearchBoxExtension::DispatchMostVisitedChanged(
481 render_view()->GetWebView()->mainFrame());
485 void SearchBox::OnPromoInformationReceived(bool is_app_launcher_enabled) {
486 app_launcher_enabled_ = is_app_launcher_enabled;
489 void SearchBox::OnSetDisplayInstantResults(bool display_instant_results) {
490 display_instant_results_ = display_instant_results;
493 void SearchBox::OnSetInputInProgress(bool is_input_in_progress) {
494 if (is_input_in_progress_ != is_input_in_progress) {
495 is_input_in_progress_ = is_input_in_progress;
496 DVLOG(1) << render_view() << " OnSetInputInProgress";
497 if (render_view()->GetWebView() &&
498 render_view()->GetWebView()->mainFrame()) {
499 if (is_input_in_progress_) {
500 extensions_v8::SearchBoxExtension::DispatchInputStart(
501 render_view()->GetWebView()->mainFrame());
502 } else {
503 extensions_v8::SearchBoxExtension::DispatchInputCancel(
504 render_view()->GetWebView()->mainFrame());
510 void SearchBox::OnSetSuggestionToPrefetch(const InstantSuggestion& suggestion) {
511 suggestion_ = suggestion;
512 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
513 DVLOG(1) << render_view() << " OnSetSuggestionToPrefetch";
514 extensions_v8::SearchBoxExtension::DispatchSuggestionChange(
515 render_view()->GetWebView()->mainFrame());
519 void SearchBox::OnSubmit(const base::string16& query,
520 const EmbeddedSearchRequestParams& params) {
521 query_ = query;
522 embedded_search_request_params_ = params;
523 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
524 DVLOG(1) << render_view() << " OnSubmit";
525 extensions_v8::SearchBoxExtension::DispatchSubmit(
526 render_view()->GetWebView()->mainFrame());
528 if (!query.empty())
529 Reset();
532 void SearchBox::OnThemeChanged(const ThemeBackgroundInfo& theme_info) {
533 // Do not send duplicate notifications.
534 if (theme_info_ == theme_info)
535 return;
537 theme_info_ = theme_info;
538 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
539 extensions_v8::SearchBoxExtension::DispatchThemeChange(
540 render_view()->GetWebView()->mainFrame());
544 void SearchBox::OnToggleVoiceSearch() {
545 if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame()) {
546 extensions_v8::SearchBoxExtension::DispatchToggleVoiceSearch(
547 render_view()->GetWebView()->mainFrame());
551 GURL SearchBox::GetURLForMostVisitedItem(InstantRestrictedID item_id) const {
552 InstantMostVisitedItem item;
553 return GetMostVisitedItemWithID(item_id, &item) ? item.url : GURL();
556 void SearchBox::Reset() {
557 query_.clear();
558 embedded_search_request_params_ = EmbeddedSearchRequestParams();
559 suggestion_ = InstantSuggestion();
560 start_margin_ = 0;
561 is_focused_ = false;
562 is_key_capture_enabled_ = false;
563 theme_info_ = ThemeBackgroundInfo();