Got the about panel to have its text lined up correctly.

Also added underline capability to linux fonts.

Review URL: http://codereview.chromium.org/338029

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30276 0039d316-1c4b-4281-b951-d872f2087c98
parent d87703cb
...@@ -185,6 +185,9 @@ void Canvas::DrawStringInt(const std::wstring& text, ...@@ -185,6 +185,9 @@ void Canvas::DrawStringInt(const std::wstring& text,
int width, height; int width, height;
pango_layout_get_pixel_size(layout, &width, &height); pango_layout_get_pixel_size(layout, &width, &height);
cairo_rectangle(cr, x, y, width, height);
cairo_clip(cr);
if (flags & Canvas::TEXT_VALIGN_TOP) { if (flags & Canvas::TEXT_VALIGN_TOP) {
// Cairo should draw from the top left corner already. // Cairo should draw from the top left corner already.
} else if (flags & Canvas::TEXT_VALIGN_BOTTOM) { } else if (flags & Canvas::TEXT_VALIGN_BOTTOM) {
...@@ -194,11 +197,16 @@ void Canvas::DrawStringInt(const std::wstring& text, ...@@ -194,11 +197,16 @@ void Canvas::DrawStringInt(const std::wstring& text,
y += ((h - height) / 2); y += ((h - height) / 2);
} }
cairo_rectangle(cr, x, y, w, h);
cairo_clip(cr);
cairo_move_to(cr, x, y); cairo_move_to(cr, x, y);
pango_cairo_show_layout(cr, layout); pango_cairo_show_layout(cr, layout);
if (font.style() & gfx::Font::UNDERLINED) {
double underline_y =
static_cast<double>(y) + height + font.underline_position();
cairo_set_line_width(cr, font.underline_thickness());
cairo_move_to(cr, x, underline_y);
cairo_line_to(cr, x + width, underline_y);
cairo_stroke(cr);
}
cairo_restore(cr); cairo_restore(cr);
g_object_unref(layout); g_object_unref(layout);
......
...@@ -136,6 +136,13 @@ class Font { ...@@ -136,6 +136,13 @@ class Font {
// Converts |gfx_font| to a new pango font. Free the returned font with // Converts |gfx_font| to a new pango font. Free the returned font with
// pango_font_description_free(). // pango_font_description_free().
static PangoFontDescription* PangoFontFromGfxFont(const gfx::Font& gfx_font); static PangoFontDescription* PangoFontFromGfxFont(const gfx::Font& gfx_font);
// Position as an offset from the height of the drawn text, used to draw
// an underline. This is a negative number, so the underline would be
// drawn at y + height + underline_position;
double underline_position() const;
// The thickness to draw the underline.
double underline_thickness() const;
#endif #endif
private: private:
...@@ -207,7 +214,10 @@ class Font { ...@@ -207,7 +214,10 @@ class Font {
static Font* default_font_; static Font* default_font_;
// The average width of a character, initialized and cached if needed. // The average width of a character, initialized and cached if needed.
double avg_width(); double avg_width() const;
// Potentially slow call to get pango metrics (avg width, underline info).
void InitPangoMetrics();
// These two both point to the same SkTypeface. We use the SkAutoUnref to // These two both point to the same SkTypeface. We use the SkAutoUnref to
// handle the reference counting, but without @typeface_ we would have to // handle the reference counting, but without @typeface_ we would have to
...@@ -224,7 +234,13 @@ class Font { ...@@ -224,7 +234,13 @@ class Font {
// Cached metrics, generated at construction // Cached metrics, generated at construction
int height_; int height_;
int ascent_; int ascent_;
// The pango metrics are much more expensive so we wait until we need them
// to compute them.
bool pango_metrics_inited_;
double avg_width_; double avg_width_;
double underline_position_;
double underline_thickness_;
#elif defined(OS_MACOSX) #elif defined(OS_MACOSX)
explicit Font(const std::wstring& font_name, int font_size, int style); explicit Font(const std::wstring& font_name, int font_size, int style);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "app/gfx/font.h" #include "app/gfx/font.h"
#include <gdk/gdk.h> #include <gdk/gdk.h>
#include <map>
#include <pango/pango.h> #include <pango/pango.h>
#include "app/gfx/canvas.h" #include "app/gfx/canvas.h"
...@@ -42,6 +43,35 @@ static double GetPangoScaleFactor() { ...@@ -42,6 +43,35 @@ static double GetPangoScaleFactor() {
return scale_factor; 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
namespace gfx { namespace gfx {
...@@ -61,7 +91,11 @@ Font::Font(SkTypeface* tf, const std::wstring& font_family, int font_size, ...@@ -61,7 +91,11 @@ Font::Font(SkTypeface* tf, const std::wstring& font_family, int font_size,
typeface_(tf), typeface_(tf),
font_family_(font_family), font_family_(font_family),
font_size_(font_size), 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(); tf->ref();
calculateMetrics(); calculateMetrics();
} }
...@@ -74,8 +108,6 @@ void Font::calculateMetrics() { ...@@ -74,8 +108,6 @@ void Font::calculateMetrics() {
ascent_ = SkScalarCeil(-metrics.fAscent); ascent_ = SkScalarCeil(-metrics.fAscent);
height_ = ascent_ + SkScalarCeil(metrics.fDescent); 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) { ...@@ -88,7 +120,10 @@ void Font::CopyFont(const Font& other) {
style_ = other.style_; style_ = other.style_;
height_ = other.height_; height_ = other.height_;
ascent_ = other.ascent_; ascent_ = other.ascent_;
pango_metrics_inited_ = other.pango_metrics_inited_;
avg_width_ = other.avg_width_; avg_width_ = other.avg_width_;
underline_position_ = other.underline_position_;
underline_thickness_ = other.underline_thickness_;
} }
int Font::height() const { int Font::height() const {
...@@ -100,7 +135,7 @@ int Font::baseline() const { ...@@ -100,7 +135,7 @@ int Font::baseline() const {
} }
int Font::ave_char_width() 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) { Font Font::CreateFont(const std::wstring& font_family, int font_size) {
...@@ -148,7 +183,7 @@ Font Font::DeriveFont(int size_delta, int style) const { ...@@ -148,7 +183,7 @@ Font Font::DeriveFont(int size_delta, int style) const {
static_cast<SkTypeface::Style>(skstyle)); static_cast<SkTypeface::Style>(skstyle));
SkAutoUnref tf_helper(tf); 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 { void Font::PaintSetup(SkPaint* paint) const {
...@@ -168,16 +203,26 @@ int Font::GetStringWidth(const std::wstring& text) const { ...@@ -168,16 +203,26 @@ int Font::GetStringWidth(const std::wstring& text) const {
return width; return width;
} }
double Font::avg_width() { void Font::InitPangoMetrics() {
if (avg_width_ < 0) { if (!pango_metrics_inited_) {
// First get the pango based width pango_metrics_inited_ = true;
PangoFontDescription* pango_desc = PangoFontFromGfxFont(*this); PangoFontDescription* pango_desc = PangoFontFromGfxFont(*this);
PangoContext* context = PangoFontMetrics* pango_metrics = GetPangoFontMetrics(pango_desc);
gdk_pango_context_get_for_screen(gdk_screen_get_default());
PangoFontMetrics* pango_metrics = underline_position_ =
pango_context_get_metrics(context, pango_font_metrics_get_underline_position(pango_metrics);
pango_desc, underline_position_ /= PANGO_SCALE;
pango_language_get_default());
// 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 = double pango_width =
pango_font_metrics_get_approximate_char_width(pango_metrics); pango_font_metrics_get_approximate_char_width(pango_metrics);
pango_width /= PANGO_SCALE; pango_width /= PANGO_SCALE;
...@@ -188,12 +233,25 @@ double Font::avg_width() { ...@@ -188,12 +233,25 @@ double Font::avg_width() {
L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
double dialog_units = (text_width / 26 + 1) / 2; double dialog_units = (text_width / 26 + 1) / 2;
avg_width_ = std::min(pango_width, dialog_units); avg_width_ = std::min(pango_width, dialog_units);
pango_font_metrics_unref(pango_metrics);
pango_font_description_free(pango_desc); pango_font_description_free(pango_desc);
} }
}
double Font::avg_width() const {
const_cast<Font*>(this)->InitPangoMetrics();
return avg_width_; 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 { int Font::GetExpectedTextWidth(int length) const {
double char_width = const_cast<Font*>(this)->avg_width(); double char_width = const_cast<Font*>(this)->avg_width();
return round(static_cast<float>(length) * char_width); return round(static_cast<float>(length) * char_width);
......
...@@ -560,7 +560,8 @@ void AboutChromeView::DrawTextStartingFrom(gfx::Canvas* canvas, ...@@ -560,7 +560,8 @@ void AboutChromeView::DrawTextStartingFrom(gfx::Canvas* canvas,
int y = position->height() + bounds.y(); int y = position->height() + bounds.y();
// Draw the text on the screen (mirrored, if RTL run). // Draw the text on the screen (mirrored, if RTL run).
canvas->DrawStringInt(word, font, text_color, x, y, w, h, flags); canvas->DrawStringInt(
word, font, text_color, x, y, w, font.height(), flags);
if (word.size() > 0 && word[word.size() - 1] == L'\x0a') { if (word.size() > 0 && word[word.size() - 1] == L'\x0a') {
// When we come across '\n', we move to the beginning of the next line. // When we come across '\n', we move to the beginning of the next line.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment