Developing new draw

git-svn-id: svn://ultimatepp.org/upp/trunk@1361 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-07-05 19:55:01 +00:00
parent 156ba63fc3
commit 144066e580
12 changed files with 1846 additions and 1895 deletions

View file

@ -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;
}

File diff suppressed because it is too large Load diff

View file

@ -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,

View file

@ -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

View file

@ -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;
}
}
// ----------------------------

View 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

View file

@ -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);
}

View file

@ -53,7 +53,8 @@ private:
friend void StaticExitDraw_();
FontInfo lastFont;
Font lastFont;
int lastAngle;
Point actual_offset_bak;

View file

@ -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

View file

@ -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
View 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

View file

@ -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