Fix search results being clipped in app list.
[chromium-blink-merge.git] / ui / gfx / platform_font_linux.cc
blob9aeaaa079f5acc4ead085c15b079c7ee7104b0f1
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"
7 #include <algorithm>
8 #include <string>
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"
24 namespace gfx {
25 namespace {
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 const char* kFallbackFontFamilyName = "sans";
32 // The default font, used for the default constructor.
33 base::LazyInstance<scoped_refptr<PlatformFontLinux>>::Leaky g_default_font =
34 LAZY_INSTANCE_INITIALIZER;
36 // Creates a SkTypeface for the passed-in Font::FontStyle and family. If a
37 // fallback typeface is used instead of the requested family, |family| will be
38 // updated to contain the fallback's family name.
39 skia::RefPtr<SkTypeface> CreateSkTypeface(int style, std::string* family) {
40 DCHECK(family);
42 int skia_style = SkTypeface::kNormal;
43 if (Font::BOLD & style)
44 skia_style |= SkTypeface::kBold;
45 if (Font::ITALIC & style)
46 skia_style |= SkTypeface::kItalic;
48 skia::RefPtr<SkTypeface> typeface = skia::AdoptRef(SkTypeface::CreateFromName(
49 family->c_str(), static_cast<SkTypeface::Style>(skia_style)));
50 if (!typeface) {
51 // A non-scalable font such as .pcf is specified. Fall back to a default
52 // scalable font.
53 typeface = skia::AdoptRef(SkTypeface::CreateFromName(
54 kFallbackFontFamilyName, static_cast<SkTypeface::Style>(skia_style)));
55 CHECK(typeface) << "Could not find any font: " << family << ", "
56 << kFallbackFontFamilyName;
57 *family = kFallbackFontFamilyName;
59 return typeface;
62 } // namespace
64 #if defined(OS_CHROMEOS)
65 std::string* PlatformFontLinux::default_font_description_ = NULL;
66 #endif
68 ////////////////////////////////////////////////////////////////////////////////
69 // PlatformFontLinux, public:
71 PlatformFontLinux::PlatformFontLinux() {
72 if (!g_default_font.Get()) {
73 std::string family = kFallbackFontFamilyName;
74 int size_pixels = 12;
75 int style = Font::NORMAL;
76 FontRenderParams params;
78 #if defined(OS_CHROMEOS)
79 // On Chrome OS, a FontList font description string is stored as a
80 // translatable resource and passed in via SetDefaultFontDescription().
81 if (default_font_description_) {
82 FontRenderParamsQuery query;
83 CHECK(FontList::ParseDescription(*default_font_description_,
84 &query.families, &query.style,
85 &query.pixel_size))
86 << "Failed to parse font description " << *default_font_description_;
87 params = gfx::GetFontRenderParams(query, &family);
88 size_pixels = query.pixel_size;
89 style = query.style;
91 #else
92 // On Linux, LinuxFontDelegate is used to query the native toolkit (e.g.
93 // GTK+) for the default UI font.
94 const LinuxFontDelegate* delegate = LinuxFontDelegate::instance();
95 if (delegate) {
96 delegate->GetDefaultFontDescription(
97 &family, &size_pixels, &style, &params);
99 #endif
101 g_default_font.Get() = new PlatformFontLinux(
102 CreateSkTypeface(style, &family), family, size_pixels, style, params);
105 InitFromPlatformFont(g_default_font.Get().get());
108 PlatformFontLinux::PlatformFontLinux(const std::string& font_name,
109 int font_size_pixels) {
110 FontRenderParamsQuery query;
111 query.families.push_back(font_name);
112 query.pixel_size = font_size_pixels;
113 query.style = Font::NORMAL;
114 InitFromDetails(skia::RefPtr<SkTypeface>(), font_name, font_size_pixels,
115 query.style, gfx::GetFontRenderParams(query, NULL));
118 ////////////////////////////////////////////////////////////////////////////////
119 // PlatformFontLinux, PlatformFont implementation:
121 // static
122 void PlatformFontLinux::ReloadDefaultFont() {
123 // Reset the scoped_refptr.
124 g_default_font.Get() = nullptr;
127 #if defined(OS_CHROMEOS)
128 // static
129 void PlatformFontLinux::SetDefaultFontDescription(
130 const std::string& font_description) {
131 delete default_font_description_;
132 default_font_description_ = new std::string(font_description);
135 #endif
137 Font PlatformFontLinux::DeriveFont(int size_delta, int style) const {
138 const int new_size = font_size_pixels_ + size_delta;
139 DCHECK_GT(new_size, 0);
141 // If the style changed, we may need to load a new face.
142 std::string new_family = font_family_;
143 skia::RefPtr<SkTypeface> typeface =
144 (style == style_) ? typeface_ : CreateSkTypeface(style, &new_family);
146 FontRenderParamsQuery query;
147 query.families.push_back(new_family);
148 query.pixel_size = new_size;
149 query.style = style;
151 return Font(new PlatformFontLinux(typeface, new_family, new_size, style,
152 gfx::GetFontRenderParams(query, NULL)));
155 int PlatformFontLinux::GetHeight() const {
156 return height_pixels_;
159 int PlatformFontLinux::GetBaseline() const {
160 return ascent_pixels_;
163 int PlatformFontLinux::GetCapHeight() const {
164 return cap_height_pixels_;
167 int PlatformFontLinux::GetExpectedTextWidth(int length) const {
168 return round(static_cast<float>(length) * average_width_pixels_);
171 int PlatformFontLinux::GetStyle() const {
172 return style_;
175 std::string PlatformFontLinux::GetFontName() const {
176 return font_family_;
179 std::string PlatformFontLinux::GetActualFontNameForTesting() const {
180 SkString family_name;
181 typeface_->getFamilyName(&family_name);
182 return family_name.c_str();
185 int PlatformFontLinux::GetFontSize() const {
186 return font_size_pixels_;
189 const FontRenderParams& PlatformFontLinux::GetFontRenderParams() {
190 #if defined(OS_CHROMEOS)
191 float current_scale_factor = GetFontRenderParamsDeviceScaleFactor();
192 if (current_scale_factor != device_scale_factor_) {
193 FontRenderParamsQuery query;
194 query.families.push_back(font_family_);
195 query.pixel_size = font_size_pixels_;
196 query.style = style_;
197 query.device_scale_factor = current_scale_factor;
198 font_render_params_ = gfx::GetFontRenderParams(query, nullptr);
199 device_scale_factor_ = current_scale_factor;
201 #endif
202 return font_render_params_;
205 ////////////////////////////////////////////////////////////////////////////////
206 // PlatformFontLinux, private:
208 PlatformFontLinux::PlatformFontLinux(const skia::RefPtr<SkTypeface>& typeface,
209 const std::string& family,
210 int size_pixels,
211 int style,
212 const FontRenderParams& render_params) {
213 InitFromDetails(typeface, family, size_pixels, style, render_params);
216 PlatformFontLinux::~PlatformFontLinux() {}
218 void PlatformFontLinux::InitFromDetails(
219 const skia::RefPtr<SkTypeface>& typeface,
220 const std::string& font_family,
221 int font_size_pixels,
222 int style,
223 const FontRenderParams& render_params) {
224 DCHECK_GT(font_size_pixels, 0);
226 font_family_ = font_family;
227 typeface_ = typeface ? typeface : CreateSkTypeface(style, &font_family_);
229 font_size_pixels_ = font_size_pixels;
230 style_ = style;
231 #if defined(OS_CHROMEOS)
232 device_scale_factor_ = GetFontRenderParamsDeviceScaleFactor();
233 #endif
234 font_render_params_ = render_params;
236 SkPaint paint;
237 paint.setAntiAlias(false);
238 paint.setSubpixelText(false);
239 paint.setTextSize(font_size_pixels_);
240 paint.setTypeface(typeface_.get());
241 paint.setFakeBoldText((Font::BOLD & style_) && !typeface_->isBold());
242 paint.setTextSkewX((Font::ITALIC & style_) && !typeface_->isItalic() ?
243 -SK_Scalar1/4 : 0);
244 SkPaint::FontMetrics metrics;
245 paint.getFontMetrics(&metrics);
246 ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent);
247 height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent);
248 cap_height_pixels_ = SkScalarCeilToInt(metrics.fCapHeight);
249 average_width_pixels_ = SkScalarToDouble(metrics.fAvgCharWidth);
252 void PlatformFontLinux::InitFromPlatformFont(const PlatformFontLinux* other) {
253 typeface_ = other->typeface_;
254 font_family_ = other->font_family_;
255 font_size_pixels_ = other->font_size_pixels_;
256 style_ = other->style_;
257 #if defined(OS_CHROMEOS)
258 device_scale_factor_ = other->device_scale_factor_;
259 #endif
260 font_render_params_ = other->font_render_params_;
261 ascent_pixels_ = other->ascent_pixels_;
262 height_pixels_ = other->height_pixels_;
263 cap_height_pixels_ = other->cap_height_pixels_;
264 average_width_pixels_ = other->average_width_pixels_;
267 ////////////////////////////////////////////////////////////////////////////////
268 // PlatformFont, public:
270 // static
271 PlatformFont* PlatformFont::CreateDefault() {
272 return new PlatformFontLinux;
275 // static
276 PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
277 int font_size) {
278 return new PlatformFontLinux(font_name, font_size);
281 } // namespace gfx