fix(renderer): Use proper font scaling based on DPI

This tries to mimic the old renderer's behavior as closely as possible.
In the absence of any information, DPI is assumed to be 96x96. DPI can
be configured on a per-bar basis using the configuration key "dpi".

To use the DPI configuration from Xresources (if built with support),
one can specify the following in the bar config:

dpi = ${xrdb:Xft.dpi:96}
This commit is contained in:
Chase Geigle 2017-01-24 20:08:14 -06:00 committed by Michael Carlberg
parent 8d79b582ec
commit e7dc6b8bbb
2 changed files with 23 additions and 7 deletions

View File

@ -30,7 +30,7 @@ namespace cairo {
virtual string name() const = 0; virtual string name() const = 0;
virtual string file() const = 0; virtual string file() const = 0;
virtual double offset() const = 0; virtual double offset() const = 0;
virtual double size() const = 0; virtual double size(double dpi) const = 0;
virtual cairo_font_extents_t extents() = 0; virtual cairo_font_extents_t extents() = 0;
@ -54,10 +54,10 @@ namespace cairo {
*/ */
class font_fc : public font { class font_fc : public font {
public: public:
explicit font_fc(cairo_t* cairo, FcPattern* pattern, double offset) : font(cairo, offset), m_pattern(pattern) { explicit font_fc(cairo_t* cairo, FcPattern* pattern, double offset, double dpi_x, double dpi_y) : font(cairo, offset), m_pattern(pattern) {
cairo_matrix_t fm; cairo_matrix_t fm;
cairo_matrix_t ctm; cairo_matrix_t ctm;
cairo_matrix_init_scale(&fm, size(), size()); cairo_matrix_init_scale(&fm, size(dpi_x), size(dpi_y));
cairo_get_matrix(m_cairo, &ctm); cairo_get_matrix(m_cairo, &ctm);
auto fontface = cairo_ft_font_face_create_for_pattern(m_pattern); auto fontface = cairo_ft_font_face_create_for_pattern(m_pattern);
@ -111,12 +111,14 @@ namespace cairo {
return m_offset; return m_offset;
} }
double size() const override { double size(double dpi) const override {
bool scalable; bool scalable;
double px; double px;
property(FC_SCALABLE, &scalable); property(FC_SCALABLE, &scalable);
if (scalable) { if (scalable) {
// convert from pt to px using the provided dpi
property(FC_SIZE, &px); property(FC_SIZE, &px);
px = static_cast<int>(px * dpi / 72.0 + 0.5);
} else { } else {
property(FC_PIXEL_SIZE, &px); property(FC_PIXEL_SIZE, &px);
px = static_cast<int>(px + 0.5); px = static_cast<int>(px + 0.5);
@ -234,7 +236,7 @@ namespace cairo {
/** /**
* Match and create font from given fontconfig pattern * Match and create font from given fontconfig pattern
*/ */
decltype(auto) make_font(cairo_t* cairo, string&& fontname, double offset) { decltype(auto) make_font(cairo_t* cairo, string&& fontname, double offset, double dpi_x, double dpi_y) {
static bool fc_init{false}; static bool fc_init{false};
if (!fc_init && !(fc_init = FcInit())) { if (!fc_init && !(fc_init = FcInit())) {
throw application_error("Could not load fontconfig"); throw application_error("Could not load fontconfig");
@ -263,7 +265,7 @@ namespace cairo {
FcPatternPrint(match); FcPatternPrint(match);
#endif #endif
return make_shared<font_fc>(cairo, match, offset); return make_shared<font_fc>(cairo, match, offset, dpi_x, dpi_y);
} }
} }

View File

@ -121,6 +121,20 @@ renderer::renderer(
m_log.trace("renderer: Load fonts"); m_log.trace("renderer: Load fonts");
{ {
double dpi_x = 96, dpi_y = 96;
if (m_conf.has(m_conf.section(), "dpi")) {
try {
// dpi specified directly as a value
dpi_x = dpi_y = m_conf.get<double>("dpi");
} catch (const value_error&) {
// dpi to be comptued
auto screen = m_connection.screen();
dpi_x = screen->width_in_pixels * 25.4 / screen->width_in_millimeters;
dpi_y = screen->height_in_pixels * 25.4 / screen->height_in_millimeters;
}
}
m_log.trace("renderer: DPI is %.1fx%.1f", dpi_x, dpi_y);
auto fonts = m_conf.get_list<string>(m_conf.section(), "font", {}); auto fonts = m_conf.get_list<string>(m_conf.section(), "font", {});
if (fonts.empty()) { if (fonts.empty()) {
m_log.warn("No fonts specified, using fallback font \"fixed\""); m_log.warn("No fonts specified, using fallback font \"fixed\"");
@ -130,7 +144,7 @@ renderer::renderer(
auto fonts_loaded = false; auto fonts_loaded = false;
for (const auto& f : fonts) { for (const auto& f : fonts) {
vector<string> fd{string_util::split(f, ';')}; vector<string> fd{string_util::split(f, ';')};
auto font = cairo::make_font(*m_context, string(fd[0]), fd.size() > 1 ? std::atoi(fd[1].c_str()) : 0); auto font = cairo::make_font(*m_context, string(fd[0]), fd.size() > 1 ? std::atoi(fd[1].c_str()) : 0, dpi_x, dpi_y);
m_log.info("Loaded font \"%s\" (name=%s, file=%s)", fd[0], font->name(), font->file()); m_log.info("Loaded font \"%s\" (name=%s, file=%s)", fd[0], font->name(), font->file());
*m_context << move(font); *m_context << move(font);
fonts_loaded = true; fonts_loaded = true;