mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-07 14:22:32 -06:00
Developing new draw
git-svn-id: svn://ultimatepp.org/upp/trunk@1361 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
156ba63fc3
commit
144066e580
12 changed files with 1846 additions and 1895 deletions
|
|
@ -67,7 +67,6 @@ String DumpFontInfo(FontInfo fi)
|
|||
{
|
||||
String out;
|
||||
out << "FontInfo(font = " << fi.GetFont() << "\n"
|
||||
"\tempty = " << fi.IsEmpty() << "\n"
|
||||
"\tascent = " << fi.GetAscent() << "\n"
|
||||
"\tdescent = " << fi.GetDescent() << "\n"
|
||||
"\texternal leading = " << fi.GetExternal() << "\n"
|
||||
|
|
@ -91,13 +90,13 @@ String DumpFontInfo(FontInfo fi)
|
|||
out << "\n\n\tright space:\n";
|
||||
for(i = 0; i < 256; i++)
|
||||
out << NFormat(i & 15 ? " " : "\n\t%02x\t", i) << NFormat("%2>d", fi.GetRightSpace(i));
|
||||
out << "\n\n\tkerning:\n";
|
||||
/* out << "\n\n\tkerning:\n";
|
||||
int kp = 0;
|
||||
for(i = 0; i < 256; i++)
|
||||
for(int j = 0; j < 256; j++)
|
||||
if(int k = fi.GetKerning(i, j))
|
||||
out << (kp++ & 7 ? " " : "\n\t") << NFormat("(%02x,%02x)=%2>d", i, j, k);
|
||||
out << (kp ? "\n" : "\tnone\n");
|
||||
out << (kp ? "\n" : "\tnone\n");*/
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
1934
newdraw/Draw/Draw.h
1934
newdraw/Draw/Draw.h
File diff suppressed because it is too large
Load diff
|
|
@ -29,12 +29,13 @@ library(FREEBSD) xcb;
|
|||
file
|
||||
Draw.h,
|
||||
Mt.cpp,
|
||||
FontInt.h,
|
||||
Font.cpp,
|
||||
FontCR.cpp,
|
||||
FontWin32.cpp,
|
||||
FontX11.cpp,
|
||||
Draw.cpp,
|
||||
DrawText.cpp,
|
||||
ComposeText.cpp,
|
||||
DrawData.cpp,
|
||||
Drawing.cpp,
|
||||
DrawUtil.cpp,
|
||||
|
|
@ -48,6 +49,7 @@ file
|
|||
DrawWin32.h,
|
||||
DrawWin32.cpp,
|
||||
DrawOpWin32.cpp,
|
||||
DrawTextWin32.cpp,
|
||||
MetaFile.cpp,
|
||||
DrawX11.h,
|
||||
DrawX11.cpp,
|
||||
|
|
|
|||
|
|
@ -277,37 +277,6 @@ void SystemDraw::DrawEllipseOp(const Rect& r, Color color, int width, Color penc
|
|||
::Ellipse(GetHandle(), r.left, r.top, r.right, r.bottom);
|
||||
}
|
||||
|
||||
void SystemDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink,
|
||||
int n, const int *dx) {
|
||||
while(n > 30000) {
|
||||
DrawTextOp(x, y, angle, text, font, ink, 30000, dx);
|
||||
if(dx) {
|
||||
for(int i = 0; i < 30000; i++)
|
||||
x += *dx++;
|
||||
}
|
||||
else
|
||||
x += GetTextSize(text, font, 30000).cx;
|
||||
n -= 30000;
|
||||
text += 30000;
|
||||
}
|
||||
DrawLock __;
|
||||
COLORREF cr = GetColor(ink);
|
||||
if(cr != lastTextColor) {
|
||||
LLOG("Setting text color: " << ink);
|
||||
::SetTextColor(handle, lastTextColor = cr);
|
||||
}
|
||||
if(angle) {
|
||||
SetFont(font, angle);
|
||||
::ExtTextOutW(handle, x + lastFont.ptr->offset.cx, y + lastFont.ptr->offset.cy,
|
||||
0, NULL, (const WCHAR *)text, n, dx);
|
||||
}
|
||||
else {
|
||||
SetFont(font);
|
||||
::ExtTextOutW(handle, x, y + lastFont.GetAscent(), 0, NULL, (const WCHAR *)text,
|
||||
n, dx);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -29,7 +29,66 @@ void Draw::DrawText(int x, int y, int angle, const wchar *text, Font font,
|
|||
if(IsNull(ink)) return;
|
||||
if(n < 0)
|
||||
n = wstrlen(text);
|
||||
ComposeText(x, y, angle, text, font, ink, n, 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)
|
||||
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;
|
||||
}
|
||||
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)
|
||||
DrawTextOp(int(x + cosa * d), int(y - sina * (fi.GetAscent() - fi2.GetAscent() + d)),
|
||||
angle, &chr, fnt, ink, 1, NULL);
|
||||
else
|
||||
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) {
|
||||
DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &cg.basic_char, font, ink, 1, NULL);
|
||||
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 {
|
||||
DrawTextOp(x + d, y, angle, &cg.basic_char, font, ink, 1, NULL);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
|
|
|
|||
57
newdraw/Draw/DrawTextWin32.cpp
Normal file
57
newdraw/Draw/DrawTextWin32.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include "Draw.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
|
||||
#define LLOG(x)
|
||||
|
||||
HFONT GetWin32Font(Font fnt, int angle);
|
||||
|
||||
void SystemDraw::SetFont(Font font, int angle) {
|
||||
DrawLock __;
|
||||
LLOG("Set font: " << font << " face: " << font.GetFaceName());
|
||||
if(lastFont == font && lastAngle == angle)
|
||||
return;
|
||||
lastFont = font;
|
||||
lastAngle = angle;
|
||||
HFONT h = (HFONT) SelectObject(handle, GetWin32Font(font, angle));
|
||||
if(!orgFont) orgFont = h;
|
||||
}
|
||||
|
||||
void SystemDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink,
|
||||
int n, const int *dx) {
|
||||
Std(font);
|
||||
while(n > 30000) {
|
||||
DrawTextOp(x, y, angle, text, font, ink, 30000, dx);
|
||||
if(dx) {
|
||||
for(int i = 0; i < 30000; i++)
|
||||
x += *dx++;
|
||||
}
|
||||
else
|
||||
x += GetTextSize(text, font, 30000).cx;
|
||||
n -= 30000;
|
||||
text += 30000;
|
||||
}
|
||||
DrawLock __;
|
||||
COLORREF cr = GetColor(ink);
|
||||
if(cr != lastTextColor) {
|
||||
LLOG("Setting text color: " << ink);
|
||||
::SetTextColor(handle, lastTextColor = cr);
|
||||
}
|
||||
SetFont(font, angle);
|
||||
int ascent = font.Info().GetAscent();
|
||||
if(angle) {
|
||||
double sina, cosa;
|
||||
Draw::SinCos(angle, sina, cosa);
|
||||
Size offset;
|
||||
::ExtTextOutW(handle, x + fround(ascent * sina), y + fround(ascent * cosa), 0, NULL, (const WCHAR *)text, n, dx);
|
||||
}
|
||||
else
|
||||
::ExtTextOutW(handle, x, y + ascent, 0, NULL, (const WCHAR *)text,
|
||||
n, dx);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -24,16 +24,6 @@ Size SystemDraw::GetNativeDpi() const
|
|||
return Dots() ? nativeDpi : Size(96, 96);
|
||||
}
|
||||
|
||||
void StaticExitDraw_()
|
||||
{
|
||||
FontInfo::FreeFonts();
|
||||
}
|
||||
|
||||
EXITBLOCK
|
||||
{
|
||||
StaticExitDraw_();
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_WINCE
|
||||
void Add(LOGPALETTE *pal, int r, int g, int b)
|
||||
{
|
||||
|
|
@ -164,16 +154,6 @@ void SystemDraw::SetDrawPen(int width, Color color) {
|
|||
}
|
||||
}
|
||||
|
||||
void SystemDraw::SetFont(Font font, int angle) {
|
||||
DrawLock __;
|
||||
LLOG("Set font: " << font << " face: " << font.GetFaceName());
|
||||
if(lastFont && lastFont.IsEqual(CHARSET_UNICODE, font, angle))
|
||||
return;
|
||||
lastFont = FontInfo::AcquireFontInfo0(font, GetHandle(), angle);
|
||||
HFONT h = (HFONT) SelectObject(handle, lastFont.ptr->hfont);
|
||||
if(!orgFont) orgFont = h;
|
||||
}
|
||||
|
||||
void SystemDraw::SetOrg() {
|
||||
DrawLock __;
|
||||
#ifdef PLATFORM_WINCE
|
||||
|
|
@ -271,7 +251,7 @@ void SystemDraw::Cinit() {
|
|||
actBrush = orgBrush = NULL;
|
||||
actPen = orgPen = NULL;
|
||||
orgFont = NULL;
|
||||
lastFont.Clear();
|
||||
lastAngle = INT_MIN;
|
||||
}
|
||||
|
||||
void SystemDraw::Init() {
|
||||
|
|
@ -296,7 +276,6 @@ SystemDraw::SystemDraw() {
|
|||
DrawLock __;
|
||||
native = 0;
|
||||
InitColors();
|
||||
FontInfo::InitFonts();
|
||||
actual_offset = Point(0, 0);
|
||||
Reset();
|
||||
handle = NULL;
|
||||
|
|
@ -306,7 +285,6 @@ SystemDraw::SystemDraw(HDC hdc) {
|
|||
DrawLock __;
|
||||
native = 0;
|
||||
InitColors();
|
||||
FontInfo::InitFonts();
|
||||
Reset();
|
||||
Attach(hdc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ private:
|
|||
|
||||
friend void StaticExitDraw_();
|
||||
|
||||
FontInfo lastFont;
|
||||
Font lastFont;
|
||||
int lastAngle;
|
||||
|
||||
Point actual_offset_bak;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,306 +1,324 @@
|
|||
#include "Draw.h"
|
||||
|
||||
#define LLOG(x)
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
void InitPlatformFonts();
|
||||
|
||||
Size FontInfo::StdFontSize;
|
||||
Font FontInfo::AStdFont;
|
||||
|
||||
int FontInfo::FontCacheMax = 32;
|
||||
int FontInfo::FontCached;
|
||||
|
||||
void FreeFonts();
|
||||
|
||||
enum FontHashConst { FONTHASH = 97 };
|
||||
|
||||
//# Pretty ugly code....
|
||||
FontInfo::Data *FontInfo::GetFontHash(int i) {
|
||||
static byte buff[FONTHASH * sizeof(FontLink)];
|
||||
static FontLink *fonthash;
|
||||
ONCELOCK {
|
||||
fonthash = (FontLink *)buff;
|
||||
for(int i = 0; i < FONTHASH; i++)
|
||||
fonthash[i].LinkSelfAll();
|
||||
}
|
||||
ASSERT(i >= 0 && i < FONTHASH);
|
||||
return (FontInfo::Data *)&fonthash[i];
|
||||
}
|
||||
|
||||
//# Pretty ugly code....
|
||||
FontInfo::Data *FontInfo::GetFontLru() {
|
||||
static byte buff[sizeof(FontLink)];
|
||||
static FontLink *fontlru;
|
||||
ONCELOCK {
|
||||
fontlru = new(buff) FontLink;
|
||||
}
|
||||
return (FontInfo::Data *)fontlru;
|
||||
}
|
||||
|
||||
INITBLOCK {
|
||||
RichValue<Font>::Register();
|
||||
}
|
||||
|
||||
void FontInfo::InitFonts()
|
||||
{
|
||||
ONCELOCK {
|
||||
static bool b;
|
||||
if(b) return;
|
||||
b = true;
|
||||
DrawLock __;
|
||||
GetFontHash(0);
|
||||
GetFontLru();
|
||||
InitPlatformFonts();
|
||||
}
|
||||
}
|
||||
|
||||
int FontFilter(int c)
|
||||
{
|
||||
return c >= 'a' && c <= 'z' || c >= '0' && c <= '9' ? c : c >= 'A' && c <= 'Z' ? ToLower(c) : 0;
|
||||
}
|
||||
|
||||
int Font::FindFaceNameIndex(const char *name) {
|
||||
FontInfo::InitFonts();
|
||||
for(int i = 1; i < GetFaceCount(); i++)
|
||||
if(GetFaceName(i) == name)
|
||||
return i;
|
||||
String n = Filter(name, FontFilter);
|
||||
for(int i = 1; i < GetFaceCount(); i++)
|
||||
if(Filter(GetFaceName(i), FontFilter) == n)
|
||||
return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FontInfo::FontInfo()
|
||||
{
|
||||
ptr = NULL;
|
||||
charset = CHARSET_UNICODE;
|
||||
InitFonts();
|
||||
}
|
||||
|
||||
SystemDraw& ScreenInfo();
|
||||
|
||||
FontInfo Font::Info() const
|
||||
{
|
||||
DrawLock __;
|
||||
return FontInfo::AcquireFontInfo(*this, 0);
|
||||
}
|
||||
|
||||
void FontInfo::SyncStdFont()
|
||||
{
|
||||
FontInfo fi = AStdFont.Info();
|
||||
FontInfo bfi = AStdFont().Bold().Info();
|
||||
StdFontSize = Size(fi.GetAveWidth(), bfi.GetHeight());
|
||||
}
|
||||
|
||||
void FontInfo::SetStdFont(Font font)
|
||||
{
|
||||
DrawLock __;
|
||||
InitFonts();
|
||||
AStdFont = font;
|
||||
SyncStdFont();
|
||||
}
|
||||
|
||||
Size FontInfo::GetStdFontSize()
|
||||
{
|
||||
ONCELOCK {
|
||||
SyncStdFont();
|
||||
}
|
||||
return StdFontSize;
|
||||
}
|
||||
|
||||
Font StdFont()
|
||||
{
|
||||
return Font(0, FontInfo::GetStdFont().GetHeight());
|
||||
}
|
||||
|
||||
String Font::GetFaceName() const {
|
||||
if(IsNull()) return String();
|
||||
if(GetFace() == 0)
|
||||
return "STDFONT";
|
||||
return GetFaceName(GetFace());
|
||||
}
|
||||
|
||||
dword Font::GetFaceInfo() const {
|
||||
if(IsNull()) return 0;
|
||||
return GetFaceInfo(GetFace());
|
||||
}
|
||||
|
||||
Font& Font::FaceName(const String& name) {
|
||||
int n = FindFaceNameIndex(name);
|
||||
Face(n < 0 ? 0xffff : n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Font::Serialize(Stream& s) {
|
||||
int version = 1;
|
||||
s / version;
|
||||
if(version >= 1) {
|
||||
int f = GetFace();
|
||||
if(f > COURIER)
|
||||
f = -1;
|
||||
s / f;
|
||||
String name;
|
||||
if(f < 0) {
|
||||
name = GetFaceName();
|
||||
s % name;
|
||||
}
|
||||
if(s.IsLoading())
|
||||
if(f >= 0)
|
||||
Face(f);
|
||||
else
|
||||
FaceName(name);
|
||||
}
|
||||
else {
|
||||
String name = GetFaceName();
|
||||
s % name;
|
||||
if(s.IsLoading()) {
|
||||
FaceName(name);
|
||||
if(IsNull())
|
||||
Face(COURIER);
|
||||
}
|
||||
}
|
||||
s % v.flags % v.height % v.width;
|
||||
}
|
||||
|
||||
template<>
|
||||
String AsString(const Font& f) {
|
||||
if(IsNull(f)) return "<null>";
|
||||
String s = "<" + f.GetFaceName() + Format(":%d", f.GetHeight());
|
||||
if(f.IsBold())
|
||||
s += " Bold";
|
||||
if(f.IsItalic())
|
||||
s += " Italic";
|
||||
if(f.IsUnderline())
|
||||
s += " Underline";
|
||||
if(f.IsStrikeout())
|
||||
s += " Strikeout";
|
||||
return s + '>';
|
||||
}
|
||||
|
||||
void FontInfo::FreeFonts() {
|
||||
FontCacheMax = FontCached = 0;
|
||||
for(int i = 0; i < FONTHASH; i++)
|
||||
GetFontHash(i)->DeleteList(HASH);
|
||||
}
|
||||
|
||||
FontInfo::FontInfo(const FontInfo& f)
|
||||
{
|
||||
Retain(f);
|
||||
}
|
||||
|
||||
FontInfo& FontInfo::operator=(const FontInfo& f)
|
||||
{
|
||||
Release();
|
||||
Retain(f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool FontInfo::IsEqual(byte _charset, Font f, int angle) const
|
||||
{
|
||||
return ptr && ptr->font == f && ptr->angle == angle && charset == _charset;
|
||||
}
|
||||
|
||||
FontInfo::CharMetrics FontInfo::GetCM(int c) const
|
||||
{
|
||||
if(c < 0) c = (byte)c;
|
||||
if(charset != CHARSET_UNICODE)
|
||||
c = ToUnicode(c, charset);
|
||||
ASSERT(c < 65536);
|
||||
if(c >= 65536) {
|
||||
CharMetrics h;
|
||||
h.width = h.lspc = h.rspc = 0;
|
||||
return h;
|
||||
}
|
||||
if(c < 2048)
|
||||
return GetPage(c >> 5)[c & 31];
|
||||
Mutex::Lock __(ptr->xmutex);
|
||||
Kinfo& ki = ptr->kinfo.At((c >> 10) - 2);
|
||||
if(!ki.flags) {
|
||||
ki.flags = new byte[128];
|
||||
memset(ki.flags, 0, 128);
|
||||
ptr->GetMetrics(&ki.std, c, 1);
|
||||
}
|
||||
int fi = (c >> 3) & 127;
|
||||
int fm = 1 << (c & 7);
|
||||
if(ki.flags[fi] & fm)
|
||||
return ki.std;
|
||||
int q = ptr->xx.Find(c);
|
||||
if(q >= 0)
|
||||
return ptr->xx[q];
|
||||
CharMetrics m;
|
||||
ptr->GetMetrics(&m, c, 1);
|
||||
if(m == ki.std)
|
||||
ki.flags[fi] |= fm;
|
||||
else
|
||||
ptr->xx.Add(c, m);
|
||||
return m;
|
||||
}
|
||||
|
||||
int FontInfo::GetWidth(int c) const {
|
||||
return GetCM(c).width;
|
||||
}
|
||||
|
||||
int FontInfo::GetLeftSpace(int c) const {
|
||||
return GetCM(c).lspc;
|
||||
}
|
||||
|
||||
int FontInfo::GetRightSpace(int c) const {
|
||||
return GetCM(c).rspc;
|
||||
}
|
||||
|
||||
void FontInfo::Release()
|
||||
{
|
||||
DrawLock __;
|
||||
if(ptr) {
|
||||
ASSERT(ptr->refcount > 0);
|
||||
LLOG("Release " << (void *)ptr << " count:" << ptr->count);
|
||||
if(--ptr->refcount == 0) {
|
||||
if(FontCacheMax == 0) {
|
||||
delete ptr;
|
||||
return;
|
||||
}
|
||||
FontInfo::Data *lru = GetFontLru();
|
||||
ptr->LinkAfter(lru, LRU);
|
||||
FontCached++;
|
||||
LLOG("Placed to cache " << ptr->ptr << " cached:" << FontCached);
|
||||
while(FontCached > FontCacheMax) {
|
||||
ASSERT(lru->GetPrev(LRU) != lru);
|
||||
FontCached--;
|
||||
LLOG("Deleting from cache " << lru->GetPrev(LRU)->ptr <<
|
||||
" cached: " << FontCached);
|
||||
delete lru->GetPrev(LRU);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FontInfo::Retain(const FontInfo& f)
|
||||
{
|
||||
DrawLock __;
|
||||
ptr = f.ptr;
|
||||
ptr->refcount++;
|
||||
charset = f.charset;
|
||||
}
|
||||
|
||||
FontInfo::CharMetrics *FontInfo::CreateMetricsPage(int page) const
|
||||
{
|
||||
DrawLock __;
|
||||
CharMetrics *cm;
|
||||
cm = new CharMetrics[32];
|
||||
ptr->GetMetrics(cm, page << 5, 32);
|
||||
if(page >= 8 && page < 12)
|
||||
ComposeMetrics(ptr->font, cm, page);
|
||||
return cm;
|
||||
}
|
||||
|
||||
FontInfo::CharMetrics *FontInfo::GetPage(int page) const
|
||||
{
|
||||
ASSERT(page >= 0 && page < 64);
|
||||
ONCELOCK_PTR(ptr->base[page], CreateMetricsPage(page));
|
||||
return ptr->base[page];
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
#include "Draw.h"
|
||||
|
||||
#define LLOG(x)
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
CommonFontInfo GetFontInfoSys(Font font);
|
||||
GlyphInfo GetGlyphInfoSys(Font font, int chr);
|
||||
void GetStdFontSys(String& name, int& height);
|
||||
Vector<FaceInfo> GetAllFacesSys();
|
||||
|
||||
bool Replace(Font fnt, int chr, Font& rfnt);
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
Size Font::StdFontSize;
|
||||
Font Font::AStdFont;
|
||||
|
||||
INITBLOCK {
|
||||
RichValue<Font>::Register();
|
||||
}
|
||||
|
||||
const Vector<FaceInfo>& Font::List()
|
||||
{
|
||||
static Vector<FaceInfo> *q;
|
||||
ONCELOCK {
|
||||
static Vector<FaceInfo> x;
|
||||
x = GetAllFacesSys();
|
||||
q = &x;
|
||||
}
|
||||
return *q;
|
||||
}
|
||||
|
||||
void sInitFonts()
|
||||
{
|
||||
Font::List();
|
||||
}
|
||||
|
||||
INITBLOCK {
|
||||
sInitFonts();
|
||||
}
|
||||
|
||||
int Font::GetFaceCount()
|
||||
{
|
||||
return List().GetCount();
|
||||
}
|
||||
|
||||
String Font::GetFaceName(int index)
|
||||
{
|
||||
const Vector<FaceInfo>& l = List();
|
||||
if(index >= 0 && index < l.GetCount())
|
||||
return l[index].name;
|
||||
return Null;
|
||||
}
|
||||
|
||||
dword Font::GetFaceInfo(int index)
|
||||
{
|
||||
const Vector<FaceInfo>& l = List();
|
||||
if(index >= 0 && index < l.GetCount())
|
||||
return l[index].info;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FontFilter(int c)
|
||||
{
|
||||
return c >= 'a' && c <= 'z' || c >= '0' && c <= '9' ? c : c >= 'A' && c <= 'Z' ? ToLower(c) : 0;
|
||||
}
|
||||
|
||||
int Font::FindFaceNameIndex(const String& name) {
|
||||
if(name == "STDFONT")
|
||||
return 0;
|
||||
for(int i = 1; i < GetFaceCount(); i++)
|
||||
if(GetFaceName(i) == name)
|
||||
return i;
|
||||
String n = Filter(name, FontFilter);
|
||||
for(int i = 1; i < GetFaceCount(); i++)
|
||||
if(Filter(GetFaceName(i), FontFilter) == n)
|
||||
return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Font::SyncStdFont()
|
||||
{
|
||||
DrawLock __;
|
||||
StdFontSize = Size(AStdFont.GetAveWidth(), AStdFont().Bold().GetGlyphsHeight());
|
||||
}
|
||||
|
||||
void Font::SetStdFont(Font font)
|
||||
{
|
||||
DrawLock __;
|
||||
AStdFont = font;
|
||||
SyncStdFont();
|
||||
}
|
||||
|
||||
void Font::InitStdFont()
|
||||
{
|
||||
ONCELOCK {
|
||||
DrawLock __;
|
||||
List();
|
||||
AStdFont = Arial(12);
|
||||
String name;
|
||||
int height = 0;
|
||||
GetStdFontSys(name, height);
|
||||
int q = FindFaceNameIndex(name);
|
||||
if(q > 0)
|
||||
SetStdFont(Font(q, max(height, 1)));
|
||||
}
|
||||
}
|
||||
|
||||
Font Font::GetStdFont()
|
||||
{
|
||||
InitStdFont();
|
||||
return AStdFont;
|
||||
}
|
||||
|
||||
Size Font::GetStdFontSize()
|
||||
{
|
||||
InitStdFont();
|
||||
return StdFontSize;
|
||||
}
|
||||
|
||||
Font StdFont()
|
||||
{
|
||||
return Font(0, Font::GetStdFont().GetHeight());
|
||||
}
|
||||
|
||||
String Font::GetFaceName() const {
|
||||
if(IsNull()) return String();
|
||||
if(GetFace() == 0)
|
||||
return "STDFONT";
|
||||
return GetFaceName(GetFace());
|
||||
}
|
||||
|
||||
dword Font::GetFaceInfo() const {
|
||||
if(IsNull()) return 0;
|
||||
return GetFaceInfo(GetFace());
|
||||
}
|
||||
|
||||
Font& Font::FaceName(const String& name) {
|
||||
int n = FindFaceNameIndex(name);
|
||||
Face(n < 0 ? 0xffff : n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Font::Serialize(Stream& s) {
|
||||
int version = 1;
|
||||
s / version;
|
||||
if(version >= 1) {
|
||||
int f = GetFace();
|
||||
if(f > COURIER)
|
||||
f = -1;
|
||||
s / f;
|
||||
String name;
|
||||
if(f < 0) {
|
||||
name = GetFaceName();
|
||||
s % name;
|
||||
}
|
||||
if(s.IsLoading())
|
||||
if(f >= 0)
|
||||
Face(f);
|
||||
else
|
||||
FaceName(name);
|
||||
}
|
||||
else {
|
||||
String name = GetFaceName();
|
||||
s % name;
|
||||
if(s.IsLoading()) {
|
||||
FaceName(name);
|
||||
if(IsNull())
|
||||
Face(COURIER);
|
||||
}
|
||||
}
|
||||
s % v.flags % v.height % v.width;
|
||||
}
|
||||
|
||||
template<>
|
||||
String AsString(const Font& f) {
|
||||
if(IsNull(f)) return "<null>";
|
||||
String s = "<" + f.GetFaceName() + Format(":%d", f.GetHeight());
|
||||
if(f.IsBold())
|
||||
s += " Bold";
|
||||
if(f.IsItalic())
|
||||
s += " Italic";
|
||||
if(f.IsUnderline())
|
||||
s += " Underline";
|
||||
if(f.IsStrikeout())
|
||||
s += " Strikeout";
|
||||
return s + '>';
|
||||
}
|
||||
|
||||
struct CharEntry {
|
||||
int64 font;
|
||||
GlyphInfo info;
|
||||
word chr;
|
||||
};
|
||||
|
||||
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.AsInt64() || 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.AsInt64() || e.chr != chr) {
|
||||
e.font = font.AsInt64();
|
||||
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.AsInt64() || 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;
|
||||
int64 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.AsInt64()) {
|
||||
DrawLock __;
|
||||
e.font = font.AsInt64();
|
||||
e.info = GetFontInfoSys(font);
|
||||
}
|
||||
return e.info;
|
||||
}
|
||||
|
||||
int Font::GetWidth(int c) const {
|
||||
return GetGlyphMetrics(*this, c).width;
|
||||
}
|
||||
|
||||
int Font::GetLeftSpace(int c) const {
|
||||
return GetGlyphMetrics(*this, c).lspc;
|
||||
}
|
||||
|
||||
int Font::GetRightSpace(int c) const {
|
||||
return GetGlyphMetrics(*this, c).rspc;
|
||||
}
|
||||
|
||||
thread__ int64 lastFiFont = INT_MIN;
|
||||
thread__ CommonFontInfo lastFontInfo;
|
||||
|
||||
const CommonFontInfo& Font::Fi() const
|
||||
{
|
||||
if(AsInt64() == lastFiFont)
|
||||
return lastFontInfo;
|
||||
lastFontInfo = GetFontInfo(*this);
|
||||
lastFiFont = AsInt64();
|
||||
return lastFontInfo;
|
||||
}
|
||||
|
||||
FontInfo Font::Info() const
|
||||
{
|
||||
FontInfo h;
|
||||
h.font = *this;
|
||||
return h;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -165,111 +165,104 @@ gc_info[128] = {
|
|||
{ CG_NONE, 0, 0 } // CG_SMALL, 'LONG S
|
||||
};
|
||||
|
||||
SystemDraw& ScreenInfo();
|
||||
|
||||
void FontInfo::ComposeMetrics(Font fnt, CharMetrics *m, int page) const
|
||||
bool Compose(Font font, int chr, ComposedGlyph& cg)
|
||||
{
|
||||
if(fnt.GetFaceInfo() & Font::COMPOSED) {
|
||||
FontInfo fi = fnt.Info();
|
||||
for(int i = 0; i < 32; i++) {
|
||||
int c = gc_info[i + (page - 8) * 32].ascii;
|
||||
m[i].lspc = fi.GetLeftSpace(c);
|
||||
m[i].width = fi[c];
|
||||
m[i].rspc = fi.GetRightSpace(c);
|
||||
if(gc_info[i].type == CG_COMMA_UR && !fi.IsFixedPitch())
|
||||
m[i].rspc += m[i].width / 2;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
void Draw::ComposeText(int x, int y, int angle, const wchar *text, Font font, Color ink,
|
||||
int n, const int *dx) {
|
||||
if(font.GetFaceInfo() & Font::COMPOSED) {
|
||||
for(int i = 0; i < n; i++)
|
||||
if(text[i] >= 256 && text[i] < 256 + 128) {
|
||||
FontInfo fi = font.Info();
|
||||
Clip(x, y, 9999, fi.GetHeight());
|
||||
Buffer<wchar> ntext(n);
|
||||
double sina;
|
||||
double cosa;
|
||||
Size offset;
|
||||
if(angle)
|
||||
SinCos(angle, sina, cosa); //TODO global sin tables!
|
||||
int xp = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
wchar chr = text[i];
|
||||
ntext[i] = chr;
|
||||
if(chr >= 256 && chr < 256 + 128) {
|
||||
CGInfo f = gc_info[chr - 256];
|
||||
if(f.type != CG_NONE) {
|
||||
ntext[i] = chr = f.ascii;
|
||||
Font mfnt = font;
|
||||
FontInfo mfi = fi;
|
||||
int my = 0;
|
||||
int mx = 0;
|
||||
int cw = fi[f.ascii];
|
||||
int mw = mfi[f.mark];
|
||||
wchar mark = f.mark;
|
||||
if(mark == CG_COMMA_UR && fi.IsFixedPitch())
|
||||
mark = CG_CARON;
|
||||
if(mark == CG_COMMA_T) {
|
||||
my -= 3 * font.GetHeight() / 4;
|
||||
mx += 4 * cw / 10;
|
||||
if(font.IsItalic())
|
||||
mx += mw / 2;
|
||||
}
|
||||
else
|
||||
if(mark == CG_COMMA_UR) {
|
||||
my -= 2 * font.GetHeight() / 3;
|
||||
mx += cw - mw / 4;
|
||||
mark = ',';
|
||||
if(font.IsItalic())
|
||||
mx += mw / 3;
|
||||
}
|
||||
else
|
||||
if(mark == CG_COMMA_URI) {
|
||||
my -= 2 * font.GetHeight() / 3;
|
||||
mx += cw - mw / 2;
|
||||
mark = ',';
|
||||
if(font.IsItalic())
|
||||
mx += mw / 3;
|
||||
}
|
||||
else
|
||||
if(mark != CG_STROKE) {
|
||||
if(f.mark != CG_OGONEK && f.mark != CG_CEDILLA && f.type == CG_CAPITAL) {
|
||||
mfnt = font(9 * font.GetHeight() / 10);
|
||||
mfi = mfnt.Info();
|
||||
my -= mark == CG_RING_ABOVE ? font.GetHeight() / 19
|
||||
: font.GetHeight() / 13;
|
||||
}
|
||||
mw = mfi[f.mark];
|
||||
mx += (cw - mw) / 2;
|
||||
if(font.IsItalic())
|
||||
mx += mw / 5;
|
||||
}
|
||||
if(angle)
|
||||
DrawText(int(x + cosa * (xp + mx) + sina * my),
|
||||
int(y - sina * (xp + mx) + cosa * my),
|
||||
angle, &mark, mfnt, ink, 1);
|
||||
else
|
||||
DrawText(x + xp + mx, y + my, &mark, mfnt, ink, 1);
|
||||
}
|
||||
}
|
||||
if(angle)
|
||||
DrawTextOp(int(x + cosa * xp), int(y - sina * xp),
|
||||
angle, &chr, font, ink, 1, dx);
|
||||
if(dx)
|
||||
xp += dx[i];
|
||||
else
|
||||
xp += fi[chr];
|
||||
}
|
||||
if(!angle)
|
||||
DrawTextOp(x, y, angle, ntext, font, ink, n, dx);
|
||||
End();
|
||||
return;
|
||||
}
|
||||
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)
|
||||
{
|
||||
static Vector<int> 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);
|
||||
}
|
||||
}
|
||||
DrawTextOp(x, y, angle, text, font, ink, n, dx);
|
||||
|
||||
Font f = fnt;
|
||||
for(int i = 0; i < rface.GetCount(); i++)
|
||||
if(IsNormal(f.Face(rface[i]), chr)) {
|
||||
rfnt = f;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
54
newdraw/Draw/FontInt.h
Normal file
54
newdraw/Draw/FontInt.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef _Draw_FontInt_h_
|
||||
#define _Draw_FontInt_h_
|
||||
|
||||
// Internal header!
|
||||
|
||||
struct FaceInfo : Moveable<FaceInfo> {
|
||||
String name;
|
||||
dword info;
|
||||
};
|
||||
|
||||
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
|
||||
String path;
|
||||
#endif
|
||||
};
|
||||
|
||||
class Font;
|
||||
|
||||
struct GlyphInfo : Moveable<GlyphInfo> {
|
||||
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; }
|
||||
};
|
||||
|
||||
void Std(Font& font);
|
||||
GlyphInfo GetGlyphInfo(Font font, int chr);
|
||||
const CommonFontInfo& GetFontInfo(Font font);
|
||||
bool IsNormal(Font font, int chr);
|
||||
void GlyphMetrics(GlyphInfo& f, Font font, int chr);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,412 +1,333 @@
|
|||
#include "Draw.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
|
||||
#define LLOG(x) // LOG(x)
|
||||
#define LTIMING(x) // TIMING(x)
|
||||
|
||||
struct FontFaceInfo : Moveable<FontFaceInfo> {
|
||||
String name;
|
||||
dword info;
|
||||
|
||||
FontFaceInfo() { info = 0; }
|
||||
};
|
||||
|
||||
static VectorMap<String, FontFaceInfo>& sFontFace()
|
||||
{
|
||||
static VectorMap<String, FontFaceInfo> s;
|
||||
return s;
|
||||
}
|
||||
|
||||
int Font::GetFaceCount()
|
||||
{
|
||||
ONCELOCK {
|
||||
FontInfo::InitFonts();
|
||||
}
|
||||
return sFontFace().GetCount();
|
||||
}
|
||||
|
||||
String Font::GetFaceName(int index) {
|
||||
ONCELOCK {
|
||||
FontInfo::InitFonts();
|
||||
}
|
||||
return index >= 0 && index < sFontFace().GetCount() ? sFontFace()[index].name
|
||||
: Null;
|
||||
}
|
||||
|
||||
dword Font::GetFaceInfo(int index) {
|
||||
ONCELOCK {
|
||||
FontInfo::InitFonts();
|
||||
}
|
||||
return index >= 0 && index < sFontFace().GetCount() ? sFontFace()[index].info
|
||||
: 0;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
int CALLBACK FontInfo::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;
|
||||
#ifndef PLATFORM_WINCE
|
||||
{
|
||||
HDC hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
|
||||
HFONT hfnt = (HFONT) CreateFontIndirect(logfont);
|
||||
HFONT o = (HFONT) SelectObject(hdc, hfnt);
|
||||
wchar wch[128];
|
||||
WORD pos[128];
|
||||
for(int i = 0; i < 128; i++)
|
||||
wch[i] = i + 256;
|
||||
Win32_GetGlyphIndices(hdc, (LPCWSTR) wch, 128, pos, 1);
|
||||
SelectObject(hdc, o);
|
||||
DeleteObject(hfnt);
|
||||
DeleteDC(hdc);
|
||||
int n = 0;
|
||||
for(int i = 0; i < 128; i++)
|
||||
if(pos[i] == 0xffff)
|
||||
n++;
|
||||
if(n > 10)
|
||||
typ |= Font::COMPOSED;
|
||||
}
|
||||
#endif
|
||||
#ifdef PLATFORM_WINCE
|
||||
if(facename) {
|
||||
FontFaceInfo& f = sFontFace().Add(WString(logfont->lfFaceName).ToString());
|
||||
f.name = WString(facename).ToString();
|
||||
return 0;
|
||||
}
|
||||
FontFaceInfo& f = sFontFace().Add(WString(logfont->lfFaceName).ToString());
|
||||
f.name = FromSystemCharset(logfont->lfFaceName);
|
||||
#else
|
||||
if(facename) {
|
||||
FontFaceInfo& f = sFontFace().Add(logfont->lfFaceName);
|
||||
f.name = facename;
|
||||
f.info = typ;
|
||||
return 0;
|
||||
}
|
||||
FontFaceInfo& f = sFontFace().Add(logfont->lfFaceName);
|
||||
f.name = FromSystemCharset(logfont->lfFaceName);
|
||||
#endif
|
||||
f.info |= typ;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FontInfo::EnumFace(HDC hdc, const char *face)
|
||||
{
|
||||
#ifdef PLATFORM_WINCE
|
||||
return EnumFontFamilies(hdc, ToSystemCharset(face), AddFace, (LPARAM)~ToSystemCharset(face));
|
||||
#else
|
||||
return EnumFontFamilies(hdc, face, AddFace, (LPARAM)face);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FontInfo::ForceFace(HDC hdc, const char *face, const char *aface)
|
||||
{
|
||||
if(!aface)
|
||||
aface = "Arial";
|
||||
if(EnumFace(hdc, face) && (aface == NULL || EnumFace(hdc, aface)))
|
||||
Panic("Missing font " + String(face));
|
||||
}
|
||||
|
||||
#ifdef PLATFORM_WINCE
|
||||
const char *FontScreenSans = "Tahoma"; //TODO!
|
||||
const char *FontScreenSerif = "Tahoma";
|
||||
const char *FontScreenFixed = "Courier New";
|
||||
const char *FontRoman = "Tahoma" ;
|
||||
const char *FontArial = "Tahoma";
|
||||
const char *FontCourier = "Tahoma";
|
||||
const char *FontSymbol = "Tahoma";
|
||||
const char *FontWingdings = "Tahoma";
|
||||
const char *FontTahoma = "Tahoma";
|
||||
#else
|
||||
const char *FontScreenSans = "Arial";
|
||||
const char *FontScreenSerif = "Times New Roman";
|
||||
const char *FontScreenFixed = "Courier New";
|
||||
const char *FontRoman = "Times New Roman" ;
|
||||
const char *FontArial = "Arial";
|
||||
const char *FontCourier = "Courier New";
|
||||
const char *FontSymbol = "Symbol";
|
||||
const char *FontWingdings = "WingDings";
|
||||
const char *FontTahoma = "Tahoma";
|
||||
#endif
|
||||
|
||||
void FontInfo::InitPlatformFonts() {
|
||||
#ifdef PLATFORM_WINCE
|
||||
HDC hdc = CreateDC(NULL, NULL, NULL, NULL);
|
||||
#else
|
||||
HDC hdc = CreateIC("DISPLAY", NULL, NULL, NULL);
|
||||
#endif
|
||||
ForceFace(hdc, "Arial", NULL);
|
||||
ForceFace(hdc, FontScreenSerif, FontScreenSans);
|
||||
ForceFace(hdc, FontScreenSans, FontScreenSans);
|
||||
ForceFace(hdc, FontScreenFixed, FontScreenSans);
|
||||
ForceFace(hdc, FontRoman, FontScreenSans);
|
||||
ForceFace(hdc, FontArial, FontScreenSans);
|
||||
ForceFace(hdc, FontCourier, FontScreenSans);
|
||||
ForceFace(hdc, FontSymbol, FontScreenSans);
|
||||
ForceFace(hdc, FontWingdings, FontArial);
|
||||
ForceFace(hdc, FontTahoma, FontArial);
|
||||
EnumFace(hdc, NULL);
|
||||
DeleteDC(hdc);
|
||||
#ifdef PLATFORM_WINCE
|
||||
SetStdFont(Arial(10));
|
||||
#else
|
||||
NONCLIENTMETRICS ncm;
|
||||
ncm.cbSize = sizeof(ncm);
|
||||
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
|
||||
SetStdFont(Font(Font::FindFaceNameIndex(ncm.lfMenuFont.lfFaceName),
|
||||
abs((int)ncm.lfMenuFont.lfHeight)));
|
||||
#endif
|
||||
}
|
||||
|
||||
FontInfo::Data::Data()
|
||||
{
|
||||
refcount = 1;
|
||||
hfont = NULL;
|
||||
for(int i = 0; i < 64; i++)
|
||||
base[i] = NULL;
|
||||
}
|
||||
|
||||
FontInfo::Data::~Data()
|
||||
{
|
||||
DrawLock __;
|
||||
if(hfont)
|
||||
DeleteObject(hfont);
|
||||
for(int i = 0; i < 64; i++)
|
||||
if(base[i]) delete[] base[i];
|
||||
}
|
||||
|
||||
bool FontInfo::Data::HasChar(int ch) const
|
||||
{
|
||||
HDC hdc = ScreenHDC();
|
||||
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
|
||||
WCHAR c = ch;
|
||||
WORD pos;
|
||||
Win32_GetGlyphIndices(hdc, &c, 1, &pos, 1);
|
||||
::SelectObject(hdc, ohfont);
|
||||
return pos != 0xffff;
|
||||
}
|
||||
|
||||
int sGetCW(HDC hdc, wchar *h, int n)
|
||||
{
|
||||
SIZE sz;
|
||||
return GetTextExtentPoint32W(hdc, h, n, &sz) ? sz.cx : 0;
|
||||
}
|
||||
|
||||
void FontInfo::Data::GetMetrics(CharMetrics *t, int from, int count)
|
||||
{
|
||||
DrawLock __;
|
||||
HDC hdc = ScreenHDC();
|
||||
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
|
||||
if(from >= 8192) {
|
||||
wchar h[3];
|
||||
h[0] = 'x';
|
||||
h[1] = 'x';
|
||||
h[2] = 'x';
|
||||
int w0 = sGetCW(hdc, h, 2);
|
||||
for(int i = 0; i < count; 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(count);
|
||||
#ifdef PLATFORM_WINCE
|
||||
if(scaleable)
|
||||
abcw = ::GetCharABCWidths(hdc, from, from + count - 1, abc);
|
||||
#else
|
||||
if(scaleable && !(abcw = ::GetCharABCWidthsW(hdc, from, from + count - 1, abc)))
|
||||
abca = ::GetCharABCWidthsA(hdc, from, from + count - 1, abc);
|
||||
#endif
|
||||
if(abcw)
|
||||
{
|
||||
for(ABC *s = abc, *lim = abc + count; s < lim; s++, t++)
|
||||
{
|
||||
t->width = s->abcA + s->abcB + s->abcC;
|
||||
t->lspc = s->abcA;
|
||||
t->rspc = s->abcC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer<int> wb(count);
|
||||
#ifdef PLATFORM_WINCE
|
||||
::GetCharWidth32(hdc, from, from + count - 1, wb);
|
||||
#else
|
||||
::GetCharWidthW(hdc, from, from + count - 1, wb);
|
||||
#endif
|
||||
for(int *s = wb, *lim = wb + count; s < lim; s++, t++)
|
||||
{
|
||||
t->width = *s - 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);
|
||||
}
|
||||
|
||||
FontInfo FontInfo::AcquireFontInfo0(Font font, HDC hdc, int angle)
|
||||
{
|
||||
DrawLock __;
|
||||
if(IsNull(font))
|
||||
font = StdFont();
|
||||
if(font.GetFace() == 0)
|
||||
font.Face(AStdFont.GetFace());
|
||||
if(font.GetHeight() == 0)
|
||||
font.Height(AStdFont.GetHeight());
|
||||
// if(font.GetFace() >= sFontFace().GetCount())
|
||||
// font.SetFace(Font::ARIAL);
|
||||
FontInfo::Data *f, *fh;
|
||||
f = fh = GetFontHash((font.GetHashValue() ^ angle) % FONTHASH);
|
||||
LLOG("Acquire " << font);
|
||||
for(;;) {
|
||||
f = f->GetNext(HASH);
|
||||
if(f == fh) break;
|
||||
if(f->font == font && f->angle == angle)
|
||||
{
|
||||
LLOG("Reusing " << f->font << " count:" << f->count);
|
||||
if(f->InList(LRU)) {
|
||||
f->Unlink(LRU);
|
||||
FontCached--;
|
||||
LLOG("Removing from cache " << f->font << " count:" << f->count <<
|
||||
" cached:" << FontCached);
|
||||
}
|
||||
f->refcount++;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
LLOG("New " << font);
|
||||
LTIMING("Acquire New");
|
||||
f = fh->InsertNext(HASH);
|
||||
f->font = font;
|
||||
f->angle = angle;
|
||||
|
||||
byte chrset;
|
||||
if((sFontFace()[font.GetFace()].info & Font::SCALEABLE) == 0)
|
||||
chrset = DEFAULT_CHARSET;
|
||||
else
|
||||
if(sFontFace()[font.GetFace()].info & Font::SYMBOLTYPE)
|
||||
chrset = SYMBOL_CHARSET;
|
||||
else
|
||||
chrset = DEFAULT_CHARSET;
|
||||
#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()));
|
||||
f->hfont = CreateFontIndirect(&lfnt);
|
||||
#else
|
||||
f->hfont = 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,
|
||||
sFontFace().GetKey(font.GetFace()));
|
||||
#endif
|
||||
ASSERT(f->hfont);
|
||||
TEXTMETRIC tm;
|
||||
HFONT hfont = (HFONT) ::SelectObject(hdc, f->hfont);
|
||||
::GetTextMetrics(hdc, &tm);
|
||||
f->ascent = tm.tmAscent;
|
||||
f->descent = tm.tmDescent;
|
||||
f->external = tm.tmExternalLeading;
|
||||
f->internal = tm.tmInternalLeading;
|
||||
f->height = f->ascent + f->descent;
|
||||
f->lineheight = f->height + f->external;
|
||||
f->overhang = tm.tmOverhang;
|
||||
f->avewidth = tm.tmAveCharWidth;
|
||||
f->maxwidth = tm.tmMaxCharWidth;
|
||||
f->firstchar = tm.tmFirstChar;
|
||||
f->charcount = tm.tmLastChar - tm.tmFirstChar + 1;
|
||||
f->default_char = tm.tmDefaultChar;
|
||||
f->fixedpitch = (tm.tmPitchAndFamily & TMPF_FIXED_PITCH) == 0;
|
||||
f->scaleable = tm.tmPitchAndFamily & TMPF_TRUETYPE;
|
||||
f->kerning.Clear();
|
||||
if(f->scaleable) {
|
||||
ABC abc;
|
||||
GetCharABCWidths(hdc, 'o', 'o', &abc);
|
||||
f->spacebefore = abc.abcA;
|
||||
f->spaceafter = abc.abcC;
|
||||
}
|
||||
else
|
||||
f->spacebefore = f->spaceafter = 0;
|
||||
#ifndef PLATFORM_WINCE
|
||||
int n = ::GetKerningPairs(hdc, 0, NULL);
|
||||
if(n) {
|
||||
Buffer<KERNINGPAIR> kp(n);
|
||||
::GetKerningPairs(hdc, n, kp);
|
||||
const KERNINGPAIR *p = kp;
|
||||
while(n--) {
|
||||
f->kerning.Add(MAKELONG(p->wFirst, p->wSecond), p->iKernAmount);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
::SelectObject(hdc, hfont);
|
||||
f->offset = Size(0, f->ascent);
|
||||
if(angle) {
|
||||
FontInfo font0 = AcquireFontInfo0(font, hdc, 0);
|
||||
double sina, cosa;
|
||||
Draw::SinCos(angle, sina, cosa);
|
||||
f->offset.cx = fround(font0.GetAscent() * sina);
|
||||
f->offset.cy = fround(font0.GetAscent() * cosa);
|
||||
}
|
||||
return FontInfo(f);
|
||||
}
|
||||
|
||||
FontInfo FontInfo::AcquireFontInfo(Font font, int angle)
|
||||
{
|
||||
return AcquireFontInfo0(font, ScreenHDC(), angle);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
#include "Draw.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
|
||||
#define LLOG(x) // LOG(x)
|
||||
#define LTIMING(x) // TIMING(x)
|
||||
|
||||
void GetStdFontSys(String& name, int& height)
|
||||
{
|
||||
#ifdef PLATFORM_WINCE
|
||||
name = "Arial";
|
||||
height = 10;
|
||||
#else
|
||||
NONCLIENTMETRICS ncm;
|
||||
ncm.cbSize = sizeof(ncm);
|
||||
::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
|
||||
name = ncm.lfMenuFont.lfFaceName;
|
||||
height = abs((int)ncm.lfMenuFont.lfHeight);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define FONTCACHE 50
|
||||
|
||||
struct HFontEntry {
|
||||
Font font;
|
||||
HFONT hfont;
|
||||
};
|
||||
|
||||
HFONT GetWin32Font(Font fnt, int angle)
|
||||
{
|
||||
RTIMING("FTFace");
|
||||
DDUMP(fnt);
|
||||
static HFontEntry cache[FONTCACHE];
|
||||
ONCELOCK {
|
||||
for(int i = 0; i < FONTCACHE; i++)
|
||||
cache[i].font.Height(-30000);
|
||||
}
|
||||
HFontEntry be;
|
||||
be = cache[0];
|
||||
for(int i = 0; i < FONTCACHE; i++) {
|
||||
HFontEntry e = cache[i];
|
||||
if(i)
|
||||
cache[i] = be;
|
||||
if(e.font == fnt) {
|
||||
if(i)
|
||||
cache[0] = e;
|
||||
return e.hfont;
|
||||
}
|
||||
be = e;
|
||||
}
|
||||
RTIMING("FTFace2");
|
||||
if(be.hfont)
|
||||
DeleteObject(be.hfont);
|
||||
|
||||
be.font = fnt;
|
||||
#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()));
|
||||
be.hfont = CreateFontIndirect(&lfnt);
|
||||
#else
|
||||
be.hfont = CreateFont(
|
||||
fnt.GetHeight() ? -abs(fnt.GetHeight()) : -12,
|
||||
fnt.GetWidth(), angle, angle, fnt.IsBold() ? FW_BOLD : FW_NORMAL,
|
||||
fnt.IsItalic(), fnt.IsUnderline(), fnt.IsStrikeout(),
|
||||
fnt.GetFace() == Font::SYMBOL ? SYMBOL_CHARSET : DEFAULT_CHARSET,
|
||||
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
|
||||
cache[0] = be;
|
||||
return be.hfont;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
CommonFontInfo GetFontInfoSys(Font font)
|
||||
{
|
||||
CommonFontInfo fi;
|
||||
memset(&fi, 0, sizeof(fi));
|
||||
HFONT hfont = GetWin32Font(font, 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) && 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;
|
||||
list.Add().name = "STDFONT";
|
||||
list.Top().info = 0;
|
||||
#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;
|
||||
}
|
||||
|
||||
#define GLYPHINFOCACHE 31
|
||||
|
||||
GlyphInfo GetGlyphInfoSys(Font font, int chr)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
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[q];
|
||||
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[q][i].width = (int16)0x8000;
|
||||
li[q][i].lspc = li[q][i].rspc = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return li[q][chr & 255];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue