Developing new draw

git-svn-id: svn://ultimatepp.org/upp/trunk@1366 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-07-06 11:45:13 +00:00
parent 39bcf6be6e
commit 97446746c8
11 changed files with 2064 additions and 2127 deletions

File diff suppressed because it is too large Load diff

View file

@ -33,7 +33,7 @@ file
Font.cpp,
FontCR.cpp,
FontWin32.cpp,
FontX11.cpp,
FontFc.cpp,
Draw.cpp,
DrawText.cpp,
DrawData.cpp,

View file

@ -1,194 +1,195 @@
#include "Draw.h"
NAMESPACE_UPP
#define LLOG(x) // LOG(x)
#define LTIMING(x) // TIMING(x)
WString TextUnicode(const char *s, int n, byte cs, Font font)
{
if(n < 0)
n = (int)strlen(s);
if(font.GetFace() == Font::SYMBOL) {
WStringBuffer b(n);
wchar *t = b;
while(n > 0) {
*t++ = *s++;
n--;
}
return b;
}
else
return ToUnicode(s, n, cs);
}
void Draw::DrawText(int x, int y, int angle, const wchar *text, Font font,
Color ink, int n, const int *dx)
{
if(IsNull(ink)) return;
if(n < 0)
n = wstrlen(text);
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()) {
Font fnt = font;
fnt.Face(gi.lspc);
fnt.Height(gi.rspc);
if(angle)
DrawTextOp(int(x + cosa * d), int(y - sina * (font.GetAscent() - fnt.GetAscent() + d)),
angle, &chr, fnt, ink, 1, NULL);
else
DrawTextOp(x + d, y + font.GetAscent() - fnt.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;
}
}
// ----------------------------
void Draw::DrawText(int x, int y, const wchar *text, Font font,
Color ink, int n, const int *dx)
{
DrawText(x, y, 0, text, font, ink, n, dx);
}
// ---------------------------
void Draw::DrawText(int x, int y, int angle, const WString& text, Font font,
Color ink, const int *dx)
{
DrawText(x, y, angle, ~text, font, ink, text.GetLength(), dx);
}
void Draw::DrawText(int x, int y, const WString& text, Font font, Color ink, const int *dx)
{
DrawText(x, y, 0, text, font, ink, dx);
}
// ---------------------------
void Draw::DrawText(int x, int y, int angle, const char *text, byte charset, Font font,
Color ink, int n, const int *dx)
{
DrawText(x, y, angle, TextUnicode(text, n, charset, font), font, ink, dx);
}
void Draw::DrawText(int x, int y, const char *text, byte charset, Font font,
Color ink, int n, const int *dx)
{
DrawText(x, y, 0, text, charset, font, ink, n, dx);
}
// ---------------------------
void Draw::DrawText(int x, int y, int angle, const char *text,
Font font, Color ink, int n, const int *dx)
{
DrawText(x, y, angle, text, CHARSET_DEFAULT, font, ink, n, dx);
}
void Draw::DrawText(int x, int y, const char *text, Font font,
Color ink, int n, const int *dx)
{
DrawText(x, y, text, CHARSET_DEFAULT, font, ink, n, dx);
}
// ---------------------------
void Draw::DrawText(int x, int y, int angle, const String& text, Font font,
Color ink, const int *dx)
{
DrawText(x, y, angle, text, font, ink, text.GetLength(), dx);
}
void Draw::DrawText(int x, int y, const String& text, Font font, Color ink, const int *dx)
{
WString h = TextUnicode(text, text.GetLength(), CHARSET_DEFAULT, font);
DrawText(x, y, h, font, ink, h.GetLength(), dx);
}
// --------------------------
Size GetTextSize(const wchar *text, Font font, int n)
{
FontInfo fi = font.Info();
if(n < 0)
n = wstrlen(text);
Size sz;
sz.cx = 0;
const wchar *wtext = (const wchar *)text;
while(n > 0) {
sz.cx += fi[*wtext++];
n--;
}
sz.cy = fi.GetHeight();
return sz;
}
Size GetTextSize(const WString& text, Font font)
{
return GetTextSize(text, font, text.GetLength());
}
Size GetTextSize(const char *text, byte charset, Font font, int n)
{
return GetTextSize(TextUnicode(text, n, charset, font), font);
}
Size GetTextSize(const char *text, Font font, int n)
{
return GetTextSize(text, CHARSET_DEFAULT, font, n);
}
Size GetTextSize(const String& text, Font font)
{
return GetTextSize(text, font, text.GetLength());
}
END_UPP_NAMESPACE
#include "Draw.h"
NAMESPACE_UPP
#define LLOG(x) // LOG(x)
#define LTIMING(x) // TIMING(x)
WString TextUnicode(const char *s, int n, byte cs, Font font)
{
if(n < 0)
n = (int)strlen(s);
#ifdef PLATFORM_WIN32
if(font.GetFace() == Font::SYMBOL) {
WStringBuffer b(n);
wchar *t = b;
while(n > 0) {
*t++ = *s++;
n--;
}
return b;
}
#endif
return ToUnicode(s, n, cs);
}
void Draw::DrawText(int x, int y, int angle, const wchar *text, Font font,
Color ink, int n, const int *dx)
{
if(IsNull(ink)) return;
if(n < 0)
n = wstrlen(text);
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()) {
Font fnt = font;
fnt.Face(gi.lspc);
fnt.Height(gi.rspc);
if(angle)
DrawTextOp(int(x + cosa * d), int(y - sina * (font.GetAscent() - fnt.GetAscent() + d)),
angle, &chr, fnt, ink, 1, NULL);
else
DrawTextOp(x + d, y + font.GetAscent() - fnt.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;
}
}
// ----------------------------
void Draw::DrawText(int x, int y, const wchar *text, Font font,
Color ink, int n, const int *dx)
{
DrawText(x, y, 0, text, font, ink, n, dx);
}
// ---------------------------
void Draw::DrawText(int x, int y, int angle, const WString& text, Font font,
Color ink, const int *dx)
{
DrawText(x, y, angle, ~text, font, ink, text.GetLength(), dx);
}
void Draw::DrawText(int x, int y, const WString& text, Font font, Color ink, const int *dx)
{
DrawText(x, y, 0, text, font, ink, dx);
}
// ---------------------------
void Draw::DrawText(int x, int y, int angle, const char *text, byte charset, Font font,
Color ink, int n, const int *dx)
{
DrawText(x, y, angle, TextUnicode(text, n, charset, font), font, ink, dx);
}
void Draw::DrawText(int x, int y, const char *text, byte charset, Font font,
Color ink, int n, const int *dx)
{
DrawText(x, y, 0, text, charset, font, ink, n, dx);
}
// ---------------------------
void Draw::DrawText(int x, int y, int angle, const char *text,
Font font, Color ink, int n, const int *dx)
{
DrawText(x, y, angle, text, CHARSET_DEFAULT, font, ink, n, dx);
}
void Draw::DrawText(int x, int y, const char *text, Font font,
Color ink, int n, const int *dx)
{
DrawText(x, y, text, CHARSET_DEFAULT, font, ink, n, dx);
}
// ---------------------------
void Draw::DrawText(int x, int y, int angle, const String& text, Font font,
Color ink, const int *dx)
{
DrawText(x, y, angle, text, font, ink, text.GetLength(), dx);
}
void Draw::DrawText(int x, int y, const String& text, Font font, Color ink, const int *dx)
{
WString h = TextUnicode(text, text.GetLength(), CHARSET_DEFAULT, font);
DrawText(x, y, h, font, ink, h.GetLength(), dx);
}
// --------------------------
Size GetTextSize(const wchar *text, Font font, int n)
{
FontInfo fi = font.Info();
if(n < 0)
n = wstrlen(text);
Size sz;
sz.cx = 0;
const wchar *wtext = (const wchar *)text;
while(n > 0) {
sz.cx += fi[*wtext++];
n--;
}
sz.cy = fi.GetHeight();
return sz;
}
Size GetTextSize(const WString& text, Font font)
{
return GetTextSize(text, font, text.GetLength());
}
Size GetTextSize(const char *text, byte charset, Font font, int n)
{
return GetTextSize(TextUnicode(text, n, charset, font), font);
}
Size GetTextSize(const char *text, Font font, int n)
{
return GetTextSize(text, CHARSET_DEFAULT, font, n);
}
Size GetTextSize(const String& text, Font font)
{
return GetTextSize(text, font, text.GetLength());
}
END_UPP_NAMESPACE

View file

@ -7,20 +7,10 @@ NAMESPACE_UPP
#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());
}
int gtk_antialias = -1;
int gtk_hinting = -1;
String gtk_hintstyle;
String gtk_rgba;
XftFont *CreateXftFont(Font font, int angle)
{
@ -124,8 +114,6 @@ void SystemDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font fon
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;
@ -207,11 +195,9 @@ void SystemDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font fon
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);
DrawRect(x, y + ascent + underline_position, cx, underline_thickness, ink);
if(font.IsStrikeout())
DrawRect(x, y + 2 * lastFont.GetAscent() / 3,
cx, lastFont.ptr->underline_thickness, ink);
DrawRect(x, y + 2 * ascent / 3, cx, underline_thickness, ink);
}
}
}

View file

@ -43,15 +43,9 @@ bool Xpalette;
dword (*Xgetpixel)(int r, int g, int b);
void StaticExitDraw_()
{
FontInfo::FreeFonts();
}
EXITBLOCK
{
if(Xdisplay) {
StaticExitDraw_();
// No CloseDisplay for now...
XCloseDisplay(Xdisplay);
LLOG("Xdisplay closed");
@ -223,7 +217,7 @@ void InitX11Draw(XDisplay *display)
}
// XFree(v);
FontInfo::SetStdFont(ScreenSans(12));
Font::SetStdFont(ScreenSans(12));
}
void InitX11Draw(const char *dispname)
@ -299,14 +293,6 @@ void SystemDraw::SetClip() {
UPP::SetClip(gc, xftdraw, clip.Top());
}
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::AcquireFontInfo(font, angle);
}
void SystemDraw::SetLineStyle(int width)
{
DrawLock __;
@ -340,7 +326,6 @@ void SystemDraw::Init()
{
DrawLock __;
pageSize = Size(Xwidth, Xheight);
FontInfo::InitFonts();
cloff.Clear();
clip.Clear();
foreground = linewidth = Null;

View file

@ -1,5 +1,7 @@
#ifdef PLATFORM_X11
void SetClip(GC gc, XftDraw *xftdraw, const Vector<Rect>& cl);
class SystemDraw : public Draw {
public:
virtual dword GetInfo() const;
@ -93,7 +95,6 @@ public:
void SetForeground(Color color);
void SetLineStyle(int width);
void SetFont(Font font, int angle);
void SetClip();
Drawable GetDrawable() const { return dw; }

View file

@ -1,326 +1,341 @@
#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().GetCy());
}
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();
e.info.rspc = rfnt.GetHeight();
}
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).Height(f.rspc), 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
#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();
GetStdFont();
}
INITBLOCK {
sInitFonts();
}
int Font::GetFaceCount()
{
return List().GetCount();
}
String Font::GetFaceName(int index)
{
if(index == 0)
return "STDFONT";
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().GetCy());
}
void Font::SetStdFont(Font font)
{
DrawLock __;
InitStdFont();
AStdFont = font;
SyncStdFont();
DLOG("SetStdFont " << font);
}
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, 0);
}
int Font::GetHeight() const
{
return v.height ? v.height : 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();
e.info.rspc = rfnt.GetHeight();
}
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).Height(f.rspc), 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;
thread__ int64 lastStdFont = INT_MIN;
const CommonFontInfo& Font::Fi() const
{
if(lastStdFont != AStdFont.AsInt64()) {
lastFiFont = INT_MIN;
lastStdFont = AStdFont.AsInt64();
}
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

225
newdraw/Draw/FontFc.cpp Normal file
View file

@ -0,0 +1,225 @@
#include "Draw.h"
NAMESPACE_UPP
#ifdef PLATFORM_POSIX
#define LLOG(x) // LOG(x)
#define LTIMING(x) // TIMING(x)
void GetStdFontSys(String& name, int& height)
{
name = "xxxx";
}
static FT_Library sFTlib;
bool sInitFt(void)
{
if(sFTlib)
return true;
return FT_Init_FreeType(&sFTlib) == 0;
}
FcPattern *CreateFcPattern(Font font, int angle)
{
LTIMING("CreateXftFont");
double sina, cosa;
int hg = abs(font.GetHeight());
if(hg == 0) hg = 10;
String n = font.GetFaceName();
const char *face = n;
FcPattern *p = FcPatternCreate();
FcPatternAddString(p, FC_FAMILY, (FcChar8*)face);
FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0);
FcPatternAddInteger(p, FC_PIXEL_SIZE, hg);
FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100);
FcPatternAddBool(p, FC_MINSPACE, 1);
if(angle) {
FcMatrix mx;
Draw::SinCos(angle, sina, cosa);
mx.xx = cosa;
mx.xy = -sina;
mx.yx = sina;
mx.yy = cosa;
FcPatternAddMatrix(p, FC_MATRIX, &mx);
}
FcResult result;
FcPattern *m = XftFontMatch(Xdisplay, Xscreenno, p, &result);
FcPatternDestroy(p);
return m;
}
FT_Face CreateFTFace(const FcPattern *pattern, String *rpath) {
FT_Face face = NULL;
int id;
double dsize;
double aspect;
FcChar8 *filename;
if(!sInitFt())
return NULL;
if(FcPatternGetString(pattern, FC_FILE, 0, &filename) != FcResultMatch)
return NULL;
if(rpath)
*rpath = (const char *)filename;
if(FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &dsize) != FcResultMatch)
dsize = 16;
if (FcPatternGetDouble(pattern, FC_ASPECT, 0, &aspect) != FcResultMatch)
aspect = 1.0;
FT_F26Dot6 ysize = (FT_F26Dot6) (dsize * 64.0);
FT_F26Dot6 xsize = (FT_F26Dot6) (dsize * aspect * 64.0);
if(FT_New_Face (sFTlib, (const char *)filename, 0, &face))
return NULL;
FT_Set_Char_Size(face, xsize, ysize, 0, 0);
return face;
}
#define FONTCACHE 37
struct FtFaceEntry {
Font font;
FT_Face face;
String path;
};
FT_Face FTFace(Font fnt, String *rpath = NULL)
{
RTIMING("FTFace");
static FtFaceEntry cache[FONTCACHE];
ONCELOCK {
for(int i = 0; i < FONTCACHE; i++)
cache[i].font.Height(-30000);
}
FtFaceEntry be;
be = cache[0];
for(int i = 0; i < FONTCACHE; i++) {
FtFaceEntry e = cache[i];
if(i)
cache[i] = be;
if(e.font == fnt) {
if(rpath)
*rpath = e.path;
if(i)
cache[0] = e;
return e.face;
}
be = e;
}
RTIMING("FTFace2");
if(be.face) {
LOG("Removing " << be.font << " - " << (void *)be.face);
FT_Done_Face(be.face);
}
be.font = fnt;
FcPattern *p = CreateFcPattern(fnt, 0);
be.face = CreateFTFace(p, &be.path);
FcPatternDestroy(p);
cache[0] = be;
if(rpath)
*rpath = be.path;
return be.face;
}
CommonFontInfo GetFontInfoSys(Font font)
{
CommonFontInfo fi;
FT_Face face = FTFace(font, &fi.path);
if(face) {
fi.ascent = face->size->metrics.ascender >> 6;
fi.descent = -(face->size->metrics.descender >> 6);
fi.height = fi.ascent + fi.descent;
fi.lineheight = face->size->metrics.height >> 6;
fi.external = 0;
fi.internal = 0;
fi.overhang = 0;
fi.maxwidth = face->size->metrics.max_advance >> 6;
fi.avewidth = fi.maxwidth;
fi.default_char = '?';
fi.fixedpitch = font.GetFaceInfo() & Font::FIXEDPITCH;
}
return fi;
}
#define FLOOR(x) ((x) & -64)
#define CEIL(x) (((x)+63) & -64)
#define TRUNC(x) ((x) >> 6)
#define ROUND(x) (((x)+32) & -64)
GlyphInfo GetGlyphInfoSys(Font font, int chr)
{
RTIMING("GetGlyphInfoSys");
GlyphInfo gi;
FT_Face face = FTFace(font, NULL);
gi.lspc = gi.rspc = 0;
gi.width = 0x8000;
if(face) {
RTIMING("GetGlyphInfoSys 2");
int glyph_index = FT_Get_Char_Index(face, chr);
if(glyph_index &&
(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT|FT_LOAD_NO_BITMAP) == 0 ||
FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0)) {
FT_Glyph_Metrics& m = face->glyph->metrics;
int left = FLOOR(m.horiBearingX);
int width = TRUNC(CEIL(m.horiBearingX + m.width) - left);
gi.width = TRUNC(ROUND(face->glyph->advance.x));
gi.lspc = TRUNC(left);
gi.rspc = gi.width - width - gi.lspc;
}
}
return gi;
}
Vector<FaceInfo> GetAllFacesSys()
{
static const char *basic_fonts[] = {
"sans-serif",
"serif",
"sans-serif",
"monospace",
"serif",
"sans-serif",
"monospace",
};
Vector<FaceInfo> list;
for(int i = 0; i < __countof(basic_fonts); i++) {
FaceInfo& fi = list.Add();
fi.name = basic_fonts[i];
fi.info = (i == 3 || i == 6) ? Font::SCALEABLE|Font::FIXEDPITCH : Font::SCALEABLE;
}
FcPattern *p = FcPatternCreate();
FcObjectSet *os = FcObjectSetBuild(XFT_FAMILY, XFT_SPACING, XFT_SCALABLE, (void *)0);
FcFontSet *fs = FcFontList(NULL, p, os);
FcPatternDestroy(p);
FcObjectSetDestroy(os);
for(int i = 0; i < fs->nfont; i++) {
FcChar8 *family = NULL;
if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == 0 && family) {
FaceInfo& fi = list.Add();
fi.name = (const char *)family;
fi.info = 0;
int iv;
if(FcPatternGetInteger(fs->fonts[i], FC_SPACING, 0, &iv) == 0 && iv == FC_MONO)
fi.info |= Font::FIXEDPITCH;
FcBool bv;
if(FcPatternGetBool(fs->fonts[i], FC_SCALABLE, 0, &bv) == 0 && bv)
fi.info |= Font::SCALEABLE;
}
}
FcFontSetDestroy(fs);
return list;
}
#endif
END_UPP_NAMESPACE

View file

@ -1,294 +0,0 @@
#include "Draw.h"
NAMESPACE_UPP
#ifdef PLATFORM_X11
#define LLOG(x) // LOG(x)
#define LTIMING(x) // TIMING(x)
struct XFTFontFaceInfo {
String name;
bool fixed:1;
bool scaleable:1;
bool compose:1;
XFTFontFaceInfo()
{
fixed = scaleable = false;
}
};
ArrayMap<String, XFTFontFaceInfo>& XFTFontFace()
{
static ArrayMap<String, XFTFontFaceInfo> x;
return x;
}
FontInfo::Data::Data()
{
refcount = 1;
for(int i = 0; i < 64; i++)
base[i] = NULL;
xftfont = NULL;
}
FontInfo::Data::~Data()
{
DrawLock __;
if(xftfont0 && xftfont0 != xftfont)
XftFontClose(Xdisplay, xftfont0);
if(xftfont)
XftFontClose(Xdisplay, xftfont);
for(int i = 0; i < 64; i++)
if(base[i]) delete[] base[i];
}
void FontInfo::Data::GetMetrics(CharMetrics *t, int from, int count)
{
DrawLock __;
LTIMING("GetMetrics");
LLOG("GetMetrics " << font << " " << from << ", " << count);
if(xftfont) {
for(int i = 0; i < count; i++) {
LTIMING("XftTextExtents16");
wchar h = from + i;
XGlyphInfo info;
XftTextExtents16(Xdisplay, xftfont0, &h, 1, &info);
t[i].width = info.xOff;
t[i].lspc = -info.x;
t[i].rspc = info.xOff - info.width + info.x;
}
}
}
const char *basic_fonts[] = {
"sans-serif",
"serif",
"sans-serif",
"monospace",
"serif",
"sans-serif",
"monospace",
};
static int sCheckComposed(const char *face)
{
XftFont *xftfont = XftFontOpen(Xdisplay, Xscreenno,
XFT_FAMILY, XftTypeString, (char *)face,
XFT_PIXEL_SIZE, XftTypeInteger, 20,
(void *)0);
if(xftfont == NULL )
return -1;
int n = 0;
for(int c = 0; c < 128; c++)
if(!XftCharExists(Xdisplay, xftfont, c + 256))
n++;
XftFontClose(Xdisplay, xftfont);
return n > 10;
}
bool FontInfo::Data::HasChar(int ch) const
{
return XftCharExists(Xdisplay, xftfont, ch);
}
void FontInfo::InitPlatformFonts()
{
for(int i = 0; i < __countof(basic_fonts); i++) {
XFTFontFaceInfo& f = XFTFontFace().Add(basic_fonts[i]);
f.name = basic_fonts[i];
f.scaleable = true;
f.fixed = i == 3 || i == 6;
f.compose = sCheckComposed(basic_fonts[i]);
}
FcFontSet *fs = XftListFonts(Xdisplay, Xscreenno, (void *)0, XFT_FAMILY, XFT_SPACING,
XFT_SCALABLE, (void *)0);
for(int i = 0; i < fs->nfont; i++) {
FcChar8 *family = NULL;
if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) == 0 && family) {
int comp = sCheckComposed((char *)family);
if(comp >= 0) {
XFTFontFaceInfo& f = XFTFontFace().GetAdd((char *)family);
int spacing;
if(FcPatternGetInteger(fs->fonts[i], FC_SPACING, 0, &spacing) == 0 && spacing == XFT_MONO)
f.fixed = true;
FcBool scaleable;
if(FcPatternGetBool(fs->fonts[i], FC_SCALABLE, 0, &scaleable) == 0 && scaleable)
f.scaleable = true;
f.compose = comp;
}
}
}
FcFontSetDestroy(fs);
}
int Font::GetFaceCount()
{
ONCELOCK {
FontInfo::InitFonts();
}
return XFTFontFace().GetCount();
}
String Font::GetFaceName(int index)
{
ONCELOCK {
FontInfo::InitFonts();
}
return index >= 0 && index < XFTFontFace().GetCount() ? XFTFontFace().GetKey(index)
: Null;
}
dword Font::GetFaceInfo(int index) {
ONCELOCK {
FontInfo::InitFonts();
}
dword w = 0;
if(index >= 0 && index < XFTFontFace().GetCount()) {
XFTFontFaceInfo& fi = XFTFontFace()[index];
if(fi.fixed)
w |= FIXEDPITCH;
if(fi.scaleable)
w |= SCALEABLE;
if(fi.compose)
w |= COMPOSED;
}
return w;
}
int gtk_antialias = -1;
int gtk_hinting = -1;
String gtk_hintstyle;
String gtk_rgba;
XftFont *FontInfo::CreateXftFont(Font font, int angle)
{
LTIMING("CreateXftFont");
XftFont *xftfont;
double sina, cosa;
int hg = abs(font.GetHeight());
if(hg == 0) hg = 10;
int i = font.GetFace();
if(i < 0 || i >= XFTFontFace().GetCount())
i = 0;
const char *face = i < 7 ? basic_fonts[i] : ~XFTFontFace().GetKey(i);
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;
}
FontInfo FontInfo::AcquireFontInfo(Font font, int angle)
{
DrawLock __;
LTIMING("Acquire");
if(IsNull(font))
font = StdFont();
if(font.GetFace() == 0)
font.Face(AStdFont.GetFace());
if(font.GetHeight() == 0)
font.Height(AStdFont.GetHeight());
FontInfo::Data *f, *fh;
f = fh = GetFontHash((font.GetHashValue() ^ angle) % (int)FONTHASH);
LLOG("Acquire " << font << " device: " << device);
for(;;) {
f = f->GetNext(HASH);
if(f == fh) break;
if(f->font == font && f->angle == angle)
{
LLOG("Reusing " << f->font);
if(f->InList(LRU)) {
f->Unlink(LRU);
FontCached--;
LLOG("Removing from cache " << f->font << " cached:" << FontCached);
}
f->refcount++;
return f;
}
}
LLOG("New " << font);
LTIMING("Acquire New");
f = fh->InsertNext(HASH);
f->font = font;
f->angle = angle;
int hg = abs(font.GetHeight());
if(hg == 0) hg = 10;
f->xftfont0 = f->xftfont = CreateXftFont(font, angle);
if(angle)
f->xftfont0 = CreateXftFont(font, 0);
f->filename = NULL;
f->ascent = (int16)f->xftfont0->ascent;
f->descent = (int16)f->xftfont0->descent;
f->height = f->ascent + f->descent;
f->lineheight = (int16)f->xftfont0->height;
f->external = 0;
f->internal = 0;
f->overhang = 0;
f->maxwidth = (int16)f->xftfont0->max_advance_width;
f->avewidth = f->maxwidth;
f->default_char = '?';
f->fixedpitch = font.GetFaceInfo() & Font::FIXEDPITCH;
f->underline_thickness = max(hg / 20, 1);
f->underline_position = max(hg / 15, int(f->descent > 0));
if(angle) {
Draw::SinCos(angle, f->sina, f->cosa);
f->offset.cx = fround(f->ascent * f->sina);
f->offset.cy = fround(f->ascent * f->cosa);
}
FontInfo fi = FontInfo(f);
fi.GetPage(0);
return fi;
}
String FontInfo::GetFileName() const
{
if(IsNull(ptr->filename)) {
char *fn = NULL;
XftPatternGetString(ptr->xftfont->pattern, XFT_FILE, 0, &fn);
if(fn)
ptr->filename = fn;
}
return ptr->filename;
}
#endif
END_UPP_NAMESPACE

