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

Side by Side Diff: gfx/platform_font_gtk.cc

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

Powered by Google App Engine
This is Rietveld 408576698