Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(201)

Side by Side Diff: ui/gfx/platform_font_gtk.cc

Issue 7977025: aura: Make 'ui' buildable without gtk. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/gfx/platform_font_gtk.h ('k') | ui/gfx/platform_font_pango.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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
5 #include "ui/gfx/platform_font_gtk.h"
6
7 #include <algorithm>
8 #include <fontconfig/fontconfig.h>
9 #include <map>
10 #include <pango/pango.h>
11 #include <string>
12
13 #include "base/logging.h"
14 #include "base/string_piece.h"
15 #include "base/utf_string_conversions.h"
16 #include "third_party/skia/include/core/SkTypeface.h"
17 #include "third_party/skia/include/core/SkPaint.h"
18 #include "ui/gfx/canvas_skia.h"
19 #include "ui/gfx/font.h"
20 #include "ui/gfx/linux_util.h"
21
22 #if !defined(USE_WAYLAND)
23 #include <gdk/gdk.h>
24 #include <gtk/gtk.h>
25 #endif
26
27 namespace {
28
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";
33
34 // Returns the number of pixels in a point.
35 // - multiply a point size by this to get pixels ("device units")
36 // - divide a pixel size by this to get points
37 float GetPixelsInPoint() {
38 static float pixels_in_point = 1.0;
39 static bool determined_value = false;
40
41 if (!determined_value) {
42 // http://goo.gl/UIh5m: "This is a scale factor between points specified in
43 // a PangoFontDescription and Cairo units. The default value is 96, meaning
44 // that a 10 point font will be 13 units high. (10 * 96. / 72. = 13.3)."
45 double pango_dpi = gfx::GetPangoResolution();
46 if (pango_dpi <= 0)
47 pango_dpi = 96.0;
48 pixels_in_point = pango_dpi / 72.0; // 72 points in an inch
49 determined_value = true;
50 }
51
52 return pixels_in_point;
53 }
54
55 // Retrieves the pango metrics for a pango font description. Caches the metrics
56 // and never frees them. The metrics objects are relatively small and
57 // very expensive to look up.
58 PangoFontMetrics* GetPangoFontMetrics(PangoFontDescription* desc) {
59 static std::map<int, PangoFontMetrics*>* desc_to_metrics = NULL;
60 static PangoContext* context = NULL;
61
62 if (!context) {
63 context = gfx::GetPangoContext();
64 pango_context_set_language(context, pango_language_get_default());
65 }
66
67 if (!desc_to_metrics) {
68 desc_to_metrics = new std::map<int, PangoFontMetrics*>();
69 }
70
71 int desc_hash = pango_font_description_hash(desc);
72 std::map<int, PangoFontMetrics*>::iterator i =
73 desc_to_metrics->find(desc_hash);
74
75 if (i == desc_to_metrics->end()) {
76 PangoFontMetrics* metrics = pango_context_get_metrics(context, desc, NULL);
77 (*desc_to_metrics)[desc_hash] = metrics;
78 return metrics;
79 } else {
80 return i->second;
81 }
82 }
83
84 // Find the best match font for |family_name| in the same way as Skia
85 // to make sure CreateFont() successfully creates a default font. In
86 // Skia, it only checks the best match font. If it failed to find
87 // one, SkTypeface will be NULL for that font family. It eventually
88 // causes a segfault. For example, family_name = "Sans" and system
89 // may have various fonts. The first font family in FcPattern will be
90 // "DejaVu Sans" but a font family returned by FcFontMatch will be "VL
91 // PGothic". In this case, SkTypeface for "Sans" returns NULL even if
92 // the system has a font for "Sans" font family. See FontMatch() in
93 // skia/ports/SkFontHost_fontconfig.cpp for more detail.
94 string16 FindBestMatchFontFamilyName(const char* family_name) {
95 FcPattern* pattern = FcPatternCreate();
96 FcValue fcvalue;
97 fcvalue.type = FcTypeString;
98 char* family_name_copy = strdup(family_name);
99 fcvalue.u.s = reinterpret_cast<FcChar8*>(family_name_copy);
100 FcPatternAdd(pattern, FC_FAMILY, fcvalue, 0);
101 FcConfigSubstitute(0, pattern, FcMatchPattern);
102 FcDefaultSubstitute(pattern);
103 FcResult result;
104 FcPattern* match = FcFontMatch(0, pattern, &result);
105 DCHECK(match) << "Could not find font: " << family_name;
106 FcChar8* match_family;
107 FcPatternGetString(match, FC_FAMILY, 0, &match_family);
108
109 string16 font_family = UTF8ToUTF16(reinterpret_cast<char*>(match_family));
110 FcPatternDestroy(match);
111 FcPatternDestroy(pattern);
112 free(family_name_copy);
113 return font_family;
114 }
115
116 std::string GetDefaultFont() {
117 #if defined(USE_WAYLAND) || defined(USE_AURA)
118 return "sans 10";
119 #else
120 GtkSettings* settings = gtk_settings_get_default();
121
122 gchar* font_name = NULL;
123 g_object_get(settings, "gtk-font-name", &font_name, NULL);
124
125 // Temporary CHECK for helping track down
126 // http://code.google.com/p/chromium/issues/detail?id=12530
127 CHECK(font_name) << " Unable to get gtk-font-name for default font.";
128
129 std::string default_font = std::string(font_name);
130 g_free(font_name);
131 return default_font;
132 #endif
133 }
134
135 } // namespace
136
137 namespace gfx {
138
139 Font* PlatformFontGtk::default_font_ = NULL;
140
141 ////////////////////////////////////////////////////////////////////////////////
142 // PlatformFontGtk, public:
143
144 PlatformFontGtk::PlatformFontGtk() {
145 if (default_font_ == NULL) {
146 std::string font_name = GetDefaultFont();
147
148 PangoFontDescription* desc =
149 pango_font_description_from_string(font_name.c_str());
150 default_font_ = new Font(desc);
151 pango_font_description_free(desc);
152
153 DCHECK(default_font_);
154 }
155
156 InitFromPlatformFont(
157 static_cast<PlatformFontGtk*>(default_font_->platform_font()));
158 }
159
160 PlatformFontGtk::PlatformFontGtk(const Font& other) {
161 InitFromPlatformFont(
162 static_cast<PlatformFontGtk*>(other.platform_font()));
163 }
164
165 PlatformFontGtk::PlatformFontGtk(NativeFont native_font) {
166 const char* family_name = pango_font_description_get_family(native_font);
167
168 gint size_in_pixels = 0;
169 if (pango_font_description_get_size_is_absolute(native_font)) {
170 // If the size is absolute, then it's in Pango units rather than points.
171 // There are PANGO_SCALE Pango units in a device unit (pixel).
172 size_in_pixels = pango_font_description_get_size(native_font) / PANGO_SCALE;
173 } else {
174 // Otherwise, we need to convert from points.
175 size_in_pixels =
176 pango_font_description_get_size(native_font) * GetPixelsInPoint() /
177 PANGO_SCALE;
178 }
179
180 // Find best match font for |family_name| to make sure we can get
181 // a SkTypeface for the default font.
182 // TODO(agl): remove this.
183 string16 font_family = FindBestMatchFontFamilyName(family_name);
184
185 InitWithNameAndSize(font_family, size_in_pixels);
186 int style = 0;
187 if (pango_font_description_get_weight(native_font) == PANGO_WEIGHT_BOLD) {
188 // TODO(davemoore) What should we do about other weights? We currently
189 // only support BOLD.
190 style |= gfx::Font::BOLD;
191 }
192 if (pango_font_description_get_style(native_font) == PANGO_STYLE_ITALIC) {
193 // TODO(davemoore) What about PANGO_STYLE_OBLIQUE?
194 style |= gfx::Font::ITALIC;
195 }
196 if (style != 0)
197 style_ = style;
198 }
199
200 PlatformFontGtk::PlatformFontGtk(const string16& font_name,
201 int font_size) {
202 InitWithNameAndSize(font_name, font_size);
203 }
204
205 double PlatformFontGtk::underline_position() const {
206 const_cast<PlatformFontGtk*>(this)->InitPangoMetrics();
207 return underline_position_pixels_;
208 }
209
210 double PlatformFontGtk::underline_thickness() const {
211 const_cast<PlatformFontGtk*>(this)->InitPangoMetrics();
212 return underline_thickness_pixels_;
213 }
214
215 ////////////////////////////////////////////////////////////////////////////////
216 // PlatformFontGtk, PlatformFont implementation:
217
218 // static
219 void PlatformFontGtk::ReloadDefaultFont() {
220 delete default_font_;
221 default_font_ = NULL;
222 }
223
224 Font PlatformFontGtk::DeriveFont(int size_delta, int style) const {
225 // If the delta is negative, if must not push the size below 1
226 if (size_delta < 0)
227 DCHECK_LT(-size_delta, font_size_pixels_);
228
229 if (style == style_) {
230 // Fast path, we just use the same typeface at a different size
231 return Font(new PlatformFontGtk(typeface_,
232 font_family_,
233 font_size_pixels_ + size_delta,
234 style_));
235 }
236
237 // If the style has changed we may need to load a new face
238 int skstyle = SkTypeface::kNormal;
239 if (gfx::Font::BOLD & style)
240 skstyle |= SkTypeface::kBold;
241 if (gfx::Font::ITALIC & style)
242 skstyle |= SkTypeface::kItalic;
243
244 SkTypeface* typeface = SkTypeface::CreateFromName(
245 UTF16ToUTF8(font_family_).c_str(),
246 static_cast<SkTypeface::Style>(skstyle));
247 SkAutoUnref tf_helper(typeface);
248
249 return Font(new PlatformFontGtk(typeface,
250 font_family_,
251 font_size_pixels_ + size_delta,
252 style));
253 }
254
255 int PlatformFontGtk::GetHeight() const {
256 return height_pixels_;
257 }
258
259 int PlatformFontGtk::GetBaseline() const {
260 return ascent_pixels_;
261 }
262
263 int PlatformFontGtk::GetAverageCharacterWidth() const {
264 return SkScalarRound(average_width_pixels_);
265 }
266
267 int PlatformFontGtk::GetStringWidth(const string16& text) const {
268 int width = 0, height = 0;
269 CanvasSkia::SizeStringInt(text, Font(const_cast<PlatformFontGtk*>(this)),
270 &width, &height, gfx::Canvas::NO_ELLIPSIS);
271 return width;
272 }
273
274 int PlatformFontGtk::GetExpectedTextWidth(int length) const {
275 double char_width = const_cast<PlatformFontGtk*>(this)->GetAverageWidth();
276 return round(static_cast<float>(length) * char_width);
277 }
278
279 int PlatformFontGtk::GetStyle() const {
280 return style_;
281 }
282
283 string16 PlatformFontGtk::GetFontName() const {
284 return font_family_;
285 }
286
287 int PlatformFontGtk::GetFontSize() const {
288 return font_size_pixels_;
289 }
290
291 NativeFont PlatformFontGtk::GetNativeFont() const {
292 PangoFontDescription* pfd = pango_font_description_new();
293 pango_font_description_set_family(pfd, UTF16ToUTF8(GetFontName()).c_str());
294 // Set the absolute size to avoid overflowing UI elements.
295 // pango_font_description_set_absolute_size() takes a size in Pango units.
296 // There are PANGO_SCALE Pango units in one device unit. Screen output
297 // devices use pixels as their device units.
298 pango_font_description_set_absolute_size(
299 pfd, font_size_pixels_ * PANGO_SCALE);
300
301 switch (GetStyle()) {
302 case gfx::Font::NORMAL:
303 // Nothing to do, should already be PANGO_STYLE_NORMAL.
304 break;
305 case gfx::Font::BOLD:
306 pango_font_description_set_weight(pfd, PANGO_WEIGHT_BOLD);
307 break;
308 case gfx::Font::ITALIC:
309 pango_font_description_set_style(pfd, PANGO_STYLE_ITALIC);
310 break;
311 case gfx::Font::UNDERLINED:
312 // TODO(deanm): How to do underlined? Where do we use it? Probably have
313 // to paint it ourselves, see pango_font_metrics_get_underline_position.
314 break;
315 }
316
317 return pfd;
318 }
319
320 ////////////////////////////////////////////////////////////////////////////////
321 // PlatformFontGtk, private:
322
323 PlatformFontGtk::PlatformFontGtk(SkTypeface* typeface,
324 const string16& name,
325 int size,
326 int style) {
327 InitWithTypefaceNameSizeAndStyle(typeface, name, size, style);
328 }
329
330 PlatformFontGtk::~PlatformFontGtk() {}
331
332 void PlatformFontGtk::InitWithNameAndSize(const string16& font_name,
333 int font_size) {
334 DCHECK_GT(font_size, 0);
335 string16 fallback;
336
337 SkTypeface* typeface = SkTypeface::CreateFromName(
338 UTF16ToUTF8(font_name).c_str(), SkTypeface::kNormal);
339 if (!typeface) {
340 // A non-scalable font such as .pcf is specified. Falls back to a default
341 // scalable font.
342 typeface = SkTypeface::CreateFromName(
343 kFallbackFontFamilyName, SkTypeface::kNormal);
344 CHECK(typeface) << "Could not find any font: "
345 << UTF16ToUTF8(font_name)
346 << ", " << kFallbackFontFamilyName;
347 fallback = UTF8ToUTF16(kFallbackFontFamilyName);
348 }
349 SkAutoUnref typeface_helper(typeface);
350
351 InitWithTypefaceNameSizeAndStyle(typeface,
352 fallback.empty() ? font_name : fallback,
353 font_size,
354 gfx::Font::NORMAL);
355 }
356
357 void PlatformFontGtk::InitWithTypefaceNameSizeAndStyle(
358 SkTypeface* typeface,
359 const string16& font_family,
360 int font_size,
361 int style) {
362 typeface_helper_.reset(new SkAutoUnref(typeface));
363 typeface_ = typeface;
364 typeface_->ref();
365 font_family_ = font_family;
366 font_size_pixels_ = font_size;
367 style_ = style;
368 pango_metrics_inited_ = false;
369 average_width_pixels_ = 0.0f;
370 underline_position_pixels_ = 0.0f;
371 underline_thickness_pixels_ = 0.0f;
372
373 SkPaint paint;
374 SkPaint::FontMetrics metrics;
375 PaintSetup(&paint);
376 paint.getFontMetrics(&metrics);
377
378 ascent_pixels_ = SkScalarCeil(-metrics.fAscent);
379 height_pixels_ = ascent_pixels_ + SkScalarCeil(metrics.fDescent);
380 }
381
382 void PlatformFontGtk::InitFromPlatformFont(const PlatformFontGtk* other) {
383 typeface_helper_.reset(new SkAutoUnref(other->typeface_));
384 typeface_ = other->typeface_;
385 typeface_->ref();
386 font_family_ = other->font_family_;
387 font_size_pixels_ = other->font_size_pixels_;
388 style_ = other->style_;
389 height_pixels_ = other->height_pixels_;
390 ascent_pixels_ = other->ascent_pixels_;
391 pango_metrics_inited_ = other->pango_metrics_inited_;
392 average_width_pixels_ = other->average_width_pixels_;
393 underline_position_pixels_ = other->underline_position_pixels_;
394 underline_thickness_pixels_ = other->underline_thickness_pixels_;
395 }
396
397 void PlatformFontGtk::PaintSetup(SkPaint* paint) const {
398 paint->setAntiAlias(false);
399 paint->setSubpixelText(false);
400 paint->setTextSize(font_size_pixels_);
401 paint->setTypeface(typeface_);
402 paint->setFakeBoldText((gfx::Font::BOLD & style_) && !typeface_->isBold());
403 paint->setTextSkewX((gfx::Font::ITALIC & style_) && !typeface_->isItalic() ?
404 -SK_Scalar1/4 : 0);
405 }
406
407 void PlatformFontGtk::InitPangoMetrics() {
408 if (!pango_metrics_inited_) {
409 pango_metrics_inited_ = true;
410 PangoFontDescription* pango_desc = GetNativeFont();
411 PangoFontMetrics* pango_metrics = GetPangoFontMetrics(pango_desc);
412
413 underline_position_pixels_ =
414 pango_font_metrics_get_underline_position(pango_metrics) /
415 PANGO_SCALE;
416
417 // TODO(davemoore): Come up with a better solution.
418 // This is a hack, but without doing this the underlines
419 // we get end up fuzzy. So we align to the midpoint of a pixel.
420 underline_position_pixels_ /= 2;
421
422 underline_thickness_pixels_ =
423 pango_font_metrics_get_underline_thickness(pango_metrics) /
424 PANGO_SCALE;
425
426 // First get the Pango-based width (converting from Pango units to pixels).
427 double pango_width_pixels =
428 pango_font_metrics_get_approximate_char_width(pango_metrics) /
429 PANGO_SCALE;
430
431 // Yes, this is how Microsoft recommends calculating the dialog unit
432 // conversions.
433 int text_width_pixels = GetStringWidth(
434 ASCIIToUTF16("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
435 double dialog_units_pixels = (text_width_pixels / 26 + 1) / 2;
436 average_width_pixels_ = std::min(pango_width_pixels, dialog_units_pixels);
437 pango_font_description_free(pango_desc);
438 }
439 }
440
441
442 double PlatformFontGtk::GetAverageWidth() const {
443 const_cast<PlatformFontGtk*>(this)->InitPangoMetrics();
444 return average_width_pixels_;
445 }
446
447 ////////////////////////////////////////////////////////////////////////////////
448 // PlatformFont, public:
449
450 // static
451 PlatformFont* PlatformFont::CreateDefault() {
452 return new PlatformFontGtk;
453 }
454
455 // static
456 PlatformFont* PlatformFont::CreateFromFont(const Font& other) {
457 return new PlatformFontGtk(other);
458 }
459
460 // static
461 PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
462 return new PlatformFontGtk(native_font);
463 }
464
465 // static
466 PlatformFont* PlatformFont::CreateFromNameAndSize(const string16& font_name,
467 int font_size) {
468 return new PlatformFontGtk(font_name, font_size);
469 }
470
471 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/platform_font_gtk.h ('k') | ui/gfx/platform_font_pango.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698