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.
5 #include "ui/gfx/platform_font_linux.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/strings/string_piece.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "third_party/skia/include/core/SkPaint.h"
16 #include "third_party/skia/include/core/SkString.h"
17 #include "third_party/skia/include/core/SkTypeface.h"
18 #include "ui/gfx/canvas.h"
19 #include "ui/gfx/font.h"
20 #include "ui/gfx/font_list.h"
21 #include "ui/gfx/linux_font_delegate.h"
22 #include "ui/gfx/text_utils.h"
27 // The font family name which is used when a user's application font for
28 // GNOME/KDE is a non-scalable one. The name should be listed in the
29 // IsFallbackFontAllowed function in skia/ext/SkFontHost_fontconfig_direct.cpp.
30 #if defined(OS_ANDROID)
31 const char* kFallbackFontFamilyName
= "serif";
33 const char* kFallbackFontFamilyName
= "sans";
36 // The default font, used for the default constructor.
37 base::LazyInstance
<scoped_refptr
<PlatformFontLinux
>>::Leaky g_default_font
=
38 LAZY_INSTANCE_INITIALIZER
;
40 // Creates a SkTypeface for the passed-in Font::FontStyle and family. If a
41 // fallback typeface is used instead of the requested family, |family| will be
42 // updated to contain the fallback's family name.
43 skia::RefPtr
<SkTypeface
> CreateSkTypeface(int style
, std::string
* family
) {
46 int skia_style
= SkTypeface::kNormal
;
47 if (Font::BOLD
& style
)
48 skia_style
|= SkTypeface::kBold
;
49 if (Font::ITALIC
& style
)
50 skia_style
|= SkTypeface::kItalic
;
52 skia::RefPtr
<SkTypeface
> typeface
= skia::AdoptRef(SkTypeface::CreateFromName(
53 family
->c_str(), static_cast<SkTypeface::Style
>(skia_style
)));
55 // A non-scalable font such as .pcf is specified. Fall back to a default
57 typeface
= skia::AdoptRef(SkTypeface::CreateFromName(
58 kFallbackFontFamilyName
, static_cast<SkTypeface::Style
>(skia_style
)));
59 CHECK(typeface
) << "Could not find any font: " << family
<< ", "
60 << kFallbackFontFamilyName
;
61 *family
= kFallbackFontFamilyName
;
68 #if defined(OS_CHROMEOS)
69 std::string
* PlatformFontLinux::default_font_description_
= NULL
;
72 ////////////////////////////////////////////////////////////////////////////////
73 // PlatformFontLinux, public:
75 PlatformFontLinux::PlatformFontLinux() {
76 if (!g_default_font
.Get()) {
77 std::string family
= kFallbackFontFamilyName
;
79 int style
= Font::NORMAL
;
80 FontRenderParams params
;
82 #if defined(OS_CHROMEOS)
83 // On Chrome OS, a FontList font description string is stored as a
84 // translatable resource and passed in via SetDefaultFontDescription().
85 if (default_font_description_
) {
86 FontRenderParamsQuery query
;
87 CHECK(FontList::ParseDescription(*default_font_description_
,
88 &query
.families
, &query
.style
,
90 << "Failed to parse font description " << *default_font_description_
;
91 params
= gfx::GetFontRenderParams(query
, &family
);
92 size_pixels
= query
.pixel_size
;
96 // On Linux, LinuxFontDelegate is used to query the native toolkit (e.g.
97 // GTK+) for the default UI font.
98 const LinuxFontDelegate
* delegate
= LinuxFontDelegate::instance();
100 delegate
->GetDefaultFontDescription(
101 &family
, &size_pixels
, &style
, ¶ms
);
105 g_default_font
.Get() = new PlatformFontLinux(
106 CreateSkTypeface(style
, &family
), family
, size_pixels
, style
, params
);
109 InitFromPlatformFont(g_default_font
.Get().get());
112 PlatformFontLinux::PlatformFontLinux(const std::string
& font_name
,
113 int font_size_pixels
) {
114 FontRenderParamsQuery query
;
115 query
.families
.push_back(font_name
);
116 query
.pixel_size
= font_size_pixels
;
117 query
.style
= Font::NORMAL
;
118 InitFromDetails(skia::RefPtr
<SkTypeface
>(), font_name
, font_size_pixels
,
119 query
.style
, gfx::GetFontRenderParams(query
, NULL
));
122 ////////////////////////////////////////////////////////////////////////////////
123 // PlatformFontLinux, PlatformFont implementation:
126 void PlatformFontLinux::ReloadDefaultFont() {
127 // Reset the scoped_refptr.
128 g_default_font
.Get() = nullptr;
131 #if defined(OS_CHROMEOS)
133 void PlatformFontLinux::SetDefaultFontDescription(
134 const std::string
& font_description
) {
135 delete default_font_description_
;
136 default_font_description_
= new std::string(font_description
);
141 Font
PlatformFontLinux::DeriveFont(int size_delta
, int style
) const {
142 const int new_size
= font_size_pixels_
+ size_delta
;
143 DCHECK_GT(new_size
, 0);
145 // If the style changed, we may need to load a new face.
146 std::string new_family
= font_family_
;
147 skia::RefPtr
<SkTypeface
> typeface
=
148 (style
== style_
) ? typeface_
: CreateSkTypeface(style
, &new_family
);
150 FontRenderParamsQuery query
;
151 query
.families
.push_back(new_family
);
152 query
.pixel_size
= new_size
;
155 return Font(new PlatformFontLinux(typeface
, new_family
, new_size
, style
,
156 gfx::GetFontRenderParams(query
, NULL
)));
159 int PlatformFontLinux::GetHeight() const {
160 return height_pixels_
;
163 int PlatformFontLinux::GetBaseline() const {
164 return ascent_pixels_
;
167 int PlatformFontLinux::GetCapHeight() const {
168 return cap_height_pixels_
;
171 int PlatformFontLinux::GetExpectedTextWidth(int length
) const {
172 return round(static_cast<float>(length
) * average_width_pixels_
);
175 int PlatformFontLinux::GetStyle() const {
179 std::string
PlatformFontLinux::GetFontName() const {
183 std::string
PlatformFontLinux::GetActualFontNameForTesting() const {
184 SkString family_name
;
185 typeface_
->getFamilyName(&family_name
);
186 return family_name
.c_str();
189 int PlatformFontLinux::GetFontSize() const {
190 return font_size_pixels_
;
193 const FontRenderParams
& PlatformFontLinux::GetFontRenderParams() {
194 #if defined(OS_CHROMEOS)
195 float current_scale_factor
= GetFontRenderParamsDeviceScaleFactor();
196 if (current_scale_factor
!= device_scale_factor_
) {
197 FontRenderParamsQuery query
;
198 query
.families
.push_back(font_family_
);
199 query
.pixel_size
= font_size_pixels_
;
200 query
.style
= style_
;
201 query
.device_scale_factor
= current_scale_factor
;
202 font_render_params_
= gfx::GetFontRenderParams(query
, nullptr);
203 device_scale_factor_
= current_scale_factor
;
206 return font_render_params_
;
209 ////////////////////////////////////////////////////////////////////////////////
210 // PlatformFontLinux, private:
212 PlatformFontLinux::PlatformFontLinux(const skia::RefPtr
<SkTypeface
>& typeface
,
213 const std::string
& family
,
216 const FontRenderParams
& render_params
) {
217 InitFromDetails(typeface
, family
, size_pixels
, style
, render_params
);
220 PlatformFontLinux::~PlatformFontLinux() {}
222 void PlatformFontLinux::InitFromDetails(
223 const skia::RefPtr
<SkTypeface
>& typeface
,
224 const std::string
& font_family
,
225 int font_size_pixels
,
227 const FontRenderParams
& render_params
) {
228 DCHECK_GT(font_size_pixels
, 0);
230 font_family_
= font_family
;
231 typeface_
= typeface
? typeface
: CreateSkTypeface(style
, &font_family_
);
233 font_size_pixels_
= font_size_pixels
;
235 #if defined(OS_CHROMEOS)
236 device_scale_factor_
= GetFontRenderParamsDeviceScaleFactor();
238 font_render_params_
= render_params
;
241 paint
.setAntiAlias(false);
242 paint
.setSubpixelText(false);
243 paint
.setTextSize(font_size_pixels_
);
244 paint
.setTypeface(typeface_
.get());
245 paint
.setFakeBoldText((Font::BOLD
& style_
) && !typeface_
->isBold());
246 paint
.setTextSkewX((Font::ITALIC
& style_
) && !typeface_
->isItalic() ?
248 SkPaint::FontMetrics metrics
;
249 paint
.getFontMetrics(&metrics
);
250 ascent_pixels_
= SkScalarCeilToInt(-metrics
.fAscent
);
251 height_pixels_
= ascent_pixels_
+ SkScalarCeilToInt(metrics
.fDescent
);
252 cap_height_pixels_
= SkScalarCeilToInt(metrics
.fCapHeight
);
253 average_width_pixels_
= SkScalarToDouble(metrics
.fAvgCharWidth
);
256 void PlatformFontLinux::InitFromPlatformFont(const PlatformFontLinux
* other
) {
257 typeface_
= other
->typeface_
;
258 font_family_
= other
->font_family_
;
259 font_size_pixels_
= other
->font_size_pixels_
;
260 style_
= other
->style_
;
261 #if defined(OS_CHROMEOS)
262 device_scale_factor_
= other
->device_scale_factor_
;
264 font_render_params_
= other
->font_render_params_
;
265 ascent_pixels_
= other
->ascent_pixels_
;
266 height_pixels_
= other
->height_pixels_
;
267 cap_height_pixels_
= other
->cap_height_pixels_
;
268 average_width_pixels_
= other
->average_width_pixels_
;
271 ////////////////////////////////////////////////////////////////////////////////
272 // PlatformFont, public:
275 PlatformFont
* PlatformFont::CreateDefault() {
276 return new PlatformFontLinux
;
280 PlatformFont
* PlatformFont::CreateFromNameAndSize(const std::string
& font_name
,
282 return new PlatformFontLinux(font_name
, font_size
);