| // 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. |
| |
| #include "chrome/browser/shortcuts/shortcut_icon_generator.h" |
| |
| #include <string> |
| |
| #include "base/i18n/break_iterator.h" |
| #include "base/i18n/case_conversion.h" |
| #include "build/build_config.h" |
| #include "cc/paint/paint_flags.h" |
| #include "chrome/grit/platform_locale_settings.h" |
| #include "components/url_formatter/url_formatter.h" |
| #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/gfx/canvas.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" |
| |
| namespace shortcuts { |
| |
| namespace { |
| |
| // Generates a square container icon of `output_size` by drawing the given |
| // `icon_letter` into a rounded background of `color`. |
| class GeneratedIconImageSource : public gfx::CanvasImageSource { |
| public: |
| GeneratedIconImageSource(std::u16string_view icon_letter, |
| SquareSizePx output_size) |
| : gfx::CanvasImageSource(gfx::Size(output_size, output_size)), |
| icon_letter_(icon_letter), |
| output_size_(output_size) {} |
| GeneratedIconImageSource(const GeneratedIconImageSource&) = delete; |
| GeneratedIconImageSource& operator=(const GeneratedIconImageSource&) = delete; |
| ~GeneratedIconImageSource() override = default; |
| |
| private: |
| // gfx::CanvasImageSource overrides: |
| void Draw(gfx::Canvas* canvas) override { |
| SquareSizePx icon_size = output_size_ * 3 / 4; |
| 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 BUILDFLAG(IS_CHROMEOS) |
| // With adaptive icons, we generate full size square icons as they will be |
| // masked by the OS. |
| icon_size = output_size_; |
| icon_inset = 0; |
| const std::string kChromeOSFontFamily = "Noto Sans"; |
| font_name = kChromeOSFontFamily; |
| #endif |
| |
| // Use a dark gray so it will stand out on the black shelf. |
| constexpr SkColor color = SK_ColorDKGRAY; |
| |
| // 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); |
| canvas->DrawStringRectWithFlags( |
| icon_letter_, gfx::FontList(gfx::Font(font_name, font_size)), |
| color_utils::GetColorWithMaxContrast(color), text_rect, |
| gfx::Canvas::TEXT_ALIGN_CENTER); |
| } |
| |
| std::u16string icon_letter_; |
| int output_size_; |
| }; |
| |
| // Gets the first grapheme of a string. |
| std::u16string_view FirstGrapheme(std::u16string_view str) { |
| base::i18n::BreakIterator iter(str, |
| base::i18n::BreakIterator::BREAK_CHARACTER); |
| if (!iter.Init()) { |
| return std::u16string_view(); |
| } |
| |
| if (!iter.Advance()) { |
| return std::u16string_view(); |
| } |
| |
| return iter.GetString(); |
| } |
| |
| } // namespace |
| |
| SkBitmap GenerateBitmap(SquareSizePx output_size, |
| std::u16string_view icon_letter) { |
| gfx::ImageSkia icon_image( |
| std::make_unique<GeneratedIconImageSource>(icon_letter, 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::u16string GenerateIconLetterFromUrl(const GURL& app_url) { |
| std::string app_url_part = " "; |
| const std::string domain_and_registry = |
| net::registry_controlled_domains::GetDomainAndRegistry( |
| app_url, |
| net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); |
| |
| if (!domain_and_registry.empty()) { |
| app_url_part = domain_and_registry; |
| } else if (app_url.has_host()) { |
| app_url_part = app_url.GetHost(); |
| } |
| |
| // Translate punycode into unicode before retrieving the first letter. |
| const std::u16string string_for_display = |
| url_formatter::IDNToUnicode(app_url_part); |
| |
| return base::i18n::ToUpper(FirstGrapheme(string_for_display)); |
| } |
| |
| std::u16string GenerateIconLetterFromName(std::u16string_view app_name) { |
| CHECK(!app_name.empty()); |
| return base::i18n::ToUpper(FirstGrapheme(app_name)); |
| } |
| |
| } // namespace shortcuts |