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 <stddef.h>
8 #include <stdint.h>
9 #include <string>
10 #include <vector>
11 
12 #include "base/containers/flat_map.h"
13 #include "base/i18n/rtl.h"
14 #include "base/json/json_writer.h"
15 #include "base/json/string_escape.h"
16 #include "base/macros.h"
17 #include "base/metrics/histogram_macros.h"
18 #include "base/metrics/user_metrics.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/time/time.h"
24 #include "chrome/common/search/generated_colors_info.h"
25 #include "chrome/common/search/instant_types.h"
26 #include "chrome/common/search/ntp_logging_events.h"
27 #include "chrome/common/search/selected_colors_info.h"
28 #include "chrome/common/url_constants.h"
29 #include "chrome/grit/renderer_resources.h"
30 #include "chrome/renderer/searchbox/searchbox.h"
31 #include "components/crx_file/id_util.h"
32 #include "components/ntp_tiles/features.h"
33 #include "components/ntp_tiles/ntp_tile_impression.h"
34 #include "components/ntp_tiles/tile_source.h"
35 #include "components/ntp_tiles/tile_visual_type.h"
36 #include "content/public/common/url_constants.h"
37 #include "content/public/renderer/chrome_object_extensions_utils.h"
38 #include "content/public/renderer/render_frame.h"
39 #include "content/public/renderer/render_thread.h"
40 #include "content/public/renderer/render_view.h"
41 #include "gin/data_object_builder.h"
42 #include "gin/handle.h"
43 #include "gin/object_template_builder.h"
44 #include "gin/wrappable.h"
45 #include "third_party/blink/public/common/page/page_zoom.h"
46 #include "third_party/blink/public/platform/web_string.h"
47 #include "third_party/blink/public/platform/web_url_request.h"
48 #include "third_party/blink/public/web/blink.h"
49 #include "third_party/blink/public/web/web_document.h"
50 #include "third_party/blink/public/web/web_local_frame.h"
51 #include "third_party/blink/public/web/web_script_source.h"
52 #include "third_party/blink/public/web/web_view.h"
53 #include "ui/base/l10n/l10n_util.h"
54 #include "ui/base/resource/resource_bundle.h"
55 #include "ui/base/window_open_disposition.h"
56 #include "ui/events/keycodes/keyboard_codes.h"
57 #include "ui/gfx/color_utils.h"
58 #include "ui/gfx/text_constants.h"
59 #include "ui/gfx/text_elider.h"
60 #include "url/gurl.h"
61 #include "url/url_constants.h"
62 #include "v8/include/v8.h"
63 
64 namespace {
65 
66 const char kCSSBackgroundImageFormat[] = "-webkit-image-set("
67     "url(chrome-search://theme/IDR_THEME_NTP_BACKGROUND?%s) 1x, "
68     "url(chrome-search://theme/IDR_THEME_NTP_BACKGROUND@2x?%s) 2x)";
69 
70 const char kCSSBackgroundPositionCenter[] = "center";
71 const char kCSSBackgroundPositionLeft[] = "left";
72 const char kCSSBackgroundPositionTop[] = "top";
73 const char kCSSBackgroundPositionRight[] = "right";
74 const char kCSSBackgroundPositionBottom[] = "bottom";
75 
76 const char kCSSBackgroundRepeatNo[] = "no-repeat";
77 const char kCSSBackgroundRepeatX[] = "repeat-x";
78 const char kCSSBackgroundRepeatY[] = "repeat-y";
79 const char kCSSBackgroundRepeat[] = "repeat";
80 
81 const char kThemeAttributionFormat[] = "-webkit-image-set("
82     "url(chrome-search://theme/IDR_THEME_NTP_ATTRIBUTION?%s) 1x, "
83     "url(chrome-search://theme/IDR_THEME_NTP_ATTRIBUTION@2x?%s) 2x)";
84 
85 const char kLTRHtmlTextDirection[] = "ltr";
86 const char kRTLHtmlTextDirection[] = "rtl";
87 
88 // Max character limit for custom link titles.
89 const size_t kMaxCustomLinkTitleLength = 150;
90 
Dispatch(blink::WebLocalFrame * frame,const blink::WebString & script)91 void Dispatch(blink::WebLocalFrame* frame, const blink::WebString& script) {
92   if (!frame)
93     return;
94   frame->ExecuteScript(blink::WebScriptSource(script));
95 }
96 
97 // Populates a Javascript MostVisitedItem object for returning from
98 // newTabPage.mostVisited. This does not include private data such as "url" or
99 // "title".
GenerateMostVisitedItem(v8::Isolate * isolate,float device_pixel_ratio,int render_view_id,InstantRestrictedID restricted_id)100 v8::Local<v8::Object> GenerateMostVisitedItem(
101     v8::Isolate* isolate,
102     float device_pixel_ratio,
103     int render_view_id,
104     InstantRestrictedID restricted_id) {
105   return gin::DataObjectBuilder(isolate)
106       .Set("rid", restricted_id)
107       .Set("faviconUrl", base::StringPrintf(
108                              "chrome-search://favicon/size/16@%fx/%d/%d",
109                              device_pixel_ratio, render_view_id, restricted_id))
110       .Build();
111 }
112 
113 // Populates a Javascript MostVisitedItem object appropriate for returning from
114 // newTabPage.getMostVisitedItemData.
115 // NOTE: Includes private data such as "url", "title", and "domain", so this
116 // should not be returned to the host page (via newTabPage.mostVisited). It is
117 // only accessible to most-visited iframes via getMostVisitedItemData.
GenerateMostVisitedItemData(v8::Isolate * isolate,int render_view_id,InstantRestrictedID restricted_id,const InstantMostVisitedItem & mv_item)118 v8::Local<v8::Object> GenerateMostVisitedItemData(
119     v8::Isolate* isolate,
120     int render_view_id,
121     InstantRestrictedID restricted_id,
122     const InstantMostVisitedItem& mv_item) {
123   // We set the "dir" attribute of the title, so that in RTL locales, a LTR
124   // title is rendered left-to-right and truncated from the right. For
125   // example, the title of http://msdn.microsoft.com/en-us/default.aspx is
126   // "MSDN: Microsoft developer network". In RTL locales, in the New Tab
127   // page, if the "dir" of this title is not specified, it takes Chrome UI's
128   // directionality. So the title will be truncated as "soft developer
129   // network". Setting the "dir" attribute as "ltr" renders the truncated
130   // title as "MSDN: Microsoft D...". As another example, the title of
131   // http://yahoo.com is "Yahoo!". In RTL locales, in the New Tab page, the
132   // title will be rendered as "!Yahoo" if its "dir" attribute is not set to
133   // "ltr".
134   const char* direction;
135   if (base::i18n::GetFirstStrongCharacterDirection(mv_item.title) ==
136       base::i18n::RIGHT_TO_LEFT) {
137     direction = kRTLHtmlTextDirection;
138   } else {
139     direction = kLTRHtmlTextDirection;
140   }
141 
142   std::string title = base::UTF16ToUTF8(mv_item.title);
143   if (title.empty())
144     title = mv_item.url.spec();
145 
146   gin::DataObjectBuilder builder(isolate);
147   builder.Set("renderViewId", render_view_id)
148       .Set("rid", restricted_id)
149       .Set("tileTitleSource", static_cast<int>(mv_item.title_source))
150       .Set("tileSource", static_cast<int>(mv_item.source))
151       .Set("title", title)
152       .Set("domain", mv_item.url.host())
153       .Set("direction", base::StringPiece(direction))
154       .Set("url", mv_item.url.spec())
155       .Set("dataGenerationTime",
156            mv_item.data_generation_time.is_null()
157                ? v8::Local<v8::Value>(v8::Null(isolate))
158                : v8::Date::New(isolate->GetCurrentContext(),
159                                mv_item.data_generation_time.ToJsTime())
160                      .ToLocalChecked());
161 
162   // If the suggestion already has a favicon, we populate the element with it.
163   if (!mv_item.favicon.spec().empty())
164     builder.Set("faviconUrl", mv_item.favicon.spec());
165 
166   return builder.Build();
167 }
168 
ConvertDateValueToTime(v8::Value * value)169 base::Time ConvertDateValueToTime(v8::Value* value) {
170   DCHECK(value);
171   if (value->IsNull() || !value->IsDate())
172     return base::Time();
173 
174   return base::Time::FromJsTime(v8::Date::Cast(value)->ValueOf());
175 }
176 
CoerceToInt(v8::Isolate * isolate,v8::Value * value)177 base::Optional<int> CoerceToInt(v8::Isolate* isolate, v8::Value* value) {
178   DCHECK(value);
179   v8::MaybeLocal<v8::Int32> maybe_int =
180       value->ToInt32(isolate->GetCurrentContext());
181   if (maybe_int.IsEmpty())
182     return base::nullopt;
183   return maybe_int.ToLocalChecked()->Value();
184 }
185 
186 // Returns an array with the RGBA color components.
SkColorToArray(v8::Isolate * isolate,const SkColor & color)187 v8::Local<v8::Value> SkColorToArray(v8::Isolate* isolate,
188                                     const SkColor& color) {
189   v8::Local<v8::Context> context = isolate->GetCurrentContext();
190   v8::Local<v8::Array> color_array = v8::Array::New(isolate, 4);
191   color_array
192       ->CreateDataProperty(context, 0,
193                            v8::Int32::New(isolate, SkColorGetR(color)))
194       .Check();
195   color_array
196       ->CreateDataProperty(context, 1,
197                            v8::Int32::New(isolate, SkColorGetG(color)))
198       .Check();
199   color_array
200       ->CreateDataProperty(context, 2,
201                            v8::Int32::New(isolate, SkColorGetB(color)))
202       .Check();
203   color_array
204       ->CreateDataProperty(context, 3,
205                            v8::Int32::New(isolate, SkColorGetA(color)))
206       .Check();
207   return color_array;
208 }
209 
210 // Converts given array to SkColor and returns whether the conversion is
211 // successful.
ArrayToSkColor(v8::Isolate * isolate,v8::Local<v8::Array> color,SkColor * color_result)212 bool ArrayToSkColor(v8::Isolate* isolate,
213                     v8::Local<v8::Array> color,
214                     SkColor* color_result) {
215   if (color->Length() != 4)
216     return false;
217 
218   v8::Local<v8::Context> context = isolate->GetCurrentContext();
219   v8::Local<v8::Value> r_value;
220   v8::Local<v8::Value> g_value;
221   v8::Local<v8::Value> b_value;
222   v8::Local<v8::Value> a_value;
223 
224   if (!color->Get(context, 0).ToLocal(&r_value) ||
225       !color->Get(context, 1).ToLocal(&g_value) ||
226       !color->Get(context, 2).ToLocal(&b_value) ||
227       !color->Get(context, 3).ToLocal(&a_value))
228     return false;
229 
230   base::Optional<int> r = CoerceToInt(isolate, *r_value);
231   base::Optional<int> g = CoerceToInt(isolate, *g_value);
232   base::Optional<int> b = CoerceToInt(isolate, *b_value);
233   base::Optional<int> a = CoerceToInt(isolate, *a_value);
234 
235   if (!r.has_value() || !g.has_value() || !b.has_value() || !a.has_value())
236     return false;
237 
238   if (*a > 255 || *r > 255 || *g > 255 || *b > 255)
239     return false;
240 
241   *color_result = SkColorSetARGB(*a, *r, *g, *b);
242   return true;
243 }
244 
GenerateNtpTheme(v8::Isolate * isolate,const NtpTheme & theme)245 v8::Local<v8::Object> GenerateNtpTheme(v8::Isolate* isolate,
246                                        const NtpTheme& theme) {
247   gin::DataObjectBuilder builder(isolate);
248 
249   // True if the theme is the system default and no custom theme has been
250   // applied.
251   // Value is always valid.
252   builder.Set("usingDefaultTheme", theme.using_default_theme);
253 
254   // Theme color for background as an array with the RGBA components in order.
255   // Value is always valid.
256   builder.Set("backgroundColorRgba",
257               SkColorToArray(isolate, theme.background_color));
258 
259   // Theme color for text as an array with the RGBA components in order.
260   // Value is always valid.
261   builder.Set("textColorRgba", SkColorToArray(isolate, theme.text_color));
262 
263   // Theme color for light text as an array with the RGBA components in order.
264   // Value is always valid.
265   builder.Set("textColorLightRgba",
266               SkColorToArray(isolate, theme.text_color_light));
267 
268   // The theme alternate logo value indicates same color when TRUE and a
269   // colorful one when FALSE.
270   builder.Set("alternateLogo", theme.logo_alternate);
271 
272   // The theme background image url is of format kCSSBackgroundImageFormat
273   // where both instances of "%s" are replaced with the id that identifies the
274   // theme.
275   // This is the CSS "background-image" format.
276   // Value is only valid if there's a custom theme background image.
277   if (theme.has_theme_image) {
278     builder.Set("imageUrl", base::StringPrintf(kCSSBackgroundImageFormat,
279                                                theme.theme_id.c_str(),
280                                                theme.theme_id.c_str()));
281 
282     // The theme background image horizontal alignment is one of "left",
283     // "right", "center".
284     // This is the horizontal component of the CSS "background-position" format.
285     // Value is only valid if |imageUrl| is not empty.
286     std::string alignment = kCSSBackgroundPositionCenter;
287     if (theme.image_horizontal_alignment == THEME_BKGRND_IMAGE_ALIGN_LEFT) {
288       alignment = kCSSBackgroundPositionLeft;
289     } else if (theme.image_horizontal_alignment ==
290                THEME_BKGRND_IMAGE_ALIGN_RIGHT) {
291       alignment = kCSSBackgroundPositionRight;
292     }
293     builder.Set("imageHorizontalAlignment", alignment);
294 
295     // The theme background image vertical alignment is one of "top", "bottom",
296     // "center".
297     // This is the vertical component of the CSS "background-position" format.
298     // Value is only valid if |image_url| is not empty.
299     if (theme.image_vertical_alignment == THEME_BKGRND_IMAGE_ALIGN_TOP) {
300       alignment = kCSSBackgroundPositionTop;
301     } else if (theme.image_vertical_alignment ==
302                THEME_BKGRND_IMAGE_ALIGN_BOTTOM) {
303       alignment = kCSSBackgroundPositionBottom;
304     } else {
305       alignment = kCSSBackgroundPositionCenter;
306     }
307     builder.Set("imageVerticalAlignment", alignment);
308 
309     // The tiling of the theme background image is one of "no-repeat",
310     // "repeat-x", "repeat-y", "repeat".
311     // This is the CSS "background-repeat" format.
312     // Value is only valid if |image_url| is not empty.
313     std::string tiling = kCSSBackgroundRepeatNo;
314     switch (theme.image_tiling) {
315       case THEME_BKGRND_IMAGE_NO_REPEAT:
316         tiling = kCSSBackgroundRepeatNo;
317         break;
318       case THEME_BKGRND_IMAGE_REPEAT_X:
319         tiling = kCSSBackgroundRepeatX;
320         break;
321       case THEME_BKGRND_IMAGE_REPEAT_Y:
322         tiling = kCSSBackgroundRepeatY;
323         break;
324       case THEME_BKGRND_IMAGE_REPEAT:
325         tiling = kCSSBackgroundRepeat;
326         break;
327     }
328     builder.Set("imageTiling", tiling);
329 
330     // The attribution URL is only valid if the theme has attribution logo.
331     if (theme.has_attribution) {
332       builder.Set("attributionUrl", base::StringPrintf(kThemeAttributionFormat,
333                                                        theme.theme_id.c_str(),
334                                                        theme.theme_id.c_str()));
335     }
336   }
337 
338   builder.Set("themeId", theme.theme_id);
339   builder.Set("themeName", theme.theme_name);
340 
341   builder.Set("customBackgroundDisabledByPolicy",
342               theme.custom_background_disabled_by_policy);
343   builder.Set("customBackgroundConfigured",
344               !theme.custom_background_url.is_empty());
345 
346   // If a custom background has been set provide the relevant information to the
347   // page.
348   if (!theme.custom_background_url.is_empty()) {
349     builder.Set("imageUrl", theme.custom_background_url.spec());
350     builder.Set("attributionActionUrl",
351                 theme.custom_background_attribution_action_url.spec());
352     builder.Set("attribution1", theme.custom_background_attribution_line_1);
353     builder.Set("attribution2", theme.custom_background_attribution_line_2);
354     builder.Set("collectionId", theme.collection_id);
355     // Clear the theme attribution url, as it shouldn't be shown when
356     // a custom background is set.
357     builder.Set("attributionUrl", std::string());
358   }
359 
360   // Set fields for themeing NTP elements.
361   builder.Set("isNtpBackgroundDark", !color_utils::IsDark(theme.text_color));
362   builder.Set("useTitleContainer", theme.has_theme_image);
363 
364   // TODO(gayane): Rename icon color to shortcut color in JS for consitancy.
365   builder.Set("iconBackgroundColor",
366               SkColorToArray(isolate, theme.shortcut_color));
367   builder.Set("useWhiteAddIcon", color_utils::IsDark(theme.shortcut_color));
368 
369   builder.Set("logoColor", SkColorToArray(isolate, theme.logo_color));
370 
371   builder.Set("colorId", theme.color_id);
372   if (theme.color_id != -1) {
373     builder.Set("colorDark", SkColorToArray(isolate, theme.color_dark));
374     builder.Set("colorLight", SkColorToArray(isolate, theme.color_light));
375     builder.Set("colorPicked", SkColorToArray(isolate, theme.color_picked));
376   }
377 
378   gin::DataObjectBuilder search_box(isolate);
379   search_box.Set("bg", SkColorToArray(isolate, theme.search_box.bg));
380   search_box.Set("icon", SkColorToArray(isolate, theme.search_box.icon));
381   search_box.Set("iconSelected",
382                  SkColorToArray(isolate, theme.search_box.icon_selected));
383   search_box.Set("placeholder",
384                  SkColorToArray(isolate, theme.search_box.placeholder));
385   search_box.Set("resultsBg",
386                  SkColorToArray(isolate, theme.search_box.results_bg));
387   search_box.Set("resultsBgHovered",
388                  SkColorToArray(isolate, theme.search_box.results_bg_hovered));
389   search_box.Set("resultsBgSelected",
390                  SkColorToArray(isolate, theme.search_box.results_bg_selected));
391   search_box.Set("resultsDim",
392                  SkColorToArray(isolate, theme.search_box.results_dim));
393   search_box.Set(
394       "resultsDimSelected",
395       SkColorToArray(isolate, theme.search_box.results_dim_selected));
396   search_box.Set("resultsText",
397                  SkColorToArray(isolate, theme.search_box.results_text));
398   search_box.Set(
399       "resultsTextSelected",
400       SkColorToArray(isolate, theme.search_box.results_text_selected));
401   search_box.Set("resultsUrl",
402                  SkColorToArray(isolate, theme.search_box.results_url));
403   search_box.Set(
404       "resultsUrlSelected",
405       SkColorToArray(isolate, theme.search_box.results_url_selected));
406   search_box.Set("text", SkColorToArray(isolate, theme.search_box.text));
407   builder.Set("searchBox", search_box.Build());
408 
409   return builder.Build();
410 }
411 
GetMainRenderFrameForCurrentContext()412 content::RenderFrame* GetMainRenderFrameForCurrentContext() {
413   blink::WebLocalFrame* frame = blink::WebLocalFrame::FrameForCurrentContext();
414   if (!frame)
415     return nullptr;
416   content::RenderFrame* main_frame =
417       content::RenderFrame::FromWebFrame(frame->LocalRoot());
418   if (!main_frame || !main_frame->IsMainFrame())
419     return nullptr;
420   return main_frame;
421 }
422 
GetSearchBoxForCurrentContext()423 SearchBox* GetSearchBoxForCurrentContext() {
424   content::RenderFrame* main_frame = GetMainRenderFrameForCurrentContext();
425   if (!main_frame)
426     return nullptr;
427   return SearchBox::Get(main_frame);
428 }
429 
CreateAutocompleteMatches(const std::vector<search::mojom::AutocompleteMatchPtr> & matches)430 base::Value CreateAutocompleteMatches(
431     const std::vector<search::mojom::AutocompleteMatchPtr>& matches) {
432   base::Value list(base::Value::Type::LIST);
433   for (const search::mojom::AutocompleteMatchPtr& match : matches) {
434     base::Value dict(base::Value::Type::DICTIONARY);
435     dict.SetBoolKey("allowedToBeDefaultMatch",
436                     match->allowed_to_be_default_match);
437     dict.SetStringKey("contents", match->contents);
438     base::Value contents_class(base::Value::Type::LIST);
439     for (const auto& classification : match->contents_class) {
440       base::Value entry(base::Value::Type::DICTIONARY);
441       entry.SetIntKey("offset", classification->offset);
442       entry.SetIntKey("style", classification->style);
443       contents_class.Append(std::move(entry));
444     }
445     dict.SetKey("contentsClass", std::move(contents_class));
446     dict.SetStringKey("description", match->description);
447     base::Value description_class(base::Value::Type::LIST);
448     for (const auto& classification : match->description_class) {
449       base::Value entry(base::Value::Type::DICTIONARY);
450       entry.SetIntKey("offset", classification->offset);
451       entry.SetIntKey("style", classification->style);
452       description_class.Append(std::move(entry));
453     }
454     dict.SetKey("descriptionClass", std::move(description_class));
455     dict.SetStringKey("destinationUrl", match->destination_url.spec());
456     dict.SetIntKey("suggestionGroupId", match->suggestion_group_id);
457     dict.SetStringKey("inlineAutocompletion", match->inline_autocompletion);
458     dict.SetBoolKey("isSearchType", match->is_search_type);
459     dict.SetStringKey("fillIntoEdit", match->fill_into_edit);
460     dict.SetStringKey("iconUrl", match->icon_url);
461     dict.SetStringKey("imageDominantColor", match->image_dominant_color);
462     dict.SetStringKey("imageUrl", match->image_url);
463     dict.SetBoolKey("swapContentsAndDescription",
464                     match->swap_contents_and_description);
465     dict.SetStringKey("type", match->type);
466     dict.SetBoolKey("supportsDeletion", match->supports_deletion);
467     list.Append(std::move(dict));
468   }
469   return list;
470 }
471 
CreateSuggestionGroupsMap(const base::flat_map<int32_t,search::mojom::SuggestionGroupPtr> & suggestion_groups_map)472 base::Value CreateSuggestionGroupsMap(
473     const base::flat_map<int32_t, search::mojom::SuggestionGroupPtr>&
474         suggestion_groups_map) {
475   base::Value result_map(base::Value::Type::DICTIONARY);
476   for (const auto& pair : suggestion_groups_map) {
477     base::Value suggestion_group(base::Value::Type::DICTIONARY);
478     suggestion_group.SetStringKey("header", pair.second->header);
479     suggestion_group.SetBoolKey("hidden", pair.second->hidden);
480     result_map.SetPath(base::NumberToString(pair.first),
481                        std::move(suggestion_group));
482   }
483   return result_map;
484 }
485 
486 static const char kDispatchFocusChangedScript[] =
487     "if (window.chrome &&"
488     "    window.chrome.embeddedSearch &&"
489     "    window.chrome.embeddedSearch.searchBox &&"
490     "    window.chrome.embeddedSearch.searchBox.onfocuschange &&"
491     "    typeof window.chrome.embeddedSearch.searchBox.onfocuschange =="
492     "         'function') {"
493     "  window.chrome.embeddedSearch.searchBox.onfocuschange();"
494     "  true;"
495     "}";
496 
497 static const char kDispatchAddCustomLinkResult[] =
498     "if (window.chrome &&"
499     "    window.chrome.embeddedSearch &&"
500     "    window.chrome.embeddedSearch.newTabPage &&"
501     "    window.chrome.embeddedSearch.newTabPage.onaddcustomlinkdone &&"
502     "    typeof window.chrome.embeddedSearch.newTabPage"
503     "        .onaddcustomlinkdone === 'function') {"
504     "  window.chrome.embeddedSearch.newTabPage.onaddcustomlinkdone(%s);"
505     "  true;"
506     "}";
507 
508 static const char kDispatchUpdateCustomLinkResult[] =
509     "if (window.chrome &&"
510     "    window.chrome.embeddedSearch &&"
511     "    window.chrome.embeddedSearch.newTabPage &&"
512     "    window.chrome.embeddedSearch.newTabPage.onupdatecustomlinkdone &&"
513     "    typeof window.chrome.embeddedSearch.newTabPage"
514     "        .onupdatecustomlinkdone === 'function') {"
515     "  window.chrome.embeddedSearch.newTabPage.onupdatecustomlinkdone(%s);"
516     "  true;"
517     "}";
518 
519 static const char kDispatchAutocompleteResultChanged[] =
520     "if (window.chrome &&"
521     "    window.chrome.embeddedSearch &&"
522     "    window.chrome.embeddedSearch.searchBox &&"
523     "    window.chrome.embeddedSearch.searchBox.autocompleteresultchanged &&"
524     "    typeof window.chrome.embeddedSearch.searchBox"
525     "        .autocompleteresultchanged === 'function') {"
526     "  window.chrome.embeddedSearch.searchBox.autocompleteresultchanged(%s);"
527     "  true;"
528     "}";
529 
530 static const char kDispatchAutocompleteMatchImageAvailable[] =
531     "if (window.chrome &&"
532     "    window.chrome.embeddedSearch &&"
533     "    window.chrome.embeddedSearch.searchBox &&"
534     "    "
535     "window.chrome.embeddedSearch.searchBox.autocompletematchimageavailable &&"
536     "    typeof window.chrome.embeddedSearch.searchBox"
537     "        .autocompletematchimageavailable === 'function') {"
538     "  window.chrome.embeddedSearch.searchBox"
539     "      .autocompletematchimageavailable(%d, '%s', '%s');"
540     "  true;"
541     "}";
542 
543 static const char kDispatchDeleteCustomLinkResult[] =
544     "if (window.chrome &&"
545     "    window.chrome.embeddedSearch &&"
546     "    window.chrome.embeddedSearch.newTabPage &&"
547     "    window.chrome.embeddedSearch.newTabPage.ondeletecustomlinkdone &&"
548     "    typeof window.chrome.embeddedSearch.newTabPage"
549     "        .ondeletecustomlinkdone === 'function') {"
550     "  window.chrome.embeddedSearch.newTabPage.ondeletecustomlinkdone(%s);"
551     "  true;"
552     "}";
553 
554 static const char kDispatchInputCancelScript[] =
555     "if (window.chrome &&"
556     "    window.chrome.embeddedSearch &&"
557     "    window.chrome.embeddedSearch.newTabPage &&"
558     "    window.chrome.embeddedSearch.newTabPage.oninputcancel &&"
559     "    typeof window.chrome.embeddedSearch.newTabPage.oninputcancel =="
560     "         'function') {"
561     "  window.chrome.embeddedSearch.newTabPage.oninputcancel();"
562     "  true;"
563     "}";
564 
565 static const char kDispatchInputStartScript[] =
566     "if (window.chrome &&"
567     "    window.chrome.embeddedSearch &&"
568     "    window.chrome.embeddedSearch.newTabPage &&"
569     "    window.chrome.embeddedSearch.newTabPage.oninputstart &&"
570     "    typeof window.chrome.embeddedSearch.newTabPage.oninputstart =="
571     "         'function') {"
572     "  window.chrome.embeddedSearch.newTabPage.oninputstart();"
573     "  true;"
574     "}";
575 
576 static const char kDispatchKeyCaptureChangeScript[] =
577     "if (window.chrome &&"
578     "    window.chrome.embeddedSearch &&"
579     "    window.chrome.embeddedSearch.searchBox &&"
580     "    window.chrome.embeddedSearch.searchBox.onkeycapturechange &&"
581     "    typeof window.chrome.embeddedSearch.searchBox.onkeycapturechange =="
582     "        'function') {"
583     "  window.chrome.embeddedSearch.searchBox.onkeycapturechange();"
584     "  true;"
585     "}";
586 
587 static const char kDispatchMostVisitedChangedScript[] =
588     "if (window.chrome &&"
589     "    window.chrome.embeddedSearch &&"
590     "    window.chrome.embeddedSearch.newTabPage &&"
591     "    window.chrome.embeddedSearch.newTabPage.onmostvisitedchange &&"
592     "    typeof window.chrome.embeddedSearch.newTabPage.onmostvisitedchange =="
593     "         'function') {"
594     "  window.chrome.embeddedSearch.newTabPage.onmostvisitedchange();"
595     "  true;"
596     "}";
597 
598 static const char kDispatchThemeChangeEventScript[] =
599     "if (window.chrome &&"
600     "    window.chrome.embeddedSearch &&"
601     "    window.chrome.embeddedSearch.newTabPage &&"
602     "    window.chrome.embeddedSearch.newTabPage.onthemechange &&"
603     "    typeof window.chrome.embeddedSearch.newTabPage.onthemechange =="
604     "        'function') {"
605     "  window.chrome.embeddedSearch.newTabPage.onthemechange();"
606     "  true;"
607     "}";
608 
609 static const char kDispatchLocalBackgroundSelectedScript[] =
610     "if (window.chrome &&"
611     "    window.chrome.embeddedSearch &&"
612     "    window.chrome.embeddedSearch.newTabPage &&"
613     "    window.chrome.embeddedSearch.newTabPage.onlocalbackgroundselected &&"
614     "    typeof "
615     "window.chrome.embeddedSearch.newTabPage.onlocalbackgroundselected =="
616     "        'function') {"
617     "  "
618     "window.chrome.embeddedSearch.newTabPage."
619     "onlocalbackgroundselected();"
620     "  true;"
621     "}";
622 
623 // ----------------------------------------------------------------------------
624 
625 class SearchBoxBindings : public gin::Wrappable<SearchBoxBindings> {
626  public:
627   static gin::WrapperInfo kWrapperInfo;
628 
629   SearchBoxBindings();
630   ~SearchBoxBindings() override;
631 
632  private:
633   // gin::Wrappable.
634   gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
635       v8::Isolate* isolate) final;
636 
637   // Handlers for JS properties.
638   static bool IsFocused();
639   static bool IsKeyCaptureEnabled();
640 
641   // Handlers for JS functions.
642   static void DeleteAutocompleteMatch(int line);
643   static void Paste(const std::string& text);
644   static void QueryAutocomplete(const base::string16& input,
645                                 bool prevent_inline_autocomplete);
646   static void StopAutocomplete(bool clear_result);
647   static void LogCharTypedToRepaintLatency(uint32_t latency_ms);
648   static void StartCapturingKeyStrokes();
649   static void StopCapturingKeyStrokes();
650   static void OpenAutocompleteMatch(int line,
651                                     const std::string& url,
652                                     bool are_matches_showing,
653                                     double time_elapsed_since_last_focus,
654                                     double button,
655                                     bool alt_key,
656                                     bool ctrl_key,
657                                     bool meta_key,
658                                     bool shift_key);
659   static void ToggleSuggestionGroupIdVisibility(int32_t suggestion_group_id);
660 
661   DISALLOW_COPY_AND_ASSIGN(SearchBoxBindings);
662 };
663 
664 gin::WrapperInfo SearchBoxBindings::kWrapperInfo = {gin::kEmbedderNativeGin};
665 
666 SearchBoxBindings::SearchBoxBindings() = default;
667 
668 SearchBoxBindings::~SearchBoxBindings() = default;
669 
GetObjectTemplateBuilder(v8::Isolate * isolate)670 gin::ObjectTemplateBuilder SearchBoxBindings::GetObjectTemplateBuilder(
671     v8::Isolate* isolate) {
672   return gin::Wrappable<SearchBoxBindings>::GetObjectTemplateBuilder(isolate)
673       .SetProperty("rtl", &base::i18n::IsRTL)
674       .SetProperty("isFocused", &SearchBoxBindings::IsFocused)
675       .SetProperty("isKeyCaptureEnabled",
676                    &SearchBoxBindings::IsKeyCaptureEnabled)
677       .SetMethod("deleteAutocompleteMatch",
678                  &SearchBoxBindings::DeleteAutocompleteMatch)
679       .SetMethod("logCharTypedToRepaintLatency",
680                  &SearchBoxBindings::LogCharTypedToRepaintLatency)
681       .SetMethod("openAutocompleteMatch",
682                  &SearchBoxBindings::OpenAutocompleteMatch)
683       .SetMethod("paste", &SearchBoxBindings::Paste)
684       .SetMethod("queryAutocomplete", &SearchBoxBindings::QueryAutocomplete)
685       .SetMethod("stopAutocomplete", &SearchBoxBindings::StopAutocomplete)
686       .SetMethod("startCapturingKeyStrokes",
687                  &SearchBoxBindings::StartCapturingKeyStrokes)
688       .SetMethod("stopCapturingKeyStrokes",
689                  &SearchBoxBindings::StopCapturingKeyStrokes)
690       .SetMethod("toggleSuggestionGroupIdVisibility",
691                  &SearchBoxBindings::ToggleSuggestionGroupIdVisibility);
692 }
693 
694 // static
IsFocused()695 bool SearchBoxBindings::IsFocused() {
696   const SearchBox* search_box = GetSearchBoxForCurrentContext();
697   if (!search_box)
698     return false;
699   return search_box->is_focused();
700 }
701 
702 // static
IsKeyCaptureEnabled()703 bool SearchBoxBindings::IsKeyCaptureEnabled() {
704   const SearchBox* search_box = GetSearchBoxForCurrentContext();
705   if (!search_box)
706     return false;
707   return search_box->is_key_capture_enabled();
708 }
709 
710 // static
DeleteAutocompleteMatch(int line)711 void SearchBoxBindings::DeleteAutocompleteMatch(int line) {
712   DCHECK_GE(line, 0);
713   DCHECK_LE(line, 255);
714   SearchBox* search_box = GetSearchBoxForCurrentContext();
715   if (!search_box)
716     return;
717   search_box->DeleteAutocompleteMatch(line);
718 }
719 
720 // static
ToggleSuggestionGroupIdVisibility(int32_t suggestion_group_id)721 void SearchBoxBindings::ToggleSuggestionGroupIdVisibility(
722     int32_t suggestion_group_id) {
723   SearchBox* search_box = GetSearchBoxForCurrentContext();
724   if (!search_box)
725     return;
726   search_box->ToggleSuggestionGroupIdVisibility(suggestion_group_id);
727 }
728 
729 // static
OpenAutocompleteMatch(int line,const std::string & url,bool are_matches_showing,double time_elapsed_since_last_focus,double button,bool alt_key,bool ctrl_key,bool meta_key,bool shift_key)730 void SearchBoxBindings::OpenAutocompleteMatch(
731     int line,
732     const std::string& url,
733     bool are_matches_showing,
734     double time_elapsed_since_last_focus,
735     double button,
736     bool alt_key,
737     bool ctrl_key,
738     bool meta_key,
739     bool shift_key) {
740   DCHECK_GE(line, 0);
741   DCHECK_LE(line, 255);
742   SearchBox* search_box = GetSearchBoxForCurrentContext();
743   if (!search_box)
744     return;
745 
746   search_box->OpenAutocompleteMatch(line, GURL(url), are_matches_showing,
747                                     time_elapsed_since_last_focus, button,
748                                     alt_key, ctrl_key, meta_key, shift_key);
749 }
750 
751 // static
Paste(const std::string & text)752 void SearchBoxBindings::Paste(const std::string& text) {
753   SearchBox* search_box = GetSearchBoxForCurrentContext();
754   if (!search_box)
755     return;
756   search_box->Paste(base::UTF8ToUTF16(text));
757 }
758 
759 // static
QueryAutocomplete(const base::string16 & input,bool prevent_inline_autocomplete)760 void SearchBoxBindings::QueryAutocomplete(const base::string16& input,
761                                           bool prevent_inline_autocomplete) {
762   SearchBox* search_box = GetSearchBoxForCurrentContext();
763   if (!search_box)
764     return;
765   search_box->QueryAutocomplete(input, prevent_inline_autocomplete);
766 }
767 
768 // static
StopAutocomplete(bool clear_result)769 void SearchBoxBindings::StopAutocomplete(bool clear_result) {
770   SearchBox* search_box = GetSearchBoxForCurrentContext();
771   if (!search_box)
772     return;
773   search_box->StopAutocomplete(clear_result);
774 }
775 
776 // static
LogCharTypedToRepaintLatency(uint32_t latency_ms)777 void SearchBoxBindings::LogCharTypedToRepaintLatency(uint32_t latency_ms) {
778   SearchBox* search_box = GetSearchBoxForCurrentContext();
779   if (!search_box)
780     return;
781   search_box->LogCharTypedToRepaintLatency(latency_ms);
782 }
783 
784 // static
StartCapturingKeyStrokes()785 void SearchBoxBindings::StartCapturingKeyStrokes() {
786   SearchBox* search_box = GetSearchBoxForCurrentContext();
787   if (!search_box)
788     return;
789   search_box->StartCapturingKeyStrokes();
790 }
791 
792 // static
StopCapturingKeyStrokes()793 void SearchBoxBindings::StopCapturingKeyStrokes() {
794   SearchBox* search_box = GetSearchBoxForCurrentContext();
795   if (!search_box)
796     return;
797   search_box->StopCapturingKeyStrokes();
798 }
799 
800 class NewTabPageBindings : public gin::Wrappable<NewTabPageBindings> {
801  public:
802   static gin::WrapperInfo kWrapperInfo;
803 
804   NewTabPageBindings();
805   ~NewTabPageBindings() override;
806 
807  private:
808   // gin::Wrappable.
809   gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
810       v8::Isolate* isolate) final;
811 
812   static bool HasOrigin(const GURL& origin);
813 
814   // Handlers for JS properties.
815   static bool IsInputInProgress();
816   static v8::Local<v8::Value> GetMostVisited(v8::Isolate* isolate);
817   static bool GetMostVisitedAvailable(v8::Isolate* isolate);
818   static v8::Local<v8::Value> GetNtpTheme(v8::Isolate* isolate);
819   static bool GetIsCustomLinks();
820   static bool GetIsUsingMostVisited();
821   static bool GetAreShortcutsVisible();
822 
823   // Handlers for JS functions visible to all NTPs.
824   static void DeleteMostVisitedItem(v8::Isolate* isolate,
825                                     v8::Local<v8::Value> rid);
826   static void UndoAllMostVisitedDeletions();
827   static void UndoMostVisitedDeletion(v8::Isolate* isolate,
828                                       v8::Local<v8::Value> rid);
829 
830   // Handlers for JS functions visible only to the most visited iframe, the edit
831   // custom links iframe, and/or the local NTP.
832   static v8::Local<v8::Value> GetMostVisitedItemData(v8::Isolate* isolate,
833                                                      int rid);
834   static void UpdateCustomLink(int rid,
835                                const std::string& url,
836                                const std::string& title);
837   static void ReorderCustomLink(int rid, int new_pos);
838   static void UndoCustomLinkAction();
839   static void ResetCustomLinks();
840   static void ToggleMostVisitedOrCustomLinks();
841   static void ToggleShortcutsVisibility(bool do_notify);
842   static std::string FixupAndValidateUrl(const std::string& url);
843   static void LogEvent(int event);
844   static void LogSuggestionEventWithValue(int event, int data);
845   static void LogMostVisitedImpression(
846       int position,
847       int tile_title_source,
848       int tile_source,
849       int tile_type,
850       v8::Local<v8::Value> data_generation_time);
851   static void LogMostVisitedNavigation(
852       int position,
853       int tile_title_source,
854       int tile_source,
855       int tile_type,
856       v8::Local<v8::Value> data_generation_time);
857   static void ResetCustomBackgroundInfo();
858   static void SetCustomBackgroundInfo(const std::string& background_url,
859                                       const std::string& attribution_line_1,
860                                       const std::string& attribution_line_2,
861                                       const std::string& attributionActionUrl,
862                                       const std::string& collection_id);
863   static void SelectLocalBackgroundImage();
864   static void BlocklistSearchSuggestion(int task_version, int task_id);
865   static void BlocklistSearchSuggestionWithHash(int task_version,
866                                                 int task_id,
867                                                 const std::string& hash);
868   static void SearchSuggestionSelected(int task_version,
869                                        int task_id,
870                                        const std::string& hash);
871   static void OptOutOfSearchSuggestions();
872   static void UseDefaultTheme();
873   static void ApplyDefaultTheme();
874   static void ApplyAutogeneratedTheme(v8::Isolate* isolate,
875                                       int id,
876                                       v8::Local<v8::Value> color);
877   static void RevertThemeChanges();
878   static void ConfirmThemeChanges();
879   static void BlocklistPromo(const std::string& promo_id);
880   static void OpenExtensionsPage(double button,
881                                  bool alt_key,
882                                  bool ctrl_key,
883                                  bool meta_key,
884                                  bool shift_key);
885   static v8::Local<v8::Value> GetColorsInfo(v8::Isolate* isolate);
886 
887   DISALLOW_COPY_AND_ASSIGN(NewTabPageBindings);
888 };
889 
890 gin::WrapperInfo NewTabPageBindings::kWrapperInfo = {gin::kEmbedderNativeGin};
891 
892 NewTabPageBindings::NewTabPageBindings() = default;
893 
894 NewTabPageBindings::~NewTabPageBindings() = default;
895 
GetObjectTemplateBuilder(v8::Isolate * isolate)896 gin::ObjectTemplateBuilder NewTabPageBindings::GetObjectTemplateBuilder(
897     v8::Isolate* isolate) {
898   return gin::Wrappable<NewTabPageBindings>::GetObjectTemplateBuilder(isolate)
899       .SetProperty("isInputInProgress", &NewTabPageBindings::IsInputInProgress)
900       .SetProperty("mostVisited", &NewTabPageBindings::GetMostVisited)
901       .SetProperty("mostVisitedAvailable",
902                    &NewTabPageBindings::GetMostVisitedAvailable)
903       .SetProperty("ntpTheme", &NewTabPageBindings::GetNtpTheme)
904       // TODO(https://crbug.com/1020450): remove "themeBackgroundInfo" legacy
905       // name when we're sure no third-party NTP needs it.
906       .SetProperty("themeBackgroundInfo", &NewTabPageBindings::GetNtpTheme)
907       .SetProperty("isCustomLinks", &NewTabPageBindings::GetIsCustomLinks)
908       .SetProperty("isUsingMostVisited",
909                    &NewTabPageBindings::GetIsUsingMostVisited)
910       .SetProperty("areShortcutsVisible",
911                    &NewTabPageBindings::GetAreShortcutsVisible)
912       .SetMethod("deleteMostVisitedItem",
913                  &NewTabPageBindings::DeleteMostVisitedItem)
914       .SetMethod("undoAllMostVisitedDeletions",
915                  &NewTabPageBindings::UndoAllMostVisitedDeletions)
916       .SetMethod("undoMostVisitedDeletion",
917                  &NewTabPageBindings::UndoMostVisitedDeletion)
918       .SetMethod("getMostVisitedItemData",
919                  &NewTabPageBindings::GetMostVisitedItemData)
920       .SetMethod("updateCustomLink", &NewTabPageBindings::UpdateCustomLink)
921       .SetMethod("reorderCustomLink", &NewTabPageBindings::ReorderCustomLink)
922       .SetMethod("undoCustomLinkAction",
923                  &NewTabPageBindings::UndoCustomLinkAction)
924       .SetMethod("resetCustomLinks", &NewTabPageBindings::ResetCustomLinks)
925       .SetMethod("toggleMostVisitedOrCustomLinks",
926                  &NewTabPageBindings::ToggleMostVisitedOrCustomLinks)
927       .SetMethod("toggleShortcutsVisibility",
928                  &NewTabPageBindings::ToggleShortcutsVisibility)
929       .SetMethod("fixupAndValidateUrl",
930                  &NewTabPageBindings::FixupAndValidateUrl)
931       .SetMethod("logEvent", &NewTabPageBindings::LogEvent)
932       .SetMethod("logSuggestionEventWithValue",
933                  &NewTabPageBindings::LogSuggestionEventWithValue)
934       .SetMethod("logMostVisitedImpression",
935                  &NewTabPageBindings::LogMostVisitedImpression)
936       .SetMethod("logMostVisitedNavigation",
937                  &NewTabPageBindings::LogMostVisitedNavigation)
938       .SetMethod("resetBackgroundInfo",
939                  &NewTabPageBindings::ResetCustomBackgroundInfo)
940       .SetMethod("setBackgroundInfo",
941                  &NewTabPageBindings::SetCustomBackgroundInfo)
942       .SetMethod("selectLocalBackgroundImage",
943                  &NewTabPageBindings::SelectLocalBackgroundImage)
944       .SetMethod("blacklistSearchSuggestion",
945                  &NewTabPageBindings::BlocklistSearchSuggestion)
946       .SetMethod("blacklistSearchSuggestionWithHash",
947                  &NewTabPageBindings::BlocklistSearchSuggestionWithHash)
948       .SetMethod("searchSuggestionSelected",
949                  &NewTabPageBindings::SearchSuggestionSelected)
950       .SetMethod("optOutOfSearchSuggestions",
951                  &NewTabPageBindings::OptOutOfSearchSuggestions)
952       .SetMethod("useDefaultTheme", &NewTabPageBindings::UseDefaultTheme)
953       .SetMethod("applyDefaultTheme", &NewTabPageBindings::ApplyDefaultTheme)
954       .SetMethod("applyAutogeneratedTheme",
955                  &NewTabPageBindings::ApplyAutogeneratedTheme)
956       .SetMethod("revertThemeChanges", &NewTabPageBindings::RevertThemeChanges)
957       .SetMethod("confirmThemeChanges",
958                  &NewTabPageBindings::ConfirmThemeChanges)
959       .SetMethod("getColorsInfo", &NewTabPageBindings::GetColorsInfo)
960       .SetMethod("blocklistPromo", &NewTabPageBindings::BlocklistPromo)
961       .SetMethod("openExtensionsPage", &NewTabPageBindings::OpenExtensionsPage);
962 }
963 
964 // static
HasOrigin(const GURL & origin)965 bool NewTabPageBindings::HasOrigin(const GURL& origin) {
966   blink::WebLocalFrame* frame = blink::WebLocalFrame::FrameForCurrentContext();
967   if (!frame)
968     return false;
969   GURL url(frame->GetDocument().Url());
970   return url.GetOrigin() == origin.GetOrigin();
971 }
972 
973 // static
IsInputInProgress()974 bool NewTabPageBindings::IsInputInProgress() {
975   SearchBox* search_box = GetSearchBoxForCurrentContext();
976   if (!search_box)
977     return false;
978   return search_box->is_input_in_progress();
979 }
980 
981 // static
GetMostVisited(v8::Isolate * isolate)982 v8::Local<v8::Value> NewTabPageBindings::GetMostVisited(v8::Isolate* isolate) {
983   const SearchBox* search_box = GetSearchBoxForCurrentContext();
984   if (!search_box)
985     return v8::Null(isolate);
986 
987   content::RenderFrame* render_frame = GetMainRenderFrameForCurrentContext();
988   content::RenderView* render_view = render_frame->GetRenderView();
989 
990   // This corresponds to "window.devicePixelRatio" in JavaScript.
991   float zoom_factor =
992       blink::PageZoomLevelToZoomFactor(render_view->GetZoomLevel());
993   float device_pixel_ratio = render_frame->GetDeviceScaleFactor() * zoom_factor;
994 
995   int render_view_id = render_view->GetRoutingID();
996 
997   std::vector<InstantMostVisitedItemIDPair> instant_mv_items;
998   search_box->GetMostVisitedItems(&instant_mv_items);
999   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1000   v8::Local<v8::Object> v8_mv_items =
1001       v8::Array::New(isolate, instant_mv_items.size());
1002   for (size_t i = 0; i < instant_mv_items.size(); ++i) {
1003     InstantRestrictedID rid = instant_mv_items[i].first;
1004     v8_mv_items
1005         ->CreateDataProperty(
1006             context, i,
1007             GenerateMostVisitedItem(isolate, device_pixel_ratio, render_view_id,
1008                                     rid))
1009         .Check();
1010   }
1011   return v8_mv_items;
1012 }
1013 
1014 // static
GetMostVisitedAvailable(v8::Isolate * isolate)1015 bool NewTabPageBindings::GetMostVisitedAvailable(v8::Isolate* isolate) {
1016   const SearchBox* search_box = GetSearchBoxForCurrentContext();
1017   if (!search_box)
1018     return false;
1019 
1020   return search_box->AreMostVisitedItemsAvailable();
1021 }
1022 
1023 // static
GetNtpTheme(v8::Isolate * isolate)1024 v8::Local<v8::Value> NewTabPageBindings::GetNtpTheme(v8::Isolate* isolate) {
1025   const SearchBox* search_box = GetSearchBoxForCurrentContext();
1026   if (!search_box)
1027     return v8::Null(isolate);
1028   const NtpTheme* theme = search_box->GetNtpTheme();
1029   if (!theme)
1030     return v8::Null(isolate);
1031   return GenerateNtpTheme(isolate, *theme);
1032 }
1033 
1034 // static
GetIsCustomLinks()1035 bool NewTabPageBindings::GetIsCustomLinks() {
1036   const SearchBox* search_box = GetSearchBoxForCurrentContext();
1037   if (!search_box || !HasOrigin(GURL(chrome::kChromeSearchMostVisitedUrl)))
1038     return false;
1039 
1040   return search_box->IsCustomLinks();
1041 }
1042 
1043 // static
GetIsUsingMostVisited()1044 bool NewTabPageBindings::GetIsUsingMostVisited() {
1045   const SearchBox* search_box = GetSearchBoxForCurrentContext();
1046   if (!search_box || !(HasOrigin(GURL(chrome::kChromeSearchMostVisitedUrl)) ||
1047                        HasOrigin(GURL(chrome::kChromeSearchLocalNtpUrl)))) {
1048     return false;
1049   }
1050 
1051   return search_box->IsUsingMostVisited();
1052 }
1053 
1054 // static
GetAreShortcutsVisible()1055 bool NewTabPageBindings::GetAreShortcutsVisible() {
1056   const SearchBox* search_box = GetSearchBoxForCurrentContext();
1057   if (!search_box || !(HasOrigin(GURL(chrome::kChromeSearchMostVisitedUrl)) ||
1058                        HasOrigin(GURL(chrome::kChromeSearchLocalNtpUrl)))) {
1059     return true;
1060   }
1061 
1062   return search_box->AreShortcutsVisible();
1063 }
1064 
1065 // static
DeleteMostVisitedItem(v8::Isolate * isolate,v8::Local<v8::Value> rid_value)1066 void NewTabPageBindings::DeleteMostVisitedItem(v8::Isolate* isolate,
1067                                                v8::Local<v8::Value> rid_value) {
1068   // Manually convert to integer, so that the string "\"1\"" is also accepted.
1069   base::Optional<int> rid = CoerceToInt(isolate, *rid_value);
1070   if (!rid.has_value())
1071     return;
1072   SearchBox* search_box = GetSearchBoxForCurrentContext();
1073   if (!search_box)
1074     return;
1075 
1076   // Treat the Most Visited item as a custom link if called from the Most
1077   // Visited or edit custom link iframes. This will initialize custom links if
1078   // they have not already been initialized.
1079   if (HasOrigin(GURL(chrome::kChromeSearchMostVisitedUrl))) {
1080     search_box->DeleteCustomLink(*rid);
1081     search_box->LogEvent(NTPLoggingEventType::NTP_CUSTOMIZE_SHORTCUT_REMOVE);
1082   } else {
1083     search_box->DeleteMostVisitedItem(*rid);
1084   }
1085 }
1086 
1087 // static
UndoAllMostVisitedDeletions()1088 void NewTabPageBindings::UndoAllMostVisitedDeletions() {
1089   SearchBox* search_box = GetSearchBoxForCurrentContext();
1090   if (!search_box)
1091     return;
1092   search_box->UndoAllMostVisitedDeletions();
1093 }
1094 
1095 // static
UndoMostVisitedDeletion(v8::Isolate * isolate,v8::Local<v8::Value> rid_value)1096 void NewTabPageBindings::UndoMostVisitedDeletion(
1097     v8::Isolate* isolate,
1098     v8::Local<v8::Value> rid_value) {
1099   // Manually convert to integer, so that the string "\"1\"" is also accepted.
1100   base::Optional<int> rid = CoerceToInt(isolate, *rid_value);
1101   if (!rid.has_value())
1102     return;
1103   SearchBox* search_box = GetSearchBoxForCurrentContext();
1104   if (!search_box)
1105     return;
1106 
1107   search_box->UndoMostVisitedDeletion(*rid);
1108 }
1109 
1110 // static
GetMostVisitedItemData(v8::Isolate * isolate,int rid)1111 v8::Local<v8::Value> NewTabPageBindings::GetMostVisitedItemData(
1112     v8::Isolate* isolate,
1113     int rid) {
1114   const SearchBox* search_box = GetSearchBoxForCurrentContext();
1115   if (!search_box || !HasOrigin(GURL(chrome::kChromeSearchMostVisitedUrl)))
1116     return v8::Null(isolate);
1117 
1118   InstantMostVisitedItem item;
1119   if (!search_box->GetMostVisitedItemWithID(rid, &item))
1120     return v8::Null(isolate);
1121 
1122   int render_view_id =
1123       GetMainRenderFrameForCurrentContext()->GetRenderView()->GetRoutingID();
1124   return GenerateMostVisitedItemData(isolate, render_view_id, rid, item);
1125 }
1126 
1127 // static
UpdateCustomLink(int rid,const std::string & url,const std::string & title)1128 void NewTabPageBindings::UpdateCustomLink(int rid,
1129                                           const std::string& url,
1130                                           const std::string& title) {
1131   SearchBox* search_box = GetSearchBoxForCurrentContext();
1132   if (!search_box || !HasOrigin(GURL(chrome::kChromeSearchMostVisitedUrl)))
1133     return;
1134 
1135   // Limit the title to |kMaxCustomLinkTitleLength| characters. If truncated,
1136   // adds an ellipsis.
1137   base::string16 truncated_title =
1138       gfx::TruncateString(base::UTF8ToUTF16(title), kMaxCustomLinkTitleLength,
1139                           gfx::CHARACTER_BREAK);
1140 
1141   const GURL gurl(url);
1142   // If rid is -1, adds a new link. Otherwise, updates the existing link
1143   // indicated by the rid (empty fields will passed as empty strings). This will
1144   // initialize custom links if they have not already been initialized.
1145   if (rid == -1) {
1146     if (!gurl.is_valid() || truncated_title.empty())
1147       return;
1148     search_box->AddCustomLink(gurl, base::UTF16ToUTF8(truncated_title));
1149     search_box->LogEvent(NTPLoggingEventType::NTP_CUSTOMIZE_SHORTCUT_ADD);
1150   } else {
1151     // Check that the URL, if provided, is valid.
1152     if (!url.empty() && !gurl.is_valid())
1153       return;
1154     search_box->UpdateCustomLink(rid, gurl, base::UTF16ToUTF8(truncated_title));
1155     search_box->LogEvent(NTPLoggingEventType::NTP_CUSTOMIZE_SHORTCUT_UPDATE);
1156   }
1157 }
1158 
1159 // static
ReorderCustomLink(int rid,int new_pos)1160 void NewTabPageBindings::ReorderCustomLink(int rid, int new_pos) {
1161   SearchBox* search_box = GetSearchBoxForCurrentContext();
1162   if (!search_box || !HasOrigin(GURL(chrome::kChromeSearchMostVisitedUrl)))
1163     return;
1164   search_box->ReorderCustomLink(rid, new_pos);
1165 }
1166 
1167 // static
UndoCustomLinkAction()1168 void NewTabPageBindings::UndoCustomLinkAction() {
1169   SearchBox* search_box = GetSearchBoxForCurrentContext();
1170   if (!search_box)
1171     return;
1172   search_box->UndoCustomLinkAction();
1173   search_box->LogEvent(NTPLoggingEventType::NTP_CUSTOMIZE_SHORTCUT_UNDO);
1174 }
1175 
1176 // static
ResetCustomLinks()1177 void NewTabPageBindings::ResetCustomLinks() {
1178   SearchBox* search_box = GetSearchBoxForCurrentContext();
1179   if (!search_box)
1180     return;
1181   search_box->ResetCustomLinks();
1182   search_box->LogEvent(NTPLoggingEventType::NTP_CUSTOMIZE_SHORTCUT_RESTORE_ALL);
1183 }
1184 
1185 // static
ToggleMostVisitedOrCustomLinks()1186 void NewTabPageBindings::ToggleMostVisitedOrCustomLinks() {
1187   SearchBox* search_box = GetSearchBoxForCurrentContext();
1188   if (!search_box)
1189     return;
1190   search_box->ToggleMostVisitedOrCustomLinks();
1191   search_box->LogEvent(NTPLoggingEventType::NTP_CUSTOMIZE_SHORTCUT_TOGGLE_TYPE);
1192 }
1193 
1194 // static
ToggleShortcutsVisibility(bool do_notify)1195 void NewTabPageBindings::ToggleShortcutsVisibility(bool do_notify) {
1196   SearchBox* search_box = GetSearchBoxForCurrentContext();
1197   if (!search_box)
1198     return;
1199   search_box->ToggleShortcutsVisibility(do_notify);
1200   search_box->LogEvent(
1201       NTPLoggingEventType::NTP_CUSTOMIZE_SHORTCUT_TOGGLE_VISIBILITY);
1202 }
1203 
1204 // static
FixupAndValidateUrl(const std::string & url)1205 std::string NewTabPageBindings::FixupAndValidateUrl(const std::string& url) {
1206   SearchBox* search_box = GetSearchBoxForCurrentContext();
1207   if (!search_box || !HasOrigin(GURL(chrome::kChromeSearchMostVisitedUrl)))
1208     return std::string();
1209   return search_box->FixupAndValidateUrl(url);
1210 }
1211 
1212 // static
LogEvent(int event)1213 void NewTabPageBindings::LogEvent(int event) {
1214   SearchBox* search_box = GetSearchBoxForCurrentContext();
1215   if (!search_box) {
1216     return;
1217   }
1218   if (event <= NTP_EVENT_TYPE_LAST)
1219     search_box->LogEvent(static_cast<NTPLoggingEventType>(event));
1220 }
1221 
1222 // static
LogSuggestionEventWithValue(int event,int data)1223 void NewTabPageBindings::LogSuggestionEventWithValue(int event, int data) {
1224   SearchBox* search_box = GetSearchBoxForCurrentContext();
1225   if (!search_box) {
1226     return;
1227   }
1228   if (event <= static_cast<int>(NTPSuggestionsLoggingEventType::kMaxValue)) {
1229     search_box->LogSuggestionEventWithValue(
1230         static_cast<NTPSuggestionsLoggingEventType>(event), data);
1231   }
1232 }
1233 
1234 // static
LogMostVisitedImpression(int position,int tile_title_source,int tile_source,int tile_type,v8::Local<v8::Value> data_generation_time)1235 void NewTabPageBindings::LogMostVisitedImpression(
1236     int position,
1237     int tile_title_source,
1238     int tile_source,
1239     int tile_type,
1240     v8::Local<v8::Value> data_generation_time) {
1241   SearchBox* search_box = GetSearchBoxForCurrentContext();
1242   if (!search_box || !HasOrigin(GURL(chrome::kChromeSearchMostVisitedUrl)))
1243     return;
1244 
1245   if (tile_title_source <= static_cast<int>(ntp_tiles::TileTitleSource::LAST) &&
1246       tile_source <= static_cast<int>(ntp_tiles::TileSource::LAST) &&
1247       tile_type <= ntp_tiles::TileVisualType::TILE_TYPE_MAX) {
1248     const ntp_tiles::NTPTileImpression impression(
1249         position, static_cast<ntp_tiles::TileSource>(tile_source),
1250         static_cast<ntp_tiles::TileTitleSource>(tile_title_source),
1251         static_cast<ntp_tiles::TileVisualType>(tile_type),
1252         favicon_base::IconType::kInvalid,
1253         ConvertDateValueToTime(*data_generation_time),
1254         /*url_for_rappor=*/GURL());
1255     search_box->LogMostVisitedImpression(impression);
1256   }
1257 }
1258 
1259 // static
LogMostVisitedNavigation(int position,int tile_title_source,int tile_source,int tile_type,v8::Local<v8::Value> data_generation_time)1260 void NewTabPageBindings::LogMostVisitedNavigation(
1261     int position,
1262     int tile_title_source,
1263     int tile_source,
1264     int tile_type,
1265     v8::Local<v8::Value> data_generation_time) {
1266   SearchBox* search_box = GetSearchBoxForCurrentContext();
1267   if (!search_box || !HasOrigin(GURL(chrome::kChromeSearchMostVisitedUrl)))
1268     return;
1269 
1270   if (tile_title_source <= static_cast<int>(ntp_tiles::TileTitleSource::LAST) &&
1271       tile_source <= static_cast<int>(ntp_tiles::TileSource::LAST) &&
1272       tile_type <= ntp_tiles::TileVisualType::TILE_TYPE_MAX) {
1273     const ntp_tiles::NTPTileImpression impression(
1274         position, static_cast<ntp_tiles::TileSource>(tile_source),
1275         static_cast<ntp_tiles::TileTitleSource>(tile_title_source),
1276         static_cast<ntp_tiles::TileVisualType>(tile_type),
1277         favicon_base::IconType::kInvalid,
1278         ConvertDateValueToTime(*data_generation_time),
1279         /*url_for_rappor=*/GURL());
1280     search_box->LogMostVisitedNavigation(impression);
1281   }
1282 }
1283 
1284 // static
ResetCustomBackgroundInfo()1285 void NewTabPageBindings::ResetCustomBackgroundInfo() {
1286   SetCustomBackgroundInfo(std::string(), std::string(), std::string(),
1287                           std::string(), std::string());
1288 }
1289 
1290 // static
SetCustomBackgroundInfo(const std::string & background_url,const std::string & attribution_line_1,const std::string & attribution_line_2,const std::string & attribution_action_url,const std::string & collection_id)1291 void NewTabPageBindings::SetCustomBackgroundInfo(
1292     const std::string& background_url,
1293     const std::string& attribution_line_1,
1294     const std::string& attribution_line_2,
1295     const std::string& attribution_action_url,
1296     const std::string& collection_id) {
1297   SearchBox* search_box = GetSearchBoxForCurrentContext();
1298   search_box->SetCustomBackgroundInfo(
1299       GURL(background_url), attribution_line_1, attribution_line_2,
1300       GURL(attribution_action_url), collection_id);
1301   // Captures different events that occur when a background selection is made
1302   // and 'Done' is clicked on the dialog.
1303   if (!collection_id.empty()) {
1304     search_box->LogEvent(
1305         NTPLoggingEventType::NTP_BACKGROUND_DAILY_REFRESH_ENABLED);
1306   } else if (background_url.empty()) {
1307     search_box->LogEvent(
1308         NTPLoggingEventType::NTP_CUSTOMIZE_RESTORE_BACKGROUND_CLICKED);
1309     search_box->LogEvent(NTPLoggingEventType::NTP_BACKGROUND_IMAGE_RESET);
1310   } else {
1311     search_box->LogEvent(
1312         NTPLoggingEventType::NTP_CUSTOMIZE_CHROME_BACKGROUND_DONE);
1313     search_box->LogEvent(NTPLoggingEventType::NTP_BACKGROUND_IMAGE_SET);
1314   }
1315 }
1316 
1317 // static
SelectLocalBackgroundImage()1318 void NewTabPageBindings::SelectLocalBackgroundImage() {
1319   SearchBox* search_box = GetSearchBoxForCurrentContext();
1320   search_box->SelectLocalBackgroundImage();
1321 }
1322 
1323 // static
BlocklistSearchSuggestion(const int task_version,const int task_id)1324 void NewTabPageBindings::BlocklistSearchSuggestion(const int task_version,
1325                                                    const int task_id) {
1326   SearchBox* search_box = GetSearchBoxForCurrentContext();
1327   if (!search_box)
1328     return;
1329   search_box->BlocklistSearchSuggestion(task_version, task_id);
1330 }
1331 
1332 // static
BlocklistSearchSuggestionWithHash(int task_version,int task_id,const std::string & hash)1333 void NewTabPageBindings::BlocklistSearchSuggestionWithHash(
1334     int task_version,
1335     int task_id,
1336     const std::string& hash) {
1337   if (hash.length() != 4) {
1338     return;
1339   }
1340 
1341   std::vector<uint8_t> data(hash.begin(), hash.end());
1342   SearchBox* search_box = GetSearchBoxForCurrentContext();
1343   if (!search_box)
1344     return;
1345   search_box->BlocklistSearchSuggestionWithHash(task_version, task_id, data);
1346 }
1347 
1348 // static
SearchSuggestionSelected(int task_version,int task_id,const std::string & hash)1349 void NewTabPageBindings::SearchSuggestionSelected(int task_version,
1350                                                   int task_id,
1351                                                   const std::string& hash) {
1352   if (hash.length() > 4) {
1353     return;
1354   }
1355 
1356   std::vector<uint8_t> data(hash.begin(), hash.end());
1357   SearchBox* search_box = GetSearchBoxForCurrentContext();
1358   if (!search_box)
1359     return;
1360   search_box->SearchSuggestionSelected(task_version, task_id, data);
1361 }
1362 
1363 // static
OptOutOfSearchSuggestions()1364 void NewTabPageBindings::OptOutOfSearchSuggestions() {
1365   SearchBox* search_box = GetSearchBoxForCurrentContext();
1366   if (!search_box)
1367     return;
1368   search_box->OptOutOfSearchSuggestions();
1369 }
1370 
1371 // static
ApplyDefaultTheme()1372 void NewTabPageBindings::ApplyDefaultTheme() {
1373   SearchBox* search_box = GetSearchBoxForCurrentContext();
1374   if (!search_box)
1375     return;
1376   search_box->ApplyDefaultTheme();
1377 }
1378 
1379 // static
UseDefaultTheme()1380 void NewTabPageBindings::UseDefaultTheme() {
1381   SearchBox* search_box = GetSearchBoxForCurrentContext();
1382   if (!search_box)
1383     return;
1384   search_box->ApplyDefaultTheme();
1385   search_box->ConfirmThemeChanges();
1386 }
1387 
1388 // static
ApplyAutogeneratedTheme(v8::Isolate * isolate,int id,v8::Local<v8::Value> value)1389 void NewTabPageBindings::ApplyAutogeneratedTheme(v8::Isolate* isolate,
1390                                                  int id,
1391                                                  v8::Local<v8::Value> value) {
1392   SearchBox* search_box = GetSearchBoxForCurrentContext();
1393   if (!search_box || !value->IsArray())
1394     return;
1395   SkColor color;
1396   if (!ArrayToSkColor(isolate, value.As<v8::Array>(), &color))
1397     return;
1398   search_box->ApplyAutogeneratedTheme(color);
1399 }
1400 
1401 // static
RevertThemeChanges()1402 void NewTabPageBindings::RevertThemeChanges() {
1403   SearchBox* search_box = GetSearchBoxForCurrentContext();
1404   if (!search_box)
1405     return;
1406   search_box->RevertThemeChanges();
1407 }
1408 
1409 // static
ConfirmThemeChanges()1410 void NewTabPageBindings::ConfirmThemeChanges() {
1411   SearchBox* search_box = GetSearchBoxForCurrentContext();
1412   if (!search_box)
1413     return;
1414   search_box->ConfirmThemeChanges();
1415 }
1416 
GetColorsInfo(v8::Isolate * isolate)1417 v8::Local<v8::Value> NewTabPageBindings::GetColorsInfo(v8::Isolate* isolate) {
1418   v8::Local<v8::Context> context = isolate->GetCurrentContext();
1419   v8::Local<v8::Object> v8_colors =
1420       v8::Array::New(isolate, chrome_colors::kNumColorsInfo);
1421   int i = 0;
1422   for (chrome_colors::ColorInfo color_info :
1423        chrome_colors::kGeneratedColorsInfo) {
1424     v8::Local<v8::Object> v8_color_info =
1425         gin::DataObjectBuilder(isolate)
1426             .Set("id", color_info.id)
1427             .Set("color", SkColorToArray(isolate, color_info.color))
1428             .Set("label", l10n_util::GetStringUTF16(color_info.label_id))
1429             .Set("icon", std::string(color_info.icon_data))
1430             .Build();
1431     v8_colors->CreateDataProperty(context, i++, v8_color_info).Check();
1432   }
1433   return v8_colors;
1434 }
1435 
BlocklistPromo(const std::string & promo_id)1436 void NewTabPageBindings::BlocklistPromo(const std::string& promo_id) {
1437   SearchBox* search_box = GetSearchBoxForCurrentContext();
1438   if (!search_box)
1439     return;
1440   search_box->BlocklistPromo(promo_id);
1441 }
1442 
OpenExtensionsPage(double button,bool alt_key,bool ctrl_key,bool meta_key,bool shift_key)1443 void NewTabPageBindings::OpenExtensionsPage(double button,
1444                                             bool alt_key,
1445                                             bool ctrl_key,
1446                                             bool meta_key,
1447                                             bool shift_key) {
1448   SearchBox* search_box = GetSearchBoxForCurrentContext();
1449   if (!search_box)
1450     return;
1451   search_box->OpenExtensionsPage(button, alt_key, ctrl_key, meta_key,
1452                                  shift_key);
1453 }
1454 
1455 }  // namespace
1456 
1457 // static
Install(blink::WebLocalFrame * frame)1458 void SearchBoxExtension::Install(blink::WebLocalFrame* frame) {
1459   v8::Isolate* isolate = blink::MainThreadIsolate();
1460   v8::HandleScope handle_scope(isolate);
1461   v8::Local<v8::Context> context = frame->MainWorldScriptContext();
1462   if (context.IsEmpty())
1463     return;
1464 
1465   v8::Context::Scope context_scope(context);
1466 
1467   gin::Handle<SearchBoxBindings> searchbox_controller =
1468       gin::CreateHandle(isolate, new SearchBoxBindings());
1469   if (searchbox_controller.IsEmpty())
1470     return;
1471 
1472   gin::Handle<NewTabPageBindings> newtabpage_controller =
1473       gin::CreateHandle(isolate, new NewTabPageBindings());
1474   if (newtabpage_controller.IsEmpty())
1475     return;
1476 
1477   v8::Local<v8::Object> chrome =
1478       content::GetOrCreateChromeObject(isolate, context);
1479   v8::Local<v8::Object> embedded_search = v8::Object::New(isolate);
1480   embedded_search
1481       ->Set(context, gin::StringToV8(isolate, "searchBox"),
1482             searchbox_controller.ToV8())
1483       .ToChecked();
1484   embedded_search
1485       ->Set(context, gin::StringToV8(isolate, "newTabPage"),
1486             newtabpage_controller.ToV8())
1487       .ToChecked();
1488   chrome
1489       ->Set(context, gin::StringToSymbol(isolate, "embeddedSearch"),
1490             embedded_search)
1491       .ToChecked();
1492 }
1493 
1494 // static
DispatchFocusChange(blink::WebLocalFrame * frame)1495 void SearchBoxExtension::DispatchFocusChange(blink::WebLocalFrame* frame) {
1496   Dispatch(frame, kDispatchFocusChangedScript);
1497 }
1498 
1499 // static
DispatchAddCustomLinkResult(blink::WebLocalFrame * frame,bool success)1500 void SearchBoxExtension::DispatchAddCustomLinkResult(
1501     blink::WebLocalFrame* frame,
1502     bool success) {
1503   blink::WebString script(blink::WebString::FromUTF8(base::StringPrintf(
1504       kDispatchAddCustomLinkResult, success ? "true" : "false")));
1505   Dispatch(frame, script);
1506 }
1507 
1508 // static
DispatchUpdateCustomLinkResult(blink::WebLocalFrame * frame,bool success)1509 void SearchBoxExtension::DispatchUpdateCustomLinkResult(
1510     blink::WebLocalFrame* frame,
1511     bool success) {
1512   blink::WebString script(blink::WebString::FromUTF8(base::StringPrintf(
1513       kDispatchUpdateCustomLinkResult, success ? "true" : "false")));
1514   Dispatch(frame, script);
1515 }
1516 
1517 // static
DispatchDeleteCustomLinkResult(blink::WebLocalFrame * frame,bool success)1518 void SearchBoxExtension::DispatchDeleteCustomLinkResult(
1519     blink::WebLocalFrame* frame,
1520     bool success) {
1521   blink::WebString script(blink::WebString::FromUTF8(base::StringPrintf(
1522       kDispatchDeleteCustomLinkResult, success ? "true" : "false")));
1523   Dispatch(frame, script);
1524 }
1525 
1526 // static
DispatchAutocompleteResultChanged(blink::WebLocalFrame * frame,search::mojom::AutocompleteResultPtr result)1527 void SearchBoxExtension::DispatchAutocompleteResultChanged(
1528     blink::WebLocalFrame* frame,
1529     search::mojom::AutocompleteResultPtr result) {
1530   base::Value dict(base::Value::Type::DICTIONARY);
1531   dict.SetStringKey("input", result->input);
1532   dict.SetKey("matches", CreateAutocompleteMatches(result->matches));
1533   dict.SetKey("suggestionGroupsMap",
1534               CreateSuggestionGroupsMap(result->suggestion_groups_map));
1535 
1536   std::string json;
1537   base::JSONWriter::Write(dict, &json);
1538   Dispatch(frame, blink::WebString::FromUTF8(base::StringPrintf(
1539                       kDispatchAutocompleteResultChanged, json.c_str())));
1540 }
1541 
1542 // static
DispatchAutocompleteMatchImageAvailable(blink::WebLocalFrame * frame,uint32_t match_index,const std::string & image_url,const std::string & data_url)1543 void SearchBoxExtension::DispatchAutocompleteMatchImageAvailable(
1544     blink::WebLocalFrame* frame,
1545     uint32_t match_index,
1546     const std::string& image_url,
1547     const std::string& data_url) {
1548   blink::WebString script(blink::WebString::FromUTF8(
1549       base::StringPrintf(kDispatchAutocompleteMatchImageAvailable, match_index,
1550                          image_url.c_str(), data_url.c_str())));
1551   Dispatch(frame, script);
1552 }
1553 
1554 // static
DispatchInputCancel(blink::WebLocalFrame * frame)1555 void SearchBoxExtension::DispatchInputCancel(blink::WebLocalFrame* frame) {
1556   Dispatch(frame, kDispatchInputCancelScript);
1557 }
1558 
1559 // static
DispatchInputStart(blink::WebLocalFrame * frame)1560 void SearchBoxExtension::DispatchInputStart(blink::WebLocalFrame* frame) {
1561   Dispatch(frame, kDispatchInputStartScript);
1562 }
1563 
1564 // static
DispatchKeyCaptureChange(blink::WebLocalFrame * frame)1565 void SearchBoxExtension::DispatchKeyCaptureChange(blink::WebLocalFrame* frame) {
1566   Dispatch(frame, kDispatchKeyCaptureChangeScript);
1567 }
1568 
1569 // static
DispatchMostVisitedChanged(blink::WebLocalFrame * frame)1570 void SearchBoxExtension::DispatchMostVisitedChanged(
1571     blink::WebLocalFrame* frame) {
1572   Dispatch(frame, kDispatchMostVisitedChangedScript);
1573 }
1574 
1575 // static
DispatchThemeChange(blink::WebLocalFrame * frame)1576 void SearchBoxExtension::DispatchThemeChange(blink::WebLocalFrame* frame) {
1577   Dispatch(frame, kDispatchThemeChangeEventScript);
1578 }
1579 
1580 // static
DispatchLocalBackgroundSelected(blink::WebLocalFrame * frame)1581 void SearchBoxExtension::DispatchLocalBackgroundSelected(
1582     blink::WebLocalFrame* frame) {
1583   Dispatch(frame, kDispatchLocalBackgroundSelectedScript);
1584 }
1585