diff options
author | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-23 04:05:01 +0000 |
---|---|---|
committer | ben@chromium.org <ben@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-23 04:05:01 +0000 |
commit | d07b6b5b992faad3506ac004503c11d25930cdca (patch) | |
tree | a5a795b8980d90e4a10208ad4f8eabe140ee3e5e /gfx/font_skia.cc | |
parent | f2a13d89ca22cdbe3808bcb14e02d5baee8d33b3 (diff) | |
download | chromium_src-d07b6b5b992faad3506ac004503c11d25930cdca.zip chromium_src-d07b6b5b992faad3506ac004503c11d25930cdca.tar.gz chromium_src-d07b6b5b992faad3506ac004503c11d25930cdca.tar.bz2 |
Move app/gfx/canvas and app/gfx/font to gfx/.
TBR=darin
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/1132006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@42312 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gfx/font_skia.cc')
-rw-r--r-- | gfx/font_skia.cc | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/gfx/font_skia.cc b/gfx/font_skia.cc new file mode 100644 index 0000000..fffc53e --- /dev/null +++ b/gfx/font_skia.cc @@ -0,0 +1,255 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gfx/font.h" + +#include <gdk/gdk.h> +#include <map> +#include <pango/pango.h> + +#include "base/logging.h" +#include "base/string_piece.h" +#include "base/sys_string_conversions.h" +#include "gfx/canvas.h" +#include "third_party/skia/include/core/SkTypeface.h" +#include "third_party/skia/include/core/SkPaint.h" + +namespace { + +// The font family name which is used when a user's application font for +// GNOME/KDE is a non-scalable one. The name should be listed in the +// IsFallbackFontAllowed function in skia/ext/SkFontHost_fontconfig_direct.cpp. +const char* kFallbackFontFamilyName = "sans"; + +// Retrieves the pango metrics for a pango font description. Caches the metrics +// and never frees them. The metrics objects are relatively small and +// very expensive to look up. +static PangoFontMetrics* GetPangoFontMetrics(PangoFontDescription* desc) { + static std::map<int, PangoFontMetrics*>* desc_to_metrics = NULL; + static PangoContext* context = NULL; + + if (!context) { + context = gdk_pango_context_get_for_screen(gdk_screen_get_default()); + pango_context_set_language(context, pango_language_get_default()); + } + + if (!desc_to_metrics) { + desc_to_metrics = new std::map<int, PangoFontMetrics*>(); + } + + int desc_hash = pango_font_description_hash(desc); + std::map<int, PangoFontMetrics*>::iterator i = + desc_to_metrics->find(desc_hash); + + if (i == desc_to_metrics->end()) { + PangoFontMetrics* metrics = pango_context_get_metrics(context, desc, NULL); + (*desc_to_metrics)[desc_hash] = metrics; + return metrics; + } else { + return i->second; + } +} + +} // namespace + +namespace gfx { + +Font::Font(const Font& other) { + CopyFont(other); +} + +Font& Font::operator=(const Font& other) { + CopyFont(other); + return *this; +} + +Font::Font(SkTypeface* tf, const std::wstring& font_family, int font_size, + int style) + : typeface_helper_(new SkAutoUnref(tf)), + typeface_(tf), + font_family_(font_family), + font_size_(font_size), + style_(style), + pango_metrics_inited_(false), + avg_width_(0.0), + underline_position_(0.0), + underline_thickness_(0.0) { + tf->ref(); + calculateMetrics(); +} + +void Font::calculateMetrics() { + SkPaint paint; + SkPaint::FontMetrics metrics; + PaintSetup(&paint); + paint.getFontMetrics(&metrics); + + ascent_ = SkScalarCeil(-metrics.fAscent); + height_ = ascent_ + SkScalarCeil(metrics.fDescent); + +} + +void Font::CopyFont(const Font& other) { + typeface_helper_.reset(new SkAutoUnref(other.typeface_)); + typeface_ = other.typeface_; + typeface_->ref(); + font_family_ = other.font_family_; + font_size_ = other.font_size_; + style_ = other.style_; + height_ = other.height_; + ascent_ = other.ascent_; + pango_metrics_inited_ = other.pango_metrics_inited_; + avg_width_ = other.avg_width_; + underline_position_ = other.underline_position_; + underline_thickness_ = other.underline_thickness_; +} + +int Font::height() const { + return height_; +} + +int Font::baseline() const { + return ascent_; +} + +int Font::ave_char_width() const { + return SkScalarRound(avg_width()); +} + +Font Font::CreateFont(const std::wstring& font_family, int font_size) { + DCHECK_GT(font_size, 0); + std::wstring fallback; + + SkTypeface* tf = SkTypeface::CreateFromName( + base::SysWideToUTF8(font_family).c_str(), SkTypeface::kNormal); + if (!tf) { + // A non-scalable font such as .pcf is specified. Falls back to a default + // scalable font. + tf = SkTypeface::CreateFromName( + kFallbackFontFamilyName, SkTypeface::kNormal); + CHECK(tf) << "Could not find any font: " + << base::SysWideToUTF8(font_family) + << ", " << kFallbackFontFamilyName; + fallback = base::SysUTF8ToWide(kFallbackFontFamilyName); + } + SkAutoUnref tf_helper(tf); + + return Font( + tf, fallback.empty() ? font_family : fallback, font_size, NORMAL); +} + +Font Font::DeriveFont(int size_delta, int style) const { + // If the delta is negative, if must not push the size below 1 + if (size_delta < 0) { + DCHECK_LT(-size_delta, font_size_); + } + + if (style == style_) { + // Fast path, we just use the same typeface at a different size + return Font(typeface_, font_family_, font_size_ + size_delta, style_); + } + + // If the style has changed we may need to load a new face + int skstyle = SkTypeface::kNormal; + if (BOLD & style) + skstyle |= SkTypeface::kBold; + if (ITALIC & style) + skstyle |= SkTypeface::kItalic; + + SkTypeface* tf = SkTypeface::CreateFromName( + base::SysWideToUTF8(font_family_).c_str(), + static_cast<SkTypeface::Style>(skstyle)); + SkAutoUnref tf_helper(tf); + + return Font(tf, font_family_, font_size_ + size_delta, style); +} + +void Font::PaintSetup(SkPaint* paint) const { + paint->setAntiAlias(false); + paint->setSubpixelText(false); + paint->setTextSize(SkFloatToScalar(font_size_ * Font::GetPangoScaleFactor())); + paint->setTypeface(typeface_); + paint->setFakeBoldText((BOLD & style_) && !typeface_->isBold()); + paint->setTextSkewX((ITALIC & style_) && !typeface_->isItalic() ? + -SK_Scalar1/4 : 0); +} + +int Font::GetStringWidth(const std::wstring& text) const { + int width = 0, height = 0; + + Canvas::SizeStringInt(text, *this, &width, &height, 0); + return width; +} + +void Font::InitPangoMetrics() { + if (!pango_metrics_inited_) { + pango_metrics_inited_ = true; + PangoFontDescription* pango_desc = PangoFontFromGfxFont(*this); + PangoFontMetrics* pango_metrics = GetPangoFontMetrics(pango_desc); + + underline_position_ = + pango_font_metrics_get_underline_position(pango_metrics); + underline_position_ /= PANGO_SCALE; + + // todo(davemoore) Come up with a better solution. + // This is a hack, but without doing this the underlines + // we get end up fuzzy. So we align to the midpoint of a pixel. + underline_position_ /= 2; + + underline_thickness_ = + pango_font_metrics_get_underline_thickness(pango_metrics); + underline_thickness_ /= PANGO_SCALE; + + // First get the pango based width + double pango_width = + pango_font_metrics_get_approximate_char_width(pango_metrics); + pango_width /= PANGO_SCALE; + + // Yes, this is how Microsoft recommends calculating the dialog unit + // conversions. + int text_width = GetStringWidth( + L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); + double dialog_units = (text_width / 26 + 1) / 2; + avg_width_ = std::min(pango_width, dialog_units); + pango_font_description_free(pango_desc); + } +} + +double Font::avg_width() const { + const_cast<Font*>(this)->InitPangoMetrics(); + return avg_width_; +} + +double Font::underline_position() const { + const_cast<Font*>(this)->InitPangoMetrics(); + return underline_position_; +} + +double Font::underline_thickness() const { + const_cast<Font*>(this)->InitPangoMetrics(); + return underline_thickness_; +} + +int Font::GetExpectedTextWidth(int length) const { + double char_width = const_cast<Font*>(this)->avg_width(); + return round(static_cast<float>(length) * char_width); +} + +int Font::style() const { + return style_; +} + +const std::wstring& Font::FontName() const { + return font_family_; +} + +int Font::FontSize() { + return font_size_; +} + +NativeFont Font::nativeFont() const { + return typeface_; +} + +} // namespace gfx |