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/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 
     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 base::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 = 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.
    147 content::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.
    167 GURL 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 
    174 namespace internal {  // for testing.
    175 
    176 // Returns an array with the RGBA color components.
    177 v8::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.
    188 GURL 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 
    197 namespace extensions_v8 {
    198 
    199 static const char kSearchBoxExtensionName[] = "v8/EmbeddedSearch";
    200 
    201 // We first send this script down to determine if the page supports instant.
    202 static 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 
    214 static 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 
    226 static 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 
    237 static 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 
    248 static 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 
    259 static 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 
    270 static 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 
    281 static 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 
    292 static 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 
    303 static 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 
    314 static 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 
    325 static 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 
    338 class 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
    457 v8::Extension* SearchBoxExtension::Get() {
    458   return new SearchBoxExtensionWrapper(ResourceBundle::GetSharedInstance().
    459       GetRawDataResource(IDR_SEARCHBOX_API));
    460 }
    461 
    462 // static
    463 bool 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
    472 void 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
    485 void SearchBoxExtension::DispatchFocusChange(blink::WebFrame* frame) {
    486   Dispatch(frame, kDispatchFocusChangedScript);
    487 }
    488 
    489 // static
    490 void SearchBoxExtension::DispatchInputCancel(blink::WebFrame* frame) {
    491   Dispatch(frame, kDispatchInputCancelScript);
    492 }
    493 
    494 // static
    495 void SearchBoxExtension::DispatchInputStart(blink::WebFrame* frame) {
    496   Dispatch(frame, kDispatchInputStartScript);
    497 }
    498 
    499 // static
    500 void SearchBoxExtension::DispatchKeyCaptureChange(blink::WebFrame* frame) {
    501   Dispatch(frame, kDispatchKeyCaptureChangeScript);
    502 }
    503 
    504 // static
    505 void SearchBoxExtension::DispatchMarginChange(blink::WebFrame* frame) {
    506   Dispatch(frame, kDispatchMarginChangeEventScript);
    507 }
    508 
    509 // static
    510 void SearchBoxExtension::DispatchMostVisitedChanged(
    511     blink::WebFrame* frame) {
    512   Dispatch(frame, kDispatchMostVisitedChangedScript);
    513 }
    514 
    515 // static
    516 void SearchBoxExtension::DispatchSubmit(blink::WebFrame* frame) {
    517   Dispatch(frame, kDispatchSubmitEventScript);
    518 }
    519 
    520 // static
    521 void SearchBoxExtension::DispatchSuggestionChange(blink::WebFrame* frame) {
    522   Dispatch(frame, kDispatchSuggestionChangeEventScript);
    523 }
    524 
    525 // static
    526 void SearchBoxExtension::DispatchThemeChange(blink::WebFrame* frame) {
    527   Dispatch(frame, kDispatchThemeChangeEventScript);
    528 }
    529 
    530 // static
    531 void SearchBoxExtension::DispatchToggleVoiceSearch(
    532     blink::WebFrame* frame) {
    533   Dispatch(frame, kDispatchToggleVoiceSearchScript);
    534 }
    535 
    536 SearchBoxExtensionWrapper::SearchBoxExtensionWrapper(
    537     const base::StringPiece& code)
    538     : v8::Extension(kSearchBoxExtensionName, code.data(), 0, 0, code.size()) {
    539 }
    540 
    541 v8::Handle<v8::FunctionTemplate>
    542 SearchBoxExtensionWrapper::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
    609 content::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
    621 void 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
    633 void 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
    643 void 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
    653 void 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
    663 void 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
    684 void 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
    709 void 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
    732 void 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
    743 void SearchBoxExtensionWrapper::GetRightToLeft(
    744     const v8::FunctionCallbackInfo<v8::Value>& args) {
    745   args.GetReturnValue().Set(base::i18n::IsRTL());
    746 }
    747 
    748 // static
    749 void 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
    758 void 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
    775 void 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
    930 void 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
    941 void 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
    953 void 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
    963 void 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
    982 void 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
    998 void 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
   1014 void 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
   1051 void 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
   1065 void 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
   1075 void 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
   1085 void 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
   1095 void 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
   1105 void 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
   1115 void 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