Developing new font metrics

git-svn-id: svn://ultimatepp.org/upp/trunk@1356 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-07-04 19:02:33 +00:00
parent ba4d690c8d
commit 98df0b46db
10 changed files with 550 additions and 91 deletions

223
uppdev/FontInfo/Compose.cpp Normal file
View file

@ -0,0 +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;
}

View file

@ -0,0 +1,117 @@
#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;
}
}

View file

@ -37,7 +37,11 @@ struct GlyphInfo : Moveable<GlyphInfo> {
int16 lspc;
int16 rspc;
bool IsMissing() const { return (word)width == (word)0x8000; }
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);
@ -49,4 +53,23 @@ struct FaceInfo : Moveable<FaceInfo> {
Vector<FaceInfo> 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

View file

@ -4,10 +4,14 @@ uses
CtrlLib;
file
FontInfo.h,
FontInfo.h charset "UTF-8",
Win32.cpp,
X11.cpp,
main.cpp;
Compose.cpp,
FontReplace.cpp,
FontInfo.cpp,
main.cpp charset "UTF-8",
app.tpp;
mainconfig
"" = "GUI";

View file

@ -0,0 +1,44 @@
#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<int> 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;
}

View file

@ -2,31 +2,46 @@
#ifdef PLATFORM_WIN32
HFONT CreateWin32Font(Font font, int angle, int chrset)
#define FONTCACHE 37
HFONT GetWin32Font(Font fnt, int angle, int chrset)
{
#ifdef PLATFORM_WINCE
LOGFONT lfnt;
Zero(lfnt);
lfnt.lfHeight = font.GetHeight() ? -abs(font.GetHeight()) : -12;
lfnt.lfWeight = font.IsBold() ? FW_BOLD : FW_NORMAL;
lfnt.lfItalic = font.IsItalic();
lfnt.lfUnderline = font.IsUnderline();
lfnt.lfStrikeOut = font.IsStrikeout();
wcscpy(lfnt.lfFaceName, ToSystemCharset(font.GetFaceName()));
return CreateFontIndirect(&lfnt);
#else
return CreateFont(
font.GetHeight() ? -abs(font.GetHeight()) : -12,
font.GetWidth(), angle, angle, font.IsBold() ? FW_BOLD : FW_NORMAL,
font.IsItalic(), font.IsUnderline(), font.IsStrikeout(),
chrset,
font.IsTrueTypeOnly() ? OUT_TT_ONLY_PRECIS : OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
font.IsNonAntiAliased() ? NONANTIALIASED_QUALITY : DEFAULT_QUALITY,
DEFAULT_PITCH|FF_DONTCARE,
font.GetFaceName()
);
#endif
static Font font[FONTCACHE];
static HFONT hfont[FONTCACHE];
ONCELOCK {
for(int i = 0; i < FONTCACHE; i++)
font[i].Face(-1);
}
int q = fnt.GetHashValue() % FONTCACHE;
if(font[q] != fnt) {
font[q] = fnt;
if(hfont[q])
DeleteObject(hfont[q]);
#ifdef PLATFORM_WINCE
LOGFONT lfnt;
Zero(lfnt);
lfnt.lfHeight = fnt.GetHeight() ? -abs(fnt.GetHeight()) : -12;
lfnt.lfWeight = fnt.IsBold() ? FW_BOLD : FW_NORMAL;
lfnt.lfItalic = fnt.IsItalic();
lfnt.lfUnderline = fnt.IsUnderline();
lfnt.lfStrikeOut = fnt.IsStrikeout();
wcscpy(lfnt.lfFaceName, ToSystemCharset(fnt.GetFaceName()));
hfont[q] = CreateFontIndirect(&lfnt);
#else
hfont[q] = CreateFont(
fnt.GetHeight() ? -abs(fnt.GetHeight()) : -12,
fnt.GetWidth(), angle, angle, fnt.IsBold() ? FW_BOLD : FW_NORMAL,
fnt.IsItalic(), fnt.IsUnderline(), fnt.IsStrikeout(),
chrset,
fnt.IsTrueTypeOnly() ? OUT_TT_ONLY_PRECIS : OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
fnt.IsNonAntiAliased() ? NONANTIALIASED_QUALITY : DEFAULT_QUALITY,
DEFAULT_PITCH|FF_DONTCARE,
fnt.GetFaceName()
);
#endif
}
return hfont[q];
}
int sGetCW(HDC hdc, wchar *h, int n)
@ -57,18 +72,28 @@ static HDC Win32_IC()
return hdc;
}
#define GLYPHINFOCACHE 31
GlyphInfo GetGlyphInfoSys(Font font, int chr)
{
static Font last;
static GlyphInfo li[256];
static int lastpage = -1;
static Font fnt[GLYPHINFOCACHE];
static int pg[GLYPHINFOCACHE];
static GlyphInfo li[GLYPHINFOCACHE][256];
ONCELOCK {
for(int i = 0; i < GLYPHINFOCACHE; i++)
pg[i] = -1;
}
int page = chr >> 8;
if(font != last || page != lastpage) {
last = font;
lastpage = page;
HFONT hfont = CreateWin32Font(font, 0, 0);
int q = CombineHash(font, page) % GLYPHINFOCACHE;
if(fnt[q] != font || pg[q] != page) {
DDUMP(font);
DDUMP(q);
fnt[q] = font;
pg[q] = page;
HFONT hfont = GetWin32Font(font, 0, 0);
if(!hfont) {
GlyphInfo n;
memset(&n, 0, sizeof(GlyphInfo));
@ -77,7 +102,7 @@ GlyphInfo GetGlyphInfoSys(Font font, int chr)
HDC hdc = Win32_IC();
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
int from = page << 8;
GlyphInfo *t = li;
GlyphInfo *t = li[q];
if(page >= 32) {
wchar h[3];
h[0] = 'x';
@ -137,20 +162,19 @@ GlyphInfo GetGlyphInfoSys(Font font, int chr)
Win32_GetGlyphIndices(hdc, wch, 256, pos, 1);
for(int i = 0; i < 256; i++)
if(pos[i] == 0xffff) {
li[i].width = 0x8000;
li[i].lspc = li[i].rspc = 0;
li[q][i].width = (int16)0x8000;
li[q][i].lspc = li[q][i].rspc = 0;
}
::SelectObject(hdc, ohfont);
#endif
}
return li[chr & 255];
return li[q][chr & 255];
}
CommonFontInfo GetFontInfoSys(Font font)
{
CommonFontInfo fi;
memset(&fi, 0, sizeof(fi));
HFONT hfont = CreateWin32Font(font, 0, 0);
HFONT hfont = GetWin32Font(font, 0, 0);
if(hfont) {
HDC hdc = Win32_IC();
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);

View file

@ -0,0 +1,4 @@
TOPIC("test$en-us")
#include "test$en-us.tppi"
END_TOPIC

View file

@ -0,0 +1,5 @@
topic "ddfff+cčď";
[ $$0,0#00000000000000000000000000000000:Default]
[{_}%EN-US
[s0; [!Corbel! ddfff`+cčď]&]
[s0; [!Algerian! ďOLIK]]

View file

@ -0,0 +1,4 @@
TITLE("ddfff+cčď")
COMPRESSED
120,156,139,86,80,81,49,208,49,80,54,32,0,172,92,82,211,18,75,115,74,98,163,171,227,107,85,93,253,116,67,131,21,162,139,13,172,21,162,21,157,243,139,146,82,115,20,21,82,82,210,210,210,18,180,147,143,244,30,233,143,85,139,133,202,58,230,164,167,22,101,38,230,41,42,28,233,247,247,241,244,142,141,5,0,149,201,33,124,

View file

@ -2,59 +2,42 @@
using namespace Upp;
#if 0
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);
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());
}
return e;
}
thread__ CharEntry fc_cache[512];
const 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;
}
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;
}
Size GetTextSizeNew(const wchar *text, Font font, int n)
{
int cx = 0;
@ -65,10 +48,38 @@ Size GetTextSizeNew(const wchar *text, Font font, int n)
}
return Size(cx, GetFontInfo(font).height);
}
#endif
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<CharDisplay>());
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());