Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chrome / renderer / searchbox / searchbox_extension.cc
blob0113c712d1d45f194874078d51d3f5d5dece3b8a
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 v8::Local<v8::String> GenerateThumb2URL(v8::Isolate* isolate, std::string url) {
121 return UTF8ToV8String(
122 isolate, base::StringPrintf("chrome-search://thumb2/%s", url.c_str()));
125 // Populates a Javascript MostVisitedItem object from |mv_item|.
126 // NOTE: Includes "url", "title" and "domain" which are private data, so should
127 // not be returned to the Instant page. These should be erased before returning
128 // the object. See GetMostVisitedItemsWrapper() in searchbox_api.js.
129 v8::Local<v8::Object> GenerateMostVisitedItem(
130 v8::Isolate* isolate,
131 int render_view_id,
132 InstantRestrictedID restricted_id,
133 const InstantMostVisitedItem& mv_item) {
134 // We set the "dir" attribute of the title, so that in RTL locales, a LTR
135 // title is rendered left-to-right and truncated from the right. For
136 // example, the title of http://msdn.microsoft.com/en-us/default.aspx is
137 // "MSDN: Microsoft developer network". In RTL locales, in the New Tab
138 // page, if the "dir" of this title is not specified, it takes Chrome UI's
139 // directionality. So the title will be truncated as "soft developer
140 // network". Setting the "dir" attribute as "ltr" renders the truncated
141 // title as "MSDN: Microsoft D...". As another example, the title of
142 // http://yahoo.com is "Yahoo!". In RTL locales, in the New Tab page, the
143 // title will be rendered as "!Yahoo" if its "dir" attribute is not set to
144 // "ltr".
145 std::string direction;
146 if (base::i18n::StringContainsStrongRTLChars(mv_item.title))
147 direction = kRTLHtmlTextDirection;
148 else
149 direction = kLTRHtmlTextDirection;
151 base::string16 title = mv_item.title;
152 if (title.empty())
153 title = base::UTF8ToUTF16(mv_item.url.spec());
155 v8::Local<v8::Object> obj = v8::Object::New(isolate);
156 obj->Set(v8::String::NewFromUtf8(isolate, "renderViewId"),
157 v8::Int32::New(isolate, render_view_id));
158 obj->Set(v8::String::NewFromUtf8(isolate, "rid"),
159 v8::Int32::New(isolate, restricted_id));
161 // If the suggestion already has a suggested thumbnail, we create an thumbnail
162 // array with both the local thumbnail and the proposed one.
163 // Otherwise, we just create an array with the generated one.
164 if (!mv_item.thumbnail.spec().empty()) {
165 v8::Local<v8::Array> thumbs = v8::Array::New(isolate, 2);
166 thumbs->Set(0, GenerateThumb2URL(isolate, mv_item.url.spec()));
167 thumbs->Set(1, UTF8ToV8String(isolate, mv_item.thumbnail.spec()));
168 obj->Set(v8::String::NewFromUtf8(isolate, "thumbnailUrls"), thumbs);
169 } else {
170 v8::Local<v8::Array> thumbs = v8::Array::New(isolate, 1);
171 thumbs->Set(0,
172 GenerateThumbnailURL(isolate, render_view_id, restricted_id));
173 obj->Set(v8::String::NewFromUtf8(isolate, "thumbnailUrls"), thumbs);
176 // If the suggestion already has a favicon, we populate the element with it.
177 if (!mv_item.favicon.spec().empty()) {
178 obj->Set(v8::String::NewFromUtf8(isolate, "faviconUrl"),
179 UTF8ToV8String(isolate, mv_item.favicon.spec()));
181 // If the suggestion has an impression url, we populate the element with it.
182 if (!mv_item.impression_url.spec().empty()) {
183 obj->Set(v8::String::NewFromUtf8(isolate, "impressionUrl"),
184 UTF8ToV8String(isolate, mv_item.impression_url.spec()));
186 // If the suggestion has a click url, we populate the element with it.
187 if (!mv_item.click_url.spec().empty()) {
188 obj->Set(v8::String::NewFromUtf8(isolate, "pingUrl"),
189 UTF8ToV8String(isolate, mv_item.click_url.spec()));
192 if (IsIconNTPEnabled()) {
193 // Update website http://www.chromium.org/embeddedsearch when we make this
194 // permanent.
195 // Large icon size is 48px * window.devicePixelRatio. This is easier to set
196 // from JS, where IsIconNTPEnabled() is not available. So we add stubs
197 // here, and let JS fill in details.
198 obj->Set(v8::String::NewFromUtf8(isolate, "largeIconUrl"),
199 v8::String::NewFromUtf8(isolate, "chrome-search://large-icon/"));
200 obj->Set(v8::String::NewFromUtf8(isolate, "fallbackIconUrl"),
201 v8::String::NewFromUtf8(isolate, "chrome-search://fallback-icon/"));
203 obj->Set(v8::String::NewFromUtf8(isolate, "title"),
204 UTF16ToV8String(isolate, title));
205 obj->Set(v8::String::NewFromUtf8(isolate, "domain"),
206 UTF8ToV8String(isolate, mv_item.url.host()));
207 obj->Set(v8::String::NewFromUtf8(isolate, "direction"),
208 UTF8ToV8String(isolate, direction));
209 obj->Set(v8::String::NewFromUtf8(isolate, "url"),
210 UTF8ToV8String(isolate, mv_item.url.spec()));
211 return obj;
214 // Returns the render view for the current JS context if it matches |origin|,
215 // otherwise returns NULL. Used to restrict methods that access suggestions and
216 // most visited data to pages with origin chrome-search://most-visited and
217 // chrome-search://suggestions.
218 content::RenderView* GetRenderViewWithCheckedOrigin(const GURL& origin) {
219 blink::WebLocalFrame* webframe =
220 blink::WebLocalFrame::frameForCurrentContext();
221 if (!webframe)
222 return NULL;
223 blink::WebView* webview = webframe->view();
224 if (!webview)
225 return NULL; // Can happen during closing.
226 content::RenderView* render_view = content::RenderView::FromWebView(webview);
227 if (!render_view)
228 return NULL;
230 GURL url(webframe->document().url());
231 if (url.GetOrigin() != origin.GetOrigin())
232 return NULL;
234 return render_view;
237 // Returns the current URL.
238 GURL GetCurrentURL(content::RenderView* render_view) {
239 blink::WebView* webview = render_view->GetWebView();
240 return webview ? GURL(webview->mainFrame()->document().url()) : GURL();
243 } // namespace
245 namespace internal { // for testing.
247 // Returns an array with the RGBA color components.
248 v8::Local<v8::Value> RGBAColorToArray(v8::Isolate* isolate,
249 const RGBAColor& color) {
250 v8::Local<v8::Array> color_array = v8::Array::New(isolate, 4);
251 color_array->Set(0, v8::Int32::New(isolate, color.r));
252 color_array->Set(1, v8::Int32::New(isolate, color.g));
253 color_array->Set(2, v8::Int32::New(isolate, color.b));
254 color_array->Set(3, v8::Int32::New(isolate, color.a));
255 return color_array;
258 // Resolves a possibly relative URL using the current URL.
259 GURL ResolveURL(const GURL& current_url,
260 const base::string16& possibly_relative_url) {
261 if (current_url.is_valid() && !possibly_relative_url.empty())
262 return current_url.Resolve(possibly_relative_url);
263 return GURL(possibly_relative_url);
266 } // namespace internal
268 namespace extensions_v8 {
270 static const char kSearchBoxExtensionName[] = "v8/EmbeddedSearch";
272 // We first send this script down to determine if the page supports instant.
273 static const char kSupportsInstantScript[] =
274 "if (window.chrome &&"
275 " window.chrome.embeddedSearch &&"
276 " window.chrome.embeddedSearch.searchBox &&"
277 " window.chrome.embeddedSearch.searchBox.onsubmit &&"
278 " typeof window.chrome.embeddedSearch.searchBox.onsubmit =="
279 " 'function') {"
280 " true;"
281 "} else {"
282 " false;"
283 "}";
285 static const char kDispatchChromeIdentityCheckResult[] =
286 "if (window.chrome &&"
287 " window.chrome.embeddedSearch &&"
288 " window.chrome.embeddedSearch.newTabPage &&"
289 " window.chrome.embeddedSearch.newTabPage.onsignedincheckdone &&"
290 " typeof window.chrome.embeddedSearch.newTabPage"
291 " .onsignedincheckdone === 'function') {"
292 " window.chrome.embeddedSearch.newTabPage.onsignedincheckdone(%s, %s);"
293 " true;"
294 "}";
296 static const char kDispatchFocusChangedScript[] =
297 "if (window.chrome &&"
298 " window.chrome.embeddedSearch &&"
299 " window.chrome.embeddedSearch.searchBox &&"
300 " window.chrome.embeddedSearch.searchBox.onfocuschange &&"
301 " typeof window.chrome.embeddedSearch.searchBox.onfocuschange =="
302 " 'function') {"
303 " window.chrome.embeddedSearch.searchBox.onfocuschange();"
304 " true;"
305 "}";
307 static const char kDispatchHistorySyncCheckResult[] =
308 "if (window.chrome &&"
309 " window.chrome.embeddedSearch &&"
310 " window.chrome.embeddedSearch.newTabPage &&"
311 " window.chrome.embeddedSearch.newTabPage.onhistorysynccheckdone &&"
312 " typeof window.chrome.embeddedSearch.newTabPage"
313 " .onhistorysynccheckdone === 'function') {"
314 " window.chrome.embeddedSearch.newTabPage.onhistorysynccheckdone(%s);"
315 " true;"
316 "}";
318 static const char kDispatchInputCancelScript[] =
319 "if (window.chrome &&"
320 " window.chrome.embeddedSearch &&"
321 " window.chrome.embeddedSearch.newTabPage &&"
322 " window.chrome.embeddedSearch.newTabPage.oninputcancel &&"
323 " typeof window.chrome.embeddedSearch.newTabPage.oninputcancel =="
324 " 'function') {"
325 " window.chrome.embeddedSearch.newTabPage.oninputcancel();"
326 " true;"
327 "}";
329 static const char kDispatchInputStartScript[] =
330 "if (window.chrome &&"
331 " window.chrome.embeddedSearch &&"
332 " window.chrome.embeddedSearch.newTabPage &&"
333 " window.chrome.embeddedSearch.newTabPage.oninputstart &&"
334 " typeof window.chrome.embeddedSearch.newTabPage.oninputstart =="
335 " 'function') {"
336 " window.chrome.embeddedSearch.newTabPage.oninputstart();"
337 " true;"
338 "}";
340 static const char kDispatchKeyCaptureChangeScript[] =
341 "if (window.chrome &&"
342 " window.chrome.embeddedSearch &&"
343 " window.chrome.embeddedSearch.searchBox &&"
344 " window.chrome.embeddedSearch.searchBox.onkeycapturechange &&"
345 " typeof window.chrome.embeddedSearch.searchBox.onkeycapturechange =="
346 " 'function') {"
347 " window.chrome.embeddedSearch.searchBox.onkeycapturechange();"
348 " true;"
349 "}";
351 static const char kDispatchMarginChangeEventScript[] =
352 "if (window.chrome &&"
353 " window.chrome.embeddedSearch &&"
354 " window.chrome.embeddedSearch.searchBox &&"
355 " window.chrome.embeddedSearch.searchBox.onmarginchange &&"
356 " typeof window.chrome.embeddedSearch.searchBox.onmarginchange =="
357 " 'function') {"
358 " window.chrome.embeddedSearch.searchBox.onmarginchange();"
359 " true;"
360 "}";
362 static const char kDispatchMostVisitedChangedScript[] =
363 "if (window.chrome &&"
364 " window.chrome.embeddedSearch &&"
365 " window.chrome.embeddedSearch.newTabPage &&"
366 " window.chrome.embeddedSearch.newTabPage.onmostvisitedchange &&"
367 " typeof window.chrome.embeddedSearch.newTabPage.onmostvisitedchange =="
368 " 'function') {"
369 " window.chrome.embeddedSearch.newTabPage.onmostvisitedchange();"
370 " true;"
371 "}";
373 static const char kDispatchSubmitEventScript[] =
374 "if (window.chrome &&"
375 " window.chrome.embeddedSearch &&"
376 " window.chrome.embeddedSearch.searchBox &&"
377 " window.chrome.embeddedSearch.searchBox.onsubmit &&"
378 " typeof window.chrome.embeddedSearch.searchBox.onsubmit =="
379 " 'function') {"
380 " window.chrome.embeddedSearch.searchBox.onsubmit();"
381 " true;"
382 "}";
384 static const char kDispatchSuggestionChangeEventScript[] =
385 "if (window.chrome &&"
386 " window.chrome.embeddedSearch &&"
387 " window.chrome.embeddedSearch.searchBox &&"
388 " window.chrome.embeddedSearch.searchBox.onsuggestionchange &&"
389 " typeof window.chrome.embeddedSearch.searchBox.onsuggestionchange =="
390 " 'function') {"
391 " window.chrome.embeddedSearch.searchBox.onsuggestionchange();"
392 " true;"
393 "}";
395 static const char kDispatchThemeChangeEventScript[] =
396 "if (window.chrome &&"
397 " window.chrome.embeddedSearch &&"
398 " window.chrome.embeddedSearch.newTabPage &&"
399 " window.chrome.embeddedSearch.newTabPage.onthemechange &&"
400 " typeof window.chrome.embeddedSearch.newTabPage.onthemechange =="
401 " 'function') {"
402 " window.chrome.embeddedSearch.newTabPage.onthemechange();"
403 " true;"
404 "}";
406 static const char kDispatchToggleVoiceSearchScript[] =
407 "if (window.chrome &&"
408 " window.chrome.embeddedSearch &&"
409 " window.chrome.embeddedSearch.searchBox &&"
410 " window.chrome.embeddedSearch.searchBox.ontogglevoicesearch &&"
411 " typeof window.chrome.embeddedSearch.searchBox.ontogglevoicesearch =="
412 " 'function') {"
413 " window.chrome.embeddedSearch.searchBox.ontogglevoicesearch();"
414 " true;"
415 "}";
417 // ----------------------------------------------------------------------------
419 class SearchBoxExtensionWrapper : public v8::Extension {
420 public:
421 explicit SearchBoxExtensionWrapper(const base::StringPiece& code);
423 // Allows v8's javascript code to call the native functions defined
424 // in this class for window.chrome.
425 v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
426 v8::Isolate*,
427 v8::Local<v8::String> name) override;
429 // Helper function to find the RenderView. May return NULL.
430 static content::RenderView* GetRenderView();
432 // Sends a Chrome identity check to the browser.
433 static void CheckIsUserSignedInToChromeAs(
434 const v8::FunctionCallbackInfo<v8::Value>& args);
436 // Checks whether the user sync his history.
437 static void CheckIsUserSyncingHistory(
438 const v8::FunctionCallbackInfo<v8::Value>& args);
440 // Deletes a Most Visited item.
441 static void DeleteMostVisitedItem(
442 const v8::FunctionCallbackInfo<v8::Value>& args);
444 // Focuses the omnibox.
445 static void Focus(const v8::FunctionCallbackInfo<v8::Value>& args);
447 // Gets whether or not the app launcher is enabled.
448 static void GetAppLauncherEnabled(
449 const v8::FunctionCallbackInfo<v8::Value>& args);
451 // Gets the desired navigation behavior from a click event.
452 static void GetDispositionFromClick(
453 const v8::FunctionCallbackInfo<v8::Value>& args);
455 // Gets Most Visited Items.
456 static void GetMostVisitedItems(
457 const v8::FunctionCallbackInfo<v8::Value>& args);
459 // Gets the raw data for a most visited item including its raw URL.
460 // GetRenderViewWithCheckedOrigin() enforces that only code in the origin
461 // chrome-search://most-visited can call this function.
462 static void GetMostVisitedItemData(
463 const v8::FunctionCallbackInfo<v8::Value>& args);
465 // Gets the submitted value of the user's search query.
466 static void GetQuery(const v8::FunctionCallbackInfo<v8::Value>& args);
468 // Returns true if the Searchbox itself is oriented right-to-left.
469 static void GetRightToLeft(const v8::FunctionCallbackInfo<v8::Value>& args);
471 // Gets the Embedded Search request params. Used for logging purposes.
472 static void GetSearchRequestParams(
473 const v8::FunctionCallbackInfo<v8::Value>& args);
475 // Gets the start-edge margin to use with extended Instant.
476 static void GetStartMargin(const v8::FunctionCallbackInfo<v8::Value>& args);
478 // Gets the current top suggestion to prefetch search results.
479 static void GetSuggestionToPrefetch(
480 const v8::FunctionCallbackInfo<v8::Value>& args);
482 // Gets the background info of the theme currently adopted by browser.
483 // Call only when overlay is showing NTP page.
484 static void GetThemeBackgroundInfo(
485 const v8::FunctionCallbackInfo<v8::Value>& args);
487 // Gets whether the omnibox has focus or not.
488 static void IsFocused(const v8::FunctionCallbackInfo<v8::Value>& args);
490 // Gets whether user input is in progress.
491 static void IsInputInProgress(
492 const v8::FunctionCallbackInfo<v8::Value>& args);
494 // Gets whether the browser is capturing key strokes.
495 static void IsKeyCaptureEnabled(
496 const v8::FunctionCallbackInfo<v8::Value>& args);
498 // Logs information from the iframes/titles on the NTP.
499 static void LogEvent(const v8::FunctionCallbackInfo<v8::Value>& args);
501 // Logs an impression on one of the Most Visited tile on the NTP.
502 static void LogMostVisitedImpression(
503 const v8::FunctionCallbackInfo<v8::Value>& args);
505 // Logs a navigation on one of the Most Visited tile on the NTP.
506 static void LogMostVisitedNavigation(
507 const v8::FunctionCallbackInfo<v8::Value>& args);
509 // Navigates the window to a URL represented by either a URL string or a
510 // restricted ID.
511 static void NavigateContentWindow(
512 const v8::FunctionCallbackInfo<v8::Value>& args);
514 // Pastes provided value or clipboard's content into the omnibox.
515 static void Paste(const v8::FunctionCallbackInfo<v8::Value>& args);
517 // Indicates whether the page supports voice search.
518 static void SetVoiceSearchSupported(
519 const v8::FunctionCallbackInfo<v8::Value>& args);
521 // Start capturing user key strokes.
522 static void StartCapturingKeyStrokes(
523 const v8::FunctionCallbackInfo<v8::Value>& args);
525 // Stop capturing user key strokes.
526 static void StopCapturingKeyStrokes(
527 const v8::FunctionCallbackInfo<v8::Value>& args);
529 // Undoes the deletion of all Most Visited itens.
530 static void UndoAllMostVisitedDeletions(
531 const v8::FunctionCallbackInfo<v8::Value>& args);
533 // Undoes the deletion of a Most Visited item.
534 static void UndoMostVisitedDeletion(
535 const v8::FunctionCallbackInfo<v8::Value>& args);
537 // Indicates whether the page supports Instant.
538 static void GetDisplayInstantResults(
539 const v8::FunctionCallbackInfo<v8::Value>& args);
541 private:
542 DISALLOW_COPY_AND_ASSIGN(SearchBoxExtensionWrapper);
545 // static
546 v8::Extension* SearchBoxExtension::Get() {
547 return new SearchBoxExtensionWrapper(ResourceBundle::GetSharedInstance().
548 GetRawDataResource(IDR_SEARCHBOX_API));
551 // static
552 bool SearchBoxExtension::PageSupportsInstant(blink::WebFrame* frame) {
553 if (!frame) return false;
554 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
555 v8::Local<v8::Value> v = frame->executeScriptAndReturnValue(
556 blink::WebScriptSource(kSupportsInstantScript));
557 return !v.IsEmpty() && v->BooleanValue();
560 // static
561 void SearchBoxExtension::DispatchChromeIdentityCheckResult(
562 blink::WebFrame* frame,
563 const base::string16& identity,
564 bool identity_match) {
565 std::string escaped_identity = base::GetQuotedJSONString(identity);
566 blink::WebString script(base::UTF8ToUTF16(base::StringPrintf(
567 kDispatchChromeIdentityCheckResult,
568 escaped_identity.c_str(),
569 identity_match ? "true" : "false")));
570 Dispatch(frame, script);
573 // static
574 void SearchBoxExtension::DispatchFocusChange(blink::WebFrame* frame) {
575 Dispatch(frame, kDispatchFocusChangedScript);
578 // static
579 void SearchBoxExtension::DispatchHistorySyncCheckResult(
580 blink::WebFrame* frame,
581 bool sync_history) {
582 blink::WebString script(base::UTF8ToUTF16(base::StringPrintf(
583 kDispatchHistorySyncCheckResult,
584 sync_history ? "true" : "false")));
585 Dispatch(frame, script);
588 // static
589 void SearchBoxExtension::DispatchInputCancel(blink::WebFrame* frame) {
590 Dispatch(frame, kDispatchInputCancelScript);
593 // static
594 void SearchBoxExtension::DispatchInputStart(blink::WebFrame* frame) {
595 Dispatch(frame, kDispatchInputStartScript);
598 // static
599 void SearchBoxExtension::DispatchKeyCaptureChange(blink::WebFrame* frame) {
600 Dispatch(frame, kDispatchKeyCaptureChangeScript);
603 // static
604 void SearchBoxExtension::DispatchMarginChange(blink::WebFrame* frame) {
605 Dispatch(frame, kDispatchMarginChangeEventScript);
608 // static
609 void SearchBoxExtension::DispatchMostVisitedChanged(
610 blink::WebFrame* frame) {
611 Dispatch(frame, kDispatchMostVisitedChangedScript);
614 // static
615 void SearchBoxExtension::DispatchSubmit(blink::WebFrame* frame) {
616 Dispatch(frame, kDispatchSubmitEventScript);
619 // static
620 void SearchBoxExtension::DispatchSuggestionChange(blink::WebFrame* frame) {
621 Dispatch(frame, kDispatchSuggestionChangeEventScript);
624 // static
625 void SearchBoxExtension::DispatchThemeChange(blink::WebFrame* frame) {
626 Dispatch(frame, kDispatchThemeChangeEventScript);
629 // static
630 void SearchBoxExtension::DispatchToggleVoiceSearch(
631 blink::WebFrame* frame) {
632 Dispatch(frame, kDispatchToggleVoiceSearchScript);
635 SearchBoxExtensionWrapper::SearchBoxExtensionWrapper(
636 const base::StringPiece& code)
637 : v8::Extension(kSearchBoxExtensionName, code.data(), 0, 0, code.size()) {
640 v8::Local<v8::FunctionTemplate>
641 SearchBoxExtensionWrapper::GetNativeFunctionTemplate(
642 v8::Isolate* isolate,
643 v8::Local<v8::String> name) {
644 if (name->Equals(
645 v8::String::NewFromUtf8(isolate, "CheckIsUserSignedInToChromeAs")))
646 return v8::FunctionTemplate::New(isolate, CheckIsUserSignedInToChromeAs);
647 if (name->Equals(
648 v8::String::NewFromUtf8(isolate, "CheckIsUserSyncingHistory")))
649 return v8::FunctionTemplate::New(isolate, CheckIsUserSyncingHistory);
650 if (name->Equals(v8::String::NewFromUtf8(isolate, "DeleteMostVisitedItem")))
651 return v8::FunctionTemplate::New(isolate, DeleteMostVisitedItem);
652 if (name->Equals(v8::String::NewFromUtf8(isolate, "Focus")))
653 return v8::FunctionTemplate::New(isolate, Focus);
654 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetAppLauncherEnabled")))
655 return v8::FunctionTemplate::New(isolate, GetAppLauncherEnabled);
656 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetDispositionFromClick")))
657 return v8::FunctionTemplate::New(isolate, GetDispositionFromClick);
658 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetMostVisitedItems")))
659 return v8::FunctionTemplate::New(isolate, GetMostVisitedItems);
660 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetMostVisitedItemData")))
661 return v8::FunctionTemplate::New(isolate, GetMostVisitedItemData);
662 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetQuery")))
663 return v8::FunctionTemplate::New(isolate, GetQuery);
664 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetRightToLeft")))
665 return v8::FunctionTemplate::New(isolate, GetRightToLeft);
666 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetSearchRequestParams")))
667 return v8::FunctionTemplate::New(isolate, GetSearchRequestParams);
668 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetStartMargin")))
669 return v8::FunctionTemplate::New(isolate, GetStartMargin);
670 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetSuggestionToPrefetch")))
671 return v8::FunctionTemplate::New(isolate, GetSuggestionToPrefetch);
672 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetThemeBackgroundInfo")))
673 return v8::FunctionTemplate::New(isolate, GetThemeBackgroundInfo);
674 if (name->Equals(v8::String::NewFromUtf8(isolate, "IsFocused")))
675 return v8::FunctionTemplate::New(isolate, IsFocused);
676 if (name->Equals(v8::String::NewFromUtf8(isolate, "IsInputInProgress")))
677 return v8::FunctionTemplate::New(isolate, IsInputInProgress);
678 if (name->Equals(v8::String::NewFromUtf8(isolate, "IsKeyCaptureEnabled")))
679 return v8::FunctionTemplate::New(isolate, IsKeyCaptureEnabled);
680 if (name->Equals(v8::String::NewFromUtf8(isolate, "LogEvent")))
681 return v8::FunctionTemplate::New(isolate, LogEvent);
682 if (name->Equals(
683 v8::String::NewFromUtf8(isolate, "LogMostVisitedImpression"))) {
684 return v8::FunctionTemplate::New(isolate, LogMostVisitedImpression);
686 if (name->Equals(
687 v8::String::NewFromUtf8(isolate, "LogMostVisitedNavigation"))) {
688 return v8::FunctionTemplate::New(isolate, LogMostVisitedNavigation);
690 if (name->Equals(v8::String::NewFromUtf8(isolate, "NavigateContentWindow")))
691 return v8::FunctionTemplate::New(isolate, NavigateContentWindow);
692 if (name->Equals(v8::String::NewFromUtf8(isolate, "Paste")))
693 return v8::FunctionTemplate::New(isolate, Paste);
694 if (name->Equals(v8::String::NewFromUtf8(isolate, "SetVoiceSearchSupported")))
695 return v8::FunctionTemplate::New(isolate, SetVoiceSearchSupported);
696 if (name->Equals(
697 v8::String::NewFromUtf8(isolate, "StartCapturingKeyStrokes")))
698 return v8::FunctionTemplate::New(isolate, StartCapturingKeyStrokes);
699 if (name->Equals(v8::String::NewFromUtf8(isolate, "StopCapturingKeyStrokes")))
700 return v8::FunctionTemplate::New(isolate, StopCapturingKeyStrokes);
701 if (name->Equals(
702 v8::String::NewFromUtf8(isolate, "UndoAllMostVisitedDeletions")))
703 return v8::FunctionTemplate::New(isolate, UndoAllMostVisitedDeletions);
704 if (name->Equals(v8::String::NewFromUtf8(isolate, "UndoMostVisitedDeletion")))
705 return v8::FunctionTemplate::New(isolate, UndoMostVisitedDeletion);
706 if (name->Equals(
707 v8::String::NewFromUtf8(isolate, "GetDisplayInstantResults")))
708 return v8::FunctionTemplate::New(isolate, GetDisplayInstantResults);
709 return v8::Local<v8::FunctionTemplate>();
712 // static
713 content::RenderView* SearchBoxExtensionWrapper::GetRenderView() {
714 blink::WebLocalFrame* webframe =
715 blink::WebLocalFrame::frameForCurrentContext();
716 if (!webframe) return NULL;
718 blink::WebView* webview = webframe->view();
719 if (!webview) return NULL; // can happen during closing
721 return content::RenderView::FromWebView(webview);
724 // static
725 void SearchBoxExtensionWrapper::CheckIsUserSignedInToChromeAs(
726 const v8::FunctionCallbackInfo<v8::Value>& args) {
727 content::RenderView* render_view = GetRenderView();
728 if (!render_view) return;
730 if (!args.Length() || args[0]->IsUndefined()) {
731 ThrowInvalidParameters(args);
732 return;
735 DVLOG(1) << render_view << " CheckIsUserSignedInToChromeAs";
737 SearchBox::Get(render_view)->CheckIsUserSignedInToChromeAs(
738 V8ValueToUTF16(args[0]));
741 // static
742 void SearchBoxExtensionWrapper::CheckIsUserSyncingHistory(
743 const v8::FunctionCallbackInfo<v8::Value>& args) {
744 content::RenderView* render_view = GetRenderView();
745 if (!render_view) return;
747 DVLOG(1) << render_view << " CheckIsUserSyncingHistory";
748 SearchBox::Get(render_view)->CheckIsUserSyncingHistory();
751 // static
752 void SearchBoxExtensionWrapper::DeleteMostVisitedItem(
753 const v8::FunctionCallbackInfo<v8::Value>& args) {
754 content::RenderView* render_view = GetRenderView();
755 if (!render_view) return;
757 if (!args.Length()) {
758 ThrowInvalidParameters(args);
759 return;
762 DVLOG(1) << render_view
763 << " DeleteMostVisitedItem: " << args[0]->ToInteger()->Value();
764 SearchBox::Get(render_view)->
765 DeleteMostVisitedItem(args[0]->ToInteger()->Value());
768 // static
769 void SearchBoxExtensionWrapper::Focus(
770 const v8::FunctionCallbackInfo<v8::Value>& args) {
771 content::RenderView* render_view = GetRenderView();
772 if (!render_view) return;
774 DVLOG(1) << render_view << " Focus";
775 SearchBox::Get(render_view)->Focus();
778 // static
779 void SearchBoxExtensionWrapper::GetAppLauncherEnabled(
780 const v8::FunctionCallbackInfo<v8::Value>& args) {
781 content::RenderView* render_view = GetRenderView();
782 if (!render_view) return;
784 args.GetReturnValue().Set(
785 SearchBox::Get(render_view)->app_launcher_enabled());
788 // static
789 void SearchBoxExtensionWrapper::GetDispositionFromClick(
790 const v8::FunctionCallbackInfo<v8::Value>& args) {
791 content::RenderView* render_view = GetRenderView();
792 if (!render_view) return;
794 if (args.Length() != 5) {
795 ThrowInvalidParameters(args);
796 return;
799 bool middle_button = args[0]->BooleanValue();
800 bool alt_key = args[1]->BooleanValue();
801 bool ctrl_key = args[2]->BooleanValue();
802 bool meta_key = args[3]->BooleanValue();
803 bool shift_key = args[4]->BooleanValue();
805 WindowOpenDisposition disposition = ui::DispositionFromClick(middle_button,
806 alt_key,
807 ctrl_key,
808 meta_key,
809 shift_key);
810 v8::Isolate* isolate = args.GetIsolate();
811 args.GetReturnValue().Set(v8::Int32::New(isolate, disposition));
814 // static
815 void SearchBoxExtensionWrapper::GetMostVisitedItems(
816 const v8::FunctionCallbackInfo<v8::Value>& args) {
817 content::RenderView* render_view = GetRenderView();
818 if (!render_view)
819 return;
820 DVLOG(1) << render_view << " GetMostVisitedItems";
822 const SearchBox* search_box = SearchBox::Get(render_view);
824 std::vector<InstantMostVisitedItemIDPair> instant_mv_items;
825 search_box->GetMostVisitedItems(&instant_mv_items);
826 v8::Isolate* isolate = args.GetIsolate();
827 v8::Local<v8::Array> v8_mv_items =
828 v8::Array::New(isolate, instant_mv_items.size());
829 for (size_t i = 0; i < instant_mv_items.size(); ++i) {
830 v8_mv_items->Set(i,
831 GenerateMostVisitedItem(isolate,
832 render_view->GetRoutingID(),
833 instant_mv_items[i].first,
834 instant_mv_items[i].second));
836 args.GetReturnValue().Set(v8_mv_items);
839 // static
840 void SearchBoxExtensionWrapper::GetMostVisitedItemData(
841 const v8::FunctionCallbackInfo<v8::Value>& args) {
842 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
843 GURL(chrome::kChromeSearchMostVisitedUrl));
844 if (!render_view) return;
846 // Need an rid argument.
847 if (!args.Length() || !args[0]->IsNumber()) {
848 ThrowInvalidParameters(args);
849 return;
852 DVLOG(1) << render_view << " GetMostVisitedItem";
853 InstantRestrictedID restricted_id = args[0]->IntegerValue();
854 InstantMostVisitedItem mv_item;
855 if (!SearchBox::Get(render_view)->GetMostVisitedItemWithID(
856 restricted_id, &mv_item)) {
857 return;
859 v8::Isolate* isolate = args.GetIsolate();
860 args.GetReturnValue().Set(GenerateMostVisitedItem(
861 isolate, render_view->GetRoutingID(), restricted_id, mv_item));
864 // static
865 void SearchBoxExtensionWrapper::GetQuery(
866 const v8::FunctionCallbackInfo<v8::Value>& args) {
867 content::RenderView* render_view = GetRenderView();
868 if (!render_view) return;
869 const base::string16& query = SearchBox::Get(render_view)->query();
870 DVLOG(1) << render_view << " GetQuery: '" << query << "'";
871 v8::Isolate* isolate = args.GetIsolate();
872 args.GetReturnValue().Set(UTF16ToV8String(isolate, query));
875 // static
876 void SearchBoxExtensionWrapper::GetRightToLeft(
877 const v8::FunctionCallbackInfo<v8::Value>& args) {
878 args.GetReturnValue().Set(base::i18n::IsRTL());
881 // static
882 void SearchBoxExtensionWrapper::GetSearchRequestParams(
883 const v8::FunctionCallbackInfo<v8::Value>& args) {
884 content::RenderView* render_view = GetRenderView();
885 if (!render_view) return;
887 const EmbeddedSearchRequestParams& params =
888 SearchBox::Get(render_view)->GetEmbeddedSearchRequestParams();
889 v8::Isolate* isolate = args.GetIsolate();
890 v8::Local<v8::Object> data = v8::Object::New(isolate);
891 if (!params.search_query.empty()) {
892 data->Set(v8::String::NewFromUtf8(isolate, kSearchQueryKey),
893 UTF16ToV8String(isolate, params.search_query));
895 if (!params.original_query.empty()) {
896 data->Set(v8::String::NewFromUtf8(isolate, kOriginalQueryKey),
897 UTF16ToV8String(isolate, params.original_query));
899 if (!params.rlz_parameter_value.empty()) {
900 data->Set(v8::String::NewFromUtf8(isolate, kRLZParameterKey),
901 UTF16ToV8String(isolate, params.rlz_parameter_value));
903 if (!params.input_encoding.empty()) {
904 data->Set(v8::String::NewFromUtf8(isolate, kInputEncodingKey),
905 UTF16ToV8String(isolate, params.input_encoding));
907 if (!params.assisted_query_stats.empty()) {
908 data->Set(v8::String::NewFromUtf8(isolate, kAssistedQueryStatsKey),
909 UTF16ToV8String(isolate, params.assisted_query_stats));
911 args.GetReturnValue().Set(data);
914 // static
915 void SearchBoxExtensionWrapper::GetStartMargin(
916 const v8::FunctionCallbackInfo<v8::Value>& args) {
917 content::RenderView* render_view = GetRenderView();
918 if (!render_view) return;
919 args.GetReturnValue().Set(static_cast<int32_t>(
920 SearchBox::Get(render_view)->start_margin()));
923 // static
924 void SearchBoxExtensionWrapper::GetSuggestionToPrefetch(
925 const v8::FunctionCallbackInfo<v8::Value>& args) {
926 content::RenderView* render_view = GetRenderView();
927 if (!render_view) return;
929 const InstantSuggestion& suggestion =
930 SearchBox::Get(render_view)->suggestion();
931 v8::Isolate* isolate = args.GetIsolate();
932 v8::Local<v8::Object> data = v8::Object::New(isolate);
933 data->Set(v8::String::NewFromUtf8(isolate, "text"),
934 UTF16ToV8String(isolate, suggestion.text));
935 data->Set(v8::String::NewFromUtf8(isolate, "metadata"),
936 UTF8ToV8String(isolate, suggestion.metadata));
937 args.GetReturnValue().Set(data);
940 // static
941 void SearchBoxExtensionWrapper::GetThemeBackgroundInfo(
942 const v8::FunctionCallbackInfo<v8::Value>& args) {
943 content::RenderView* render_view = GetRenderView();
944 if (!render_view) return;
946 DVLOG(1) << render_view << " GetThemeBackgroundInfo";
947 const ThemeBackgroundInfo& theme_info =
948 SearchBox::Get(render_view)->GetThemeBackgroundInfo();
949 v8::Isolate* isolate = args.GetIsolate();
950 v8::Local<v8::Object> info = v8::Object::New(isolate);
952 info->Set(v8::String::NewFromUtf8(isolate, "usingDefaultTheme"),
953 v8::Boolean::New(isolate, theme_info.using_default_theme));
955 // The theme background color is in RGBA format "rgba(R,G,B,A)" where R, G and
956 // B are between 0 and 255 inclusive, and A is a double between 0 and 1
957 // inclusive.
958 // This is the CSS "background-color" format.
959 // Value is always valid.
960 // TODO(jfweitz): Remove this field after GWS is modified to use the new
961 // backgroundColorRgba field.
962 info->Set(
963 v8::String::NewFromUtf8(isolate, "colorRgba"),
964 UTF8ToV8String(
965 isolate,
966 // Convert the alpha using DoubleToString because StringPrintf will
967 // use
968 // locale specific formatters (e.g., use , instead of . in German).
969 base::StringPrintf(
970 kCSSBackgroundColorFormat,
971 theme_info.background_color.r,
972 theme_info.background_color.g,
973 theme_info.background_color.b,
974 base::DoubleToString(theme_info.background_color.a / 255.0)
975 .c_str())));
977 // Theme color for background as an array with the RGBA components in order.
978 // Value is always valid.
979 info->Set(v8::String::NewFromUtf8(isolate, "backgroundColorRgba"),
980 internal::RGBAColorToArray(isolate, theme_info.background_color));
982 // Theme color for text as an array with the RGBA components in order.
983 // Value is always valid.
984 info->Set(v8::String::NewFromUtf8(isolate, "textColorRgba"),
985 internal::RGBAColorToArray(isolate, theme_info.text_color));
987 // Theme color for links as an array with the RGBA components in order.
988 // Value is always valid.
989 info->Set(v8::String::NewFromUtf8(isolate, "linkColorRgba"),
990 internal::RGBAColorToArray(isolate, theme_info.link_color));
992 // Theme color for light text as an array with the RGBA components in order.
993 // Value is always valid.
994 info->Set(v8::String::NewFromUtf8(isolate, "textColorLightRgba"),
995 internal::RGBAColorToArray(isolate, theme_info.text_color_light));
997 // Theme color for header as an array with the RGBA components in order.
998 // Value is always valid.
999 info->Set(v8::String::NewFromUtf8(isolate, "headerColorRgba"),
1000 internal::RGBAColorToArray(isolate, theme_info.header_color));
1002 // Theme color for section border as an array with the RGBA components in
1003 // order. Value is always valid.
1004 info->Set(
1005 v8::String::NewFromUtf8(isolate, "sectionBorderColorRgba"),
1006 internal::RGBAColorToArray(isolate, theme_info.section_border_color));
1008 // The theme alternate logo value indicates a white logo when TRUE and a
1009 // colorful one when FALSE.
1010 info->Set(v8::String::NewFromUtf8(isolate, "alternateLogo"),
1011 v8::Boolean::New(isolate, theme_info.logo_alternate));
1013 // The theme background image url is of format kCSSBackgroundImageFormat
1014 // where both instances of "%s" are replaced with the id that identifies the
1015 // theme.
1016 // This is the CSS "background-image" format.
1017 // Value is only valid if there's a custom theme background image.
1018 if (crx_file::id_util::IdIsValid(theme_info.theme_id)) {
1019 info->Set(v8::String::NewFromUtf8(isolate, "imageUrl"),
1020 UTF8ToV8String(isolate,
1021 base::StringPrintf(kCSSBackgroundImageFormat,
1022 theme_info.theme_id.c_str(),
1023 theme_info.theme_id.c_str())));
1025 // The theme background image horizontal alignment is one of "left",
1026 // "right", "center".
1027 // This is the horizontal component of the CSS "background-position" format.
1028 // Value is only valid if |imageUrl| is not empty.
1029 std::string alignment = kCSSBackgroundPositionCenter;
1030 if (theme_info.image_horizontal_alignment ==
1031 THEME_BKGRND_IMAGE_ALIGN_LEFT) {
1032 alignment = kCSSBackgroundPositionLeft;
1033 } else if (theme_info.image_horizontal_alignment ==
1034 THEME_BKGRND_IMAGE_ALIGN_RIGHT) {
1035 alignment = kCSSBackgroundPositionRight;
1037 info->Set(v8::String::NewFromUtf8(isolate, "imageHorizontalAlignment"),
1038 UTF8ToV8String(isolate, alignment));
1040 // The theme background image vertical alignment is one of "top", "bottom",
1041 // "center".
1042 // This is the vertical component of the CSS "background-position" format.
1043 // Value is only valid if |image_url| is not empty.
1044 if (theme_info.image_vertical_alignment == THEME_BKGRND_IMAGE_ALIGN_TOP) {
1045 alignment = kCSSBackgroundPositionTop;
1046 } else if (theme_info.image_vertical_alignment ==
1047 THEME_BKGRND_IMAGE_ALIGN_BOTTOM) {
1048 alignment = kCSSBackgroundPositionBottom;
1049 } else {
1050 alignment = kCSSBackgroundPositionCenter;
1052 info->Set(v8::String::NewFromUtf8(isolate, "imageVerticalAlignment"),
1053 UTF8ToV8String(isolate, alignment));
1055 // The tiling of the theme background image is one of "no-repeat",
1056 // "repeat-x", "repeat-y", "repeat".
1057 // This is the CSS "background-repeat" format.
1058 // Value is only valid if |image_url| is not empty.
1059 std::string tiling = kCSSBackgroundRepeatNo;
1060 switch (theme_info.image_tiling) {
1061 case THEME_BKGRND_IMAGE_NO_REPEAT:
1062 tiling = kCSSBackgroundRepeatNo;
1063 break;
1064 case THEME_BKGRND_IMAGE_REPEAT_X:
1065 tiling = kCSSBackgroundRepeatX;
1066 break;
1067 case THEME_BKGRND_IMAGE_REPEAT_Y:
1068 tiling = kCSSBackgroundRepeatY;
1069 break;
1070 case THEME_BKGRND_IMAGE_REPEAT:
1071 tiling = kCSSBackgroundRepeat;
1072 break;
1074 info->Set(v8::String::NewFromUtf8(isolate, "imageTiling"),
1075 UTF8ToV8String(isolate, tiling));
1077 // The theme background image height is only valid if |imageUrl| is valid.
1078 info->Set(v8::String::NewFromUtf8(isolate, "imageHeight"),
1079 v8::Int32::New(isolate, theme_info.image_height));
1081 // The attribution URL is only valid if the theme has attribution logo.
1082 if (theme_info.has_attribution) {
1083 info->Set(
1084 v8::String::NewFromUtf8(isolate, "attributionUrl"),
1085 UTF8ToV8String(isolate,
1086 base::StringPrintf(kThemeAttributionFormat,
1087 theme_info.theme_id.c_str(),
1088 theme_info.theme_id.c_str())));
1092 args.GetReturnValue().Set(info);
1095 // static
1096 void SearchBoxExtensionWrapper::IsFocused(
1097 const v8::FunctionCallbackInfo<v8::Value>& args) {
1098 content::RenderView* render_view = GetRenderView();
1099 if (!render_view) return;
1101 bool is_focused = SearchBox::Get(render_view)->is_focused();
1102 DVLOG(1) << render_view << " IsFocused: " << is_focused;
1103 args.GetReturnValue().Set(is_focused);
1106 // static
1107 void SearchBoxExtensionWrapper::IsInputInProgress(
1108 const v8::FunctionCallbackInfo<v8::Value>& args) {
1109 content::RenderView* render_view = GetRenderView();
1110 if (!render_view) return;
1112 bool is_input_in_progress =
1113 SearchBox::Get(render_view)->is_input_in_progress();
1114 DVLOG(1) << render_view << " IsInputInProgress: " << is_input_in_progress;
1115 args.GetReturnValue().Set(is_input_in_progress);
1118 // static
1119 void SearchBoxExtensionWrapper::IsKeyCaptureEnabled(
1120 const v8::FunctionCallbackInfo<v8::Value>& args) {
1121 content::RenderView* render_view = GetRenderView();
1122 if (!render_view) return;
1124 args.GetReturnValue().Set(SearchBox::Get(render_view)->
1125 is_key_capture_enabled());
1128 // static
1129 void SearchBoxExtensionWrapper::LogEvent(
1130 const v8::FunctionCallbackInfo<v8::Value>& args) {
1131 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
1132 GURL(chrome::kChromeSearchMostVisitedUrl));
1133 if (!render_view) return;
1135 if (!args.Length() || !args[0]->IsNumber()) {
1136 ThrowInvalidParameters(args);
1137 return;
1140 DVLOG(1) << render_view << " LogEvent";
1142 if (args[0]->Uint32Value() <= NTP_EVENT_TYPE_LAST) {
1143 NTPLoggingEventType event =
1144 static_cast<NTPLoggingEventType>(args[0]->Uint32Value());
1145 SearchBox::Get(render_view)->LogEvent(event);
1149 // static
1150 void SearchBoxExtensionWrapper::LogMostVisitedImpression(
1151 const v8::FunctionCallbackInfo<v8::Value>& args) {
1152 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
1153 GURL(chrome::kChromeSearchMostVisitedUrl));
1154 if (!render_view) return;
1156 if (args.Length() < 2 || !args[0]->IsNumber() || args[1]->IsUndefined()) {
1157 ThrowInvalidParameters(args);
1158 return;
1161 DVLOG(1) << render_view << " LogMostVisitedImpression";
1163 SearchBox::Get(render_view)->LogMostVisitedImpression(
1164 args[0]->IntegerValue(), V8ValueToUTF16(args[1]));
1167 // static
1168 void SearchBoxExtensionWrapper::LogMostVisitedNavigation(
1169 const v8::FunctionCallbackInfo<v8::Value>& args) {
1170 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
1171 GURL(chrome::kChromeSearchMostVisitedUrl));
1172 if (!render_view) return;
1174 if (args.Length() < 2 || !args[0]->IsNumber() || args[1]->IsUndefined()) {
1175 ThrowInvalidParameters(args);
1176 return;
1179 DVLOG(1) << render_view << " LogMostVisitedNavigation";
1181 SearchBox::Get(render_view)->LogMostVisitedNavigation(
1182 args[0]->IntegerValue(), V8ValueToUTF16(args[1]));
1185 // static
1186 void SearchBoxExtensionWrapper::NavigateContentWindow(
1187 const v8::FunctionCallbackInfo<v8::Value>& args) {
1188 content::RenderView* render_view = GetRenderView();
1189 if (!render_view) return;
1191 if (!args.Length()) {
1192 ThrowInvalidParameters(args);
1193 return;
1196 GURL destination_url;
1197 bool is_most_visited_item_url = false;
1198 // Check if the url is a rid
1199 if (args[0]->IsNumber()) {
1200 InstantMostVisitedItem item;
1201 if (SearchBox::Get(render_view)->GetMostVisitedItemWithID(
1202 args[0]->IntegerValue(), &item)) {
1203 destination_url = item.url;
1204 is_most_visited_item_url = true;
1206 } else {
1207 // Resolve the URL
1208 const base::string16& possibly_relative_url = V8ValueToUTF16(args[0]);
1209 GURL current_url = GetCurrentURL(render_view);
1210 destination_url = internal::ResolveURL(current_url, possibly_relative_url);
1213 DVLOG(1) << render_view << " NavigateContentWindow: " << destination_url;
1215 // Navigate the main frame.
1216 if (destination_url.is_valid() &&
1217 !destination_url.SchemeIs(url::kJavaScriptScheme)) {
1218 WindowOpenDisposition disposition = CURRENT_TAB;
1219 if (args[1]->IsNumber()) {
1220 disposition = (WindowOpenDisposition) args[1]->Uint32Value();
1222 SearchBox::Get(render_view)->NavigateToURL(destination_url, disposition,
1223 is_most_visited_item_url);
1227 // static
1228 void SearchBoxExtensionWrapper::Paste(
1229 const v8::FunctionCallbackInfo<v8::Value>& args) {
1230 content::RenderView* render_view = GetRenderView();
1231 if (!render_view) return;
1233 base::string16 text;
1234 if (!args[0]->IsUndefined())
1235 text = V8ValueToUTF16(args[0]);
1237 DVLOG(1) << render_view << " Paste: " << text;
1238 SearchBox::Get(render_view)->Paste(text);
1241 // static
1242 void SearchBoxExtensionWrapper::StartCapturingKeyStrokes(
1243 const v8::FunctionCallbackInfo<v8::Value>& args) {
1244 content::RenderView* render_view = GetRenderView();
1245 if (!render_view) return;
1247 DVLOG(1) << render_view << " StartCapturingKeyStrokes";
1248 SearchBox::Get(render_view)->StartCapturingKeyStrokes();
1251 // static
1252 void SearchBoxExtensionWrapper::StopCapturingKeyStrokes(
1253 const v8::FunctionCallbackInfo<v8::Value>& args) {
1254 content::RenderView* render_view = GetRenderView();
1255 if (!render_view) return;
1257 DVLOG(1) << render_view << " StopCapturingKeyStrokes";
1258 SearchBox::Get(render_view)->StopCapturingKeyStrokes();
1261 // static
1262 void SearchBoxExtensionWrapper::SetVoiceSearchSupported(
1263 const v8::FunctionCallbackInfo<v8::Value>& args) {
1264 content::RenderView* render_view = GetRenderView();
1265 if (!render_view) {
1266 return;
1268 if (!args.Length()) {
1269 ThrowInvalidParameters(args);
1270 return;
1273 DVLOG(1) << render_view << " SetVoiceSearchSupported";
1274 SearchBox::Get(render_view)->SetVoiceSearchSupported(args[0]->BooleanValue());
1277 // static
1278 void SearchBoxExtensionWrapper::UndoAllMostVisitedDeletions(
1279 const v8::FunctionCallbackInfo<v8::Value>& args) {
1280 content::RenderView* render_view = GetRenderView();
1281 if (!render_view) return;
1283 DVLOG(1) << render_view << " UndoAllMostVisitedDeletions";
1284 SearchBox::Get(render_view)->UndoAllMostVisitedDeletions();
1287 // static
1288 void SearchBoxExtensionWrapper::UndoMostVisitedDeletion(
1289 const v8::FunctionCallbackInfo<v8::Value>& args) {
1290 content::RenderView* render_view = GetRenderView();
1291 if (!render_view) {
1292 return;
1294 if (!args.Length()) {
1295 ThrowInvalidParameters(args);
1296 return;
1299 DVLOG(1) << render_view << " UndoMostVisitedDeletion";
1300 SearchBox::Get(render_view)
1301 ->UndoMostVisitedDeletion(args[0]->ToInteger()->Value());
1304 // static
1305 void SearchBoxExtensionWrapper::GetDisplayInstantResults(
1306 const v8::FunctionCallbackInfo<v8::Value>& args) {
1307 content::RenderView* render_view = GetRenderView();
1308 if (!render_view) return;
1310 bool display_instant_results =
1311 SearchBox::Get(render_view)->display_instant_results();
1312 DVLOG(1) << render_view << " GetDisplayInstantResults" <<
1313 display_instant_results;
1314 args.GetReturnValue().Set(display_instant_results);
1317 } // namespace extensions_v8