platform_font_skia.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/gfx/platform_font_skia.h"
  5. #include <algorithm>
  6. #include <string>
  7. #include "base/lazy_instance.h"
  8. #include "base/logging.h"
  9. #include "base/strings/string_piece.h"
  10. #include "base/strings/string_split.h"
  11. #include "base/strings/utf_string_conversions.h"
  12. #include "base/trace_event/trace_event.h"
  13. #include "build/build_config.h"
  14. #include "third_party/skia/include/core/SkFont.h"
  15. #include "third_party/skia/include/core/SkFontMetrics.h"
  16. #include "third_party/skia/include/core/SkFontStyle.h"
  17. #include "third_party/skia/include/core/SkString.h"
  18. #include "ui/gfx/canvas.h"
  19. #include "ui/gfx/font.h"
  20. #include "ui/gfx/font_list.h"
  21. #include "ui/gfx/font_render_params.h"
  22. #include "ui/gfx/text_utils.h"
  23. #if BUILDFLAG(IS_WIN)
  24. #include "ui/gfx/system_fonts_win.h"
  25. #endif
  26. #if BUILDFLAG(IS_LINUX)
  27. #include "ui/linux/linux_ui.h"
  28. #endif
  29. namespace gfx {
  30. namespace {
  31. // The font family name which is used when a user's application font for
  32. // GNOME/KDE is a non-scalable one. The name should be listed in the
  33. // IsFallbackFontAllowed function in skia/ext/SkFontHost_fontconfig_direct.cpp.
  34. #if BUILDFLAG(IS_ANDROID)
  35. const char kFallbackFontFamilyName[] = "serif";
  36. #else
  37. const char kFallbackFontFamilyName[] = "sans";
  38. #endif
  39. constexpr SkGlyphID kUnsupportedGlyph = 0;
  40. // The default font, used for the default constructor.
  41. base::LazyInstance<scoped_refptr<PlatformFontSkia>>::Leaky g_default_font =
  42. LAZY_INSTANCE_INITIALIZER;
  43. // Creates a SkTypeface for the passed-in Font::FontStyle and family. If a
  44. // fallback typeface is used instead of the requested family, |family| will be
  45. // updated to contain the fallback's family name.
  46. sk_sp<SkTypeface> CreateSkTypeface(bool italic,
  47. gfx::Font::Weight weight,
  48. std::string* family,
  49. bool* out_success) {
  50. DCHECK(family);
  51. TRACE_EVENT0("fonts", "gfx::CreateSkTypeface");
  52. const int font_weight = (weight == Font::Weight::INVALID)
  53. ? static_cast<int>(Font::Weight::NORMAL)
  54. : static_cast<int>(weight);
  55. SkFontStyle sk_style(
  56. font_weight, SkFontStyle::kNormal_Width,
  57. italic ? SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
  58. sk_sp<SkTypeface> typeface;
  59. {
  60. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("fonts"), "SkTypeface::MakeFromName",
  61. "family", *family);
  62. typeface = SkTypeface::MakeFromName(family->c_str(), sk_style);
  63. }
  64. if (!typeface) {
  65. TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("fonts"), "SkTypeface::MakeFromName",
  66. "family", kFallbackFontFamilyName);
  67. // A non-scalable font such as .pcf is specified. Fall back to a default
  68. // scalable font.
  69. typeface = sk_sp<SkTypeface>(
  70. SkTypeface::MakeFromName(kFallbackFontFamilyName, sk_style));
  71. if (!typeface) {
  72. *out_success = false;
  73. return nullptr;
  74. }
  75. *family = kFallbackFontFamilyName;
  76. }
  77. *out_success = true;
  78. return typeface;
  79. }
  80. } // namespace
  81. std::string* PlatformFontSkia::default_font_description_ = NULL;
  82. ////////////////////////////////////////////////////////////////////////////////
  83. // PlatformFontSkia, public:
  84. PlatformFontSkia::PlatformFontSkia() {
  85. EnsuresDefaultFontIsInitialized();
  86. InitFromPlatformFont(g_default_font.Get().get());
  87. }
  88. PlatformFontSkia::PlatformFontSkia(const std::string& font_name,
  89. int font_size_pixels) {
  90. FontRenderParamsQuery query;
  91. query.families.push_back(font_name);
  92. query.pixel_size = font_size_pixels;
  93. query.weight = Font::Weight::NORMAL;
  94. InitFromDetails(nullptr, font_name, font_size_pixels, Font::NORMAL,
  95. query.weight, gfx::GetFontRenderParams(query, nullptr));
  96. }
  97. PlatformFontSkia::PlatformFontSkia(
  98. sk_sp<SkTypeface> typeface,
  99. int font_size_pixels,
  100. const absl::optional<FontRenderParams>& params) {
  101. DCHECK(typeface);
  102. SkString family_name;
  103. typeface->getFamilyName(&family_name);
  104. SkFontStyle font_style = typeface->fontStyle();
  105. Font::Weight font_weight = FontWeightFromInt(font_style.weight());
  106. int style = typeface->isItalic() ? Font::ITALIC : Font::NORMAL;
  107. FontRenderParams actual_render_params;
  108. if (!params) {
  109. FontRenderParamsQuery query;
  110. query.families.push_back(family_name.c_str());
  111. query.pixel_size = font_size_pixels;
  112. query.weight = font_weight;
  113. actual_render_params = gfx::GetFontRenderParams(query, nullptr);
  114. } else {
  115. actual_render_params = params.value();
  116. }
  117. InitFromDetails(std::move(typeface), family_name.c_str(), font_size_pixels,
  118. style, font_weight, actual_render_params);
  119. }
  120. ////////////////////////////////////////////////////////////////////////////////
  121. // PlatformFontSkia, PlatformFont implementation:
  122. // static
  123. void PlatformFontSkia::EnsuresDefaultFontIsInitialized() {
  124. if (g_default_font.Get())
  125. return;
  126. std::string family = kFallbackFontFamilyName;
  127. int size_pixels = PlatformFont::kDefaultBaseFontSize;
  128. int style = Font::NORMAL;
  129. Font::Weight weight = Font::Weight::NORMAL;
  130. FontRenderParams params;
  131. #if BUILDFLAG(IS_WIN)
  132. // On windows, the system default font is retrieved by using the GDI API
  133. // SystemParametersInfo(...) (see struct NONCLIENTMETRICS). The font
  134. // properties need to be converted as close as possible to a skia font.
  135. // The style must be kept (see http://crbug/989476).
  136. gfx::Font system_font = win::GetDefaultSystemFont();
  137. family = system_font.GetFontName();
  138. size_pixels = system_font.GetFontSize();
  139. style = system_font.GetStyle();
  140. weight = system_font.GetWeight();
  141. #endif // BUILDFLAG(IS_WIN)
  142. #if BUILDFLAG(IS_LINUX)
  143. // On Linux, LinuxUi is used to query the native toolkit (e.g.
  144. // GTK) for the default UI font.
  145. if (const auto* linux_ui = ui::LinuxUi::instance()) {
  146. int weight_int;
  147. linux_ui->GetDefaultFontDescription(
  148. &family, &size_pixels, &style, static_cast<int*>(&weight_int), &params);
  149. weight = static_cast<Font::Weight>(weight_int);
  150. } else
  151. #endif
  152. if (default_font_description_) {
  153. #if BUILDFLAG(IS_CHROMEOS)
  154. // On ChromeOS, a FontList font description string is stored as a
  155. // translatable resource and passed in via SetDefaultFontDescription().
  156. FontRenderParamsQuery query;
  157. CHECK(FontList::ParseDescription(*default_font_description_,
  158. &query.families, &query.style,
  159. &query.pixel_size, &query.weight))
  160. << "Failed to parse font description " << *default_font_description_;
  161. params = gfx::GetFontRenderParams(query, &family);
  162. size_pixels = query.pixel_size;
  163. style = query.style;
  164. weight = query.weight;
  165. #else
  166. NOTREACHED();
  167. #endif
  168. } else {
  169. params = gfx::GetFontRenderParams(FontRenderParamsQuery(), nullptr);
  170. }
  171. bool success = false;
  172. sk_sp<SkTypeface> typeface =
  173. CreateSkTypeface(style & Font::ITALIC, weight, &family, &success);
  174. // It's possible that the Skia interface is not longer able to proxy queries
  175. // to the browser process which make all requests to fail. Calling
  176. // MakeDefault() will try to get the default typeface; in case of failure it
  177. // returns an instance of SkEmptyTypeface. MakeDefault() should never fail.
  178. // See https://crbug.com/1287371 for details.
  179. if (!success) {
  180. typeface = SkTypeface::MakeDefault();
  181. }
  182. // Ensure there is a typeface available. If none is available, there is
  183. // nothing we can do about it and Chrome won't be able to work.
  184. CHECK(typeface.get()) << "No typeface available";
  185. g_default_font.Get() = new PlatformFontSkia(
  186. std::move(typeface), family, size_pixels, style, weight, params);
  187. }
  188. // static
  189. void PlatformFontSkia::ReloadDefaultFont() {
  190. // Reset the scoped_refptr.
  191. g_default_font.Get() = nullptr;
  192. }
  193. // static
  194. void PlatformFontSkia::SetDefaultFontDescription(
  195. const std::string& font_description) {
  196. delete default_font_description_;
  197. default_font_description_ = new std::string(font_description);
  198. }
  199. Font PlatformFontSkia::DeriveFont(int size_delta,
  200. int style,
  201. Font::Weight weight) const {
  202. #if BUILDFLAG(IS_WIN)
  203. const int new_size = win::AdjustFontSize(font_size_pixels_, size_delta);
  204. #else
  205. const int new_size = font_size_pixels_ + size_delta;
  206. #endif
  207. DCHECK_GT(new_size, 0);
  208. // If the style changed, we may need to load a new face.
  209. std::string new_family = font_family_;
  210. bool success = true;
  211. sk_sp<SkTypeface> typeface =
  212. (weight == weight_ && style == style_)
  213. ? typeface_
  214. : CreateSkTypeface(style, weight, &new_family, &success);
  215. if (!success) {
  216. LOG(ERROR) << "Could not find any font: " << new_family << ", "
  217. << kFallbackFontFamilyName << ". Falling back to the default";
  218. return Font(new PlatformFontSkia);
  219. }
  220. FontRenderParamsQuery query;
  221. query.families.push_back(new_family);
  222. query.pixel_size = new_size;
  223. query.style = style;
  224. return Font(new PlatformFontSkia(std::move(typeface), new_family, new_size,
  225. style, weight,
  226. gfx::GetFontRenderParams(query, NULL)));
  227. }
  228. int PlatformFontSkia::GetHeight() {
  229. ComputeMetricsIfNecessary();
  230. return height_pixels_;
  231. }
  232. Font::Weight PlatformFontSkia::GetWeight() const {
  233. return weight_;
  234. }
  235. int PlatformFontSkia::GetBaseline() {
  236. ComputeMetricsIfNecessary();
  237. return ascent_pixels_;
  238. }
  239. int PlatformFontSkia::GetCapHeight() {
  240. ComputeMetricsIfNecessary();
  241. return cap_height_pixels_;
  242. }
  243. int PlatformFontSkia::GetExpectedTextWidth(int length) {
  244. ComputeMetricsIfNecessary();
  245. return round(static_cast<float>(length) * average_width_pixels_);
  246. }
  247. int PlatformFontSkia::GetStyle() const {
  248. return style_;
  249. }
  250. const std::string& PlatformFontSkia::GetFontName() const {
  251. return font_family_;
  252. }
  253. std::string PlatformFontSkia::GetActualFontName() const {
  254. SkString family_name;
  255. typeface_->getFamilyName(&family_name);
  256. return family_name.c_str();
  257. }
  258. int PlatformFontSkia::GetFontSize() const {
  259. return font_size_pixels_;
  260. }
  261. const FontRenderParams& PlatformFontSkia::GetFontRenderParams() {
  262. TRACE_EVENT0("fonts", "PlatformFontSkia::GetFontRenderParams");
  263. float current_scale_factor = GetFontRenderParamsDeviceScaleFactor();
  264. if (current_scale_factor != device_scale_factor_) {
  265. FontRenderParamsQuery query;
  266. query.families.push_back(font_family_);
  267. query.pixel_size = font_size_pixels_;
  268. query.style = style_;
  269. query.weight = weight_;
  270. query.device_scale_factor = current_scale_factor;
  271. font_render_params_ = gfx::GetFontRenderParams(query, nullptr);
  272. device_scale_factor_ = current_scale_factor;
  273. }
  274. return font_render_params_;
  275. }
  276. sk_sp<SkTypeface> PlatformFontSkia::GetNativeSkTypeface() const {
  277. DCHECK(typeface_);
  278. return sk_sp<SkTypeface>(typeface_);
  279. }
  280. ////////////////////////////////////////////////////////////////////////////////
  281. // PlatformFontSkia, private:
  282. PlatformFontSkia::PlatformFontSkia(sk_sp<SkTypeface> typeface,
  283. const std::string& family,
  284. int size_pixels,
  285. int style,
  286. Font::Weight weight,
  287. const FontRenderParams& render_params) {
  288. InitFromDetails(std::move(typeface), family, size_pixels, style, weight,
  289. render_params);
  290. }
  291. PlatformFontSkia::~PlatformFontSkia() {}
  292. void PlatformFontSkia::InitFromDetails(sk_sp<SkTypeface> typeface,
  293. const std::string& font_family,
  294. int font_size_pixels,
  295. int style,
  296. Font::Weight weight,
  297. const FontRenderParams& render_params) {
  298. TRACE_EVENT0("fonts", "PlatformFontSkia::InitFromDetails");
  299. DCHECK_GT(font_size_pixels, 0);
  300. font_family_ = font_family;
  301. bool success = true;
  302. typeface_ = typeface ? std::move(typeface)
  303. : CreateSkTypeface(style & Font::ITALIC, weight,
  304. &font_family_, &success);
  305. if (!success) {
  306. EnsuresDefaultFontIsInitialized();
  307. InitFromPlatformFont(g_default_font.Get().get());
  308. return;
  309. }
  310. font_size_pixels_ = font_size_pixels;
  311. style_ = style;
  312. weight_ = weight;
  313. device_scale_factor_ = GetFontRenderParamsDeviceScaleFactor();
  314. font_render_params_ = render_params;
  315. }
  316. void PlatformFontSkia::InitFromPlatformFont(const PlatformFontSkia* other) {
  317. TRACE_EVENT0("fonts", "PlatformFontSkia::InitFromPlatformFont");
  318. typeface_ = other->typeface_;
  319. font_family_ = other->font_family_;
  320. font_size_pixels_ = other->font_size_pixels_;
  321. style_ = other->style_;
  322. weight_ = other->weight_;
  323. device_scale_factor_ = other->device_scale_factor_;
  324. font_render_params_ = other->font_render_params_;
  325. if (!other->metrics_need_computation_) {
  326. metrics_need_computation_ = false;
  327. ascent_pixels_ = other->ascent_pixels_;
  328. height_pixels_ = other->height_pixels_;
  329. cap_height_pixels_ = other->cap_height_pixels_;
  330. average_width_pixels_ = other->average_width_pixels_;
  331. }
  332. }
  333. void PlatformFontSkia::ComputeMetricsIfNecessary() {
  334. if (metrics_need_computation_) {
  335. TRACE_EVENT0("fonts", "PlatformFontSkia::ComputeMetricsIfNecessary");
  336. metrics_need_computation_ = false;
  337. SkFont font(typeface_, font_size_pixels_);
  338. const FontRenderParams& params = GetFontRenderParams();
  339. if (!params.antialiasing) {
  340. font.setEdging(SkFont::Edging::kAlias);
  341. } else if (params.subpixel_rendering ==
  342. FontRenderParams::SUBPIXEL_RENDERING_NONE) {
  343. font.setEdging(SkFont::Edging::kAntiAlias);
  344. } else {
  345. font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
  346. }
  347. font.setEmbolden(weight_ >= Font::Weight::BOLD && !typeface_->isBold());
  348. font.setSkewX((Font::ITALIC & style_) && !typeface_->isItalic()
  349. ? -SK_Scalar1 / 4
  350. : 0);
  351. SkFontMetrics metrics;
  352. font.getMetrics(&metrics);
  353. ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent);
  354. cap_height_pixels_ = SkScalarCeilToInt(metrics.fCapHeight);
  355. // There is a mismatch between the way the PlatformFontWin was computing the
  356. // font height in pixel. The font height may vary by one pixel due to
  357. // decimal rounding.
  358. // Windows Skia implements : ceil(descent - ascent)
  359. // Linux Skia implements : ceil(-ascent) + ceil(descent)
  360. // TODO(etienneb): Make both implementation consistent and fix the broken
  361. // unittests.
  362. #if BUILDFLAG(IS_WIN)
  363. height_pixels_ = SkScalarCeilToInt(metrics.fDescent - metrics.fAscent);
  364. #else
  365. height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent);
  366. #endif
  367. if (metrics.fAvgCharWidth) {
  368. average_width_pixels_ = SkScalarToDouble(metrics.fAvgCharWidth);
  369. } else {
  370. // Some Skia fonts manager do not compute the average character size
  371. // (e.g. Direct Write). The following code computes the average character
  372. // width the same way Blink (e.g. SimpleFontData) does. Use the width of
  373. // the letter 'x' when available, otherwise use the max character width.
  374. SkGlyphID glyph = typeface_->unicharToGlyph('x');
  375. if (glyph != kUnsupportedGlyph) {
  376. SkScalar sk_width;
  377. font.getWidths(&glyph, 1, &sk_width);
  378. average_width_pixels_ = SkScalarToDouble(sk_width);
  379. }
  380. if (!average_width_pixels_) {
  381. if (metrics.fMaxCharWidth) {
  382. average_width_pixels_ = SkScalarToDouble(metrics.fMaxCharWidth);
  383. } else {
  384. // Older version of the DirectWrite API doesn't implement support for
  385. // max char width. Fall back on a multiple of the ascent. This is
  386. // entirely arbitrary but comes pretty close to the expected value in
  387. // most cases.
  388. average_width_pixels_ = ascent_pixels_ * 2;
  389. }
  390. }
  391. }
  392. DCHECK_NE(average_width_pixels_, 0);
  393. }
  394. }
  395. ////////////////////////////////////////////////////////////////////////////////
  396. // PlatformFont, public:
  397. // static
  398. PlatformFont* PlatformFont::CreateDefault() {
  399. return new PlatformFontSkia;
  400. }
  401. // static
  402. PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
  403. int font_size) {
  404. TRACE_EVENT0("fonts", "PlatformFont::CreateFromNameAndSize");
  405. return new PlatformFontSkia(font_name, font_size);
  406. }
  407. // static
  408. PlatformFont* PlatformFont::CreateFromSkTypeface(
  409. sk_sp<SkTypeface> typeface,
  410. int font_size_pixels,
  411. const absl::optional<FontRenderParams>& params) {
  412. TRACE_EVENT0("fonts", "PlatformFont::CreateFromSkTypeface");
  413. return new PlatformFontSkia(typeface, font_size_pixels, params);
  414. }
  415. } // namespace gfx