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