Commit 623b7070 authored by Alexey Baskakov's avatar Alexey Baskakov Committed by Commit Bot

WebApp: Extract BookmarkAppHelper's gfx stuff into a separate file.

Extract all the low-level skia/gfx/color_util stuff as
ResizeIconsAndGenerateMissing function.

This is a cut-and-paste CL, no behavior changes.

Notes:
- WebApplicationInfo::IconInfo becomes IconInfo. TODO for next CL:
Merge IconInfo and BitmapAndSource - they are essentially the same.

- BookmarkAppHelperExtensionServiceTest.LinkedAppIconsAreNotChanged test
was always broken (a bug in ValidateAllIconsWithURLsArePresent helper)
https://codereview.chromium.org/1066623008/patch/80001/90005

This is a re-land of:
https://chromium-review.googlesource.com/c/chromium/src/+/1166751
MSan issue solved, ouput parameters initialized everywhere:
SkColor generated_icon_color = SK_ColorTRANSPARENT;

TBR=ortuno@chromium.org

Bug: 860581
Change-Id: Ib26c765083e67e3a1c938a49994a5f5d5ecc8265
Reviewed-on: https://chromium-review.googlesource.com/1170665
Commit-Queue: Alexey Baskakov <loyso@chromium.org>
Reviewed-by: default avatarGiovanni Ortuño Urquidi <ortuno@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#582491}
parent f708c466
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "chrome/browser/installable/installable_metrics.h" #include "chrome/browser/installable/installable_metrics.h"
#include "chrome/browser/web_applications/components/web_app_icon_generator.h"
#include "chrome/common/web_application_info.h" #include "chrome/common/web_application_info.h"
#include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_registrar.h"
...@@ -45,15 +46,6 @@ class BookmarkAppHelper : public content::NotificationObserver { ...@@ -45,15 +46,6 @@ class BookmarkAppHelper : public content::NotificationObserver {
kUnknown, kUnknown,
}; };
struct BitmapAndSource {
BitmapAndSource();
BitmapAndSource(const GURL& source_url_p, const SkBitmap& bitmap_p);
~BitmapAndSource();
GURL source_url;
SkBitmap bitmap;
};
typedef base::Callback<void(const Extension*, const WebApplicationInfo&)> typedef base::Callback<void(const Extension*, const WebApplicationInfo&)>
CreateBookmarkAppCallback; CreateBookmarkAppCallback;
...@@ -75,24 +67,10 @@ class BookmarkAppHelper : public content::NotificationObserver { ...@@ -75,24 +67,10 @@ class BookmarkAppHelper : public content::NotificationObserver {
WebApplicationInfo* web_app_info, WebApplicationInfo* web_app_info,
ForInstallableSite installable_site); ForInstallableSite installable_site);
// This finds the closest not-smaller bitmap in |bitmaps| for each size in
// |sizes| and resizes it to that size. This returns a map of sizes to bitmaps
// which contains only bitmaps of a size in |sizes| and at most one bitmap of
// each size.
static std::map<int, BitmapAndSource> ConstrainBitmapsToSizes(
const std::vector<BitmapAndSource>& bitmaps,
const std::set<int>& sizes);
// 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 |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. The generated icon is returned in a
static void GenerateIcon(std::map<int, BitmapAndSource>* bitmaps,
int output_size,
SkColor color,
char letter);
// Same as above, but the generated icon is returned in a
// `WebApplicationInfo::IconInfo`. // `WebApplicationInfo::IconInfo`.
static WebApplicationInfo::IconInfo GenerateIconInfo(int output_size, static WebApplicationInfo::IconInfo GenerateIconInfo(int output_size,
SkColor color, SkColor color,
...@@ -105,8 +83,8 @@ class BookmarkAppHelper : public content::NotificationObserver { ...@@ -105,8 +83,8 @@ class BookmarkAppHelper : public content::NotificationObserver {
// Resize icons to the accepted sizes, and generate any that are missing. Does // Resize icons to the accepted sizes, and generate any that are missing. Does
// not update |web_app_info| except to update |generated_icon_color|. // not update |web_app_info| except to update |generated_icon_color|.
static std::map<int, BitmapAndSource> ResizeIconsAndGenerateMissing( static std::map<int, web_app::BitmapAndSource> ResizeIconsAndGenerateMissing(
std::vector<BitmapAndSource> icons, std::vector<web_app::BitmapAndSource> icons,
std::set<int> sizes_to_generate, std::set<int> sizes_to_generate,
WebApplicationInfo* web_app_info); WebApplicationInfo* web_app_info);
...@@ -118,7 +96,7 @@ class BookmarkAppHelper : public content::NotificationObserver { ...@@ -118,7 +96,7 @@ class BookmarkAppHelper : public content::NotificationObserver {
// |bitmap_map| that has a URL and size matching that in |web_app_info|, as // |bitmap_map| that has a URL and size matching that in |web_app_info|, as
// well as adding any new images from |bitmap_map| that have no URL. // well as adding any new images from |bitmap_map| that have no URL.
static void UpdateWebAppIconsWithoutChangingLinks( static void UpdateWebAppIconsWithoutChangingLinks(
std::map<int, BookmarkAppHelper::BitmapAndSource> bitmap_map, std::map<int, web_app::BitmapAndSource> bitmap_map,
WebApplicationInfo* web_app_info); WebApplicationInfo* web_app_info);
// Begins the asynchronous bookmark app creation. // Begins the asynchronous bookmark app creation.
......
...@@ -8,6 +8,8 @@ source_set("components") { ...@@ -8,6 +8,8 @@ source_set("components") {
"pending_app_manager.h", "pending_app_manager.h",
"web_app_helpers.cc", "web_app_helpers.cc",
"web_app_helpers.h", "web_app_helpers.h",
"web_app_icon_generator.cc",
"web_app_icon_generator.h",
"web_app_shortcut.cc", "web_app_shortcut.cc",
"web_app_shortcut.h", "web_app_shortcut.h",
"web_app_shortcut_chromeos.cc", "web_app_shortcut_chromeos.cc",
...@@ -49,6 +51,7 @@ source_set("unit_tests") { ...@@ -49,6 +51,7 @@ source_set("unit_tests") {
sources = [ sources = [
"web_app_helpers_unittest.cc", "web_app_helpers_unittest.cc",
"web_app_icon_downloader_unittest.cc", "web_app_icon_downloader_unittest.cc",
"web_app_icon_generator_unittest.cc",
"web_app_shortcut_mac_unittest.mm", "web_app_shortcut_mac_unittest.mm",
"web_app_shortcut_unittest.cc", "web_app_shortcut_unittest.cc",
] ]
......
// Copyright 2018 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/components/web_app_icon_generator.h"
#include <cctype>
#include <string>
#include <utility>
#include "base/macros.h"
#include "build/build_config.h"
#include "chrome/grit/platform_locale_settings.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "skia/ext/image_operations.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_analysis.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/font.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/image/canvas_image_source.h"
#include "ui/gfx/image/image.h"
namespace web_app {
namespace {
// Generates a square container icon of |output_size| by drawing the given
// |letter| into a rounded background of |color|.
class GeneratedIconImageSource : public gfx::CanvasImageSource {
public:
explicit GeneratedIconImageSource(char letter, SkColor color, int output_size)
: gfx::CanvasImageSource(gfx::Size(output_size, output_size), false),
letter_(letter),
color_(color),
output_size_(output_size) {}
~GeneratedIconImageSource() override {}
private:
// gfx::CanvasImageSource overrides:
void Draw(gfx::Canvas* canvas) override {
const uint8_t kLumaThreshold = 190;
const int icon_size = output_size_ * 3 / 4;
const int icon_inset = output_size_ / 8;
const size_t border_radius = output_size_ / 16;
const size_t font_size = output_size_ * 7 / 16;
std::string font_name =
l10n_util::GetStringUTF8(IDS_SANS_SERIF_FONT_FAMILY);
#if defined(OS_CHROMEOS)
const std::string kChromeOSFontFamily = "Noto Sans";
font_name = kChromeOSFontFamily;
#endif
// Draw a rounded rect of the given |color|.
cc::PaintFlags background_flags;
background_flags.setAntiAlias(true);
background_flags.setColor(color_);
gfx::Rect icon_rect(icon_inset, icon_inset, icon_size, icon_size);
canvas->DrawRoundRect(icon_rect, border_radius, background_flags);
// 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);
// Draw the letter onto the rounded rect. The letter's color depends on the
// luma of |color|.
const uint8_t luma = color_utils::GetLuma(color_);
canvas->DrawStringRectWithFlags(
base::string16(1, std::toupper(letter_)),
gfx::FontList(gfx::Font(font_name, font_size)),
(luma > kLumaThreshold) ? SK_ColorBLACK : SK_ColorWHITE, text_rect,
gfx::Canvas::TEXT_ALIGN_CENTER);
}
char letter_;
SkColor color_;
int output_size_;
DISALLOW_COPY_AND_ASSIGN(GeneratedIconImageSource);
};
// 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
// |color|. For each size, if an icon of the requested size already exists in
// |bitmaps|, nothing will happen.
void GenerateIcon(std::map<int, BitmapAndSource>* bitmaps,
int output_size,
SkColor color,
char letter) {
// Do nothing if there is already an icon of |output_size|.
if (bitmaps->count(output_size))
return;
(*bitmaps)[output_size].bitmap = GenerateBitmap(output_size, color, letter);
}
void GenerateIcons(std::set<int> generate_sizes,
const GURL& app_url,
SkColor generated_icon_color,
std::map<int, BitmapAndSource>* bitmap_map) {
// The letter that will be painted on the generated icon.
char icon_letter = ' ';
std::string domain_and_registry(
net::registry_controlled_domains::GetDomainAndRegistry(
app_url,
net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
if (!domain_and_registry.empty()) {
icon_letter = domain_and_registry[0];
} else if (app_url.has_host()) {
icon_letter = app_url.host_piece()[0];
}
// If no color has been specified, use a dark gray so it will stand out on the
// black shelf.
if (generated_icon_color == SK_ColorTRANSPARENT)
generated_icon_color = SK_ColorDKGRAY;
for (int size : generate_sizes) {
GenerateIcon(bitmap_map, size, generated_icon_color, icon_letter);
}
}
} // namespace
BitmapAndSource::BitmapAndSource() {}
BitmapAndSource::BitmapAndSource(const GURL& source_url_p,
const SkBitmap& bitmap_p)
: source_url(source_url_p), bitmap(bitmap_p) {}
BitmapAndSource::~BitmapAndSource() {}
std::map<int, BitmapAndSource> ConstrainBitmapsToSizes(
const std::vector<BitmapAndSource>& bitmaps,
const std::set<int>& sizes) {
std::map<int, BitmapAndSource> output_bitmaps;
std::map<int, BitmapAndSource> ordered_bitmaps;
for (const BitmapAndSource& bitmap_and_source : bitmaps) {
const SkBitmap& bitmap = bitmap_and_source.bitmap;
DCHECK(bitmap.width() == bitmap.height());
ordered_bitmaps[bitmap.width()] = bitmap_and_source;
}
if (ordered_bitmaps.size() > 0) {
for (const auto& size : sizes) {
// Find the closest not-smaller bitmap, or failing that use the largest
// icon available.
auto bitmaps_it = ordered_bitmaps.lower_bound(size);
if (bitmaps_it != ordered_bitmaps.end())
output_bitmaps[size] = bitmaps_it->second;
else
output_bitmaps[size] = ordered_bitmaps.rbegin()->second;
// Resize the bitmap if it does not exactly match the desired size.
if (output_bitmaps[size].bitmap.width() != size) {
output_bitmaps[size].bitmap = skia::ImageOperations::Resize(
output_bitmaps[size].bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
size, size);
}
}
}
return output_bitmaps;
}
SkBitmap GenerateBitmap(int output_size, SkColor color, char letter) {
gfx::ImageSkia icon_image(
std::make_unique<GeneratedIconImageSource>(letter, color, output_size),
gfx::Size(output_size, output_size));
SkBitmap dst;
if (dst.tryAllocPixels(icon_image.bitmap()->info())) {
icon_image.bitmap()->readPixels(dst.info(), dst.getPixels(), dst.rowBytes(),
0, 0);
}
return dst;
}
std::map<int, BitmapAndSource> ResizeIconsAndGenerateMissing(
const std::vector<BitmapAndSource>& icons,
const std::set<int>& sizes_to_generate,
const GURL& app_url,
SkColor* generated_icon_color) {
DCHECK(generated_icon_color);
// Resize provided icons to make sure we have versions for each size in
// |sizes_to_generate|.
std::map<int, BitmapAndSource> resized_bitmaps(
ConstrainBitmapsToSizes(icons, sizes_to_generate));
// Also add all provided icon sizes.
for (const BitmapAndSource& icon : icons) {
if (resized_bitmaps.find(icon.bitmap.width()) == resized_bitmaps.end())
resized_bitmaps.insert(std::make_pair(icon.bitmap.width(), icon));
}
// Determine the color that will be used for the icon's background. For this
// the dominant color of the first icon found is used.
if (resized_bitmaps.size()) {
color_utils::GridSampler sampler;
*generated_icon_color = color_utils::CalculateKMeanColorOfBitmap(
resized_bitmaps.begin()->second.bitmap);
}
// Work out what icons we need to generate here. Icons are only generated if
// there is no icon in the required size.
std::set<int> generate_sizes;
for (int size : sizes_to_generate) {
if (resized_bitmaps.find(size) == resized_bitmaps.end())
generate_sizes.insert(size);
}
GenerateIcons(generate_sizes, app_url, *generated_icon_color,
&resized_bitmaps);
return resized_bitmaps;
}
} // namespace web_app
// Copyright 2018 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.
#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_ICON_GENERATOR_H_
#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_ICON_GENERATOR_H_
#include <map>
#include <set>
#include <vector>
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
#include "url/gurl.h"
namespace web_app {
struct BitmapAndSource {
BitmapAndSource();
BitmapAndSource(const GURL& source_url_p, const SkBitmap& bitmap_p);
~BitmapAndSource();
GURL source_url;
SkBitmap bitmap;
};
// This finds the closest not-smaller bitmap in |bitmaps| for each size in
// |sizes| and resizes it to that size. This returns a map of sizes to bitmaps
// which contains only bitmaps of a size in |sizes| and at most one bitmap of
// each size.
std::map<int, BitmapAndSource> ConstrainBitmapsToSizes(
const std::vector<BitmapAndSource>& bitmaps,
const std::set<int>& sizes);
// Generates a square container icon of |output_size| by drawing the given
// |letter| into a rounded background of |color|.
SkBitmap GenerateBitmap(int output_size, SkColor color, char letter);
// Resize icons to the accepted sizes, and generate any that are missing.
// Note that |app_url| is the launch URL for the app.
// Output: |generated_icon_color| is the color to use if an icon needs to be
// generated for the web app.
std::map<int, BitmapAndSource> ResizeIconsAndGenerateMissing(
const std::vector<BitmapAndSource>& icons,
const std::set<int>& sizes_to_generate,
const GURL& app_url,
SkColor* generated_icon_color);
} // namespace web_app
#endif // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_ICON_GENERATOR_H_
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