font: Work around chromatic aberration issue with Windows ClearType

This disables subpixel hinting, causing Cairo to render wispy text
because of gamma issues when not rendering text directly onto an opaque
surface (which we can't help due to the game engine's current design).
However, it also makes the implementation of pango_text overblend all
transparent pixels to compensate like it was previously done before the
revert in commit c91b200b7a.

Overblending by 75% seems good enough for our purposes, and also close
enough to what we get on Linux with FreeType alone.
This commit is contained in:
Iris Morelle 2021-03-15 03:22:26 -03:00
parent c4c5629c66
commit cb37afe1a5

View file

@ -31,6 +31,7 @@
#include "serialization/string_utils.hpp"
#include "serialization/unicode.hpp"
#include "preferences/general.hpp"
#include "utils/general.hpp"
#include <boost/algorithm/string/replace.hpp>
@ -82,7 +83,9 @@ pango_text::pango_text()
cairo_font_options_t *fo = cairo_font_options_create();
cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
cairo_font_options_set_hint_metrics(fo, CAIRO_HINT_METRICS_ON);
cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_DEFAULT);
// Always use grayscale AA, particularly on Windows where ClearType subpixel hinting
// will result in colour fringing otherwise. See from_cairo_format() further below.
cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY);
pango_cairo_context_set_font_options(context_.get(), fo);
cairo_font_options_destroy(fo);
@ -613,6 +616,17 @@ static void from_cairo_format(uint32_t & c)
unpremultiply(g, div);
unpremultiply(b, div);
#ifdef _WIN32
// Grayscale AA with ClearType results in wispy unreadable text because of gamma issues
// that would normally be solved by rendering directly onto the destination surface without
// alpha blending. However, since the current game engine design would never allow us to do
// that, we work around that by increasing alpha at the expense of AA accuracy (which is
// not particularly noticeable if you don't know what you're looking for anyway).
if(a < 255) {
a = utils::clamp<unsigned>(unsigned(a) * 1.75, 0, 255);
}
#endif
c = (static_cast<uint32_t>(a) << 24) | (static_cast<uint32_t>(r) << 16) | (static_cast<uint32_t>(g) << 8) | static_cast<uint32_t>(b);
}