| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "gfx/font.h" | |
| 6 | |
| 7 #include <gdk/gdk.h> | |
| 8 #include <map> | |
| 9 #include <pango/pango.h> | |
| 10 | |
| 11 #include "base/logging.h" | |
| 12 #include "base/string_piece.h" | |
| 13 #include "base/sys_string_conversions.h" | |
| 14 #include "gfx/canvas_skia.h" | |
| 15 #include "third_party/skia/include/core/SkTypeface.h" | |
| 16 #include "third_party/skia/include/core/SkPaint.h" | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 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"; | |
| 24 | |
| 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; | |
| 31 | |
| 32 if (!context) { | |
| 33 context = gdk_pango_context_get_for_screen(gdk_screen_get_default()); | |
| 34 pango_context_set_language(context, pango_language_get_default()); | |
| 35 } | |
| 36 | |
| 37 if (!desc_to_metrics) { | |
| 38 desc_to_metrics = new std::map<int, PangoFontMetrics*>(); | |
| 39 } | |
| 40 | |
| 41 int desc_hash = pango_font_description_hash(desc); | |
| 42 std::map<int, PangoFontMetrics*>::iterator i = | |
| 43 desc_to_metrics->find(desc_hash); | |
| 44 | |
| 45 if (i == desc_to_metrics->end()) { | |
| 46 PangoFontMetrics* metrics = pango_context_get_metrics(context, desc, NULL); | |
| 47 (*desc_to_metrics)[desc_hash] = metrics; | |
| 48 return metrics; | |
| 49 } else { | |
| 50 return i->second; | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 } // namespace | |
| 55 | |
| 56 namespace gfx { | |
| 57 | |
| 58 Font::Font(const Font& other) { | |
| 59 CopyFont(other); | |
| 60 } | |
| 61 | |
| 62 Font& Font::operator=(const Font& other) { | |
| 63 CopyFont(other); | |
| 64 return *this; | |
| 65 } | |
| 66 | |
| 67 Font::Font(SkTypeface* tf, const std::wstring& font_family, int font_size, | |
| 68 int style) | |
| 69 : typeface_helper_(new SkAutoUnref(tf)), | |
| 70 typeface_(tf), | |
| 71 font_family_(font_family), | |
| 72 font_size_(font_size), | |
| 73 style_(style), | |
| 74 pango_metrics_inited_(false), | |
| 75 avg_width_(0.0), | |
| 76 underline_position_(0.0), | |
| 77 underline_thickness_(0.0) { | |
| 78 tf->ref(); | |
| 79 calculateMetrics(); | |
| 80 } | |
| 81 | |
| 82 void Font::calculateMetrics() { | |
| 83 SkPaint paint; | |
| 84 SkPaint::FontMetrics metrics; | |
| 85 PaintSetup(&paint); | |
| 86 paint.getFontMetrics(&metrics); | |
| 87 | |
| 88 ascent_ = SkScalarCeil(-metrics.fAscent); | |
| 89 height_ = ascent_ + SkScalarCeil(metrics.fDescent); | |
| 90 | |
| 91 } | |
| 92 | |
| 93 void Font::CopyFont(const Font& other) { | |
| 94 typeface_helper_.reset(new SkAutoUnref(other.typeface_)); | |
| 95 typeface_ = other.typeface_; | |
| 96 typeface_->ref(); | |
| 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_; | |
| 106 } | |
| 107 | |
| 108 int Font::height() 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); | |
| 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() ? | |
| 175 -SK_Scalar1/4 : 0); | |
| 176 } | |
| 177 | |
| 178 int Font::GetStringWidth(const std::wstring& text) const { | |
| 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_) { | |
| 187 pango_metrics_inited_ = true; | |
| 188 PangoFontDescription* pango_desc = PangoFontFromGfxFont(*this); | |
| 189 PangoFontMetrics* pango_metrics = GetPangoFontMetrics(pango_desc); | |
| 190 | |
| 191 underline_position_ = | |
| 192 pango_font_metrics_get_underline_position(pango_metrics); | |
| 193 underline_position_ /= PANGO_SCALE; | |
| 194 | |
| 195 // todo(davemoore) Come up with a better solution. | |
| 196 // 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. | |
| 198 underline_position_ /= 2; | |
| 199 | |
| 200 underline_thickness_ = | |
| 201 pango_font_metrics_get_underline_thickness(pango_metrics); | |
| 202 underline_thickness_ /= PANGO_SCALE; | |
| 203 | |
| 204 // First get the pango based width | |
| 205 double pango_width = | |
| 206 pango_font_metrics_get_approximate_char_width(pango_metrics); | |
| 207 pango_width /= PANGO_SCALE; | |
| 208 | |
| 209 // Yes, this is how Microsoft recommends calculating the dialog unit | |
| 210 // conversions. | |
| 211 int text_width = GetStringWidth( | |
| 212 L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); | |
| 213 double dialog_units = (text_width / 26 + 1) / 2; | |
| 214 avg_width_ = std::min(pango_width, dialog_units); | |
| 215 pango_font_description_free(pango_desc); | |
| 216 } | |
| 217 } | |
| 218 | |
| 219 double Font::avg_width() const { | |
| 220 const_cast<Font*>(this)->InitPangoMetrics(); | |
| 221 return avg_width_; | |
| 222 } | |
| 223 | |
| 224 double Font::underline_position() const { | |
| 225 const_cast<Font*>(this)->InitPangoMetrics(); | |
| 226 return underline_position_; | |
| 227 } | |
| 228 | |
| 229 double Font::underline_thickness() const { | |
| 230 const_cast<Font*>(this)->InitPangoMetrics(); | |
| 231 return underline_thickness_; | |
| 232 } | |
| 233 | |
| 234 int Font::GetExpectedTextWidth(int length) const { | |
| 235 double char_width = const_cast<Font*>(this)->avg_width(); | |
| 236 return round(static_cast<float>(length) * char_width); | |
| 237 } | |
| 238 | |
| 239 int Font::style() const { | |
| 240 return style_; | |
| 241 } | |
| 242 | |
| 243 const std::wstring& Font::FontName() const { | |
| 244 return font_family_; | |
| 245 } | |
| 246 | |
| 247 int Font::FontSize() { | |
| 248 return font_size_; | |
| 249 } | |
| 250 | |
| 251 NativeFont Font::nativeFont() const { | |
| 252 return typeface_; | |
| 253 } | |
| 254 | |
| 255 } // namespace gfx | |
| OLD | NEW |