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