Developing Win32 font metrics

git-svn-id: svn://ultimatepp.org/upp/trunk@1355 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-07-03 17:29:39 +00:00
parent 186475dc3b
commit e6240bf46b
6 changed files with 680 additions and 520 deletions

View file

@ -1,53 +1,52 @@
#ifndef _FontInfo_FontInfo_h_
#define _FontInfo_FontInfo_h_
#include <CtrlLib/CtrlLib.h>
using namespace Upp;
struct CommonFontInfo : Moveable<CommonFontInfo> {
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<GlyphInfo> {
int16 width;
int16 lspc;
int16 rspc;
bool IsMissing() const { return (word)width == (word)0x8000; }
};
GlyphInfo GetGlyphInfoSys(Font font, int chr);
struct FaceInfo : Moveable<FaceInfo> {
String name;
bool scalable;
bool fixed;
};
Vector<FaceInfo> GetAllFacesSys();
#endif
#ifndef _FontInfo_FontInfo_h_
#define _FontInfo_FontInfo_h_
#include <CtrlLib/CtrlLib.h>
using namespace Upp;
struct CommonFontInfo : Moveable<CommonFontInfo> {
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<GlyphInfo> {
int16 width;
int16 lspc;
int16 rspc;
bool IsMissing() const { return (word)width == (word)0x8000; }
};
GlyphInfo GetGlyphInfoSys(Font font, int chr);
struct FaceInfo : Moveable<FaceInfo> {
String name;
dword info;
};
Vector<FaceInfo> GetAllFacesSys();
#endif

View file

@ -1,150 +1,271 @@
#include "FontInfo.h"
#ifdef PLATFORM_WIN32
HFONT CreateWin32Font(Font font, 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
}
int sGetCW(HDC hdc, wchar *h, int n)
{
SIZE sz;
return GetTextExtentPoint32W(hdc, h, n, &sz) ? sz.cx : 0;
}
GlyphInfo GetGlyphInfoSys(Font font, int chr)
{
static Font last;
static GlyphInfo li[256];
static int lastpage = -1;
int page = chr >> 8;
if(page == lastpage)
return li[chr & 255];
HFONT hfont = CreateWin32Font(font, 0, 0);
if(!hfont) {
GlyphInfo n;
memset(&n, 0, sizeof(GlyphInfo));
return n;
}
HDC hdc = ScreenHDC();
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
int from = page << 8;
GlyphInfo *t = li;
if(page >= 32) {
wchar h[3];
h[0] = 'x';
h[1] = 'x';
h[2] = 'x';
int w0 = sGetCW(hdc, h, 2);
for(int i = 0; i < 256; i++) {
h[1] = from + i;
t[i].width = sGetCW(hdc, h, 3) - w0;
t[i].lspc = t[i].rspc = 0;
}
}
else {
bool abca = false, abcw = false;
Buffer<ABC> abc(256);
abcw = ::GetCharABCWidths(hdc, from, from + 256 - 1, abc);
#ifndef PLATFORM_WINCE
if(!abcw)
abca = ::GetCharABCWidthsA(hdc, from, from + 256 - 1, abc);
#endif
if(abcw)
{
for(ABC *s = abc, *lim = abc + 256; s < lim; s++, t++)
{
t->width = s->abcA + s->abcB + s->abcC;
t->lspc = s->abcA;
t->rspc = s->abcC;
}
}
else
{
Buffer<int> wb(256);
#ifdef PLATFORM_WINCE
::GetCharWidth32(hdc, from, from + 256 - 1, wb);
#else
::GetCharWidthW(hdc, from, from + 256 - 1, wb);
#endif
for(int *s = wb, *lim = wb + 256; s < lim; s++, t++)
{
t->width = *s - GetFontInfoSys(font).overhang;
if(abca)
{
ABC aa = abc[(byte)ToAscii(from++)];
t->lspc = aa.abcA;
t->rspc = aa.abcC;
}
else
t->lspc = t->rspc = 0;
}
}
}
::SelectObject(hdc, ohfont);
return li[chr & 255];
}
CommonFontInfo GetFontInfoSys(Font font)
{
CommonFontInfo fi;
memset(&fi, 0, sizeof(fi));
HFONT hfont = CreateWin32Font(font, 0, 0);
if(hfont) {
HDC hdc = ScreenHDC();
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
TEXTMETRIC tm;
::GetTextMetrics(hdc, &tm);
fi.ascent = tm.tmAscent;
fi.descent = tm.tmDescent;
fi.external = tm.tmExternalLeading;
fi.internal = tm.tmInternalLeading;
fi.height = fi.ascent + fi.descent;
fi.lineheight = fi.height + fi.external;
fi.overhang = tm.tmOverhang;
fi.avewidth = tm.tmAveCharWidth;
fi.maxwidth = tm.tmMaxCharWidth;
fi.firstchar = tm.tmFirstChar;
fi.charcount = tm.tmLastChar - tm.tmFirstChar + 1;
fi.default_char = tm.tmDefaultChar;
fi.fixedpitch = (tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0;
fi.scaleable = tm.tmPitchAndFamily & TMPF_TRUETYPE;
if(fi.scaleable) {
ABC abc;
GetCharABCWidths(hdc, 'o', 'o', &abc);
fi.spacebefore = abc.abcA;
fi.spaceafter = abc.abcC;
}
else
fi.spacebefore = fi.spaceafter = 0;
::SelectObject(hdc, ohfont);
}
return fi;
}
#endif
#include "FontInfo.h"
#ifdef PLATFORM_WIN32
HFONT CreateWin32Font(Font font, 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
}
int sGetCW(HDC hdc, wchar *h, int n)
{
SIZE sz;
return GetTextExtentPoint32W(hdc, h, n, &sz) ? sz.cx : 0;
}
static void Win32_GetGlyphIndices(HDC hdc, LPCWSTR s, int n, LPWORD r, DWORD flag)
{
typedef DWORD (WINAPI *GGIW)(HDC, LPCWSTR, int, LPWORD, DWORD);
static GGIW fn;
ONCELOCK
if(HMODULE hDLL = LoadLibrary("gdi32"))
fn = (GGIW) GetProcAddress(hDLL, "GetGlyphIndicesW");
if(fn)
fn(hdc, s, n, r, flag);
else
memset(r, 0, n * sizeof(WORD));
}
static HDC Win32_IC()
{
static HDC hdc;
ONCELOCK {
hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
}
return hdc;
}
GlyphInfo GetGlyphInfoSys(Font font, int chr)
{
static Font last;
static GlyphInfo li[256];
static int lastpage = -1;
int page = chr >> 8;
if(font != last || page != lastpage) {
last = font;
lastpage = page;
HFONT hfont = CreateWin32Font(font, 0, 0);
if(!hfont) {
GlyphInfo n;
memset(&n, 0, sizeof(GlyphInfo));
return n;
}
HDC hdc = Win32_IC();
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
int from = page << 8;
GlyphInfo *t = li;
if(page >= 32) {
wchar h[3];
h[0] = 'x';
h[1] = 'x';
h[2] = 'x';
int w0 = sGetCW(hdc, h, 2);
for(int i = 0; i < 256; i++) {
h[1] = from + i;
t[i].width = sGetCW(hdc, h, 3) - w0;
t[i].lspc = t[i].rspc = 0;
}
}
else {
bool abca = false, abcw = false;
Buffer<ABC> abc(256);
abcw = ::GetCharABCWidths(hdc, from, from + 256 - 1, abc);
#ifndef PLATFORM_WINCE
if(!abcw)
abca = ::GetCharABCWidthsA(hdc, from, from + 256 - 1, abc);
#endif
if(abcw)
{
for(ABC *s = abc, *lim = abc + 256; s < lim; s++, t++)
{
t->width = s->abcA + s->abcB + s->abcC;
t->lspc = s->abcA;
t->rspc = s->abcC;
}
}
else
{
Buffer<int> wb(256);
#ifdef PLATFORM_WINCE
::GetCharWidth32(hdc, from, from + 256 - 1, wb);
#else
::GetCharWidthW(hdc, from, from + 256 - 1, wb);
#endif
for(int *s = wb, *lim = wb + 256; s < lim; s++, t++)
{
t->width = *s - GetFontInfoSys(font).overhang;
if(abca)
{
ABC aa = abc[(byte)ToAscii(from++)];
t->lspc = aa.abcA;
t->rspc = aa.abcC;
}
else
t->lspc = t->rspc = 0;
}
}
}
#ifndef PLATFORM_WINCE
WORD pos[256];
WCHAR wch[256];
for(int i = 0; i < 256; i++)
wch[i] = from + i;
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;
}
::SelectObject(hdc, ohfont);
#endif
}
return li[chr & 255];
}
CommonFontInfo GetFontInfoSys(Font font)
{
CommonFontInfo fi;
memset(&fi, 0, sizeof(fi));
HFONT hfont = CreateWin32Font(font, 0, 0);
if(hfont) {
HDC hdc = Win32_IC();
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
TEXTMETRIC tm;
::GetTextMetrics(hdc, &tm);
fi.ascent = tm.tmAscent;
fi.descent = tm.tmDescent;
fi.external = tm.tmExternalLeading;
fi.internal = tm.tmInternalLeading;
fi.height = fi.ascent + fi.descent;
fi.lineheight = fi.height + fi.external;
fi.overhang = tm.tmOverhang;
fi.avewidth = tm.tmAveCharWidth;
fi.maxwidth = tm.tmMaxCharWidth;
fi.firstchar = tm.tmFirstChar;
fi.charcount = tm.tmLastChar - tm.tmFirstChar + 1;
fi.default_char = tm.tmDefaultChar;
fi.fixedpitch = (tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0;
fi.scaleable = tm.tmPitchAndFamily & TMPF_TRUETYPE;
if(fi.scaleable) {
ABC abc;
GetCharABCWidths(hdc, 'o', 'o', &abc);
fi.spacebefore = abc.abcA;
fi.spaceafter = abc.abcC;
}
else
fi.spacebefore = fi.spaceafter = 0;
::SelectObject(hdc, ohfont);
}
return fi;
}
static Vector<FaceInfo> *sList;
static int CALLBACK Win32_AddFace(const LOGFONT *logfont, const TEXTMETRIC *, dword type, LPARAM param)
{
#ifdef PLATFORM_WINCE
const wchar *facename = (const wchar *)param;
if(facename && _wcsicmp(logfont->lfFaceName, facename))
return 1;
#else
const char *facename = (const char *)param;
if(facename && stricmp(logfont->lfFaceName, facename))
return 1;
#endif
dword typ = 0;
if((logfont->lfPitchAndFamily & 3) == FIXED_PITCH)
typ |= Font::FIXEDPITCH;
if(type & TRUETYPE_FONTTYPE)
typ |= Font::SCALEABLE;
if(logfont->lfCharSet == SYMBOL_CHARSET)
typ |= Font::SYMBOLTYPE;
else
if(logfont->lfCharSet != 0)
typ |= Font::LOCAL;
#ifdef PLATFORM_WINCE
FontFaceInfo& f = sFontFace().Add(WString(logfont->lfFaceName).ToString());
f.name = FromSystemCharset(logfont->lfFaceName);
#else
FaceInfo& f = sList->Add();
f.name = FromSystemCharset(logfont->lfFaceName);
f.info = typ;
#endif
return facename ? 0 : 1;
}
static int Win32_EnumFace(HDC hdc, const char *face)
{
#ifdef PLATFORM_WINCE
return EnumFontFamilies(hdc, ToSystemCharset(face), Win32_AddFace, (LPARAM)~ToSystemCharset(face));
#else
return EnumFontFamilies(hdc, face, Win32_AddFace, (LPARAM)face);
#endif
}
static void Win32_ForceFace(HDC hdc, const char *face, const char *aface)
{
if(!aface)
aface = "Arial";
if(Win32_EnumFace(hdc, face) && Win32_EnumFace(hdc, aface))
Panic("Missing font " + String(face));
}
Vector<FaceInfo> GetAllFacesSys()
{
Vector<FaceInfo> list;
sList = &list;
#ifdef PLATFORM_WINCE
HDC hdc = CreateDC(NULL, NULL, NULL, NULL);
Win32_ForceFace(hdc, "Tahoma", NULL);
Win32_ForceFace(hdc, "Tahoma", "Tahoma");
Win32_ForceFace(hdc, "Courier New", "Tahoma");
Win32_ForceFace(hdc, "Tahoma", "Tahoma");
Win32_ForceFace(hdc, "Tahoma", "Tahoma");
Win32_ForceFace(hdc, "Tahoma", "Tahoma");
Win32_ForceFace(hdc, "Tahoma", "Tahoma");
Win32_ForceFace(hdc, "Tahoma", "Tahoma");
Win32_ForceFace(hdc, "Tahoma", "Tahoma");
#else
HDC hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
Win32_ForceFace(hdc, "Arial", NULL);
Win32_ForceFace(hdc, "Times New Roman", "Arial");
Win32_ForceFace(hdc, "Courier New", "Arial");
Win32_ForceFace(hdc, "Times New Roman", "Arial");
Win32_ForceFace(hdc, "Arial", "Arial");
Win32_ForceFace(hdc, "Courier New", "Arial");
Win32_ForceFace(hdc, "Symbol", "Arial");
Win32_ForceFace(hdc, "WingDings", "Arial");
Win32_ForceFace(hdc, "Tahoma", "Arial");
#endif
Win32_EnumFace(hdc, NULL);
DeleteDC(hdc);
return list;
}
#endif

View file

@ -1,185 +1,188 @@
#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<FaceInfo> GetAllFacesSys()
{
static const char *basic_fonts[] = {
"sans-serif",
"serif",
"sans-serif",
"monospace",
"serif",
"sans-serif",
"monospace",
};
Vector<FaceInfo> 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;
int iv;
fi.fixed = FcPatternGetInteger(fs->fonts[i], FC_SPACING, 0, &iv) == 0 && iv == XFT_MONO;
FcBool bv;
fi.scalable = FcPatternGetBool(fs->fonts[i], FC_SCALABLE, 0, &bv) == 0 && bv;
}
}
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;
}
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<FaceInfo> GetAllFacesSys()
{
static const char *basic_fonts[] = {
"sans-serif",
"serif",
"sans-serif",
"monospace",
"serif",
"sans-serif",
"monospace",
};
Vector<FaceInfo> 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

View file

@ -1,132 +1,139 @@
#include "FontInfo.h"
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);
}
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;
const wchar *wtext = (const wchar *)text;
while(n > 0) {
cx += GetGlyphInfo(font, *wtext++).width;
n--;
}
return Size(cx, GetFontInfo(font).height);
}
#endif
GUI_APP_MAIN
{
{
for(int i = 0; i < 65536; i++) {
GlyphInfo g = GetGlyphInfoSys(Arial(100).Bold(), i);
if(g.IsMissing())
LOG(i);
}
}
Vector<FaceInfo> fa = GetAllFacesSys();
for(int i = 0; i < fa.GetCount(); i++)
LOG(fa[i].name << ": scalable: " << fa[i].scalable << ", fixed: " << fa[i].fixed);
CommonFontInfo f = GetFontInfoSys(Arial(100).Bold());
DDUMP(f.ascent);
DDUMP(f.descent);
DDUMP(f.lineheight);
DDUMP(f.maxwidth);
DDUMP(f.path);
FontInfo fi = Arial(100).Bold().Info();
DDUMP(fi.GetAscent());
DDUMP(fi.GetDescent());
DDUMP(fi.GetMaxWidth());
for(int c = '0'; c < 'z'; c++) {
LOG("-------------------------");
DDUMP((char)c);
GlyphInfo g = GetGlyphInfoSys(Arial(100).Bold(), c);
DDUMP(g.width);
DDUMP(fi[c]);
DDUMP(g.lspc);
DDUMP(fi.GetLeftSpace(c));
DDUMP(g.rspc);
DDUMP(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;
#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);
}
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;
const wchar *wtext = (const wchar *)text;
while(n > 0) {
cx += GetGlyphInfo(font, *wtext++).width;
n--;
}
return Size(cx, GetFontInfo(font).height);
}
#endif
GUI_APP_MAIN
{
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<FaceInfo> 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
}

21
uppdev/trn/trn.cpp Normal file
View file

@ -0,0 +1,21 @@
#include <Core/Core.h>
using namespace Upp;
int Trn(int x)
{
if(x % 2)
return x + 1;
else
return x;
}
CONSOLE_APP_MAIN
{
for(;;) {
Cout() << "Zadej cislo x: ";
int cislo = atoi(ReadStdIn());
Cout() << "Trn(" << cislo << ") = " << Trn(cislo) << "\n";
}
}

9
uppdev/trn/trn.upp Normal file
View file

@ -0,0 +1,9 @@
uses
Core;
file
trn.cpp;
mainconfig
"" = "";