View file

@ -1,342 +1,334 @@
#define NEWIMAGE
enum ImageKind {
IMAGE_UNKNOWN,
IMAGE_EMPTY,
IMAGE_ALPHA,
IMAGE_MASK,
IMAGE_OPAQUE,
};
inline bool operator==(const RGBA& a, const RGBA& b)
{
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}
inline bool operator!=(const RGBA& a, const RGBA& b)
{
return !(a == b);
}
inline RGBA RGBAZero() { RGBA c; c.r = c.g = c.b = c.a = 0; return c; }
void Fill(RGBA *t, const RGBA& src, int n);
void FillColor(RGBA *t, const RGBA& src, int n);
void Copy(RGBA *t, const RGBA *s, int n);
int Premultiply(RGBA *t, const RGBA *s, int len);
int Unmultiply(RGBA *t, const RGBA *s, int len);
void AlphaBlend(RGBA *t, const RGBA *s, int len);
void AlphaBlend(RGBA *t, const RGBA *s, int len, Color color);
void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len, Color color);
void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len);
void AlphaBlendStraight(RGBA *b, const RGBA *f, int len);
void AlphaBlendStraight(RGBA *b, const RGBA *f, int len, Color color);
void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len);
void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len, int alpha);
int GetChMaskPos32(dword mask);
void AlphaBlendOverBgST(RGBA *b, RGBA bg, int len);
const byte *UnpackRLE(RGBA *t, const byte *src, int len);
String PackRLE(const RGBA *s, int len);
inline int Grayscale(int r, int g, int b) { return (77 * r + 151 * g + 28 * b) >> 8; }
inline int Grayscale(const RGBA& c) { return Grayscale(c.r, c.g, c.b); }
inline byte Saturate255(int x) { return byte(~(x >> 24) & (x | (-(x >> 8) >> 24)) & 0xff); }
class Image;
class ImageDraw;
class ImageBuffer : NoCopy {
mutable int kind;
Size size;
Buffer<RGBA> pixels;
Point hotspot;
Point spot2;
Size dots;
void Set(Image& img);
void DeepCopy(const ImageBuffer& img);
RGBA* Line(int i) const { ASSERT(i >= 0 && i < size.cy); return (RGBA *)~pixels + i * size.cx; }
friend void DropPixels___(ImageBuffer& b) { b.pixels.Clear(); }
friend class Image;
public:
void SetKind(int k) { kind = k; }
int GetKind() const { return kind; }
int ScanKind() const;
int GetScanKind() const { return kind == IMAGE_UNKNOWN ? ScanKind() : kind; }
void SetHotSpot(Point p) { hotspot = p; }
Point GetHotSpot() const { return hotspot; }
void Set2ndSpot(Point p) { spot2 = p; }
Point Get2ndSpot() const { return spot2; }
void SetDots(Size sz) { dots = sz; }
Size GetDots() const { return dots; }
Size GetSize() const { return size; }
int GetWidth() const { return size.cx; }
int GetHeight() const { return size.cy; }
int GetLength() const { return size.cx * size.cy; }
RGBA *operator[](int i) { return Line(i); }
const RGBA *operator[](int i) const { return Line(i); }
RGBA *operator~() { return pixels; }
operator RGBA*() { return pixels; }
const RGBA *operator~() const { return pixels; }
operator const RGBA*() const { return pixels; }
void Create(int cx, int cy);
void Create(Size sz) { Create(sz.cx, sz.cy); }
bool IsEmpty() const { return (size.cx | size.cy) == 0; }
void Clear() { Create(0, 0); }
void operator=(Image& img);
void operator=(ImageBuffer& img);
ImageBuffer() { Create(0, 0); }
ImageBuffer(int cx, int cy) { Create(cx, cy); }
ImageBuffer(Size sz) { Create(sz.cx, sz.cy); }
ImageBuffer(Image& img);
ImageBuffer(ImageDraw& w);
ImageBuffer(ImageBuffer& b);
};
void Premultiply(ImageBuffer& b);
void Unmultiply(ImageBuffer& b);
void SetSurface(Draw& w, int x, int y, int cx, int cy, const RGBA *pixels);
class Image : public AssignValueTypeNo< Image, 150, Moveable<Image> > {
private:
struct Data : Link<Data> {
Atomic refcount;
int64 serial;
int paintcount;
static Link<Data> ResData[1];
static int ResCount;
void Retain() { AtomicInc(refcount); }
void Release() { if(AtomicDec(refcount) == 0) delete this; }
struct SystemData;
void *system_buffer[6];
SystemData& Sys() const;
#ifdef PLATFORM_WIN32
void CreateHBMP(HDC dc, const RGBA *data);
int GetResCount() const;
#endif
#ifdef PLATFORM_X11
int cursor_cheat;
XPicture picture;
XPicture picture8;
int GetResCount() const { return !!picture; }
#endif
ImageBuffer buffer;
bool paintonly;
void SysInit();
void SysRelease();
int GetKind();
void Paint(SystemDraw& w, int x, int y, const Rect& src, Color c);
void PaintOnlyShrink();
Data(ImageBuffer& b);
~Data();
};
Data *data;
static Link<Image::Data> ResData[1];
static int ResCount;
void Set(ImageBuffer& b);
friend class ImageBuffer;
friend struct Data;
friend class SystemDraw;
void PaintImage(SystemDraw& w, int x, int y, const Rect& src, Color c) const;
friend void SetPaintOnly___(Image& m);
friend void DrawImageBandRLE(Draw& w, int x, int y, const Image& m, int minp);
#ifdef PLATFORM_WIN32
#ifndef PLATFORM_WINCE
void SetCursorCheat(LPCSTR id);
LPCSTR GetCursorCheat() const;
friend Image Win32IconCursor(LPCSTR id, int iconsize, bool cursor);
friend HICON IconWin32(const Image& img, bool cursor);
#endif
#endif
#ifdef PLATFORM_X11
void SetCursorCheat(int id) { data->cursor_cheat = id; }
int GetCursorCheat() const { return data ? data->cursor_cheat : -1; }
friend Cursor X11Cursor(const Image&);
friend Image sX11Cursor__(int c);
#endif
public:
const RGBA* operator~() const;
operator const RGBA*() const;
const RGBA* operator[](int i) const;
Size GetSize() const;
int GetWidth() const { return GetSize().cx; }
int GetHeight() const { return GetSize().cy; }
int GetLength() const;
Point GetHotSpot() const;
Point Get2ndSpot() const;
Size GetDots() const;
int GetKindNoScan() const;
int GetKind() const;
int64 GetSerialId() const { return data ? data->serial : 0; }
bool IsSame(const Image& img) const { return GetSerialId() == img.GetSerialId(); }
bool operator==(const Image& img) const;
bool operator!=(const Image& img) const;
dword GetHashValue() const;
String ToString() const;
void Serialize(Stream& s);
void Clear();
Image& operator=(const Image& img);
Image& operator=(ImageBuffer& img);
bool IsNullInstance() const { Size sz = GetSize(); return (sz.cx|sz.cy) == 0; }
bool IsEmpty() const { return IsNullInstance(); }
operator Value() const { return RichValue<Image>(*this); }
Image() { data = NULL; }
Image(const Nuller&) { data = NULL; }
Image(const Value& src);
Image(const Image& img);
Image(Image (*fn)());
Image(ImageBuffer& b);
~Image();
static Image Arrow();
static Image Wait();
static Image IBeam();
static Image No();
static Image SizeAll();
static Image SizeHorz();
static Image SizeVert();
static Image SizeTopLeft();
static Image SizeTop();
static Image SizeTopRight();
static Image SizeLeft();
static Image SizeRight();
static Image SizeBottomLeft();
static Image SizeBottom();
static Image SizeBottomRight();
static Image Cross();
static Image Hand();
// IML support ("private"), deprecated - legacy .iml
struct Init {
const char *const *scans;
int16 scan_count;
char info[24];
};
explicit Image(const Init& init);
};
Image Premultiply(const Image& img);
Image Unmultiply(const Image& img);
Vector<Image> UnpackImlData(const void *ptr, int len);
Vector<Image> UnpackImlData(const String& d);
class Iml {
struct IImage : Moveable<IImage> {
bool loaded;
Image image;
IImage() { loaded = false; }
};
struct Data : Moveable<Data> {
const char *data;
int len, count;
};
Vector<Data> data;
VectorMap<String, IImage> map;
const Image::Init *img_init;
const char **name;
bool premultiply;
void Init(int n);
public:
void Enter();
void Leave();
void Reset();
int GetCount() const { return map.GetCount(); }
String GetId(int i) { return map.GetKey(i); }
Image Get(int i);
int Find(const String& s) const { return map.Find(s); }
void Set(int i, const Image& img);
void Premultiplied() { premultiply = false; }
#ifdef _DEBUG
int GetBinSize() const;
#endif
Iml(const Image::Init *img_init, const char **name, int n);//Deprecated - legacy .iml
void AddData(const byte *data, int len, int count);
};
void Register(const char *imageclass, Iml& iml);
int GetImlCount();
String GetImlName(int i);
Iml& GetIml(int i);
int FindIml(const char *name);
Image GetImlImage(const char *name);
void SetImlImage(const char *name, const Image& m);
String StoreImageAsString(const Image& img);
Image LoadImageFromString(const String& s);
Size GetImageStringSize(const String& src);
Size GetImageStringDots(const String& src);
#include "Raster.h"
#include "ImageOp.h"
#ifdef PLATFORM_WIN32
#ifndef PLATFORM_WINCE
Image Win32Icon(LPCSTR id, int iconsize = 0);
Image Win32Icon(int id, int iconsize = 0);
Image Win32Cursor(LPCSTR id);
Image Win32Cursor(int id);
HICON IconWin32(const Image& img, bool cursor = false);
Image Win32DllIcon(const char *dll, int ii, bool large);
#endif
#endif
#ifdef PLATFORM_X11
Cursor X11Cursor(const Image& img);
#endif
#define NEWIMAGE
enum ImageKind {
IMAGE_UNKNOWN,
IMAGE_EMPTY,
IMAGE_ALPHA,
IMAGE_MASK,
IMAGE_OPAQUE,
};
inline bool operator==(const RGBA& a, const RGBA& b)
{
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}
inline bool operator!=(const RGBA& a, const RGBA& b)
{
return !(a == b);
}
inline RGBA RGBAZero() { RGBA c; c.r = c.g = c.b = c.a = 0; return c; }
void Fill(RGBA *t, const RGBA& src, int n);
void FillColor(RGBA *t, const RGBA& src, int n);
void Copy(RGBA *t, const RGBA *s, int n);
int Premultiply(RGBA *t, const RGBA *s, int len);
int Unmultiply(RGBA *t, const RGBA *s, int len);
void AlphaBlend(RGBA *t, const RGBA *s, int len);
void AlphaBlend(RGBA *t, const RGBA *s, int len, Color color);
void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len, Color color);
void AlphaBlendOpaque(RGBA *t, const RGBA *s, int len);
void AlphaBlendStraight(RGBA *b, const RGBA *f, int len);
void AlphaBlendStraight(RGBA *b, const RGBA *f, int len, Color color);
void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len);
void AlphaBlendStraightOpaque(RGBA *t, const RGBA *s, int len, int alpha);
int GetChMaskPos32(dword mask);
void AlphaBlendOverBgST(RGBA *b, RGBA bg, int len);
const byte *UnpackRLE(RGBA *t, const byte *src, int len);
String PackRLE(const RGBA *s, int len);
inline int Grayscale(int r, int g, int b) { return (77 * r + 151 * g + 28 * b) >> 8; }
inline int Grayscale(const RGBA& c) { return Grayscale(c.r, c.g, c.b); }
inline byte Saturate255(int x) { return byte(~(x >> 24) & (x | (-(x >> 8) >> 24)) & 0xff); }
class Image;
class ImageDraw;
class ImageBuffer : NoCopy {
mutable int kind;
Size size;
Buffer<RGBA> pixels;
Point hotspot;
Point spot2;
Size dots;
void Set(Image& img);
void DeepCopy(const ImageBuffer& img);
RGBA* Line(int i) const { ASSERT(i >= 0 && i < size.cy); return (RGBA *)~pixels + i * size.cx; }
friend void DropPixels___(ImageBuffer& b) { b.pixels.Clear(); }
friend class Image;
public:
void SetKind(int k) { kind = k; }
int GetKind() const { return kind; }
int ScanKind() const;
int GetScanKind() const { return kind == IMAGE_UNKNOWN ? ScanKind() : kind; }
void SetHotSpot(Point p) { hotspot = p; }
Point GetHotSpot() const { return hotspot; }
void Set2ndSpot(Point p) { spot2 = p; }
Point Get2ndSpot() const { return spot2; }
void SetDots(Size sz) { dots = sz; }
Size GetDots() const { return dots; }
Size GetSize() const { return size; }
int GetWidth() const { return size.cx; }
int GetHeight() const { return size.cy; }
int GetLength() const { return size.cx * size.cy; }
RGBA *operator[](int i) { return Line(i); }
const RGBA *operator[](int i) const { return Line(i); }
RGBA *operator~() { return pixels; }
operator RGBA*() { return pixels; }
const RGBA *operator~() const { return pixels; }
operator const RGBA*() const { return pixels; }
void Create(int cx, int cy);
void Create(Size sz) { Create(sz.cx, sz.cy); }
bool IsEmpty() const { return (size.cx | size.cy) == 0; }
void Clear() { Create(0, 0); }
void operator=(Image& img);
void operator=(ImageBuffer& img);
ImageBuffer() { Create(0, 0); }
ImageBuffer(int cx, int cy) { Create(cx, cy); }
ImageBuffer(Size sz) { Create(sz.cx, sz.cy); }
ImageBuffer(Image& img);
ImageBuffer(ImageDraw& w);
ImageBuffer(ImageBuffer& b);
};
void Premultiply(ImageBuffer& b);
void Unmultiply(ImageBuffer& b);
void SetSurface(Draw& w, int x, int y, int cx, int cy, const RGBA *pixels);
class Image : public AssignValueTypeNo< Image, 150, Moveable<Image> > {
private:
struct Data : Link<Data> {
Atomic refcount;
int64 serial;
int paintcount;
static Link<Data> ResData[1];
static int ResCount;
void Retain() { AtomicInc(refcount); }
void Release() { if(AtomicDec(refcount) == 0) delete this; }
struct SystemData;
void *system_buffer[6];
SystemData& Sys() const;
int GetResCount() const;
#ifdef PLATFORM_WIN32
void CreateHBMP(HDC dc, const RGBA *data);
#endif
ImageBuffer buffer;
bool paintonly;
void SysInit();
void SysRelease();
int GetKind();
void Paint(SystemDraw& w, int x, int y, const Rect& src, Color c);
void PaintOnlyShrink();
Data(ImageBuffer& b);
~Data();
};
Data *data;
static Link<Image::Data> ResData[1];
static int ResCount;
void Set(ImageBuffer& b);
friend class ImageBuffer;
friend struct Data;
friend class SystemDraw;
void PaintImage(SystemDraw& w, int x, int y, const Rect& src, Color c) const;
friend void SetPaintOnly___(Image& m);
friend void DrawImageBandRLE(Draw& w, int x, int y, const Image& m, int minp);
#ifdef PLATFORM_WIN32
#ifndef PLATFORM_WINCE
void SetCursorCheat(LPCSTR id);
LPCSTR GetCursorCheat() const;
friend Image Win32IconCursor(LPCSTR id, int iconsize, bool cursor);
friend HICON IconWin32(const Image& img, bool cursor);
#endif
#endif
#ifdef PLATFORM_X11
void SetCursorCheat(int id);
int GetCursorCheat() const;
friend Cursor X11Cursor(const Image&);
friend Image sX11Cursor__(int c);
#endif
public:
const RGBA* operator~() const;
operator const RGBA*() const;
const RGBA* operator[](int i) const;
Size GetSize() const;
int GetWidth() const { return GetSize().cx; }
int GetHeight() const { return GetSize().cy; }
int GetLength() const;
Point GetHotSpot() const;
Point Get2ndSpot() const;
Size GetDots() const;
int GetKindNoScan() const;
int GetKind() const;
int64 GetSerialId() const { return data ? data->serial : 0; }
bool IsSame(const Image& img) const { return GetSerialId() == img.GetSerialId(); }
bool operator==(const Image& img) const;
bool operator!=(const Image& img) const;
dword GetHashValue() const;
String ToString() const;
void Serialize(Stream& s);
void Clear();
Image& operator=(const Image& img);
Image& operator=(ImageBuffer& img);
bool IsNullInstance() const { Size sz = GetSize(); return (sz.cx|sz.cy) == 0; }
bool IsEmpty() const { return IsNullInstance(); }
operator Value() const { return RichValue<Image>(*this); }
Image() { data = NULL; }
Image(const Nuller&) { data = NULL; }
Image(const Value& src);
Image(const Image& img);
Image(Image (*fn)());
Image(ImageBuffer& b);
~Image();
static Image Arrow();
static Image Wait();
static Image IBeam();
static Image No();
static Image SizeAll();
static Image SizeHorz();
static Image SizeVert();
static Image SizeTopLeft();
static Image SizeTop();
static Image SizeTopRight();
static Image SizeLeft();
static Image SizeRight();
static Image SizeBottomLeft();
static Image SizeBottom();
static Image SizeBottomRight();
static Image Cross();
static Image Hand();
// IML support ("private"), deprecated - legacy .iml
struct Init {
const char *const *scans;
int16 scan_count;
char info[24];
};
explicit Image(const Init& init);
};
Image Premultiply(const Image& img);
Image Unmultiply(const Image& img);
Vector<Image> UnpackImlData(const void *ptr, int len);
Vector<Image> UnpackImlData(const String& d);
class Iml {
struct IImage : Moveable<IImage> {
bool loaded;
Image image;
IImage() { loaded = false; }
};
struct Data : Moveable<Data> {
const char *data;
int len, count;
};
Vector<Data> data;
VectorMap<String, IImage> map;
const Image::Init *img_init;
const char **name;
bool premultiply;
void Init(int n);
public:
void Enter();
void Leave();
void Reset();
int GetCount() const { return map.GetCount(); }
String GetId(int i) { return map.GetKey(i); }
Image Get(int i);
int Find(const String& s) const { return map.Find(s); }
void Set(int i, const Image& img);
void Premultiplied() { premultiply = false; }
#ifdef _DEBUG
int GetBinSize() const;
#endif
Iml(const Image::Init *img_init, const char **name, int n);//Deprecated - legacy .iml
void AddData(const byte *data, int len, int count);
};
void Register(const char *imageclass, Iml& iml);
int GetImlCount();
String GetImlName(int i);
Iml& GetIml(int i);
int FindIml(const char *name);
Image GetImlImage(const char *name);
void SetImlImage(const char *name, const Image& m);
String StoreImageAsString(const Image& img);
Image LoadImageFromString(const String& s);
Size GetImageStringSize(const String& src);
Size GetImageStringDots(const String& src);
#include "Raster.h"
#include "ImageOp.h"
#ifdef PLATFORM_WIN32
#ifndef PLATFORM_WINCE
Image Win32Icon(LPCSTR id, int iconsize = 0);
Image Win32Icon(int id, int iconsize = 0);
Image Win32Cursor(LPCSTR id);
Image Win32Cursor(int id);
HICON IconWin32(const Image& img, bool cursor = false);
Image Win32DllIcon(const char *dll, int ii, bool large);
#endif
#endif
#ifdef PLATFORM_X11
Cursor X11Cursor(const Image& img);
#endif

