diff --git a/dlangui.visualdproj b/dlangui.visualdproj index c933b26d..ced817a2 100644 --- a/dlangui.visualdproj +++ b/dlangui.visualdproj @@ -190,6 +190,11 @@ + + + + + diff --git a/src/dlangui/graphics/fonts.d b/src/dlangui/graphics/fonts.d index 36ed525a..3ffa8351 100644 --- a/src/dlangui/graphics/fonts.d +++ b/src/dlangui/graphics/fonts.d @@ -4,7 +4,7 @@ public import dlangui.core.types; public import dlangui.core.logger; import std.algorithm; -public enum FontFamily : int { +enum FontFamily : int { SansSerif, Serif, Fantasy, @@ -12,25 +12,25 @@ public enum FontFamily : int { MonoSpace } -public struct Glyph +struct Glyph { - public ubyte blackBoxX; ///< 0: width of glyph - public ubyte blackBoxY; ///< 1: height of glyph black box - public byte originX; ///< 2: X origin for glyph - public byte originY; ///< 3: Y origin for glyph - public ushort glyphIndex; ///< 4: bytes in glyph array - public ubyte width; ///< 6: full width of glyph - public ubyte lastUsage; - public ubyte[] glyph; ///< 7: glyph data, arbitrary size + ubyte blackBoxX; ///< 0: width of glyph + ubyte blackBoxY; ///< 1: height of glyph black box + byte originX; ///< 2: X origin for glyph + byte originY; ///< 3: Y origin for glyph + ushort glyphIndex; ///< 4: bytes in glyph array + ubyte width; ///< 6: full width of glyph + ubyte lastUsage; + ubyte[] glyph; ///< 7: glyph data, arbitrary size } -public struct GlyphCache +struct GlyphCache { Glyph[] _data; uint _len; // find glyph in cache - public Glyph * find(ushort glyphIndex) { + Glyph * find(ushort glyphIndex) { for (uint i = 0; i < _len; i++) { Glyph * item = &_data[i]; if (item.glyphIndex == glyphIndex) { @@ -41,7 +41,7 @@ public struct GlyphCache return null; } - public Glyph * put(ushort glyphIndex, Glyph * glyph) { + Glyph * put(ushort glyphIndex, Glyph * glyph) { if (_len >= _data.length) { uint newsize = (_len < 32) ? 32 : _len * 2; _data.length = newsize; @@ -53,14 +53,14 @@ public struct GlyphCache } // clear usage flags for all entries - public void checkpoint() { + void checkpoint() { for (uint src = 0; src < _len; src++) { _data[src].lastUsage = 0; } } // removes entries not used after last call of checkpoint() or cleanup() - public void cleanup() { + void cleanup() { uint dst = 0; for (uint src = 0; src < _len; src++) { if (_data[src].lastUsage != 0) { @@ -74,49 +74,56 @@ public struct GlyphCache } // removes all entries - public void clear() { + void clear() { _data = null; _len = 0; } - public ~this() { + ~this() { clear(); } } -public class Font : RefCountedObject { - abstract public @property int size(); - abstract public @property int height(); - abstract public @property int weight(); - abstract public @property int baseline(); - abstract public @property bool italic(); - abstract public @property string face(); - abstract public @property FontFamily family(); - abstract public @property bool isNull(); +class Font : RefCountedObject { + abstract @property int size(); + abstract @property int height(); + abstract @property int weight(); + abstract @property int baseline(); + abstract @property bool italic(); + abstract @property string face(); + abstract @property FontFamily family(); + abstract @property bool isNull(); // measure text string, return accumulated widths[] (distance to end of n-th character), returns number of measured chars. - abstract public int measureText(const dchar[] text, ref int[] widths, int maxWidth); + abstract int measureText(const dchar[] text, ref int[] widths, int maxWidth); // draw text string to buffer - abstract public void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color); - abstract public Glyph * getCharGlyph(dchar ch); - public void clear() {} - public ~this() { clear(); } + abstract void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color); + abstract Glyph * getCharGlyph(dchar ch); + + // clear usage flags for all entries + abstract void checkpoint(); + // removes entries not used after last call of checkpoint() or cleanup() + abstract void cleanup(); + + void clear() {} + + ~this() { clear(); } } alias FontRef = Ref!Font; -public struct FontList { +struct FontList { FontRef[] _list; uint _len; - public ~this() { + ~this() { for (uint i = 0; i < _len; i++) { _list[i].clear(); } } // returns item by index - public ref FontRef get(int index) { + ref FontRef get(int index) { return _list[index]; } // returns index of found item, -1 if not found - public int find(int size, int weight, bool italic, FontFamily family, string face) { - for (int i = 0; i < _list.length; i++) { + int find(int size, int weight, bool italic, FontFamily family, string face) { + for (int i = 0; i < _len; i++) { Font item = _list[i].get; if (item.family != family) continue; @@ -130,7 +137,7 @@ public struct FontList { } return -1; } - public ref FontRef add(Font item) { + ref FontRef add(Font item) { Log.d("FontList.add() enter"); if (_len >= _list.length) { _list.length = _len < 16 ? 16 : _list.length * 2; @@ -139,16 +146,43 @@ public struct FontList { Log.d("FontList.add() exit"); return _list[_len - 1]; } + // remove unused items - with reference == 1 + void cleanup() { + for (int i = 0; i < _len; i++) + if (_list[i].refCount <= 1) + _list[i].clear(); + int dst = 0; + for (int i = 0; i < _len; i++) { + if (!_list[i].isNull) + if (i != dst) + _list[dst++] = _list[i]; + } + _len = dst; + for (int i = 0; i < _len; i++) + _list[i].cleanup(); + } + void checkpoint() { + for (int i = 0; i < _len; i++) + _list[i].checkpoint(); + } } -public class FontManager { +class FontManager { static __gshared FontManager _instance; - public static @property void instance(FontManager manager) { + static @property void instance(FontManager manager) { _instance = manager; } - public static @property FontManager instance() { + static @property FontManager instance() { return _instance; } - abstract public ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face); - public ~this() {} + + abstract ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face); + + // clear usage flags for all entries + abstract void checkpoint(); + + // removes entries not used after last call of checkpoint() or cleanup() + abstract void cleanup(); + + ~this() {} } diff --git a/src/dlangui/platforms/windows/winapp.d b/src/dlangui/platforms/windows/winapp.d index 768c6daa..dff2dc91 100644 --- a/src/dlangui/platforms/windows/winapp.d +++ b/src/dlangui/platforms/windows/winapp.d @@ -1,6 +1,5 @@ module dlangui.platforms.windows.winapp; - version (Windows) { import core.runtime; @@ -31,7 +30,10 @@ struct FontDef { } } -class Win32Font : Font { +/** +* Font implementation based on Win32 API system fonts. +*/ +public class Win32Font : Font { HFONT _hfont; int _size; int _height; @@ -44,12 +46,16 @@ class Win32Font : Font { Win32ColorDrawBuf _drawbuf; GlyphCache _glyphCache; + /// need to call create() after construction to initialize font public this() { } + + /// do cleanup public ~this() { - Log.d("Deleting font"); clear(); } + + /// cleanup resources public override void clear() { if (_hfont !is null) { @@ -262,6 +268,17 @@ class Win32Font : Font { Log.d("Created font ", _face, " ", _size); return true; } + + // clear usage flags for all entries + override void checkpoint() { + _glyphCache.checkpoint(); + } + + // removes entries not used after last call of checkpoint() or cleanup() + override void cleanup() { + _glyphCache.cleanup(); + } + public @property override int size() { return _size; } public @property override int height() { return _height; } public @property override int weight() { return _weight; } @@ -273,15 +290,21 @@ class Win32Font : Font { } - +/** + * Font manager implementation based on Win32 API system fonts. + */ class Win32FontManager : FontManager { FontList _activeFonts; FontDef[] _fontFaces; FontDef*[string] _faceByName; + + /// initialize in constructor public this() { instance = this; init(); } + + /// initialize font manager by enumerating of system fonts public bool init() { Log.i("Win32FontManager.init()"); Win32ColorDrawBuf drawbuf = new Win32ColorDrawBuf(1,1); @@ -301,7 +324,11 @@ class Win32FontManager : FontManager { Log.i("Found ", _fontFaces.length, " font faces"); return res!=0; } + + /// for returning of not found font FontRef _emptyFontRef; + + /// get font by properties public override ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face) { Log.i("getFont()"); FontDef * def = findFace(family, face); @@ -319,6 +346,8 @@ class Win32FontManager : FontManager { return _emptyFontRef; } } + + /// find font face definition by family only (try to get one of defaults for family if possible) FontDef * findFace(FontFamily family) { FontDef * res = null; switch(family) { @@ -351,6 +380,8 @@ class Win32FontManager : FontManager { } return null; } + + /// find font face definition by face only FontDef * findFace(string face) { if (face.length == 0) return null; @@ -358,6 +389,8 @@ class Win32FontManager : FontManager { return _faceByName[face]; return null; } + + /// find font face definition by family and face public FontDef * findFace(FontFamily family, string face) { // by face only FontDef * res = findFace(face); @@ -377,12 +410,25 @@ class Win32FontManager : FontManager { return res; return &_fontFaces[0]; } + + /// register enumerated font 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; } + + /// clear usage flags for all entries + public override void checkpoint() { + _activeFonts.checkpoint(); + } + + /// removes entries not used after last call of checkpoint() or cleanup() + public override void cleanup() { + _activeFonts.cleanup(); + //_list.cleanup(); + } } string fromStringz(const(char[]) s) {