1 // Copyright 2019 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/browser/ui/webui/new_tab_page/new_tab_page_ui.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/search/instant_service.h"
12 #include "chrome/browser/search/instant_service_factory.h"
13 #include "chrome/browser/search_engines/template_url_service_factory.h"
14 #include "chrome/browser/ui/webui/favicon_source.h"
15 #include "chrome/browser/ui/webui/new_tab_page/new_tab_page_handler.h"
16 #include "chrome/browser/ui/webui/new_tab_page/untrusted_source.h"
17 #include "chrome/browser/ui/webui/webui_util.h"
18 #include "chrome/common/url_constants.h"
19 #include "chrome/grit/generated_resources.h"
20 #include "chrome/grit/new_tab_page_resources.h"
21 #include "chrome/grit/new_tab_page_resources_map.h"
22 #include "components/favicon_base/favicon_url_parser.h"
23 #include "components/strings/grit/components_strings.h"
24 #include "content/public/browser/url_data_source.h"
25 #include "content/public/browser/web_ui_data_source.h"
26 #include "ui/base/accelerators/accelerator.h"
27 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/base/webui/web_ui_util.h"
29 
30 using content::BrowserContext;
31 using content::WebContents;
32 
33 namespace {
34 
35 constexpr char kGeneratedPath[] =
36     "@out_folder@/gen/chrome/browser/resources/new_tab_page/";
37 
CreateNewTabPageUiHtmlSource(Profile * profile)38 content::WebUIDataSource* CreateNewTabPageUiHtmlSource(Profile* profile) {
39   content::WebUIDataSource* source =
40       content::WebUIDataSource::Create(chrome::kChromeUINewTabPageHost);
41   source->OverrideContentSecurityPolicyChildSrc(base::StringPrintf(
42       "frame-src %s;", chrome::kChromeUIUntrustedNewTabPageUrl));
43 
44   ui::Accelerator undo_accelerator(ui::VKEY_Z, ui::EF_PLATFORM_ACCELERATOR);
45   source->AddString("undoDescription", l10n_util::GetStringFUTF16(
46                                            IDS_UNDO_DESCRIPTION,
47                                            undo_accelerator.GetShortcutText()));
48   source->AddString("googleBaseUrl",
49                     GURL(TemplateURLServiceFactory::GetForProfile(profile)
50                              ->search_terms_data()
51                              .GoogleBaseURLValue())
52                         .spec());
53 
54   static constexpr webui::LocalizedString kStrings[] = {
55       {"title", IDS_NEW_TAB_TITLE},
56       {"undo", IDS_NEW_TAB_UNDO_THUMBNAIL_REMOVE},
57 
58       // Custom Links
59       {"addLinkTitle", IDS_NTP_CUSTOM_LINKS_ADD_SHORTCUT_TITLE},
60       {"editLinkTitle", IDS_NTP_CUSTOM_LINKS_EDIT_SHORTCUT},
61       {"invalidUrl", IDS_NTP_CUSTOM_LINKS_INVALID_URL},
62       {"linkAddedMsg", IDS_NTP_CONFIRM_MSG_SHORTCUT_ADDED},
63       {"linkCancel", IDS_NTP_CUSTOM_LINKS_CANCEL},
64       {"linkCantCreate", IDS_NTP_CUSTOM_LINKS_CANT_CREATE},
65       {"linkCantEdit", IDS_NTP_CUSTOM_LINKS_CANT_EDIT},
66       {"linkDone", IDS_NTP_CUSTOM_LINKS_DONE},
67       {"linkEditedMsg", IDS_NTP_CONFIRM_MSG_SHORTCUT_EDITED},
68       {"linkRemove", IDS_NTP_CUSTOM_LINKS_REMOVE},
69       {"linkRemovedMsg", IDS_NTP_CONFIRM_MSG_SHORTCUT_REMOVED},
70       {"nameField", IDS_NTP_CUSTOM_LINKS_NAME},
71       {"restoreDefaultLinks", IDS_NTP_CONFIRM_MSG_RESTORE_DEFAULTS},
72       {"restoreThumbnailsShort", IDS_NEW_TAB_RESTORE_THUMBNAILS_SHORT_LINK},
73       {"urlField", IDS_NTP_CUSTOM_LINKS_URL},
74 
75       // Customize button and dialog.
76       {"backButton", IDS_ACCNAME_BACK},
77       {"backgroundsMenuItem", IDS_NTP_CUSTOMIZE_MENU_BACKGROUND_LABEL},
78       {"cancelButton", IDS_CANCEL},
79       {"colorPickerLabel", IDS_NTP_CUSTOMIZE_COLOR_PICKER_LABEL},
80       {"customizeButton", IDS_NTP_CUSTOMIZE_BUTTON_LABEL},
81       {"customizeThisPage", IDS_NTP_CUSTOM_BG_CUSTOMIZE_NTP_LABEL},
82       {"defaultThemeLabel", IDS_NTP_CUSTOMIZE_DEFAULT_LABEL},
83       {"doneButton", IDS_DONE},
84       {"hideShortcuts", IDS_NTP_CUSTOMIZE_HIDE_SHORTCUTS_LABEL},
85       {"hideShortcutsDesc", IDS_NTP_CUSTOMIZE_HIDE_SHORTCUTS_DESC},
86       {"mostVisited", IDS_NTP_CUSTOMIZE_MOST_VISITED_LABEL},
87       {"myShortcuts", IDS_NTP_CUSTOMIZE_MY_SHORTCUTS_LABEL},
88       {"shortcutsCurated", IDS_NTP_CUSTOMIZE_MY_SHORTCUTS_DESC},
89       {"shortcutsMenuItem", IDS_NTP_CUSTOMIZE_MENU_SHORTCUTS_LABEL},
90       {"shortcutsOption", IDS_NTP_CUSTOMIZE_MENU_SHORTCUTS_LABEL},
91       {"shortcutsSuggested", IDS_NTP_CUSTOMIZE_MOST_VISITED_DESC},
92       {"themesMenuItem", IDS_NTP_CUSTOMIZE_MENU_COLOR_LABEL},
93       {"thirdPartyThemeDescription", IDS_NTP_CUSTOMIZE_3PT_THEME_DESC},
94       {"uninstallThirdPartyThemeButton", IDS_NTP_CUSTOMIZE_3PT_THEME_UNINSTALL},
95 
96       // Voice search.
97       {"audioError", IDS_NEW_TAB_VOICE_AUDIO_ERROR},
98       {"close", IDS_NEW_TAB_VOICE_CLOSE_TOOLTIP},
99       {"details", IDS_NEW_TAB_VOICE_DETAILS},
100       {"languageError", IDS_NEW_TAB_VOICE_LANGUAGE_ERROR},
101       {"learnMore", IDS_LEARN_MORE},
102       {"listening", IDS_NEW_TAB_VOICE_LISTENING},
103       {"networkError", IDS_NEW_TAB_VOICE_NETWORK_ERROR},
104       {"noTranslation", IDS_NEW_TAB_VOICE_NO_TRANSLATION},
105       {"noVoice", IDS_NEW_TAB_VOICE_NO_VOICE},
106       {"otherError", IDS_NEW_TAB_VOICE_OTHER_ERROR},
107       {"permissionError", IDS_NEW_TAB_VOICE_PERMISSION_ERROR},
108       {"speak", IDS_NEW_TAB_VOICE_READY},
109       {"tryAgain", IDS_NEW_TAB_VOICE_TRY_AGAIN},
110       {"voiceSearchButtonLabel", IDS_TOOLTIP_MIC_SEARCH},
111       {"waiting", IDS_NEW_TAB_VOICE_WAITING},
112 
113       // Search box.
114       {"searchBoxHint", IDS_GOOGLE_SEARCH_BOX_EMPTY_HINT_MD},
115   };
116   AddLocalizedStringsBulk(source, kStrings);
117 
118   source->AddResourcePath("skcolor.mojom-lite.js",
119                           IDR_NEW_TAB_PAGE_SKCOLOR_MOJO_LITE_JS);
120   source->AddResourcePath("new_tab_page.mojom-lite.js",
121                           IDR_NEW_TAB_PAGE_MOJO_LITE_JS);
122   webui::SetupWebUIDataSource(
123       source, base::make_span(kNewTabPageResources, kNewTabPageResourcesSize),
124       kGeneratedPath, IDR_NEW_TAB_PAGE_NEW_TAB_PAGE_HTML);
125 
126   return source;
127 }
128 
129 }  // namespace
130 
NewTabPageUI(content::WebUI * web_ui)131 NewTabPageUI::NewTabPageUI(content::WebUI* web_ui)
132     : ui::MojoWebUIController(web_ui, true),
133       page_factory_receiver_(this),
134       profile_(Profile::FromWebUI(web_ui)),
135       instant_service_(InstantServiceFactory::GetForProfile(profile_)),
136       web_contents_(web_ui->GetWebContents()) {
137   content::WebUIDataSource::Add(profile_,
138                                 CreateNewTabPageUiHtmlSource(profile_));
139 
140   content::URLDataSource::Add(
141       profile_, std::make_unique<FaviconSource>(
142                     profile_, chrome::FaviconUrlFormat::kFavicon2));
143   content::URLDataSource::Add(profile_,
144                               std::make_unique<UntrustedSource>(profile_));
145 
146   web_ui->AddRequestableScheme(content::kChromeUIUntrustedScheme);
147 
148   UpdateBackgroundColor(*instant_service_->GetInitializedNtpTheme());
149   instant_service_->AddObserver(this);
150 }
151 
WEB_UI_CONTROLLER_TYPE_IMPL(NewTabPageUI)152 WEB_UI_CONTROLLER_TYPE_IMPL(NewTabPageUI)
153 
154 NewTabPageUI::~NewTabPageUI() {
155   instant_service_->RemoveObserver(this);
156 }
157 
158 // static
IsNewTabPageOrigin(const GURL & url)159 bool NewTabPageUI::IsNewTabPageOrigin(const GURL& url) {
160   return url.GetOrigin() == GURL(chrome::kChromeUINewTabPageURL).GetOrigin();
161 }
162 
BindInterface(mojo::PendingReceiver<new_tab_page::mojom::PageHandlerFactory> pending_receiver)163 void NewTabPageUI::BindInterface(
164     mojo::PendingReceiver<new_tab_page::mojom::PageHandlerFactory>
165         pending_receiver) {
166   if (page_factory_receiver_.is_bound()) {
167     page_factory_receiver_.reset();
168   }
169 
170   page_factory_receiver_.Bind(std::move(pending_receiver));
171 }
172 
CreatePageHandler(mojo::PendingRemote<new_tab_page::mojom::Page> pending_page,mojo::PendingReceiver<new_tab_page::mojom::PageHandler> pending_page_handler)173 void NewTabPageUI::CreatePageHandler(
174     mojo::PendingRemote<new_tab_page::mojom::Page> pending_page,
175     mojo::PendingReceiver<new_tab_page::mojom::PageHandler>
176         pending_page_handler) {
177   DCHECK(pending_page.is_valid());
178   page_handler_ = std::make_unique<NewTabPageHandler>(
179       std::move(pending_page_handler), std::move(pending_page), profile_,
180       web_contents_);
181 }
182 
NtpThemeChanged(const NtpTheme & theme)183 void NewTabPageUI::NtpThemeChanged(const NtpTheme& theme) {
184   // Load time data is cached across page reloads. Update the background color
185   // here to prevent a white flicker on page reload.
186   UpdateBackgroundColor(theme);
187 }
188 
MostVisitedInfoChanged(const InstantMostVisitedInfo & info)189 void NewTabPageUI::MostVisitedInfoChanged(const InstantMostVisitedInfo& info) {}
190 
UpdateBackgroundColor(const NtpTheme & theme)191 void NewTabPageUI::UpdateBackgroundColor(const NtpTheme& theme) {
192   std::unique_ptr<base::DictionaryValue> update(new base::DictionaryValue);
193   auto background_color = theme.background_color;
194   update->SetString(
195       "backgroundColor",
196       base::StringPrintf("#%02X%02X%02X", SkColorGetR(background_color),
197                          SkColorGetG(background_color),
198                          SkColorGetB(background_color)));
199   content::WebUIDataSource::Update(profile_, chrome::kChromeUINewTabPageHost,
200                                    std::move(update));
201 }
202