123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- // Copyright (c) 2012 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 "ui/gfx/platform_font_skia.h"
- #include <algorithm>
- #include <string>
- #include "base/lazy_instance.h"
- #include "base/logging.h"
- #include "base/strings/string_piece.h"
- #include "base/strings/string_split.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/trace_event/trace_event.h"
- #include "build/build_config.h"
- #include "third_party/skia/include/core/SkFont.h"
- #include "third_party/skia/include/core/SkFontMetrics.h"
- #include "third_party/skia/include/core/SkFontStyle.h"
- #include "third_party/skia/include/core/SkString.h"
- #include "ui/gfx/canvas.h"
- #include "ui/gfx/font.h"
- #include "ui/gfx/font_list.h"
- #include "ui/gfx/font_render_params.h"
- #include "ui/gfx/text_utils.h"
- #if BUILDFLAG(IS_WIN)
- #include "ui/gfx/system_fonts_win.h"
- #endif
- #if BUILDFLAG(IS_LINUX)
- #include "ui/linux/linux_ui.h"
- #endif
- namespace gfx {
- namespace {
- // The font family name which is used when a user's application font for
- // GNOME/KDE is a non-scalable one. The name should be listed in the
- // IsFallbackFontAllowed function in skia/ext/SkFontHost_fontconfig_direct.cpp.
- #if BUILDFLAG(IS_ANDROID)
- const char kFallbackFontFamilyName[] = "serif";
- #else
- const char kFallbackFontFamilyName[] = "sans";
- #endif
- constexpr SkGlyphID kUnsupportedGlyph = 0;
- // The default font, used for the default constructor.
- base::LazyInstance<scoped_refptr<PlatformFontSkia>>::Leaky g_default_font =
- LAZY_INSTANCE_INITIALIZER;
- // Creates a SkTypeface for the passed-in Font::FontStyle and family. If a
- // fallback typeface is used instead of the requested family, |family| will be
- // updated to contain the fallback's family name.
- sk_sp<SkTypeface> CreateSkTypeface(bool italic,
- gfx::Font::Weight weight,
- std::string* family,
- bool* out_success) {
- DCHECK(family);
- TRACE_EVENT0("fonts", "gfx::CreateSkTypeface");
- const int font_weight = (weight == Font::Weight::INVALID)
- ? static_cast<int>(Font::Weight::NORMAL)
- : static_cast<int>(weight);
- SkFontStyle sk_style(
- font_weight, SkFontStyle::kNormal_Width,
- italic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
- sk_sp<SkTypeface> typeface;
- {
- TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("fonts"), "SkTypeface::MakeFromName",
- "family", *family);
- typeface = SkTypeface::MakeFromName(family->c_str(), sk_style);
- }
- if (!typeface) {
- TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("fonts"), "SkTypeface::MakeFromName",
- "family", kFallbackFontFamilyName);
- // A non-scalable font such as .pcf is specified. Fall back to a default
- // scalable font.
- typeface = sk_sp<SkTypeface>(
- SkTypeface::MakeFromName(kFallbackFontFamilyName, sk_style));
- if (!typeface) {
- *out_success = false;
- return nullptr;
- }
- *family = kFallbackFontFamilyName;
- }
- *out_success = true;
- return typeface;
- }
- } // namespace
- std::string* PlatformFontSkia::default_font_description_ = NULL;
- ////////////////////////////////////////////////////////////////////////////////
- // PlatformFontSkia, public:
- PlatformFontSkia::PlatformFontSkia() {
- EnsuresDefaultFontIsInitialized();
- InitFromPlatformFont(g_default_font.Get().get());
- }
- PlatformFontSkia::PlatformFontSkia(const std::string& font_name,
- int font_size_pixels) {
- FontRenderParamsQuery query;
- query.families.push_back(font_name);
- query.pixel_size = font_size_pixels;
- query.weight = Font::Weight::NORMAL;
- InitFromDetails(nullptr, font_name, font_size_pixels, Font::NORMAL,
- query.weight, gfx::GetFontRenderParams(query, nullptr));
- }
- PlatformFontSkia::PlatformFontSkia(
- sk_sp<SkTypeface> typeface,
- int font_size_pixels,
- const absl::optional<FontRenderParams>& params) {
- DCHECK(typeface);
- SkString family_name;
- typeface->getFamilyName(&family_name);
- SkFontStyle font_style = typeface->fontStyle();
- Font::Weight font_weight = FontWeightFromInt(font_style.weight());
- int style = typeface->isItalic() ? Font::ITALIC : Font::NORMAL;
- FontRenderParams actual_render_params;
- if (!params) {
- FontRenderParamsQuery query;
- query.families.push_back(family_name.c_str());
- query.pixel_size = font_size_pixels;
- query.weight = font_weight;
- actual_render_params = gfx::GetFontRenderParams(query, nullptr);
- } else {
- actual_render_params = params.value();
- }
- InitFromDetails(std::move(typeface), family_name.c_str(), font_size_pixels,
- style, font_weight, actual_render_params);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // PlatformFontSkia, PlatformFont implementation:
- // static
- void PlatformFontSkia::EnsuresDefaultFontIsInitialized() {
- if (g_default_font.Get())
- return;
- std::string family = kFallbackFontFamilyName;
- int size_pixels = PlatformFont::kDefaultBaseFontSize;
- int style = Font::NORMAL;
- Font::Weight weight = Font::Weight::NORMAL;
- FontRenderParams params;
- #if BUILDFLAG(IS_WIN)
- // On windows, the system default font is retrieved by using the GDI API
- // SystemParametersInfo(...) (see struct NONCLIENTMETRICS). The font
- // properties need to be converted as close as possible to a skia font.
- // The style must be kept (see http://crbug/989476).
- gfx::Font system_font = win::GetDefaultSystemFont();
- family = system_font.GetFontName();
- size_pixels = system_font.GetFontSize();
- style = system_font.GetStyle();
- weight = system_font.GetWeight();
- #endif // BUILDFLAG(IS_WIN)
- #if BUILDFLAG(IS_LINUX)
- // On Linux, LinuxUi is used to query the native toolkit (e.g.
- // GTK) for the default UI font.
- if (const auto* linux_ui = ui::LinuxUi::instance()) {
- int weight_int;
- linux_ui->GetDefaultFontDescription(
- &family, &size_pixels, &style, static_cast<int*>(&weight_int), ¶ms);
- weight = static_cast<Font::Weight>(weight_int);
- } else
- #endif
- if (default_font_description_) {
- #if BUILDFLAG(IS_CHROMEOS)
- // On ChromeOS, a FontList font description string is stored as a
- // translatable resource and passed in via SetDefaultFontDescription().
- FontRenderParamsQuery query;
- CHECK(FontList::ParseDescription(*default_font_description_,
- &query.families, &query.style,
- &query.pixel_size, &query.weight))
- << "Failed to parse font description " << *default_font_description_;
- params = gfx::GetFontRenderParams(query, &family);
- size_pixels = query.pixel_size;
- style = query.style;
- weight = query.weight;
- #else
- NOTREACHED();
- #endif
- } else {
- params = gfx::GetFontRenderParams(FontRenderParamsQuery(), nullptr);
- }
- bool success = false;
- sk_sp<SkTypeface> typeface =
- CreateSkTypeface(style & Font::ITALIC, weight, &family, &success);
- // It's possible that the Skia interface is not longer able to proxy queries
- // to the browser process which make all requests to fail. Calling
- // MakeDefault() will try to get the default typeface; in case of failure it
- // returns an instance of SkEmptyTypeface. MakeDefault() should never fail.
- // See https://crbug.com/1287371 for details.
- if (!success) {
- typeface = SkTypeface::MakeDefault();
- }
- // Ensure there is a typeface available. If none is available, there is
- // nothing we can do about it and Chrome won't be able to work.
- CHECK(typeface.get()) << "No typeface available";
- g_default_font.Get() = new PlatformFontSkia(
- std::move(typeface), family, size_pixels, style, weight, params);
- }
- // static
- void PlatformFontSkia::ReloadDefaultFont() {
- // Reset the scoped_refptr.
- g_default_font.Get() = nullptr;
- }
- // static
- void PlatformFontSkia::SetDefaultFontDescription(
- const std::string& font_description) {
- delete default_font_description_;
- default_font_description_ = new std::string(font_description);
- }
- Font PlatformFontSkia::DeriveFont(int size_delta,
- int style,
- Font::Weight weight) const {
- #if BUILDFLAG(IS_WIN)
- const int new_size = win::AdjustFontSize(font_size_pixels_, size_delta);
- #else
- const int new_size = font_size_pixels_ + size_delta;
- #endif
- DCHECK_GT(new_size, 0);
- // If the style changed, we may need to load a new face.
- std::string new_family = font_family_;
- bool success = true;
- sk_sp<SkTypeface> typeface =
- (weight == weight_ && style == style_)
- ? typeface_
- : CreateSkTypeface(style, weight, &new_family, &success);
- if (!success) {
- LOG(ERROR) << "Could not find any font: " << new_family << ", "
- << kFallbackFontFamilyName << ". Falling back to the default";
- return Font(new PlatformFontSkia);
- }
- FontRenderParamsQuery query;
- query.families.push_back(new_family);
- query.pixel_size = new_size;
- query.style = style;
- return Font(new PlatformFontSkia(std::move(typeface), new_family, new_size,
- style, weight,
- gfx::GetFontRenderParams(query, NULL)));
- }
- int PlatformFontSkia::GetHeight() {
- ComputeMetricsIfNecessary();
- return height_pixels_;
- }
- Font::Weight PlatformFontSkia::GetWeight() const {
- return weight_;
- }
- int PlatformFontSkia::GetBaseline() {
- ComputeMetricsIfNecessary();
- return ascent_pixels_;
- }
- int PlatformFontSkia::GetCapHeight() {
- ComputeMetricsIfNecessary();
- return cap_height_pixels_;
- }
- int PlatformFontSkia::GetExpectedTextWidth(int length) {
- ComputeMetricsIfNecessary();
- return round(static_cast<float>(length) * average_width_pixels_);
- }
- int PlatformFontSkia::GetStyle() const {
- return style_;
- }
- const std::string& PlatformFontSkia::GetFontName() const {
- return font_family_;
- }
- std::string PlatformFontSkia::GetActualFontName() const {
- SkString family_name;
- typeface_->getFamilyName(&family_name);
- return family_name.c_str();
- }
- int PlatformFontSkia::GetFontSize() const {
- return font_size_pixels_;
- }
- const FontRenderParams& PlatformFontSkia::GetFontRenderParams() {
- TRACE_EVENT0("fonts", "PlatformFontSkia::GetFontRenderParams");
- float current_scale_factor = GetFontRenderParamsDeviceScaleFactor();
- if (current_scale_factor != device_scale_factor_) {
- FontRenderParamsQuery query;
- query.families.push_back(font_family_);
- query.pixel_size = font_size_pixels_;
- query.style = style_;
- query.weight = weight_;
- query.device_scale_factor = current_scale_factor;
- font_render_params_ = gfx::GetFontRenderParams(query, nullptr);
- device_scale_factor_ = current_scale_factor;
- }
- return font_render_params_;
- }
- sk_sp<SkTypeface> PlatformFontSkia::GetNativeSkTypeface() const {
- DCHECK(typeface_);
- return sk_sp<SkTypeface>(typeface_);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // PlatformFontSkia, private:
- PlatformFontSkia::PlatformFontSkia(sk_sp<SkTypeface> typeface,
- const std::string& family,
- int size_pixels,
- int style,
- Font::Weight weight,
- const FontRenderParams& render_params) {
- InitFromDetails(std::move(typeface), family, size_pixels, style, weight,
- render_params);
- }
- PlatformFontSkia::~PlatformFontSkia() {}
- void PlatformFontSkia::InitFromDetails(sk_sp<SkTypeface> typeface,
- const std::string& font_family,
- int font_size_pixels,
- int style,
- Font::Weight weight,
- const FontRenderParams& render_params) {
- TRACE_EVENT0("fonts", "PlatformFontSkia::InitFromDetails");
- DCHECK_GT(font_size_pixels, 0);
- font_family_ = font_family;
- bool success = true;
- typeface_ = typeface ? std::move(typeface)
- : CreateSkTypeface(style & Font::ITALIC, weight,
- &font_family_, &success);
- if (!success) {
- EnsuresDefaultFontIsInitialized();
- InitFromPlatformFont(g_default_font.Get().get());
- return;
- }
- font_size_pixels_ = font_size_pixels;
- style_ = style;
- weight_ = weight;
- device_scale_factor_ = GetFontRenderParamsDeviceScaleFactor();
- font_render_params_ = render_params;
- }
- void PlatformFontSkia::InitFromPlatformFont(const PlatformFontSkia* other) {
- TRACE_EVENT0("fonts", "PlatformFontSkia::InitFromPlatformFont");
- typeface_ = other->typeface_;
- font_family_ = other->font_family_;
- font_size_pixels_ = other->font_size_pixels_;
- style_ = other->style_;
- weight_ = other->weight_;
- device_scale_factor_ = other->device_scale_factor_;
- font_render_params_ = other->font_render_params_;
- if (!other->metrics_need_computation_) {
- metrics_need_computation_ = false;
- ascent_pixels_ = other->ascent_pixels_;
- height_pixels_ = other->height_pixels_;
- cap_height_pixels_ = other->cap_height_pixels_;
- average_width_pixels_ = other->average_width_pixels_;
- }
- }
- void PlatformFontSkia::ComputeMetricsIfNecessary() {
- if (metrics_need_computation_) {
- TRACE_EVENT0("fonts", "PlatformFontSkia::ComputeMetricsIfNecessary");
- metrics_need_computation_ = false;
- SkFont font(typeface_, font_size_pixels_);
- const FontRenderParams& params = GetFontRenderParams();
- if (!params.antialiasing) {
- font.setEdging(SkFont::Edging::kAlias);
- } else if (params.subpixel_rendering ==
- FontRenderParams::SUBPIXEL_RENDERING_NONE) {
- font.setEdging(SkFont::Edging::kAntiAlias);
- } else {
- font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
- }
- font.setEmbolden(weight_ >= Font::Weight::BOLD && !typeface_->isBold());
- font.setSkewX((Font::ITALIC & style_) && !typeface_->isItalic()
- ? -SK_Scalar1 / 4
- : 0);
- SkFontMetrics metrics;
- font.getMetrics(&metrics);
- ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent);
- cap_height_pixels_ = SkScalarCeilToInt(metrics.fCapHeight);
- // There is a mismatch between the way the PlatformFontWin was computing the
- // font height in pixel. The font height may vary by one pixel due to
- // decimal rounding.
- // Windows Skia implements : ceil(descent - ascent)
- // Linux Skia implements : ceil(-ascent) + ceil(descent)
- // TODO(etienneb): Make both implementation consistent and fix the broken
- // unittests.
- #if BUILDFLAG(IS_WIN)
- height_pixels_ = SkScalarCeilToInt(metrics.fDescent - metrics.fAscent);
- #else
- height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent);
- #endif
- if (metrics.fAvgCharWidth) {
- average_width_pixels_ = SkScalarToDouble(metrics.fAvgCharWidth);
- } else {
- // Some Skia fonts manager do not compute the average character size
- // (e.g. Direct Write). The following code computes the average character
- // width the same way Blink (e.g. SimpleFontData) does. Use the width of
- // the letter 'x' when available, otherwise use the max character width.
- SkGlyphID glyph = typeface_->unicharToGlyph('x');
- if (glyph != kUnsupportedGlyph) {
- SkScalar sk_width;
- font.getWidths(&glyph, 1, &sk_width);
- average_width_pixels_ = SkScalarToDouble(sk_width);
- }
- if (!average_width_pixels_) {
- if (metrics.fMaxCharWidth) {
- average_width_pixels_ = SkScalarToDouble(metrics.fMaxCharWidth);
- } else {
- // Older version of the DirectWrite API doesn't implement support for
- // max char width. Fall back on a multiple of the ascent. This is
- // entirely arbitrary but comes pretty close to the expected value in
- // most cases.
- average_width_pixels_ = ascent_pixels_ * 2;
- }
- }
- }
- DCHECK_NE(average_width_pixels_, 0);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // PlatformFont, public:
- // static
- PlatformFont* PlatformFont::CreateDefault() {
- return new PlatformFontSkia;
- }
- // static
- PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
- int font_size) {
- TRACE_EVENT0("fonts", "PlatformFont::CreateFromNameAndSize");
- return new PlatformFontSkia(font_name, font_size);
- }
- // static
- PlatformFont* PlatformFont::CreateFromSkTypeface(
- sk_sp<SkTypeface> typeface,
- int font_size_pixels,
- const absl::optional<FontRenderParams>& params) {
- TRACE_EVENT0("fonts", "PlatformFont::CreateFromSkTypeface");
- return new PlatformFontSkia(typeface, font_size_pixels, params);
- }
- } // namespace gfx
|