diff options
Diffstat (limited to 'app/gfx/font_gtk.cc')
-rw-r--r-- | app/gfx/font_gtk.cc | 188 |
1 files changed, 65 insertions, 123 deletions
diff --git a/app/gfx/font_gtk.cc b/app/gfx/font_gtk.cc index 5e16fc2..244810a 100644 --- a/app/gfx/font_gtk.cc +++ b/app/gfx/font_gtk.cc @@ -7,87 +7,56 @@ #include <fontconfig/fontconfig.h> #include <gtk/gtk.h> -#include "app/gfx/canvas.h" #include "base/string_util.h" namespace gfx { -namespace { - -// Returns a PangoContext that is used to get metrics. The returned context -// should never be freed. -PangoContext* get_context() { - static PangoContext* context = NULL; - if (!context) { - context = gdk_pango_context_get_for_screen(gdk_screen_get_default()); - pango_context_set_language(context, gtk_get_default_language()); - } - return context; -} +Font* Font::default_font_ = NULL; +// 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. +static 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; } -Font* Font::default_font_ = NULL; - // static Font Font::CreateFont(PangoFontDescription* desc) { - return Font(desc); -} - -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_ref_->size()); - - PangoFontDescription* pfd = pango_font_description_copy(nativeFont()); - pango_font_description_set_size( - pfd, (font_ref_->size() + size_delta) * PANGO_SCALE); - pango_font_description_set_style( - pfd, style & ITALIC ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); - pango_font_description_set_weight( - pfd, style & BOLD ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); - Font font(pfd); - pango_font_description_free(pfd); - return font; -} + gint size = pango_font_description_get_size(desc); + const char* family_name = pango_font_description_get_family(desc); -int Font::height() const { - return font_ref_->height(); -} - -int Font::baseline() const { - return font_ref_->ascent(); -} - -int Font::ave_char_width() const { - return font_ref_->ave_char_width(); -} - -int Font::GetStringWidth(const std::wstring& text) const { - int width = 0, height = 0; - - Canvas::SizeStringInt(text, *this, &width, &height, 0); - return width; -} + // 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); -int Font::GetExpectedTextWidth(int length) const { - return length * font_ref_->ave_char_width(); -} - -int Font::style() const { - return font_ref_->style(); -} - -std::wstring Font::FontName() { - return font_ref_->family(); -} - -int Font::FontSize() { - return font_ref_->size(); -} - -PangoFontDescription* Font::nativeFont() const { - return font_ref_->pfd(); + return Font(CreateFont(font_family, size / PANGO_SCALE)); } // Get the default gtk system font (name and size). @@ -106,68 +75,41 @@ Font::Font() { PangoFontDescription* desc = pango_font_description_from_string(font_name); - default_font_ = new Font(desc); + default_font_ = new Font(CreateFont(desc)); pango_font_description_free(desc); g_free(font_name); + + DCHECK(default_font_); } - *this = *default_font_; + CopyFont(*default_font_); } // static -Font Font::CreateFont(const std::wstring& font_family, int font_size) { - DCHECK_GT(font_size, 0); - +PangoFontDescription* Font::PangoFontFromGfxFont( + const gfx::Font& gfx_font) { + gfx::Font font = gfx_font; // Copy so we can call non-const methods. PangoFontDescription* pfd = pango_font_description_new(); - pango_font_description_set_family(pfd, WideToUTF8(font_family).c_str()); - pango_font_description_set_size(pfd, font_size * PANGO_SCALE); - pango_font_description_set_style(pfd, PANGO_STYLE_NORMAL); - pango_font_description_set_weight(pfd, PANGO_WEIGHT_NORMAL); - Font font(pfd); - pango_font_description_free(pfd); - return font; -} - -Font::Font(PangoFontDescription* desc) { - PangoContext* context = get_context(); - pango_context_set_font_description(context, desc); - PangoFontMetrics* metrics = pango_context_get_metrics(context, desc, NULL); - int ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; - int height = ascent + pango_font_metrics_get_descent(metrics) / PANGO_SCALE; - int size = pango_font_description_get_size(desc) / PANGO_SCALE; - int style = 0; - if (pango_font_description_get_weight(desc) >= PANGO_WEIGHT_BOLD) - style |= BOLD; - if (pango_font_description_get_style(desc) == PANGO_STYLE_ITALIC) - style |= ITALIC; - // TODO(deanm): How to do underlined? Where do we use it? Probably have - // to paint it ourselves, see pango_font_metrics_get_underline_position. - int avg_width = pango_font_metrics_get_approximate_char_width(metrics) / - PANGO_SCALE; - std::wstring name(UTF8ToWide(pango_font_description_get_family(desc))); - font_ref_ = new PangoFontRef(desc, name, size, style, height, ascent, - avg_width); - pango_font_metrics_unref(metrics); -} - -Font::PangoFontRef::PangoFontRef(PangoFontDescription* pfd, - const std::wstring& family, - int size, - int style, - int height, - int ascent, - int ave_char_width) - : pfd_(pango_font_description_copy(pfd)), - family_(family), - size_(size), - style_(style), - height_(height), - ascent_(ascent), - ave_char_width_(ave_char_width) { -} + pango_font_description_set_family(pfd, WideToUTF8(font.FontName()).c_str()); + pango_font_description_set_size(pfd, font.FontSize() * PANGO_SCALE); + + switch (font.style()) { + 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; + } -Font::PangoFontRef::~PangoFontRef() { - pango_font_description_free(pfd_); + return pfd; } } // namespace gfx |