gpu: Tweak Android WebGL test expectations
[chromium-blink-merge.git] / ui / gfx / platform_font_pango.cc
blobb950d23aac1462fe1db3273d3dc16650f9fd3989
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 "grit/app_locale_settings.h"
18 #include "third_party/skia/include/core/SkPaint.h"
19 #include "third_party/skia/include/core/SkTypeface.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #include "ui/gfx/canvas.h"
22 #include "ui/gfx/font.h"
23 #include "ui/gfx/pango_util.h"
25 #if defined(TOOLKIT_GTK)
26 #include <gdk/gdk.h>
27 #include <gtk/gtk.h>
28 #endif
30 namespace {
32 // The font family name which is used when a user's application font for
33 // GNOME/KDE is a non-scalable one. The name should be listed in the
34 // IsFallbackFontAllowed function in skia/ext/SkFontHost_fontconfig_direct.cpp.
35 const char* kFallbackFontFamilyName = "sans";
37 // Returns the available font family that best (in FontConfig's eyes) matches
38 // the supplied list of family names.
39 std::string FindBestMatchFontFamilyName(
40 const std::vector<std::string>& family_names) {
41 FcPattern* pattern = FcPatternCreate();
42 for (std::vector<std::string>::const_iterator it = family_names.begin();
43 it != family_names.end(); ++it) {
44 FcValue fcvalue;
45 fcvalue.type = FcTypeString;
46 fcvalue.u.s = reinterpret_cast<const FcChar8*>(it->c_str());
47 FcPatternAdd(pattern, FC_FAMILY, fcvalue, FcTrue /* append */);
50 FcConfigSubstitute(0, pattern, FcMatchPattern);
51 FcDefaultSubstitute(pattern);
52 FcResult result;
53 FcPattern* match = FcFontMatch(0, pattern, &result);
54 DCHECK(match) << "Could not find font";
55 FcChar8* match_family = NULL;
56 FcPatternGetString(match, FC_FAMILY, 0, &match_family);
57 std::string font_family(reinterpret_cast<char*>(match_family));
58 FcPatternDestroy(pattern);
59 FcPatternDestroy(match);
60 return font_family;
63 // Returns a Pango font description (suitable for parsing by
64 // pango_font_description_from_string()) for the default UI font.
65 std::string GetDefaultFont() {
66 #if !defined(TOOLKIT_GTK)
67 #if defined(OS_CHROMEOS)
68 return l10n_util::GetStringUTF8(IDS_UI_FONT_FAMILY_CROS);
69 #else
70 return "sans 10";
71 #endif // defined(OS_CHROMEOS)
72 #else
73 GtkSettings* settings = gtk_settings_get_default();
75 gchar* font_name = NULL;
76 g_object_get(settings, "gtk-font-name", &font_name, NULL);
78 // Temporary CHECK for helping track down
79 // http://code.google.com/p/chromium/issues/detail?id=12530
80 CHECK(font_name) << " Unable to get gtk-font-name for default font.";
82 std::string default_font = std::string(font_name);
83 g_free(font_name);
84 return default_font;
85 #endif // !defined(TOOLKIT_GTK)
88 } // namespace
90 namespace gfx {
92 Font* PlatformFontPango::default_font_ = NULL;
94 ////////////////////////////////////////////////////////////////////////////////
95 // PlatformFontPango, public:
97 PlatformFontPango::PlatformFontPango() {
98 if (default_font_ == NULL) {
99 std::string font_name = GetDefaultFont();
101 ScopedPangoFontDescription desc(
102 pango_font_description_from_string(font_name.c_str()));
103 default_font_ = new Font(desc.get());
105 DCHECK(default_font_);
108 InitFromPlatformFont(
109 static_cast<PlatformFontPango*>(default_font_->platform_font()));
112 PlatformFontPango::PlatformFontPango(NativeFont native_font) {
113 std::vector<std::string> family_names;
114 base::SplitString(pango_font_description_get_family(native_font), ',',
115 &family_names);
116 std::string font_family = FindBestMatchFontFamilyName(family_names);
117 InitWithNameAndSize(font_family, gfx::GetPangoFontSizeInPixels(native_font));
119 int style = 0;
120 if (pango_font_description_get_weight(native_font) == PANGO_WEIGHT_BOLD) {
121 // TODO(davemoore) What should we do about other weights? We currently
122 // only support BOLD.
123 style |= gfx::Font::BOLD;
125 if (pango_font_description_get_style(native_font) == PANGO_STYLE_ITALIC) {
126 // TODO(davemoore) What about PANGO_STYLE_OBLIQUE?
127 style |= gfx::Font::ITALIC;
129 if (style != 0)
130 style_ = style;
133 PlatformFontPango::PlatformFontPango(const std::string& font_name,
134 int font_size) {
135 InitWithNameAndSize(font_name, font_size);
138 double PlatformFontPango::underline_position() const {
139 const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
140 return underline_position_pixels_;
143 double PlatformFontPango::underline_thickness() const {
144 const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
145 return underline_thickness_pixels_;
148 ////////////////////////////////////////////////////////////////////////////////
149 // PlatformFontPango, PlatformFont implementation:
151 // static
152 void PlatformFontPango::ReloadDefaultFont() {
153 delete default_font_;
154 default_font_ = NULL;
157 Font PlatformFontPango::DeriveFont(int size_delta, int style) const {
158 // If the delta is negative, if must not push the size below 1
159 if (size_delta < 0)
160 DCHECK_LT(-size_delta, font_size_pixels_);
162 if (style == style_) {
163 // Fast path, we just use the same typeface at a different size
164 return Font(new PlatformFontPango(typeface_,
165 font_family_,
166 font_size_pixels_ + size_delta,
167 style_));
170 // If the style has changed we may need to load a new face
171 int skstyle = SkTypeface::kNormal;
172 if (gfx::Font::BOLD & style)
173 skstyle |= SkTypeface::kBold;
174 if (gfx::Font::ITALIC & style)
175 skstyle |= SkTypeface::kItalic;
177 skia::RefPtr<SkTypeface> typeface = skia::AdoptRef(
178 SkTypeface::CreateFromName(
179 font_family_.c_str(),
180 static_cast<SkTypeface::Style>(skstyle)));
182 return Font(new PlatformFontPango(typeface,
183 font_family_,
184 font_size_pixels_ + size_delta,
185 style));
188 int PlatformFontPango::GetHeight() const {
189 return height_pixels_;
192 int PlatformFontPango::GetBaseline() const {
193 return ascent_pixels_;
196 int PlatformFontPango::GetAverageCharacterWidth() const {
197 const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
198 return SkScalarRound(average_width_pixels_);
201 int PlatformFontPango::GetStringWidth(const base::string16& text) const {
202 return Canvas::GetStringWidth(text,
203 Font(const_cast<PlatformFontPango*>(this)));
206 int PlatformFontPango::GetExpectedTextWidth(int length) const {
207 double char_width = const_cast<PlatformFontPango*>(this)->GetAverageWidth();
208 return round(static_cast<float>(length) * char_width);
211 int PlatformFontPango::GetStyle() const {
212 return style_;
215 std::string PlatformFontPango::GetFontName() const {
216 return font_family_;
219 int PlatformFontPango::GetFontSize() const {
220 return font_size_pixels_;
223 NativeFont PlatformFontPango::GetNativeFont() const {
224 PangoFontDescription* pfd = pango_font_description_new();
225 pango_font_description_set_family(pfd, GetFontName().c_str());
226 // Set the absolute size to avoid overflowing UI elements.
227 // pango_font_description_set_absolute_size() takes a size in Pango units.
228 // There are PANGO_SCALE Pango units in one device unit. Screen output
229 // devices use pixels as their device units.
230 pango_font_description_set_absolute_size(
231 pfd, font_size_pixels_ * PANGO_SCALE);
233 switch (GetStyle()) {
234 case gfx::Font::NORMAL:
235 // Nothing to do, should already be PANGO_STYLE_NORMAL.
236 break;
237 case gfx::Font::BOLD:
238 pango_font_description_set_weight(pfd, PANGO_WEIGHT_BOLD);
239 break;
240 case gfx::Font::ITALIC:
241 pango_font_description_set_style(pfd, PANGO_STYLE_ITALIC);
242 break;
243 case gfx::Font::UNDERLINE:
244 // TODO(deanm): How to do underline? Where do we use it? Probably have
245 // to paint it ourselves, see pango_font_metrics_get_underline_position.
246 break;
249 return pfd;
252 ////////////////////////////////////////////////////////////////////////////////
253 // PlatformFontPango, private:
255 PlatformFontPango::PlatformFontPango(const skia::RefPtr<SkTypeface>& typeface,
256 const std::string& name,
257 int size,
258 int style) {
259 InitWithTypefaceNameSizeAndStyle(typeface, name, size, style);
262 PlatformFontPango::~PlatformFontPango() {}
264 void PlatformFontPango::InitWithNameAndSize(const std::string& font_name,
265 int font_size) {
266 DCHECK_GT(font_size, 0);
267 std::string fallback;
269 skia::RefPtr<SkTypeface> typeface = skia::AdoptRef(
270 SkTypeface::CreateFromName(font_name.c_str(), SkTypeface::kNormal));
271 if (!typeface) {
272 // A non-scalable font such as .pcf is specified. Falls back to a default
273 // scalable font.
274 typeface = skia::AdoptRef(
275 SkTypeface::CreateFromName(
276 kFallbackFontFamilyName, SkTypeface::kNormal));
277 CHECK(typeface) << "Could not find any font: "
278 << font_name
279 << ", " << kFallbackFontFamilyName;
280 fallback = kFallbackFontFamilyName;
283 InitWithTypefaceNameSizeAndStyle(typeface,
284 fallback.empty() ? font_name : fallback,
285 font_size,
286 gfx::Font::NORMAL);
289 void PlatformFontPango::InitWithTypefaceNameSizeAndStyle(
290 const skia::RefPtr<SkTypeface>& typeface,
291 const std::string& font_family,
292 int font_size,
293 int style) {
294 typeface_ = typeface;
295 font_family_ = font_family;
296 font_size_pixels_ = font_size;
297 style_ = style;
298 pango_metrics_inited_ = false;
299 average_width_pixels_ = 0.0f;
300 underline_position_pixels_ = 0.0f;
301 underline_thickness_pixels_ = 0.0f;
303 SkPaint paint;
304 SkPaint::FontMetrics metrics;
305 PaintSetup(&paint);
306 paint.getFontMetrics(&metrics);
308 ascent_pixels_ = SkScalarCeil(-metrics.fAscent);
309 height_pixels_ = ascent_pixels_ + SkScalarCeil(metrics.fDescent);
312 void PlatformFontPango::InitFromPlatformFont(const PlatformFontPango* other) {
313 typeface_ = other->typeface_;
314 font_family_ = other->font_family_;
315 font_size_pixels_ = other->font_size_pixels_;
316 style_ = other->style_;
317 height_pixels_ = other->height_pixels_;
318 ascent_pixels_ = other->ascent_pixels_;
319 pango_metrics_inited_ = other->pango_metrics_inited_;
320 average_width_pixels_ = other->average_width_pixels_;
321 underline_position_pixels_ = other->underline_position_pixels_;
322 underline_thickness_pixels_ = other->underline_thickness_pixels_;
325 void PlatformFontPango::PaintSetup(SkPaint* paint) const {
326 paint->setAntiAlias(false);
327 paint->setSubpixelText(false);
328 paint->setTextSize(font_size_pixels_);
329 paint->setTypeface(typeface_.get());
330 paint->setFakeBoldText((gfx::Font::BOLD & style_) && !typeface_->isBold());
331 paint->setTextSkewX((gfx::Font::ITALIC & style_) && !typeface_->isItalic() ?
332 -SK_Scalar1/4 : 0);
335 void PlatformFontPango::InitPangoMetrics() {
336 if (!pango_metrics_inited_) {
337 pango_metrics_inited_ = true;
338 ScopedPangoFontDescription pango_desc(GetNativeFont());
339 PangoFontMetrics* pango_metrics = GetPangoFontMetrics(pango_desc.get());
341 underline_position_pixels_ =
342 pango_font_metrics_get_underline_position(pango_metrics) /
343 PANGO_SCALE;
345 // TODO(davemoore): Come up with a better solution.
346 // This is a hack, but without doing this the underlines
347 // we get end up fuzzy. So we align to the midpoint of a pixel.
348 underline_position_pixels_ /= 2;
350 underline_thickness_pixels_ =
351 pango_font_metrics_get_underline_thickness(pango_metrics) /
352 PANGO_SCALE;
354 // First get the Pango-based width (converting from Pango units to pixels).
355 const double pango_width_pixels =
356 pango_font_metrics_get_approximate_char_width(pango_metrics) /
357 PANGO_SCALE;
359 // Yes, this is how Microsoft recommends calculating the dialog unit
360 // conversions.
361 const int text_width_pixels = GetStringWidth(
362 ASCIIToUTF16("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
363 const double dialog_units_pixels = (text_width_pixels / 26 + 1) / 2;
364 average_width_pixels_ = std::min(pango_width_pixels, dialog_units_pixels);
369 double PlatformFontPango::GetAverageWidth() const {
370 const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
371 return average_width_pixels_;
374 ////////////////////////////////////////////////////////////////////////////////
375 // PlatformFont, public:
377 // static
378 PlatformFont* PlatformFont::CreateDefault() {
379 return new PlatformFontPango;
382 // static
383 PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
384 return new PlatformFontPango(native_font);
387 // static
388 PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
389 int font_size) {
390 return new PlatformFontPango(font_name, font_size);
393 } // namespace gfx