Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / gfx / platform_font_pango.cc
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.
4
5 #include "ui/gfx/platform_font_pango.h"
6
7 #include <pango/pango.h>
8
9 #include <algorithm>
10 #include <string>
11
12 #include "base/logging.h"
13 #include "base/strings/string_piece.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "third_party/skia/include/core/SkPaint.h"
17 #include "third_party/skia/include/core/SkString.h"
18 #include "third_party/skia/include/core/SkTypeface.h"
19 #include "ui/gfx/canvas.h"
20 #include "ui/gfx/font.h"
21 #include "ui/gfx/font_list.h"
22 #include "ui/gfx/linux_font_delegate.h"
23 #include "ui/gfx/pango_util.h"
24 #include "ui/gfx/text_utils.h"
25
26 namespace {
27
28 // The font family name which is used when a user's application font for
29 // GNOME/KDE is a non-scalable one. The name should be listed in the
30 // IsFallbackFontAllowed function in skia/ext/SkFontHost_fontconfig_direct.cpp.
31 const char* kFallbackFontFamilyName = "sans";
32
33 // Creates a SkTypeface for the passed-in Font::FontStyle and family. If a
34 // fallback typeface is used instead of the requested family, |family| will be
35 // updated to contain the fallback's family name.
36 skia::RefPtr<SkTypeface> CreateSkTypeface(int style, std::string* family) {
37   DCHECK(family);
38
39   int skia_style = SkTypeface::kNormal;
40   if (gfx::Font::BOLD & style)
41     skia_style |= SkTypeface::kBold;
42   if (gfx::Font::ITALIC & style)
43     skia_style |= SkTypeface::kItalic;
44
45   skia::RefPtr<SkTypeface> typeface = skia::AdoptRef(SkTypeface::CreateFromName(
46       family->c_str(), static_cast<SkTypeface::Style>(skia_style)));
47   if (!typeface) {
48     // A non-scalable font such as .pcf is specified. Fall back to a default
49     // scalable font.
50     typeface = skia::AdoptRef(SkTypeface::CreateFromName(
51         kFallbackFontFamilyName, static_cast<SkTypeface::Style>(skia_style)));
52     CHECK(typeface) << "Could not find any font: " << family << ", "
53                     << kFallbackFontFamilyName;
54     *family = kFallbackFontFamilyName;
55   }
56   return typeface;
57 }
58
59 }  // namespace
60
61 namespace gfx {
62
63 // static
64 Font* PlatformFontPango::default_font_ = NULL;
65
66 #if defined(OS_CHROMEOS)
67 // static
68 std::string* PlatformFontPango::default_font_description_ = NULL;
69 #endif
70
71 ////////////////////////////////////////////////////////////////////////////////
72 // PlatformFontPango, public:
73
74 PlatformFontPango::PlatformFontPango() {
75   if (!default_font_) {
76     scoped_ptr<ScopedPangoFontDescription> description;
77 #if defined(OS_CHROMEOS)
78     CHECK(default_font_description_);
79     description.reset(
80         new ScopedPangoFontDescription(*default_font_description_));
81 #else
82     const gfx::LinuxFontDelegate* delegate = gfx::LinuxFontDelegate::instance();
83     if (delegate)
84       description = delegate->GetDefaultPangoFontDescription();
85 #endif
86     if (!description || !description->get())
87       description.reset(new ScopedPangoFontDescription("sans 10"));
88     default_font_ = new Font(description->get());
89   }
90
91   InitFromPlatformFont(
92       static_cast<PlatformFontPango*>(default_font_->platform_font()));
93 }
94
95 PlatformFontPango::PlatformFontPango(NativeFont native_font) {
96   FontRenderParamsQuery query(false);
97   base::SplitString(pango_font_description_get_family(native_font), ',',
98                     &query.families);
99
100   const int pango_size =
101       pango_font_description_get_size(native_font) / PANGO_SCALE;
102   if (pango_font_description_get_size_is_absolute(native_font))
103     query.pixel_size = pango_size;
104   else
105     query.point_size = pango_size;
106
107   query.style = gfx::Font::NORMAL;
108   // TODO(davemoore): Support weights other than bold?
109   if (pango_font_description_get_weight(native_font) == PANGO_WEIGHT_BOLD)
110     query.style |= gfx::Font::BOLD;
111   // TODO(davemoore): What about PANGO_STYLE_OBLIQUE?
112   if (pango_font_description_get_style(native_font) == PANGO_STYLE_ITALIC)
113     query.style |= gfx::Font::ITALIC;
114
115   std::string font_family;
116   const FontRenderParams params = gfx::GetFontRenderParams(query, &font_family);
117   InitFromDetails(skia::RefPtr<SkTypeface>(), font_family,
118                   gfx::GetPangoFontSizeInPixels(native_font),
119                   query.style, params);
120 }
121
122 PlatformFontPango::PlatformFontPango(const std::string& font_name,
123                                      int font_size_pixels) {
124   FontRenderParamsQuery query(false);
125   query.families.push_back(font_name);
126   query.pixel_size = font_size_pixels;
127   query.style = gfx::Font::NORMAL;
128   InitFromDetails(skia::RefPtr<SkTypeface>(), font_name, font_size_pixels,
129                   query.style, gfx::GetFontRenderParams(query, NULL));
130 }
131
132 ////////////////////////////////////////////////////////////////////////////////
133 // PlatformFontPango, PlatformFont implementation:
134
135 // static
136 void PlatformFontPango::ReloadDefaultFont() {
137   delete default_font_;
138   default_font_ = NULL;
139 }
140
141 #if defined(OS_CHROMEOS)
142 // static
143 void PlatformFontPango::SetDefaultFontDescription(
144     const std::string& font_description) {
145   delete default_font_description_;
146   default_font_description_ = new std::string(font_description);
147 }
148
149 #endif
150
151 Font PlatformFontPango::DeriveFont(int size_delta, int style) const {
152   const int new_size = font_size_pixels_ + size_delta;
153   DCHECK_GT(new_size, 0);
154
155   // If the style changed, we may need to load a new face.
156   std::string new_family = font_family_;
157   skia::RefPtr<SkTypeface> typeface =
158       (style == style_) ? typeface_ : CreateSkTypeface(style, &new_family);
159
160   FontRenderParamsQuery query(false);
161   query.families.push_back(new_family);
162   query.pixel_size = new_size;
163   query.style = style;
164
165   return Font(new PlatformFontPango(typeface, new_family, new_size, style,
166                                     gfx::GetFontRenderParams(query, NULL)));
167 }
168
169 int PlatformFontPango::GetHeight() const {
170   return height_pixels_;
171 }
172
173 int PlatformFontPango::GetBaseline() const {
174   return ascent_pixels_;
175 }
176
177 int PlatformFontPango::GetCapHeight() const {
178   return cap_height_pixels_;
179 }
180
181 int PlatformFontPango::GetExpectedTextWidth(int length) const {
182   double char_width = const_cast<PlatformFontPango*>(this)->GetAverageWidth();
183   return round(static_cast<float>(length) * char_width);
184 }
185
186 int PlatformFontPango::GetStyle() const {
187   return style_;
188 }
189
190 std::string PlatformFontPango::GetFontName() const {
191   return font_family_;
192 }
193
194 std::string PlatformFontPango::GetActualFontNameForTesting() const {
195   SkString family_name;
196   typeface_->getFamilyName(&family_name);
197   return family_name.c_str();
198 }
199
200 int PlatformFontPango::GetFontSize() const {
201   return font_size_pixels_;
202 }
203
204 const FontRenderParams& PlatformFontPango::GetFontRenderParams() const {
205   return font_render_params_;
206 }
207
208 NativeFont PlatformFontPango::GetNativeFont() const {
209   PangoFontDescription* pfd = pango_font_description_new();
210   pango_font_description_set_family(pfd, GetFontName().c_str());
211   // Set the absolute size to avoid overflowing UI elements.
212   // pango_font_description_set_absolute_size() takes a size in Pango units.
213   // There are PANGO_SCALE Pango units in one device unit.  Screen output
214   // devices use pixels as their device units.
215   pango_font_description_set_absolute_size(
216       pfd, font_size_pixels_ * PANGO_SCALE);
217
218   switch (GetStyle()) {
219     case gfx::Font::NORMAL:
220       // Nothing to do, should already be PANGO_STYLE_NORMAL.
221       break;
222     case gfx::Font::BOLD:
223       pango_font_description_set_weight(pfd, PANGO_WEIGHT_BOLD);
224       break;
225     case gfx::Font::ITALIC:
226       pango_font_description_set_style(pfd, PANGO_STYLE_ITALIC);
227       break;
228     case gfx::Font::UNDERLINE:
229       // TODO(deanm): How to do underline?  Where do we use it?  Probably have
230       // to paint it ourselves, see pango_font_metrics_get_underline_position.
231       break;
232   }
233
234   return pfd;
235 }
236
237 ////////////////////////////////////////////////////////////////////////////////
238 // PlatformFontPango, private:
239
240 PlatformFontPango::PlatformFontPango(const skia::RefPtr<SkTypeface>& typeface,
241                                      const std::string& name,
242                                      int size_pixels,
243                                      int style,
244                                      const FontRenderParams& render_params) {
245   InitFromDetails(typeface, name, size_pixels, style, render_params);
246 }
247
248 PlatformFontPango::~PlatformFontPango() {}
249
250 void PlatformFontPango::InitFromDetails(
251     const skia::RefPtr<SkTypeface>& typeface,
252     const std::string& font_family,
253     int font_size_pixels,
254     int style,
255     const FontRenderParams& render_params) {
256   DCHECK_GT(font_size_pixels, 0);
257
258   font_family_ = font_family;
259   typeface_ = typeface ? typeface : CreateSkTypeface(style, &font_family_);
260
261   font_size_pixels_ = font_size_pixels;
262   style_ = style;
263   font_render_params_ = render_params;
264
265   SkPaint paint;
266   SkPaint::FontMetrics metrics;
267   PaintSetup(&paint);
268   paint.getFontMetrics(&metrics);
269   ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent);
270   height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent);
271   cap_height_pixels_ = SkScalarCeilToInt(metrics.fCapHeight);
272
273   pango_metrics_inited_ = false;
274   average_width_pixels_ = 0.0f;
275 }
276
277 void PlatformFontPango::InitFromPlatformFont(const PlatformFontPango* other) {
278   typeface_ = other->typeface_;
279   font_family_ = other->font_family_;
280   font_size_pixels_ = other->font_size_pixels_;
281   style_ = other->style_;
282   font_render_params_ = other->font_render_params_;
283   ascent_pixels_ = other->ascent_pixels_;
284   height_pixels_ = other->height_pixels_;
285   cap_height_pixels_ = other->cap_height_pixels_;
286   pango_metrics_inited_ = other->pango_metrics_inited_;
287   average_width_pixels_ = other->average_width_pixels_;
288 }
289
290 void PlatformFontPango::PaintSetup(SkPaint* paint) const {
291   paint->setAntiAlias(false);
292   paint->setSubpixelText(false);
293   paint->setTextSize(font_size_pixels_);
294   paint->setTypeface(typeface_.get());
295   paint->setFakeBoldText((gfx::Font::BOLD & style_) && !typeface_->isBold());
296   paint->setTextSkewX((gfx::Font::ITALIC & style_) && !typeface_->isItalic() ?
297                       -SK_Scalar1/4 : 0);
298 }
299
300 void PlatformFontPango::InitPangoMetrics() {
301   if (!pango_metrics_inited_) {
302     pango_metrics_inited_ = true;
303     ScopedPangoFontDescription pango_desc(GetNativeFont());
304     PangoFontMetrics* pango_metrics = GetPangoFontMetrics(pango_desc.get());
305
306     // First get the Pango-based width (converting from Pango units to pixels).
307     const double pango_width_pixels =
308         pango_font_metrics_get_approximate_char_width(pango_metrics) /
309         PANGO_SCALE;
310
311     // Yes, this is how Microsoft recommends calculating the dialog unit
312     // conversions.
313     const int text_width_pixels = GetStringWidth(
314         base::ASCIIToUTF16(
315             "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),
316         FontList(Font(this)));
317     const double dialog_units_pixels = (text_width_pixels / 26 + 1) / 2;
318     average_width_pixels_ = std::min(pango_width_pixels, dialog_units_pixels);
319   }
320 }
321
322 double PlatformFontPango::GetAverageWidth() const {
323   const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
324   return average_width_pixels_;
325 }
326
327 ////////////////////////////////////////////////////////////////////////////////
328 // PlatformFont, public:
329
330 // static
331 PlatformFont* PlatformFont::CreateDefault() {
332   return new PlatformFontPango;
333 }
334
335 // static
336 PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
337   return new PlatformFontPango(native_font);
338 }
339
340 // static
341 PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
342                                                   int font_size) {
343   return new PlatformFontPango(font_name, font_size);
344 }
345
346 }  // namespace gfx