#include <memory>
#include <utility>
#include <vector>
#include "base/barrier_callback.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/test_future.h"
#include "build/chromeos_buildflags.h"
#include "cc/test/pixel_comparator.h"
#include "cc/test/pixel_test_utils.h"
#include "chrome/browser/apps/app_service/app_icon/app_icon_factory.h"
#include "chrome/browser/apps/app_service/app_icon/app_icon_test_util.h"
#include "chrome/browser/apps/app_service/app_icon/web_app_icon_test_helper.h"
#include "chrome/browser/web_applications/test/test_file_utils.h"
#include "chrome/browser/web_applications/test/web_app_icon_test_utils.h"
#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
#include "chrome/browser/web_applications/test/web_app_test_utils.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_constants.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_icon_generator.h"
#include "chrome/browser/web_applications/web_app_icon_manager.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_sync_bridge.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "components/services/app_service/public/cpp/features.h"
#include "components/services/app_service/public/cpp/icon_effects.h"
#include "components/services/app_service/public/cpp/icon_types.h"
#include "content/public/test/browser_task_environment.h"
#include "extensions/grit/extensions_browser_resources.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/resource/resource_scale_factor.h"
#include "ui/gfx/image/image_unittest_util.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_features.h"
#include "chrome/browser/apps/app_service/app_icon/app_icon_decoder.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/ash/app_list/md_icon_normalizer.h"
#include "chrome/browser/ash/arc/icon_decode_request.h"
#include "chrome/common/chrome_features.h"
#include "chrome/grit/chrome_unscaled_resources.h"
#include "chromeos/ash/components/standalone_browser/feature_refs.h"
#include "components/services/app_service/public/cpp/icon_loader.h"
#include "components/services/app_service/public/cpp/icon_types.h"
#include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
#include "ui/base/resource/resource_scale_factor.h"
#endif
namespace apps {
IconPurpose;
class WebAppIconFactoryTest : public testing::Test { … };
TEST_F(WebAppIconFactoryTest, LoadNonMaskableIcon) { … }
TEST_F(WebAppIconFactoryTest, LoadNonMaskableNonEffectCompressedIcon) { … }
TEST_F(WebAppIconFactoryTest,
LoadNonMaskableNonEffectCompressedIconWithDifferentSizeIcon) { … }
TEST_F(WebAppIconFactoryTest, LoadNonMaskableCompressedIcon) { … }
TEST_F(WebAppIconFactoryTest, LoadMaskableIcon) { … }
TEST_F(WebAppIconFactoryTest, LoadMaskableCompressedIcon) { … }
TEST_F(WebAppIconFactoryTest, LoadNonMaskableIconWithMaskableIcon) { … }
TEST_F(WebAppIconFactoryTest, LoadSmallMaskableIcon) { … }
TEST_F(WebAppIconFactoryTest, LoadExactSizeIcon) { … }
TEST_F(WebAppIconFactoryTest, LoadIconFailed) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(WebAppIconFactoryTest, ConvertSquareBitmapsToImageSkia_Empty) {
gfx::ImageSkia converted_image = ConvertSquareBitmapsToImageSkia(
std::map<web_app::SquareSizePx, SkBitmap>{},
apps::IconEffects::kNone,
32);
EXPECT_TRUE(converted_image.isNull());
}
TEST_F(WebAppIconFactoryTest,
ConvertSquareBitmapsToImageSkia_OneBigIconForDownscale) {
std::map<web_app::SquareSizePx, SkBitmap> icon_bitmaps;
web_app::AddGeneratedIcon(&icon_bitmaps, web_app::icon_size::k512,
SK_ColorYELLOW);
gfx::ImageSkia converted_image = ConvertSquareBitmapsToImageSkia(
icon_bitmaps, apps::IconEffects::kNone,
32);
const std::vector<ui::ResourceScaleFactor>& scale_factors =
ui::GetSupportedResourceScaleFactors();
ASSERT_EQ(2U, scale_factors.size());
for (const auto scale_factor : scale_factors) {
const float scale = ui::GetScaleForResourceScaleFactor(scale_factor);
ASSERT_TRUE(converted_image.HasRepresentation(scale));
EXPECT_EQ(
SK_ColorYELLOW,
converted_image.GetRepresentation(scale).GetBitmap().getColor(0, 0));
}
}
TEST_F(WebAppIconFactoryTest,
ConvertSquareBitmapsToImageSkia_OneSmallIconNoUpscale) {
std::map<web_app::SquareSizePx, SkBitmap> icon_bitmaps;
web_app::AddGeneratedIcon(&icon_bitmaps, web_app::icon_size::k16,
SK_ColorMAGENTA);
gfx::ImageSkia converted_image = ConvertSquareBitmapsToImageSkia(
icon_bitmaps, apps::IconEffects::kNone,
32);
EXPECT_TRUE(converted_image.isNull());
}
TEST_F(WebAppIconFactoryTest, ConvertSquareBitmapsToImageSkia_MatchBigger) {
const std::vector<web_app::SquareSizePx> sizes_px{
web_app::icon_size::k16, web_app::icon_size::k32, web_app::icon_size::k48,
web_app::icon_size::k64, web_app::icon_size::k128};
const std::vector<SkColor> colors{SK_ColorBLUE, SK_ColorRED, SK_ColorMAGENTA,
SK_ColorGREEN, SK_ColorWHITE};
std::map<web_app::SquareSizePx, SkBitmap> icon_bitmaps;
for (size_t i = 0; i < sizes_px.size(); ++i) {
web_app::AddGeneratedIcon(&icon_bitmaps, sizes_px[i], colors[i]);
}
gfx::ImageSkia converted_image = ConvertSquareBitmapsToImageSkia(
icon_bitmaps, apps::IconEffects::kNone,
32);
const std::vector<ui::ResourceScaleFactor>& scale_factors =
ui::GetSupportedResourceScaleFactors();
ASSERT_EQ(2U, scale_factors.size());
const std::vector<SkColor> expected_colors{SK_ColorRED, SK_ColorGREEN};
for (size_t i = 0; i < scale_factors.size(); ++i) {
const float scale = ui::GetScaleForResourceScaleFactor(scale_factors[i]);
ASSERT_TRUE(converted_image.HasRepresentation(scale));
EXPECT_EQ(
expected_colors[i],
converted_image.GetRepresentation(scale).GetBitmap().getColor(0, 0));
}
}
TEST_F(WebAppIconFactoryTest, ConvertSquareBitmapsToImageSkia_StandardEffect) {
const std::vector<web_app::SquareSizePx> sizes_px{web_app::icon_size::k48,
web_app::icon_size::k96};
const std::vector<SkColor> colors{SK_ColorBLUE, SK_ColorRED};
std::map<web_app::SquareSizePx, SkBitmap> icon_bitmaps;
for (size_t i = 0; i < sizes_px.size(); ++i) {
web_app::AddGeneratedIcon(&icon_bitmaps, sizes_px[i], colors[i]);
}
gfx::ImageSkia converted_image = ConvertSquareBitmapsToImageSkia(
icon_bitmaps,
apps::IconEffects::kCrOsStandardBackground |
apps::IconEffects::kCrOsStandardMask,
32);
EnsureRepresentationsLoaded(converted_image);
const std::vector<ui::ResourceScaleFactor>& scale_factors =
ui::GetSupportedResourceScaleFactors();
ASSERT_EQ(2U, scale_factors.size());
for (size_t i = 0; i < scale_factors.size(); ++i) {
const float scale = ui::GetScaleForResourceScaleFactor(scale_factors[i]);
ASSERT_TRUE(converted_image.HasRepresentation(scale));
EXPECT_FALSE(
converted_image.GetRepresentation(scale).GetBitmap().getColor(0, 0));
const web_app::SquareSizePx center_px = sizes_px[i] / 2;
EXPECT_TRUE(converted_image.GetRepresentation(scale).GetBitmap().getColor(
center_px, center_px));
}
}
TEST_F(WebAppIconFactoryTest, ApplyBackgroundAndMask_NullImage) {
gfx::ImageSkia image = apps::ApplyBackgroundAndMask(gfx::ImageSkia());
DCHECK(image.isNull());
}
TEST_F(WebAppIconFactoryTest, GetNonMaskableCompressedIconData) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = kSizeInDip * scale1;
const int kIconSize2 = kSizeInDip * scale2;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
test_helper().RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data1 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale1);
std::vector<uint8_t> src_data2 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale2);
auto icon1 =
GetWebAppCompressedIconData(app_id, ui::ResourceScaleFactor::k100Percent);
auto icon2 =
GetWebAppCompressedIconData(app_id, ui::ResourceScaleFactor::k200Percent);
VerifyCompressedIcon(src_data1, *icon1);
ASSERT_FALSE(icon1->is_maskable_icon);
VerifyCompressedIcon(src_data2, *icon2);
ASSERT_FALSE(icon2->is_maskable_icon);
}
TEST_F(WebAppIconFactoryTest,
GetNonMaskableCompressedIconDataWithDifferentSizeIcon) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = 96;
const int kIconSize2 = 256;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
test_helper().RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data1 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale1);
std::vector<uint8_t> src_data2 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale2);
auto icon1 =
GetWebAppCompressedIconData(app_id, ui::ResourceScaleFactor::k100Percent);
auto icon2 =
GetWebAppCompressedIconData(app_id, ui::ResourceScaleFactor::k200Percent);
VerifyCompressedIcon(src_data1, *icon1);
ASSERT_FALSE(icon1->is_maskable_icon);
VerifyCompressedIcon(src_data2, *icon2);
ASSERT_FALSE(icon2->is_maskable_icon);
}
TEST_F(WebAppIconFactoryTest, GetNonMaskableNonEffectCompressedIcon) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = kSizeInDip * scale1;
const int kIconSize2 = kSizeInDip * scale2;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
test_helper().RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data1 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale1);
std::vector<uint8_t> src_data2 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale2);
auto icon1 =
GetWebAppCompressedIconData(app_id, ui::ResourceScaleFactor::k100Percent);
auto icon2 =
GetWebAppCompressedIconData(app_id, ui::ResourceScaleFactor::k200Percent);
VerifyCompressedIcon(src_data1, *icon1);
ASSERT_FALSE(icon1->is_maskable_icon);
VerifyCompressedIcon(src_data2, *icon2);
ASSERT_FALSE(icon2->is_maskable_icon);
}
TEST_F(WebAppIconFactoryTest,
GetNonMaskableNonEffectCompressedIconWithDifferentSizeIcon) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = 96;
const int kIconSize2 = 256;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
test_helper().RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data1 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale1);
std::vector<uint8_t> src_data2 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale2);
auto icon1 =
GetWebAppCompressedIconData(app_id, ui::ResourceScaleFactor::k100Percent);
auto icon2 =
GetWebAppCompressedIconData(app_id, ui::ResourceScaleFactor::k200Percent);
VerifyCompressedIcon(src_data1, *icon1);
ASSERT_FALSE(icon1->is_maskable_icon);
VerifyCompressedIcon(src_data2, *icon2);
ASSERT_FALSE(icon2->is_maskable_icon);
}
TEST_F(WebAppIconFactoryTest, GetMaskableCompressedIcon) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = 128;
const int kIconSize2 = 256;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY, IconPurpose::MASKABLE},
sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, {kIconSize1});
web_app->SetDownloadedIconSizes(IconPurpose::MASKABLE, {kIconSize2});
test_helper().RegisterApp(std::move(web_app));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize2},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data1 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::MASKABLE, apps::IconEffects::kNone, {kIconSize2},
scale_to_size_in_px, scale1);
std::vector<uint8_t> src_data2 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::MASKABLE, apps::IconEffects::kNone, {kIconSize2},
scale_to_size_in_px, scale2);
apps::IconValuePtr icon;
auto icon1 =
GetWebAppCompressedIconData(app_id, ui::ResourceScaleFactor::k100Percent);
auto icon2 =
GetWebAppCompressedIconData(app_id, ui::ResourceScaleFactor::k200Percent);
VerifyCompressedIcon(src_data1, *icon1);
ASSERT_TRUE(icon1->is_maskable_icon);
VerifyCompressedIcon(src_data2, *icon2);
ASSERT_TRUE(icon1->is_maskable_icon);
}
class AppServiceWebAppIconTest : public WebAppIconFactoryTest {
public:
void SetUp() override {
WebAppIconFactoryTest::SetUp();
proxy_ = AppServiceProxyFactory::GetForProfile(profile());
fake_icon_loader_ = std::make_unique<apps::FakeIconLoader>(proxy_);
OverrideAppServiceProxyInnerIconLoader(fake_icon_loader_.get());
fake_publisher_ =
std::make_unique<apps::FakePublisherForIconTest>(proxy_, AppType::kWeb);
}
void OverrideAppServiceProxyInnerIconLoader(apps::IconLoader* icon_loader) {
app_service_proxy().OverrideInnerIconLoaderForTesting(icon_loader);
}
apps::IconValuePtr LoadIcon(const std::string& app_id, IconType icon_type) {
base::test::TestFuture<apps::IconValuePtr> result;
app_service_proxy().LoadIcon(app_id, icon_type, kSizeInDip,
false,
result.GetCallback());
return result.Take();
}
apps::IconValuePtr LoadIconWithIconEffects(const std::string& app_id,
uint32_t icon_effects,
IconType icon_type) {
base::test::TestFuture<apps::IconValuePtr> result;
app_service_proxy().LoadIconWithIconEffects(
app_id, icon_effects, icon_type, kSizeInDip,
false, result.GetCallback());
return result.Take();
}
std::vector<apps::IconValuePtr> MultipleLoadIconWithSameIconEffects(
const std::string& app_id,
uint32_t icon_effects,
IconType icon_type) {
base::test::TestFuture<std::vector<apps::IconValuePtr>> result;
auto barrier_callback =
base::BarrierCallback<apps::IconValuePtr>(2, result.GetCallback());
app_service_proxy().LoadIconWithIconEffects(
app_id, icon_effects, icon_type, kSizeInDip,
false, barrier_callback);
app_service_proxy().LoadIconWithIconEffects(
app_id, icon_effects, icon_type, kSizeInDip,
false, barrier_callback);
return result.Take();
}
std::vector<apps::IconValuePtr> MultipleLoadIconWithIconEffects(
const std::string& app_id,
uint32_t icon_effects1,
uint32_t icon_effects2,
IconType icon_type) {
base::test::TestFuture<std::vector<apps::IconValuePtr>> result;
auto barrier_callback =
base::BarrierCallback<apps::IconValuePtr>(2, result.GetCallback());
app_service_proxy().LoadIconWithIconEffects(
app_id, icon_effects1, icon_type, kSizeInDip,
false, barrier_callback);
app_service_proxy().LoadIconWithIconEffects(
app_id, icon_effects2, icon_type, kSizeInDip,
false, barrier_callback);
return result.Take();
}
void UpdateIcon(const std::string& app_id, const IconKey& icon_key) {
std::vector<AppPtr> apps;
AppPtr app = std::make_unique<App>(AppType::kWeb, app_id);
app->icon_key = std::move(*icon_key.Clone());
apps.push_back(std::move(app));
app_service_proxy().OnApps(std::move(apps), AppType::kWeb,
false);
}
void ReinstallApps(const std::vector<std::string>& app_ids) {
std::vector<AppPtr> uninstall_apps;
for (const auto& app_id : app_ids) {
AppPtr app = std::make_unique<App>(AppType::kWeb, app_id);
app->readiness = Readiness::kUninstalledByUser;
uninstall_apps.push_back(std::move(app));
}
app_service_proxy().OnApps(std::move(uninstall_apps), AppType::kWeb,
false);
std::vector<AppPtr> reinstall_apps;
for (const auto& app_id : app_ids) {
AppPtr app = std::make_unique<App>(AppType::kWeb, app_id);
app->readiness = Readiness::kReady;
reinstall_apps.push_back(std::move(app));
}
app_service_proxy().OnApps(std::move(reinstall_apps), AppType::kWeb,
false);
}
void RegisterApp(std::unique_ptr<web_app::WebApp> web_app) {
std::vector<AppPtr> apps;
AppPtr app = std::make_unique<App>(AppType::kWeb, web_app->app_id());
app->readiness = Readiness::kReady;
apps.push_back(std::move(app));
test_helper().RegisterApp(std::move(web_app));
app_service_proxy().OnApps(std::move(apps), AppType::kWeb,
false);
}
AppServiceProxy& app_service_proxy() { return *proxy_; }
private:
data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
raw_ptr<AppServiceProxy> proxy_;
std::unique_ptr<apps::FakeIconLoader> fake_icon_loader_;
std::unique_ptr<apps::FakePublisherForIconTest> fake_publisher_;
};
TEST_F(AppServiceWebAppIconTest, GetNonMaskableCompressedIconData) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = kSizeInDip * scale1;
const int kIconSize2 = kSizeInDip * scale2;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kRoundCorners, sizes_px,
scale_to_size_in_px, scale1);
VerifyCompressedIcon(src_data, *LoadIconWithIconEffects(
app_id, apps::IconEffects::kRoundCorners,
IconType::kCompressed));
}
TEST_F(AppServiceWebAppIconTest, GetNonMaskableCompressedIconDatasSeparately) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = kSizeInDip * scale1;
const int kIconSize2 = kSizeInDip * scale2;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data1 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale1);
std::vector<uint8_t> src_data2 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kRoundCorners, sizes_px,
scale_to_size_in_px, scale1);
VerifyCompressedIcon(src_data1,
*LoadIconWithIconEffects(app_id, IconEffects::kNone,
IconType::kCompressed));
VerifyCompressedIcon(src_data2, *LoadIconWithIconEffects(
app_id, apps::IconEffects::kRoundCorners,
IconType::kCompressed));
}
TEST_F(AppServiceWebAppIconTest, GetNonMaskableCompressedIconDatas) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = kSizeInDip * scale1;
const int kIconSize2 = kSizeInDip * scale2;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data1 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale1);
std::vector<uint8_t> src_data2 = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kRoundCorners, sizes_px,
scale_to_size_in_px, scale1);
auto ret = MultipleLoadIconWithIconEffects(app_id, apps::IconEffects::kNone,
apps::IconEffects::kRoundCorners,
IconType::kCompressed);
ASSERT_EQ(2U, ret.size());
VerifyCompressedIcon(src_data1, *ret[0]);
VerifyCompressedIcon(src_data2, *ret[1]);
}
TEST_F(AppServiceWebAppIconTest, GetNonMaskableStandardIconData) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = kSizeInDip * scale1;
const int kIconSize2 = kSizeInDip * scale2;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
gfx::ImageSkia src_image_skia = test_helper().GenerateWebAppIcon(
app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
apps::IconValuePtr iv = LoadIconWithIconEffects(
app_id,
apps::IconEffects::kRoundCorners | apps::IconEffects::kCrOsStandardIcon,
IconType::kStandard);
ASSERT_EQ(apps::IconType::kStandard, iv->icon_type);
VerifyIcon(src_image_skia, iv->uncompressed);
}
TEST_F(AppServiceWebAppIconTest,
GetNonMaskableCompressedIconDataWithDifferentSizeIcon) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale = 1.0;
const int kIconSize1 = 96;
const int kIconSize2 = 256;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kRoundCorners, sizes_px,
scale_to_size_in_px, scale);
VerifyCompressedIcon(src_data, *LoadIconWithIconEffects(
app_id, apps::IconEffects::kRoundCorners,
IconType::kCompressed));
gfx::ImageSkia src_image_skia = test_helper().GenerateWebAppIcon(
app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
true);
apps::IconValuePtr iv1 = LoadIcon(app_id, IconType::kUncompressed);
ASSERT_EQ(apps::IconType::kUncompressed, iv1->icon_type);
VerifyIcon(src_image_skia, iv1->uncompressed);
apps::IconValuePtr iv2 = LoadIcon(app_id, IconType::kStandard);
ASSERT_EQ(apps::IconType::kStandard, iv2->icon_type);
VerifyIcon(src_image_skia, iv2->uncompressed);
}
TEST_F(AppServiceWebAppIconTest,
GetNonMaskableStandardIconDataWithDifferentSizeIcon) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const int kIconSize1 = 96;
const int kIconSize2 = 256;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
gfx::ImageSkia src_image_skia = test_helper().GenerateWebAppIcon(
app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
auto ret = MultipleLoadIconWithSameIconEffects(
app_id,
apps::IconEffects::kRoundCorners | apps::IconEffects::kCrOsStandardIcon,
IconType::kStandard);
ASSERT_EQ(2U, ret.size());
ASSERT_EQ(apps::IconType::kStandard, ret[0]->icon_type);
VerifyIcon(src_image_skia, ret[0]->uncompressed);
ASSERT_EQ(apps::IconType::kStandard, ret[1]->icon_type);
VerifyIcon(src_image_skia, ret[1]->uncompressed);
}
TEST_F(AppServiceWebAppIconTest, GetNonMaskableNonEffectCompressedIcon) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = kSizeInDip * scale1;
const int kIconSize2 = kSizeInDip * scale2;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale1);
VerifyCompressedIcon(src_data, *LoadIcon(app_id, IconType::kCompressed));
}
TEST_F(AppServiceWebAppIconTest,
GetNonMaskableNonEffectCompressedIconWithDifferentSizeIcon) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale = 1.0;
const int kIconSize1 = 96;
const int kIconSize2 = 256;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::ANY, apps::IconEffects::kNone, sizes_px,
scale_to_size_in_px, scale);
VerifyCompressedIcon(src_data, *LoadIcon(app_id, IconType::kCompressed));
gfx::ImageSkia src_image_skia = test_helper().GenerateWebAppIcon(
app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px,
true);
apps::IconValuePtr iv1 = LoadIcon(app_id, IconType::kUncompressed);
ASSERT_EQ(apps::IconType::kUncompressed, iv1->icon_type);
VerifyIcon(src_image_skia, iv1->uncompressed);
apps::IconValuePtr iv2 = LoadIcon(app_id, IconType::kStandard);
ASSERT_EQ(apps::IconType::kStandard, iv2->icon_type);
VerifyIcon(src_image_skia, iv2->uncompressed);
}
TEST_F(AppServiceWebAppIconTest, GetMaskableCompressedIcon) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale = 1.0;
const int kIconSize1 = 128;
const int kIconSize2 = 256;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY, IconPurpose::MASKABLE},
sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, {kIconSize1});
web_app->SetDownloadedIconSizes(IconPurpose::MASKABLE, {kIconSize2});
RegisterApp(std::move(web_app));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize2},
{2.0, kIconSize2}};
std::vector<uint8_t> src_data = test_helper().GenerateWebAppCompressedIcon(
app_id, IconPurpose::MASKABLE, apps::IconEffects::kNone, {kIconSize2},
scale_to_size_in_px, scale);
VerifyCompressedIcon(src_data, *LoadIcon(app_id, IconType::kCompressed));
gfx::ImageSkia src_image_skia = test_helper().GenerateWebAppIcon(
app_id, IconPurpose::MASKABLE, {kIconSize2}, scale_to_size_in_px,
true);
apps::IconValuePtr iv1 = LoadIcon(app_id, IconType::kUncompressed);
ASSERT_EQ(apps::IconType::kUncompressed, iv1->icon_type);
VerifyIcon(src_image_skia, iv1->uncompressed);
apps::IconValuePtr iv2 = LoadIcon(app_id, IconType::kStandard);
ASSERT_EQ(apps::IconType::kStandard, iv2->icon_type);
VerifyIcon(src_image_skia, iv2->uncompressed);
}
TEST_F(AppServiceWebAppIconTest, GetMaskableStandardIcon) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const int kIconSize1 = 128;
const int kIconSize2 = 256;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY, IconPurpose::MASKABLE},
sizes_px, colors);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, {kIconSize1});
web_app->SetDownloadedIconSizes(IconPurpose::MASKABLE, {kIconSize2});
RegisterApp(std::move(web_app));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize2},
{2.0, kIconSize2}};
gfx::ImageSkia src_image_skia = test_helper().GenerateWebAppIcon(
app_id, IconPurpose::MASKABLE, {kIconSize2}, scale_to_size_in_px);
auto ret = MultipleLoadIconWithSameIconEffects(
app_id,
apps::IconEffects::kRoundCorners | apps::IconEffects::kCrOsStandardIcon,
IconType::kStandard);
ASSERT_EQ(2U, ret.size());
ASSERT_EQ(apps::IconType::kStandard, ret[0]->icon_type);
VerifyIcon(src_image_skia, ret[0]->uncompressed);
ASSERT_EQ(apps::IconType::kStandard, ret[1]->icon_type);
VerifyIcon(src_image_skia, ret[1]->uncompressed);
}
TEST_F(AppServiceWebAppIconTest, IconUpdate) {
auto web_app = web_app::test::CreateWebApp();
const std::string app_id = web_app->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = kSizeInDip * scale1;
const int kIconSize2 = kSizeInDip * scale2;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors1{SK_ColorGREEN, SK_ColorYELLOW};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors1);
web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app));
ASSERT_TRUE(icon_manager().HasIcons(app_id, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
gfx::ImageSkia src_image_skia1 = test_helper().GenerateWebAppIcon(
app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
uint32_t icon_effects =
apps::IconEffects::kRoundCorners | apps::IconEffects::kCrOsStandardIcon;
apps::IconValuePtr iv1 =
LoadIconWithIconEffects(app_id, icon_effects, IconType::kStandard);
ASSERT_EQ(apps::IconType::kStandard, iv1->icon_type);
VerifyIcon(src_image_skia1, iv1->uncompressed);
const std::vector<SkColor> colors2{SK_ColorRED, SK_ColorBLUE};
test_helper().WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors2);
gfx::ImageSkia src_image_skia2 = test_helper().GenerateWebAppIcon(
app_id, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
IconKey icon_key(true, icon_effects);
UpdateIcon(app_id, icon_key);
apps::IconValuePtr iv2 =
LoadIconWithIconEffects(app_id, icon_effects, IconType::kStandard);
ASSERT_EQ(apps::IconType::kStandard, iv2->icon_type);
VerifyIcon(src_image_skia2, iv2->uncompressed);
}
TEST_F(AppServiceWebAppIconTest, IconLoadingForReinstallApps) {
const GURL app1_scope("https://example.com/app");
const GURL app2_scope("https://example.com/app-two");
auto web_app1 = web_app::test::CreateWebApp(app1_scope);
const std::string app_id1 = web_app1->app_id();
auto web_app2 = web_app::test::CreateWebApp(app2_scope);
const std::string app_id2 = web_app2->app_id();
const float scale1 = 1.0;
const float scale2 = 2.0;
const int kIconSize1 = kSizeInDip * scale1;
const int kIconSize2 = kSizeInDip * scale2;
const std::vector<int> sizes_px{kIconSize1, kIconSize2};
const std::vector<SkColor> colors1{SK_ColorGREEN, SK_ColorYELLOW};
const std::vector<SkColor> colors2{SK_ColorRED, SK_ColorBLUE};
test_helper().WriteIcons(app_id1, {IconPurpose::ANY}, sizes_px, colors1);
test_helper().WriteIcons(app_id2, {IconPurpose::ANY}, sizes_px, colors2);
web_app1->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app1));
web_app2->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
RegisterApp(std::move(web_app2));
ASSERT_TRUE(icon_manager().HasIcons(app_id1, IconPurpose::ANY, sizes_px));
ASSERT_TRUE(icon_manager().HasIcons(app_id2, IconPurpose::ANY, sizes_px));
apps::ScaleToSize scale_to_size_in_px = {{1.0, kIconSize1},
{2.0, kIconSize2}};
gfx::ImageSkia src_image_skia1 = test_helper().GenerateWebAppIcon(
app_id1, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
gfx::ImageSkia src_image_skia2 = test_helper().GenerateWebAppIcon(
app_id2, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
uint32_t icon_effects =
apps::IconEffects::kRoundCorners | apps::IconEffects::kCrOsStandardIcon;
apps::IconValuePtr iv1 =
LoadIconWithIconEffects(app_id1, icon_effects, IconType::kStandard);
apps::IconValuePtr iv2 =
LoadIconWithIconEffects(app_id2, icon_effects, IconType::kStandard);
ASSERT_EQ(apps::IconType::kStandard, iv1->icon_type);
VerifyIcon(src_image_skia1, iv1->uncompressed);
ASSERT_EQ(apps::IconType::kStandard, iv2->icon_type);
VerifyIcon(src_image_skia2, iv2->uncompressed);
const std::vector<SkColor> colors3{SK_ColorBLACK, SK_ColorWHITE};
const std::vector<SkColor> colors4{SK_ColorDKGRAY, SK_ColorLTGRAY};
test_helper().WriteIcons(app_id1, {IconPurpose::ANY}, sizes_px, colors3);
test_helper().WriteIcons(app_id2, {IconPurpose::ANY}, sizes_px, colors4);
gfx::ImageSkia src_image_skia3 = test_helper().GenerateWebAppIcon(
app_id1, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
gfx::ImageSkia src_image_skia4 = test_helper().GenerateWebAppIcon(
app_id2, IconPurpose::ANY, sizes_px, scale_to_size_in_px);
ReinstallApps({app_id1, app_id2});
apps::IconValuePtr iv3 =
LoadIconWithIconEffects(app_id1, icon_effects, IconType::kStandard);
apps::IconValuePtr iv4 =
LoadIconWithIconEffects(app_id2, icon_effects, IconType::kStandard);
ASSERT_EQ(apps::IconType::kStandard, iv3->icon_type);
VerifyIcon(src_image_skia3, iv3->uncompressed);
ASSERT_EQ(apps::IconType::kStandard, iv4->icon_type);
VerifyIcon(src_image_skia4, iv4->uncompressed);
}
#endif
}