blob: e6d5b2ca5a72dff83a5e152d6d49009e475d4cfa [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/web_applications/extensions/bookmark_app_icon_manager.h"
#include <map>
#include <string>
#include <utility>
#include "base/check_op.h"
#include "base/notreached.h"
#include "chrome/browser/extensions/menu_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
#include "chrome/browser/web_applications/extensions/bookmark_app_util.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/image_loader.h"
#include "extensions/common/extension_icon_set.h"
#include "extensions/common/manifest_handlers/icons_handler.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
namespace extensions {
namespace {
void OnExtensionIconLoaded(BookmarkAppIconManager::ReadIconCallback callback,
const gfx::Image& image) {
std::move(callback).Run(image.IsEmpty() ? SkBitmap() : *image.ToSkBitmap());
}
const Extension* GetBookmarkApp(Profile* profile,
const web_app::AppId& app_id) {
const Extension* extension =
ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(app_id);
return (extension && extension->from_bookmark()) ? extension : nullptr;
}
void ReadExtensionIcon(Profile* profile,
const web_app::AppId& app_id,
SquareSizePx icon_size_in_px,
ExtensionIconSet::MatchType match_type,
BookmarkAppIconManager::ReadIconCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const Extension* extension = GetBookmarkApp(profile, app_id);
DCHECK(extension);
ImageLoader* loader = ImageLoader::Get(profile);
loader->LoadImageAsync(
extension,
IconsInfo::GetIconResource(extension, icon_size_in_px, match_type),
gfx::Size(icon_size_in_px, icon_size_in_px),
base::BindOnce(&OnExtensionIconLoaded, std::move(callback)));
}
void OnExtensionIconsLoaded(BookmarkAppIconManager::ReadIconsCallback callback,
const gfx::Image& image) {
std::map<SquareSizePx, SkBitmap> icons_map;
gfx::ImageSkia image_skia = image.AsImageSkia();
for (const gfx::ImageSkiaRep& image_skia_rep : image_skia.image_reps())
icons_map[image_skia_rep.pixel_width()] = image_skia_rep.GetBitmap();
std::move(callback).Run(std::move(icons_map));
}
void ReadExtensionIcons(Profile* profile,
const web_app::AppId& app_id,
const std::vector<SquareSizePx>& icon_sizes_in_px,
BookmarkAppIconManager::ReadIconsCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const Extension* app = GetBookmarkApp(profile, app_id);
DCHECK(app);
std::vector<ImageLoader::ImageRepresentation> info_list;
for (SquareSizePx size_in_px : icon_sizes_in_px) {
ExtensionResource resource = IconsInfo::GetIconResource(
app, size_in_px, ExtensionIconSet::MATCH_EXACTLY);
ImageLoader::ImageRepresentation image_rep{
resource, ImageLoader::ImageRepresentation::NEVER_RESIZE,
gfx::Size{size_in_px, size_in_px}, /*scale_factor=*/0.0f};
info_list.push_back(image_rep);
}
ImageLoader* loader = ImageLoader::Get(profile);
loader->LoadImagesAsync(
app, info_list,
base::BindOnce(&OnExtensionIconsLoaded, std::move(callback)));
}
} // anonymous namespace
BookmarkAppIconManager::BookmarkAppIconManager(Profile* profile)
: profile_(profile) {}
BookmarkAppIconManager::~BookmarkAppIconManager() = default;
void BookmarkAppIconManager::Start() {}
void BookmarkAppIconManager::Shutdown() {}
bool BookmarkAppIconManager::HasIcons(
const web_app::AppId& app_id,
const std::vector<SquareSizePx>& icon_sizes_in_px) const {
const Extension* app = GetBookmarkApp(profile_, app_id);
if (!app)
return false;
const ExtensionIconSet& icons = IconsInfo::GetIcons(app);
for (SquareSizePx size_in_px : icon_sizes_in_px) {
const std::string& path =
icons.Get(size_in_px, ExtensionIconSet::MATCH_EXACTLY);
if (path.empty())
return false;
}
return true;
}
bool BookmarkAppIconManager::HasSmallestIcon(
const web_app::AppId& app_id,
SquareSizePx icon_size_in_px) const {
const Extension* app = GetBookmarkApp(profile_, app_id);
if (!app)
return false;
const ExtensionIconSet& icons = IconsInfo::GetIcons(app);
const std::string& path =
icons.Get(icon_size_in_px, ExtensionIconSet::MATCH_BIGGER);
return !path.empty();
}
void BookmarkAppIconManager::ReadIcons(
const web_app::AppId& app_id,
const std::vector<SquareSizePx>& icon_sizes_in_px,
ReadIconsCallback callback) const {
DCHECK(HasIcons(app_id, icon_sizes_in_px));
ReadExtensionIcons(profile_, app_id, icon_sizes_in_px, std::move(callback));
}
void BookmarkAppIconManager::ReadAllIcons(const web_app::AppId& app_id,
ReadIconsCallback callback) const {
const Extension* app = GetBookmarkApp(profile_, app_id);
DCHECK(app);
ReadExtensionIcons(profile_, app_id, GetBookmarkAppDownloadedIconSizes(app),
std::move(callback));
}
void BookmarkAppIconManager::ReadAllShortcutsMenuIcons(
const web_app::AppId& app_id,
ReadShortcutsMenuIconsCallback callback) const {
// TODO(https://crbug.com/926083): This needs to be implemented to support
// Manifest update and local installs.
NOTIMPLEMENTED();
std::move(callback).Run(ShortcutsMenuIconsBitmaps{});
}
void BookmarkAppIconManager::ReadSmallestIcon(const web_app::AppId& app_id,
SquareSizePx icon_size_in_px,
ReadIconCallback callback) const {
DCHECK(HasSmallestIcon(app_id, icon_size_in_px));
ReadExtensionIcon(profile_, app_id, icon_size_in_px,
ExtensionIconSet::MATCH_BIGGER, std::move(callback));
}
void BookmarkAppIconManager::ReadSmallestCompressedIcon(
const web_app::AppId& app_id,
SquareSizePx icon_size_in_px,
ReadCompressedIconCallback callback) const {
NOTIMPLEMENTED();
DCHECK(HasSmallestIcon(app_id, icon_size_in_px));
std::move(callback).Run(std::vector<uint8_t>());
}
SkBitmap BookmarkAppIconManager::GetFavicon(
const web_app::AppId& app_id) const {
auto* menu_manager = extensions::MenuManager::Get(profile_);
return menu_manager->GetIconForExtension(app_id).AsBitmap();
}
} // namespace extensions