Commit e8b9095f authored by Md. Hasanur Rashid's avatar Md. Hasanur Rashid Committed by Commit Bot

desktop-pwas: Use app name if available to generate the icon

Currently, if we can't retrieve the app's icon or the app has no icons,
we use the app's start URL to generate an icon. This change use the
app's name when available to generate the icon.

Bug: 904280
Change-Id: I6233ea5ee90f32de6e270123239055f425edd257
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1989435Reviewed-by: default avatarAlexey Baskakov <loyso@chromium.org>
Commit-Queue: Md. Hasanur Rashid <hasanur.r@samsung.com>
Cr-Commit-Position: refs/heads/master@{#732668}
parent 138de6d5
...@@ -31,17 +31,17 @@ namespace web_app { ...@@ -31,17 +31,17 @@ namespace web_app {
namespace { namespace {
// Generates a square container icon of |output_size| by drawing the given // Generates a square container icon of |output_size| by drawing the given
// |letter| into a rounded background of |color|. // |icon_letter| into a rounded background of |color|.
class GeneratedIconImageSource : public gfx::CanvasImageSource { class GeneratedIconImageSource : public gfx::CanvasImageSource {
public: public:
explicit GeneratedIconImageSource(base::char16 letter, explicit GeneratedIconImageSource(base::char16 icon_letter,
SkColor color, SkColor color,
SquareSizePx output_size) SquareSizePx output_size)
: gfx::CanvasImageSource(gfx::Size(output_size, output_size)), : gfx::CanvasImageSource(gfx::Size(output_size, output_size)),
letter_(letter), icon_letter_(icon_letter),
color_(color), color_(color),
output_size_(output_size) {} output_size_(output_size) {}
~GeneratedIconImageSource() override {} ~GeneratedIconImageSource() override = default;
private: private:
// gfx::CanvasImageSource overrides: // gfx::CanvasImageSource overrides:
...@@ -69,13 +69,13 @@ class GeneratedIconImageSource : public gfx::CanvasImageSource { ...@@ -69,13 +69,13 @@ class GeneratedIconImageSource : public gfx::CanvasImageSource {
// The text rect's size needs to be odd to center the text correctly. // The text rect's size needs to be odd to center the text correctly.
gfx::Rect text_rect(icon_inset, icon_inset, icon_size + 1, icon_size + 1); gfx::Rect text_rect(icon_inset, icon_inset, icon_size + 1, icon_size + 1);
canvas->DrawStringRectWithFlags( canvas->DrawStringRectWithFlags(
base::string16(1, letter_), base::string16(1, icon_letter_),
gfx::FontList(gfx::Font(font_name, font_size)), gfx::FontList(gfx::Font(font_name, font_size)),
color_utils::GetColorWithMaxContrast(color_), text_rect, color_utils::GetColorWithMaxContrast(color_), text_rect,
gfx::Canvas::TEXT_ALIGN_CENTER); gfx::Canvas::TEXT_ALIGN_CENTER);
} }
base::char16 letter_; base::char16 icon_letter_;
SkColor color_; SkColor color_;
...@@ -85,22 +85,22 @@ class GeneratedIconImageSource : public gfx::CanvasImageSource { ...@@ -85,22 +85,22 @@ class GeneratedIconImageSource : public gfx::CanvasImageSource {
}; };
// Adds a square container icon of |output_size| and 2 * |output_size| pixels // Adds a square container icon of |output_size| and 2 * |output_size| pixels
// to |bitmaps| by drawing the given |letter| into a rounded background of // to |bitmaps| by drawing the given |icon_letter| into a rounded background of
// |color|. For each size, if an icon of the requested size already exists in // |color|. For each size, if an icon of the requested size already exists in
// |bitmaps|, nothing will happen. // |bitmaps|, nothing will happen.
void GenerateIcon(std::map<SquareSizePx, SkBitmap>* bitmaps, void GenerateIcon(std::map<SquareSizePx, SkBitmap>* bitmaps,
SquareSizePx output_size, SquareSizePx output_size,
SkColor color, SkColor color,
base::char16 letter) { base::char16 icon_letter) {
// Do nothing if there is already an icon of |output_size|. // Do nothing if there is already an icon of |output_size|.
if (bitmaps->count(output_size)) if (bitmaps->count(output_size))
return; return;
(*bitmaps)[output_size] = GenerateBitmap(output_size, color, letter); (*bitmaps)[output_size] = GenerateBitmap(output_size, color, icon_letter);
} }
void GenerateIcons(std::set<SquareSizePx> generate_sizes, void GenerateIcons(std::set<SquareSizePx> generate_sizes,
const GURL& app_url, base::char16 icon_letter,
SkColor generated_icon_color, SkColor generated_icon_color,
std::map<SquareSizePx, SkBitmap>* bitmap_map) { std::map<SquareSizePx, SkBitmap>* bitmap_map) {
// If no color has been specified, use a dark gray so it will stand out on the // If no color has been specified, use a dark gray so it will stand out on the
...@@ -108,8 +108,6 @@ void GenerateIcons(std::set<SquareSizePx> generate_sizes, ...@@ -108,8 +108,6 @@ void GenerateIcons(std::set<SquareSizePx> generate_sizes,
if (generated_icon_color == SK_ColorTRANSPARENT) if (generated_icon_color == SK_ColorTRANSPARENT)
generated_icon_color = SK_ColorDKGRAY; generated_icon_color = SK_ColorDKGRAY;
const base::char16 icon_letter = GenerateIconLetterFromUrl(app_url);
for (SquareSizePx size : generate_sizes) for (SquareSizePx size : generate_sizes)
GenerateIcon(bitmap_map, size, generated_icon_color, icon_letter); GenerateIcon(bitmap_map, size, generated_icon_color, icon_letter);
} }
...@@ -161,10 +159,10 @@ std::map<SquareSizePx, SkBitmap> ConstrainBitmapsToSizes( ...@@ -161,10 +159,10 @@ std::map<SquareSizePx, SkBitmap> ConstrainBitmapsToSizes(
SkBitmap GenerateBitmap(SquareSizePx output_size, SkBitmap GenerateBitmap(SquareSizePx output_size,
SkColor color, SkColor color,
base::char16 letter) { base::char16 icon_letter) {
gfx::ImageSkia icon_image( gfx::ImageSkia icon_image(std::make_unique<GeneratedIconImageSource>(
std::make_unique<GeneratedIconImageSource>(letter, color, output_size), icon_letter, color, output_size),
gfx::Size(output_size, output_size)); gfx::Size(output_size, output_size));
SkBitmap dst; SkBitmap dst;
if (dst.tryAllocPixels(icon_image.bitmap()->info())) { if (dst.tryAllocPixels(icon_image.bitmap()->info())) {
icon_image.bitmap()->readPixels(dst.info(), dst.getPixels(), dst.rowBytes(), icon_image.bitmap()->readPixels(dst.info(), dst.getPixels(), dst.rowBytes(),
...@@ -173,7 +171,6 @@ SkBitmap GenerateBitmap(SquareSizePx output_size, ...@@ -173,7 +171,6 @@ SkBitmap GenerateBitmap(SquareSizePx output_size,
return dst; return dst;
} }
// Returns the letter that will be painted on the generated icon.
base::char16 GenerateIconLetterFromUrl(const GURL& app_url) { base::char16 GenerateIconLetterFromUrl(const GURL& app_url) {
std::string app_url_part = " "; std::string app_url_part = " ";
const std::string domain_and_registry = const std::string domain_and_registry =
...@@ -195,10 +192,15 @@ base::char16 GenerateIconLetterFromUrl(const GURL& app_url) { ...@@ -195,10 +192,15 @@ base::char16 GenerateIconLetterFromUrl(const GURL& app_url) {
return icon_letter; return icon_letter;
} }
base::char16 GenerateIconLetterFromAppName(const base::string16& app_name) {
CHECK(!app_name.empty());
return base::i18n::ToUpper(app_name)[0];
}
std::map<SquareSizePx, SkBitmap> ResizeIconsAndGenerateMissing( std::map<SquareSizePx, SkBitmap> ResizeIconsAndGenerateMissing(
const std::vector<SkBitmap>& icons, const std::vector<SkBitmap>& icons,
const std::set<SquareSizePx>& sizes_to_generate, const std::set<SquareSizePx>& sizes_to_generate,
const GURL& app_url, base::char16 icon_letter,
SkColor* generated_icon_color) { SkColor* generated_icon_color) {
DCHECK(generated_icon_color); DCHECK(generated_icon_color);
...@@ -228,7 +230,7 @@ std::map<SquareSizePx, SkBitmap> ResizeIconsAndGenerateMissing( ...@@ -228,7 +230,7 @@ std::map<SquareSizePx, SkBitmap> ResizeIconsAndGenerateMissing(
if (resized_bitmaps.find(size) == resized_bitmaps.end()) if (resized_bitmaps.find(size) == resized_bitmaps.end())
generate_sizes.insert(size); generate_sizes.insert(size);
} }
GenerateIcons(generate_sizes, app_url, *generated_icon_color, GenerateIcons(generate_sizes, icon_letter, *generated_icon_color,
&resized_bitmaps); &resized_bitmaps);
return resized_bitmaps; return resized_bitmaps;
...@@ -237,14 +239,12 @@ std::map<SquareSizePx, SkBitmap> ResizeIconsAndGenerateMissing( ...@@ -237,14 +239,12 @@ std::map<SquareSizePx, SkBitmap> ResizeIconsAndGenerateMissing(
std::map<SquareSizePx, SkBitmap> GenerateIcons(const std::string& app_name, std::map<SquareSizePx, SkBitmap> GenerateIcons(const std::string& app_name,
SkColor background_icon_color) { SkColor background_icon_color) {
const base::string16 app_name_utf16 = base::UTF8ToUTF16(app_name); const base::string16 app_name_utf16 = base::UTF8ToUTF16(app_name);
CHECK(!app_name_utf16.empty()); const base::char16 icon_letter =
const base::char16 first_app_name_letter = GenerateIconLetterFromAppName(app_name_utf16);
base::i18n::ToUpper(app_name_utf16)[0];
std::map<SquareSizePx, SkBitmap> icons; std::map<SquareSizePx, SkBitmap> icons;
for (SquareSizePx size : SizesToGenerate()) { for (SquareSizePx size : SizesToGenerate()) {
icons[size] = icons[size] = GenerateBitmap(size, background_icon_color, icon_letter);
GenerateBitmap(size, background_icon_color, first_app_name_letter);
} }
return icons; return icons;
} }
......
...@@ -49,22 +49,28 @@ std::map<SquareSizePx, SkBitmap> ConstrainBitmapsToSizes( ...@@ -49,22 +49,28 @@ std::map<SquareSizePx, SkBitmap> ConstrainBitmapsToSizes(
const std::set<SquareSizePx>& sizes); const std::set<SquareSizePx>& sizes);
// Generates a square container icon of |output_size| by drawing the given // Generates a square container icon of |output_size| by drawing the given
// |letter| into a rounded background of |color|. // |icon_letter| into a rounded background of |color|.
SkBitmap GenerateBitmap(SquareSizePx output_size, SkBitmap GenerateBitmap(SquareSizePx output_size,
SkColor color, SkColor color,
base::char16 letter); base::char16 icon_letter);
// Returns the letter that will be painted on the generated icon. // Returns the first letter from |app_url| that will be painted on the generated
// icon.
base::char16 GenerateIconLetterFromUrl(const GURL& app_url); base::char16 GenerateIconLetterFromUrl(const GURL& app_url);
// Returns the first letter from |app_name| that will be painted on the
// generated icon.
base::char16 GenerateIconLetterFromAppName(const base::string16& app_name);
// Resize icons to the accepted sizes, and generate any that are missing. // Resize icons to the accepted sizes, and generate any that are missing.
// Note that |app_url| is the launch URL for the app. // Note that |icon_letter| is the first letter of app name if available
// otherwise the first letter of app url.
// Output: |generated_icon_color| is the color to use if an icon needs to be // Output: |generated_icon_color| is the color to use if an icon needs to be
// generated for the web app. // generated for the web app.
std::map<SquareSizePx, SkBitmap> ResizeIconsAndGenerateMissing( std::map<SquareSizePx, SkBitmap> ResizeIconsAndGenerateMissing(
const std::vector<SkBitmap>& icons, const std::vector<SkBitmap>& icons,
const std::set<SquareSizePx>& sizes_to_generate, const std::set<SquareSizePx>& sizes_to_generate,
const GURL& app_url, base::char16 icon_letter,
SkColor* generated_icon_color); SkColor* generated_icon_color);
// Generate icons for default sizes, using the first letter of the application // Generate icons for default sizes, using the first letter of the application
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/web_applications/test/web_app_icon_test_utils.h" #include "chrome/browser/web_applications/test/web_app_icon_test_utils.h"
...@@ -29,7 +30,9 @@ const int kIconSizeLargeBetweenMediumAndLarge = 96; ...@@ -29,7 +30,9 @@ const int kIconSizeLargeBetweenMediumAndLarge = 96;
std::set<int> TestSizesToGenerate() { std::set<int> TestSizesToGenerate() {
const int kIconSizesToGenerate[] = { const int kIconSizesToGenerate[] = {
icon_size::k32, icon_size::k48, icon_size::k128, icon_size::k32,
icon_size::k48,
icon_size::k128,
}; };
return std::set<int>(kIconSizesToGenerate, return std::set<int>(kIconSizesToGenerate,
kIconSizesToGenerate + base::size(kIconSizesToGenerate)); kIconSizesToGenerate + base::size(kIconSizesToGenerate));
...@@ -151,7 +154,9 @@ void TestIconGeneration(int icon_size, ...@@ -151,7 +154,9 @@ void TestIconGeneration(int icon_size,
// Now run the resizing/generation and validation. // Now run the resizing/generation and validation.
SkColor generated_icon_color = SK_ColorTRANSPARENT; SkColor generated_icon_color = SK_ColorTRANSPARENT;
auto size_map = ResizeIconsAndGenerateMissing( auto size_map = ResizeIconsAndGenerateMissing(
downloaded, TestSizesToGenerate(), GURL(), &generated_icon_color); downloaded, TestSizesToGenerate(),
GenerateIconLetterFromAppName(base::UTF8ToUTF16("Test")),
&generated_icon_color);
ValidateIconsGeneratedAndResizedCorrectly( ValidateIconsGeneratedAndResizedCorrectly(
downloaded, size_map, TestSizesToGenerate(), expected_generated, downloaded, size_map, TestSizesToGenerate(), expected_generated,
...@@ -236,7 +241,9 @@ TEST_F(WebAppIconGeneratorTest, LinkedAppIconsAreNotChanged) { ...@@ -236,7 +241,9 @@ TEST_F(WebAppIconGeneratorTest, LinkedAppIconsAreNotChanged) {
// Now run the resizing and generation into a new web icons info. // Now run the resizing and generation into a new web icons info.
SkColor generated_icon_color = SK_ColorTRANSPARENT; SkColor generated_icon_color = SK_ColorTRANSPARENT;
std::map<int, SkBitmap> size_map = ResizeIconsAndGenerateMissing( std::map<int, SkBitmap> size_map = ResizeIconsAndGenerateMissing(
downloaded, sizes, GURL(), &generated_icon_color); downloaded, sizes,
GenerateIconLetterFromAppName(base::UTF8ToUTF16("Test")),
&generated_icon_color);
EXPECT_EQ(sizes.size(), size_map.size()); EXPECT_EQ(sizes.size(), size_map.size());
// Now check that the linked app icons are matching. // Now check that the linked app icons are matching.
...@@ -258,7 +265,9 @@ TEST_F(WebAppIconGeneratorTest, IconsResizedFromOddSizes) { ...@@ -258,7 +265,9 @@ TEST_F(WebAppIconGeneratorTest, IconsResizedFromOddSizes) {
// Now run the resizing and generation. // Now run the resizing and generation.
SkColor generated_icon_color = SK_ColorTRANSPARENT; SkColor generated_icon_color = SK_ColorTRANSPARENT;
std::map<int, SkBitmap> size_map = ResizeIconsAndGenerateMissing( std::map<int, SkBitmap> size_map = ResizeIconsAndGenerateMissing(
downloaded, TestSizesToGenerate(), GURL(), &generated_icon_color); downloaded, TestSizesToGenerate(),
GenerateIconLetterFromAppName(base::UTF8ToUTF16("Test")),
&generated_icon_color);
// No icons should be generated. The LARGE and MEDIUM sizes should be resized. // No icons should be generated. The LARGE and MEDIUM sizes should be resized.
ValidateIconsGeneratedAndResizedCorrectly(downloaded, size_map, ValidateIconsGeneratedAndResizedCorrectly(downloaded, size_map,
...@@ -276,7 +285,9 @@ TEST_F(WebAppIconGeneratorTest, IconsResizedFromLarger) { ...@@ -276,7 +285,9 @@ TEST_F(WebAppIconGeneratorTest, IconsResizedFromLarger) {
// Now run the resizing and generation. // Now run the resizing and generation.
SkColor generated_icon_color = SK_ColorTRANSPARENT; SkColor generated_icon_color = SK_ColorTRANSPARENT;
std::map<int, SkBitmap> size_map = ResizeIconsAndGenerateMissing( std::map<int, SkBitmap> size_map = ResizeIconsAndGenerateMissing(
downloaded, TestSizesToGenerate(), GURL(), &generated_icon_color); downloaded, TestSizesToGenerate(),
GenerateIconLetterFromAppName(base::UTF8ToUTF16("Test")),
&generated_icon_color);
// Expect icon for MEDIUM and LARGE to be resized from the gigantor icon // Expect icon for MEDIUM and LARGE to be resized from the gigantor icon
// as it was not downloaded. // as it was not downloaded.
...@@ -291,7 +302,9 @@ TEST_F(WebAppIconGeneratorTest, AllIconsGeneratedWhenNotDownloaded) { ...@@ -291,7 +302,9 @@ TEST_F(WebAppIconGeneratorTest, AllIconsGeneratedWhenNotDownloaded) {
// Now run the resizing and generation. // Now run the resizing and generation.
SkColor generated_icon_color = SK_ColorTRANSPARENT; SkColor generated_icon_color = SK_ColorTRANSPARENT;
std::map<int, SkBitmap> size_map = ResizeIconsAndGenerateMissing( std::map<int, SkBitmap> size_map = ResizeIconsAndGenerateMissing(
downloaded, TestSizesToGenerate(), GURL(), &generated_icon_color); downloaded, TestSizesToGenerate(),
GenerateIconLetterFromAppName(base::UTF8ToUTF16("Test")),
&generated_icon_color);
// Expect all icons to be generated. // Expect all icons to be generated.
ValidateIconsGeneratedAndResizedCorrectly(downloaded, size_map, ValidateIconsGeneratedAndResizedCorrectly(downloaded, size_map,
...@@ -308,7 +321,9 @@ TEST_F(WebAppIconGeneratorTest, IconResizedFromLargerAndSmaller) { ...@@ -308,7 +321,9 @@ TEST_F(WebAppIconGeneratorTest, IconResizedFromLargerAndSmaller) {
// Now run the resizing and generation. // Now run the resizing and generation.
SkColor generated_icon_color = SK_ColorTRANSPARENT; SkColor generated_icon_color = SK_ColorTRANSPARENT;
std::map<int, SkBitmap> size_map = ResizeIconsAndGenerateMissing( std::map<int, SkBitmap> size_map = ResizeIconsAndGenerateMissing(
downloaded, TestSizesToGenerate(), GURL(), &generated_icon_color); downloaded, TestSizesToGenerate(),
GenerateIconLetterFromAppName(base::UTF8ToUTF16("Test")),
&generated_icon_color);
// Expect no icons to be generated, but the LARGE and SMALL icons to be // Expect no icons to be generated, but the LARGE and SMALL icons to be
// resized from the MEDIUM icon. // resized from the MEDIUM icon.
...@@ -343,6 +358,17 @@ TEST_F(WebAppIconGeneratorTest, GenerateIconLetterFromUrl) { ...@@ -343,6 +358,17 @@ TEST_F(WebAppIconGeneratorTest, GenerateIconLetterFromUrl) {
GenerateIconLetterFromUrl(GURL("http://xn--mgbh0fb.example/"))); GenerateIconLetterFromUrl(GURL("http://xn--mgbh0fb.example/")));
} }
TEST_F(WebAppIconGeneratorTest, GenerateIconLetterFromAppName) {
// ASCII Encoding
EXPECT_EQ('T',
GenerateIconLetterFromAppName(base::ASCIIToUTF16("test app name")));
EXPECT_EQ('T',
GenerateIconLetterFromAppName(base::ASCIIToUTF16("Test app name")));
// UTF16 encoding:
const base::char16 russian_name[] = {0x0438, 0x043c, 0x044f, 0x0};
EXPECT_EQ(0x0418, GenerateIconLetterFromAppName(russian_name));
}
TEST_F(WebAppIconGeneratorTest, GenerateIcons) { TEST_F(WebAppIconGeneratorTest, GenerateIcons) {
std::set<int> sizes = SizesToGenerate(); std::set<int> sizes = SizesToGenerate();
const SkColor bg_color = SK_ColorCYAN; const SkColor bg_color = SK_ColorCYAN;
......
...@@ -153,11 +153,15 @@ void FilterAndResizeIconsGenerateMissing(WebApplicationInfo* web_app_info, ...@@ -153,11 +153,15 @@ void FilterAndResizeIconsGenerateMissing(WebApplicationInfo* web_app_info,
sizes_to_generate.insert(icon.square_size_px); sizes_to_generate.insert(icon.square_size_px);
} }
base::char16 icon_letter =
web_app_info->title.empty()
? GenerateIconLetterFromUrl(web_app_info->app_url)
: GenerateIconLetterFromAppName(web_app_info->title);
web_app_info->generated_icon_color = SK_ColorTRANSPARENT; web_app_info->generated_icon_color = SK_ColorTRANSPARENT;
// TODO(https://crbug.com/1029223): Don't resize before writing to disk, it's // TODO(https://crbug.com/1029223): Don't resize before writing to disk, it's
// not necessary and would simplify this code path to remove. // not necessary and would simplify this code path to remove.
std::map<SquareSizePx, SkBitmap> size_to_icon = ResizeIconsAndGenerateMissing( std::map<SquareSizePx, SkBitmap> size_to_icon = ResizeIconsAndGenerateMissing(
square_icons, sizes_to_generate, web_app_info->app_url, square_icons, sizes_to_generate, icon_letter,
&web_app_info->generated_icon_color); &web_app_info->generated_icon_color);
for (std::pair<const SquareSizePx, SkBitmap>& item : size_to_icon) { for (std::pair<const SquareSizePx, SkBitmap>& item : size_to_icon) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment