| Index: app/gfx/font_skia.cc
|
| diff --git a/app/gfx/font_skia.cc b/app/gfx/font_skia.cc
|
| index 8f6ccc1c5e04b5bb5e5ec2a325382fd755e37364..a283306b0dc9f4b9bf39d2e9b3d5aa666b1b2e8e 100755
|
| --- a/app/gfx/font_skia.cc
|
| +++ b/app/gfx/font_skia.cc
|
| @@ -5,6 +5,7 @@
|
| #include "app/gfx/font.h"
|
|
|
| #include <gdk/gdk.h>
|
| +#include <map>
|
| #include <pango/pango.h>
|
|
|
| #include "app/gfx/canvas.h"
|
| @@ -42,6 +43,35 @@ static double GetPangoScaleFactor() {
|
| return scale_factor;
|
| }
|
|
|
| +// 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 {
|
| @@ -61,7 +91,11 @@ Font::Font(SkTypeface* tf, const std::wstring& font_family, int font_size,
|
| typeface_(tf),
|
| font_family_(font_family),
|
| font_size_(font_size),
|
| - style_(style) {
|
| + style_(style),
|
| + pango_metrics_inited_(false),
|
| + avg_width_(0.0),
|
| + underline_position_(0.0),
|
| + underline_thickness_(0.0) {
|
| tf->ref();
|
| calculateMetrics();
|
| }
|
| @@ -74,8 +108,6 @@ void Font::calculateMetrics() {
|
|
|
| ascent_ = SkScalarCeil(-metrics.fAscent);
|
| height_ = ascent_ + SkScalarCeil(metrics.fDescent);
|
| - // avg_width_ is calculated lazily, as it's expensive and not used often.
|
| - avg_width_ = -1.0;
|
|
|
| }
|
|
|
| @@ -88,7 +120,10 @@ void Font::CopyFont(const Font& other) {
|
| 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 {
|
| @@ -100,7 +135,7 @@ int Font::baseline() const {
|
| }
|
|
|
| int Font::ave_char_width() const {
|
| - return SkScalarRound(const_cast<Font*>(this)->avg_width());
|
| + return SkScalarRound(avg_width());
|
| }
|
|
|
| Font Font::CreateFont(const std::wstring& font_family, int font_size) {
|
| @@ -148,7 +183,7 @@ Font Font::DeriveFont(int size_delta, int style) const {
|
| static_cast<SkTypeface::Style>(skstyle));
|
| SkAutoUnref tf_helper(tf);
|
|
|
| - return Font(tf, font_family_, font_size_ + size_delta, skstyle);
|
| + return Font(tf, font_family_, font_size_ + size_delta, style);
|
| }
|
|
|
| void Font::PaintSetup(SkPaint* paint) const {
|
| @@ -168,16 +203,26 @@ int Font::GetStringWidth(const std::wstring& text) const {
|
| return width;
|
| }
|
|
|
| -double Font::avg_width() {
|
| - if (avg_width_ < 0) {
|
| - // First get the pango based width
|
| +void Font::InitPangoMetrics() {
|
| + if (!pango_metrics_inited_) {
|
| + pango_metrics_inited_ = true;
|
| PangoFontDescription* pango_desc = PangoFontFromGfxFont(*this);
|
| - PangoContext* context =
|
| - gdk_pango_context_get_for_screen(gdk_screen_get_default());
|
| - PangoFontMetrics* pango_metrics =
|
| - pango_context_get_metrics(context,
|
| - pango_desc,
|
| - pango_language_get_default());
|
| + 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;
|
| @@ -188,12 +233,25 @@ double Font::avg_width() {
|
| L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
|
| double dialog_units = (text_width / 26 + 1) / 2;
|
| avg_width_ = std::min(pango_width, dialog_units);
|
| - pango_font_metrics_unref(pango_metrics);
|
| 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);
|
|
|