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.
4
5 #include "chrome/renderer/searchbox/searchbox_extension.h"
6
7 #include "base/i18n/rtl.h"
8 #include "base/json/string_escape.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/common/autocomplete_match_type.h"
14 #include "chrome/common/instant_types.h"
15 #include "chrome/common/ntp_logging_events.h"
16 #include "chrome/common/url_constants.h"
17 #include "chrome/renderer/searchbox/searchbox.h"
18 #include "content/public/renderer/render_view.h"
19 #include "extensions/common/extension.h"
20 #include "grit/renderer_resources.h"
21 #include "third_party/WebKit/public/platform/WebURLRequest.h"
22 #include "third_party/WebKit/public/web/WebDocument.h"
23 #include "third_party/WebKit/public/web/WebLocalFrame.h"
24 #include "third_party/WebKit/public/web/WebScriptSource.h"
25 #include "third_party/WebKit/public/web/WebView.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "ui/base/window_open_disposition.h"
28 #include "ui/events/keycodes/keyboard_codes.h"
29 #include "url/gurl.h"
30 #include "url/url_constants.h"
31 #include "v8/include/v8.h"
32
33 namespace {
34
35 const char kCSSBackgroundImageFormat[] = "-webkit-image-set("
36 "url(chrome-search://theme/IDR_THEME_NTP_BACKGROUND?%s) 1x, "
37 "url(chrome-search://theme/IDR_THEME_NTP_BACKGROUND@2x?%s) 2x)";
38
39 const char kCSSBackgroundColorFormat[] = "rgba(%d,%d,%d,%s)";
40
41 const char kCSSBackgroundPositionCenter[] = "center";
42 const char kCSSBackgroundPositionLeft[] = "left";
43 const char kCSSBackgroundPositionTop[] = "top";
44 const char kCSSBackgroundPositionRight[] = "right";
45 const char kCSSBackgroundPositionBottom[] = "bottom";
46
47 const char kCSSBackgroundRepeatNo[] = "no-repeat";
48 const char kCSSBackgroundRepeatX[] = "repeat-x";
49 const char kCSSBackgroundRepeatY[] = "repeat-y";
50 const char kCSSBackgroundRepeat[] = "repeat";
51
52 const char kThemeAttributionFormat[] = "-webkit-image-set("
53 "url(chrome-search://theme/IDR_THEME_NTP_ATTRIBUTION?%s) 1x, "
54 "url(chrome-search://theme/IDR_THEME_NTP_ATTRIBUTION@2x?%s) 2x)";
55
56 const char kLTRHtmlTextDirection[] = "ltr";
57 const char kRTLHtmlTextDirection[] = "rtl";
58
59 // Converts a V8 value to a string16.
V8ValueToUTF16(v8::Handle<v8::Value> v)60 base::string16 V8ValueToUTF16(v8::Handle<v8::Value> v) {
61 v8::String::Value s(v);
62 return base::string16(reinterpret_cast<const base::char16*>(*s), s.length());
63 }
64
65 // Converts string16 to V8 String.
UTF16ToV8String(v8::Isolate * isolate,const base::string16 & s)66 v8::Handle<v8::String> UTF16ToV8String(v8::Isolate* isolate,
67 const base::string16& s) {
68 return v8::String::NewFromTwoByte(isolate,
69 reinterpret_cast<const uint16_t*>(s.data()),
70 v8::String::kNormalString,
71 s.size());
72 }
73
74 // Converts std::string to V8 String.
UTF8ToV8String(v8::Isolate * isolate,const std::string & s)75 v8::Handle<v8::String> UTF8ToV8String(v8::Isolate* isolate,
76 const std::string& s) {
77 return v8::String::NewFromUtf8(
78 isolate, s.data(), v8::String::kNormalString, s.size());
79 }
80
Dispatch(blink::WebFrame * frame,const blink::WebString & script)81 void Dispatch(blink::WebFrame* frame, const blink::WebString& script) {
82 if (!frame) return;
83 frame->executeScript(blink::WebScriptSource(script));
84 }
85
GenerateThumbnailURL(v8::Isolate * isolate,int render_view_id,InstantRestrictedID most_visited_item_id)86 v8::Handle<v8::String> GenerateThumbnailURL(
87 v8::Isolate* isolate,
88 int render_view_id,
89 InstantRestrictedID most_visited_item_id) {
90 return UTF8ToV8String(
91 isolate,
92 base::StringPrintf(
93 "chrome-search://thumb/%d/%d", render_view_id, most_visited_item_id));
94 }
95
96 // Populates a Javascript MostVisitedItem object from |mv_item|.
97 // NOTE: Includes "url", "title" and "domain" which are private data, so should
98 // not be returned to the Instant page. These should be erased before returning
99 // the object. See GetMostVisitedItemsWrapper() in searchbox_api.js.
GenerateMostVisitedItem(v8::Isolate * isolate,int render_view_id,InstantRestrictedID restricted_id,const InstantMostVisitedItem & mv_item)100 v8::Handle<v8::Object> GenerateMostVisitedItem(
101 v8::Isolate* isolate,
102 int render_view_id,
103 InstantRestrictedID restricted_id,
104 const InstantMostVisitedItem& mv_item) {
105 // We set the "dir" attribute of the title, so that in RTL locales, a LTR
106 // title is rendered left-to-right and truncated from the right. For
107 // example, the title of http://msdn.microsoft.com/en-us/default.aspx is
108 // "MSDN: Microsoft developer network". In RTL locales, in the New Tab
109 // page, if the "dir" of this title is not specified, it takes Chrome UI's
110 // directionality. So the title will be truncated as "soft developer
111 // network". Setting the "dir" attribute as "ltr" renders the truncated
112 // title as "MSDN: Microsoft D...". As another example, the title of
113 // http://yahoo.com is "Yahoo!". In RTL locales, in the New Tab page, the
114 // title will be rendered as "!Yahoo" if its "dir" attribute is not set to
115 // "ltr".
116 std::string direction;
117 if (base::i18n::StringContainsStrongRTLChars(mv_item.title))
118 direction = kRTLHtmlTextDirection;
119 else
120 direction = kLTRHtmlTextDirection;
121
122 base::string16 title = mv_item.title;
123 if (title.empty())
124 title = base::UTF8ToUTF16(mv_item.url.spec());
125
126 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
127 obj->Set(v8::String::NewFromUtf8(isolate, "renderViewId"),
128 v8::Int32::New(isolate, render_view_id));
129 obj->Set(v8::String::NewFromUtf8(isolate, "rid"),
130 v8::Int32::New(isolate, restricted_id));
131 obj->Set(v8::String::NewFromUtf8(isolate, "thumbnailUrl"),
132 GenerateThumbnailURL(isolate, render_view_id, restricted_id));
133 obj->Set(v8::String::NewFromUtf8(isolate, "title"),
134 UTF16ToV8String(isolate, title));
135 obj->Set(v8::String::NewFromUtf8(isolate, "domain"),
136 UTF8ToV8String(isolate, mv_item.url.host()));
137 obj->Set(v8::String::NewFromUtf8(isolate, "direction"),
138 UTF8ToV8String(isolate, direction));
139 obj->Set(v8::String::NewFromUtf8(isolate, "url"),
140 UTF8ToV8String(isolate, mv_item.url.spec()));
141 return obj;
142 }
143
144 // Returns the render view for the current JS context if it matches |origin|,
145 // otherwise returns NULL. Used to restrict methods that access suggestions and
146 // most visited data to pages with origin chrome-search://most-visited and
147 // chrome-search://suggestions.
GetRenderViewWithCheckedOrigin(const GURL & origin)148 content::RenderView* GetRenderViewWithCheckedOrigin(const GURL& origin) {
149 blink::WebLocalFrame* webframe =
150 blink::WebLocalFrame::frameForCurrentContext();
151 if (!webframe)
152 return NULL;
153 blink::WebView* webview = webframe->view();
154 if (!webview)
155 return NULL; // Can happen during closing.
156 content::RenderView* render_view = content::RenderView::FromWebView(webview);
157 if (!render_view)
158 return NULL;
159
160 GURL url(webframe->document().url());
161 if (url.GetOrigin() != origin.GetOrigin())
162 return NULL;
163
164 return render_view;
165 }
166
167 // Returns the current URL.
GetCurrentURL(content::RenderView * render_view)168 GURL GetCurrentURL(content::RenderView* render_view) {
169 blink::WebView* webview = render_view->GetWebView();
170 return webview ? GURL(webview->mainFrame()->document().url()) : GURL();
171 }
172
173 } // namespace
174
175 namespace internal { // for testing.
176
177 // Returns an array with the RGBA color components.
RGBAColorToArray(v8::Isolate * isolate,const RGBAColor & color)178 v8::Handle<v8::Value> RGBAColorToArray(v8::Isolate* isolate,
179 const RGBAColor& color) {
180 v8::Handle<v8::Array> color_array = v8::Array::New(isolate, 4);
181 color_array->Set(0, v8::Int32::New(isolate, color.r));
182 color_array->Set(1, v8::Int32::New(isolate, color.g));
183 color_array->Set(2, v8::Int32::New(isolate, color.b));
184 color_array->Set(3, v8::Int32::New(isolate, color.a));
185 return color_array;
186 }
187
188 // Resolves a possibly relative URL using the current URL.
ResolveURL(const GURL & current_url,const base::string16 & possibly_relative_url)189 GURL ResolveURL(const GURL& current_url,
190 const base::string16& possibly_relative_url) {
191 if (current_url.is_valid() && !possibly_relative_url.empty())
192 return current_url.Resolve(possibly_relative_url);
193 return GURL(possibly_relative_url);
194 }
195
196 } // namespace internal
197
198 namespace extensions_v8 {
199
200 static const char kSearchBoxExtensionName[] = "v8/EmbeddedSearch";
201
202 // We first send this script down to determine if the page supports instant.
203 static const char kSupportsInstantScript[] =
204 "if (window.chrome &&"
205 " window.chrome.embeddedSearch &&"
206 " window.chrome.embeddedSearch.searchBox &&"
207 " window.chrome.embeddedSearch.searchBox.onsubmit &&"
208 " typeof window.chrome.embeddedSearch.searchBox.onsubmit =="
209 " 'function') {"
210 " true;"
211 "} else {"
212 " false;"
213 "}";
214
215 static const char kDispatchChromeIdentityCheckResult[] =
216 "if (window.chrome &&"
217 " window.chrome.embeddedSearch &&"
218 " window.chrome.embeddedSearch.newTabPage &&"
219 " window.chrome.embeddedSearch.newTabPage.onsignedincheckdone &&"
220 " typeof window.chrome.embeddedSearch.newTabPage"
221 " .onsignedincheckdone === 'function') {"
222 " window.chrome.embeddedSearch.newTabPage.onsignedincheckdone(%s, %s);"
223 " true;"
224 "}";
225
226
227 static const char kDispatchFocusChangedScript[] =
228 "if (window.chrome &&"
229 " window.chrome.embeddedSearch &&"
230 " window.chrome.embeddedSearch.searchBox &&"
231 " window.chrome.embeddedSearch.searchBox.onfocuschange &&"
232 " typeof window.chrome.embeddedSearch.searchBox.onfocuschange =="
233 " 'function') {"
234 " window.chrome.embeddedSearch.searchBox.onfocuschange();"
235 " true;"
236 "}";
237
238 static const char kDispatchInputCancelScript[] =
239 "if (window.chrome &&"
240 " window.chrome.embeddedSearch &&"
241 " window.chrome.embeddedSearch.newTabPage &&"
242 " window.chrome.embeddedSearch.newTabPage.oninputcancel &&"
243 " typeof window.chrome.embeddedSearch.newTabPage.oninputcancel =="
244 " 'function') {"
245 " window.chrome.embeddedSearch.newTabPage.oninputcancel();"
246 " true;"
247 "}";
248
249 static const char kDispatchInputStartScript[] =
250 "if (window.chrome &&"
251 " window.chrome.embeddedSearch &&"
252 " window.chrome.embeddedSearch.newTabPage &&"
253 " window.chrome.embeddedSearch.newTabPage.oninputstart &&"
254 " typeof window.chrome.embeddedSearch.newTabPage.oninputstart =="
255 " 'function') {"
256 " window.chrome.embeddedSearch.newTabPage.oninputstart();"
257 " true;"
258 "}";
259
260 static const char kDispatchKeyCaptureChangeScript[] =
261 "if (window.chrome &&"
262 " window.chrome.embeddedSearch &&"
263 " window.chrome.embeddedSearch.searchBox &&"
264 " window.chrome.embeddedSearch.searchBox.onkeycapturechange &&"
265 " typeof window.chrome.embeddedSearch.searchBox.onkeycapturechange =="
266 " 'function') {"
267 " window.chrome.embeddedSearch.searchBox.onkeycapturechange();"
268 " true;"
269 "}";
270
271 static const char kDispatchMarginChangeEventScript[] =
272 "if (window.chrome &&"
273 " window.chrome.embeddedSearch &&"
274 " window.chrome.embeddedSearch.searchBox &&"
275 " window.chrome.embeddedSearch.searchBox.onmarginchange &&"
276 " typeof window.chrome.embeddedSearch.searchBox.onmarginchange =="
277 " 'function') {"
278 " window.chrome.embeddedSearch.searchBox.onmarginchange();"
279 " true;"
280 "}";
281
282 static const char kDispatchMostVisitedChangedScript[] =
283 "if (window.chrome &&"
284 " window.chrome.embeddedSearch &&"
285 " window.chrome.embeddedSearch.newTabPage &&"
286 " window.chrome.embeddedSearch.newTabPage.onmostvisitedchange &&"
287 " typeof window.chrome.embeddedSearch.newTabPage.onmostvisitedchange =="
288 " 'function') {"
289 " window.chrome.embeddedSearch.newTabPage.onmostvisitedchange();"
290 " true;"
291 "}";
292
293 static const char kDispatchSubmitEventScript[] =
294 "if (window.chrome &&"
295 " window.chrome.embeddedSearch &&"
296 " window.chrome.embeddedSearch.searchBox &&"
297 " window.chrome.embeddedSearch.searchBox.onsubmit &&"
298 " typeof window.chrome.embeddedSearch.searchBox.onsubmit =="
299 " 'function') {"
300 " window.chrome.embeddedSearch.searchBox.onsubmit();"
301 " true;"
302 "}";
303
304 static const char kDispatchSuggestionChangeEventScript[] =
305 "if (window.chrome &&"
306 " window.chrome.embeddedSearch &&"
307 " window.chrome.embeddedSearch.searchBox &&"
308 " window.chrome.embeddedSearch.searchBox.onsuggestionchange &&"
309 " typeof window.chrome.embeddedSearch.searchBox.onsuggestionchange =="
310 " 'function') {"
311 " window.chrome.embeddedSearch.searchBox.onsuggestionchange();"
312 " true;"
313 "}";
314
315 static const char kDispatchThemeChangeEventScript[] =
316 "if (window.chrome &&"
317 " window.chrome.embeddedSearch &&"
318 " window.chrome.embeddedSearch.newTabPage &&"
319 " window.chrome.embeddedSearch.newTabPage.onthemechange &&"
320 " typeof window.chrome.embeddedSearch.newTabPage.onthemechange =="
321 " 'function') {"
322 " window.chrome.embeddedSearch.newTabPage.onthemechange();"
323 " true;"
324 "}";
325
326 static const char kDispatchToggleVoiceSearchScript[] =
327 "if (window.chrome &&"
328 " window.chrome.embeddedSearch &&"
329 " window.chrome.embeddedSearch.searchBox &&"
330 " window.chrome.embeddedSearch.searchBox.ontogglevoicesearch &&"
331 " typeof window.chrome.embeddedSearch.searchBox.ontogglevoicesearch =="
332 " 'function') {"
333 " window.chrome.embeddedSearch.searchBox.ontogglevoicesearch();"
334 " true;"
335 "}";
336
337 // ----------------------------------------------------------------------------
338
339 class SearchBoxExtensionWrapper : public v8::Extension {
340 public:
341 explicit SearchBoxExtensionWrapper(const base::StringPiece& code);
342
343 // Allows v8's javascript code to call the native functions defined
344 // in this class for window.chrome.
345 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
346 v8::Isolate*,
347 v8::Handle<v8::String> name) OVERRIDE;
348
349 // Helper function to find the RenderView. May return NULL.
350 static content::RenderView* GetRenderView();
351
352 // Sends a Chrome identity check to the browser.
353 static void CheckIsUserSignedInToChromeAs(
354 const v8::FunctionCallbackInfo<v8::Value>& args);
355
356 // Deletes a Most Visited item.
357 static void DeleteMostVisitedItem(
358 const v8::FunctionCallbackInfo<v8::Value>& args);
359
360 // Focuses the omnibox.
361 static void Focus(const v8::FunctionCallbackInfo<v8::Value>& args);
362
363 // Gets whether or not the app launcher is enabled.
364 static void GetAppLauncherEnabled(
365 const v8::FunctionCallbackInfo<v8::Value>& args);
366
367 // Gets the desired navigation behavior from a click event.
368 static void GetDispositionFromClick(
369 const v8::FunctionCallbackInfo<v8::Value>& args);
370
371 // Gets Most Visited Items.
372 static void GetMostVisitedItems(
373 const v8::FunctionCallbackInfo<v8::Value>& args);
374
375 // Gets the raw data for a most visited item including its raw URL.
376 // GetRenderViewWithCheckedOrigin() enforces that only code in the origin
377 // chrome-search://most-visited can call this function.
378 static void GetMostVisitedItemData(
379 const v8::FunctionCallbackInfo<v8::Value>& args);
380
381 // Gets the submitted value of the user's search query.
382 static void GetQuery(const v8::FunctionCallbackInfo<v8::Value>& args);
383
384 // Returns true if the Searchbox itself is oriented right-to-left.
385 static void GetRightToLeft(const v8::FunctionCallbackInfo<v8::Value>& args);
386
387 // Gets the start-edge margin to use with extended Instant.
388 static void GetStartMargin(const v8::FunctionCallbackInfo<v8::Value>& args);
389
390 // Gets the current top suggestion to prefetch search results.
391 static void GetSuggestionToPrefetch(
392 const v8::FunctionCallbackInfo<v8::Value>& args);
393
394 // Gets the background info of the theme currently adopted by browser.
395 // Call only when overlay is showing NTP page.
396 static void GetThemeBackgroundInfo(
397 const v8::FunctionCallbackInfo<v8::Value>& args);
398
399 // Gets whether the omnibox has focus or not.
400 static void IsFocused(const v8::FunctionCallbackInfo<v8::Value>& args);
401
402 // Gets whether user input is in progress.
403 static void IsInputInProgress(
404 const v8::FunctionCallbackInfo<v8::Value>& args);
405
406 // Gets whether the browser is capturing key strokes.
407 static void IsKeyCaptureEnabled(
408 const v8::FunctionCallbackInfo<v8::Value>& args);
409
410 // Logs information from the iframes/titles on the NTP.
411 static void LogEvent(const v8::FunctionCallbackInfo<v8::Value>& args);
412
413 // Logs an impression on one of the Most Visited tile on the NTP.
414 static void LogMostVisitedImpression(
415 const v8::FunctionCallbackInfo<v8::Value>& args);
416
417 // Logs a navigation on one of the Most Visited tile on the NTP.
418 static void LogMostVisitedNavigation(
419 const v8::FunctionCallbackInfo<v8::Value>& args);
420
421 // Navigates the window to a URL represented by either a URL string or a
422 // restricted ID.
423 static void NavigateContentWindow(
424 const v8::FunctionCallbackInfo<v8::Value>& args);
425
426 // Pastes provided value or clipboard's content into the omnibox.
427 static void Paste(const v8::FunctionCallbackInfo<v8::Value>& args);
428
429 // Indicates whether the page supports voice search.
430 static void SetVoiceSearchSupported(
431 const v8::FunctionCallbackInfo<v8::Value>& args);
432
433 // Start capturing user key strokes.
434 static void StartCapturingKeyStrokes(
435 const v8::FunctionCallbackInfo<v8::Value>& args);
436
437 // Stop capturing user key strokes.
438 static void StopCapturingKeyStrokes(
439 const v8::FunctionCallbackInfo<v8::Value>& args);
440
441 // Undoes the deletion of all Most Visited itens.
442 static void UndoAllMostVisitedDeletions(
443 const v8::FunctionCallbackInfo<v8::Value>& args);
444
445 // Undoes the deletion of a Most Visited item.
446 static void UndoMostVisitedDeletion(
447 const v8::FunctionCallbackInfo<v8::Value>& args);
448
449 // Indicates whether the page supports Instant.
450 static void GetDisplayInstantResults(
451 const v8::FunctionCallbackInfo<v8::Value>& args);
452
453 private:
454 DISALLOW_COPY_AND_ASSIGN(SearchBoxExtensionWrapper);
455 };
456
457 // static
Get()458 v8::Extension* SearchBoxExtension::Get() {
459 return new SearchBoxExtensionWrapper(ResourceBundle::GetSharedInstance().
460 GetRawDataResource(IDR_SEARCHBOX_API));
461 }
462
463 // static
PageSupportsInstant(blink::WebFrame * frame)464 bool SearchBoxExtension::PageSupportsInstant(blink::WebFrame* frame) {
465 if (!frame) return false;
466 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
467 v8::Handle<v8::Value> v = frame->executeScriptAndReturnValue(
468 blink::WebScriptSource(kSupportsInstantScript));
469 return !v.IsEmpty() && v->BooleanValue();
470 }
471
472 // static
DispatchChromeIdentityCheckResult(blink::WebFrame * frame,const base::string16 & identity,bool identity_match)473 void SearchBoxExtension::DispatchChromeIdentityCheckResult(
474 blink::WebFrame* frame,
475 const base::string16& identity,
476 bool identity_match) {
477 std::string escaped_identity = base::GetQuotedJSONString(identity);
478 blink::WebString script(base::UTF8ToUTF16(base::StringPrintf(
479 kDispatchChromeIdentityCheckResult,
480 escaped_identity.c_str(),
481 identity_match ? "true" : "false")));
482 Dispatch(frame, script);
483 }
484
485 // static
DispatchFocusChange(blink::WebFrame * frame)486 void SearchBoxExtension::DispatchFocusChange(blink::WebFrame* frame) {
487 Dispatch(frame, kDispatchFocusChangedScript);
488 }
489
490 // static
DispatchInputCancel(blink::WebFrame * frame)491 void SearchBoxExtension::DispatchInputCancel(blink::WebFrame* frame) {
492 Dispatch(frame, kDispatchInputCancelScript);
493 }
494
495 // static
DispatchInputStart(blink::WebFrame * frame)496 void SearchBoxExtension::DispatchInputStart(blink::WebFrame* frame) {
497 Dispatch(frame, kDispatchInputStartScript);
498 }
499
500 // static
DispatchKeyCaptureChange(blink::WebFrame * frame)501 void SearchBoxExtension::DispatchKeyCaptureChange(blink::WebFrame* frame) {
502 Dispatch(frame, kDispatchKeyCaptureChangeScript);
503 }
504
505 // static
DispatchMarginChange(blink::WebFrame * frame)506 void SearchBoxExtension::DispatchMarginChange(blink::WebFrame* frame) {
507 Dispatch(frame, kDispatchMarginChangeEventScript);
508 }
509
510 // static
DispatchMostVisitedChanged(blink::WebFrame * frame)511 void SearchBoxExtension::DispatchMostVisitedChanged(
512 blink::WebFrame* frame) {
513 Dispatch(frame, kDispatchMostVisitedChangedScript);
514 }
515
516 // static
DispatchSubmit(blink::WebFrame * frame)517 void SearchBoxExtension::DispatchSubmit(blink::WebFrame* frame) {
518 Dispatch(frame, kDispatchSubmitEventScript);
519 }
520
521 // static
DispatchSuggestionChange(blink::WebFrame * frame)522 void SearchBoxExtension::DispatchSuggestionChange(blink::WebFrame* frame) {
523 Dispatch(frame, kDispatchSuggestionChangeEventScript);
524 }
525
526 // static
DispatchThemeChange(blink::WebFrame * frame)527 void SearchBoxExtension::DispatchThemeChange(blink::WebFrame* frame) {
528 Dispatch(frame, kDispatchThemeChangeEventScript);
529 }
530
531 // static
DispatchToggleVoiceSearch(blink::WebFrame * frame)532 void SearchBoxExtension::DispatchToggleVoiceSearch(
533 blink::WebFrame* frame) {
534 Dispatch(frame, kDispatchToggleVoiceSearchScript);
535 }
536
SearchBoxExtensionWrapper(const base::StringPiece & code)537 SearchBoxExtensionWrapper::SearchBoxExtensionWrapper(
538 const base::StringPiece& code)
539 : v8::Extension(kSearchBoxExtensionName, code.data(), 0, 0, code.size()) {
540 }
541
542 v8::Handle<v8::FunctionTemplate>
GetNativeFunctionTemplate(v8::Isolate * isolate,v8::Handle<v8::String> name)543 SearchBoxExtensionWrapper::GetNativeFunctionTemplate(
544 v8::Isolate* isolate,
545 v8::Handle<v8::String> name) {
546 if (name->Equals(
547 v8::String::NewFromUtf8(isolate, "CheckIsUserSignedInToChromeAs")))
548 return v8::FunctionTemplate::New(isolate, CheckIsUserSignedInToChromeAs);
549 if (name->Equals(v8::String::NewFromUtf8(isolate, "DeleteMostVisitedItem")))
550 return v8::FunctionTemplate::New(isolate, DeleteMostVisitedItem);
551 if (name->Equals(v8::String::NewFromUtf8(isolate, "Focus")))
552 return v8::FunctionTemplate::New(isolate, Focus);
553 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetAppLauncherEnabled")))
554 return v8::FunctionTemplate::New(isolate, GetAppLauncherEnabled);
555 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetDispositionFromClick")))
556 return v8::FunctionTemplate::New(isolate, GetDispositionFromClick);
557 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetMostVisitedItems")))
558 return v8::FunctionTemplate::New(isolate, GetMostVisitedItems);
559 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetMostVisitedItemData")))
560 return v8::FunctionTemplate::New(isolate, GetMostVisitedItemData);
561 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetQuery")))
562 return v8::FunctionTemplate::New(isolate, GetQuery);
563 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetRightToLeft")))
564 return v8::FunctionTemplate::New(isolate, GetRightToLeft);
565 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetStartMargin")))
566 return v8::FunctionTemplate::New(isolate, GetStartMargin);
567 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetSuggestionToPrefetch")))
568 return v8::FunctionTemplate::New(isolate, GetSuggestionToPrefetch);
569 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetThemeBackgroundInfo")))
570 return v8::FunctionTemplate::New(isolate, GetThemeBackgroundInfo);
571 if (name->Equals(v8::String::NewFromUtf8(isolate, "IsFocused")))
572 return v8::FunctionTemplate::New(isolate, IsFocused);
573 if (name->Equals(v8::String::NewFromUtf8(isolate, "IsInputInProgress")))
574 return v8::FunctionTemplate::New(isolate, IsInputInProgress);
575 if (name->Equals(v8::String::NewFromUtf8(isolate, "IsKeyCaptureEnabled")))
576 return v8::FunctionTemplate::New(isolate, IsKeyCaptureEnabled);
577 if (name->Equals(v8::String::NewFromUtf8(isolate, "LogEvent")))
578 return v8::FunctionTemplate::New(isolate, LogEvent);
579 if (name->Equals(
580 v8::String::NewFromUtf8(isolate, "LogMostVisitedImpression"))) {
581 return v8::FunctionTemplate::New(isolate, LogMostVisitedImpression);
582 }
583 if (name->Equals(
584 v8::String::NewFromUtf8(isolate, "LogMostVisitedNavigation"))) {
585 return v8::FunctionTemplate::New(isolate, LogMostVisitedNavigation);
586 }
587 if (name->Equals(v8::String::NewFromUtf8(isolate, "NavigateContentWindow")))
588 return v8::FunctionTemplate::New(isolate, NavigateContentWindow);
589 if (name->Equals(v8::String::NewFromUtf8(isolate, "Paste")))
590 return v8::FunctionTemplate::New(isolate, Paste);
591 if (name->Equals(v8::String::NewFromUtf8(isolate, "SetVoiceSearchSupported")))
592 return v8::FunctionTemplate::New(isolate, SetVoiceSearchSupported);
593 if (name->Equals(
594 v8::String::NewFromUtf8(isolate, "StartCapturingKeyStrokes")))
595 return v8::FunctionTemplate::New(isolate, StartCapturingKeyStrokes);
596 if (name->Equals(v8::String::NewFromUtf8(isolate, "StopCapturingKeyStrokes")))
597 return v8::FunctionTemplate::New(isolate, StopCapturingKeyStrokes);
598 if (name->Equals(
599 v8::String::NewFromUtf8(isolate, "UndoAllMostVisitedDeletions")))
600 return v8::FunctionTemplate::New(isolate, UndoAllMostVisitedDeletions);
601 if (name->Equals(v8::String::NewFromUtf8(isolate, "UndoMostVisitedDeletion")))
602 return v8::FunctionTemplate::New(isolate, UndoMostVisitedDeletion);
603 if (name->Equals(
604 v8::String::NewFromUtf8(isolate, "GetDisplayInstantResults")))
605 return v8::FunctionTemplate::New(isolate, GetDisplayInstantResults);
606 return v8::Handle<v8::FunctionTemplate>();
607 }
608
609 // static
GetRenderView()610 content::RenderView* SearchBoxExtensionWrapper::GetRenderView() {
611 blink::WebLocalFrame* webframe =
612 blink::WebLocalFrame::frameForCurrentContext();
613 if (!webframe) return NULL;
614
615 blink::WebView* webview = webframe->view();
616 if (!webview) return NULL; // can happen during closing
617
618 return content::RenderView::FromWebView(webview);
619 }
620
621 // static
CheckIsUserSignedInToChromeAs(const v8::FunctionCallbackInfo<v8::Value> & args)622 void SearchBoxExtensionWrapper::CheckIsUserSignedInToChromeAs(
623 const v8::FunctionCallbackInfo<v8::Value>& args) {
624 content::RenderView* render_view = GetRenderView();
625 if (!render_view || args.Length() == 0 || args[0]->IsUndefined()) return;
626
627 DVLOG(1) << render_view << " CheckIsUserSignedInToChromeAs";
628
629 SearchBox::Get(render_view)->CheckIsUserSignedInToChromeAs(
630 V8ValueToUTF16(args[0]));
631 }
632
633 // static
DeleteMostVisitedItem(const v8::FunctionCallbackInfo<v8::Value> & args)634 void SearchBoxExtensionWrapper::DeleteMostVisitedItem(
635 const v8::FunctionCallbackInfo<v8::Value>& args) {
636 content::RenderView* render_view = GetRenderView();
637 if (!render_view || !args.Length()) return;
638
639 DVLOG(1) << render_view << " DeleteMostVisitedItem";
640 SearchBox::Get(render_view)->DeleteMostVisitedItem(args[0]->IntegerValue());
641 }
642
643 // static
Focus(const v8::FunctionCallbackInfo<v8::Value> & args)644 void SearchBoxExtensionWrapper::Focus(
645 const v8::FunctionCallbackInfo<v8::Value>& args) {
646 content::RenderView* render_view = GetRenderView();
647 if (!render_view) return;
648
649 DVLOG(1) << render_view << " Focus";
650 SearchBox::Get(render_view)->Focus();
651 }
652
653 // static
GetAppLauncherEnabled(const v8::FunctionCallbackInfo<v8::Value> & args)654 void SearchBoxExtensionWrapper::GetAppLauncherEnabled(
655 const v8::FunctionCallbackInfo<v8::Value>& args) {
656 content::RenderView* render_view = GetRenderView();
657 if (!render_view) return;
658
659 args.GetReturnValue().Set(
660 SearchBox::Get(render_view)->app_launcher_enabled());
661 }
662
663 // static
GetDispositionFromClick(const v8::FunctionCallbackInfo<v8::Value> & args)664 void SearchBoxExtensionWrapper::GetDispositionFromClick(
665 const v8::FunctionCallbackInfo<v8::Value>& args) {
666 content::RenderView* render_view = GetRenderView();
667 if (!render_view || args.Length() != 5) return;
668
669 bool middle_button = args[0]->BooleanValue();
670 bool alt_key = args[1]->BooleanValue();
671 bool ctrl_key = args[2]->BooleanValue();
672 bool meta_key = args[3]->BooleanValue();
673 bool shift_key = args[4]->BooleanValue();
674
675 WindowOpenDisposition disposition = ui::DispositionFromClick(middle_button,
676 alt_key,
677 ctrl_key,
678 meta_key,
679 shift_key);
680 v8::Isolate* isolate = args.GetIsolate();
681 args.GetReturnValue().Set(v8::Int32::New(isolate, disposition));
682 }
683
684 // static
GetMostVisitedItems(const v8::FunctionCallbackInfo<v8::Value> & args)685 void SearchBoxExtensionWrapper::GetMostVisitedItems(
686 const v8::FunctionCallbackInfo<v8::Value>& args) {
687 content::RenderView* render_view = GetRenderView();
688 if (!render_view)
689 return;
690 DVLOG(1) << render_view << " GetMostVisitedItems";
691
692 const SearchBox* search_box = SearchBox::Get(render_view);
693
694 std::vector<InstantMostVisitedItemIDPair> instant_mv_items;
695 search_box->GetMostVisitedItems(&instant_mv_items);
696 v8::Isolate* isolate = args.GetIsolate();
697 v8::Handle<v8::Array> v8_mv_items =
698 v8::Array::New(isolate, instant_mv_items.size());
699 for (size_t i = 0; i < instant_mv_items.size(); ++i) {
700 v8_mv_items->Set(i,
701 GenerateMostVisitedItem(isolate,
702 render_view->GetRoutingID(),
703 instant_mv_items[i].first,
704 instant_mv_items[i].second));
705 }
706 args.GetReturnValue().Set(v8_mv_items);
707 }
708
709 // static
GetMostVisitedItemData(const v8::FunctionCallbackInfo<v8::Value> & args)710 void SearchBoxExtensionWrapper::GetMostVisitedItemData(
711 const v8::FunctionCallbackInfo<v8::Value>& args) {
712 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
713 GURL(chrome::kChromeSearchMostVisitedUrl));
714 if (!render_view) return;
715
716 // Need an rid argument.
717 if (args.Length() < 1 || !args[0]->IsNumber())
718 return;
719
720 DVLOG(1) << render_view << " GetMostVisitedItem";
721 InstantRestrictedID restricted_id = args[0]->IntegerValue();
722 InstantMostVisitedItem mv_item;
723 if (!SearchBox::Get(render_view)->GetMostVisitedItemWithID(
724 restricted_id, &mv_item)) {
725 return;
726 }
727 v8::Isolate* isolate = args.GetIsolate();
728 args.GetReturnValue().Set(GenerateMostVisitedItem(
729 isolate, render_view->GetRoutingID(), restricted_id, mv_item));
730 }
731
732 // static
GetQuery(const v8::FunctionCallbackInfo<v8::Value> & args)733 void SearchBoxExtensionWrapper::GetQuery(
734 const v8::FunctionCallbackInfo<v8::Value>& args) {
735 content::RenderView* render_view = GetRenderView();
736 if (!render_view) return;
737 const base::string16& query = SearchBox::Get(render_view)->query();
738 DVLOG(1) << render_view << " GetQuery: '" << query << "'";
739 v8::Isolate* isolate = args.GetIsolate();
740 args.GetReturnValue().Set(UTF16ToV8String(isolate, query));
741 }
742
743 // static
GetRightToLeft(const v8::FunctionCallbackInfo<v8::Value> & args)744 void SearchBoxExtensionWrapper::GetRightToLeft(
745 const v8::FunctionCallbackInfo<v8::Value>& args) {
746 args.GetReturnValue().Set(base::i18n::IsRTL());
747 }
748
749 // static
GetStartMargin(const v8::FunctionCallbackInfo<v8::Value> & args)750 void SearchBoxExtensionWrapper::GetStartMargin(
751 const v8::FunctionCallbackInfo<v8::Value>& args) {
752 content::RenderView* render_view = GetRenderView();
753 if (!render_view) return;
754 args.GetReturnValue().Set(static_cast<int32_t>(
755 SearchBox::Get(render_view)->start_margin()));
756 }
757
758 // static
GetSuggestionToPrefetch(const v8::FunctionCallbackInfo<v8::Value> & args)759 void SearchBoxExtensionWrapper::GetSuggestionToPrefetch(
760 const v8::FunctionCallbackInfo<v8::Value>& args) {
761 content::RenderView* render_view = GetRenderView();
762 if (!render_view) return;
763
764 const InstantSuggestion& suggestion =
765 SearchBox::Get(render_view)->suggestion();
766 v8::Isolate* isolate = args.GetIsolate();
767 v8::Handle<v8::Object> data = v8::Object::New(isolate);
768 data->Set(v8::String::NewFromUtf8(isolate, "text"),
769 UTF16ToV8String(isolate, suggestion.text));
770 data->Set(v8::String::NewFromUtf8(isolate, "metadata"),
771 UTF8ToV8String(isolate, suggestion.metadata));
772 args.GetReturnValue().Set(data);
773 }
774
775 // static
GetThemeBackgroundInfo(const v8::FunctionCallbackInfo<v8::Value> & args)776 void SearchBoxExtensionWrapper::GetThemeBackgroundInfo(
777 const v8::FunctionCallbackInfo<v8::Value>& args) {
778 content::RenderView* render_view = GetRenderView();
779 if (!render_view) return;
780
781 DVLOG(1) << render_view << " GetThemeBackgroundInfo";
782 const ThemeBackgroundInfo& theme_info =
783 SearchBox::Get(render_view)->GetThemeBackgroundInfo();
784 v8::Isolate* isolate = args.GetIsolate();
785 v8::Handle<v8::Object> info = v8::Object::New(isolate);
786
787 info->Set(v8::String::NewFromUtf8(isolate, "usingDefaultTheme"),
788 v8::Boolean::New(isolate, theme_info.using_default_theme));
789
790 // The theme background color is in RGBA format "rgba(R,G,B,A)" where R, G and
791 // B are between 0 and 255 inclusive, and A is a double between 0 and 1
792 // inclusive.
793 // This is the CSS "background-color" format.
794 // Value is always valid.
795 // TODO(jfweitz): Remove this field after GWS is modified to use the new
796 // backgroundColorRgba field.
797 info->Set(
798 v8::String::NewFromUtf8(isolate, "colorRgba"),
799 UTF8ToV8String(
800 isolate,
801 // Convert the alpha using DoubleToString because StringPrintf will
802 // use
803 // locale specific formatters (e.g., use , instead of . in German).
804 base::StringPrintf(
805 kCSSBackgroundColorFormat,
806 theme_info.background_color.r,
807 theme_info.background_color.g,
808 theme_info.background_color.b,
809 base::DoubleToString(theme_info.background_color.a / 255.0)
810 .c_str())));
811
812 // Theme color for background as an array with the RGBA components in order.
813 // Value is always valid.
814 info->Set(v8::String::NewFromUtf8(isolate, "backgroundColorRgba"),
815 internal::RGBAColorToArray(isolate, theme_info.background_color));
816
817 // Theme color for text as an array with the RGBA components in order.
818 // Value is always valid.
819 info->Set(v8::String::NewFromUtf8(isolate, "textColorRgba"),
820 internal::RGBAColorToArray(isolate, theme_info.text_color));
821
822 // Theme color for links as an array with the RGBA components in order.
823 // Value is always valid.
824 info->Set(v8::String::NewFromUtf8(isolate, "linkColorRgba"),
825 internal::RGBAColorToArray(isolate, theme_info.link_color));
826
827 // Theme color for light text as an array with the RGBA components in order.
828 // Value is always valid.
829 info->Set(v8::String::NewFromUtf8(isolate, "textColorLightRgba"),
830 internal::RGBAColorToArray(isolate, theme_info.text_color_light));
831
832 // Theme color for header as an array with the RGBA components in order.
833 // Value is always valid.
834 info->Set(v8::String::NewFromUtf8(isolate, "headerColorRgba"),
835 internal::RGBAColorToArray(isolate, theme_info.header_color));
836
837 // Theme color for section border as an array with the RGBA components in
838 // order. Value is always valid.
839 info->Set(
840 v8::String::NewFromUtf8(isolate, "sectionBorderColorRgba"),
841 internal::RGBAColorToArray(isolate, theme_info.section_border_color));
842
843 // The theme alternate logo value indicates a white logo when TRUE and a
844 // colorful one when FALSE.
845 info->Set(v8::String::NewFromUtf8(isolate, "alternateLogo"),
846 v8::Boolean::New(isolate, theme_info.logo_alternate));
847
848 // The theme background image url is of format kCSSBackgroundImageFormat
849 // where both instances of "%s" are replaced with the id that identifies the
850 // theme.
851 // This is the CSS "background-image" format.
852 // Value is only valid if there's a custom theme background image.
853 if (extensions::Extension::IdIsValid(theme_info.theme_id)) {
854 info->Set(v8::String::NewFromUtf8(isolate, "imageUrl"),
855 UTF8ToV8String(isolate,
856 base::StringPrintf(kCSSBackgroundImageFormat,
857 theme_info.theme_id.c_str(),
858 theme_info.theme_id.c_str())));
859
860 // The theme background image horizontal alignment is one of "left",
861 // "right", "center".
862 // This is the horizontal component of the CSS "background-position" format.
863 // Value is only valid if |imageUrl| is not empty.
864 std::string alignment = kCSSBackgroundPositionCenter;
865 if (theme_info.image_horizontal_alignment ==
866 THEME_BKGRND_IMAGE_ALIGN_LEFT) {
867 alignment = kCSSBackgroundPositionLeft;
868 } else if (theme_info.image_horizontal_alignment ==
869 THEME_BKGRND_IMAGE_ALIGN_RIGHT) {
870 alignment = kCSSBackgroundPositionRight;
871 }
872 info->Set(v8::String::NewFromUtf8(isolate, "imageHorizontalAlignment"),
873 UTF8ToV8String(isolate, alignment));
874
875 // The theme background image vertical alignment is one of "top", "bottom",
876 // "center".
877 // This is the vertical component of the CSS "background-position" format.
878 // Value is only valid if |image_url| is not empty.
879 if (theme_info.image_vertical_alignment == THEME_BKGRND_IMAGE_ALIGN_TOP) {
880 alignment = kCSSBackgroundPositionTop;
881 } else if (theme_info.image_vertical_alignment ==
882 THEME_BKGRND_IMAGE_ALIGN_BOTTOM) {
883 alignment = kCSSBackgroundPositionBottom;
884 } else {
885 alignment = kCSSBackgroundPositionCenter;
886 }
887 info->Set(v8::String::NewFromUtf8(isolate, "imageVerticalAlignment"),
888 UTF8ToV8String(isolate, alignment));
889
890 // The tiling of the theme background image is one of "no-repeat",
891 // "repeat-x", "repeat-y", "repeat".
892 // This is the CSS "background-repeat" format.
893 // Value is only valid if |image_url| is not empty.
894 std::string tiling = kCSSBackgroundRepeatNo;
895 switch (theme_info.image_tiling) {
896 case THEME_BKGRND_IMAGE_NO_REPEAT:
897 tiling = kCSSBackgroundRepeatNo;
898 break;
899 case THEME_BKGRND_IMAGE_REPEAT_X:
900 tiling = kCSSBackgroundRepeatX;
901 break;
902 case THEME_BKGRND_IMAGE_REPEAT_Y:
903 tiling = kCSSBackgroundRepeatY;
904 break;
905 case THEME_BKGRND_IMAGE_REPEAT:
906 tiling = kCSSBackgroundRepeat;
907 break;
908 }
909 info->Set(v8::String::NewFromUtf8(isolate, "imageTiling"),
910 UTF8ToV8String(isolate, tiling));
911
912 // The theme background image height is only valid if |imageUrl| is valid.
913 info->Set(v8::String::NewFromUtf8(isolate, "imageHeight"),
914 v8::Int32::New(isolate, theme_info.image_height));
915
916 // The attribution URL is only valid if the theme has attribution logo.
917 if (theme_info.has_attribution) {
918 info->Set(
919 v8::String::NewFromUtf8(isolate, "attributionUrl"),
920 UTF8ToV8String(isolate,
921 base::StringPrintf(kThemeAttributionFormat,
922 theme_info.theme_id.c_str(),
923 theme_info.theme_id.c_str())));
924 }
925 }
926
927 args.GetReturnValue().Set(info);
928 }
929
930 // static
IsFocused(const v8::FunctionCallbackInfo<v8::Value> & args)931 void SearchBoxExtensionWrapper::IsFocused(
932 const v8::FunctionCallbackInfo<v8::Value>& args) {
933 content::RenderView* render_view = GetRenderView();
934 if (!render_view) return;
935
936 bool is_focused = SearchBox::Get(render_view)->is_focused();
937 DVLOG(1) << render_view << " IsFocused: " << is_focused;
938 args.GetReturnValue().Set(is_focused);
939 }
940
941 // static
IsInputInProgress(const v8::FunctionCallbackInfo<v8::Value> & args)942 void SearchBoxExtensionWrapper::IsInputInProgress(
943 const v8::FunctionCallbackInfo<v8::Value>& args) {
944 content::RenderView* render_view = GetRenderView();
945 if (!render_view) return;
946
947 bool is_input_in_progress =
948 SearchBox::Get(render_view)->is_input_in_progress();
949 DVLOG(1) << render_view << " IsInputInProgress: " << is_input_in_progress;
950 args.GetReturnValue().Set(is_input_in_progress);
951 }
952
953 // static
IsKeyCaptureEnabled(const v8::FunctionCallbackInfo<v8::Value> & args)954 void SearchBoxExtensionWrapper::IsKeyCaptureEnabled(
955 const v8::FunctionCallbackInfo<v8::Value>& args) {
956 content::RenderView* render_view = GetRenderView();
957 if (!render_view) return;
958
959 args.GetReturnValue().Set(SearchBox::Get(render_view)->
960 is_key_capture_enabled());
961 }
962
963 // static
LogEvent(const v8::FunctionCallbackInfo<v8::Value> & args)964 void SearchBoxExtensionWrapper::LogEvent(
965 const v8::FunctionCallbackInfo<v8::Value>& args) {
966 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
967 GURL(chrome::kChromeSearchMostVisitedUrl));
968 if (!render_view) return;
969
970 if (args.Length() < 1 || !args[0]->IsNumber())
971 return;
972
973 DVLOG(1) << render_view << " LogEvent";
974
975 if (args[0]->Uint32Value() < NTP_NUM_EVENT_TYPES) {
976 NTPLoggingEventType event =
977 static_cast<NTPLoggingEventType>(args[0]->Uint32Value());
978 SearchBox::Get(render_view)->LogEvent(event);
979 }
980 }
981
982 // static
LogMostVisitedImpression(const v8::FunctionCallbackInfo<v8::Value> & args)983 void SearchBoxExtensionWrapper::LogMostVisitedImpression(
984 const v8::FunctionCallbackInfo<v8::Value>& args) {
985 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
986 GURL(chrome::kChromeSearchMostVisitedUrl));
987 if (!render_view) return;
988
989 if (args.Length() < 2 || !args[0]->IsNumber() || args[1]->IsUndefined())
990 return;
991
992 DVLOG(1) << render_view << " LogMostVisitedImpression";
993
994 SearchBox::Get(render_view)->LogMostVisitedImpression(
995 args[0]->IntegerValue(), V8ValueToUTF16(args[1]));
996 }
997
998 // static
LogMostVisitedNavigation(const v8::FunctionCallbackInfo<v8::Value> & args)999 void SearchBoxExtensionWrapper::LogMostVisitedNavigation(
1000 const v8::FunctionCallbackInfo<v8::Value>& args) {
1001 content::RenderView* render_view = GetRenderViewWithCheckedOrigin(
1002 GURL(chrome::kChromeSearchMostVisitedUrl));
1003 if (!render_view) return;
1004
1005 if (args.Length() < 2 || !args[0]->IsNumber() || args[1]->IsUndefined())
1006 return;
1007
1008 DVLOG(1) << render_view << " LogMostVisitedNavigation";
1009
1010 SearchBox::Get(render_view)->LogMostVisitedNavigation(
1011 args[0]->IntegerValue(), V8ValueToUTF16(args[1]));
1012 }
1013
1014 // static
NavigateContentWindow(const v8::FunctionCallbackInfo<v8::Value> & args)1015 void SearchBoxExtensionWrapper::NavigateContentWindow(
1016 const v8::FunctionCallbackInfo<v8::Value>& args) {
1017 content::RenderView* render_view = GetRenderView();
1018 if (!render_view || !args.Length()) return;
1019
1020 GURL destination_url;
1021 bool is_most_visited_item_url = false;
1022 // Check if the url is a rid
1023 if (args[0]->IsNumber()) {
1024 InstantMostVisitedItem item;
1025 if (SearchBox::Get(render_view)->GetMostVisitedItemWithID(
1026 args[0]->IntegerValue(), &item)) {
1027 destination_url = item.url;
1028 is_most_visited_item_url = true;
1029 }
1030 } else {
1031 // Resolve the URL
1032 const base::string16& possibly_relative_url = V8ValueToUTF16(args[0]);
1033 GURL current_url = GetCurrentURL(render_view);
1034 destination_url = internal::ResolveURL(current_url, possibly_relative_url);
1035 }
1036
1037 DVLOG(1) << render_view << " NavigateContentWindow: " << destination_url;
1038
1039 // Navigate the main frame.
1040 if (destination_url.is_valid() &&
1041 !destination_url.SchemeIs(url::kJavaScriptScheme)) {
1042 WindowOpenDisposition disposition = CURRENT_TAB;
1043 if (args[1]->IsNumber()) {
1044 disposition = (WindowOpenDisposition) args[1]->Uint32Value();
1045 }
1046 SearchBox::Get(render_view)->NavigateToURL(destination_url, disposition,
1047 is_most_visited_item_url);
1048 }
1049 }
1050
1051 // static
Paste(const v8::FunctionCallbackInfo<v8::Value> & args)1052 void SearchBoxExtensionWrapper::Paste(
1053 const v8::FunctionCallbackInfo<v8::Value>& args) {
1054 content::RenderView* render_view = GetRenderView();
1055 if (!render_view) return;
1056
1057 base::string16 text;
1058 if (!args[0]->IsUndefined())
1059 text = V8ValueToUTF16(args[0]);
1060
1061 DVLOG(1) << render_view << " Paste: " << text;
1062 SearchBox::Get(render_view)->Paste(text);
1063 }
1064
1065 // static
StartCapturingKeyStrokes(const v8::FunctionCallbackInfo<v8::Value> & args)1066 void SearchBoxExtensionWrapper::StartCapturingKeyStrokes(
1067 const v8::FunctionCallbackInfo<v8::Value>& args) {
1068 content::RenderView* render_view = GetRenderView();
1069 if (!render_view) return;
1070
1071 DVLOG(1) << render_view << " StartCapturingKeyStrokes";
1072 SearchBox::Get(render_view)->StartCapturingKeyStrokes();
1073 }
1074
1075 // static
StopCapturingKeyStrokes(const v8::FunctionCallbackInfo<v8::Value> & args)1076 void SearchBoxExtensionWrapper::StopCapturingKeyStrokes(
1077 const v8::FunctionCallbackInfo<v8::Value>& args) {
1078 content::RenderView* render_view = GetRenderView();
1079 if (!render_view) return;
1080
1081 DVLOG(1) << render_view << " StopCapturingKeyStrokes";
1082 SearchBox::Get(render_view)->StopCapturingKeyStrokes();
1083 }
1084
1085 // static
SetVoiceSearchSupported(const v8::FunctionCallbackInfo<v8::Value> & args)1086 void SearchBoxExtensionWrapper::SetVoiceSearchSupported(
1087 const v8::FunctionCallbackInfo<v8::Value>& args) {
1088 content::RenderView* render_view = GetRenderView();
1089 if (!render_view || args.Length() < 1) return;
1090
1091 DVLOG(1) << render_view << " SetVoiceSearchSupported";
1092 SearchBox::Get(render_view)->SetVoiceSearchSupported(args[0]->BooleanValue());
1093 }
1094
1095 // static
UndoAllMostVisitedDeletions(const v8::FunctionCallbackInfo<v8::Value> & args)1096 void SearchBoxExtensionWrapper::UndoAllMostVisitedDeletions(
1097 const v8::FunctionCallbackInfo<v8::Value>& args) {
1098 content::RenderView* render_view = GetRenderView();
1099 if (!render_view) return;
1100
1101 DVLOG(1) << render_view << " UndoAllMostVisitedDeletions";
1102 SearchBox::Get(render_view)->UndoAllMostVisitedDeletions();
1103 }
1104
1105 // static
UndoMostVisitedDeletion(const v8::FunctionCallbackInfo<v8::Value> & args)1106 void SearchBoxExtensionWrapper::UndoMostVisitedDeletion(
1107 const v8::FunctionCallbackInfo<v8::Value>& args) {
1108 content::RenderView* render_view = GetRenderView();
1109 if (!render_view || !args.Length()) return;
1110
1111 DVLOG(1) << render_view << " UndoMostVisitedDeletion";
1112 SearchBox::Get(render_view)->UndoMostVisitedDeletion(args[0]->IntegerValue());
1113 }
1114
1115 // static
GetDisplayInstantResults(const v8::FunctionCallbackInfo<v8::Value> & args)1116 void SearchBoxExtensionWrapper::GetDisplayInstantResults(
1117 const v8::FunctionCallbackInfo<v8::Value>& args) {
1118 content::RenderView* render_view = GetRenderView();
1119 if (!render_view) return;
1120
1121 bool display_instant_results =
1122 SearchBox::Get(render_view)->display_instant_results();
1123 DVLOG(1) << render_view << " GetDisplayInstantResults" <<
1124 display_instant_results;
1125 args.GetReturnValue().Set(display_instant_results);
1126 }
1127
1128 } // namespace extensions_v8
1129