mirror of https://github.com/buggins/dlangui.git
freetype support
This commit is contained in:
parent
993b367913
commit
aab292ecad
|
@ -129,7 +129,7 @@ class Font : RefCountedObject {
|
||||||
}
|
}
|
||||||
// draw text string to buffer
|
// draw text string to buffer
|
||||||
abstract void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color);
|
abstract void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color);
|
||||||
abstract Glyph * getCharGlyph(dchar ch);
|
abstract Glyph * getCharGlyph(dchar ch, bool withImage = true);
|
||||||
|
|
||||||
// clear usage flags for all entries
|
// clear usage flags for all entries
|
||||||
abstract void checkpoint();
|
abstract void checkpoint();
|
||||||
|
@ -154,7 +154,7 @@ struct FontList {
|
||||||
ref FontRef get(int index) {
|
ref FontRef get(int index) {
|
||||||
return _list[index];
|
return _list[index];
|
||||||
}
|
}
|
||||||
// returns index of found item, -1 if not found
|
// find by a set of parameters - returns index of found item, -1 if not found
|
||||||
int find(int size, int weight, bool italic, FontFamily family, string face) {
|
int find(int size, int weight, bool italic, FontFamily family, string face) {
|
||||||
for (int i = 0; i < _len; i++) {
|
for (int i = 0; i < _len; i++) {
|
||||||
Font item = _list[i].get;
|
Font item = _list[i].get;
|
||||||
|
@ -170,6 +170,16 @@ struct FontList {
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
// find by size only - returns index of found item, -1 if not found
|
||||||
|
int find(int size) {
|
||||||
|
for (int i = 0; i < _len; i++) {
|
||||||
|
Font item = _list[i].get;
|
||||||
|
if (item.size != size)
|
||||||
|
continue;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
ref FontRef add(Font item) {
|
ref FontRef add(Font item) {
|
||||||
Log.d("FontList.add() enter");
|
Log.d("FontList.add() enter");
|
||||||
if (_len >= _list.length) {
|
if (_len >= _list.length) {
|
||||||
|
|
|
@ -39,6 +39,7 @@ private struct FontDef {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FontFileItem {
|
private class FontFileItem {
|
||||||
|
private FontList _activeFonts;
|
||||||
private FT_Library _library;
|
private FT_Library _library;
|
||||||
private FontDef _def;
|
private FontDef _def;
|
||||||
string[] _filenames;
|
string[] _filenames;
|
||||||
|
@ -56,6 +57,20 @@ private class FontFileItem {
|
||||||
_library = library;
|
_library = library;
|
||||||
_def = def;
|
_def = def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FontRef _nullFontRef;
|
||||||
|
ref FontRef get(int size) {
|
||||||
|
int index = _activeFonts.find(size);
|
||||||
|
if (index >= 0)
|
||||||
|
return _activeFonts.get(index);
|
||||||
|
FreeTypeFont font = new FreeTypeFont(this, size);
|
||||||
|
if (!font.create()) {
|
||||||
|
destroy(font);
|
||||||
|
return _nullFontRef;
|
||||||
|
}
|
||||||
|
return _activeFonts.add(font);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FreeTypeFontFile {
|
private class FreeTypeFontFile {
|
||||||
|
@ -206,16 +221,16 @@ private class FreeTypeFontFile {
|
||||||
return ch_glyph_index;
|
return ch_glyph_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
int myabs(int n) { return n >= 0 ? n : -n; }
|
|
||||||
|
|
||||||
/// retrieve glyph information, filling glyph struct; returns false if glyph not found
|
/// retrieve glyph information, filling glyph struct; returns false if glyph not found
|
||||||
bool getGlyphInfo(dchar code, Glyph glyph, dchar def_char)
|
bool getGlyphInfo(dchar code, Glyph glyph, dchar def_char, bool withImage = true)
|
||||||
{
|
{
|
||||||
//FONT_GUARD
|
//FONT_GUARD
|
||||||
int glyph_index = getCharIndex(code, def_char);
|
int glyph_index = getCharIndex(code, def_char);
|
||||||
int flags = FT_LOAD_DEFAULT;
|
int flags = FT_LOAD_DEFAULT;
|
||||||
const bool _drawMonochrome = false;
|
const bool _drawMonochrome = false;
|
||||||
flags |= (!_drawMonochrome ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO);
|
flags |= (!_drawMonochrome ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO);
|
||||||
|
if (withImage)
|
||||||
|
flags |= FT_LOAD_RENDER;
|
||||||
//if (_hintingMode == HINTING_MODE_AUTOHINT)
|
//if (_hintingMode == HINTING_MODE_AUTOHINT)
|
||||||
// flags |= FT_LOAD_FORCE_AUTOHINT;
|
// flags |= FT_LOAD_FORCE_AUTOHINT;
|
||||||
//else if (_hintingMode == HINTING_MODE_DISABLED)
|
//else if (_hintingMode == HINTING_MODE_DISABLED)
|
||||||
|
@ -226,11 +241,25 @@ private class FreeTypeFontFile {
|
||||||
flags ); /* load flags, see below */
|
flags ); /* load flags, see below */
|
||||||
if ( error )
|
if ( error )
|
||||||
return false;
|
return false;
|
||||||
|
glyph.lastUsage = 1;
|
||||||
glyph.blackBoxX = cast(ubyte)(_slot.metrics.width >> 6);
|
glyph.blackBoxX = cast(ubyte)(_slot.metrics.width >> 6);
|
||||||
glyph.blackBoxY = cast(ubyte)(_slot.metrics.height >> 6);
|
glyph.blackBoxY = cast(ubyte)(_slot.metrics.height >> 6);
|
||||||
glyph.originX = cast(byte)(_slot.metrics.horiBearingX >> 6);
|
glyph.originX = cast(byte)(_slot.metrics.horiBearingX >> 6);
|
||||||
glyph.originY = cast(byte)(_slot.metrics.horiBearingY >> 6);
|
glyph.originY = cast(byte)(_slot.metrics.horiBearingY >> 6);
|
||||||
glyph.width = cast(ubyte)(myabs(_slot.metrics.horiAdvance) >> 6);
|
glyph.width = cast(ubyte)(myabs(_slot.metrics.horiAdvance) >> 6);
|
||||||
|
if (withImage) {
|
||||||
|
FT_Bitmap* bitmap = &_slot.bitmap;
|
||||||
|
ubyte w = cast(ubyte)(bitmap.width);
|
||||||
|
ubyte h = cast(ubyte)(bitmap.rows);
|
||||||
|
glyph.blackBoxX = w;
|
||||||
|
glyph.blackBoxY = h;
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,44 +316,88 @@ class FreeTypeFont : Font {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
override Glyph * getCharGlyph(dchar ch) {
|
/// find glyph index for character
|
||||||
uint glyphIndex = getGlyphIndex(ch);
|
bool findGlyph(dchar code, dchar def_char, ref FT_UInt index, ref FreeTypeFontFile file) {
|
||||||
if (!glyphIndex)
|
foreach(FreeTypeFontFile f; _files) {
|
||||||
|
index = f.getCharIndex(code, def_char);
|
||||||
|
if (index != 0) {
|
||||||
|
file = f;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Glyph tmpGlyphInfo;
|
||||||
|
override Glyph * getCharGlyph(dchar ch, bool withImage = true) {
|
||||||
|
if (ch > 0xFFFF) // do not support unicode chars above 0xFFFF - due to cache limitations
|
||||||
return null;
|
return null;
|
||||||
|
Glyph * found = _glyphCache.find(cast(ushort)ch);
|
||||||
|
if (found !is null)
|
||||||
|
return found;
|
||||||
|
FT_UInt index;
|
||||||
|
FreeTypeFontFile file;
|
||||||
|
if (!findGlyph(ch, 0, index, file)) {
|
||||||
|
if (!findGlyph(ch, '?', index, file))
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (!file.getGlyphInfo(ch, tmpGlyphInfo, 0, withImage))
|
||||||
|
return null;
|
||||||
|
if (withImage)
|
||||||
|
return _glyphCache.put(cast(ushort)ch, &tmpGlyphInfo);
|
||||||
|
return &tmpGlyphInfo;
|
||||||
|
}
|
||||||
|
|
||||||
// draw text string to buffer
|
// draw text string to buffer
|
||||||
override void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color) {
|
override void drawText(DrawBuf buf, int x, int y, const dchar[] text, uint color) {
|
||||||
int[] widths;
|
int[] widths;
|
||||||
int charsMeasured = measureText(text, widths, 3000);
|
|
||||||
int bl = baseline;
|
int bl = baseline;
|
||||||
for (int i = 0; i < charsMeasured; i++) {
|
int xx = 0;
|
||||||
int xx = (i > 0) ? widths[i - 1] : 0;
|
for (int i = 0; i < text.length; i++) {
|
||||||
Glyph * glyph = getCharGlyph(text[i]);
|
Glyph * glyph = getCharGlyph(text[i], true);
|
||||||
if (glyph is null)
|
if (glyph is null)
|
||||||
continue;
|
continue;
|
||||||
if ( glyph.blackBoxX && glyph.blackBoxY ) {
|
if ( glyph.blackBoxX && glyph.blackBoxY ) {
|
||||||
buf.drawGlyph( x + xx + glyph.originX,
|
int x0 = x + xx + glyph.originX;
|
||||||
y + bl - glyph.originY,
|
int y0 = y + bl - glyph.originY;
|
||||||
|
if (x0 > buf.width)
|
||||||
|
break; // outside right bound
|
||||||
|
Rect rc = Rect(x0, y0, x0 + glyph.blackBoxX, y0 + glyph.blackBoxY);
|
||||||
|
if (buf.applyClipping(rc))
|
||||||
|
buf.drawGlyph( x0,
|
||||||
|
y0,
|
||||||
glyph,
|
glyph,
|
||||||
color);
|
color);
|
||||||
}
|
}
|
||||||
|
xx += glyph.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override int measureText(const dchar[] text, ref int[] widths, int maxWidth) {
|
override int measureText(const dchar[] text, ref int[] widths, int maxWidth) {
|
||||||
if (text.length == 0)
|
if (text.length == 0)
|
||||||
return 0;
|
return 0;
|
||||||
dstring utf32text = toUTF32(text);
|
const dchar * pstr = text.ptr;
|
||||||
const dchar * pstr = utf32text.ptr;
|
uint len = cast(uint)text.length;
|
||||||
uint len = cast(uint)utf32text.length;
|
int x = 0;
|
||||||
bool res = false;
|
int charsMeasured = 0;
|
||||||
if (!res) {
|
for (int i = 0; i < len; i++) {
|
||||||
widths[0] = 0;
|
Glyph * glyph = getCharGlyph(text[i], true); // TODO: what is better
|
||||||
return 0;
|
if (glyph is null) {
|
||||||
|
// if no glyph, use previous width - treat as zero width
|
||||||
|
widths[i] = i > 0 ? widths[i-1] : 0;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
return 0;
|
int w = x + glyph.width; // using advance
|
||||||
|
int w2 = x + glyph.originX + glyph.blackBoxX; // using black box
|
||||||
|
if (w < w2) // choose bigger value
|
||||||
|
w = w2;
|
||||||
|
widths[i] = w;
|
||||||
|
x += glyph.width;
|
||||||
|
charsMeasured = i + 1;
|
||||||
|
if (x > maxWidth)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return charsMeasured;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool create() {
|
bool create() {
|
||||||
|
@ -373,6 +446,27 @@ class FreeTypeFontManager : FontManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FontFileItem findBestMatch(int weight, bool italic, FontFamily family, string face) {
|
||||||
|
FontFileItem best = null;
|
||||||
|
int bestScore = 0;
|
||||||
|
foreach(FontFileItem item; _fontFiles) {
|
||||||
|
int score = 0;
|
||||||
|
if (face is null || face.equal(item.def.face))
|
||||||
|
score += 200; // face match
|
||||||
|
if (family == item.def.family)
|
||||||
|
score += 100; // family match
|
||||||
|
if (italic == item.def.italic)
|
||||||
|
score += 50; // italic match
|
||||||
|
int weightDiff = myabs(weight - item.def.weight);
|
||||||
|
score += 30 - weightDiff / 30; // weight match
|
||||||
|
if (score > bestScore) {
|
||||||
|
bestScore = score;
|
||||||
|
best = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
private FontList _activeFonts;
|
private FontList _activeFonts;
|
||||||
|
|
||||||
private static FontRef _nullFontRef;
|
private static FontRef _nullFontRef;
|
||||||
|
@ -395,7 +489,10 @@ class FreeTypeFontManager : FontManager {
|
||||||
|
|
||||||
/// get font instance with specified parameters
|
/// get font instance with specified parameters
|
||||||
override ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face) {
|
override ref FontRef getFont(int size, int weight, bool italic, FontFamily family, string face) {
|
||||||
|
FontFileItem f = findBestMatch(weight, italic, family, face);
|
||||||
|
if (f is null)
|
||||||
return _nullFontRef;
|
return _nullFontRef;
|
||||||
|
return f.get(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// clear usage flags for all entries
|
/// clear usage flags for all entries
|
||||||
|
@ -443,3 +540,5 @@ class FreeTypeFontManager : FontManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int myabs(int n) { return n >= 0 ? n : -n; }
|
||||||
|
|
|
@ -100,7 +100,7 @@ class Win32Font : Font {
|
||||||
return g[0];
|
return g[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
override Glyph * getCharGlyph(dchar ch) {
|
override Glyph * getCharGlyph(dchar ch, bool withImage = true) {
|
||||||
uint glyphIndex = getGlyphIndex(ch);
|
uint glyphIndex = getGlyphIndex(ch);
|
||||||
if (!glyphIndex)
|
if (!glyphIndex)
|
||||||
return null;
|
return null;
|
||||||
|
|
Loading…
Reference in New Issue