blob: 861f4c60fd67735424ee110a2e9d7a66b13fdb69 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/webui_util_desktop.h"
#include "base/containers/fixed_flat_map.h"
#include "base/containers/map_util.h"
#include "base/strings/strcat.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/webui/top_chrome/webui_url_utils.h"
#include "chrome/common/webui_url_constants.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/widget/widget.h"
#include "ui/webui/buildflags.h"
#if BUILDFLAG(ENABLE_WEBUI_GENERATE_CODE_CACHE)
#include "chrome/grit/side_panel_bookmarks_code_cache_resources_map.h"
#include "chrome/grit/side_panel_customize_chrome_code_cache_resources_map.h"
#include "chrome/grit/side_panel_reading_list_code_cache_resources_map.h"
#include "chrome/grit/side_panel_shared_code_cache_resources_map.h"
#include "content/public/common/content_features.h"
#include "ui/webui/resources/grit/webui_code_cache_resources_map.h"
#endif // BUILDFLAG(ENABLE_WEBUI_GENERATE_CODE_CACHE)
namespace webui {
namespace {
const ui::ThemeProvider* g_theme_provider_for_testing = nullptr;
// Maps the url host to its metrics appropriate host name for metrics reporting.
// Keep in sync with the WebUIHostname variant in
// histograms/metadata/others.xml.
const std::string_view* GetWebUIMetricsHostname(const GURL& webui_url) {
static constexpr auto kWebUIHostnames =
base::MakeFixedFlatMap<std::string_view, std::string_view>({
{chrome::kChromeUIBookmarksHost, "Bookmarks"},
{chrome::kChromeUIBookmarksSidePanelHost, "BookmarksSidePanel"},
{chrome::kChromeUICommentsSidePanelHost, "CommentsSidePanel"},
{chrome::kChromeUICustomizeChromeSidePanelHost,
"CustomizeChromeSidePanel"},
{chrome::kChromeUIDownloadsHost, "Downloads"},
{chrome::kChromeUIHistoryHost, "History"},
{chrome::kChromeUIHistoryClustersSidePanelHost,
"HistoryClustersSidePanel"},
{chrome::kChromeUINewTabPageHost, "NewTabPage"},
{chrome::kChromeUINewTabPageThirdPartyHost, "NewTabPageThirdParty"},
{chrome::kChromeUIUntrustedReadAnythingSidePanelHost,
"ReadAnythingSidePanel"},
{chrome::kChromeUIReadLaterHost, "ReadLater"},
{content::kChromeUIResourcesHost, "Resources"},
{chrome::kChromeUISettingsHost, "Settings"},
{chrome::kChromeUITabSearchHost, "TabSearch"},
{chrome::kChromeUIThemeHost, "Theme"},
{chrome::kChromeUITopChromeDomain, "TopChrome"},
});
return base::FindOrNull(kWebUIHostnames, webui_url.host());
}
} // namespace
ui::NativeTheme* GetNativeThemeDeprecated(content::WebContents* web_contents) {
ui::NativeTheme* native_theme = nullptr;
if (web_contents) {
Browser* browser = chrome::FindBrowserWithTab(web_contents);
if (browser) {
// Find for WebContents hosted in a tab.
native_theme = browser->window()->GetNativeTheme();
}
if (!native_theme) {
// Find for WebContents hosted in a widget, but not directly in a
// Browser. e.g. Tab Search, Read Later.
views::Widget* widget = views::Widget::GetTopLevelWidgetForNativeView(
web_contents->GetContentNativeView());
if (widget) {
native_theme = widget->GetNativeTheme();
}
}
}
if (!native_theme) {
// Find for isolated WebContents, e.g. in tests.
// Or when |web_contents| is nullptr, because the renderer is not ready.
// TODO(crbug.com/40677117): Remove global accessor to NativeTheme.
native_theme = ui::NativeTheme::GetInstanceForNativeUi();
}
return native_theme;
}
const ui::ThemeProvider* GetThemeProviderDeprecated(
content::WebContents* web_contents) {
if (g_theme_provider_for_testing) {
return g_theme_provider_for_testing;
}
auto* browser_window =
BrowserWindow::FindBrowserWindowWithWebContents(web_contents);
if (browser_window) {
return browser_window->GetThemeProvider();
}
// Fallback 1: get the theme provider from the profile's associated browser.
// This is used in newly created tabs, e.g. NewTabPageUI, where theming is
// required before the WebContents is attached to a browser window.
// TODO(crbug.com/40823135): Remove this fallback by associating the
// WebContents during navigation.
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
const Browser* browser = chrome::FindBrowserWithProfile(profile);
if (browser) {
return browser->window()->GetThemeProvider();
}
// Fallback 2: get the theme provider from the last created browser.
// This is used in ChromeOS, where under multi-signin a browser window can
// be sent to another profile.
// TODO(crbug.com/40823135): Remove this fallback by associating the
// WebContents during navigation.
BrowserList* browser_list = BrowserList::GetInstance();
browser = browser_list->empty()
? nullptr
: *std::prev(BrowserList::GetInstance()->end());
return browser ? browser->window()->GetThemeProvider() : nullptr;
}
void SetThemeProviderForTestingDeprecated(
const ui::ThemeProvider* theme_provider) {
g_theme_provider_for_testing = theme_provider;
}
std::string GetWebUIHostnameForCodeCacheMetrics(const GURL& webui_url) {
const std::string_view* hostname = GetWebUIMetricsHostname(webui_url);
return hostname ? std::string(*hostname) : std::string();
}
void AppendWebUIResourceURLToCodeCachePairs(
std::string_view scheme,
std::string_view host,
base::span<const ResourcePath> code_cache_resources,
std::vector<std::pair<GURL, int>>& resource_code_cache_pairs) {
for (const ResourcePath& code_cache_resource : code_cache_resources) {
std::string_view code_cache_path = code_cache_resource.path;
// Stripping the .code_cache suffix from code cache resource paths
// yields the corresponding resource paths.
constexpr std::string_view kCodeCacheResourceSuffix = ".code_cache";
DCHECK(code_cache_path.ends_with(kCodeCacheResourceSuffix));
std::string_view resource_path = code_cache_path.substr(
0, code_cache_path.size() - kCodeCacheResourceSuffix.size());
resource_code_cache_pairs.emplace_back(
GURL(base::StrCat({scheme, "://", host, "/", resource_path})),
code_cache_resource.id);
}
}
base::flat_map<GURL, int> GetWebUIResourceUrlToCodeCacheMap() {
// Collects relevant code cache pairs used to initialize the requested map.
std::vector<std::pair<GURL, int>> url_to_code_cache_pairs;
#if BUILDFLAG(ENABLE_WEBUI_GENERATE_CODE_CACHE)
if (features::kWebUIBundledCodeCacheGenerateResourceMap.Get()) {
// Shared resources.
AppendWebUIResourceURLToCodeCachePairs(
content::kChromeUIScheme, content::kChromeUIResourcesHost,
kWebuiCodeCacheResources, url_to_code_cache_pairs);
AppendWebUIResourceURLToCodeCachePairs(
content::kChromeUIUntrustedScheme, content::kChromeUIResourcesHost,
kWebuiCodeCacheResources, url_to_code_cache_pairs);
// TODO(crbug.com/402625343): We can avoid enumerating host-specific WebUI
// code cache resources here and instead delegate to registered WebUI
// configs or similar. This may also be unnecessary once these mappings are
// exposed in renderers at compile-time.
// chrome://bookmarks-side-panel.top-chrome
AppendWebUIResourceURLToCodeCachePairs(
content::kChromeUIScheme, chrome::kChromeUIBookmarksSidePanelHost,
kSidePanelSharedCodeCacheResources, url_to_code_cache_pairs);
AppendWebUIResourceURLToCodeCachePairs(
content::kChromeUIScheme, chrome::kChromeUIBookmarksSidePanelHost,
kSidePanelBookmarksCodeCacheResources, url_to_code_cache_pairs);
// chrome://customize-chrome-side-panel.top-chrome
AppendWebUIResourceURLToCodeCachePairs(
content::kChromeUIScheme, chrome::kChromeUICustomizeChromeSidePanelHost,
kSidePanelSharedCodeCacheResources, url_to_code_cache_pairs);
AppendWebUIResourceURLToCodeCachePairs(
content::kChromeUIScheme, chrome::kChromeUICustomizeChromeSidePanelHost,
kSidePanelCustomizeChromeCodeCacheResources, url_to_code_cache_pairs);
// chrome://read-later.top-chrome
AppendWebUIResourceURLToCodeCachePairs(
content::kChromeUIScheme, chrome::kChromeUIReadLaterHost,
kSidePanelSharedCodeCacheResources, url_to_code_cache_pairs);
AppendWebUIResourceURLToCodeCachePairs(
content::kChromeUIScheme, chrome::kChromeUIReadLaterHost,
kSidePanelReadingListCodeCacheResources, url_to_code_cache_pairs);
}
#endif // BUILDFLAG(ENABLE_WEBUI_GENERATE_CODE_CACHE)
return {url_to_code_cache_pairs};
}
} // namespace webui