Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / renderer / searchbox / searchbox_extension.cc
blob17e7bf15a118c7bc1cc64b0afbdc8239a520900a
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_extension.h"
7 #include "base/command_line.h"
8 #include "base/i18n/rtl.h"
9 #include "base/json/string_escape.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/common/instant_types.h"
16 #include "chrome/common/ntp_logging_events.h"
17 #include "chrome/common/url_constants.h"
18 #include "chrome/grit/renderer_resources.h"
19 #include "chrome/renderer/searchbox/searchbox.h"
20 #include "components/crx_file/id_util.h"
21 #include "content/public/renderer/render_view.h"
22 #include "third_party/WebKit/public/platform/WebURLRequest.h"
23 #include "third_party/WebKit/public/web/WebDocument.h"
24 #include "third_party/WebKit/public/web/WebLocalFrame.h"
25 #include "third_party/WebKit/public/web/WebScriptSource.h"
26 #include "third_party/WebKit/public/web/WebView.h"
27 #include "ui/base/resource/resource_bundle.h"
28 #include "ui/base/ui_base_switches.h"
29 #include "ui/base/window_open_disposition.h"
30 #include "ui/events/keycodes/keyboard_codes.h"
31 #include "url/gurl.h"
32 #include "url/url_constants.h"
33 #include "v8/include/v8.h"
35 namespace {
37 const char kCSSBackgroundImageFormat[] = "-webkit-image-set("
38 "url(chrome-search://theme/IDR_THEME_NTP_BACKGROUND?%s) 1x, "
39 "url(chrome-search://theme/IDR_THEME_NTP_BACKGROUND@2x?%s) 2x)";
41 const char kCSSBackgroundColorFormat[] = "rgba(%d,%d,%d,%s)";
43 const char kCSSBackgroundPositionCenter[] = "center";
44 const char kCSSBackgroundPositionLeft[] = "left";
45 const char kCSSBackgroundPositionTop[] = "top";
46 const char kCSSBackgroundPositionRight[] = "right";
47 const char kCSSBackgroundPositionBottom[] = "bottom";
49 const char kCSSBackgroundRepeatNo[] = "no-repeat";
50 const char kCSSBackgroundRepeatX[] = "repeat-x";
51 const char kCSSBackgroundRepeatY[] = "repeat-y";
52 const char kCSSBackgroundRepeat[] = "repeat";
54 const char kThemeAttributionFormat[] = "-webkit-image-set("
55 "url(chrome-search://theme/IDR_THEME_NTP_ATTRIBUTION?%s) 1x, "
56 "url(chrome-search://theme/IDR_THEME_NTP_ATTRIBUTION@2x?%s) 2x)";
58 const char kLTRHtmlTextDirection[] = "ltr";
59 const char kRTLHtmlTextDirection[] = "rtl";
61 // Converts a V8 value to a string16.
62 base::string16 V8ValueToUTF16(v8::Local<v8::Value> v) {
63 v8::String::Value s(v);
64 return base::string16(reinterpret_cast<const base::char16*>(*s), s.length());
67 // Returns whether icon NTP is enabled by experiment.
68 // TODO(huangs): Remove all 3 copies of this routine once Icon NTP launches.
69 bool IsIconNTPEnabled() {
70 // Note: It's important to query the field trial state first, to ensure that
71 // UMA reports the correct group.
72 const std::string group_name = base::FieldTrialList::FindFullName("IconNTP");
73 using base::CommandLine;
74 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableIconNtp))
75 return false;
76 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableIconNtp))
77 return true;
79 return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE);
82 // Converts string16 to V8 String.
83 v8::Local<v8::String> UTF16ToV8String(v8::Isolate* isolate,
84 const base::string16& s) {
85 return v8::String::NewFromTwoByte(isolate,
86 reinterpret_cast<const uint16_t*>(s.data()),
87 v8::String::kNormalString,
88 s.size());
91 // Converts std::string to V8 String.
92 v8::Local<v8::String> UTF8ToV8String(v8::Isolate* isolate,
93 const std::string& s) {
94 return v8::String::NewFromUtf8(
95 isolate, s.data(), v8::String::kNormalString, s.size());
98 // Throws a TypeError on the current V8 context if the args are invalid.
99 void ThrowInvalidParameters(const v8::FunctionCallbackInfo<v8::Value>& args) {
100 v8::Isolate* isolate = args.GetIsolate();
101 isolate->ThrowException(v8::Exception::TypeError(
102 v8::String::NewFromUtf8(isolate, "Invalid parameters")));
105 void Dispatch(blink::WebFrame* frame, const blink::WebString& script) {
106 if (!frame) return;
107 frame->executeScript(blink::WebScriptSource(script));
110 v8::Local<v8::String> GenerateThumbnailURL(
111 v8::Isolate* isolate,
112 int render_view_id,
113 InstantRestrictedID most_visited_item_id) {
114 return UTF8ToV8String(
115 isolate,
116 base::StringPrintf(
117 "chrome-search://thumb/%d/%d", render_view_id, most_visited_item_id));
120 // Populates a Javascript MostVisitedItem object from |mv_item|.
121 // NOTE: Includes "url", "title" and "domain" which are private data, so should
122 // not be returned to the Instant page. These should be erased before returning
123 // the object. See GetMostVisitedItemsWrapper() in searchbox_api.js.
124 v8::Local<v8::Object> GenerateMostVisitedItem(
125 v8::Isolate* isolate,
126 int render_view_id,
127 InstantRestrictedID restricted_id,
128 const InstantMostVisitedItem& mv_item) {
129 // We set the "dir" attribute of the title, so that in RTL locales, a LTR
130 // title is rendered left-to-right and truncated from the right. For
131 // example, the title of http://msdn.microsoft.com/en-us/default.aspx is
132 // "MSDN: Microsoft developer network". In RTL locales, in the New Tab
133 // page, if the "dir" of this title is not specified, it takes Chrome UI's
134 // directionality. So the title will be truncated as "soft developer
135 // network". Setting the "dir" attribute as "ltr" renders the truncated
136 // title as "MSDN: Microsoft D...". As another example, the title of
137 // http://yahoo.com is "Yahoo!". In RTL locales, in the New Tab page, the
138 // title will be rendered as "!Yahoo" if its "dir" attribute is not set to
139 // "ltr".
140 std::string direction;
141 if (base::i18n::StringContainsStrongRTLChars(mv_item.title))
142 direction = kRTLHtmlTextDirection;
143 else
144 direction = kLTRHtmlTextDirection;
146 base::string16 title = mv_item.title;
147 if (title.empty())
148 title = base::UTF8ToUTF16(mv_item.url.spec());
150 v8::Local<v8::Object> obj = v8::Object::New(isolate);
151 obj->Set(v8::String::NewFromUtf8(isolate, "renderViewId"),
152 v8::Int32::New(isolate, render_view_id));
153 obj->Set(v8::String::NewFromUtf8(isolate, "rid"),
154 v8::Int32::New(isolate, restricted_id));
155 obj->Set(v8::String::NewFromUtf8(isolate, "thumbnailUrl"),
156 GenerateThumbnailURL(isolate, render_view_id, restricted_id));
157 if (IsIconNTPEnabled()) {
158 // Update website http://www.chromium.org/embeddedsearch when we make this
159 // permanent.
160 // Large icon size is 48px * window.devicePixelRatio. This is easier to set
161 // from JS, where IsIconNTPEnabled() is not available. So we add stubs
162 // here, and let JS fill in details.
163 obj->Set(v8::String::NewFromUtf8(isolate, "largeIconUrl"),
164 v8::String::NewFromUtf8(isolate, "chrome-search://large-icon/"));
165 obj->Set(v8::String::NewFromUtf8(isolate, "fallbackIconUrl"),
166 v8::String::NewFromUtf8(isolate, "chrome-search://fallback-icon/"));
168 obj->Set(v8::String::NewFromUtf8(isolate, "title"),
169 UTF16ToV8String(isolate, title));
170 obj->Set(v8::String::NewFromUtf8(isolate, "domain"),
171 UTF8ToV8String(isolate, mv_item.url.host()));
172 obj->Set(v8::String::NewFromUtf8(isolate, "direction"),
173 UTF8ToV8String(isolate, direction));
174 obj->Set(v8::String::NewFromUtf8(isolate, "url"),
175 UTF8ToV8String(isolate, mv_item.url.spec()));
176 return obj;
179 // Returns the render view for the current JS context if it matches |origin|,
180 // otherwise returns NULL. Used to restrict methods that access suggestions and
181 // most visited data to pages with origin chrome-search://most-visited and
182 // chrome-search://suggestions.
183 content::RenderView* GetRenderViewWithCheckedOrigin(const GURL& origin) {
184 blink::WebLocalFrame* webframe =
185 blink::WebLocalFrame::frameForCurrentContext();
186 if (!webframe)
187 return NULL;
188 blink::WebView* webview = webframe->view();
189 if (!webview)
190 return NULL; // Can happen during closing.
191 content::RenderView* render_view = content::RenderView::FromWebView(webview);
192 if (!render_view)
193 return NULL;
195 GURL url(webframe->document().url());
196 if (url.GetOrigin() != origin.GetOrigin())
197 return NULL;
199 return render_view;
202 // Returns the current URL.
203 GURL GetCurrentURL(content::RenderView* render_view) {
204 blink::WebView* webview = render_view->GetWebView();
205 return webview ? GURL(webview->mainFrame()->document().url()) : GURL();
208 } // namespace
210 namespace internal { // for testing.
212 // Returns an array with the RGBA color components.
213 v8::Local<v8::Value> RGBAColorToArray(v8::Isolate* isolate,
214 const RGBAColor& color) {
215 v8::Local<v8::Array> color_array = v8::Array::New(isolate, 4);
216 color_array->Set(0, v8::Int32::New(isolate, color.r));
217 color_array->Set(1, v8::Int32::New(isolate, color.g));
218 color_array->Set(2, v8::Int32::New(isolate, color.b));
219 color_array->Set(3, v8::Int32::New(isolate, color.a));
220 return color_array;
223 // Resolves a possibly relative URL using the current URL.
224 GURL ResolveURL(const GURL& current_url,
225 const base::string16& possibly_relative_url) {
226 if (current_url.is_valid() && !possibly_relative_url.empty())
227 return current_url.Resolve(possibly_relative_url);
228 return GURL(possibly_relative_url);
231 } // namespace internal
233 namespace extensions_v8 {
235 static const char kSearchBoxExtensionName[] = "v8/EmbeddedSearch";
237 // We first send this script down to determine if the page supports instant.
238 static const char kSupportsInstantScript[] =
239 "if (window.chrome &&"
240 " window.chrome.embeddedSearch &&"
241 " window.chrome.embeddedSearch.searchBox &&"
242 " window.chrome.embeddedSearch.searchBox.onsubmit &&"
243 " typeof window.chrome.embeddedSearch.searchBox.onsubmit =="
244 " 'function') {"
245 " true;"
246 "} else {"
247 " false;"
248 "}";
250 static const char kDispatchChromeIdentityCheckResult[] =
251 "if (window.chrome &&"
252 " window.chrome.embeddedSearch &&"
253 " window.chrome.embeddedSearch.newTabPage &&"
254 " window.chrome.embeddedSearch.newTabPage.onsignedincheckdone &&"
255 " typeof window.chrome.embeddedSearch.newTabPage"
256 " .onsignedincheckdone === 'function') {"
257 " window.chrome.embeddedSearch.newTabPage.onsignedincheckdone(%s, %s);"
258 " true;"
259 "}";
261 static const char kDispatchFocusChangedScript[] =
262 "if (window.chrome &&"
263 " window.chrome.embeddedSearch &&"
264 " window.chrome.embeddedSearch.searchBox &&"
265 " window.chrome.embeddedSearch.searchBox.onfocuschange &&"
266 " typeof window.chrome.embeddedSearch.searchBox.onfocuschange =="
267 " 'function') {"
268 " window.chrome.embeddedSearch.searchBox.onfocuschange();"
269 " true;"
270 "}";
272 static const char kDispatchHistorySyncCheckResult[] =
273 "if (window.chrome &&"
274 " window.chrome.embeddedSearch &&"
275 " window.chrome.embeddedSearch.newTabPage &&"
276 " window.chrome.embeddedSearch.newTabPage.onhistorysynccheckdone &&"
277 " typeof window.chrome.embeddedSearch.newTabPage"
278 " .onhistorysynccheckdone === 'function') {"
279 " window.chrome.embeddedSearch.newTabPage.onhistorysynccheckdone(%s);"
280 " true;"
281 "}";
283 static const char kDispatchInputCancelScript[] =
284 "if (window.chrome &&"
285 " window.chrome.embeddedSearch &&"
286 " window.chrome.embeddedSearch.newTabPage &&"
287 " window.chrome.embeddedSearch.newTabPage.oninputcancel &&"
288 " typeof window.chrome.embeddedSearch.newTabPage.oninputcancel =="
289 " 'function') {"
290 " window.chrome.embeddedSearch.newTabPage.oninputcancel();"
291 " true;"
292 "}";
294 static const char kDispatchInputStartScript[] =
295 "if (window.chrome &&"
296 " window.chrome.embeddedSearch &&"
297 " window.chrome.embeddedSearch.newTabPage &&"
298 " window.chrome.embeddedSearch.newTabPage.oninputstart &&"
299 " typeof window.chrome.embeddedSearch.newTabPage.oninputstart =="
300 " 'function') {"
301 " window.chrome.embeddedSearch.newTabPage.oninputstart();"
302 " true;"
303 "}";
305 static const char kDispatchKeyCaptureChangeScript[] =
306 "if (window.chrome &&"
307 " window.chrome.embeddedSearch &&"
308 " window.chrome.embeddedSearch.searchBox &&"
309 " window.chrome.embeddedSearch.searchBox.onkeycapturechange &&"
310 " typeof window.chrome.embeddedSearch.searchBox.onkeycapturechange =="
311 " 'function') {"
312 " window.chrome.embeddedSearch.searchBox.onkeycapturechange();"
313 " true;"
314 "}";
316 static const char kDispatchMarginChangeEventScript[] =
317 "if (window.chrome &&"
318 " window.chrome.embeddedSearch &&"
319 " window.chrome.embeddedSearch.searchBox &&"
320 " window.chrome.embeddedSearch.searchBox.onmarginchange &&"
321 " typeof window.chrome.embeddedSearch.searchBox.onmarginchange =="
322 " 'function') {"
323 " window.chrome.embeddedSearch.searchBox.onmarginchange();"
324 " true;"
325 "}";
327 static const char kDispatchMostVisitedChangedScript[] =
328 "if (window.chrome &&"
329 " window.chrome.embeddedSearch &&"
330 " window.chrome.embeddedSearch.newTabPage &&"
331 " window.chrome.embeddedSearch.newTabPage.onmostvisitedchange &&"
332 " typeof window.chrome.embeddedSearch.newTabPage.onmostvisitedchange =="
333 " 'function') {"
334 " window.chrome.embeddedSearch.newTabPage.onmostvisitedchange();"
335 " true;"
336 "}";
338 static const char kDispatchSubmitEventScript[] =
339 "if (window.chrome &&"
340 " window.chrome.embeddedSearch &&"
341 " window.chrome.embeddedSearch.searchBox &&"
342 " window.chrome.embeddedSearch.searchBox.onsubmit &&"
343 " typeof window.chrome.embeddedSearch.searchBox.onsubmit =="
344 " 'function') {"
345 " window.chrome.embeddedSearch.searchBox.onsubmit();"
346 " true;"
347 "}";
349 static const char kDispatchSuggestionChangeEventScript[] =
350 "if (window.chrome &&"
351 " window.chrome.embeddedSearch &&"
352 " window.chrome.embeddedSearch.searchBox &&"
353 " window.chrome.embeddedSearch.searchBox.onsuggestionchange &&"
354 " typeof window.chrome.embeddedSearch.searchBox.onsuggestionchange =="
355 " 'function') {"
356 " window.chrome.embeddedSearch.searchBox.onsuggestionchange();"
357 " true;"
358 "}";
360 static const char kDispatchThemeChangeEventScript[] =
361 "if (window.chrome &&"
362 " window.chrome.embeddedSearch &&"
363 " window.chrome.embeddedSearch.newTabPage &&"
364 " window.chrome.embeddedSearch.newTabPage.onthemechange &&"
365 " typeof window.chrome.embeddedSearch.newTabPage.onthemechange =="
366 " 'function') {"
367 " window.chrome.embeddedSearch.newTabPage.onthemechange();"
368 " true;"
369 "}";
371 static const char kDispatchToggleVoiceSearchScript[] =
372 "if (window.chrome &&"
373 " window.chrome.embeddedSearch &&"
374 " window.chrome.embeddedSearch.searchBox &&"
375 " window.chrome.embeddedSearch.searchBox.ontogglevoicesearch &&"
376 " typeof window.chrome.embeddedSearch.searchBox.ontogglevoicesearch =="
377 " 'function') {"
378 " window.chrome.embeddedSearch.searchBox.ontogglevoicesearch();"
379 " true;"
380 "}";
382 // ----------------------------------------------------------------------------
384 class SearchBoxExtensionWrapper : public v8::Extension {
385 public:
386 explicit SearchBoxExtensionWrapper(const base::StringPiece& code);
388 // Allows v8's javascript code to call the native functions defined
389 // in this class for window.chrome.
390 v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
391 v8::Isolate*,
392 v8::Local<v8::String> name) override;
394 // Helper function to find the RenderView. May return NULL.
395 static content::RenderView* GetRenderView();
397 // Sends a Chrome identity check to the browser.
398 static void CheckIsUserSignedInToChromeAs(
399 const v8::FunctionCallbackInfo<v8::Value>& args);
401 // Checks whether the user sync his history.
402 static void CheckIsUserSyncingHistory(
403 const v8::FunctionCallbackInfo<v8::Value>& args);
405 // Deletes a Most Visited item.
406 static void DeleteMostVisitedItem(
407 const v8::FunctionCallbackInfo<v8::Value>& args);
409 // Focuses the omnibox.
410 static void Focus(const v8::FunctionCallbackInfo<v8::Value>& args);
412 // Gets whether or not the app launcher is enabled.
413 static void GetAppLauncherEnabled(
414 const v8::FunctionCallbackInfo<v8::Value>& args);
416 // Gets the desired navigation behavior from a click event.
417 static void GetDispositionFromClick(
418 const v8::FunctionCallbackInfo<v8::Value>& args);
420 // Gets Most Visited Items.
421 static void GetMostVisitedItems(
422 const v8::FunctionCallbackInfo<v8::Value>& args);
424 // Gets the raw data for a most visited item including its raw URL.
425 // GetRenderViewWithCheckedOrigin() enforces that only code in the origin
426 // chrome-search://most-visited can call this function.
427 static void GetMostVisitedItemData(
428 const v8::FunctionCallbackInfo<v8::Value>& args);
430 // Gets the submitted value of the user's search query.
431 static void GetQuery(const v8::FunctionCallbackInfo<v8::Value>& args);
433 // Returns true if the Searchbox itself is oriented right-to-left.
434 static void GetRightToLeft(const v8::FunctionCallbackInfo<v8::Value>& args);
436 // Gets the Embedded Search request params. Used for logging purposes.
437 static void GetSearchRequestParams(
438 const v8::FunctionCallbackInfo<v8::Value>& args);
440 // Gets the start-edge margin to use with extended Instant.
441 static void GetStartMargin(const v8::FunctionCallbackInfo<v8::Value>& args);
443 // Gets the current top suggestion to prefetch search results.
444 static void GetSuggestionToPrefetch(
445 const v8::FunctionCallbackInfo<v8::Value>& args);
447 // Gets the background info of the theme currently adopted by browser.
448 // Call only when overlay is showing NTP page.
449 static void GetThemeBackgroundInfo(
450 const v8::FunctionCallbackInfo<v8::Value>& args);
452 // Gets whether the omnibox has focus or not.
453 static void IsFocused(const v8::FunctionCallbackInfo<v8::Value>& args);
455 // Gets whether user input is in progress.
456 static void IsInputInProgress(
457 const v8::FunctionCallbackInfo<v8::Value>& args);
459 // Gets whether the browser is capturing key strokes.
460 static void IsKeyCaptureEnabled(
461 const v8::FunctionCallbackInfo<v8::Value>& args);
463 // Logs information from the iframes/titles on the NTP.
464 static void LogEvent(const v8::FunctionCallbackInfo<v8::Value>& args);
466 // Logs an impression on one of the Most Visited tile on the NTP.
467 static void LogMostVisitedImpression(
468 const v8::FunctionCallbackInfo<v8::Value>& args);
470 // Logs a navigation on one of the Most Visited tile on the NTP.
471 static void LogMostVisitedNavigation(
472 const v8::FunctionCallbackInfo<v8::Value>& args);
474 // Navigates the window to a URL represented by either a URL string or a
475 // restricted ID.
476 static void NavigateContentWindow(
477 const v8::FunctionCallbackInfo<v8::Value>& args);
479 // Pastes provided value or clipboard's content into the omnibox.
480 static void Paste(const v8::FunctionCallbackInfo<v8::Value>& args);
482 // Indicates whether the page supports voice search.
483 static void SetVoiceSearchSupported(
484 const v8::FunctionCallbackInfo<v8::Value>& args);
486 // Start capturing user key strokes.
487 static void StartCapturingKeyStrokes(
488 const v8::FunctionCallbackInfo<v8::Value>& args);
490 // Stop capturing user key strokes.
491 static void StopCapturingKeyStrokes(
492 const v8::FunctionCallbackInfo<v8::Value>& args);
494 // Undoes the deletion of all Most Visited itens.
495 static void UndoAllMostVisitedDeletions(
496 const v8::FunctionCallbackInfo<v8::Value>& args);
498 // Undoes the deletion of a Most Visited item.
499 static void UndoMostVisitedDeletion(
500 const v8::FunctionCallbackInfo<v8::Value>& args);
502 // Indicates whether the page supports Instant.
503 static void GetDisplayInstantResults(
504 const v8::FunctionCallbackInfo<v8::Value>& args);
506 private:
507 DISALLOW_COPY_AND_ASSIGN(SearchBoxExtensionWrapper);
510 // static
511 v8::Extension* SearchBoxExtension::Get() {
512 return new SearchBoxExtensionWrapper(ResourceBundle::GetSharedInstance().
513 GetRawDataResource(IDR_SEARCHBOX_API));
516 // static
517 bool SearchBoxExtension::PageSupportsInstant(blink::WebFrame* frame) {
518 if (!frame) return false;
519 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
520 v8::Local<v8::Value> v = frame->executeScriptAndReturnValue(
521 blink::WebScriptSource(kSupportsInstantScript));
522 return !v.IsEmpty() && v->BooleanValue();
525 // static
526 void SearchBoxExtension::DispatchChromeIdentityCheckResult(
527 blink::WebFrame* frame,
528 const base::string16& identity,
529 bool identity_match) {
530 std::string escaped_identity = base::GetQuotedJSONString(identity);
531 blink::WebString script(base::UTF8ToUTF16(base::StringPrintf(
532 kDispatchChromeIdentityCheckResult,
533 escaped_identity.c_str(),
534 identity_match ? "true" : "false")));
535 Dispatch(frame, script);
538 // static
539 void SearchBoxExtension::DispatchFocusChange(blink::WebFrame* frame) {
540 Dispatch(frame, kDispatchFocusChangedScript);
543 // static
544 void SearchBoxExtension::DispatchHistorySyncCheckResult(
545 blink::WebFrame* frame,
546 bool sync_history) {
547 blink::WebString script(base::UTF8ToUTF16(base::StringPrintf(
548 kDispatchHistorySyncCheckResult,
549 sync_history ? "true" : "false")));
550 Dispatch(frame, script);
553 // static
554 void SearchBoxExtension::DispatchInputCancel(blink::WebFrame* frame) {
555 Dispatch(frame, kDispatchInputCancelScript);
558 // static
559 void SearchBoxExtension::DispatchInputStart(blink::WebFrame* frame) {
560 Dispatch(frame, kDispatchInputStartScript);
563 // static
564 void SearchBoxExtension::DispatchKeyCaptureChange(blink::WebFrame* frame) {
565 Dispatch(frame, kDispatchKeyCaptureChangeScript);
568 // static
569 void SearchBoxExtension::DispatchMarginChange(blink::WebFrame* frame) {
570 Dispatch(frame, kDispatchMarginChangeEventScript);
573 // static
574 void SearchBoxExtension::DispatchMostVisitedChanged(
575 blink::WebFrame* frame) {
576 Dispatch(frame, kDispatchMostVisitedChangedScript);
579 // static
580 void SearchBoxExtension::DispatchSubmit(blink::WebFrame* frame) {
581 Dispatch(frame, kDispatchSubmitEventScript);
584 // static
585 void SearchBoxExtension::DispatchSuggestionChange(blink::WebFrame* frame) {
586 Dispatch(frame, kDispatchSuggestionChangeEventScript);
589 // static
590 void SearchBoxExtension::DispatchThemeChange(blink::WebFrame* frame) {
591 Dispatch(frame, kDispatchThemeChangeEventScript);
594 // static
595 void SearchBoxExtension::DispatchToggleVoiceSearch(
596 blink::WebFrame* frame) {
597 Dispatch(frame, kDispatchToggleVoiceSearchScript);
600 SearchBoxExtensionWrapper::SearchBoxExtensionWrapper(
601 const base::StringPiece& code)
602 : v8::Extension(kSearchBoxExtensionName, code.data(), 0, 0, code.size()) {
605 v8::Local<v8::FunctionTemplate>
606 SearchBoxExtensionWrapper::GetNativeFunctionTemplate(
607 v8::Isolate* isolate,
608 v8::Local<v8::String> name) {
609 if (name->Equals(
610 v8::String::NewFromUtf8(isolate, "CheckIsUserSignedInToChromeAs")))
611 return v8::FunctionTemplate::New(isolate, CheckIsUserSignedInToChromeAs);
612 if (name->Equals(
613 v8::String::NewFromUtf8(isolate, "CheckIsUserSyncingHistory")))
614 return v8::FunctionTemplate::New(isolate, CheckIsUserSyncingHistory);
615 if (name->Equals(v8::String::NewFromUtf8(isolate, "DeleteMostVisitedItem")))
616 return v8::FunctionTemplate::New(isolate, DeleteMostVisitedItem);
617 if (name->Equals(v8::String::NewFromUtf8(isolate, "Focus")))
618 return v8::FunctionTemplate::New(isolate, Focus);
619 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetAppLauncherEnabled")))
620 return v8::FunctionTemplate::New(isolate, GetAppLauncherEnabled);
621 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetDispositionFromClick")))
622 return v8::FunctionTemplate::New(isolate, GetDispositionFromClick);
623 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetMostVisitedItems")))
624 return v8::FunctionTemplate::New(isolate, GetMostVisitedItems);
625 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetMostVisitedItemData")))
626 return v8::FunctionTemplate::New(isolate, GetMostVisitedItemData);
627 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetQuery")))
628 return v8::FunctionTemplate::New(isolate, GetQuery);
629 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetRightToLeft")))
630 return v8::FunctionTemplate::New(isolate, GetRightToLeft);
631 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetSearchRequestParams")))
632 return v8::FunctionTemplate::New(isolate, GetSearchRequestParams);
633 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetStartMargin")))
634 return v8::FunctionTemplate::New(isolate, GetStartMargin);
635 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetSuggestionToPrefetch")))
636 return v8::FunctionTemplate::New(isolate, GetSuggestionToPrefetch);
637 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetThemeBackgroundInfo")))
638 return v8::FunctionTemplate::New(isolate, GetThemeBackgroundInfo);
639 if (name->Equals(v8::String::NewFromUtf8(isolate, "IsFocused")))
640 return v8::FunctionTemplate::New(isolate, IsFocused);
641 if (name->Equals(v8::String::NewFromUtf8(isolate, "IsInputInProgress")))
642 return v8::FunctionTemplate::New(isolate, IsInputInProgress);
643 if (name->Equals(v8::String::NewFromUtf8(isolate, "IsKeyCaptureEnabled")))
644 return v8::FunctionTemplate::New(isolate, IsKeyCaptureEnabled);
645 if (name->Equals(v8::String::NewFromUtf8(isolate, "LogEvent")))
646 return v8::FunctionTemplate::New(isolate, LogEvent);
647 if (name->Equals(
648 v8::String::NewFromUtf8(isolate, "LogMostVisitedImpression"))) {
649 return v8::FunctionTemplate::New(isolate, LogMostVisitedImpression);
651 if (name->Equals(
652 v8::String::NewFromUtf8(isolate, "LogMostVisitedNavigation"))) {
653 return v8::FunctionTemplate::New(isolate, LogMostVisitedNavigation);
655 if (name->Equals(v8::String::NewFromUtf8(isolate, "NavigateContentWindow")))
656 return v8::FunctionTemplate::New(isolate, NavigateContentWindow);
657 if (name->Equals(v8::String::NewFromUtf8(isolate, "Paste")))
658 return v8::FunctionTemplate::New(isolate, Paste);
659 if (name->Equals(v8::String::NewFromUtf8(isolate, "SetVoiceSearchSupported")))
660 return v8::FunctionTemplate::New(isolate, SetVoiceSearchSupported);
661 if (name->Equals(
662 v8::String::NewFromUtf8(isolate, "StartCapturingKeyStrokes")))
663 return v8::FunctionTemplate::New(isolate, StartCapturingKeyStrokes);
664 if (name->Equals(v8::String::NewFromUtf8(isolate, "StopCapturingKeyStrokes")))
665 return v8::FunctionTemplate::New(isolate, StopCapturingKeyStrokes);
666 if (name->Equals(
667 v8::String::NewFromUtf8(isolate, "UndoAllMostVisitedDeletions")))
668 return v8::FunctionTemplate::New(isolate, UndoAllMostVisitedDeletions);
669 if (name->Equals(v8::String::NewFromUtf8(isolate, "UndoMostVisitedDeletion")))
670 return v8::FunctionTemplate::New(isolate, UndoMostVisitedDeletion);
671 if (name->Equals(
672 v8::String::NewFromUtf8(isolate, "GetDisplayInstantResults")))
673 return v8::FunctionTemplate::New(isolate, GetDisplayInstantResults);
674 return v8::Local<v8::FunctionTemplate>();
677 // static
678 content::RenderView* SearchBoxExtensionWrapper::GetRenderView() {
679 blink::WebLocalFrame* webframe =
680 blink::WebLocalFrame::frameForCurrentContext();
681 if (!webframe) return NULL;
683 blink::WebView* webview = webframe->view();
684 if (!webview) return NULL; // can happen during closing
686 return content::RenderView::FromWebView(webview);
689 // static
690 void SearchBoxExtensionWrapper::CheckIsUserSignedInToChromeAs(
691 const v8::FunctionCallbackInfo<v8::Value>& args) {
692 content::RenderView* render_view = GetRenderView();
693 if (!render_view) return;
695 if (!args.Length() || args[0]->IsUndefined()) {
696 ThrowInvalidParameters(args);
697 return;
700 DVLOG(1) << render_view << " CheckIsUserSignedInToChromeAs";
702 SearchBox::Get(render_view)->CheckIsUserSignedInToChromeAs(
703 V8ValueToUTF16(args[0]));
706 // static
707 void SearchBoxExtensionWrapper::CheckIsUserSyncingHistory(
708 const v8::FunctionCallbackInfo<v8::Value>& args) {
709 content::RenderView* render_view = GetRenderView();
710 if (!render_view) return;
712 DVLOG(1) << render_view << " CheckIsUserSyncingHistory";
713 SearchBox::Get(render_view)->CheckIsUserSyncingHistory();
716 // static
717 void SearchBoxExtensionWrapper::DeleteMostVisitedItem(
718 const v8::FunctionCallbackInfo<v8::Value>& args) {
719 content::RenderView* render_view = GetRenderView();
720 if (!render_view) return;
722 if (!args.Length()) {
723 ThrowInvalidParameters(args);
724 return;
727 DVLOG(1) << render_view
728 << " DeleteMostVisitedItem: " << args[0]->ToInteger()->Value();
729 SearchBox::Get(render_view)->
730 DeleteMostVisitedItem(args[0]->ToInteger()->Value());
733 // static
734 void SearchBoxExtensionWrapper::Focus(
735 const v8::FunctionCallbackInfo<v8::Value>& args) {
736 content::RenderView* render_view = GetRenderView();
737 if (!render_view) return;
739 DVLOG(1) << render_view << " Focus";
740 SearchBox::Get(render_view)->Focus();
743 // static
744 void SearchBoxExtensionWrapper::GetAppLauncherEnabled(
745 const v8::FunctionCallbackInfo<v8::Value>& args) {
746 content::RenderView* render_view = GetRenderView();
747 if (!render_view) return;
749 args.GetReturnValue().Set(
750 SearchBox::Get(render_view)->app_launcher_enabled());
753 // static
754 void SearchBoxExtensionWrapper::GetDispositionFromClick(
755 const v8::FunctionCallbackInfo<v8::Value>& args) {
756 content::RenderView* render_view = GetRenderView();
757 if (!render_view) return;
759 if (args.Length() != 5) {
760 ThrowInvalidParameters(args);
761 return;
764 bool middle_button = args[0]->BooleanValue();
765 bool alt_key = args[1]->BooleanValue();
766 bool ctrl_key = args[2]->BooleanValue();
767 bool meta_key = args[3]->BooleanValue();
768 bool shift_key = args[4]->BooleanValue();
770 WindowOpenDisposition disposition = ui::DispositionFromClick(middle_button,
771 alt_key,
772 ctrl_key,
773 meta_key,
774 shift_key);
775 v8::Isolate* isolate = args.GetIsolate();
776 args.GetReturnValue().Set(v8::Int32::New(isolate, disposition));
779 // static
780 void SearchBoxExtensionWrapper::GetMostVisitedItems(
781 const v8::FunctionCallbackInfo<v8::Value>& args) {
782 content::RenderView* render_view = GetRenderView();
783 if (!render_view)
784 return;
785 DVLOG(1) << render_view << " GetMostVisitedItems";
787 const SearchBox* search_box = SearchBox::Get(render_view);
789 std::vector<InstantMostVisitedItemIDPair> instant_mv_items;
790 search_box->GetMostVisitedItems(&instant_mv_items);
791 v8::Isolate* isolate = args.GetIsolate();
792 v8::Local<v8::Array> v8_mv_items =
793 v8::Array::New(isolate, instant_mv_items.size());
794 for (size_t i = 0; i < instant_mv_items.size(); ++i) {
795 v8_mv_items->Set(i,
796 GenerateMostVisitedItem(isolate,
797 render_view->GetRoutingID(),
798 instant_mv_items[i].first,
799 instant_mv_items[i].second));
801 args.GetReturnValue().Set(v8_mv_items);
804 // static
805 void SearchBoxExtensionWrapper::GetMostVisitedItemData(
806 const v8::FunctionCallbackInfo<v8::Value>& args) {
807 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
808 GURL(chrome::kChromeSearchMostVisitedUrl));
809 if (!render_view) return;
811 // Need an rid argument.
812 if (!args.Length() || !args[0]->IsNumber()) {
813 ThrowInvalidParameters(args);
814 return;
817 DVLOG(1) << render_view << " GetMostVisitedItem";
818 InstantRestrictedID restricted_id = args[0]->IntegerValue();
819 InstantMostVisitedItem mv_item;
820 if (!SearchBox::Get(render_view)->GetMostVisitedItemWithID(
821 restricted_id, &mv_item)) {
822 return;
824 v8::Isolate* isolate = args.GetIsolate();
825 args.GetReturnValue().Set(GenerateMostVisitedItem(
826 isolate, render_view->GetRoutingID(), restricted_id, mv_item));
829 // static
830 void SearchBoxExtensionWrapper::GetQuery(
831 const v8::FunctionCallbackInfo<v8::Value>& args) {
832 content::RenderView* render_view = GetRenderView();
833 if (!render_view) return;
834 const base::string16& query = SearchBox::Get(render_view)->query();
835 DVLOG(1) << render_view << " GetQuery: '" << query << "'";
836 v8::Isolate* isolate = args.GetIsolate();
837 args.GetReturnValue().Set(UTF16ToV8String(isolate, query));
840 // static
841 void SearchBoxExtensionWrapper::GetRightToLeft(
842 const v8::FunctionCallbackInfo<v8::Value>& args) {
843 args.GetReturnValue().Set(base::i18n::IsRTL());
846 // static
847 void SearchBoxExtensionWrapper::GetSearchRequestParams(
848 const v8::FunctionCallbackInfo<v8::Value>& args) {
849 content::RenderView* render_view = GetRenderView();
850 if (!render_view) return;
852 const EmbeddedSearchRequestParams& params =
853 SearchBox::Get(render_view)->GetEmbeddedSearchRequestParams();
854 v8::Isolate* isolate = args.GetIsolate();
855 v8::Local<v8::Object> data = v8::Object::New(isolate);
856 if (!params.search_query.empty()) {
857 data->Set(v8::String::NewFromUtf8(isolate, kSearchQueryKey),
858 UTF16ToV8String(isolate, params.search_query));
860 if (!params.original_query.empty()) {
861 data->Set(v8::String::NewFromUtf8(isolate, kOriginalQueryKey),
862 UTF16ToV8String(isolate, params.original_query));
864 if (!params.rlz_parameter_value.empty()) {
865 data->Set(v8::String::NewFromUtf8(isolate, kRLZParameterKey),
866 UTF16ToV8String(isolate, params.rlz_parameter_value));
868 if (!params.input_encoding.empty()) {
869 data->Set(v8::String::NewFromUtf8(isolate, kInputEncodingKey),
870 UTF16ToV8String(isolate, params.input_encoding));
872 if (!params.assisted_query_stats.empty()) {
873 data->Set(v8::String::NewFromUtf8(isolate, kAssistedQueryStatsKey),
874 UTF16ToV8String(isolate, params.assisted_query_stats));
876 args.GetReturnValue().Set(data);
879 // static
880 void SearchBoxExtensionWrapper::GetStartMargin(
881 const v8::FunctionCallbackInfo<v8::Value>& args) {
882 content::RenderView* render_view = GetRenderView();
883 if (!render_view) return;
884 args.GetReturnValue().Set(static_cast<int32_t>(
885 SearchBox::Get(render_view)->start_margin()));
888 // static
889 void SearchBoxExtensionWrapper::GetSuggestionToPrefetch(
890 const v8::FunctionCallbackInfo<v8::Value>& args) {
891 content::RenderView* render_view = GetRenderView();
892 if (!render_view) return;
894 const InstantSuggestion& suggestion =
895 SearchBox::Get(render_view)->suggestion();
896 v8::Isolate* isolate = args.GetIsolate();
897 v8::Local<v8::Object> data = v8::Object::New(isolate);
898 data->Set(v8::String::NewFromUtf8(isolate, "text"),
899 UTF16ToV8String(isolate, suggestion.text));
900 data->Set(v8::String::NewFromUtf8(isolate, "metadata"),
901 UTF8ToV8String(isolate, suggestion.metadata));
902 args.GetReturnValue().Set(data);
905 // static
906 void SearchBoxExtensionWrapper::GetThemeBackgroundInfo(
907 const v8::FunctionCallbackInfo<v8::Value>& args) {
908 content::RenderView* render_view = GetRenderView();
909 if (!render_view) return;
911 DVLOG(1) << render_view << " GetThemeBackgroundInfo";
912 const ThemeBackgroundInfo& theme_info =
913 SearchBox::Get(render_view)->GetThemeBackgroundInfo();
914 v8::Isolate* isolate = args.GetIsolate();
915 v8::Local<v8::Object> info = v8::Object::New(isolate);
917 info->Set(v8::String::NewFromUtf8(isolate, "usingDefaultTheme"),
918 v8::Boolean::New(isolate, theme_info.using_default_theme));
920 // The theme background color is in RGBA format "rgba(R,G,B,A)" where R, G and
921 // B are between 0 and 255 inclusive, and A is a double between 0 and 1
922 // inclusive.
923 // This is the CSS "background-color" format.
924 // Value is always valid.
925 // TODO(jfweitz): Remove this field after GWS is modified to use the new
926 // backgroundColorRgba field.
927 info->Set(
928 v8::String::NewFromUtf8(isolate, "colorRgba"),
929 UTF8ToV8String(
930 isolate,
931 // Convert the alpha using DoubleToString because StringPrintf will
932 // use
933 // locale specific formatters (e.g., use , instead of . in German).
934 base::StringPrintf(
935 kCSSBackgroundColorFormat,
936 theme_info.background_color.r,
937 theme_info.background_color.g,
938 theme_info.background_color.b,
939 base::DoubleToString(theme_info.background_color.a / 255.0)
940 .c_str())));
942 // Theme color for background as an array with the RGBA components in order.
943 // Value is always valid.
944 info->Set(v8::String::NewFromUtf8(isolate, "backgroundColorRgba"),
945 internal::RGBAColorToArray(isolate, theme_info.background_color));
947 // Theme color for text as an array with the RGBA components in order.
948 // Value is always valid.
949 info->Set(v8::String::NewFromUtf8(isolate, "textColorRgba"),
950 internal::RGBAColorToArray(isolate, theme_info.text_color));
952 // Theme color for links as an array with the RGBA components in order.
953 // Value is always valid.
954 info->Set(v8::String::NewFromUtf8(isolate, "linkColorRgba"),
955 internal::RGBAColorToArray(isolate, theme_info.link_color));
957 // Theme color for light text as an array with the RGBA components in order.
958 // Value is always valid.
959 info->Set(v8::String::NewFromUtf8(isolate, "textColorLightRgba"),
960 internal::RGBAColorToArray(isolate, theme_info.text_color_light));
962 // Theme color for header as an array with the RGBA components in order.
963 // Value is always valid.
964 info->Set(v8::String::NewFromUtf8(isolate, "headerColorRgba"),
965 internal::RGBAColorToArray(isolate, theme_info.header_color));
967 // Theme color for section border as an array with the RGBA components in
968 // order. Value is always valid.
969 info->Set(
970 v8::String::NewFromUtf8(isolate, "sectionBorderColorRgba"),
971 internal::RGBAColorToArray(isolate, theme_info.section_border_color));
973 // The theme alternate logo value indicates a white logo when TRUE and a
974 // colorful one when FALSE.
975 info->Set(v8::String::NewFromUtf8(isolate, "alternateLogo"),
976 v8::Boolean::New(isolate, theme_info.logo_alternate));
978 // The theme background image url is of format kCSSBackgroundImageFormat
979 // where both instances of "%s" are replaced with the id that identifies the
980 // theme.
981 // This is the CSS "background-image" format.
982 // Value is only valid if there's a custom theme background image.
983 if (crx_file::id_util::IdIsValid(theme_info.theme_id)) {
984 info->Set(v8::String::NewFromUtf8(isolate, "imageUrl"),
985 UTF8ToV8String(isolate,
986 base::StringPrintf(kCSSBackgroundImageFormat,
987 theme_info.theme_id.c_str(),
988 theme_info.theme_id.c_str())));
990 // The theme background image horizontal alignment is one of "left",
991 // "right", "center".
992 // This is the horizontal component of the CSS "background-position" format.
993 // Value is only valid if |imageUrl| is not empty.
994 std::string alignment = kCSSBackgroundPositionCenter;
995 if (theme_info.image_horizontal_alignment ==
996 THEME_BKGRND_IMAGE_ALIGN_LEFT) {
997 alignment = kCSSBackgroundPositionLeft;
998 } else if (theme_info.image_horizontal_alignment ==
999 THEME_BKGRND_IMAGE_ALIGN_RIGHT) {
1000 alignment = kCSSBackgroundPositionRight;
1002 info->Set(v8::String::NewFromUtf8(isolate, "imageHorizontalAlignment"),
1003 UTF8ToV8String(isolate, alignment));
1005 // The theme background image vertical alignment is one of "top", "bottom",
1006 // "center".
1007 // This is the vertical component of the CSS "background-position" format.
1008 // Value is only valid if |image_url| is not empty.
1009 if (theme_info.image_vertical_alignment == THEME_BKGRND_IMAGE_ALIGN_TOP) {
1010 alignment = kCSSBackgroundPositionTop;
1011 } else if (theme_info.image_vertical_alignment ==
1012 THEME_BKGRND_IMAGE_ALIGN_BOTTOM) {
1013 alignment = kCSSBackgroundPositionBottom;
1014 } else {
1015 alignment = kCSSBackgroundPositionCenter;
1017 info->Set(v8::String::NewFromUtf8(isolate, "imageVerticalAlignment"),
1018 UTF8ToV8String(isolate, alignment));
1020 // The tiling of the theme background image is one of "no-repeat",
1021 // "repeat-x", "repeat-y", "repeat".
1022 // This is the CSS "background-repeat" format.
1023 // Value is only valid if |image_url| is not empty.
1024 std::string tiling = kCSSBackgroundRepeatNo;
1025 switch (theme_info.image_tiling) {
1026 case THEME_BKGRND_IMAGE_NO_REPEAT:
1027 tiling = kCSSBackgroundRepeatNo;
1028 break;
1029 case THEME_BKGRND_IMAGE_REPEAT_X:
1030 tiling = kCSSBackgroundRepeatX;
1031 break;
1032 case THEME_BKGRND_IMAGE_REPEAT_Y:
1033 tiling = kCSSBackgroundRepeatY;
1034 break;
1035 case THEME_BKGRND_IMAGE_REPEAT:
1036 tiling = kCSSBackgroundRepeat;
1037 break;
1039 info->Set(v8::String::NewFromUtf8(isolate, "imageTiling"),
1040 UTF8ToV8String(isolate, tiling));
1042 // The theme background image height is only valid if |imageUrl| is valid.
1043 info->Set(v8::String::NewFromUtf8(isolate, "imageHeight"),
1044 v8::Int32::New(isolate, theme_info.image_height));
1046 // The attribution URL is only valid if the theme has attribution logo.
1047 if (theme_info.has_attribution) {
1048 info->Set(
1049 v8::String::NewFromUtf8(isolate, "attributionUrl"),
1050 UTF8ToV8String(isolate,
1051 base::StringPrintf(kThemeAttributionFormat,
1052 theme_info.theme_id.c_str(),
1053 theme_info.theme_id.c_str())));
1057 args.GetReturnValue().Set(info);
1060 // static
1061 void SearchBoxExtensionWrapper::IsFocused(
1062 const v8::FunctionCallbackInfo<v8::Value>& args) {
1063 content::RenderView* render_view = GetRenderView();
1064 if (!render_view) return;
1066 bool is_focused = SearchBox::Get(render_view)->is_focused();
1067 DVLOG(1) << render_view << " IsFocused: " << is_focused;
1068 args.GetReturnValue().Set(is_focused);
1071 // static
1072 void SearchBoxExtensionWrapper::IsInputInProgress(
1073 const v8::FunctionCallbackInfo<v8::Value>& args) {
1074 content::RenderView* render_view = GetRenderView();
1075 if (!render_view) return;
1077 bool is_input_in_progress =
1078 SearchBox::Get(render_view)->is_input_in_progress();
1079 DVLOG(1) << render_view << " IsInputInProgress: " << is_input_in_progress;
1080 args.GetReturnValue().Set(is_input_in_progress);
1083 // static
1084 void SearchBoxExtensionWrapper::IsKeyCaptureEnabled(
1085 const v8::FunctionCallbackInfo<v8::Value>& args) {
1086 content::RenderView* render_view = GetRenderView();
1087 if (!render_view) return;
1089 args.GetReturnValue().Set(SearchBox::Get(render_view)->
1090 is_key_capture_enabled());
1093 // static
1094 void SearchBoxExtensionWrapper::LogEvent(
1095 const v8::FunctionCallbackInfo<v8::Value>& args) {
1096 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
1097 GURL(chrome::kChromeSearchMostVisitedUrl));
1098 if (!render_view) return;
1100 if (!args.Length() || !args[0]->IsNumber()) {
1101 ThrowInvalidParameters(args);
1102 return;
1105 DVLOG(1) << render_view << " LogEvent";
1107 if (args[0]->Uint32Value() <= NTP_EVENT_TYPE_LAST) {
1108 NTPLoggingEventType event =
1109 static_cast<NTPLoggingEventType>(args[0]->Uint32Value());
1110 SearchBox::Get(render_view)->LogEvent(event);
1114 // static
1115 void SearchBoxExtensionWrapper::LogMostVisitedImpression(
1116 const v8::FunctionCallbackInfo<v8::Value>& args) {
1117 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
1118 GURL(chrome::kChromeSearchMostVisitedUrl));
1119 if (!render_view) return;
1121 if (args.Length() < 2 || !args[0]->IsNumber() || args[1]->IsUndefined()) {
1122 ThrowInvalidParameters(args);
1123 return;
1126 DVLOG(1) << render_view << " LogMostVisitedImpression";
1128 SearchBox::Get(render_view)->LogMostVisitedImpression(
1129 args[0]->IntegerValue(), V8ValueToUTF16(args[1]));
1132 // static
1133 void SearchBoxExtensionWrapper::LogMostVisitedNavigation(
1134 const v8::FunctionCallbackInfo<v8::Value>& args) {
1135 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
1136 GURL(chrome::kChromeSearchMostVisitedUrl));
1137 if (!render_view) return;
1139 if (args.Length() < 2 || !args[0]->IsNumber() || args[1]->IsUndefined()) {
1140 ThrowInvalidParameters(args);
1141 return;
1144 DVLOG(1) << render_view << " LogMostVisitedNavigation";
1146 SearchBox::Get(render_view)->LogMostVisitedNavigation(
1147 args[0]->IntegerValue(), V8ValueToUTF16(args[1]));
1150 // static
1151 void SearchBoxExtensionWrapper::NavigateContentWindow(
1152 const v8::FunctionCallbackInfo<v8::Value>& args) {
1153 content::RenderView* render_view = GetRenderView();
1154 if (!render_view) return;
1156 if (!args.Length()) {
1157 ThrowInvalidParameters(args);
1158 return;
1161 GURL destination_url;
1162 bool is_most_visited_item_url = false;
1163 // Check if the url is a rid
1164 if (args[0]->IsNumber()) {
1165 InstantMostVisitedItem item;
1166 if (SearchBox::Get(render_view)->GetMostVisitedItemWithID(
1167 args[0]->IntegerValue(), &item)) {
1168 destination_url = item.url;
1169 is_most_visited_item_url = true;
1171 } else {
1172 // Resolve the URL
1173 const base::string16& possibly_relative_url = V8ValueToUTF16(args[0]);
1174 GURL current_url = GetCurrentURL(render_view);
1175 destination_url = internal::ResolveURL(current_url, possibly_relative_url);
1178 DVLOG(1) << render_view << " NavigateContentWindow: " << destination_url;
1180 // Navigate the main frame.
1181 if (destination_url.is_valid() &&
1182 !destination_url.SchemeIs(url::kJavaScriptScheme)) {
1183 WindowOpenDisposition disposition = CURRENT_TAB;
1184 if (args[1]->IsNumber()) {
1185 disposition = (WindowOpenDisposition) args[1]->Uint32Value();
1187 SearchBox::Get(render_view)->NavigateToURL(destination_url, disposition,
1188 is_most_visited_item_url);
1192 // static
1193 void SearchBoxExtensionWrapper::Paste(
1194 const v8::FunctionCallbackInfo<v8::Value>& args) {
1195 content::RenderView* render_view = GetRenderView();
1196 if (!render_view) return;
1198 base::string16 text;
1199 if (!args[0]->IsUndefined())
1200 text = V8ValueToUTF16(args[0]);
1202 DVLOG(1) << render_view << " Paste: " << text;
1203 SearchBox::Get(render_view)->Paste(text);
1206 // static
1207 void SearchBoxExtensionWrapper::StartCapturingKeyStrokes(
1208 const v8::FunctionCallbackInfo<v8::Value>& args) {
1209 content::RenderView* render_view = GetRenderView();
1210 if (!render_view) return;
1212 DVLOG(1) << render_view << " StartCapturingKeyStrokes";
1213 SearchBox::Get(render_view)->StartCapturingKeyStrokes();
1216 // static
1217 void SearchBoxExtensionWrapper::StopCapturingKeyStrokes(
1218 const v8::FunctionCallbackInfo<v8::Value>& args) {
1219 content::RenderView* render_view = GetRenderView();
1220 if (!render_view) return;
1222 DVLOG(1) << render_view << " StopCapturingKeyStrokes";
1223 SearchBox::Get(render_view)->StopCapturingKeyStrokes();
1226 // static
1227 void SearchBoxExtensionWrapper::SetVoiceSearchSupported(
1228 const v8::FunctionCallbackInfo<v8::Value>& args) {
1229 content::RenderView* render_view = GetRenderView();
1230 if (!render_view) {
1231 return;
1233 if (!args.Length()) {
1234 ThrowInvalidParameters(args);
1235 return;
1238 DVLOG(1) << render_view << " SetVoiceSearchSupported";
1239 SearchBox::Get(render_view)->SetVoiceSearchSupported(args[0]->BooleanValue());
1242 // static
1243 void SearchBoxExtensionWrapper::UndoAllMostVisitedDeletions(
1244 const v8::FunctionCallbackInfo<v8::Value>& args) {
1245 content::RenderView* render_view = GetRenderView();
1246 if (!render_view) return;
1248 DVLOG(1) << render_view << " UndoAllMostVisitedDeletions";
1249 SearchBox::Get(render_view)->UndoAllMostVisitedDeletions();
1252 // static
1253 void SearchBoxExtensionWrapper::UndoMostVisitedDeletion(
1254 const v8::FunctionCallbackInfo<v8::Value>& args) {
1255 content::RenderView* render_view = GetRenderView();
1256 if (!render_view) {
1257 return;
1259 if (!args.Length()) {
1260 ThrowInvalidParameters(args);
1261 return;
1264 DVLOG(1) << render_view << " UndoMostVisitedDeletion";
1265 SearchBox::Get(render_view)
1266 ->UndoMostVisitedDeletion(args[0]->ToInteger()->Value());
1269 // static
1270 void SearchBoxExtensionWrapper::GetDisplayInstantResults(
1271 const v8::FunctionCallbackInfo<v8::Value>& args) {
1272 content::RenderView* render_view = GetRenderView();
1273 if (!render_view) return;
1275 bool display_instant_results =
1276 SearchBox::Get(render_view)->display_instant_results();
1277 DVLOG(1) << render_view << " GetDisplayInstantResults" <<
1278 display_instant_results;
1279 args.GetReturnValue().Set(display_instant_results);
1282 } // namespace extensions_v8