View file

@ -4,6 +4,28 @@ NAMESPACE_UPP
#ifdef PLATFORM_X11
struct Image::Data::SystemData {
int cursor_cheat;
XPicture picture;
XPicture picture8;
};
Image::Data::SystemData& Image::Data::Sys() const
{
ASSERT(sizeof(system_buffer) >= sizeof(SystemData));
return *(SystemData *)system_buffer;
}
void Image::SetCursorCheat(int id)
{
data->Sys().cursor_cheat = id;
}
int Image::GetCursorCheat() const
{
return data ? data->Sys().cursor_cheat : -1;
}
static void sInitXImage(XImage& ximg, Size sz)
{
Zero(ximg);
@ -51,26 +73,33 @@ void SetSurface(SystemDraw& w, int x, int y, int cx, int cy, const RGBA *pixels)
XRenderFreePicture(Xdisplay, picture);
}
int Image::Data::GetResCount() const
{
return !!Sys().picture + !!Sys().picture8;
}
void Image::Data::SysInit()
{
picture = 0;
picture8 = 0;
cursor_cheat = -1;
SystemData& sd = Sys();
sd.picture = 0;
sd.picture8 = 0;
sd.cursor_cheat = -1;
}
void Image::Data::SysRelease()
{
if(picture) {
SystemData& sd = Sys();
if(sd.picture) {
DrawLock __;
if(Xdisplay) XRenderFreePicture(Xdisplay, picture);
if(Xdisplay) XRenderFreePicture(Xdisplay, sd.picture);
ResCount -= !paintonly;
picture = 0;
sd.picture = 0;
}
if(picture8) {
if(sd.picture8) {
DrawLock __;
if(Xdisplay) XRenderFreePicture(Xdisplay, picture8);
if(Xdisplay) XRenderFreePicture(Xdisplay, sd.picture8);
ResCount -= !paintonly;
picture8 = 0;
sd.picture8 = 0;
}
}
@ -119,6 +148,7 @@ static XPicture sGetSolidFill(Color c)
void Image::Data::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c)
{
DrawLock __;
SystemData& sd = Sys();
while(ResCount > 512) {
Image::Data *l = ResData->GetPrev();
l->SysRelease();
@ -146,10 +176,10 @@ void Image::Data::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c)
Unlink();
LinkAfter(ResData);
if(IsNull(c)) {
if(!picture) {
if(!sd.picture) {
bool opaque = GetKind() == IMAGE_OPAQUE;
Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, opaque ? 24 : 32);
picture = XRenderCreatePicture(
sd.picture = XRenderCreatePicture(
Xdisplay, pixmap,
XRenderFindStandardFormat(Xdisplay, opaque ? PictStandardRGB24
: PictStandardARGB32),
@ -175,16 +205,16 @@ void Image::Data::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c)
PaintOnlyShrink();
}
XRenderComposite(Xdisplay, PictOpOver,
picture, 0, XftDrawPicture(w.GetXftDraw()),
sd.picture, 0, XftDrawPicture(w.GetXftDraw()),
sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy);
}
else {
ASSERT(!paintonly);
if(!picture8) {
if(!sd.picture8) {
Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, 8);
picture8 = XRenderCreatePicture(Xdisplay, pixmap,
XRenderFindStandardFormat(Xdisplay, PictStandardA8),
0, 0);
sd.picture8 = XRenderCreatePicture(Xdisplay, pixmap,
XRenderFindStandardFormat(Xdisplay, PictStandardA8),
0, 0);
ResCount++;
Buffer<byte> ab(len);
byte *t = ab;
@ -207,7 +237,7 @@ void Image::Data::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c)
XFreePixmap(Xdisplay, pixmap);
}
XRenderComposite(Xdisplay, PictOpOver,
sGetSolidFill(c), picture8, XftDrawPicture(w.GetXftDraw()),
sGetSolidFill(c), sd.picture8, XftDrawPicture(w.GetXftDraw()),
sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy);
}
}