| OLD | NEW |
| (Empty) |
| 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 | |
| OLD | NEW |