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