base: Change DCHECK_IS_ON to a macro DCHECK_IS_ON().
[chromium-blink-merge.git] / ui / gfx / platform_font_pango.cc
blob67c1b2d9af8ebd4945ae8e7efeabd72a4617441a
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.
5 #include "ui/gfx/platform_font_pango.h"
7 #include <pango/pango.h>
9 #include <algorithm>
10 #include <string>
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"
26 namespace {
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";
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);
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;
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;
56 return typeface;
59 } // namespace
61 namespace gfx {
63 // static
64 Font* PlatformFontPango::default_font_ = NULL;
66 #if defined(OS_CHROMEOS)
67 // static
68 std::string* PlatformFontPango::default_font_description_ = NULL;
69 #endif
71 ////////////////////////////////////////////////////////////////////////////////
72 // PlatformFontPango, public:
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());
91 InitFromPlatformFont(
92 static_cast<PlatformFontPango*>(default_font_->platform_font()));
95 PlatformFontPango::PlatformFontPango(NativeFont native_font) {
96 FontRenderParamsQuery query(false);
97 base::SplitString(pango_font_description_get_family(native_font), ',',
98 &query.families);
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;
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;
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);
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));
132 ////////////////////////////////////////////////////////////////////////////////
133 // PlatformFontPango, PlatformFont implementation:
135 // static
136 void PlatformFontPango::ReloadDefaultFont() {
137 delete default_font_;
138 default_font_ = NULL;
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);
149 #endif
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);
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);
160 FontRenderParamsQuery query(false);
161 query.families.push_back(new_family);
162 query.pixel_size = new_size;
163 query.style = style;
165 return Font(new PlatformFontPango(typeface, new_family, new_size, style,
166 gfx::GetFontRenderParams(query, NULL)));
169 int PlatformFontPango::GetHeight() const {
170 return height_pixels_;
173 int PlatformFontPango::GetBaseline() const {
174 return ascent_pixels_;
177 int PlatformFontPango::GetCapHeight() const {
178 return cap_height_pixels_;
181 int PlatformFontPango::GetExpectedTextWidth(int length) const {
182 return round(static_cast<float>(length) * average_width_pixels_);
185 int PlatformFontPango::GetStyle() const {
186 return style_;
189 std::string PlatformFontPango::GetFontName() const {
190 return font_family_;
193 std::string PlatformFontPango::GetActualFontNameForTesting() const {
194 SkString family_name;
195 typeface_->getFamilyName(&family_name);
196 return family_name.c_str();
199 int PlatformFontPango::GetFontSize() const {
200 return font_size_pixels_;
203 const FontRenderParams& PlatformFontPango::GetFontRenderParams() {
204 #if defined(OS_CHROMEOS)
205 float current_scale_factor = gfx::GetFontRenderParamsDeviceScaleFactor();
206 if (current_scale_factor != device_scale_factor_) {
207 FontRenderParamsQuery query(false);
208 query.families.push_back(font_family_);
209 query.pixel_size = font_size_pixels_;
210 query.style = style_;
211 query.device_scale_factor = current_scale_factor;
212 font_render_params_ = gfx::GetFontRenderParams(query, nullptr);
213 device_scale_factor_ = current_scale_factor;
215 #endif
216 return font_render_params_;
219 NativeFont PlatformFontPango::GetNativeFont() const {
220 PangoFontDescription* pfd = pango_font_description_new();
221 pango_font_description_set_family(pfd, GetFontName().c_str());
222 // Set the absolute size to avoid overflowing UI elements.
223 // pango_font_description_set_absolute_size() takes a size in Pango units.
224 // There are PANGO_SCALE Pango units in one device unit. Screen output
225 // devices use pixels as their device units.
226 pango_font_description_set_absolute_size(
227 pfd, font_size_pixels_ * PANGO_SCALE);
229 switch (GetStyle()) {
230 case gfx::Font::NORMAL:
231 // Nothing to do, should already be PANGO_STYLE_NORMAL.
232 break;
233 case gfx::Font::BOLD:
234 pango_font_description_set_weight(pfd, PANGO_WEIGHT_BOLD);
235 break;
236 case gfx::Font::ITALIC:
237 pango_font_description_set_style(pfd, PANGO_STYLE_ITALIC);
238 break;
239 case gfx::Font::UNDERLINE:
240 // TODO(deanm): How to do underline? Where do we use it? Probably have
241 // to paint it ourselves, see pango_font_metrics_get_underline_position.
242 break;
245 return pfd;
248 ////////////////////////////////////////////////////////////////////////////////
249 // PlatformFontPango, private:
251 PlatformFontPango::PlatformFontPango(const skia::RefPtr<SkTypeface>& typeface,
252 const std::string& name,
253 int size_pixels,
254 int style,
255 const FontRenderParams& render_params) {
256 InitFromDetails(typeface, name, size_pixels, style, render_params);
259 PlatformFontPango::~PlatformFontPango() {}
261 void PlatformFontPango::InitFromDetails(
262 const skia::RefPtr<SkTypeface>& typeface,
263 const std::string& font_family,
264 int font_size_pixels,
265 int style,
266 const FontRenderParams& render_params) {
267 DCHECK_GT(font_size_pixels, 0);
269 font_family_ = font_family;
270 typeface_ = typeface ? typeface : CreateSkTypeface(style, &font_family_);
272 font_size_pixels_ = font_size_pixels;
273 style_ = style;
274 #if defined(OS_CHROMEOS)
275 device_scale_factor_ = gfx::GetFontRenderParamsDeviceScaleFactor();
276 #endif
277 font_render_params_ = render_params;
279 SkPaint paint;
280 paint.setAntiAlias(false);
281 paint.setSubpixelText(false);
282 paint.setTextSize(font_size_pixels_);
283 paint.setTypeface(typeface_.get());
284 paint.setFakeBoldText((gfx::Font::BOLD & style_) && !typeface_->isBold());
285 paint.setTextSkewX((gfx::Font::ITALIC & style_) && !typeface_->isItalic() ?
286 -SK_Scalar1/4 : 0);
287 SkPaint::FontMetrics metrics;
288 paint.getFontMetrics(&metrics);
289 ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent);
290 height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent);
291 cap_height_pixels_ = SkScalarCeilToInt(metrics.fCapHeight);
292 average_width_pixels_ = SkScalarToDouble(metrics.fAvgCharWidth);
295 void PlatformFontPango::InitFromPlatformFont(const PlatformFontPango* other) {
296 typeface_ = other->typeface_;
297 font_family_ = other->font_family_;
298 font_size_pixels_ = other->font_size_pixels_;
299 style_ = other->style_;
300 #if defined(OS_CHROMEOS)
301 device_scale_factor_ = other->device_scale_factor_;
302 #endif
303 font_render_params_ = other->font_render_params_;
304 ascent_pixels_ = other->ascent_pixels_;
305 height_pixels_ = other->height_pixels_;
306 cap_height_pixels_ = other->cap_height_pixels_;
307 average_width_pixels_ = other->average_width_pixels_;
310 ////////////////////////////////////////////////////////////////////////////////
311 // PlatformFont, public:
313 // static
314 PlatformFont* PlatformFont::CreateDefault() {
315 return new PlatformFontPango;
318 // static
319 PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
320 return new PlatformFontPango(native_font);
323 // static
324 PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name,
325 int font_size) {
326 return new PlatformFontPango(font_name, font_size);
329 } // namespace gfx