| // Copyright 2019 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/web_applications/app_browser_controller.h" |
| |
| #include "base/feature_list.h" |
| #include "base/functional/bind.h" |
| #include "base/strings/escape.h" |
| #include "base/strings/string_piece.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "build/build_config.h" |
| #include "build/chromeos_buildflags.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ssl/security_state_tab_helper.h" |
| #include "chrome/browser/themes/browser_theme_pack.h" |
| #include "chrome/browser/themes/theme_properties.h" |
| #include "chrome/browser/themes/theme_service.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/browser_window_state.h" |
| #include "chrome/browser/ui/color/chrome_color_id.h" |
| #include "chrome/browser/ui/tabs/tab_menu_model_factory.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/themes/autogenerated_theme_util.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "components/security_state/core/security_state.h" |
| #include "components/url_formatter/url_formatter.h" |
| #include "components/webapps/browser/installable/installable_manager.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/navigation_entry.h" |
| #include "content/public/browser/navigation_handle.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/url_constants.h" |
| #include "extensions/common/constants.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "ui/base/models/image_model.h" |
| #include "ui/color/color_id.h" |
| #include "ui/color/color_recipe.h" |
| #include "ui/color/color_transform.h" |
| #include "ui/display/display.h" |
| #include "ui/display/screen.h" |
| #include "ui/gfx/color_palette.h" |
| #include "ui/gfx/color_utils.h" |
| #include "ui/gfx/favicon_size.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/resize_utils.h" |
| #include "ui/gfx/image/image_skia.h" |
| #include "ui/native_theme/native_theme.h" |
| #include "url/gurl.h" |
| #include "url/origin.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "chrome/browser/apps/icon_standardizer.h" |
| #include "chrome/browser/ash/system_web_apps/types/system_web_app_delegate.h" |
| #include "chrome/browser/ash/system_web_apps/types/system_web_app_type.h" |
| #include "chromeos/ui/base/chromeos_ui_constants.h" |
| #endif |
| |
| namespace { |
| |
| SkColor GetAltColor(SkColor color) { |
| return color_utils::BlendForMinContrast( |
| color, color, absl::nullopt, |
| kAutogeneratedThemeActiveTabPreferredContrast) |
| .color; |
| } |
| |
| } // namespace |
| |
| namespace web_app { |
| |
| // static |
| bool AppBrowserController::IsWebApp(const Browser* browser) { |
| return browser && browser->app_controller(); |
| } |
| |
| // static |
| bool AppBrowserController::IsForWebApp(const Browser* browser, |
| const AppId& app_id) { |
| return IsWebApp(browser) && browser->app_controller()->app_id() == app_id; |
| } |
| |
| // static |
| Browser* AppBrowserController::FindForWebApp(const Profile& profile, |
| const AppId& app_id) { |
| const BrowserList* browser_list = BrowserList::GetInstance(); |
| for (auto it = browser_list->begin_browsers_ordered_by_activation(); |
| it != browser_list->end_browsers_ordered_by_activation(); ++it) { |
| Browser* browser = *it; |
| if (browser->type() == Browser::TYPE_POPUP) |
| continue; |
| if (browser->profile() != &profile) |
| continue; |
| if (!IsForWebApp(browser, app_id)) |
| continue; |
| return browser; |
| } |
| return nullptr; |
| } |
| |
| // static |
| std::u16string AppBrowserController::FormatUrlOrigin( |
| const GURL& url, |
| url_formatter::FormatUrlTypes format_types) { |
| auto origin = url::Origin::Create(url); |
| return url_formatter::FormatUrl(origin.opaque() ? url : origin.GetURL(), |
| format_types, base::UnescapeRule::SPACES, |
| nullptr, nullptr, nullptr); |
| } |
| |
| const ui::ThemeProvider* AppBrowserController::GetThemeProvider() const { |
| return theme_provider_.get(); |
| } |
| |
| AppBrowserController::AppBrowserController( |
| Browser* browser, |
| AppId app_id, |
| bool has_tab_strip) |
| : content::WebContentsObserver(nullptr), |
| browser_(browser), |
| app_id_(std::move(app_id)), |
| has_tab_strip_(has_tab_strip), |
| theme_provider_( |
| ThemeService::CreateBoundThemeProvider(browser_->profile(), this)) { |
| browser->tab_strip_model()->AddObserver(this); |
| } |
| |
| AppBrowserController::AppBrowserController(Browser* browser, AppId app_id) |
| : AppBrowserController(browser, std::move(app_id), false) {} |
| |
| void AppBrowserController::Init() { |
| UpdateThemePack(); |
| } |
| |
| AppBrowserController::~AppBrowserController() { |
| browser()->tab_strip_model()->RemoveObserver(this); |
| } |
| |
| bool AppBrowserController::ShouldShowCustomTabBar() const { |
| if (!IsInstalled()) |
| return false; |
| |
| content::WebContents* web_contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| |
| if (!web_contents) |
| return false; |
| |
| GURL start_url = GetAppStartUrl(); |
| base::StringPiece start_url_scheme = start_url.scheme_piece(); |
| |
| bool is_internal_start_url_scheme = |
| start_url_scheme == extensions::kExtensionScheme || |
| start_url_scheme == content::kChromeUIScheme || |
| start_url_scheme == content::kChromeUIUntrustedScheme; |
| |
| auto should_show_toolbar_for_url = [&](const GURL& url) -> bool { |
| // If the url is unset, it doesn't give a signal as to whether the toolbar |
| // should be shown or not. In lieu of more information, do not show the |
| // toolbar. |
| if (url.is_empty()) |
| return false; |
| |
| // Show toolbar when not using 'https', unless this is an internal app, |
| // or origin is secure (e.g. localhost). |
| if (!is_internal_start_url_scheme && !url.SchemeIs(url::kHttpsScheme) && |
| !webapps::InstallableManager::IsOriginConsideredSecure(url)) { |
| return true; |
| } |
| |
| // Page URLs that are not within scope |
| // (https://www.w3.org/TR/appmanifest/#dfn-within-scope) of the app |
| // corresponding to |start_url| show the toolbar. |
| return !IsUrlInAppScope(url); |
| }; |
| |
| GURL visible_url = web_contents->GetVisibleURL(); |
| GURL last_committed_url = web_contents->GetLastCommittedURL(); |
| |
| if (last_committed_url.is_empty() && visible_url.is_empty()) |
| return should_show_toolbar_for_url(initial_url()); |
| |
| if (should_show_toolbar_for_url(visible_url) || |
| should_show_toolbar_for_url(last_committed_url)) { |
| return true; |
| } |
| |
| // Insecure external web sites show the toolbar. |
| // Note: IsContentSecure is false until a navigation is committed. |
| if (!last_committed_url.is_empty() && !is_internal_start_url_scheme && |
| !webapps::InstallableManager::IsContentSecure(web_contents)) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool AppBrowserController::has_tab_strip() const { |
| return has_tab_strip_; |
| } |
| |
| bool AppBrowserController::HasTitlebarMenuButton() const { |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // Hide for system apps. |
| return !system_app(); |
| #else |
| return true; |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| } |
| |
| bool AppBrowserController::HasTitlebarAppOriginText() const { |
| bool hide = base::FeatureList::IsEnabled(features::kHideWebAppOriginText); |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // Do not show origin text for System Apps. |
| if (system_app()) |
| hide = true; |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| return !hide; |
| } |
| |
| bool AppBrowserController::HasTitlebarContentSettings() const { |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // Do not show content settings for System Apps. |
| return !system_app(); |
| #else |
| return true; |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| } |
| |
| std::vector<PageActionIconType> AppBrowserController::GetTitleBarPageActions() |
| const { |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| if (system_app()) { |
| return {PageActionIconType::kFind, PageActionIconType::kZoom}; |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| std::vector<PageActionIconType> types_enabled; |
| types_enabled.push_back(PageActionIconType::kFind); |
| types_enabled.push_back(PageActionIconType::kManagePasswords); |
| types_enabled.push_back(PageActionIconType::kTranslate); |
| types_enabled.push_back(PageActionIconType::kZoom); |
| types_enabled.push_back(PageActionIconType::kFileSystemAccess); |
| types_enabled.push_back(PageActionIconType::kCookieControls); |
| types_enabled.push_back(PageActionIconType::kLocalCardMigration); |
| types_enabled.push_back(PageActionIconType::kSaveCard); |
| |
| return types_enabled; |
| } |
| |
| bool AppBrowserController::IsInstalled() const { |
| return false; |
| } |
| |
| std::unique_ptr<TabMenuModelFactory> |
| AppBrowserController::GetTabMenuModelFactory() const { |
| return nullptr; |
| } |
| |
| bool AppBrowserController::AppUsesWindowControlsOverlay() const { |
| return false; |
| } |
| |
| bool AppBrowserController::AppUsesBorderlessMode() const { |
| return false; |
| } |
| |
| bool AppBrowserController::AppUsesTabbed() const { |
| return false; |
| } |
| |
| bool AppBrowserController::IsIsolatedWebApp() const { |
| return false; |
| } |
| |
| bool AppBrowserController::IsWindowControlsOverlayEnabled() const { |
| return false; |
| } |
| |
| void AppBrowserController::ToggleWindowControlsOverlayEnabled( |
| base::OnceClosure on_complete) { |
| std::move(on_complete).Run(); |
| } |
| |
| gfx::Rect AppBrowserController::GetDefaultBounds() const { |
| return gfx::Rect(); |
| } |
| |
| bool AppBrowserController::HasReloadButton() const { |
| return true; |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| const ash::SystemWebAppDelegate* AppBrowserController::system_app() const { |
| return nullptr; |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| std::u16string AppBrowserController::GetLaunchFlashText() const { |
| // Isolated Web Apps should show the app's name instead of the origin. |
| // App Short Name is considered trustworthy because manifest comes from signed |
| // web bundle. |
| // TODO:(crbug.com/b/1394199) Disable IWA launch flash text for OSs that |
| // already display name on title bar. |
| if (IsIsolatedWebApp()) { |
| return GetAppShortName(); |
| } |
| return GetFormattedUrlOrigin(); |
| } |
| |
| bool AppBrowserController::IsHostedApp() const { |
| return false; |
| } |
| |
| WebAppBrowserController* AppBrowserController::AsWebAppBrowserController() { |
| return nullptr; |
| } |
| |
| bool AppBrowserController::CanUserUninstall() const { |
| return false; |
| } |
| |
| void AppBrowserController::Uninstall( |
| webapps::WebappUninstallSource webapp_uninstall_source) { |
| NOTREACHED(); |
| } |
| |
| void AppBrowserController::UpdateCustomTabBarVisibility(bool animate) const { |
| browser()->window()->UpdateCustomTabBarVisibility(ShouldShowCustomTabBar(), |
| animate); |
| } |
| |
| void AppBrowserController::DidStartNavigation( |
| content::NavigationHandle* navigation_handle) { |
| if (!initial_url().is_empty()) |
| return; |
| if (!navigation_handle->IsInPrimaryMainFrame()) |
| return; |
| if (navigation_handle->GetURL().is_empty()) |
| return; |
| SetInitialURL(navigation_handle->GetURL()); |
| } |
| |
| void AppBrowserController::DidFinishNavigation( |
| content::NavigationHandle* navigation_handle) { |
| if (!navigation_handle->IsInPrimaryMainFrame() || |
| navigation_handle->IsSameDocument()) |
| return; |
| |
| // For borderless mode when we navigate out of scope and then back to scope, |
| // the draggable regions stay same and nothing triggers to re-initialize them. |
| // So if they are cleared, they don't work anymore when coming back to scope. |
| if (AppUsesBorderlessMode()) |
| return; |
| |
| // Reset the draggable regions so they are not cached on navigation. |
| draggable_region_ = absl::nullopt; |
| } |
| |
| void AppBrowserController::DOMContentLoaded( |
| content::RenderFrameHost* render_frame_host) { |
| // We hold off changing theme color for a new tab until the page is loaded. |
| UpdateThemePack(); |
| } |
| |
| void AppBrowserController::DidChangeThemeColor() { |
| UpdateThemePack(); |
| } |
| |
| void AppBrowserController::OnBackgroundColorChanged() { |
| UpdateThemePack(); |
| } |
| |
| absl::optional<SkColor> AppBrowserController::GetThemeColor() const { |
| absl::optional<SkColor> result; |
| // HTML meta theme-color tag overrides manifest theme_color, see spec: |
| // https://www.w3.org/TR/appmanifest/#theme_color-member |
| content::WebContents* web_contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| if (web_contents) { |
| absl::optional<SkColor> color = web_contents->GetThemeColor(); |
| if (color) |
| result = color; |
| } |
| |
| if (!result) |
| return absl::nullopt; |
| |
| // The frame/tabstrip code expects an opaque color. |
| return SkColorSetA(*result, SK_AlphaOPAQUE); |
| } |
| |
| absl::optional<SkColor> AppBrowserController::GetBackgroundColor() const { |
| absl::optional<SkColor> color; |
| if (auto* web_contents = browser()->tab_strip_model()->GetActiveWebContents()) |
| color = web_contents->GetBackgroundColor(); |
| return color ? SkColorSetA(*color, SK_AlphaOPAQUE) : color; |
| } |
| |
| std::u16string AppBrowserController::GetTitle() const { |
| content::WebContents* web_contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| if (!web_contents) |
| return std::u16string(); |
| |
| content::NavigationEntry* entry = |
| web_contents->GetController().GetVisibleEntry(); |
| return entry ? entry->GetTitle() : std::u16string(); |
| } |
| |
| std::string AppBrowserController::GetTitleForMediaControls() const { |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // Only return the app name if we're a System Web App. |
| if (system_app()) |
| return base::UTF16ToUTF8(GetAppShortName()); |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| return std::string(); |
| } |
| |
| GURL AppBrowserController::GetAppNewTabUrl() const { |
| return GetAppStartUrl(); |
| } |
| |
| #if BUILDFLAG(IS_MAC) |
| bool AppBrowserController::AlwaysShowToolbarInFullscreen() const { |
| return true; |
| } |
| |
| void AppBrowserController::ToggleAlwaysShowToolbarInFullscreen() {} |
| #endif |
| |
| void AppBrowserController::OnTabStripModelChanged( |
| TabStripModel* tab_strip_model, |
| const TabStripModelChange& change, |
| const TabStripSelectionChange& selection) { |
| if (selection.active_tab_changed()) { |
| content::WebContentsObserver::Observe(selection.new_contents); |
| // Update theme when tabs change unless there are no tabs, or if the tab has |
| // not finished loading, we will update later in DOMContentLoaded(). |
| if (tab_strip_model->count() > 0 && |
| selection.new_contents->IsDocumentOnLoadCompletedInPrimaryMainFrame()) { |
| UpdateThemePack(); |
| } |
| } |
| if (change.type() == TabStripModelChange::kInserted) { |
| for (const auto& contents : change.GetInsert()->contents) |
| OnTabInserted(contents.contents); |
| } else if (change.type() == TabStripModelChange::kRemoved) { |
| for (const auto& contents : change.GetRemove()->contents) |
| OnTabRemoved(contents.contents); |
| // WebContents should be null when the last tab is closed. |
| DCHECK_EQ(web_contents() == nullptr, tab_strip_model->empty()); |
| } |
| UpdateCustomTabBarVisibility(/*animate=*/false); |
| } |
| |
| CustomThemeSupplier* AppBrowserController::GetThemeSupplier() const { |
| return theme_pack_.get(); |
| } |
| |
| bool AppBrowserController::ShouldUseCustomFrame() const { |
| return true; |
| } |
| |
| void AppBrowserController::AddColorMixers( |
| ui::ColorProvider* provider, |
| const ui::ColorProviderManager::Key& key) const { |
| constexpr SkAlpha kSeparatorOpacity = 0.15f * 255.0f; |
| #if !BUILDFLAG(IS_CHROMEOS_ASH) |
| // This color is the same as the default active frame color. |
| const absl::optional<SkColor> theme_color = GetThemeColor(); |
| ui::ColorTransform default_background = |
| key.color_mode == ui::ColorProviderManager::ColorMode::kLight |
| ? ui::ColorTransform(ui::kColorFrameActiveUnthemed) |
| : ui::HSLShift(ui::kColorFrameActiveUnthemed, |
| ThemeProperties::GetDefaultTint( |
| ThemeProperties::TINT_FRAME, true)); |
| #endif |
| ui::ColorMixer& mixer = provider->AddMixer(); |
| absl::optional<SkColor> bg_color = GetBackgroundColor(); |
| // TODO(kylixrd): The definition of kColorPwaBackground isn't fully fleshed |
| // out yet. Whether or not the PWA background color is set is used in many |
| // locations to derive other colors. Those specific locations would need to be |
| // addressed in their own context. |
| if (bg_color) |
| mixer[kColorPwaBackground] = {bg_color.value()}; |
| mixer[kColorPwaMenuButtonIcon] = {kColorToolbarButtonIcon}; |
| mixer[kColorPwaSecurityChipForeground] = {ui::kColorSecondaryForeground}; |
| mixer[kColorPwaSecurityChipForegroundDangerous] = { |
| ui::kColorAlertHighSeverity}; |
| mixer[kColorPwaSecurityChipForegroundPolicyCert] = { |
| ui::kColorDisabledForeground}; |
| mixer[kColorPwaSecurityChipForegroundSecure] = { |
| kColorPwaSecurityChipForeground}; |
| auto separator_color = |
| ui::GetColorWithMaxContrast(kColorPwaToolbarBackground); |
| mixer[kColorPwaTabBarBottomSeparator] = ui::AlphaBlend( |
| separator_color, kColorPwaToolbarBackground, kSeparatorOpacity); |
| mixer[kColorPwaTabBarTopSeparator] = |
| ui::AlphaBlend(separator_color, kColorPwaTheme, kSeparatorOpacity); |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // Ash system frames differ from ChromeOS browser frames. |
| mixer[kColorPwaTheme] = {chromeos::kDefaultFrameColor}; |
| #else |
| mixer[kColorPwaTheme] = theme_color ? ui::ColorTransform(theme_color.value()) |
| : default_background; |
| #endif |
| mixer[kColorPwaToolbarBackground] = {ui::kColorEndpointBackground}; |
| mixer[kColorPwaToolbarButtonIcon] = |
| ui::DeriveDefaultIconColor(ui::kColorEndpointForeground); |
| mixer[kColorPwaToolbarButtonIconDisabled] = |
| ui::SetAlpha(kColorPwaToolbarButtonIcon, gfx::kDisabledControlAlpha); |
| if (bg_color) |
| mixer[kColorWebContentsBackground] = {kColorPwaBackground}; |
| |
| mixer[kColorInfoBarBackground] = {kColorPwaToolbarBackground}; |
| mixer[kColorInfoBarForeground] = {kColorPwaToolbarButtonIcon}; |
| } |
| |
| void AppBrowserController::OnReceivedInitialURL() { |
| UpdateCustomTabBarVisibility(/*animate=*/false); |
| |
| // If the window bounds have not been overridden, there is no need to resize |
| // the window. |
| if (!browser()->bounds_overridden()) |
| return; |
| |
| // The saved bounds will only be wrong if they are content bounds. |
| if (!chrome::SavedBoundsAreContentBounds(browser())) |
| return; |
| |
| // TODO(crbug.com/964825): Correctly set the window size at creation time. |
| // This is currently not possible because the current url is not easily known |
| // at popup construction time. |
| browser()->window()->SetContentsSize(browser()->override_bounds().size()); |
| } |
| |
| void AppBrowserController::OnTabInserted(content::WebContents* contents) { |
| if (!contents->GetVisibleURL().is_empty() && initial_url_.is_empty()) |
| SetInitialURL(contents->GetVisibleURL()); |
| } |
| |
| void AppBrowserController::OnTabRemoved(content::WebContents* contents) {} |
| |
| ui::ImageModel AppBrowserController::GetFallbackAppIcon() const { |
| gfx::ImageSkia page_icon = browser()->GetCurrentPageIcon().AsImageSkia(); |
| if (!page_icon.isNull()) { |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| return ui::ImageModel::FromImageSkia( |
| apps::CreateStandardIconImage(page_icon)); |
| #else |
| return ui::ImageModel::FromImageSkia(page_icon); |
| #endif |
| } |
| |
| // The icon may be loading still. Return a transparent icon rather |
| // than using a placeholder to avoid flickering. |
| SkBitmap bitmap; |
| bitmap.allocN32Pixels(gfx::kFaviconSize, gfx::kFaviconSize); |
| bitmap.eraseColor(SK_ColorTRANSPARENT); |
| return ui::ImageModel::FromImageSkia( |
| gfx::ImageSkia::CreateFrom1xBitmap(bitmap)); |
| } |
| |
| void AppBrowserController::UpdateDraggableRegion(const SkRegion& region) { |
| draggable_region_ = region; |
| |
| if (on_draggable_region_set_for_testing_) |
| std::move(on_draggable_region_set_for_testing_).Run(); |
| } |
| |
| void AppBrowserController::SetOnUpdateDraggableRegionForTesting( |
| base::OnceClosure done) { |
| on_draggable_region_set_for_testing_ = std::move(done); |
| } |
| |
| void AppBrowserController::UpdateThemePack() { |
| absl::optional<SkColor> theme_color = GetThemeColor(); |
| |
| AutogeneratedThemeColors colors; |
| // TODO(crbug.com/1053823): Add tests for theme properties being set in this |
| // branch. |
| absl::optional<SkColor> background_color = GetBackgroundColor(); |
| if (theme_color == last_theme_color_ && |
| background_color == last_background_color_) { |
| return; |
| } |
| last_theme_color_ = theme_color; |
| last_background_color_ = background_color; |
| |
| bool no_custom_colors = !theme_color && !background_color; |
| bool non_tabbed_no_frame_color = !has_tab_strip_ && !theme_color; |
| if (no_custom_colors || non_tabbed_no_frame_color) { |
| theme_pack_ = nullptr; |
| if (browser_->window()) { |
| browser_->window()->UserChangedTheme( |
| BrowserThemeChangeType::kWebAppTheme); |
| } |
| return; |
| } |
| |
| if (!theme_color) { |
| theme_color = GetAltColor(*background_color); |
| } else if (!background_color) { |
| background_color = |
| ui::NativeTheme::GetInstanceForNativeUi()->ShouldUseDarkColors() |
| ? gfx::kGoogleGrey900 |
| : SK_ColorWHITE; |
| } |
| |
| // For regular web apps, frame gets theme color and active tab gets |
| // background color. |
| colors.frame_color = *theme_color; |
| colors.active_tab_color = *background_color; |
| colors.ntp_color = *background_color; |
| |
| colors.frame_text_color = |
| color_utils::GetColorWithMaxContrast(colors.frame_color); |
| colors.active_tab_text_color = |
| color_utils::GetColorWithMaxContrast(colors.active_tab_color); |
| |
| theme_pack_ = base::MakeRefCounted<BrowserThemePack>( |
| ui::ColorProviderManager::ThemeInitializerSupplier::ThemeType:: |
| kAutogenerated); |
| BrowserThemePack::BuildFromColors(colors, theme_pack_.get()); |
| if (browser_->window()) |
| browser_->window()->UserChangedTheme(BrowserThemeChangeType::kWebAppTheme); |
| } |
| |
| void AppBrowserController::SetInitialURL(const GURL& initial_url) { |
| DCHECK(initial_url_.is_empty()); |
| initial_url_ = initial_url; |
| |
| OnReceivedInitialURL(); |
| } |
| |
| } // namespace web_app |