blob: f582ddd48dcfd528517b5763d9827d5224458bed [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_INSTALL_INFO_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_INSTALL_INFO_H_
#include <array>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/types/expected.h"
#include "base/values.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
#include "chrome/browser/web_applications/proto/web_app.pb.h"
#include "chrome/browser/web_applications/scope_extension_info.h"
#include "components/services/app_service/public/cpp/file_handler.h"
#include "components/services/app_service/public/cpp/icon_info.h"
#include "components/services/app_service/public/cpp/protocol_handler_info.h"
#include "components/services/app_service/public/cpp/share_target.h"
#include "components/webapps/common/web_app_id.h"
#include "services/network/public/cpp/permissions_policy/permissions_policy_declaration.h"
#include "third_party/blink/public/common/manifest/manifest.h"
#include "third_party/blink/public/mojom/manifest/capture_links.mojom-shared.h"
#include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
#include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
static_assert(BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_LINUX) ||
BUILDFLAG(IS_CHROMEOS));
namespace web_app {
// A map of icon urls to the bitmaps provided by that url.
using IconsMap = std::map<GURL, std::vector<SkBitmap>>;
using SquareSizePx = int;
// Iterates in ascending order (checked in SortedSizesPxIsAscending test).
using SortedSizesPx = base::flat_set<SquareSizePx, std::less<>>;
using IconPurpose = blink::mojom::ManifestImageResource_Purpose;
constexpr std::array<IconPurpose,
static_cast<int>(IconPurpose::kMaxValue) -
static_cast<int>(IconPurpose::kMinValue) + 1>
kIconPurposes{IconPurpose::ANY, IconPurpose::MONOCHROME,
IconPurpose::MASKABLE};
struct SizeComparator {
constexpr bool operator()(const gfx::Size& left,
const gfx::Size& right) const {
if (left.height() != right.height()) {
return left.height() < right.height();
}
return left.width() < right.width();
}
};
using SizeSet = base::flat_set<gfx::Size, SizeComparator>;
apps::IconInfo::Purpose ManifestPurposeToIconInfoPurpose(
IconPurpose manifest_purpose);
// Icon bitmaps for each IconPurpose.
struct IconBitmaps {
IconBitmaps();
~IconBitmaps();
IconBitmaps(const IconBitmaps&);
IconBitmaps(IconBitmaps&&) noexcept;
IconBitmaps& operator=(const IconBitmaps&);
IconBitmaps& operator=(IconBitmaps&&) noexcept;
bool operator==(const IconBitmaps&) const;
const std::map<SquareSizePx, SkBitmap>& GetBitmapsForPurpose(
IconPurpose purpose) const;
void SetBitmapsForPurpose(IconPurpose purpose,
std::map<SquareSizePx, SkBitmap> bitmaps);
bool empty() const;
// TODO(crbug.com/40158740): Consider using base::flat_map.
// Icon bitmaps suitable for any context, keyed by their square size.
// See https://www.w3.org/TR/appmanifest/#dfn-any-purpose
std::map<SquareSizePx, SkBitmap> any;
// Icon bitmaps designed for masking, keyed by their square size.
// See https://www.w3.org/TR/appmanifest/#dfn-maskable-purpose
std::map<SquareSizePx, SkBitmap> maskable;
// Monochrome bitmaps designed for any context, keyed by their square size.
// See https://www.w3.org/TR/appmanifest/#purpose-member
std::map<SquareSizePx, SkBitmap> monochrome;
};
// Icon sizes for each IconPurpose.
struct IconSizes {
IconSizes();
~IconSizes();
IconSizes(const IconSizes&);
IconSizes(IconSizes&&) noexcept;
IconSizes& operator=(const IconSizes&);
IconSizes& operator=(IconSizes&&) noexcept;
base::Value AsDebugValue() const;
const std::vector<SquareSizePx>& GetSizesForPurpose(
IconPurpose purpose) const;
void SetSizesForPurpose(IconPurpose purpose, std::vector<SquareSizePx> sizes);
bool empty() const;
// Sizes of icon bitmaps suitable for any context.
// See https://www.w3.org/TR/appmanifest/#dfn-any-purpose
std::vector<SquareSizePx> any;
// Sizes of icon bitmaps designed for masking.
// See https://www.w3.org/TR/appmanifest/#dfn-maskable-purpose
std::vector<SquareSizePx> maskable;
// Sizes of monochrome bitmaps, keyed by their square size.
// See https://www.w3.org/TR/appmanifest/#purpose-member
std::vector<SquareSizePx> monochrome;
};
using ShortcutsMenuIconBitmaps = std::vector<IconBitmaps>;
// Structure used when creating app icon shortcuts menu and for downloading
// associated shortcut icons when supported by OS platform (eg. Windows).
struct WebAppShortcutsMenuItemInfo {
struct Icon {
Icon();
Icon(const Icon&);
Icon(Icon&&) noexcept;
~Icon();
Icon& operator=(const Icon&);
Icon& operator=(Icon&&);
base::Value AsDebugValue() const;
GURL url;
SquareSizePx square_size_px = 0;
};
WebAppShortcutsMenuItemInfo();
WebAppShortcutsMenuItemInfo(const WebAppShortcutsMenuItemInfo&);
WebAppShortcutsMenuItemInfo(WebAppShortcutsMenuItemInfo&&) noexcept;
~WebAppShortcutsMenuItemInfo();
WebAppShortcutsMenuItemInfo& operator=(const WebAppShortcutsMenuItemInfo&);
WebAppShortcutsMenuItemInfo& operator=(
WebAppShortcutsMenuItemInfo&&) noexcept;
const std::vector<Icon>& GetShortcutIconInfosForPurpose(
IconPurpose purpose) const;
void SetShortcutIconInfosForPurpose(
IconPurpose purpose,
std::vector<Icon> shortcut_manifest_icons);
base::Value AsDebugValue() const;
// Title of shortcut item in App Icon Shortcut Menu.
std::u16string name;
// URL launched when shortcut item is selected.
GURL url;
// List of shortcut icon URLs with associated square size,
// suitable for any context.
// See https://www.w3.org/TR/appmanifest/#dfn-any-purpose
std::vector<Icon> any;
// List of shortcut icon URLs with associated square size,
// designed for masking.
// See https://www.w3.org/TR/appmanifest/#dfn-maskable-purpose
std::vector<Icon> maskable;
// List of shortcut icon URLs with associated square size,
// designed for monochrome contexts.
// See https://www.w3.org/TR/appmanifest/#purpose-member
std::vector<Icon> monochrome;
// Sizes of successfully downloaded icons for this shortcut menu item.
IconSizes downloaded_icon_sizes{};
};
struct IconsWithSizeAny {
IconsWithSizeAny();
~IconsWithSizeAny();
IconsWithSizeAny(const IconsWithSizeAny& icons_with_size_any);
IconsWithSizeAny& operator=(const IconsWithSizeAny& icons_with_size_any);
bool operator==(const IconsWithSizeAny& icons_with_size_any) const;
base::Value ToDebugValue() const;
std::string ToString() const;
// 4 different maps are needed to keep track of the icons since there is no
// guarantee that the icons specified for each component that uses icons (like
// file handlers) will exist at the higher level `icons` entry for the
// manifest.
// A single GURL is stored per IconPurpose since only the last available icon
// needs to be considered as per the manifest spec.
base::flat_map<IconPurpose, GURL> manifest_icons;
SizeSet manifest_icon_provided_sizes;
base::flat_map<IconPurpose, GURL> shortcut_menu_icons;
SizeSet shortcut_menu_icons_provided_sizes;
base::flat_map<IconPurpose, GURL> file_handling_icons;
SizeSet file_handling_icon_provided_sizes;
base::flat_map<IconPurpose, GURL> home_tab_icons;
SizeSet home_tab_icon_provided_sizes;
};
// Structure used when installing a web page as an app.
struct WebAppInstallInfo {
enum MobileCapable {
MOBILE_CAPABLE_UNSPECIFIED,
MOBILE_CAPABLE,
MOBILE_CAPABLE_APPLE
};
// This creates WebAppInstallInfo in the same way as the default constructor
// does, but it will return an error on invalid arguments instead of failing
// with a CHECK().
static base::expected<WebAppInstallInfo, std::string> Create(
const GURL& manifest_url,
const webapps::ManifestId& manifest_id,
const GURL& start_url);
// This creates a WebAppInstallInfo where the `manifest_id` is derived from
// the `start_url` using `GenerateManifestIdFromStartUrlOnly`, and the `scope`
// is generated from the `start_url` without the filename.
static std::unique_ptr<WebAppInstallInfo> CreateWithStartUrlForTesting(
const GURL& start_url);
// Creates a WebAppInstallInfo from a `start_url`, where the `manifest_id` is
// derived from the `start_url` using `GenerateManifestIdFromStartUrlOnly`,
// and the `scope` is generated from the `start_url` without the filename.
// This also populates some common required fields like the title, as well as
// allows easy specification of often-modified fields like `display` and
// `user_display_mode`.
static std::unique_ptr<WebAppInstallInfo> CreateForTesting(
const GURL& start_url,
blink::mojom::DisplayMode display = blink::mojom::DisplayMode::kMinimalUi,
mojom::UserDisplayMode user_display_mode =
mojom::UserDisplayMode::kStandalone,
std::optional<blink::mojom::ManifestLaunchHandler_ClientMode>
client_mode = std::nullopt);
// The `manifest_id` and the `start_url` MUST be valid and same-origin. The
// `manifest_id` MUST NOT contain refs (e.g. '#refs').
WebAppInstallInfo(const webapps::ManifestId& manifest_id,
const GURL& start_url);
// Deleted to prevent accidental copying. Use Clone() to deep copy explicitly.
WebAppInstallInfo& operator=(const WebAppInstallInfo&) = delete;
WebAppInstallInfo(WebAppInstallInfo&&);
WebAppInstallInfo& operator=(WebAppInstallInfo&&);
~WebAppInstallInfo();
// Creates a deep copy of this struct.
WebAppInstallInfo Clone() const;
// ID specified in the manifest.
// Guaranteed to be valid & non-empty & same-origin with `start_url()` & have
// no "#ref" part in the URL.
// https://www.w3.org/TR/appmanifest/#id-member
const webapps::ManifestId& manifest_id() const { return manifest_id_; }
// URL the site would prefer the user agent load when launching the app.
// Guaranteed to be valid & non-empty & same-origin with `manifest_id()`.
// https://www.w3.org/TR/appmanifest/#start_url-member
const GURL& start_url() const { return start_url_; }
// Set the `manifest_id` and `start_url` fields. Both are set at once to allow
// origin changes if necessary. The `manifest_id` and the `start_url` have the
// same requirements as in the WebAppInstallInfo constructor.
void SetManifestIdAndStartUrl(const webapps::ManifestId& manifest_id,
const GURL& start_url);
// Title of the application.
std::u16string title;
// Description of the application.
std::u16string description;
// The URL of the manifest.
// https://www.w3.org/TR/appmanifest/#web-application-manifest
GURL manifest_url;
// Optional query parameters to add to the start_url when launching the app.
std::optional<std::string> launch_query_params;
// Scope for the app. Dictates what URLs will be opened in the app.
// https://www.w3.org/TR/appmanifest/#scope-member
GURL scope;
// List of icon URLs with associated square size and purpose. The size
// corresponds to what was specified in the manifest rather than any actual
// size of a downloaded icon.
std::vector<apps::IconInfo> manifest_icons;
// Icon bitmaps, keyed by their square size.
IconBitmaps icon_bitmaps;
// Icon bitmaps that are considered trusted by the user, keyed by their square
// size. Can be autogenerated if no icons are considered trusted.
IconBitmaps trusted_icon_bitmaps;
// A collection of unprocessed icons keyed by their download URL. The usage
// and purpose of these icons is tracked elsewhere, such as in
// `file_handlers`. Currently, this is only used for file handling icons, but
// other icons may be added here in the future.
IconsMap other_icon_bitmaps;
// Represents whether the icons for the web app are generated by Chrome due to
// no suitable icons being available.
bool is_generated_icon = false;
// Whether the page is marked as mobile-capable, including apple specific meta
// tag.
MobileCapable mobile_capable = MOBILE_CAPABLE_UNSPECIFIED;
// The color to use for the web app frame.
std::optional<SkColor> theme_color;
// The color to use for the web app frame when
// launched in dark mode. This doesn't yet have manifest support.
std::optional<SkColor> dark_mode_theme_color;
// The expected page background color of the web app.
// https://www.w3.org/TR/appmanifest/#background_color-member
std::optional<SkColor> background_color;
// The color to use for the background when
// launched in dark mode. This doesn't yet have manifest support.
std::optional<SkColor> dark_mode_background_color;
// App preference regarding whether the app should be opened in a tab,
// in a window (with or without minimal-ui buttons), or full screen. Defaults
// to browser display mode as specified in
// https://w3c.github.io/manifest/#display-modes
blink::mojom::DisplayMode display_mode = blink::mojom::DisplayMode::kBrowser;
// App preference to control display fallback ordering
std::vector<blink::mojom::DisplayMode> display_override;
// User preference for whether the app should be opened as a tab or in an app
// window. Must be either kBrowser or kStandalone, this will be checked by
// WebApp::SetUserDisplayMode().
std::optional<web_app::mojom::UserDisplayMode> user_display_mode =
web_app::mojom::UserDisplayMode::kBrowser;
// The extensions and mime types the app can handle.
apps::FileHandlers file_handlers;
// File types the app accepts as a Web Share Target.
std::optional<apps::ShareTarget> share_target;
// Additional search terms that users can use to find the app.
std::vector<std::string> additional_search_terms;
// Set of shortcuts menu item infos populated using shortcuts specified in the
// manifest.
std::vector<WebAppShortcutsMenuItemInfo> shortcuts_menu_item_infos;
// Vector of shortcut icon bitmaps keyed by their square size. The index of a
// given |IconBitmaps| matches that of the shortcut in
// |shortcuts_menu_item_infos| whose bitmaps it contains.
// Notes: It is not guaranteed that these are populated if the menu items are.
// See https://crbug.com/1427444.
ShortcutsMenuIconBitmaps shortcuts_menu_icon_bitmaps;
// The URL protocols/schemes that the app can handle.
std::vector<apps::ProtocolHandlerInfo> protocol_handlers;
// The app intends to have an extended scope containing URLs described by this
// information.
// Note: All specified 'scope' members of these extensions will have queries
// and fragments stripped, per specification.
// https://w3c.github.io/manifest/#scope-member
base::flat_set<web_app::ScopeExtensionInfo> scope_extensions;
// `scope_extensions` after going through validation with associated origins.
// Only entries that have been validated by the corresponding origins remain.
// See
// https://github.com/WICG/manifest-incubations/blob/gh-pages/scope_extensions-explainer.md
// for association requirements.
// Note: All specified 'scope' members of these extensions will have queries
// and fragments stripped, per specification.
// https://w3c.github.io/manifest/#scope-member
std::optional<base::flat_set<web_app::ScopeExtensionInfo>>
validated_scope_extensions;
// URL within scope to launch on the lock screen for a "show on lock screen"
// action. Valid iff this is considered a lock-screen-capable app.
GURL lock_screen_start_url;
// URL within scope to launch for a "new note" action. Valid iff this is
// considered a note-taking app.
GURL note_taking_new_note_url;
// The link capturing behaviour to use for navigations into in the app's
// scope.
blink::mojom::CaptureLinks capture_links =
blink::mojom::CaptureLinks::kUndefined;
// The window selection behaviour of app launches.
std::optional<blink::Manifest::LaunchHandler> launch_handler;
// A mapping from locales to translated fields.
base::flat_map<std::string, blink::Manifest::TranslationItem> translations;
// The declared permissions policy to apply as the baseline policy for all
// documents belonging to the application.
network::ParsedPermissionsPolicy permissions_policy;
// See ExternallyManagedAppManager for placeholder app documentation.
// Intended to be a temporary app while we wait for the install_url to
// successfully load.
bool is_placeholder = false;
// The install URL for the app. This does not always need to be
// populated (especially for user installed or sync installed apps)
// in which case the URL will not be written to the web_app DB.
GURL install_url;
// Customisations to the tab strip. This field is only used when the
// display mode is set to 'tabbed'.
std::optional<blink::Manifest::TabStrip> tab_strip;
// Id of the app that called the SUB_APP API to install this app. This field
// is only used when the app is installed as a sub app through the SUB_APP
// API.
std::optional<webapps::AppId> parent_app_id;
// ManifestId of the app that called the SUB_APP API to install this app. This
// field is only used when the app is installed as a sub app through the
// SUB_APP API.
std::optional<webapps::ManifestId> parent_app_manifest_id;
// A list of additional terms to use when matching this app against
// identifiers in admin policies (for shelf pinning, default file handlers,
// etc).
// Note that list is not meant to be an exhaustive enumeration of all possible
// policy_ids but rather just a supplement for tricky cases.
std::vector<std::string> additional_policy_ids;
// Used to specify the version of an Isolated Web App that is being installed.
base::Version isolated_web_app_version;
// Bookkeeping details about attempts to fix broken icons from sync installed
// web apps.
std::optional<proto::GeneratedIconFix> generated_icon_fix;
IconsWithSizeAny icons_with_size_any;
// A DIY app isn't installable or promotable, and the user was able to
// customize the title, etc.
bool is_diy_app = false;
// Apps that are listed as related applications in the manifest.
std::vector<blink::Manifest::RelatedApplication> related_applications;
// List of icon URLs with associated square size and purpose that is
// considered trusted. This is used to write to the web_app post installation
// or updates, and is used to store metadata about the icon that will be shown
// for the web app on security sensitive surfaces.
std::vector<apps::IconInfo> trusted_icons;
private:
// Used this method in Clone() method. Use Clone() to deep copy explicitly.
WebAppInstallInfo(const WebAppInstallInfo& other);
// See `manifest_id()`.
webapps::ManifestId manifest_id_;
// See `start_url()`.
GURL start_url_;
};
bool operator==(const IconSizes& icon_sizes1, const IconSizes& icon_sizes2);
bool operator==(const WebAppShortcutsMenuItemInfo::Icon& icon1,
const WebAppShortcutsMenuItemInfo::Icon& icon2);
bool operator==(const WebAppShortcutsMenuItemInfo& shortcut_info1,
const WebAppShortcutsMenuItemInfo& shortcut_info2);
} // namespace web_app
#endif // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_INSTALL_INFO_H_