Support for unpacked ARM packed relocations.
[chromium-blink-merge.git] / ui / gfx / platform_font_pango.cc
blobefc940bd1864172c4e2d1a25c84d01544e9e37e2
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_pango.h"
7 #include <fontconfig/fontconfig.h>
8 #include <pango/pango.h>
10 #include <algorithm>
11 #include <string>
13 #include "base/logging.h"
14 #include "base/strings/string_piece.h"
15 #include "base/strings/string_split.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "third_party/skia/include/core/SkPaint.h"
18 #include "third_party/skia/include/core/SkString.h"
19 #include "third_party/skia/include/core/SkTypeface.h"
20 #include "ui/gfx/canvas.h"
21 #include "ui/gfx/font.h"
22 #include "ui/gfx/font_list.h"
23 #include "ui/gfx/linux_font_delegate.h"
24 #include "ui/gfx/pango_util.h"
25 #include "ui/gfx/text_utils.h"
27 namespace {
29 // The font family name which is used when a user's application font for
30 // GNOME/KDE is a non-scalable one. The name should be listed in the
31 // IsFallbackFontAllowed function in skia/ext/SkFontHost_fontconfig_direct.cpp.
32 const char* kFallbackFontFamilyName = "sans";
34 // Returns the available font family that best (in FontConfig's eyes) matches
35 // the supplied list of family names.
36 std::string FindBestMatchFontFamilyName(
37 const std::vector<std::string>& family_names) {
38 FcPattern* pattern = FcPatternCreate();
39 for (std::vector<std::string>::const_iterator it = family_names.begin();
40 it != family_names.end(); ++it) {
41 FcValue fcvalue;
42 fcvalue.type = FcTypeString;
43 fcvalue.u.s = reinterpret_cast<const FcChar8*>(it->c_str());
44 FcPatternAdd(pattern, FC_FAMILY, fcvalue, FcTrue /* append */);
47 FcConfigSubstitute(0, pattern, FcMatchPattern);
48 FcDefaultSubstitute(pattern);
49 FcResult result;
50 FcPattern* match = FcFontMatch(0, pattern, &result);
51 DCHECK(match) << "Could not find font";
52 FcChar8* match_family = NULL;
53 FcPatternGetString(match, FC_FAMILY, 0, &match_family);
54 std::string font_family(reinterpret_cast<char*>(match_family));
55 FcPatternDestroy(pattern);
56 FcPatternDestroy(match);
57 return font_family;
60 } // namespace
62 namespace gfx {
64 // static
65 Font* PlatformFontPango::default_font_ = NULL;
67 #if defined(OS_CHROMEOS)
68 // static
69 std::string* PlatformFontPango::default_font_description_ = NULL;
70 #endif
72 ////////////////////////////////////////////////////////////////////////////////
73 // PlatformFontPango, public:
75 PlatformFontPango::PlatformFontPango() {
76 if (default_font_ == NULL) {
77 std::string font_name = GetDefaultFont();
79 ScopedPangoFontDescription desc(
80 pango_font_description_from_string(font_name.c_str()));
81 default_font_ = new Font(desc.get());
83 DCHECK(default_font_);
86 InitFromPlatformFont(
87 static_cast<PlatformFontPango*>(default_font_->platform_font()));
90 PlatformFontPango::PlatformFontPango(NativeFont native_font) {
91 std::vector<std::string> family_names;
92 base::SplitString(pango_font_description_get_family(native_font), ',',
93 &family_names);
94 std::string font_family = FindBestMatchFontFamilyName(family_names);
95 InitWithNameAndSize(font_family, gfx::GetPangoFontSizeInPixels(native_font));
97 int style = 0;
98 if (pango_font_description_get_weight(native_font) == PANGO_WEIGHT_BOLD) {
99 // TODO(davemoore) What should we do about other weights? We currently
100 // only support BOLD.
101 style |= gfx::Font::BOLD;
103 if (pango_font_description_get_style(native_font) == PANGO_STYLE_ITALIC) {
104 // TODO(davemoore) What about PANGO_STYLE_OBLIQUE?
105 style |= gfx::Font::ITALIC;
107 if (style != 0)
108 style_ = style;
111 PlatformFontPango::PlatformFontPango(const std::string& font_name,
112 int font_size) {
113 InitWithNameAndSize(font_name, font_size);
116 double PlatformFontPango::underline_position() const {
117 const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
118 return underline_position_pixels_;
121 double PlatformFontPango::underline_thickness() const {
122 const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
123 return underline_thickness_pixels_;
126 ////////////////////////////////////////////////////////////////////////////////
127 // PlatformFontPango, PlatformFont implementation:
129 // static
130 void PlatformFontPango::ReloadDefaultFont() {
131 delete default_font_;
132 default_font_ = NULL;
135 #if defined(OS_CHROMEOS)
136 // static
137 void PlatformFontPango::SetDefaultFontDescription(
138 const std::string& font_description) {
139 delete default_font_description_;
140 default_font_description_ = new std::string(font_description);
143 #endif
145 Font PlatformFontPango::DeriveFont(int size_delta, int style) const {
146 // If the delta is negative, if must not push the size below 1
147 if (size_delta < 0)
148 DCHECK_LT(-size_delta, font_size_pixels_);
150 if (style == style_) {
151 // Fast path, we just use the same typeface at a different size
152 return Font(new PlatformFontPango(typeface_,
153 font_family_,
154 font_size_pixels_ + size_delta,
155 style_));
158 // If the style has changed we may need to load a new face
159 int skstyle = SkTypeface::kNormal;
160 if (gfx::Font::BOLD & style)
161 skstyle |= SkTypeface::kBold;
162 if (gfx::Font::ITALIC & style)
163 skstyle |= SkTypeface::kItalic;
165 skia::RefPtr<SkTypeface> typeface = skia::AdoptRef(
166 SkTypeface::CreateFromName(
167 font_family_.c_str(),
168 static_cast<SkTypeface::Style>(skstyle)));
170 return Font(new PlatformFontPango(typeface,
171 font_family_,
172 font_size_pixels_ + size_delta,
173 style));
176 int PlatformFontPango::GetHeight() const {
177 return height_pixels_;
180 int PlatformFontPango::GetBaseline() const {
181 return ascent_pixels_;
184 int PlatformFontPango::GetCapHeight() const {
185 return cap_height_pixels_;
188 int PlatformFontPango::GetExpectedTextWidth(int length) const {
189 double char_width = const_cast<PlatformFontPango*>(this)->GetAverageWidth();
190 return round(static_cast<float>(length) * char_width);
193 int PlatformFontPango::GetStyle() const {
194 return style_;
197 std::string PlatformFontPango::GetFontName() const {
198 return font_family_;
201 std::string PlatformFontPango::GetActualFontNameForTesting() const {
202 SkString family_name;
203 typeface_->getFamilyName(&family_name);
204 return family_name.c_str();
207 int PlatformFontPango::GetFontSize() const {
208 return font_size_pixels_;
211 NativeFont PlatformFontPango::GetNativeFont() const {
212 PangoFontDescription* pfd = pango_font_description_new();
213 pango_font_description_set_family(pfd, GetFontName().c_str());
214 // Set the absolute size to avoid overflowing UI elements.
215 // pango_font_description_set_absolute_size() takes a size in Pango units.
216 // There are PANGO_SCALE Pango units in one device unit. Screen output
217 // devices use pixels as their device units.
218 pango_font_description_set_absolute_size(
219 pfd, font_size_pixels_ * PANGO_SCALE);
221 switch (GetStyle()) {
222 case gfx::Font::NORMAL:
223 // Nothing to do, should already be PANGO_STYLE_NORMAL.
224 break;
225 case gfx::Font::BOLD:
226 pango_font_description_set_weight(pfd, PANGO_WEIGHT_BOLD);
227 break;
228 case gfx::Font::ITALIC:
229 pango_font_description_set_style(pfd, PANGO_STYLE_ITALIC);
230 break;
231 case gfx::Font::UNDERLINE:
232 // TODO(deanm): How to do underline? Where do we use it? Probably have
233 // to paint it ourselves, see pango_font_metrics_get_underline_position.
234 break;
237 return pfd;
240 ////////////////////////////////////////////////////////////////////////////////
241 // PlatformFontPango, private:
243 PlatformFontPango::PlatformFontPango(const skia::RefPtr<SkTypeface>& typeface,
244 const std::string& name,
245 int size,
246 int style) {
247 InitWithTypefaceNameSizeAndStyle(typeface, name, size, style);
250 PlatformFontPango::~PlatformFontPango() {}
252 // static
253 std::string PlatformFontPango::GetDefaultFont() {
254 #if defined(OS_CHROMEOS)
255 // Font name must have been provided by way of SetDefaultFontDescription().
256 CHECK(default_font_description_);
257 return *default_font_description_;
258 #else
259 const gfx::LinuxFontDelegate* delegate = gfx::LinuxFontDelegate::instance();
260 if (delegate)
261 return delegate->GetDefaultFontName();
263 return "sans 10";
264 #endif // defined(OS_CHROMEOS)
267 void PlatformFontPango::InitWithNameAndSize(const std::string& font_name,
268 int font_size) {
269 DCHECK_GT(font_size, 0);
270 std::string fallback;
272 skia::RefPtr<SkTypeface> typeface = skia::AdoptRef(
273 SkTypeface::CreateFromName(font_name.c_str(), SkTypeface::kNormal));
274 if (!typeface) {
275 // A non-scalable font such as .pcf is specified. Falls back to a default
276 // scalable font.
277 typeface = skia::AdoptRef(
278 SkTypeface::CreateFromName(
279 kFallbackFontFamilyName, SkTypeface::kNormal));
280 CHECK(typeface) << "Could not find any font: "
281 << font_name
282 << ", " << kFallbackFontFamilyName;
283 fallback = kFallbackFontFamilyName;
286 InitWithTypefaceNameSizeAndStyle(typeface,
287 fallback.empty() ? font_name : fallback,
288 font_size,
289 gfx::Font::NORMAL);
292 void PlatformFontPango::InitWithTypefaceNameSizeAndStyle(
293 const skia::RefPtr<SkTypeface>& typeface,
294 const std::string& font_family,
295 int font_size,
296 int style) {
297 typeface_ = typeface;
298 font_family_ = font_family;
299 font_size_pixels_ = font_size;
300 style_ = style;
301 pango_metrics_inited_ = false;
302 average_width_pixels_ = 0.0f;
303 underline_position_pixels_ = 0.0f;
304 underline_thickness_pixels_ = 0.0f;
306 SkPaint paint;
307 SkPaint::FontMetrics metrics;
308 PaintSetup(&paint);
309 paint.getFontMetrics(&metrics);
311 ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent);
312 height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent);
313 cap_height_pixels_ = SkScalarCeilToInt(metrics.fCapHeight);
316 void PlatformFontPango::InitFromPlatformFont(const PlatformFontPango* other) {
317 typeface_ = other->typeface_;
318 font_family_ = other->font_family_;
319 font_size_pixels_ = other->font_size_pixels_;
320 style_ = other->style_;
321 height_pixels_ = other->height_pixels_;
322 ascent_pixels_ = other->ascent_pixels_;
323 cap_height_pixels_ = other->cap_height_pixels_;
324 pango_metrics_inited_ = other->pango_metrics_inited_;
325 average_width_pixels_ = other->average_width_pixels_;
326 underline_position_pixels_ = other->underline_position_pixels_;
327 underline_thickness_pixels_ = other->underline_thickness_pixels_;
330 void PlatformFontPango::PaintSetup(SkPaint* paint) const {
331 paint->setAntiAlias(false);
332 paint->setSubpixelText(false);
333 paint->setTextSize(font_size_pixels_);
334 paint->setTypeface(typeface_.get());
335 paint->setFakeBoldText((gfx::Font::BOLD & style_) && !typeface_->isBold());
336 paint->setTextSkewX((gfx::Font::ITALIC & style_) && !typeface_->isItalic() ?
337 -SK_Scalar1/4 : 0);
340 void PlatformFontPango::InitPangoMetrics() {
341 if (!pango_metrics_inited_) {
342 pango_metrics_inited_ = true;
343 ScopedPangoFontDescription pango_desc(GetNativeFont());
344 PangoFontMetrics* pango_metrics = GetPangoFontMetrics(pango_desc.get());
346 underline_position_pixels_ =
347 pango_font_metrics_get_underline_position(pango_metrics) /
348 PANGO_SCALE;
350 // TODO(davemoore): Come up with a better solution.
351 // This is a hack, but without doing this the underlines
352 // we get end up fuzzy. So we align to the midpoint of a pixel.
353 underline_position_pixels_ /= 2;
355 underline_thickness_pixels_ =
356 pango_font_metrics_get_underline_thickness(pango_metrics) /
357 PANGO_SCALE;
359 // First get the Pango-based width (converting from Pango units to pixels).
360 const double pango_width_pixels =
361 pango_font_metrics_get_approximate_char_width(pango_metrics) /
362 PANGO_SCALE;
364 // Yes, this is how Microsoft recommends calculating the dialog unit
365 // conversions.
366 const int text_width_pixels = GetStringWidth(
367 base::ASCIIToUTF16(
368 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),
369 FontList(Font(this)));
370 const double dialog_units_pixels = (text_width_pixels / 26 + 1) / 2;
371 average_width_pixels_ = std::min(pango_width_pixels, dialog_units_pixels);
375 double PlatformFontPango::GetAverageWidth() const {
376 const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
377 return average_width_pixels_;
380 ////////////////////////////////////////////////////////////////////////////////
381 // PlatformFont, public:
383 // static
384 PlatformFont* PlatformFont::CreateDefault() {
385 return new PlatformFontPango;
388 // static
389 PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
390 return new PlatformFontPango(native_font);
393 // static
394 PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
395 int font_size) {
396 return new PlatformFontPango(font_name, font_size);
399 } // namespace gfx