blob: 235701835ee2df94e981c77341b2ea04a0a74751 [file] [log] [blame]
// Copyright 2018 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_ICON_MANAGER_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_ICON_MANAGER_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "chrome/browser/web_applications/web_app_install_info.h"
#include "chrome/browser/web_applications/web_app_install_manager_observer.h"
#include "components/webapps/common/web_app_id.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image_skia.h"
class Profile;
namespace base {
class SequencedTaskRunner;
class Time;
} // namespace base
namespace web_app {
class WebAppInstallManager;
class WebAppProvider;
using HomeTabIconBitmaps = std::vector<SkBitmap>;
using SquareSizeDip = int;
// Exclusively used from the UI thread.
class WebAppIconManager : public WebAppInstallManagerObserver {
public:
using FaviconReadCallback =
base::RepeatingCallback<void(const webapps::AppId& app_id)>;
using ReadImageSkiaCallback =
base::OnceCallback<void(gfx::ImageSkia image_skia)>;
explicit WebAppIconManager(Profile* profile);
WebAppIconManager(const WebAppIconManager&) = delete;
WebAppIconManager& operator=(const WebAppIconManager&) = delete;
~WebAppIconManager() override;
using WriteDataCallback = base::OnceCallback<void(bool success)>;
// Writes all data (icons) for an app.
void WriteData(webapps::AppId app_id,
IconBitmaps icon_bitmaps,
IconBitmaps trusted_icon_bitmaps,
ShortcutsMenuIconBitmaps shortcuts_menu_icons,
IconsMap other_icons_map,
WriteDataCallback callback);
// Writes pending icon bitmaps for an app.
void WritePendingIconData(webapps::AppId app_id,
IconBitmaps pending_trusted_icon_bitmaps,
IconBitmaps pending_manifest_icon_bitmaps,
WriteDataCallback callback);
void DeleteData(webapps::AppId app_id, WriteDataCallback callback);
void SetProvider(base::PassKey<WebAppProvider>, WebAppProvider& provider);
void Start();
void Shutdown();
// Returns false if any icon in |icon_sizes_in_px| is missing from downloaded
// icons for a given app and |purpose|.
bool HasIcons(const webapps::AppId& app_id,
IconPurpose purpose,
const SortedSizesPx& icon_sizes) const;
// Returns false if any icon in |icon_sizes_in_px| is missing from stored
// trusted icons for a given app and |purpose|.
bool HasTrustedIcons(const webapps::AppId& app_id,
IconPurpose purpose,
const SortedSizesPx& icon_sizes) const;
struct IconSizeAndPurpose {
SquareSizePx size_px = 0;
IconPurpose purpose = IconPurpose::ANY;
bool is_trusted = false;
};
// For each of |purposes|, in the given order, looks for an icon with size at
// least |min_icon_size|. Returns information on the first icon found.
std::optional<IconSizeAndPurpose> FindIconMatchBigger(
const webapps::AppId& app_id,
const std::vector<IconPurpose>& purposes,
SquareSizePx min_size,
bool skip_trusted_icons_for_favicons = false) const;
// Returns whether there is a downloaded icon of at least |min_size| for any
// of the given |purposes|.
bool HasSmallestIcon(const webapps::AppId& app_id,
const std::vector<IconPurpose>& purposes,
SquareSizePx min_size) const;
using ReadIconsCallback =
base::OnceCallback<void(std::map<SquareSizePx, SkBitmap> icon_bitmaps)>;
// Reads specified icon bitmaps for an app and |purpose|. These icons are
// downloaded directly from the manifest and are not always surfaced to the
// end user, which is why they are untrusted. Returns empty map in |callback|
// if IO error.
void ReadUntrustedIcons(const webapps::AppId& app_id,
IconPurpose purpose,
const SortedSizesPx& icon_sizes,
ReadIconsCallback callback);
// Reads the bitmaps for the trusted icon for an app of sizes specified in
// `icon_sizes`. Returns empty map in `callback` if an IO error happens.
// The `purpose_for_fallback` information is used as a fallback to read the
// icon bitmaps obtained from the manifest, mimicking the behavior of
// ReadUntrustedIcons().
void ReadTrustedIconsWithFallbackToManifestIcons(
const webapps::AppId& app_id,
const SortedSizesPx& icon_sizes,
IconPurpose purpose_for_fallback,
ReadIconsCallback callback);
// Mimics WebAppShortcutsMenuItemInfo but stores timestamps instead of icons
// for os integration.
using ShortcutMenuIconTimes =
base::flat_map<IconPurpose, base::flat_map<SquareSizePx, base::Time>>;
using ShortcutIconDataVector = std::vector<ShortcutMenuIconTimes>;
using ShortcutIconDataCallback =
base::OnceCallback<void(ShortcutIconDataVector)>;
void ReadAllShortcutMenuIconsWithTimestamp(const webapps::AppId& app_id,
ShortcutIconDataCallback callback);
using ReadIconsUpdateTimeCallback = base::OnceCallback<void(
base::flat_map<SquareSizePx, base::Time> time_map)>;
// Reads all the last updated time for all icons in the app. Returns empty map
// in |callback| if IO error.
void ReadIconsLastUpdateTime(const webapps::AppId& app_id,
ReadIconsUpdateTimeCallback callback);
// Encapsulate the type of bitmaps being returned by ReadAllIcons().
struct WebAppBitmaps {
WebAppBitmaps(IconBitmaps manifest_icons, IconBitmaps trusted_icons)
: manifest_icons(std::move(manifest_icons)),
trusted_icons(std::move(trusted_icons)) {}
WebAppBitmaps() = default;
~WebAppBitmaps() = default;
IconBitmaps manifest_icons;
IconBitmaps trusted_icons;
};
using ReadIconBitmapsCallback =
base::OnceCallback<void(WebAppBitmaps disk_bitmap)>;
// Reads all icon bitmaps for an app. Returns empty |icon_bitmaps| in
// |callback| if IO error.
void ReadAllIcons(const webapps::AppId& app_id,
ReadIconBitmapsCallback callback);
using ReadShortcutsMenuIconsCallback = base::OnceCallback<void(
ShortcutsMenuIconBitmaps shortcuts_menu_icon_bitmaps)>;
// Reads bitmaps for all shortcuts menu icons for an app. Returns a vector of
// map<SquareSizePx, SkBitmap>. The index of a map in the vector is the same
// as that of its corresponding shortcut in the manifest's shortcuts vector.
// Returns empty vector in |callback| if we hit any error.
void ReadAllShortcutsMenuIcons(const webapps::AppId& app_id,
ReadShortcutsMenuIconsCallback callback);
using ReadIconWithPurposeCallback =
base::OnceCallback<void(IconPurpose, SkBitmap)>;
// For each of |purposes|, in the given order, looks for an icon with size at
// least |min_icon_size|. Returns the first icon found, as a bitmap. Returns
// an empty SkBitmap in |callback| if IO error.
void ReadSmallestIcon(const webapps::AppId& app_id,
const std::vector<IconPurpose>& purposes,
SquareSizePx min_size_in_px,
ReadIconWithPurposeCallback callback);
using ReadCompressedIconWithPurposeCallback =
base::OnceCallback<void(IconPurpose, std::vector<uint8_t> data)>;
// For each of |purposes|, in the given order, looks for an icon with size at
// least |min_icon_size|. Returns the first icon found, compressed as PNG.
// Returns empty |data| in |callback| if IO error.
void ReadSmallestCompressedIcon(
const webapps::AppId& app_id,
const std::vector<IconPurpose>& purposes,
SquareSizePx min_size_in_px,
ReadCompressedIconWithPurposeCallback callback);
using GetIconsSizeCallback = base::OnceCallback<void(uint64_t)>;
void GetIconsSizeForApp(const webapps::AppId& app_id,
GetIconsSizeCallback callback) const;
// Returns a square icon of gfx::kFaviconSize px, or an empty bitmap if not
// found.
SkBitmap GetFavicon(const webapps::AppId& app_id) const;
gfx::ImageSkia GetFaviconImageSkia(const webapps::AppId& app_id) const;
gfx::ImageSkia GetMonochromeFavicon(const webapps::AppId& app_id) const;
// WebAppInstallManagerObserver:
void OnWebAppInstalled(const webapps::AppId& app_id) override;
void OnWebAppInstallManagerDestroyed() override;
// Calls back with an icon of the |desired_icon_size| and |purpose|, resizing
// an icon of a different size if necessary. If no icons were available, calls
// back with an empty map. Prefers resizing a large icon smaller over resizing
// a small icon larger.
void ReadIconAndResize(const webapps::AppId& app_id,
IconPurpose purpose,
SquareSizePx desired_icon_size,
ReadIconsCallback callback);
// Reads multiple densities of the icon for each supported UI scale factor.
// See ui/base/resource/resource_scale_factor.h. Returns null image in
// `callback` if no icons found for all supported UI scale factors (matches
// only bigger icons, no upscaling).
// TODO(crbug.com/427566193): Rename here and callsites that this might be
// untrusted.
void ReadFavicons(const webapps::AppId& app_id,
IconPurpose purpose,
ReadImageSkiaCallback callback);
struct IconFilesCheck {
size_t empty = 0;
size_t missing = 0;
};
void CheckForEmptyOrMissingIconFiles(
const webapps::AppId& app_id,
base::OnceCallback<void(IconFilesCheck)> callback) const;
void SetFaviconReadCallbackForTesting(FaviconReadCallback callback);
void SetFaviconMonochromeReadCallbackForTesting(FaviconReadCallback callback);
base::FilePath GetIconFilePathForTesting(const webapps::AppId& app_id,
IconPurpose purpose,
SquareSizePx size);
// Collects icon read/write errors (unbounded) if the |kRecordWebAppDebugInfo|
// flag is enabled to be used by: chrome://web-app-internals
const std::vector<std::string>* error_log() const { return error_log_.get(); }
std::vector<std::string>* error_log() { return error_log_.get(); }
private:
base::WeakPtr<const WebAppIconManager> GetWeakPtr() const;
base::WeakPtr<WebAppIconManager> GetWeakPtr();
std::optional<IconSizeAndPurpose> FindIconMatchSmaller(
const webapps::AppId& app_id,
const std::vector<IconPurpose>& purposes,
SquareSizePx max_size,
bool skip_trusted_icons_for_favicons = false) const;
void OnReadFavicons(ReadImageSkiaCallback callback,
std::map<SquareSizePx, SkBitmap> icon_bitmaps);
void ReadFavicon(const webapps::AppId& app_id);
void OnReadFavicon(const webapps::AppId& app_id, gfx::ImageSkia image_skia);
void ReadMonochromeFavicon(const webapps::AppId& app_id);
void OnReadMonochromeFavicon(const webapps::AppId& app_id,
gfx::ImageSkia manifest_monochrome_image);
void OnMonochromeIconConverted(const webapps::AppId& app_id,
gfx::ImageSkia converted_image);
raw_ptr<WebAppProvider> provider_ = nullptr;
base::FilePath web_apps_directory_;
scoped_refptr<base::SequencedTaskRunner> icon_task_runner_;
base::ScopedObservation<WebAppInstallManager, WebAppInstallManagerObserver>
install_manager_observation_{this};
// We cache different densities for high-DPI displays per each app.
std::map<webapps::AppId, gfx::ImageSkia> favicon_cache_;
std::map<webapps::AppId, gfx::ImageSkia> favicon_monochrome_cache_;
FaviconReadCallback favicon_read_callback_;
FaviconReadCallback favicon_monochrome_read_callback_;
std::unique_ptr<std::vector<std::string>> error_log_;
base::WeakPtrFactory<WebAppIconManager> weak_ptr_factory_{this};
};
} // namespace web_app
#endif // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_ICON_MANAGER_H_