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