mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-21 06:45:39 -06:00
Developing newdraw
git-svn-id: svn://ultimatepp.org/upp/trunk@1359 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
dad8006d13
commit
379bc287f1
5 changed files with 1545 additions and 1405 deletions
2029
newdraw/Draw/Draw.h
2029
newdraw/Draw/Draw.h
File diff suppressed because it is too large
Load diff
|
|
@ -52,6 +52,7 @@ file
|
|||
DrawX11.h,
|
||||
DrawX11.cpp,
|
||||
DrawOpX11.cpp,
|
||||
DrawTextX11.cpp,
|
||||
BackDraw.h,
|
||||
BackDraw.cpp,
|
||||
Image readonly separator,
|
||||
|
|
|
|||
|
|
@ -298,93 +298,6 @@ void SystemDraw::DrawArcOp(const Rect& rc, Point start, Point end, int width, Co
|
|||
XChangeGC(Xdisplay, GetGC(), GCForeground, &gcv_old);
|
||||
}
|
||||
|
||||
void SystemDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font,
|
||||
Color ink, int n, const int *dx) {
|
||||
LTIMING("DrawText");
|
||||
LLOG("DrawText " << ToUtf8(WString(text, n)) << " color:" << ink << " font:" << font);
|
||||
//TODO - X11 seems to crash when displaying too long strings (?)
|
||||
int ox = x + actual_offset.x;
|
||||
int oy = y + actual_offset.y;
|
||||
SetForeground(ink);
|
||||
SetFont(font, angle);
|
||||
const FontInfo::Data *fd = lastFont.ptr;
|
||||
XftColor c;
|
||||
c.color.red = ink.GetR() << 8;
|
||||
c.color.green = ink.GetG() << 8;
|
||||
c.color.blue = ink.GetB() << 8;
|
||||
c.color.alpha = 0xffff;
|
||||
c.pixel = GetXPixel(ink.GetR(), ink.GetG(), ink.GetB());
|
||||
if(angle) {
|
||||
int xpos = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
wchar h = text[i];
|
||||
XftDrawString16(xftdraw, &c, fd->xftfont,
|
||||
int(ox + xpos * fd->cosa + fd->offset.cx),
|
||||
int(oy - xpos * fd->sina + fd->offset.cy),
|
||||
(FcChar16 *)&h, 1);
|
||||
xpos += dx ? dx[i] : lastFont[text[i]];
|
||||
}
|
||||
if(font.IsUnderline() || font.IsStrikeout()) {
|
||||
x += fd->offset.cx;
|
||||
y += fd->offset.cy;
|
||||
if(font.IsUnderline())
|
||||
DrawLine(
|
||||
int(x + fd->underline_position * fd->sina),
|
||||
int(y + fd->underline_position * fd->cosa),
|
||||
int(x + xpos * fd->cosa + fd->underline_position * fd->sina),
|
||||
int(y - xpos * fd->sina + fd->underline_position * fd->cosa),
|
||||
fd->underline_thickness,
|
||||
ink
|
||||
);
|
||||
if(font.IsStrikeout()) {
|
||||
int p = 2 * fd->ascent / 3;
|
||||
DrawLine(
|
||||
int(x + p * fd->sina),
|
||||
int(y + p * fd->cosa),
|
||||
int(x + xpos * fd->cosa + p * fd->sina),
|
||||
int(y - xpos * fd->sina + p * fd->cosa),
|
||||
fd->underline_thickness,
|
||||
ink
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(dx) {
|
||||
int xpos = ox;
|
||||
Buffer<XftCharSpec> ch(n);
|
||||
for(int i = 0; i < n; i++) {
|
||||
ch[i].ucs4 = text[i];
|
||||
ch[i].x = xpos;
|
||||
ch[i].y = oy + fd->ascent;
|
||||
xpos += dx[i];
|
||||
}
|
||||
XftDrawCharSpec(xftdraw, &c, fd->xftfont, ch, n);
|
||||
}
|
||||
else
|
||||
XftDrawString16(xftdraw, &c, fd->xftfont, ox, oy + fd->ascent,
|
||||
(FcChar16 *)text, n);
|
||||
LLOG("XftColor: r=" << c.color.red << ", g=" << c.color.green << ", b=" << c.color.blue
|
||||
<< ", alpha=" << c.color.alpha << ", pixel=" << FormatIntHex(c.pixel));
|
||||
if(font.IsUnderline() || font.IsStrikeout()) {
|
||||
int cx;
|
||||
if(dx && n > 0) {
|
||||
cx = 0;
|
||||
Sum(cx, dx, dx + n - 1);
|
||||
cx += lastFont[text[n - 1]];
|
||||
}
|
||||
else
|
||||
cx = GetTextSize(text, font, n).cx;
|
||||
if(font.IsUnderline())
|
||||
DrawRect(x, y + lastFont.GetAscent() + lastFont.ptr->underline_position,
|
||||
cx, lastFont.ptr->underline_thickness, ink);
|
||||
if(font.IsStrikeout())
|
||||
DrawRect(x, y + 2 * lastFont.GetAscent() / 3,
|
||||
cx, lastFont.ptr->underline_thickness, ink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
|
|||
221
newdraw/Draw/DrawTextX11.cpp
Normal file
221
newdraw/Draw/DrawTextX11.cpp
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
#include "Draw.h"
|
||||
|
||||
NAMESPACE_UPP
|
||||
|
||||
#ifdef PLATFORM_X11
|
||||
|
||||
#define LTIMING(x)
|
||||
#define LLOG(x)
|
||||
|
||||
extern int gtk_antialias;
|
||||
extern int gtk_hinting;
|
||||
extern String gtk_hintstyle;
|
||||
extern String gtk_rgba;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
XftFont *CreateXftFont(Font font, int angle)
|
||||
{
|
||||
LTIMING("CreateXftFont");
|
||||
XftFont *xftfont;
|
||||
double sina, cosa;
|
||||
Std(font);
|
||||
int hg = abs(font.GetHeight());
|
||||
if(hg == 0) hg = 10;
|
||||
int i = font.GetFace();
|
||||
if(i < 0 || i >= Font::GetFaceCount())
|
||||
i = 0;
|
||||
String face = font.GetFaceName();
|
||||
FcPattern *p = FcPatternCreate();
|
||||
FcPatternAddString(p, FC_FAMILY, (FcChar8*)~face);
|
||||
FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0);
|
||||
FcPatternAddInteger(p, FC_PIXEL_SIZE, hg);
|
||||
FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100);
|
||||
FcPatternAddBool(p, FC_MINSPACE, 1);
|
||||
if(angle) {
|
||||
FcMatrix mx;
|
||||
Draw::SinCos(angle, sina, cosa);
|
||||
mx.xx = cosa;
|
||||
mx.xy = -sina;
|
||||
mx.yx = sina;
|
||||
mx.yy = cosa;
|
||||
FcPatternAddMatrix(p, FC_MATRIX, &mx);
|
||||
}
|
||||
FcResult result;
|
||||
FcPattern *m = XftFontMatch(Xdisplay, Xscreenno, p, &result);
|
||||
if(font.IsNonAntiAliased() || gtk_antialias >= 0) {
|
||||
FcPatternDel(m, FC_ANTIALIAS);
|
||||
FcPatternAddBool(m, FC_ANTIALIAS,
|
||||
font.IsNonAntiAliased() ? FcFalse : gtk_antialias ? FcTrue : FcFalse);
|
||||
}
|
||||
if(gtk_hinting >= 0) {
|
||||
FcPatternDel(m, FC_HINTING);
|
||||
FcPatternAddBool(m, FC_HINTING, gtk_hinting);
|
||||
}
|
||||
const char *hs[] = { "hintnone", "hintslight", "hintmedium", "hintfull" };
|
||||
for(int i = 0; i < 4; i++)
|
||||
if(gtk_hintstyle == hs[i]) {
|
||||
FcPatternDel(m, FC_HINT_STYLE);
|
||||
FcPatternAddInteger(m, FC_HINT_STYLE, i);
|
||||
}
|
||||
const char *rgba[] = { "_", "rgb", "bgr", "vrgb", "vbgr" };
|
||||
for(int i = 0; i < __countof(rgba); i++)
|
||||
if(gtk_rgba == rgba[i]) {
|
||||
FcPatternDel(m, FC_RGBA);
|
||||
FcPatternAddInteger(m, FC_RGBA, i);
|
||||
}
|
||||
xftfont = XftFontOpenPattern(Xdisplay, m);
|
||||
FcPatternDestroy(p);
|
||||
return xftfont;
|
||||
}
|
||||
|
||||
#define FONTCACHE 37
|
||||
|
||||
struct XftEntry {
|
||||
Font font;
|
||||
int angle;
|
||||
XftFont *xftfont;
|
||||
};
|
||||
|
||||
XftFont *GetXftFont(Font fnt, int angle)
|
||||
{
|
||||
static XftEntry cache[FONTCACHE];
|
||||
ONCELOCK {
|
||||
for(int i = 0; i < FONTCACHE; i++)
|
||||
cache[i].font.Height(-30000);
|
||||
}
|
||||
XftEntry be;
|
||||
be = cache[0];
|
||||
for(int i = 0; i < FONTCACHE; i++) {
|
||||
XftEntry e = cache[i];
|
||||
if(i)
|
||||
cache[i] = be;
|
||||
if(e.font == fnt && e.angle == angle) {
|
||||
if(i)
|
||||
cache[0] = e;
|
||||
return e.xftfont;
|
||||
}
|
||||
be = e;
|
||||
}
|
||||
if(be.xftfont) {
|
||||
XftFontClose(Xdisplay, be.xftfont);
|
||||
}
|
||||
be.font = fnt;
|
||||
be.angle = angle;
|
||||
be.xftfont = CreateXftFont(fnt, angle);
|
||||
cache[0] = be;
|
||||
return be.xftfont;
|
||||
}
|
||||
|
||||
void SystemDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font,
|
||||
Color ink, int n, const int *dx) {
|
||||
DrawLock __;
|
||||
LTIMING("DrawText");
|
||||
LLOG("DrawText " << ToUtf8(WString(text, n)) << " color:" << ink << " font:" << font);
|
||||
//TODO - X11 seems to crash when displaying too long strings (?)
|
||||
int ox = x + actual_offset.x;
|
||||
int oy = y + actual_offset.y;
|
||||
SetForeground(ink);
|
||||
SetFont(font, angle);
|
||||
const FontInfo::Data *fd = lastFont.ptr;
|
||||
XftColor c;
|
||||
c.color.red = ink.GetR() << 8;
|
||||
c.color.green = ink.GetG() << 8;
|
||||
c.color.blue = ink.GetB() << 8;
|
||||
c.color.alpha = 0xffff;
|
||||
c.pixel = GetXPixel(ink.GetR(), ink.GetG(), ink.GetB());
|
||||
XftFont *xftfont = GetXftFont(font, angle);
|
||||
Size offset = Point(0, 0);
|
||||
double sina, cosa;
|
||||
int ascent = font.Info().GetAscent();
|
||||
if(angle) {
|
||||
SinCos(angle, sina, cosa);
|
||||
offset.cx = fround(ascent * sina);
|
||||
offset.cy = fround(ascent * cosa);
|
||||
}
|
||||
int hg = abs(font.GetHeight());
|
||||
if(hg == 0) hg = 10;
|
||||
int underline_thickness = max(hg / 20, 1);
|
||||
int underline_position = max(hg / 15, int(font.Info().GetDescent() > 0));
|
||||
if(angle) {
|
||||
int xpos = 0;
|
||||
for(int i = 0; i < n; i++) {
|
||||
wchar h = text[i];
|
||||
XftDrawString16(xftdraw, &c, xftfont,
|
||||
int(ox + xpos * cosa + offset.cx),
|
||||
int(oy - xpos * sina + offset.cy),
|
||||
(FcChar16 *)&h, 1);
|
||||
xpos += dx ? dx[i] : lastFont[text[i]];
|
||||
}
|
||||
if(font.IsUnderline() || font.IsStrikeout()) {
|
||||
x += offset.cx;
|
||||
y += offset.cy;
|
||||
if(font.IsUnderline())
|
||||
DrawLine(
|
||||
int(x + underline_position * sina),
|
||||
int(y + underline_position * cosa),
|
||||
int(x + xpos * cosa + underline_position * sina),
|
||||
int(y - xpos * sina + underline_position * cosa),
|
||||
underline_thickness,
|
||||
ink
|
||||
);
|
||||
if(font.IsStrikeout()) {
|
||||
int p = 2 * ascent / 3;
|
||||
DrawLine(
|
||||
int(x + p * sina),
|
||||
int(y + p * cosa),
|
||||
int(x + xpos * cosa + p * sina),
|
||||
int(y - xpos * sina + p * cosa),
|
||||
underline_thickness,
|
||||
ink
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(dx) {
|
||||
int xpos = ox;
|
||||
Buffer<XftCharSpec> ch(n);
|
||||
for(int i = 0; i < n; i++) {
|
||||
ch[i].ucs4 = text[i];
|
||||
ch[i].x = xpos;
|
||||
ch[i].y = oy + ascent;
|
||||
xpos += dx[i];
|
||||
}
|
||||
XftDrawCharSpec(xftdraw, &c, xftfont, ch, n);
|
||||
}
|
||||
else
|
||||
XftDrawString16(xftdraw, &c, xftfont, ox, oy + ascent,
|
||||
(FcChar16 *)text, n);
|
||||
LLOG("XftColor: r=" << c.color.red << ", g=" << c.color.green << ", b=" << c.color.blue
|
||||
<< ", alpha=" << c.color.alpha << ", pixel=" << FormatIntHex(c.pixel));
|
||||
if(font.IsUnderline() || font.IsStrikeout()) {
|
||||
int cx;
|
||||
if(dx && n > 0) {
|
||||
cx = 0;
|
||||
Sum(cx, dx, dx + n - 1);
|
||||
cx += lastFont[text[n - 1]];
|
||||
}
|
||||
else
|
||||
cx = GetTextSize(text, font, n).cx;
|
||||
if(font.IsUnderline())
|
||||
DrawRect(x, y + lastFont.GetAscent() + lastFont.ptr->underline_position,
|
||||
cx, lastFont.ptr->underline_thickness, ink);
|
||||
if(font.IsStrikeout())
|
||||
DrawRect(x, y + 2 * lastFont.GetAscent() / 3,
|
||||
cx, lastFont.ptr->underline_thickness, ink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
END_UPP_NAMESPACE
|
||||
|
|
@ -1,306 +1,306 @@
|
|||
#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 % flags % height % 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
|
||||
|
||||
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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue