Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(825)

Unified Diff: gfx/platform_font_gtk.cc

Issue 3083022: Rework gfx::Font by moving platform-specific code into inner classes.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gfx/platform_font_gtk.h ('k') | gfx/platform_font_mac.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: gfx/platform_font_gtk.cc
===================================================================
--- gfx/platform_font_gtk.cc (revision 55264)
+++ gfx/platform_font_gtk.cc (working copy)
@@ -2,16 +2,22 @@
// 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 "gfx/platform_font_gtk.h"
+#include <algorithm>
+#include <fontconfig/fontconfig.h>
#include <gdk/gdk.h>
+#include <gtk/gtk.h>
#include <map>
#include <pango/pango.h>
#include "base/logging.h"
#include "base/string_piece.h"
#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
#include "gfx/canvas_skia.h"
+#include "gfx/font.h"
+#include "gfx/gtk_util.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/core/SkPaint.h"
@@ -25,7 +31,7 @@
// 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) {
+PangoFontMetrics* GetPangoFontMetrics(PangoFontDescription* desc) {
static std::map<int, PangoFontMetrics*>* desc_to_metrics = NULL;
static PangoContext* context = NULL;
@@ -51,141 +57,301 @@
}
}
+// Find the best match font for |family_name| in the same way as Skia
+// to make sure CreateFont() successfully creates a default font. In
+// Skia, it only checks the best match font. If it failed to find
+// one, SkTypeface will be NULL for that font family. It eventually
+// causes a segfault. For example, family_name = "Sans" and system
+// may have various fonts. The first font family in FcPattern will be
+// "DejaVu Sans" but a font family returned by FcFontMatch will be "VL
+// PGothic". In this case, SkTypeface for "Sans" returns NULL even if
+// the system has a font for "Sans" font family. See FontMatch() in
+// skia/ports/SkFontHost_fontconfig.cpp for more detail.
+std::wstring FindBestMatchFontFamilyName(const char* family_name) {
+ FcPattern* pattern = FcPatternCreate();
+ FcValue fcvalue;
+ fcvalue.type = FcTypeString;
+ char* family_name_copy = strdup(family_name);
+ fcvalue.u.s = reinterpret_cast<FcChar8*>(family_name_copy);
+ FcPatternAdd(pattern, FC_FAMILY, fcvalue, 0);
+ FcConfigSubstitute(0, pattern, FcMatchPattern);
+ FcDefaultSubstitute(pattern);
+ FcResult result;
+ FcPattern* match = FcFontMatch(0, pattern, &result);
+ DCHECK(match) << "Could not find font: " << family_name;
+ FcChar8* match_family;
+ FcPatternGetString(match, FC_FAMILY, 0, &match_family);
+
+ std::wstring font_family = UTF8ToWide(reinterpret_cast<char*>(match_family));
+ FcPatternDestroy(match);
+ FcPatternDestroy(pattern);
+ free(family_name_copy);
+ return font_family;
+}
+
} // namespace
namespace gfx {
-Font::Font(const Font& other) {
- CopyFont(other);
+Font* PlatformFontGtk::default_font_ = NULL;
+
+////////////////////////////////////////////////////////////////////////////////
+// PlatformFontGtk, public:
+
+PlatformFontGtk::PlatformFontGtk() {
+ if (default_font_ == NULL) {
+ GtkSettings* settings = gtk_settings_get_default();
+
+ gchar* font_name = NULL;
+ g_object_get(settings, "gtk-font-name", &font_name, NULL);
+
+ // Temporary CHECK for helping track down
+ // http://code.google.com/p/chromium/issues/detail?id=12530
+ CHECK(font_name) << " Unable to get gtk-font-name for default font.";
+
+ PangoFontDescription* desc =
+ pango_font_description_from_string(font_name);
+ default_font_ = new Font(desc);
+ pango_font_description_free(desc);
+ g_free(font_name);
+
+ DCHECK(default_font_);
+ }
+
+ InitFromPlatformFont(
+ static_cast<PlatformFontGtk*>(default_font_->platform_font()));
}
-Font& Font::operator=(const Font& other) {
- CopyFont(other);
- return *this;
+PlatformFontGtk::PlatformFontGtk(const Font& other) {
+ InitFromPlatformFont(
+ static_cast<PlatformFontGtk*>(other.platform_font()));
}
-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();
+PlatformFontGtk::PlatformFontGtk(NativeFont native_font) {
+ gint size = pango_font_description_get_size(native_font);
+ const char* family_name = pango_font_description_get_family(native_font);
+
+ // Find best match font for |family_name| to make sure we can get
+ // a SkTypeface for the default font.
+ // TODO(agl): remove this.
+ std::wstring font_family = FindBestMatchFontFamilyName(family_name);
+
+ InitWithNameAndSize(font_family, size / PANGO_SCALE);
+ int style = 0;
+ if (pango_font_description_get_weight(native_font) == PANGO_WEIGHT_BOLD) {
+ // TODO(davemoore) What should we do about other weights? We currently
+ // only support BOLD.
+ style |= gfx::Font::BOLD;
+ }
+ if (pango_font_description_get_style(native_font) == PANGO_STYLE_ITALIC) {
+ // TODO(davemoore) What about PANGO_STYLE_OBLIQUE?
+ style |= gfx::Font::ITALIC;
+ }
+ if (style != 0)
+ style_ = style;
}
-void Font::calculateMetrics() {
- SkPaint paint;
- SkPaint::FontMetrics metrics;
- PaintSetup(&paint);
- paint.getFontMetrics(&metrics);
+PlatformFontGtk::PlatformFontGtk(const std::wstring& font_name,
+ int font_size) {
+ InitWithNameAndSize(font_name, font_size);
+}
- ascent_ = SkScalarCeil(-metrics.fAscent);
- height_ = ascent_ + SkScalarCeil(metrics.fDescent);
+double PlatformFontGtk::underline_position() const {
+ const_cast<PlatformFontGtk*>(this)->InitPangoMetrics();
+ return underline_position_;
+}
+double PlatformFontGtk::underline_thickness() const {
+ const_cast<PlatformFontGtk*>(this)->InitPangoMetrics();
+ return underline_thickness_;
}
-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_;
+////////////////////////////////////////////////////////////////////////////////
+// PlatformFontGtk, PlatformFont implementation:
+
+Font PlatformFontGtk::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(new PlatformFontGtk(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 (gfx::Font::BOLD & style)
+ skstyle |= SkTypeface::kBold;
+ if (gfx::Font::ITALIC & style)
+ skstyle |= SkTypeface::kItalic;
+
+ SkTypeface* typeface = SkTypeface::CreateFromName(
+ base::SysWideToUTF8(font_family_).c_str(),
+ static_cast<SkTypeface::Style>(skstyle));
+ SkAutoUnref tf_helper(typeface);
+
+ return Font(new PlatformFontGtk(typeface,
+ font_family_,
+ font_size_ + size_delta,
+ style));
}
-int Font::height() const {
+int PlatformFontGtk::GetHeight() const {
return height_;
}
-int Font::baseline() const {
+int PlatformFontGtk::GetBaseline() const {
return ascent_;
}
-int Font::ave_char_width() const {
- return SkScalarRound(avg_width());
+int PlatformFontGtk::GetAverageCharacterWidth() const {
+ return SkScalarRound(average_width_);
}
-Font Font::CreateFont(const std::wstring& font_family, int font_size) {
+int PlatformFontGtk::GetStringWidth(const std::wstring& text) const {
+ int width = 0, height = 0;
+ CanvasSkia::SizeStringInt(text, Font(const_cast<PlatformFontGtk*>(this)),
+ &width, &height, gfx::Canvas::NO_ELLIPSIS);
+ return width;
+}
+
+int PlatformFontGtk::GetExpectedTextWidth(int length) const {
+ double char_width = const_cast<PlatformFontGtk*>(this)->GetAverageWidth();
+ return round(static_cast<float>(length) * char_width);
+}
+
+int PlatformFontGtk::GetStyle() const {
+ return style_;
+}
+
+const std::wstring& PlatformFontGtk::GetFontName() const {
+ return font_family_;
+}
+
+int PlatformFontGtk::GetFontSize() const {
+ return font_size_;
+}
+
+NativeFont PlatformFontGtk::GetNativeFont() const {
+ PangoFontDescription* pfd = pango_font_description_new();
+ pango_font_description_set_family(pfd, WideToUTF8(GetFontName()).c_str());
+ // Set the absolute size to avoid overflowing UI elements.
+ pango_font_description_set_absolute_size(pfd,
+ GetFontSize() * PANGO_SCALE * GetPangoScaleFactor());
+
+ switch (GetStyle()) {
+ case gfx::Font::NORMAL:
+ // Nothing to do, should already be PANGO_STYLE_NORMAL.
+ break;
+ case gfx::Font::BOLD:
+ pango_font_description_set_weight(pfd, PANGO_WEIGHT_BOLD);
+ break;
+ case gfx::Font::ITALIC:
+ pango_font_description_set_style(pfd, PANGO_STYLE_ITALIC);
+ break;
+ case gfx::Font::UNDERLINED:
+ // TODO(deanm): How to do underlined? Where do we use it? Probably have
+ // to paint it ourselves, see pango_font_metrics_get_underline_position.
+ break;
+ }
+
+ return pfd;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PlatformFontGtk, private:
+
+PlatformFontGtk::PlatformFontGtk(SkTypeface* typeface,
+ const std::wstring& name,
+ int size,
+ int style) {
+ InitWithTypefaceNameSizeAndStyle(typeface, name, size, style);
+}
+
+void PlatformFontGtk::InitWithNameAndSize(const std::wstring& font_name,
+ 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) {
+ SkTypeface* typeface = SkTypeface::CreateFromName(
+ base::SysWideToUTF8(font_name).c_str(), SkTypeface::kNormal);
+ if (!typeface) {
// A non-scalable font such as .pcf is specified. Falls back to a default
// scalable font.
- tf = SkTypeface::CreateFromName(
+ typeface = SkTypeface::CreateFromName(
kFallbackFontFamilyName, SkTypeface::kNormal);
- CHECK(tf) << "Could not find any font: "
- << base::SysWideToUTF8(font_family)
- << ", " << kFallbackFontFamilyName;
+ CHECK(typeface) << "Could not find any font: "
+ << base::SysWideToUTF8(font_name)
+ << ", " << kFallbackFontFamilyName;
fallback = base::SysUTF8ToWide(kFallbackFontFamilyName);
}
- SkAutoUnref tf_helper(tf);
+ SkAutoUnref typeface_helper(typeface);
- return Font(
- tf, fallback.empty() ? font_family : fallback, font_size, NORMAL);
+ InitWithTypefaceNameSizeAndStyle(typeface,
+ fallback.empty() ? font_name : fallback,
+ font_size,
+ gfx::Font::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_);
- }
+void PlatformFontGtk::InitWithTypefaceNameSizeAndStyle(
+ SkTypeface* typeface,
+ const std::wstring& font_family,
+ int font_size,
+ int style) {
+ typeface_helper_.reset(new SkAutoUnref(typeface));
+ typeface_ = typeface;
+ typeface_->ref();
+ font_family_ = font_family;
+ font_size_ = font_size;
+ style_ = style;
+ pango_metrics_inited_ = false;
+ average_width_ = 0.0f;
+ underline_position_ = 0.0f;
+ underline_thickness_ = 0.0f;
- 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_);
- }
+ SkPaint paint;
+ SkPaint::FontMetrics metrics;
+ PaintSetup(&paint);
+ paint.getFontMetrics(&metrics);
- // 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;
+ ascent_ = SkScalarCeil(-metrics.fAscent);
+ height_ = ascent_ + SkScalarCeil(metrics.fDescent);
+}
- 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 PlatformFontGtk::InitFromPlatformFont(const PlatformFontGtk* 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_;
+ average_width_ = other->average_width_;
+ underline_position_ = other->underline_position_;
+ underline_thickness_ = other->underline_thickness_;
}
-void Font::PaintSetup(SkPaint* paint) const {
+void PlatformFontGtk::PaintSetup(SkPaint* paint) const {
paint->setAntiAlias(false);
paint->setSubpixelText(false);
- paint->setTextSize(SkFloatToScalar(font_size_ * Font::GetPangoScaleFactor()));
+ paint->setTextSize(
+ SkFloatToScalar(font_size_ * PlatformFontGtk::GetPangoScaleFactor()));
paint->setTypeface(typeface_);
- paint->setFakeBoldText((BOLD & style_) && !typeface_->isBold());
- paint->setTextSkewX((ITALIC & style_) && !typeface_->isItalic() ?
+ paint->setFakeBoldText((gfx::Font::BOLD & style_) && !typeface_->isBold());
+ paint->setTextSkewX((gfx::Font::ITALIC & style_) && !typeface_->isItalic() ?
-SK_Scalar1/4 : 0);
}
-int Font::GetStringWidth(const std::wstring& text) const {
- int width = 0, height = 0;
- CanvasSkia::SizeStringInt(text, *this, &width, &height,
- gfx::Canvas::NO_ELLIPSIS);
- return width;
-}
-
-void Font::InitPangoMetrics() {
+void PlatformFontGtk::InitPangoMetrics() {
if (!pango_metrics_inited_) {
pango_metrics_inited_ = true;
- PangoFontDescription* pango_desc = PangoFontFromGfxFont(*this);
+ PangoFontDescription* pango_desc = GetNativeFont();
PangoFontMetrics* pango_metrics = GetPangoFontMetrics(pango_desc);
underline_position_ =
@@ -211,45 +377,58 @@
int text_width = GetStringWidth(
L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
double dialog_units = (text_width / 26 + 1) / 2;
- avg_width_ = std::min(pango_width, dialog_units);
+ average_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_;
+float PlatformFontGtk::GetPangoScaleFactor() {
+ // Pango scales font sizes. This returns the scale factor. See
+ // pango_cairo_context_set_resolution for details.
+ // NOTE: this isn't entirely accurate, in that Pango also consults the
+ // FC_PIXEL_SIZE first (see get_font_size in pangocairo-fcfont), but this
+ // seems to give us the same sizes as used by Pango for all our fonts in both
+ // English and Thai.
+ static float scale_factor = gfx::GetPangoResolution();
+ static bool determined_scale = false;
+ if (!determined_scale) {
+ if (scale_factor <= 0)
+ scale_factor = 1;
+ else
+ scale_factor /= 72.0;
+ determined_scale = true;
+ }
+ return scale_factor;
}
-double Font::underline_thickness() const {
- const_cast<Font*>(this)->InitPangoMetrics();
- return underline_thickness_;
+double PlatformFontGtk::GetAverageWidth() const {
+ const_cast<PlatformFontGtk*>(this)->InitPangoMetrics();
+ return average_width_;
}
-int Font::GetExpectedTextWidth(int length) const {
- double char_width = const_cast<Font*>(this)->avg_width();
- return round(static_cast<float>(length) * char_width);
-}
+////////////////////////////////////////////////////////////////////////////////
+// PlatformFont, public:
-int Font::style() const {
- return style_;
+// static
+PlatformFont* PlatformFont::CreateDefault() {
+ return new PlatformFontGtk;
}
-const std::wstring& Font::FontName() const {
- return font_family_;
+// static
+PlatformFont* PlatformFont::CreateFromFont(const Font& other) {
+ return new PlatformFontGtk(other);
}
-int Font::FontSize() {
- return font_size_;
+// static
+PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
+ return new PlatformFontGtk(native_font);
}
-NativeFont Font::nativeFont() const {
- return typeface_;
+// static
+PlatformFont* PlatformFont::CreateFromNameAndSize(const std::wstring& font_name,
+ int font_size) {
+ return new PlatformFontGtk(font_name, font_size);
}
} // namespace gfx
« no previous file with comments | « gfx/platform_font_gtk.h ('k') | gfx/platform_font_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698