support font antialiasing and hinting settings

This commit is contained in:
Vadim Lopatin 2015-01-19 09:58:54 +03:00
parent ddc97cd563
commit 269b1736d3
4 changed files with 156 additions and 41 deletions

View File

@ -134,6 +134,12 @@ class Font : RefCountedObject {
/// returns true if font object is not yet initialized / loaded
abstract @property bool isNull();
/// return true if antialiasing is enabled, false if not enabled
@property bool antialiased() {
return size >= FontManager.instance.minAnitialiasedFontSize;
}
private int _fixedFontDetection = -1;
/// returns true if font has fixed pitch (all characters have equal width)
@ -415,10 +421,24 @@ struct FontList {
}
}
/// default min font size for antialiased fonts (e.g. if 16 is set, for 16+ sizes antialiasing will be used, for sizes <=15 - antialiasing will be off)
const int DEF_MIN_ANTIALIASED_FONT_SIZE = 0; // 0 means always use antialiasing
/// Hinting mode (currently supported for FreeType only)
enum HintingMode : int {
/// based on information from font (using bytecode interpreter)
Normal,
/// force autohinting algorithm even if font contains hint data
AutoHint,
/// disable hinting completely
Disabled
}
/// Access points to fonts.
class FontManager {
protected static __gshared FontManager _instance;
protected static __gshared int _minAnitialiasedFontSize = DEF_MIN_ANTIALIASED_FONT_SIZE;
protected static __gshared HintingMode _hintingMode = HintingMode.Normal;
/// sets new font manager singleton instance
static @property void instance(FontManager manager) {
@ -443,6 +463,26 @@ class FontManager {
/// removes entries not used after last call of checkpoint() or cleanup()
abstract void cleanup();
/// get min font size for antialiased fonts
@property int minAnitialiasedFontSize() {
return _minAnitialiasedFontSize;
}
/// set new min font size for antialiased fonts
@property void minAnitialiasedFontSize(int size) {
_minAnitialiasedFontSize = size;
}
/// get current hinting mode
@property HintingMode hintingMode() {
return _hintingMode;
}
/// set hinting mode
@property void hintingMode(HintingMode mode) {
_hintingMode = mode;
}
~this() {
Log.d("Destroying font manager");
}

View File

@ -246,14 +246,14 @@ private class FreeTypeFontFile {
//FONT_GUARD
int glyph_index = getCharIndex(code, def_char);
int flags = FT_LOAD_DEFAULT;
const bool _drawMonochrome = false;
const bool _drawMonochrome = _size < FontManager.instance.minAnitialiasedFontSize;
flags |= (!_drawMonochrome ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO);
if (withImage)
flags |= FT_LOAD_RENDER;
//if (_hintingMode == HINTING_MODE_AUTOHINT)
// flags |= FT_LOAD_FORCE_AUTOHINT;
//else if (_hintingMode == HINTING_MODE_DISABLED)
// flags |= FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING;
if (FontManager.instance.hintingMode == HintingMode.AutoHint)
flags |= FT_LOAD_FORCE_AUTOHINT;
else if (FontManager.instance.hintingMode == HintingMode.Disabled)
flags |= FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING;
int error = FT_Load_Glyph(
_face, /* handle to face object */
glyph_index, /* glyph index */
@ -276,8 +276,30 @@ private class FreeTypeFontFile {
int sz = w * cast(int)h;
if (sz > 0) {
glyph.glyph = new ubyte[sz];
for (int i = 0; i < sz; i++)
glyph.glyph[i] = bitmap.buffer[i];
if (_drawMonochrome) {
// monochrome bitmap
ubyte mask = 0x80;
ubyte * ptr = bitmap.buffer;
ubyte * dst = glyph.glyph.ptr;
for ( int y=0; y<h; y++ ) {
ubyte * row = ptr;
mask = 0x80;
for ( int x=0; x<w; x++ ) {
*dst++ = (*row & mask) ? 0xFF : 00;
mask >>= 1;
if ( !mask && x != w-1) {
mask = 0x80;
row++;
}
}
ptr += bitmap.pitch;
}
} else {
// antialiased
for (int i = 0; i < sz; i++)
glyph.glyph[i] = bitmap.buffer[i];
}
}
version (USE_OPENGL) {
glyph.id = nextGlyphId();

View File

@ -142,12 +142,24 @@ class Win32Font : Font {
&identity );
if (res == GDI_ERROR)
return null;
int gs = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
GGO_GRAY8_BITMAP, //GGO_METRICS
&metrics,
0,
NULL,
&identity );
int gs = 0;
// calculate bitmap size
if (antialiased) {
gs = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
GGO_GRAY8_BITMAP,
&metrics,
0,
NULL,
&identity );
} else {
gs = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
GGO_BITMAP,
&metrics,
0,
NULL,
&identity );
}
if (gs >= 0x10000 || gs < 0)
return null;
@ -167,33 +179,65 @@ class Win32Font : Font {
g.glyph = new ubyte[g.blackBoxX * g.blackBoxY];
if (gs>0)
{
ubyte[] glyph = new ubyte[gs];
res = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
GGO_GRAY8_BITMAP, //GGO_METRICS
&metrics,
gs,
glyph.ptr,
&identity );
if (res==GDI_ERROR)
{
return null;
}
int glyph_row_size = (g.blackBoxX + 3) / 4 * 4;
ubyte * src = glyph.ptr;
ubyte * dst = g.glyph.ptr;
for (int y = 0; y < g.blackBoxY; y++)
{
for (int x = 0; x < g.blackBoxX; x++)
{
ubyte b = src[x];
if (b>=64)
b = 63;
b = (b<<2) & 0xFC;
dst[x] = b;
}
src += glyph_row_size;
dst += g.blackBoxX;
}
if (antialiased) {
// antialiased glyph
ubyte[] glyph = new ubyte[gs];
res = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
GGO_GRAY8_BITMAP, //GGO_METRICS
&metrics,
gs,
glyph.ptr,
&identity );
if (res==GDI_ERROR)
{
return null;
}
int glyph_row_size = (g.blackBoxX + 3) / 4 * 4;
ubyte * src = glyph.ptr;
ubyte * dst = g.glyph.ptr;
for (int y = 0; y < g.blackBoxY; y++)
{
for (int x = 0; x < g.blackBoxX; x++)
{
ubyte b = src[x];
if (b>=64)
b = 63;
b = (b<<2) & 0xFC;
dst[x] = b;
}
src += glyph_row_size;
dst += g.blackBoxX;
}
} else {
// bitmap glyph
ubyte[] glyph = new ubyte[gs];
res = GetGlyphOutlineW( _drawbuf.dc, cast(wchar)ch,
GGO_BITMAP, //GGO_METRICS
&metrics,
gs,
glyph.ptr,
&identity );
if (res==GDI_ERROR)
{
return null;
}
int glyph_row_bytes = ((g.blackBoxX + 7) / 8);
int glyph_row_size = (glyph_row_bytes + 3) / 4 * 4;
ubyte * src = glyph.ptr;
ubyte * dst = g.glyph.ptr;
for (int y = 0; y < g.blackBoxY; y++)
{
for (int x = 0; x < g.blackBoxX; x++)
{
int offset = x >> 3;
int shift = 7 - (x & 7);
ubyte b = ((src[offset] >> shift) & 1) ? 255 : 0;
dst[x] = b;
}
src += glyph_row_size;
dst += g.blackBoxX;
}
}
}
else
{
@ -217,6 +261,7 @@ class Win32Font : Font {
lf.lfFaceName[def.face.length] = 0;
lf.lfHeight = size; //-size;
lf.lfItalic = italic;
lf.lfWeight = weight;
lf.lfOutPrecision = OUT_OUTLINE_PRECIS; //OUT_TT_ONLY_PRECIS;
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
//lf.lfQuality = NONANTIALIASED_QUALITY; //ANTIALIASED_QUALITY;

View File

@ -859,7 +859,7 @@ int myWinMain(void* hInstance, void* hPrevInstance, char* lpCmdLine, int iCmdSho
/// testing freetype font manager
static if (false) {
version(USE_FREETYPE) {
import dlangui.graphics.ftfonts;
import win32.shlobj;
FreeTypeFontManager ftfontMan = new FreeTypeFontManager();
@ -889,6 +889,14 @@ int myWinMain(void* hInstance, void* hPrevInstance, char* lpCmdLine, int iCmdSho
ftfontMan.registerFont(fontsPath ~ "timesbd.ttf", FontFamily.Serif, "Times New Roman", false, FontWeight.Bold);
ftfontMan.registerFont(fontsPath ~ "timesbi.ttf", FontFamily.Serif, "Times New Roman", true, FontWeight.Bold);
ftfontMan.registerFont(fontsPath ~ "timesi.ttf", FontFamily.Serif, "Times New Roman", true, FontWeight.Normal);
ftfontMan.registerFont(fontsPath ~ "consola.ttf", FontFamily.MonoSpace, "Consolas", false, FontWeight.Normal);
ftfontMan.registerFont(fontsPath ~ "consolab.ttf", FontFamily.MonoSpace, "Consolas", false, FontWeight.Bold);
ftfontMan.registerFont(fontsPath ~ "consolai.ttf", FontFamily.MonoSpace, "Consolas", true, FontWeight.Normal);
ftfontMan.registerFont(fontsPath ~ "consolaz.ttf", FontFamily.MonoSpace, "Consolas", true, FontWeight.Bold);
ftfontMan.registerFont(fontsPath ~ "verdana.ttf", FontFamily.SansSerif, "Verdana", false, FontWeight.Normal);
ftfontMan.registerFont(fontsPath ~ "verdanab.ttf", FontFamily.SansSerif, "Verdana", false, FontWeight.Bold);
ftfontMan.registerFont(fontsPath ~ "verdanai.ttf", FontFamily.SansSerif, "Verdana", true, FontWeight.Normal);
ftfontMan.registerFont(fontsPath ~ "verdanaz.ttf", FontFamily.SansSerif, "Verdana", true, FontWeight.Bold);
FontManager.instance = ftfontMan;
}