diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/gfx/canvas_linux.cc | 30 | ||||
-rw-r--r-- | app/gfx/font.h | 5 | ||||
-rw-r--r-- | app/gfx/font_skia.cc | 43 |
3 files changed, 54 insertions, 24 deletions
diff --git a/app/gfx/canvas_linux.cc b/app/gfx/canvas_linux.cc index 7ed1904..fc4e10e3 100644 --- a/app/gfx/canvas_linux.cc +++ b/app/gfx/canvas_linux.cc @@ -98,8 +98,10 @@ Canvas::Canvas() : skia::PlatformCanvas() { Canvas::~Canvas() { } +// Pass a width > 0 to force wrapping and elliding. static void SetupPangoLayout(PangoLayout* layout, const gfx::Font& font, + int width, int flags) { if (!cairo_font_options) UpdateCairoFontOptions(); @@ -112,6 +114,9 @@ static void SetupPangoLayout(PangoLayout* layout, // scope out RTL characters. pango_layout_set_auto_dir(layout, FALSE); + if (width > 0) + pango_layout_set_width(layout, width * PANGO_SCALE); + if (flags & Canvas::NO_ELLIPSIS) { pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE); } else { @@ -144,14 +149,16 @@ void Canvas::SizeStringInt(const std::wstring& text, cairo_t* cr = cairo_create(surface); PangoLayout* layout = pango_cairo_create_layout(cr); - SetupPangoLayout(layout, font, flags); + SetupPangoLayout(layout, font, *width, flags); std::string utf8 = WideToUTF8(text); pango_layout_set_text(layout, utf8.data(), utf8.size()); - pango_layout_get_size(layout, width, height); + int chars_height; + pango_layout_get_size(layout, width, &chars_height); *width /= PANGO_SCALE; - *height /= PANGO_SCALE; + // Pango returns the height of the characters, not the height of the font. + *height = font.height(); g_object_unref(layout); cairo_destroy(cr); @@ -160,14 +167,14 @@ void Canvas::SizeStringInt(const std::wstring& text, void Canvas::DrawStringInt(const std::wstring& text, const gfx::Font& font, - const SkColor& color, int x, int y, int w, int h, + const SkColor& color, + int x, int y, int w, int h, int flags) { cairo_t* cr = beginPlatformPaint(); PangoLayout* layout = pango_cairo_create_layout(cr); - SetupPangoLayout(layout, font, flags); + SetupPangoLayout(layout, font, w, flags); - pango_layout_set_width(layout, w * PANGO_SCALE); pango_layout_set_height(layout, h * PANGO_SCALE); cairo_save(cr); @@ -179,16 +186,19 @@ void Canvas::DrawStringInt(const std::wstring& text, std::string utf8 = WideToUTF8(text); pango_layout_set_text(layout, utf8.data(), utf8.size()); - int width, height; - pango_layout_get_size(layout, &width, &height); + int width, height, chars_height; + pango_layout_get_size(layout, &width, &chars_height); + width /= PANGO_SCALE; + // Pango returns the height of the characters, not the height of the font. + height = font.height(); if (flags & Canvas::TEXT_VALIGN_TOP) { // Cairo should draw from the top left corner already. } else if (flags & Canvas::TEXT_VALIGN_BOTTOM) { - y = y + (h - (height / PANGO_SCALE)); + y += (h - height); } else { // Vertically centered. - y = y + ((h - (height / PANGO_SCALE)) / 2); + y += ((h - height) / 2); } cairo_rectangle(cr, x, y, w, h); diff --git a/app/gfx/font.h b/app/gfx/font.h index e53bd79..bc8ee92 100644 --- a/app/gfx/font.h +++ b/app/gfx/font.h @@ -206,6 +206,9 @@ class Font { // The default font, used for the default constructor. static Font* default_font_; + // The average width of a character, initialized and cached if needed. + double avg_width(); + // These two both point to the same SkTypeface. We use the SkAutoUnref to // handle the reference counting, but without @typeface_ we would have to // cast the SkRefCnt from @typeface_helper_ every time. @@ -221,7 +224,7 @@ class Font { // Cached metrics, generated at construction int height_; int ascent_; - int avg_width_; + double avg_width_; #elif defined(OS_MACOSX) explicit Font(const std::wstring& font_name, int font_size, int style); diff --git a/app/gfx/font_skia.cc b/app/gfx/font_skia.cc index 41c29c6..70d6cf2 100644 --- a/app/gfx/font_skia.cc +++ b/app/gfx/font_skia.cc @@ -69,22 +69,14 @@ Font::Font(SkTypeface* tf, const std::wstring& font_family, int font_size, void Font::calculateMetrics() { SkPaint paint; SkPaint::FontMetrics metrics; - PaintSetup(&paint); paint.getFontMetrics(&metrics); 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; - if (metrics.fAvgCharWidth) { - avg_width_ = SkScalarRound(metrics.fAvgCharWidth); - } else { - static const char x_char = 'x'; - paint.setTextEncoding(SkPaint::kUTF8_TextEncoding); - SkScalar width = paint.measureText(&x_char, 1); - - avg_width_ = static_cast<int>(ceilf(SkScalarToFloat(width))); - } } void Font::CopyFont(const Font& other) { @@ -108,7 +100,7 @@ int Font::baseline() const { } int Font::ave_char_width() const { - return avg_width_; + return SkScalarRound(const_cast<Font*>(this)->avg_width()); } Font Font::CreateFont(const std::wstring& font_family, int font_size) { @@ -176,10 +168,35 @@ int Font::GetStringWidth(const std::wstring& text) const { return width; } -int Font::GetExpectedTextWidth(int length) const { - return length * avg_width_; +double Font::avg_width() { + if (avg_width_ < 0) { + // First get the pango based width + PangoFontDescription* pango_desc = gfx::Font::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()); + 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); + } + return avg_width_; } +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_; |