From a1995fb53ec174cea23f65d74ef22eef58c19983 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 4 Mar 2014 10:02:18 +0400 Subject: [PATCH] win32 font manager - font creation --- src/dlangui/core/types.d | 3 + src/dlangui/graphics/fonts.d | 4 +- src/dlangui/platforms/windows/winapp.d | 213 +++++++++++++++++-------- 3 files changed, 154 insertions(+), 66 deletions(-) diff --git a/src/dlangui/core/types.d b/src/dlangui/core/types.d index 7e896567..cf3960b6 100644 --- a/src/dlangui/core/types.d +++ b/src/dlangui/core/types.d @@ -80,6 +80,9 @@ public struct Ref(T) { // if (T is RefCountedObject) _data = null; } } + public @property T get() { + return _data; + } public ~this() { if (_data !is null) _data.releaseRef(); diff --git a/src/dlangui/graphics/fonts.d b/src/dlangui/graphics/fonts.d index fd1b87f3..578ef6ac 100644 --- a/src/dlangui/graphics/fonts.d +++ b/src/dlangui/graphics/fonts.d @@ -4,6 +4,8 @@ import dlangui.core.types; enum FontFamily : int { SansSerif, Serif, + Fantasy, + Cursive, MonoSpace } @@ -29,6 +31,6 @@ class FontManager { public static @property FontManager instance() { return _instance; } - abstract public Font getFont(int size, int weight, bool italic, FontFamily family, string face); + abstract public FontRef getFont(int size, int weight, bool italic, FontFamily family, string face); public ~this() {} } diff --git a/src/dlangui/platforms/windows/winapp.d b/src/dlangui/platforms/windows/winapp.d index 4f651781..a393b2ea 100644 --- a/src/dlangui/platforms/windows/winapp.d +++ b/src/dlangui/platforms/windows/winapp.d @@ -8,6 +8,7 @@ import win32.windows; import std.string; import std.utf; import std.stdio; +import std.algorithm; import dlangui.platforms.common.platform; import dlangui.graphics.drawbuf; import dlangui.graphics.fonts; @@ -17,8 +18,17 @@ pragma(lib, "gdi32.lib"); pragma(lib, "user32.lib"); struct FontDef { - string _face; - FontFamily _family; + immutable FontFamily _family; + immutable string _face; + immutable ubyte _pitchAndFamily; + public @property FontFamily family() { return _family; } + public @property string face() { return _face; } + public @property ubyte pitchAndFamily() { return _pitchAndFamily; } + public this(FontFamily family, string face, ubyte putchAndFamily) { + _family = family; + _face = face; + _pitchAndFamily = pitchAndFamily; + } } class Win32Font : Font { @@ -33,7 +43,6 @@ class Win32Font : Font { LOGFONTA _logfont; Win32ColorDrawBuf _drawbuf; public this() { - _drawbuf = new Win32ColorDrawBuf(1, 1); } public override void clear() { if (_hfont !is null) @@ -49,16 +58,36 @@ class Win32Font : Font { _drawbuf = null; } } - public this(HFONT hfont, int size, int height, int weight, bool italic, string face, FontFamily family, int baseline) { - _hfont = hfont; - _size = size; - _height = height; + public bool create(FontDef * def, int size, int weight, bool italic) { + if (!isNull()) + clear(); + LOGFONTA lf; + lf.lfCharSet = ANSI_CHARSET; //DEFAULT_CHARSET; + lf.lfFaceName[0..def.face.length] = def.face; + lf.lfFaceName[def.face.length] = 0; + lf.lfHeight = -size; + lf.lfItalic = italic; + lf.lfOutPrecision = OUT_TT_ONLY_PRECIS; + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + lf.lfQuality = ANTIALIASED_QUALITY; + lf.lfPitchAndFamily = def.pitchAndFamily; + _hfont = CreateFontIndirectA(&lf); + _drawbuf = new Win32ColorDrawBuf(1, 1); + SelectObject(_drawbuf.dc, _hfont); + + TEXTMETRICW tm; + GetTextMetricsW(_drawbuf.dc, &tm); + + _size = size; + _height = tm.tmHeight; + _baseline = _height - tm.tmDescent; _weight = weight; - _baseline = baseline; _italic = italic; - _face = face; - _family = family; - } + _face = def.face; + _family = def.family; + Log.d("Created font ", _face, " ", _size); + return true; + } public @property override int size() { return _size; } public @property override int height() { return _height; } public @property override int weight() { return _weight; } @@ -67,42 +96,14 @@ class Win32Font : Font { public @property override string face() { return _face; } public @property override FontFamily family() { return _family; } public @property override bool isNull() { return _hfont is null; } - public bool create(const LOGFONTA * logfont) { - if (!isNull()) - clear(); - _logfont = *logfont; - _hfont = CreateFontIndirectA(logfont); - if (!_hfont) - return false; - //memcpy( &_logfont, &lf, sizeof(LOGFONT) ); - // get text metrics - SelectObject(_drawbuf.dc, _hfont); - TEXTMETRICW tm; - GetTextMetricsW(_drawbuf.dc, &tm); - _family = FontFamily.SansSerif; - ubyte pitchAndFamily = _logfont.lfPitchAndFamily; - if ((pitchAndFamily & (FIXED_PITCH | MONO_FONT | FF_MODERN)) != 0) - _family = FontFamily.MonoSpace; - else if ((pitchAndFamily & (FF_ROMAN | FF_SCRIPT)) != 0) - _family = FontFamily.Serif; - _logfont.lfHeight = tm.tmHeight; - _logfont.lfWeight = tm.tmWeight; - _logfont.lfItalic = tm.tmItalic; - _logfont.lfCharSet = tm.tmCharSet; - GetTextFaceA(_drawbuf.dc, _logfont.lfFaceName.length - 1, _logfont.lfFaceName.ptr); - int i = 0; - for (;_logfont.lfFaceName[i]; i++) { - } - _face = cast(string)(_logfont.lfFaceName[0..i].dup); - _height = tm.tmHeight; - _baseline = _height - tm.tmDescent; - return true; - } } class Win32FontManager : FontManager { + FontRef[] _activeFonts; + FontDef[] _fontFaces; + FontDef*[string] _faceByName; public this() { instance = this; init(); @@ -123,15 +124,98 @@ class Win32FontManager : FontManager { 0U // not used; must be 0 ); destroy(drawbuf); - Log.i("EnumFontFamiliesExA returned ", res); + Log.i("Found ", _fontFaces.length, " font faces"); return res!=0; } - public override Font getFont(int size, int weight, bool italic, FontFamily family, string face) { - // TODO: - return null; + public override FontRef getFont(int size, int weight, bool italic, FontFamily family, string face) { + FontRef res; + FontDef * def = findFace(family, face); + if (def !is null) { + for (int i = 0; i < _activeFonts.length; i++) { + Font item = _activeFonts[i].get; + if (item.family != def.family) + continue; + if (item.size != size) + continue; + if (item.italic != italic || item.weight != weight) + continue; + if (!equal(item.face, def.face)) + continue; + res = _activeFonts[i]; + break; + } + if (res.isNull) { + Win32Font item = new Win32Font(); + if (!item.create(def, size, weight, italic)) + return res; + res = item; + _activeFonts ~= res; + } + } + return res; } - public bool registerFont(FontFamily family, string fontFace, const LOGFONTA * logfont) { + FontDef * findFace(FontFamily family) { + FontDef * res = null; + switch(family) { + case FontFamily.SansSerif: + res = findFace("Arial"); if (res !is null) return res; + res = findFace("Tahoma"); if (res !is null) return res; + res = findFace("Calibri"); if (res !is null) return res; + res = findFace("Verdana"); if (res !is null) return res; + res = findFace("Lucida Sans"); if (res !is null) return res; + break; + case FontFamily.Serif: + res = findFace("Times New Roman"); if (res !is null) return res; + res = findFace("Georgia"); if (res !is null) return res; + res = findFace("Century Schoolbook"); if (res !is null) return res; + res = findFace("Bookman Old Style"); if (res !is null) return res; + break; + case FontFamily.MonoSpace: + res = findFace("Courier New"); if (res !is null) return res; + res = findFace("Lucida Console"); if (res !is null) return res; + res = findFace("Century Schoolbook"); if (res !is null) return res; + res = findFace("Bookman Old Style"); if (res !is null) return res; + break; + case FontFamily.Cursive: + res = findFace("Comic Sans MS"); if (res !is null) return res; + res = findFace("Lucida Handwriting"); if (res !is null) return res; + res = findFace("Monotype Corsiva"); if (res !is null) return res; + break; + default: + break; + } + return null; + } + FontDef * findFace(string face) { + if (face.length == 0) + return null; + if (face in _faceByName) + return _faceByName[face]; + return null; + } + public FontDef * findFace(FontFamily family, string face) { + // by face only + FontDef * res = findFace(face); + if (res !is null) + return res; + // best for family + res = findFace(family); + if (res !is null) + return res; + for (int i = 0; i < _fontFaces.length; i++) { + res = &_fontFaces[i]; + if (res.family == family) + return res; + } + res = findFace(FontFamily.SansSerif); + if (res !is null) + return res; + return &_fontFaces[0]; + } + public bool registerFont(FontFamily family, string fontFace, ubyte pitchAndFamily) { Log.d("registerFont(", family, ",", fontFace, ")"); + _fontFaces ~= FontDef(family, fontFace, pitchAndFamily); + _faceByName[fontFace] = &_fontFaces[$ - 1]; return true; } } @@ -143,6 +227,18 @@ string fromStringz(const(char[]) s) { return cast(string)(s[0..i].dup); } +FontFamily pitchAndFamilyToFontFamily(ubyte flags) { + if ((flags & FF_DECORATIVE) == FF_DECORATIVE) + return FontFamily.Fantasy; + else if ((flags & (FIXED_PITCH)) != 0) // | | MONO_FONT + return FontFamily.MonoSpace; + else if ((flags & (FF_ROMAN)) != 0) + return FontFamily.Serif; + else if ((flags & (FF_SCRIPT)) != 0) + return FontFamily.Cursive; + return FontFamily.SansSerif; +} + // definition extern(Windows) { int LVWin32FontEnumFontFamExProc( @@ -161,24 +257,11 @@ extern(Windows) { void * p = cast(void*)lParam; Win32FontManager fontman = cast(Win32FontManager)p; string face = fromStringz(lf.lfFaceName); - Log.d("face:", face); - Win32Font fnt = new Win32Font(); - //if (strcmp(lf->lfFaceName, "Courier New")) - // return 1; - if (fnt.create(lf)) - { - // - wchar chars[] = [0, 0xBF, 0xE9, 0x106, 0x410, 0x44F, 0]; - for (int i=0; chars[i]; i++) - { - //LVFont::glyph_info_t glyph; - //if (!fnt.getGlyphInfo( chars[i], &glyph, L' ' )) //def_char - // return 1; - } - fontman.registerFont(fnt.family, fnt.face, lf); - } - fnt.clear(); - destroy(fnt); + FontFamily family = pitchAndFamilyToFontFamily(lf.lfPitchAndFamily); + if (face.length < 2 || face[0] == '@') + return 1; + //Log.d("face:", face); + fontman.registerFont(family, face, lf.lfPitchAndFamily); } return 1; }