diff --git a/uppdev/FontInfo/Compose.cpp b/uppdev/FontInfo/Compose.cpp index ec681521d..97465e30f 100644 --- a/uppdev/FontInfo/Compose.cpp +++ b/uppdev/FontInfo/Compose.cpp @@ -1,223 +1,223 @@ -#include "FontInfo.h" - -enum { - CG_NONE, - CG_CAPITAL, - CG_SMALL -}; - -enum { - CG_GRAVE = 0x60, - CG_ACUTE = 0xb4, - CG_CEDILLA = 0xb8, - CG_MACRON = 175, - CG_CIRCUMFLEX = 0x2c6, - CG_TILDE = 0x2dc, - CG_DOT_ABOVE = 0x2d9, - CG_OGONEK = 0x2db, - CG_STROKE = '-', - CG_BREVE = 0x2d8, - CG_CARON = 0x2c7, - CG_MIDDLE_DOT = 0xb7, - CG_DOUBLE_ACUTE = 0x2dd, - CG_DIAERESIS = 0xa8, - CG_RING_ABOVE = 0x2da, - CG_COMMA_T = ',', - CG_COMMA_UR = 1, - CG_COMMA_URI, -}; - -struct CGInfo { - byte type; - char ascii; - wchar mark; -} -gc_info[128] = { - { CG_CAPITAL, 'A', CG_MACRON }, - { CG_SMALL, 'a', CG_MACRON }, - { CG_CAPITAL, 'A', CG_BREVE }, - { CG_SMALL, 'a', CG_BREVE }, - { CG_CAPITAL, 'A', CG_OGONEK }, - { CG_SMALL, 'a', CG_OGONEK }, - { CG_CAPITAL, 'C', CG_ACUTE }, - { CG_SMALL, 'c', CG_ACUTE }, - { CG_CAPITAL, 'C', CG_CIRCUMFLEX }, - { CG_SMALL, 'c', CG_CIRCUMFLEX }, - { CG_CAPITAL, 'C', CG_DOT_ABOVE }, - { CG_SMALL, 'c', CG_DOT_ABOVE }, - { CG_CAPITAL, 'C', CG_CARON }, - { CG_SMALL, 'c', CG_CARON }, - { CG_CAPITAL, 'D', CG_CARON }, - { CG_SMALL, 'd', CG_COMMA_UR }, - { CG_CAPITAL, 'D', CG_STROKE }, - { CG_SMALL, 'd', CG_STROKE }, - { CG_CAPITAL, 'E', CG_MACRON }, - { CG_SMALL, 'e', CG_MACRON }, - { CG_CAPITAL, 'E', CG_BREVE }, - { CG_SMALL, 'e', CG_BREVE }, - { CG_CAPITAL, 'E', CG_DOT_ABOVE }, - { CG_SMALL, 'e', CG_DOT_ABOVE }, - { CG_CAPITAL, 'E', CG_OGONEK }, - { CG_SMALL, 'e', CG_OGONEK }, - { CG_CAPITAL, 'E', CG_CARON }, - { CG_SMALL, 'e', CG_CARON }, - { CG_CAPITAL, 'G', CG_CIRCUMFLEX }, - { CG_SMALL, 'g', CG_CIRCUMFLEX }, - { CG_CAPITAL, 'G', CG_BREVE }, - { CG_SMALL, 'g', CG_BREVE }, - { CG_CAPITAL, 'G', CG_DOT_ABOVE }, - { CG_SMALL, 'g', CG_DOT_ABOVE }, - { CG_CAPITAL, 'G', CG_CEDILLA }, - { CG_SMALL, 'g', CG_CEDILLA }, - { CG_CAPITAL, 'H', CG_CIRCUMFLEX }, - { CG_SMALL, 'h', CG_CIRCUMFLEX }, - { CG_CAPITAL, 'H', CG_STROKE }, - { CG_SMALL, 'h', CG_STROKE }, - { CG_CAPITAL, 'I', CG_TILDE }, - { CG_SMALL, 'i', CG_TILDE }, - { CG_CAPITAL, 'I', CG_MACRON }, - { CG_SMALL, 'i', CG_MACRON }, - { CG_CAPITAL, 'I', CG_BREVE }, - { CG_SMALL, 'i', CG_BREVE }, - { CG_CAPITAL, 'I', CG_OGONEK }, - { CG_SMALL, 'i', CG_OGONEK }, - { CG_CAPITAL, 'I', CG_DOT_ABOVE }, - { CG_NONE, 0, 0 }, // , CG_SMALL, 'DOTLESS I - { CG_NONE, 0, 0 }, // LATIN CAPITAL LIGATURE IJ - { CG_NONE, 0, 0 }, // LATIN SMALL LIGATURE IJ - { CG_CAPITAL, 'J', CG_CIRCUMFLEX }, - { CG_SMALL, 'j', CG_CIRCUMFLEX }, - { CG_CAPITAL, 'K', CG_CEDILLA }, - { CG_SMALL, 'k', CG_CEDILLA }, - { CG_NONE, 0, 0 }, // CG_SMALL, 'KRA - { CG_CAPITAL, 'L', CG_ACUTE }, - { CG_SMALL, 'l', CG_ACUTE }, - { CG_CAPITAL, 'L', CG_CEDILLA }, - { CG_SMALL, 'l', CG_CEDILLA }, - { CG_CAPITAL, 'L', CG_COMMA_URI }, - { CG_SMALL, 'l', CG_COMMA_UR }, - { CG_CAPITAL, 'L', CG_MIDDLE_DOT }, - { CG_SMALL, 'l', CG_MIDDLE_DOT }, - { CG_CAPITAL, 'L', CG_STROKE }, - { CG_SMALL, 'l', CG_STROKE }, - { CG_CAPITAL, 'N', CG_ACUTE }, - { CG_SMALL, 'n', CG_ACUTE }, - { CG_CAPITAL, 'N', CG_CEDILLA }, - { CG_SMALL, 'n', CG_CEDILLA }, - { CG_CAPITAL, 'N', CG_CARON }, - { CG_SMALL, 'n', CG_CARON }, - { CG_NONE, 0, 0 }, // CG_SMALL, 'N PRECEDED BY APOSTROPHE - { CG_NONE, 0, 0 }, //CG_CAPITAL, 'ENG - { CG_NONE, 0, 0 }, //CG_SMALL, 'ENG - { CG_CAPITAL, 'O', CG_MACRON }, - { CG_SMALL, 'o', CG_MACRON }, - { CG_CAPITAL, 'O', CG_BREVE }, - { CG_SMALL, 'o', CG_BREVE }, - { CG_CAPITAL, 'O', CG_DOUBLE_ACUTE }, - { CG_SMALL, 'o', CG_DOUBLE_ACUTE }, - { CG_NONE, 0, 0 }, // LATIN CAPITAL LIGATURE OE - { CG_NONE, 0, 0 }, // LATIN SMALL LIGATURE OE - { CG_CAPITAL, 'R', CG_ACUTE }, - { CG_SMALL, 'r', CG_ACUTE }, - { CG_CAPITAL, 'R', CG_CEDILLA }, - { CG_SMALL, 'r', CG_CEDILLA }, - { CG_CAPITAL, 'R', CG_CARON }, - { CG_SMALL, 'r', CG_CARON }, - { CG_CAPITAL, 'S', CG_ACUTE }, - { CG_SMALL, 's', CG_ACUTE }, - { CG_CAPITAL, 'S', CG_CIRCUMFLEX }, - { CG_SMALL, 's', CG_CIRCUMFLEX }, - { CG_CAPITAL, 'S', CG_CEDILLA }, - { CG_SMALL, 's', CG_CEDILLA }, - { CG_CAPITAL, 'S', CG_CARON }, - { CG_SMALL, 's', CG_CARON }, - { CG_CAPITAL, 'T', CG_CEDILLA }, - { CG_SMALL, 't', CG_CEDILLA }, - { CG_CAPITAL, 'T', CG_CARON }, - { CG_SMALL, 't', CG_COMMA_T }, - { CG_CAPITAL, 'T', CG_STROKE }, - { CG_SMALL, 't', CG_STROKE }, - { CG_CAPITAL, 'U', CG_TILDE }, - { CG_SMALL, 'u', CG_TILDE }, - { CG_CAPITAL, 'U', CG_MACRON }, - { CG_SMALL, 'u', CG_MACRON }, - { CG_CAPITAL, 'U', CG_BREVE }, - { CG_SMALL, 'u', CG_BREVE }, - { CG_CAPITAL, 'U', CG_RING_ABOVE }, - { CG_SMALL, 'u', CG_RING_ABOVE }, - { CG_CAPITAL, 'U', CG_DOUBLE_ACUTE }, - { CG_SMALL, 'u', CG_DOUBLE_ACUTE }, - { CG_CAPITAL, 'U', CG_OGONEK }, - { CG_SMALL, 'u', CG_OGONEK }, - { CG_CAPITAL, 'W', CG_CIRCUMFLEX }, - { CG_SMALL, 'w', CG_CIRCUMFLEX }, - { CG_CAPITAL, 'Y', CG_CIRCUMFLEX }, - { CG_SMALL, 'y', CG_CIRCUMFLEX }, - { CG_CAPITAL, 'Y', CG_DIAERESIS }, - { CG_CAPITAL, 'Z', CG_ACUTE }, - { CG_SMALL, 'z', CG_ACUTE }, - { CG_CAPITAL, 'Z', CG_DOT_ABOVE }, - { CG_SMALL, 'z', CG_DOT_ABOVE }, - { CG_CAPITAL, 'Z', CG_CARON }, - { CG_SMALL, 'z', CG_CARON }, - { CG_NONE, 0, 0 } // CG_SMALL, 'LONG S -}; - -bool Compose(Font font, int chr, ComposedGlyph& cg) -{ - if(chr < 256 || chr > 256 + 128) - return false; - CGInfo f = gc_info[chr - 256]; - if(f.type == CG_NONE) - return false; - GlyphInfo gi = GetGlyphInfo(font, f.ascii); - if(gi.IsMissing()) - return false; - int cw = gi.width; - CommonFontInfo fi = GetFontInfo(font); - gi = GetGlyphInfo(font, f.mark); - if(gi.IsMissing()) - return false; - int mw = gi.width; - cg.mark_font = font; - cg.mark_pos.x = cg.mark_pos.y = 0; - cg.basic_char = f.ascii; - cg.mark_char = f.mark; - if(cg.mark_char == CG_COMMA_UR && fi.fixedpitch) - cg.mark_char = CG_CARON; - if(cg.mark_char == CG_COMMA_T) { - cg.mark_pos.y -= 3 * font.GetHeight() / 4; - cg.mark_pos.x += 4 * cw / 10; - if(font.IsItalic()) - cg.mark_pos.x += mw / 2; - } - else - if(cg.mark_char == CG_COMMA_UR) { - cg.mark_pos.y -= 2 * font.GetHeight() / 3; - cg.mark_pos.x += cw - mw / 4; - cg.mark_char = ','; - if(font.IsItalic()) - cg.mark_pos.x += mw / 3; - } - else - if(cg.mark_char == CG_COMMA_URI) { - cg.mark_pos.y -= 2 * font.GetHeight() / 3; - cg.mark_pos.x += cw - mw / 2; - cg.mark_char = ','; - if(font.IsItalic()) - cg.mark_pos.x += mw / 3; - } - else - if(cg.mark_char != CG_STROKE) { - if(cg.mark_char != CG_OGONEK && cg.mark_char != CG_CEDILLA && f.type == CG_CAPITAL) { - cg.mark_font = font(9 * font.GetHeight() / 10); - mw = GetGlyphInfo(cg.mark_font, f.mark).width; - cg.mark_pos.y -= cg.mark_char == CG_RING_ABOVE ? font.GetHeight() / 19 - : font.GetHeight() / 10; - } - cg.mark_pos.x += (cw - mw) / 2; - if(font.IsItalic()) - cg.mark_pos.x += mw / 5; - } - return true; -} +#include "FontInfo.h" + +enum { + CG_NONE, + CG_CAPITAL, + CG_SMALL +}; + +enum { + CG_GRAVE = 0x60, + CG_ACUTE = 0xb4, + CG_CEDILLA = 0xb8, + CG_MACRON = 175, + CG_CIRCUMFLEX = 0x2c6, + CG_TILDE = 0x2dc, + CG_DOT_ABOVE = 0x2d9, + CG_OGONEK = 0x2db, + CG_STROKE = '-', + CG_BREVE = 0x2d8, + CG_CARON = 0x2c7, + CG_MIDDLE_DOT = 0xb7, + CG_DOUBLE_ACUTE = 0x2dd, + CG_DIAERESIS = 0xa8, + CG_RING_ABOVE = 0x2da, + CG_COMMA_T = ',', + CG_COMMA_UR = 1, + CG_COMMA_URI, +}; + +struct CGInfo { + byte type; + char ascii; + wchar mark; +} +gc_info[128] = { + { CG_CAPITAL, 'A', CG_MACRON }, + { CG_SMALL, 'a', CG_MACRON }, + { CG_CAPITAL, 'A', CG_BREVE }, + { CG_SMALL, 'a', CG_BREVE }, + { CG_CAPITAL, 'A', CG_OGONEK }, + { CG_SMALL, 'a', CG_OGONEK }, + { CG_CAPITAL, 'C', CG_ACUTE }, + { CG_SMALL, 'c', CG_ACUTE }, + { CG_CAPITAL, 'C', CG_CIRCUMFLEX }, + { CG_SMALL, 'c', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'C', CG_DOT_ABOVE }, + { CG_SMALL, 'c', CG_DOT_ABOVE }, + { CG_CAPITAL, 'C', CG_CARON }, + { CG_SMALL, 'c', CG_CARON }, + { CG_CAPITAL, 'D', CG_CARON }, + { CG_SMALL, 'd', CG_COMMA_UR }, + { CG_CAPITAL, 'D', CG_STROKE }, + { CG_SMALL, 'd', CG_STROKE }, + { CG_CAPITAL, 'E', CG_MACRON }, + { CG_SMALL, 'e', CG_MACRON }, + { CG_CAPITAL, 'E', CG_BREVE }, + { CG_SMALL, 'e', CG_BREVE }, + { CG_CAPITAL, 'E', CG_DOT_ABOVE }, + { CG_SMALL, 'e', CG_DOT_ABOVE }, + { CG_CAPITAL, 'E', CG_OGONEK }, + { CG_SMALL, 'e', CG_OGONEK }, + { CG_CAPITAL, 'E', CG_CARON }, + { CG_SMALL, 'e', CG_CARON }, + { CG_CAPITAL, 'G', CG_CIRCUMFLEX }, + { CG_SMALL, 'g', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'G', CG_BREVE }, + { CG_SMALL, 'g', CG_BREVE }, + { CG_CAPITAL, 'G', CG_DOT_ABOVE }, + { CG_SMALL, 'g', CG_DOT_ABOVE }, + { CG_CAPITAL, 'G', CG_CEDILLA }, + { CG_SMALL, 'g', CG_CEDILLA }, + { CG_CAPITAL, 'H', CG_CIRCUMFLEX }, + { CG_SMALL, 'h', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'H', CG_STROKE }, + { CG_SMALL, 'h', CG_STROKE }, + { CG_CAPITAL, 'I', CG_TILDE }, + { CG_SMALL, 'i', CG_TILDE }, + { CG_CAPITAL, 'I', CG_MACRON }, + { CG_SMALL, 'i', CG_MACRON }, + { CG_CAPITAL, 'I', CG_BREVE }, + { CG_SMALL, 'i', CG_BREVE }, + { CG_CAPITAL, 'I', CG_OGONEK }, + { CG_SMALL, 'i', CG_OGONEK }, + { CG_CAPITAL, 'I', CG_DOT_ABOVE }, + { CG_NONE, 0, 0 }, // , CG_SMALL, 'DOTLESS I + { CG_NONE, 0, 0 }, // LATIN CAPITAL LIGATURE IJ + { CG_NONE, 0, 0 }, // LATIN SMALL LIGATURE IJ + { CG_CAPITAL, 'J', CG_CIRCUMFLEX }, + { CG_SMALL, 'j', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'K', CG_CEDILLA }, + { CG_SMALL, 'k', CG_CEDILLA }, + { CG_NONE, 0, 0 }, // CG_SMALL, 'KRA + { CG_CAPITAL, 'L', CG_ACUTE }, + { CG_SMALL, 'l', CG_ACUTE }, + { CG_CAPITAL, 'L', CG_CEDILLA }, + { CG_SMALL, 'l', CG_CEDILLA }, + { CG_CAPITAL, 'L', CG_COMMA_URI }, + { CG_SMALL, 'l', CG_COMMA_UR }, + { CG_CAPITAL, 'L', CG_MIDDLE_DOT }, + { CG_SMALL, 'l', CG_MIDDLE_DOT }, + { CG_CAPITAL, 'L', CG_STROKE }, + { CG_SMALL, 'l', CG_STROKE }, + { CG_CAPITAL, 'N', CG_ACUTE }, + { CG_SMALL, 'n', CG_ACUTE }, + { CG_CAPITAL, 'N', CG_CEDILLA }, + { CG_SMALL, 'n', CG_CEDILLA }, + { CG_CAPITAL, 'N', CG_CARON }, + { CG_SMALL, 'n', CG_CARON }, + { CG_NONE, 0, 0 }, // CG_SMALL, 'N PRECEDED BY APOSTROPHE + { CG_NONE, 0, 0 }, //CG_CAPITAL, 'ENG + { CG_NONE, 0, 0 }, //CG_SMALL, 'ENG + { CG_CAPITAL, 'O', CG_MACRON }, + { CG_SMALL, 'o', CG_MACRON }, + { CG_CAPITAL, 'O', CG_BREVE }, + { CG_SMALL, 'o', CG_BREVE }, + { CG_CAPITAL, 'O', CG_DOUBLE_ACUTE }, + { CG_SMALL, 'o', CG_DOUBLE_ACUTE }, + { CG_NONE, 0, 0 }, // LATIN CAPITAL LIGATURE OE + { CG_NONE, 0, 0 }, // LATIN SMALL LIGATURE OE + { CG_CAPITAL, 'R', CG_ACUTE }, + { CG_SMALL, 'r', CG_ACUTE }, + { CG_CAPITAL, 'R', CG_CEDILLA }, + { CG_SMALL, 'r', CG_CEDILLA }, + { CG_CAPITAL, 'R', CG_CARON }, + { CG_SMALL, 'r', CG_CARON }, + { CG_CAPITAL, 'S', CG_ACUTE }, + { CG_SMALL, 's', CG_ACUTE }, + { CG_CAPITAL, 'S', CG_CIRCUMFLEX }, + { CG_SMALL, 's', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'S', CG_CEDILLA }, + { CG_SMALL, 's', CG_CEDILLA }, + { CG_CAPITAL, 'S', CG_CARON }, + { CG_SMALL, 's', CG_CARON }, + { CG_CAPITAL, 'T', CG_CEDILLA }, + { CG_SMALL, 't', CG_CEDILLA }, + { CG_CAPITAL, 'T', CG_CARON }, + { CG_SMALL, 't', CG_COMMA_T }, + { CG_CAPITAL, 'T', CG_STROKE }, + { CG_SMALL, 't', CG_STROKE }, + { CG_CAPITAL, 'U', CG_TILDE }, + { CG_SMALL, 'u', CG_TILDE }, + { CG_CAPITAL, 'U', CG_MACRON }, + { CG_SMALL, 'u', CG_MACRON }, + { CG_CAPITAL, 'U', CG_BREVE }, + { CG_SMALL, 'u', CG_BREVE }, + { CG_CAPITAL, 'U', CG_RING_ABOVE }, + { CG_SMALL, 'u', CG_RING_ABOVE }, + { CG_CAPITAL, 'U', CG_DOUBLE_ACUTE }, + { CG_SMALL, 'u', CG_DOUBLE_ACUTE }, + { CG_CAPITAL, 'U', CG_OGONEK }, + { CG_SMALL, 'u', CG_OGONEK }, + { CG_CAPITAL, 'W', CG_CIRCUMFLEX }, + { CG_SMALL, 'w', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'Y', CG_CIRCUMFLEX }, + { CG_SMALL, 'y', CG_CIRCUMFLEX }, + { CG_CAPITAL, 'Y', CG_DIAERESIS }, + { CG_CAPITAL, 'Z', CG_ACUTE }, + { CG_SMALL, 'z', CG_ACUTE }, + { CG_CAPITAL, 'Z', CG_DOT_ABOVE }, + { CG_SMALL, 'z', CG_DOT_ABOVE }, + { CG_CAPITAL, 'Z', CG_CARON }, + { CG_SMALL, 'z', CG_CARON }, + { CG_NONE, 0, 0 } // CG_SMALL, 'LONG S +}; + +bool Compose(Font font, int chr, ComposedGlyph& cg) +{ + if(chr < 256 || chr > 256 + 128) + return false; + CGInfo f = gc_info[chr - 256]; + if(f.type == CG_NONE) + return false; + GlyphInfo gi = GetGlyphInfo(font, f.ascii); + if(!gi.IsNormal()) + return false; + int cw = gi.width; + CommonFontInfo fi = GetFontInfo(font); + gi = GetGlyphInfo(font, f.mark); + if(!gi.IsNormal()) + return false; + int mw = gi.width; + cg.mark_font = font; + cg.mark_pos.x = cg.mark_pos.y = 0; + cg.basic_char = f.ascii; + cg.mark_char = f.mark; + if(cg.mark_char == CG_COMMA_UR && fi.fixedpitch) + cg.mark_char = CG_CARON; + if(cg.mark_char == CG_COMMA_T) { + cg.mark_pos.y -= 3 * font.GetHeight() / 4; + cg.mark_pos.x += 4 * cw / 10; + if(font.IsItalic()) + cg.mark_pos.x += mw / 2; + } + else + if(cg.mark_char == CG_COMMA_UR) { + cg.mark_pos.y -= 2 * font.GetHeight() / 3; + cg.mark_pos.x += cw - mw / 4; + cg.mark_char = ','; + if(font.IsItalic()) + cg.mark_pos.x += mw / 3; + } + else + if(cg.mark_char == CG_COMMA_URI) { + cg.mark_pos.y -= 2 * font.GetHeight() / 3; + cg.mark_pos.x += cw - mw / 2; + cg.mark_char = ','; + if(font.IsItalic()) + cg.mark_pos.x += mw / 3; + } + else + if(cg.mark_char != CG_STROKE) { + if(cg.mark_char != CG_OGONEK && cg.mark_char != CG_CEDILLA && f.type == CG_CAPITAL) { + cg.mark_font = font(9 * font.GetHeight() / 10); + mw = GetGlyphInfo(cg.mark_font, f.mark).width; + cg.mark_pos.y -= cg.mark_char == CG_RING_ABOVE ? font.GetHeight() / 19 + : font.GetHeight() / 10; + } + cg.mark_pos.x += (cw - mw) / 2; + if(font.IsItalic()) + cg.mark_pos.x += mw / 5; + } + return true; +} diff --git a/uppdev/FontInfo/FontInfo.cpp b/uppdev/FontInfo/FontInfo.cpp index e3b68d1e6..932b342cf 100644 --- a/uppdev/FontInfo/FontInfo.cpp +++ b/uppdev/FontInfo/FontInfo.cpp @@ -1,117 +1,170 @@ -#include "FontInfo.h" - -struct CharEntry { - GlyphInfo info; - word chr; - Font font; -}; - -CharEntry fc_cache_global[4096]; - -CharEntry GetGlyphEntry(Font font, int chr) -{ - DrawLock __; - unsigned hash = CombineHash(font.GetHashValue(), chr) & 511; - CharEntry& e = fc_cache_global[hash]; - if(e.font != font || e.chr != chr) { - e.font = font; - e.chr = chr; - e.info = GetGlyphInfoSys(font, chr); - if(!e.info.IsNormal()) { - ComposedGlyph cg; - Font rfnt; - if(Compose(font, chr, cg)) { - e.info.lspc = -1; - e.info.rspc = cg.basic_char; - } - else - if(Replace(font, chr, rfnt)) - e.info.lspc = rfnt.GetFace(); - else - e.info.lspc = -2; - } - } - return e; -} - -thread__ CharEntry fc_cache[512]; - -GlyphInfo GetGlyphInfo(Font font, int chr) -{ - unsigned hash = CombineHash(font.GetHashValue(), chr) & 511; - CharEntry& e = fc_cache[hash]; - if(e.font != font || e.chr != chr) - e = GetGlyphEntry(font, chr); - return e.info; -} - -void GlyphMetrics(GlyphInfo& f, Font font, int chr) -{ - if(f.IsReplaced()) - f = GetGlyphInfo(font().Face(f.lspc), chr); - if(f.IsComposed()) { - f = GetGlyphInfo(font, f.rspc); - if(f.IsComposedLM()) - f.rspc += f.width / 2; - } -} - -GlyphInfo GetGlyphMetrics(Font font, int chr) -{ - GlyphInfo f = GetGlyphInfo(font, chr); - if(f.IsMissing()) - f = GetGlyphInfo(font, '?'); - GlyphMetrics(f, font, chr); - return f; -} - -struct FontEntry { - CommonFontInfo info; - Font font; -}; - -thread__ FontEntry fi_cache[64]; - -const CommonFontInfo& GetFontInfo(Font font) -{ - unsigned hash = font.GetHashValue() & 63; - FontEntry& e = fi_cache[hash]; - if(e.font != font) { - DrawLock __; - e.font = font; - e.info = GetFontInfoSys(font); - } - return e.info; -} - -void DoDrawText(Draw& w, int x, int y, int angle, const wchar *text, Font font, Color ink, - int n, const int *dx) -{ - for(int i = 0; i < n; i++) { - wchar chr = text[i]; - GlyphInfo gi = GetGlyphInfo(font, chr); - if(gi.IsNormal()) - w.DrawTextOp(x, y, angle, &chr, font, ink, 1, NULL); - else - if(gi.IsReplaced()) { - FontInfo fi = font.Info(); - Font fnt = font; - fnt.Face(gi.lspc); - FontInfo fi2 = fnt.Info(); - w.DrawTextOp(x, y + fi.GetAscent() - fi2.GetAscent(), angle, &chr, fnt, ink, 1, NULL); - GlyphMetrics(gi, font, chr); - } - else - if(gi.IsComposed()) { - ComposedGlyph cg; - Compose(font, chr, cg); - w.DrawTextOp(x, y, angle, &cg.basic_char, font, ink, 1, NULL); - w.DrawTextOp(x + cg.mark_pos.x, y + cg.mark_pos.y, angle, &cg.mark_char, cg.mark_font, ink, 1, NULL); - GlyphMetrics(gi, font, chr); - } - if(dx) - x += *dx++; - else - x += gi.width; - } -} +#include "FontInfo.h" + +void Std(Font& font) +{ + if(IsNull(font)) + font = StdFont(); + if(font.GetFace() == 0) + font.Face(GetStdFont.GetFace()); + if(font.GetHeight() == 0) + font.Height(GetStdFont.GetHeight()); +} + +struct CharEntry { + GlyphInfo info; + word chr; + Font font; +}; + +CharEntry fc_cache_global[4093]; + +bool IsNormal(Font font, int chr) +{ + DrawLock __; + CharEntry& e = fc_cache_global[CombineHash(font.GetHashValue(), chr) % 4093]; + if(e.font == font || e.chr == chr) + return e.info.IsNormal(); + return GetGlyphInfoSys(font, chr).IsNormal(); +} + +CharEntry GetGlyphEntry(Font font, int chr, unsigned hash) +{ + DrawLock __; + CharEntry& e = fc_cache_global[hash % 4093]; + if(e.font != font || e.chr != chr) { + e.font = font; + e.chr = chr; + e.info = GetGlyphInfoSys(font, chr); + if(!e.info.IsNormal()) { + ComposedGlyph cg; + Font rfnt; + if(Compose(font, chr, cg)) { + e.info.lspc = -1; + e.info.rspc = cg.basic_char; + } + else + if(Replace(font, chr, rfnt)) + e.info.lspc = rfnt.GetFace(); + else + e.info.lspc = -2; + } + } + return e; +} + +thread__ CharEntry fc_cache[512]; + +GlyphInfo GetGlyphInfo(Font font, int chr) +{ + Std(font); + unsigned hash = CombineHash(font.GetHashValue(), chr); + CharEntry& e = fc_cache[hash & 511]; + if(e.font != font || e.chr != chr) + e = GetGlyphEntry(font, chr, hash); + return e.info; +} + +void GlyphMetrics(GlyphInfo& f, Font font, int chr) +{ + if(f.IsReplaced()) + f = GetGlyphInfo(font().Face(f.lspc), chr); + if(f.IsComposed()) { + f = GetGlyphInfo(font, f.rspc); + if(f.IsComposedLM()) + f.rspc += f.width / 2; + } +} + +GlyphInfo GetGlyphMetrics(Font font, int chr) +{ + GlyphInfo f = GetGlyphInfo(font, chr); + if(f.IsMissing()) + f = GetGlyphInfo(font, '?'); + GlyphMetrics(f, font, chr); + return f; +} + +struct FontEntry { + CommonFontInfo info; + Font font; +}; + +thread__ FontEntry fi_cache[64]; + +const CommonFontInfo& GetFontInfo(Font font) +{ + Std(font); + unsigned hash = font.GetHashValue() & 63; + FontEntry& e = fi_cache[hash]; + if(e.font != font) { + DrawLock __; + e.font = font; + e.info = GetFontInfoSys(font); + } + return e.info; +} + +void DoDrawText(Draw& w, int x, int y, int angle, const wchar *text, Font font, Color ink, + int n, const int *dx) +{ + Std(font); + double sina; + double cosa; + int d = 0; + if(angle) + Draw::SinCos(angle, sina, cosa); //TODO global sin tables! + for(int i = 0; i < n; i++) { + wchar chr = text[i]; + GlyphInfo gi = GetGlyphInfo(font, chr); + if(gi.IsNormal()) + if(angle) + w.DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &chr, font, ink, 1, NULL); + else { + int c = 1; + int dd = 0; + if(!dx) + while(c < n) { + GlyphInfo gi2 = GetGlyphInfo(font, text[i + c]); + if(!gi2.IsNormal()) + break; + c++; + dd += gi.width; + gi = gi2; + } + w.DrawTextOp(x + d, y, 0, text + i, font, ink, c, NULL); + i += c - 1; + d += dd; + } + else + if(gi.IsReplaced()) { + FontInfo fi = font.Info(); + Font fnt = font; + fnt.Face(gi.lspc); + FontInfo fi2 = fnt.Info(); + if(angle) + w.DrawTextOp(int(x + cosa * d), int(y - sina * (fi.GetAscent() - fi2.GetAscent() + d)), + angle, &chr, fnt, ink, 1, NULL); + else + w.DrawTextOp(x + d, y + fi.GetAscent() - fi2.GetAscent(), 0, &chr, fnt, ink, 1, NULL); + GlyphMetrics(gi, font, chr); + } + else + if(gi.IsComposed()) { + ComposedGlyph cg; + Compose(font, chr, cg); + if(angle) { + w.DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &cg.basic_char, font, ink, 1, NULL); + w.DrawTextOp(int(x + cosa * (d + cg.mark_pos.x)), int(y - sina * (cg.mark_pos.y + d)), angle, &cg.mark_char, cg.mark_font, ink, 1, NULL); + } + else { + w.DrawTextOp(x + d, y, angle, &cg.basic_char, font, ink, 1, NULL); + w.DrawTextOp(x + cg.mark_pos.x + d, y + cg.mark_pos.y, angle, &cg.mark_char, cg.mark_font, ink, 1, NULL); + } + GlyphMetrics(gi, font, chr); + } + if(dx) + d += *dx++; + else + d += gi.width; + } +} diff --git a/uppdev/FontInfo/FontInfo.h b/uppdev/FontInfo/FontInfo.h index 2b4517dfe..36e80b889 100644 --- a/uppdev/FontInfo/FontInfo.h +++ b/uppdev/FontInfo/FontInfo.h @@ -1,75 +1,79 @@ -#ifndef _FontInfo_FontInfo_h_ -#define _FontInfo_FontInfo_h_ - -#include - -using namespace Upp; - -struct CommonFontInfo : Moveable { - int ascent; - int descent; - int external; - int internal; - int height; - int lineheight; - int overhang; - int avewidth; - int maxwidth; - int firstchar; - int charcount; - int default_char; - int spacebefore; - int spaceafter; - bool fixedpitch; - bool scaleable; - -#ifdef PLATFORM_POSIX - int underline_thickness; - int underline_position; - String path; -#endif -}; - -CommonFontInfo GetFontInfoSys(Font font); - -struct GlyphInfo : Moveable { - int16 width; - int16 lspc; - int16 rspc; - - bool IsNormal() const { return (word)width != 0x8000; } - bool IsComposed() const { return !IsNormal() && (lspc == -1 || lspc == -11); } - bool IsComposedLM() const { return !IsNormal() && lspc == -11; } - bool IsReplaced() const { return !IsNormal() && lspc >= 0; } - bool IsMissing() const { return !IsNormal() && lspc == -2; } -}; - -GlyphInfo GetGlyphInfoSys(Font font, int chr); - -struct FaceInfo : Moveable { - String name; - dword info; -}; - -Vector GetAllFacesSys(); - -GlyphInfo GetGlyphInfo(Font font, int chr); -void GlyphMetrics(GlyphInfo& f, Font font, int chr); -GlyphInfo GetGlyphMetrics(Font font, int chr); - -const CommonFontInfo& GetFontInfo(Font font); - -struct ComposedGlyph { - wchar basic_char; - Point mark_pos; - wchar mark_char; - Font mark_font; -}; - -bool Compose(Font fnt, int chr, ComposedGlyph& cs); -bool Replace(Font fnt, int chr, Font& rfnt); - -void DoDrawText(Draw& w, int x, int y, int angle, const wchar *text, Font font, Color ink, - int n, const int *dx); - -#endif +#ifndef _FontInfo_FontInfo_h_ +#define _FontInfo_FontInfo_h_ + +#include + +using namespace Upp; + +struct CommonFontInfo : Moveable { + int ascent; + int descent; + int external; + int internal; + int height; + int lineheight; + int overhang; + int avewidth; + int maxwidth; + int firstchar; + int charcount; + int default_char; + int spacebefore; + int spaceafter; + bool fixedpitch; + bool scaleable; + +#ifdef PLATFORM_POSIX + int underline_thickness; + int underline_position; + String path; +#endif +}; + +CommonFontInfo GetFontInfoSys(Font font); + +struct GlyphInfo : Moveable { + int16 width; + int16 lspc; + int16 rspc; + + bool IsNormal() const { return (word)width != 0x8000; } + bool IsComposed() const { return !IsNormal() && (lspc == -1 || lspc == -11); } + bool IsComposedLM() const { return !IsNormal() && lspc == -11; } + bool IsReplaced() const { return !IsNormal() && lspc >= 0; } + bool IsMissing() const { return !IsNormal() && lspc == -2; } +}; + +GlyphInfo GetGlyphInfoSys(Font font, int chr); + +struct FaceInfo : Moveable { + String name; + dword info; +}; + +Vector GetAllFacesSys(); + +void Std(Font& font); + +bool IsNormal(Font font, int chr); + +GlyphInfo GetGlyphInfo(Font font, int chr); +void GlyphMetrics(GlyphInfo& f, Font font, int chr); +GlyphInfo GetGlyphMetrics(Font font, int chr); + +const CommonFontInfo& GetFontInfo(Font font); + +struct ComposedGlyph { + wchar basic_char; + Point mark_pos; + wchar mark_char; + Font mark_font; +}; + +bool Compose(Font fnt, int chr, ComposedGlyph& cs); +bool Replace(Font fnt, int chr, Font& rfnt); + +void DoDrawText(Draw& w, int x, int y, int angle, const wchar *text, Font font, Color ink, + int n, const int *dx); + +#endif diff --git a/uppdev/FontInfo/FontInfo.upp b/uppdev/FontInfo/FontInfo.upp index 0a9b700f2..3628b596f 100644 --- a/uppdev/FontInfo/FontInfo.upp +++ b/uppdev/FontInfo/FontInfo.upp @@ -8,7 +8,7 @@ file Win32.cpp, X11.cpp, Compose.cpp, - FontReplace.cpp, + FontReplace.cpp charset "UTF-8", FontInfo.cpp, main.cpp charset "UTF-8", app.tpp; diff --git a/uppdev/FontInfo/FontReplace.cpp b/uppdev/FontInfo/FontReplace.cpp index cd950ff6f..664987bae 100644 --- a/uppdev/FontInfo/FontReplace.cpp +++ b/uppdev/FontInfo/FontReplace.cpp @@ -1,44 +1,46 @@ -#include "FontInfo.h" - -static const char *sFontReplacements[] = { - "Symbol", - "Arial Unicode MS", - "Arial", - "MS UI Gothic", - "MS Mincho", - "Arial", - "Gulim", - "SimSun", - "PMingLiU", -}; - -bool Replace(Font fnt, int chr, Font& rfnt) -{ - static Vector rface; - ONCELOCK { - for(int i = 0; i < __countof(sFontReplacements); i++) { - int q = Font::FindFaceNameIndex(sFontReplacements[i]); - if(q > 0) - rface.Add(q); - } - DDUMP(rface.GetCount()); - } - static Font last; - static Font lastR; - if(last == fnt && GetGlyphInfo(lastR, chr).IsNormal()) { - rfnt = lastR; - return true; - } - Font f = fnt; - for(int i = 0; i < rface.GetCount(); i++) { - f.Face(rface[i]); - DDUMP(f.GetFaceName()); - if(GetGlyphInfo(f, chr).IsNormal()) { - LOG("-----------"); - last = fnt; - rfnt = lastR = f; - return true; - } - } - return false; -} +#include "FontInfo.h" + +static const char *sFontReplacements[] = { + "sans-serif", + "Arial", + "Arial Unicode MS", + "Symbol", + "文泉驛等寬正黑", + "文泉驛正黑", + "MS UI Gothic", + "MS Mincho", + "Arial", + "AlArabiya" + "FreeSerif", + "Kochi Mincho", + "Kochi Gothic", + "Sazanami Mincho", + "Sazanami Gothic", + "Gulim", + "SimSun", + "PMingLiU", +}; + +bool Replace(Font fnt, int chr, Font& rfnt) +{ +// ASSERT(chr >= 0 && chr < + LOG("Replace: " << fnt << ": " << chr); + static Vector rface; + ONCELOCK { + for(int i = 0; i < __countof(sFontReplacements) && rface.GetCount() < 20; i++) { + int q = Font::FindFaceNameIndex(sFontReplacements[i]); + if(q > 0) + rface.Add(q); + } + } + + Font f = fnt; + for(int i = 0; i < rface.GetCount(); i++) + if(IsNormal(f.Face(rface[i]), chr)) { + rfnt = f; + LOG("Replacement: " << rfnt); + return true; + } + LOG("No replace"); + return false; +} diff --git a/uppdev/FontInfo/X11.cpp b/uppdev/FontInfo/X11.cpp index e2f7bdd8d..0f17e50f2 100644 --- a/uppdev/FontInfo/X11.cpp +++ b/uppdev/FontInfo/X11.cpp @@ -1,188 +1,222 @@ -#include "FontInfo.h" - -#define LTIMING(x) - -#ifdef PLATFORM_X11 - -static FT_Library sFTlib; - -bool sInitFt(void) -{ - if(sFTlib) - return true; - return FT_Init_FreeType(&sFTlib) == 0; -} - -FcPattern *CreateFcPattern(Font font, int angle) -{ - LTIMING("CreateXftFont"); - double sina, cosa; - int hg = abs(font.GetHeight()); - if(hg == 0) hg = 10; - String n = font.GetFaceName(); - const char *face = n; - FcPattern *p = FcPatternCreate(); - FcPatternAddString(p, FC_FAMILY, (FcChar8*)face); - FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0); - FcPatternAddInteger(p, FC_PIXEL_SIZE, hg); - FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100); - FcPatternAddBool(p, FC_MINSPACE, 1); - if(angle) { - FcMatrix mx; - Draw::SinCos(angle, sina, cosa); - mx.xx = cosa; - mx.xy = -sina; - mx.yx = sina; - mx.yy = cosa; - FcPatternAddMatrix(p, FC_MATRIX, &mx); - } - FcResult result; - FcPattern *m = XftFontMatch(Xdisplay, Xscreenno, p, &result); - FcPatternDestroy(p); - return m; -} - -FT_Face CreateFTFace(const FcPattern *pattern, String *rpath) { - FT_Face face = NULL; - - int id; - double dsize; - double aspect; - FcChar8 *filename; - - if(!sInitFt()) - return NULL; - - if(FcPatternGetString(pattern, FC_FILE, 0, &filename) != FcResultMatch) - return NULL; - - if(rpath) - *rpath = (const char *)filename; - - if(FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &dsize) != FcResultMatch) - dsize = 16; - - if (FcPatternGetDouble(pattern, FC_ASPECT, 0, &aspect) != FcResultMatch) - aspect = 1.0; - - FT_F26Dot6 ysize = (FT_F26Dot6) (dsize * 64.0); - FT_F26Dot6 xsize = (FT_F26Dot6) (dsize * aspect * 64.0); - - if(FT_New_Face (sFTlib, (const char *)filename, 0, &face)) - return NULL; - - FT_Set_Char_Size(face, xsize, ysize, 0, 0); - return face; -} - -FT_Face FTFace(Font fnt, String *rpath = NULL) -{ - static FT_Face cached_face; - static Font cached_font; - if(cached_font != fnt) { - cached_font = fnt; - if(cached_face) - FT_Done_Face(cached_face); - FcPattern *p = CreateFcPattern(cached_font, 0); - cached_face = CreateFTFace(p, rpath); - FcPatternDestroy(p); - } - return cached_face; -} - -CommonFontInfo GetFontInfoSys(Font font) -{ - CommonFontInfo fi; - - FT_Face face = FTFace(font, &fi.path); - if(face) { - fi.ascent = face->size->metrics.ascender >> 6; - fi.descent = -(face->size->metrics.descender >> 6); - fi.height = fi.ascent + fi.descent; - fi.lineheight = face->size->metrics.height >> 6; - fi.external = 0; - fi.internal = 0; - fi.overhang = 0; - fi.maxwidth = face->size->metrics.max_advance >> 6; - fi.avewidth = fi.maxwidth; - fi.default_char = '?'; - fi.fixedpitch = font.GetFaceInfo() & Font::FIXEDPITCH; - int hg = abs(font.GetHeight()); - if(hg == 0) hg = 10; - fi.underline_thickness = max(hg / 20, 1); - fi.underline_position = max(hg / 15, int(fi.descent > 0)); - } - return fi; -} - -#define FLOOR(x) ((x) & -64) -#define CEIL(x) (((x)+63) & -64) -#define TRUNC(x) ((x) >> 6) -#define ROUND(x) (((x)+32) & -64) - -GlyphInfo GetGlyphInfoSys(Font font, int chr) -{ - GlyphInfo gi; - FT_Face face = FTFace(font, NULL); - gi.lspc = gi.rspc = 0; - gi.width = 0x8000; - if(face) { - int glyph_index = FT_Get_Char_Index(face, chr); - if(glyph_index && - (FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP) == 0 || - FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0)) { - FT_Glyph_Metrics& m = face->glyph->metrics; - int left = FLOOR(m.horiBearingX); - int width = TRUNC(CEIL(m.horiBearingX + m.width) - left); - gi.width = TRUNC(ROUND(face->glyph->advance.x)); - gi.lspc = TRUNC(left); - gi.rspc = gi.width - width - gi.lspc; - } - } - return gi; -} - -Vector GetAllFacesSys() -{ - static const char *basic_fonts[] = { - "sans-serif", - "serif", - "sans-serif", - "monospace", - "serif", - "sans-serif", - "monospace", - }; - - Vector list; - for(int i = 0; i < __countof(basic_fonts); i++) { - FaceInfo& fi = list.Add(); - f.name = basic_fonts[i]; - f.scaleable = true; - f.fixed = i == 3 || i == 6; - f.compose = sCheckComposed(basic_fonts[i]); - } - FcPattern *p = FcPatternCreate(); - FcObjectSet *os = FcObjectSetBuild(XFT_FAMILY, XFT_SPACING, XFT_SCALABLE, (void *)0); - FcFontSet *fs = FcFontList(NULL, p, os); - FcPatternDestroy(p); - FcObjectSetDestroy(os); - for(int i = 0; i < fs->nfont; i++) { - FcChar8 *family = NULL; - if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == 0 && family) { - FaceInfo& fi = list.Add(); - fi.name = (const char *)family; - fi.type = 0; - int iv; - if(FcPatternGetInteger(fs->fonts[i], FC_SPACING, 0, &iv) == 0 && iv == FC_MONO) - fi.type |= Font::FIXEDPITCH; - FcBool bv; - if(FcPatternGetBool(fs->fonts[i], FC_SCALABLE, 0, &bv) == 0 && bv) - fi.type |= Font::SCALEABLE; - } - } - FcFontSetDestroy(fs); - return list; -} - -#endif +#include "FontInfo.h" + +#define LTIMING(x) + +#ifdef PLATFORM_X11 + +static FT_Library sFTlib; + +bool sInitFt(void) +{ + if(sFTlib) + return true; + return FT_Init_FreeType(&sFTlib) == 0; +} + +FcPattern *CreateFcPattern(Font font, int angle) +{ + LTIMING("CreateXftFont"); + double sina, cosa; + int hg = abs(font.GetHeight()); + if(hg == 0) hg = 10; + String n = font.GetFaceName(); + const char *face = n; + FcPattern *p = FcPatternCreate(); + FcPatternAddString(p, FC_FAMILY, (FcChar8*)face); + FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0); + FcPatternAddInteger(p, FC_PIXEL_SIZE, hg); + FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100); + FcPatternAddBool(p, FC_MINSPACE, 1); + if(angle) { + FcMatrix mx; + Draw::SinCos(angle, sina, cosa); + mx.xx = cosa; + mx.xy = -sina; + mx.yx = sina; + mx.yy = cosa; + FcPatternAddMatrix(p, FC_MATRIX, &mx); + } + FcResult result; + FcPattern *m = XftFontMatch(Xdisplay, Xscreenno, p, &result); + FcPatternDestroy(p); + return m; +} + +FT_Face CreateFTFace(const FcPattern *pattern, String *rpath) { + FT_Face face = NULL; + + int id; + double dsize; + double aspect; + FcChar8 *filename; + + if(!sInitFt()) + return NULL; + + if(FcPatternGetString(pattern, FC_FILE, 0, &filename) != FcResultMatch) + return NULL; + + if(rpath) + *rpath = (const char *)filename; + + if(FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &dsize) != FcResultMatch) + dsize = 16; + + if (FcPatternGetDouble(pattern, FC_ASPECT, 0, &aspect) != FcResultMatch) + aspect = 1.0; + + FT_F26Dot6 ysize = (FT_F26Dot6) (dsize * 64.0); + FT_F26Dot6 xsize = (FT_F26Dot6) (dsize * aspect * 64.0); + + if(FT_New_Face (sFTlib, (const char *)filename, 0, &face)) + return NULL; + + FT_Set_Char_Size(face, xsize, ysize, 0, 0); + return face; +} + +#define FONTCACHE 37 + +struct FtFaceEntry { + Font font; + FT_Face face; + String path; +}; + +FT_Face FTFace(Font fnt, String *rpath = NULL) +{ + RTIMING("FTFace"); + DDUMP(fnt); + static FtFaceEntry cache[FONTCACHE]; + ONCELOCK { + for(int i = 0; i < FONTCACHE; i++) + cache[i].font.Height(-30000); + } + FtFaceEntry be; + be = cache[0]; + for(int i = 0; i < FONTCACHE; i++) { + FtFaceEntry e = cache[i]; + if(i) + cache[i] = be; + if(e.font == fnt) { + if(rpath) + *rpath = e.path; + if(i) + cache[0] = e; + return e.face; + } + be = e; + } + RTIMING("FTFace2"); + if(be.face) { + LOG("Removing " << be.font << " - " << (void *)be.face); + FT_Done_Face(be.face); + } + be.font = fnt; + FcPattern *p = CreateFcPattern(fnt, 0); + be.face = CreateFTFace(p, &be.path); + FcPatternDestroy(p); + cache[0] = be; + if(rpath) + *rpath = be.path; + for(int i = 0; i < FONTCACHE; i++) + LOG(i << ": " << cache[i].font); + return be.face; +} + +CommonFontInfo GetFontInfoSys(Font font) +{ + CommonFontInfo fi; + + FT_Face face = FTFace(font, &fi.path); + if(face) { + fi.ascent = face->size->metrics.ascender >> 6; + fi.descent = -(face->size->metrics.descender >> 6); + fi.height = fi.ascent + fi.descent; + fi.lineheight = face->size->metrics.height >> 6; + fi.external = 0; + fi.internal = 0; + fi.overhang = 0; + fi.maxwidth = face->size->metrics.max_advance >> 6; + fi.avewidth = fi.maxwidth; + fi.default_char = '?'; + fi.fixedpitch = font.GetFaceInfo() & Font::FIXEDPITCH; + int hg = abs(font.GetHeight()); + if(hg == 0) hg = 10; + fi.underline_thickness = max(hg / 20, 1); + fi.underline_position = max(hg / 15, int(fi.descent > 0)); + } + return fi; +} + +#define FLOOR(x) ((x) & -64) +#define CEIL(x) (((x)+63) & -64) +#define TRUNC(x) ((x) >> 6) +#define ROUND(x) (((x)+32) & -64) + +GlyphInfo GetGlyphInfoSys(Font font, int chr) +{ + RTIMING("GetGlyphInfoSys"); + GlyphInfo gi; + FT_Face face = FTFace(font, NULL); + gi.lspc = gi.rspc = 0; + gi.width = 0x8000; + if(face) { + RTIMING("GetGlyphInfoSys 2"); + int glyph_index = FT_Get_Char_Index(face, chr); + if(glyph_index && + (FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP) == 0 || + FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0)) { + FT_Glyph_Metrics& m = face->glyph->metrics; + int left = FLOOR(m.horiBearingX); + int width = TRUNC(CEIL(m.horiBearingX + m.width) - left); + gi.width = TRUNC(ROUND(face->glyph->advance.x)); + gi.lspc = TRUNC(left); + gi.rspc = gi.width - width - gi.lspc; + } + } + return gi; +} + +Vector GetAllFacesSys() +{ + static const char *basic_fonts[] = { + "sans-serif", + "serif", + "sans-serif", + "monospace", + "serif", + "sans-serif", + "monospace", + }; + + Vector list; + for(int i = 0; i < __countof(basic_fonts); i++) { + FaceInfo& fi = list.Add(); + fi.name = basic_fonts[i]; + fi.info = (i == 3 || i == 6) ? Font::SCALEABLE|Font::FIXEDPITCH : Font::SCALEABLE; + } + FcPattern *p = FcPatternCreate(); + FcObjectSet *os = FcObjectSetBuild(XFT_FAMILY, XFT_SPACING, XFT_SCALABLE, (void *)0); + FcFontSet *fs = FcFontList(NULL, p, os); + FcPatternDestroy(p); + FcObjectSetDestroy(os); + for(int i = 0; i < fs->nfont; i++) { + FcChar8 *family = NULL; + if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == 0 && family) { + FaceInfo& fi = list.Add(); + fi.name = (const char *)family; + fi.info = 0; + int iv; + if(FcPatternGetInteger(fs->fonts[i], FC_SPACING, 0, &iv) == 0 && iv == FC_MONO) + fi.info |= Font::FIXEDPITCH; + FcBool bv; + if(FcPatternGetBool(fs->fonts[i], FC_SCALABLE, 0, &bv) == 0 && bv) + fi.info |= Font::SCALEABLE; + } + } + FcFontSetDestroy(fs); + return list; +} + +#endif diff --git a/uppdev/FontInfo/main.cpp b/uppdev/FontInfo/main.cpp index 016dafb30..af557675e 100644 --- a/uppdev/FontInfo/main.cpp +++ b/uppdev/FontInfo/main.cpp @@ -1,150 +1,179 @@ -#include "FontInfo.h" - -using namespace Upp; - -struct CharDisplay : public Display { - virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const - { - w.DrawRect(r, paper); - w.DrawText(r.left, r.top, AsString(q), StdFont(), ink); - Font fnt; - fnt.FaceName("Bitstream Vera Sans Mono"); - fnt.Height(13); - WString txt((int)q, 1); - w.DrawText(r.left + 40, r.top, txt, Courier(20), ink); - GlyphInfo gi = GetGlyphMetrics(fnt, q); - w.DrawRect(r.left + 60, r.top, gi.width, r.GetHeight(), LtCyan()); - gi = GetGlyphInfo(fnt, q); - if(!gi.IsMissing()) { - if(gi.IsNormal()) - w.DrawText(r.left + 60, r.top, txt, fnt); - else - if(gi.IsReplaced()) - w.DrawText(r.left + 60, r.top, txt, fnt().Face(gi.lspc), Magenta()); - else - if(gi.IsComposed()) { - ComposedGlyph g; - if(Compose(fnt, q, g)) { - w.DrawText(r.left + 60, r.top, WString(g.basic_char, 1), fnt, LtBlue()); - w.DrawText(r.left + 60 + g.mark_pos.x, r.top + g.mark_pos.y, - WString(g.mark_char, 1), g.mark_font, LtRed()); - } - } - } - else - w.DrawText(r.left + 60, r.top, txt, fnt, ink); - w.DrawRect(r.left, r.bottom - 1, r.Width(), 1, Black()); - } - -}; - -Size GetTextSizeNew(const wchar *text, Font font, int n) -{ - int cx = 0; - const wchar *wtext = (const wchar *)text; - while(n > 0) { - cx += GetGlyphInfo(font, *wtext++).width; - n--; - } - return Size(cx, GetFontInfo(font).height); -} - -struct App : TopWindow { - virtual void Paint(Draw& w) { - WString h = "Hello ěščřžýáíéúů "; - for(int i = 0; i < 10; i++) - h.Cat(20000 + i); - w.DrawRect(GetSize(), White()); - Font fnt; - fnt.FaceName("Bitstream Vera Sans Mono"); - fnt.Height(13); - DoDrawText(w, 100, 100, 0, h, fnt, Black(), h.GetCount(), NULL); - } -}; - -GUI_APP_MAIN -{ - SetDefaultCharset(CHARSET_UTF8); - App app; - app.Open(); - GetGlyphInfo(Font().FaceName("Bitstream Vera Sans Mono").Height(20), 461); - ColumnList list; - list.SetDisplay(Single()); - list.ItemHeight(25).Columns(12); - for(int i = 32; i < 65536; i++) - list.Add(i); - TopWindow win; -// list.SetCursor(461); - win.Add(list.SizePos()); - win.Run(); - - return; - - FontInfo fi = Arial(100).Bold().Info(); - DUMP(fi.GetAscent()); - DUMP(fi.GetDescent()); - DUMP(fi.GetMaxWidth()); - - { - int from = 0; - for(int i = 0; i < 65536; i++) { - GlyphInfo g = GetGlyphInfoSys(Arial(100).Bold(), i); - if(g.IsMissing()) { -// if(!fi.HasChar(i)) { - if(from < i) - LOG(from << " - " << i - 1); - from = i + 1; - } - } - if(from < 65535) - LOG(from << " - " << 65535); - } - - Vector fa = GetAllFacesSys(); - for(int i = 0; i < fa.GetCount(); i++) - LOG(fa[i].name << ": scalable: " << (fa[i].info & Font::SCALEABLE) << ", fixed: " << (fa[i].info & Font::FIXEDPITCH)); - CommonFontInfo f = GetFontInfoSys(Arial(100).Bold()); - DUMP(f.ascent); - DUMP(f.descent); - DUMP(f.lineheight); - DUMP(f.maxwidth); -// DUMP(f.path); - - - for(int c = '0'; c < 'z'; c++) { - LOG("-------------------------"); - DUMP((char)c); - GlyphInfo g = GetGlyphInfoSys(Arial(100).Bold(), c); - DUMP(g.width); - DUMP(fi[c]); - DUMP(g.lspc); - DUMP(fi.GetLeftSpace(c)); - DUMP(g.rspc); - DUMP(fi.GetRightSpace(c)); - } - - -#if 0 - WString x = "Just a little test!"; - RDUMP(GetTextSize(x, Arial(20), x.GetCount())); - RDUMP(GetTextSizeNew(x, Arial(20), x.GetCount())); - RDUMP(sizeof(GlyphInfo)); - RDUMP(sizeof(CharEntry)); - RDUMP(sizeof(CommonFontInfo)); - #ifndef _DEBUG - int cx = 0; - { - RTIMING("Old"); - for(int i = 0; i < 1000000; i++) { - cx += GetTextSize(x, Arial(20), x.GetCount()).cx; - } - } - { - RTIMING("New"); - for(int i = 0; i < 1000000; i++) { - cx += GetTextSizeNew(x, Arial(20), x.GetCount()).cx; - } - } - #endif -#endif -} +#include "FontInfo.h" + +using namespace Upp; + +struct CharDisplay : public Display { + virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const + { + w.DrawRect(r, paper); + w.DrawText(r.left, r.top, AsString(q), StdFont(), ink); + Font fnt; + fnt.FaceName("Bitstream Vera Sans Mono"); +// fnt.Face(Font::ARIAL); + fnt.Height(20); + WString txt((int)q, 1); + w.DrawText(r.left + 40, r.top, txt, Courier(20), ink); + GlyphInfo gi = GetGlyphMetrics(fnt, q); + w.DrawRect(r.left + 60, r.top, gi.width, r.GetHeight(), LtCyan()); + gi = GetGlyphInfo(fnt, q); + if(!gi.IsMissing()) { + if(gi.IsNormal()) + w.DrawText(r.left + 60, r.top, txt, fnt); + else + if(gi.IsReplaced()) + w.DrawText(r.left + 60, r.top, txt, fnt().Face(gi.lspc), Magenta()); + else + if(gi.IsComposed()) { + ComposedGlyph g; + if(Compose(fnt, q, g)) { + w.DrawText(r.left + 60, r.top, WString(g.basic_char, 1), fnt, LtBlue()); + w.DrawText(r.left + 60 + g.mark_pos.x, r.top + g.mark_pos.y, + WString(g.mark_char, 1), g.mark_font, LtRed()); + } + } + } + else + w.DrawText(r.left + 60, r.top, txt, fnt, ink); + w.DrawRect(r.left, r.bottom - 1, r.Width(), 1, Black()); + } + +}; + +Size GetTextSizeNew(const wchar *text, Font font, int n) +{ + int cx = 0; + const wchar *wtext = (const wchar *)text; + while(n > 0) { + cx += GetGlyphInfo(font, *wtext++).width; + n--; + } + return Size(cx, GetFontInfo(font).height); +} + +struct App : TopWindow { + virtual void Paint(Draw& w) { + WString h = "Hello ěščřžýáíéúů "; + for(int i = 0; i < 10; i++) + h.Cat(20000 + i); + w.DrawRect(GetSize(), White()); + Font fnt; + fnt.FaceName("Bitstream Vera Sans Mono"); + fnt.Height(13); + DoDrawText(w, 100, 100, 0, h, fnt, Black(), h.GetCount(), NULL); + DoDrawText(w, 100, 300, 300, h, fnt, Black(), h.GetCount(), NULL); + } +}; + +GUI_APP_MAIN +{ + SetDefaultCharset(CHARSET_UTF8); + + +#if 0 + static dword t[] = { 0x9d15, 0x3092,0x4e26,0xe20,0xf780,0x994,0x636,0xfeb2,0xfebe,0x2126 }; + VectorMap stat; + for(int i = 0; i < __countof(t); i++) { + int chr = t[i]; + LOG("-------- " << chr); + for(int i = 0; i < Font::GetFaceCount(); i++) { + Font fnt; + fnt.Height(20); + fnt.Face(i); + if(GetGlyphInfoSys(fnt, chr).IsNormal()) { + LOG(fnt.GetFaceName()); + stat.GetAdd(fnt.GetFaceName(), 0)++; + } + } + } + LOG("--------------------------"); + Vector o = GetSortOrder(stat.GetValues()); + for(int i = 0; i < o.GetCount(); i++) + LOG(stat.GetKey(o[i]) << ": " << stat[o[i]]); + LOG("--------------------------"); +#endif + App app; + app.Open(); + GetGlyphInfo(Font().FaceName("Bitstream Vera Sans Mono").Height(20), 461); + ColumnList list; + list.SetDisplay(Single()); + list.ItemHeight(25).Columns(12); + for(int i = 32; i < 65536; i++) + list.Add(i); + TopWindow win; +// list.SetCursor(461); + win.Add(list.SizePos()); + win.Run(); + + return; + + FontInfo fi = Arial(100).Bold().Info(); + DUMP(fi.GetAscent()); + DUMP(fi.GetDescent()); + DUMP(fi.GetMaxWidth()); + + { + int from = 0; + for(int i = 0; i < 65536; i++) { + GlyphInfo g = GetGlyphInfoSys(Arial(100).Bold(), i); + if(g.IsMissing()) { +// if(!fi.HasChar(i)) { + if(from < i) + LOG(from << " - " << i - 1); + from = i + 1; + } + } + if(from < 65535) + LOG(from << " - " << 65535); + } + + Vector fa = GetAllFacesSys(); + for(int i = 0; i < fa.GetCount(); i++) + LOG(fa[i].name << ": scalable: " << (fa[i].info & Font::SCALEABLE) << ", fixed: " << (fa[i].info & Font::FIXEDPITCH)); + CommonFontInfo f = GetFontInfoSys(Arial(100).Bold()); + DUMP(f.ascent); + DUMP(f.descent); + DUMP(f.lineheight); + DUMP(f.maxwidth); +// DUMP(f.path); + + + for(int c = '0'; c < 'z'; c++) { + LOG("-------------------------"); + DUMP((char)c); + GlyphInfo g = GetGlyphInfoSys(Arial(100).Bold(), c); + DUMP(g.width); + DUMP(fi[c]); + DUMP(g.lspc); + DUMP(fi.GetLeftSpace(c)); + DUMP(g.rspc); + DUMP(fi.GetRightSpace(c)); + } + + + + + +#if 0 + WString x = "Just a little test!"; + RDUMP(GetTextSize(x, Arial(20), x.GetCount())); + RDUMP(GetTextSizeNew(x, Arial(20), x.GetCount())); + RDUMP(sizeof(GlyphInfo)); + RDUMP(sizeof(CharEntry)); + RDUMP(sizeof(CommonFontInfo)); + #ifndef _DEBUG + int cx = 0; + { + RTIMING("Old"); + for(int i = 0; i < 1000000; i++) { + cx += GetTextSize(x, Arial(20), x.GetCount()).cx; + } + } + { + RTIMING("New"); + for(int i = 0; i < 1000000; i++) { + cx += GetTextSizeNew(x, Arial(20), x.GetCount()).cx; + } + } + #endif +#endif +}