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