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.
9 #include <pango/pango.h>
11 #include "base/logging.h"
12 #include "base/string_piece.h"
13 #include "base/sys_string_conversions.h"
14 #include "gfx/canvas.h"
15 #include "third_party/skia/include/core/SkTypeface.h"
16 #include "third_party/skia/include/core/SkPaint.h"
20 // 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
22 // IsFallbackFontAllowed function in skia/ext/SkFontHost_fontconfig_direct.cpp.
23 const char* kFallbackFontFamilyName
= "sans";
25 // Retrieves the pango metrics for a pango font description. Caches the metrics
26 // and never frees them. The metrics objects are relatively small and
27 // very expensive to look up.
28 static PangoFontMetrics
* GetPangoFontMetrics(PangoFontDescription
* desc
) {
29 static std::map
<int, PangoFontMetrics
*>* desc_to_metrics
= NULL
;
30 static PangoContext
* context
= NULL
;
33 context
= gdk_pango_context_get_for_screen(gdk_screen_get_default());
34 pango_context_set_language(context
, pango_language_get_default());
37 if (!desc_to_metrics
) {
38 desc_to_metrics
= new std::map
<int, PangoFontMetrics
*>();
41 int desc_hash
= pango_font_description_hash(desc
);
42 std::map
<int, PangoFontMetrics
*>::iterator i
=
43 desc_to_metrics
->find(desc_hash
);
45 if (i
== desc_to_metrics
->end()) {
46 PangoFontMetrics
* metrics
= pango_context_get_metrics(context
, desc
, NULL
);
47 (*desc_to_metrics
)[desc_hash
] = metrics
;
58 Font::Font(const Font
& other
) {
62 Font
& Font::operator=(const Font
& other
) {
67 Font::Font(SkTypeface
* tf
, const std::wstring
& font_family
, int font_size
,
69 : typeface_helper_(new SkAutoUnref(tf
)),
71 font_family_(font_family
),
72 font_size_(font_size
),
74 pango_metrics_inited_(false),
76 underline_position_(0.0),
77 underline_thickness_(0.0) {
82 void Font::calculateMetrics() {
84 SkPaint::FontMetrics metrics
;
86 paint
.getFontMetrics(&metrics
);
88 ascent_
= SkScalarCeil(-metrics
.fAscent
);
89 height_
= ascent_
+ SkScalarCeil(metrics
.fDescent
);
93 void Font::CopyFont(const Font
& other
) {
94 typeface_helper_
.reset(new SkAutoUnref(other
.typeface_
));
95 typeface_
= other
.typeface_
;
97 font_family_
= other
.font_family_
;
98 font_size_
= other
.font_size_
;
99 style_
= other
.style_
;
100 height_
= other
.height_
;
101 ascent_
= other
.ascent_
;
102 pango_metrics_inited_
= other
.pango_metrics_inited_
;
103 avg_width_
= other
.avg_width_
;
104 underline_position_
= other
.underline_position_
;
105 underline_thickness_
= other
.underline_thickness_
;
108 int Font::height() const {
112 int Font::baseline() const {
116 int Font::ave_char_width() const {
117 return SkScalarRound(avg_width());
120 Font
Font::CreateFont(const std::wstring
& font_family
, int font_size
) {
121 DCHECK_GT(font_size
, 0);
122 std::wstring fallback
;
124 SkTypeface
* tf
= SkTypeface::CreateFromName(
125 base::SysWideToUTF8(font_family
).c_str(), SkTypeface::kNormal
);
127 // A non-scalable font such as .pcf is specified. Falls back to a default
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
);
136 SkAutoUnref
tf_helper(tf
);
139 tf
, fallback
.empty() ? font_family
: fallback
, font_size
, NORMAL
);
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_
);
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_
);
153 // If the style has changed we may need to load a new face
154 int skstyle
= SkTypeface::kNormal
;
156 skstyle
|= SkTypeface::kBold
;
158 skstyle
|= SkTypeface::kItalic
;
160 SkTypeface
* tf
= SkTypeface::CreateFromName(
161 base::SysWideToUTF8(font_family_
).c_str(),
162 static_cast<SkTypeface::Style
>(skstyle
));
163 SkAutoUnref
tf_helper(tf
);
165 return Font(tf
, font_family_
, font_size_
+ size_delta
, style
);
168 void Font::PaintSetup(SkPaint
* paint
) const {
169 paint
->setAntiAlias(false);
170 paint
->setSubpixelText(false);
171 paint
->setTextSize(SkFloatToScalar(font_size_
* Font::GetPangoScaleFactor()));
172 paint
->setTypeface(typeface_
);
173 paint
->setFakeBoldText((BOLD
& style_
) && !typeface_
->isBold());
174 paint
->setTextSkewX((ITALIC
& style_
) && !typeface_
->isItalic() ?
178 int Font::GetStringWidth(const std::wstring
& text
) const {
179 int width
= 0, height
= 0;
180 Canvas::SizeStringInt(text
, *this, &width
, &height
, gfx::Canvas::NO_ELLIPSIS
);
184 void Font::InitPangoMetrics() {
185 if (!pango_metrics_inited_
) {
186 pango_metrics_inited_
= true;
187 PangoFontDescription
* pango_desc
= PangoFontFromGfxFont(*this);
188 PangoFontMetrics
* pango_metrics
= GetPangoFontMetrics(pango_desc
);
190 underline_position_
=
191 pango_font_metrics_get_underline_position(pango_metrics
);
192 underline_position_
/= PANGO_SCALE
;
194 // todo(davemoore) Come up with a better solution.
195 // This is a hack, but without doing this the underlines
196 // we get end up fuzzy. So we align to the midpoint of a pixel.
197 underline_position_
/= 2;
199 underline_thickness_
=
200 pango_font_metrics_get_underline_thickness(pango_metrics
);
201 underline_thickness_
/= PANGO_SCALE
;
203 // First get the pango based width
205 pango_font_metrics_get_approximate_char_width(pango_metrics
);
206 pango_width
/= PANGO_SCALE
;
208 // Yes, this is how Microsoft recommends calculating the dialog unit
210 int text_width
= GetStringWidth(
211 L
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
212 double dialog_units
= (text_width
/ 26 + 1) / 2;
213 avg_width_
= std::min(pango_width
, dialog_units
);
214 pango_font_description_free(pango_desc
);
218 double Font::avg_width() const {
219 const_cast<Font
*>(this)->InitPangoMetrics();
223 double Font::underline_position() const {
224 const_cast<Font
*>(this)->InitPangoMetrics();
225 return underline_position_
;
228 double Font::underline_thickness() const {
229 const_cast<Font
*>(this)->InitPangoMetrics();
230 return underline_thickness_
;
233 int Font::GetExpectedTextWidth(int length
) const {
234 double char_width
= const_cast<Font
*>(this)->avg_width();
235 return round(static_cast<float>(length
) * char_width
);
238 int Font::style() const {
242 const std::wstring
& Font::FontName() const {
246 int Font::FontSize() {
250 NativeFont
Font::nativeFont() const {