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