• 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/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