Draw, CtrlCore: Major refactor of Draw

git-svn-id: svn://ultimatepp.org/upp/trunk@5545 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2012-11-11 12:33:47 +00:00
parent fa5f9ec55e
commit bd87a04fda
37 changed files with 2704 additions and 2655 deletions

View file

@ -61,6 +61,7 @@ void Build(const char *nest, const char *bm, bool release)
Cout() << " *** FAILED *** !\n";
failed = true;
LOG("FAILED: " << txt);
LOG(c);
LOG(out);
}
else {

View file

@ -22,9 +22,13 @@
NAMESPACE_UPP
#ifdef _MULTITHREADED
void EnterGMutex(int n);
int LeaveGMutexAll();
void EnterGuiMutex();
void LeaveGuiMutex();
#else
inline void EnterGMutex(int) {}
inline int LeaveGMutexAll() { return 0; }
inline void EnterGuiMutex() {}
inline void LeaveGuiMutex() {}
#endif

View file

@ -1,194 +1,234 @@
#include "CtrlCore.h"
#define LLOG(x) // if(!IsMainThread()) DLOG((int)GetCurrentThreadId() << " " << x)
NAMESPACE_UPP
#ifdef _MULTITHREADED
static int NonMain;
static StaticMutex NonMainLock;
void EnterGuiMutex()
{
LLOG("Thread " << IsMainThread() << " trying to lock" << ", nonmain: " << NonMain);
bool nonmain = !IsMainThread();
if(nonmain)
NonMainLock.Enter();
EnterGMutex();
if(nonmain)
NonMain++;
LLOG("Thread " << IsMainThread() << " LOCK" << ", nonmain: " << NonMain);
}
void LeaveGuiMutex()
{
LLOG("Thread " << IsMainThread() << " trying to unlock" << ", nonmain: " << NonMain);
bool nonmain = !IsMainThread();
if(nonmain)
NonMain--;
LeaveGMutex();
if(nonmain)
NonMainLock.Leave();
LLOG("Thread " << IsMainThread() << " UNLOCK" << ", nonmain: " << NonMain);
}
struct Ctrl::CallBox {
Semaphore sem;
Callback cb;
};
void Ctrl::PerformCall(Ctrl::CallBox *cbox)
{
cbox->cb();
LLOG("Sem release");
cbox->sem.Release();
}
Callback Ctrl::CtrlCall;
static Mutex CtrlCallMutex;
void WakeUpGuiThread();
bool Ctrl::DoCall()
{
LLOG("DoCall");
GuiLock __;
{
Mutex::Lock __(CtrlCallMutex);
CtrlCall();
CtrlCall.Clear();
}
LLOG("--- DoCall, nonmain: " << NonMain);
return NonMain;
}
void Ctrl::ICall(Callback cb)
{
LLOG("Ctrl::Call " << IsMainThread() << ", nonmain: " << NonMain);
if(IsMainThread())
cb();
else {
GuiLock __;
CallBox cbox;
cbox.cb = cb;
{
Mutex::Lock __(CtrlCallMutex);
CtrlCall = callback1(PerformCall, &cbox);
}
int level = LeaveGMutexAll();
WakeUpGuiThread();
LLOG("Waiting for semaphore");
if(!Thread::IsShutdownThreads())
cbox.sem.Wait();
EnterGMutex(level);
}
LLOG("-- Ctrl::Call " << IsMainThread());
}
void Ctrl::Call(Callback cb)
{
if(IsMainThread())
cb();
else {
GuiLock __;
CallBox cbox;
cbox.cb = cb;
UPP::PostCallback(callback1(PerformCall, &cbox));
int n = NonMain;
NonMain = 0;
for(int i = 0; i < n; i++)
NonMainLock.Leave();
int level = LeaveGMutexAll();
WakeUpGuiThread();
if(!Thread::IsShutdownThreads())
cbox.sem.Wait();
for(int i = 0; i < n; i++)
NonMainLock.Enter();
EnterGMutex(level);
NonMain = n;
}
}
#else
bool Ctrl::DoCall()
{
return false;
}
void Ctrl::ICall(Callback cb)
{
cb();
}
void Ctrl::Call(Callback cb)
{
cb();
}
#endif
void Ctrl::GuiSleep(int ms)
{
Call(callback1(&Ctrl::GuiSleep0, ms));
}
void Ctrl::WndDestroy()
{
ICall(callback(this, &Ctrl::WndDestroy0));
}
void Ctrl::WndShow(bool b)
{
ICall(THISBACK1(WndShow0, b));
}
void Ctrl::WndUpdate()
{
ICall(THISBACK(WndUpdate0));
}
void Ctrl::SetWndForeground()
{
ICall(THISBACK(SetWndForeground0));
}
bool Ctrl::WndEnable(bool b)
{
ICall(THISBACK1(WndEnable0, &b));
return b;
}
bool Ctrl::SetWndFocus()
{
bool b;
ICall(THISBACK1(SetWndFocus0, &b));
return b;
}
void Ctrl::WndInvalidateRect(const Rect& r)
{
ICall(THISBACK1(WndInvalidateRect0, r));
}
void Ctrl::WndSetPos(const Rect& rect)
{
ICall(THISBACK1(WndSetPos0, rect));
}
void Ctrl::WndUpdate(const Rect& r)
{
ICall(THISBACK1(WndUpdate0r, r));
}
void Ctrl::WndScrollView(const Rect& r, int dx, int dy)
{
ICall(THISBACK3(WndScrollView0, r, dx, dy));
}
void Ctrl::EventLoop(Ctrl *ctrl)
{
Call(callback1(&Ctrl::EventLoop0, ctrl));
}
END_UPP_NAMESPACE
#include "CtrlCore.h"
#define LLOG(x) // if(!IsMainThread()) DLOG((int)GetCurrentThreadId() << " " << x)
NAMESPACE_UPP
#ifdef _MULTITHREADED
static StaticMutex sGLock;
static thread__ int sGLockLevel = 0;
void EnterGMutex()
{
if(sGLockLevel++ == 0)
sGLock.Enter();
LLOG("EnterGMutex");
}
void EnterGMutex(int n)
{
if(n > 0) {
if(sGLockLevel == 0)
sGLock.Enter();
sGLockLevel += n;
}
LLOG("EnterGMutex " << n);
}
void LeaveGMutex()
{
ASSERT(sGLockLevel > 0);
if(--sGLockLevel == 0)
sGLock.Leave();
LLOG("LeaveGMutex");
}
int LeaveGMutexAll()
{
int q = sGLockLevel;
if(q) {
sGLock.Leave();
sGLockLevel = 0;
}
LLOG("LeaveGMutex all");
return q;
}
static int NonMain;
static StaticMutex NonMainLock;
void EnterGuiMutex()
{
LLOG("Thread " << IsMainThread() << " trying to lock" << ", nonmain: " << NonMain);
bool nonmain = !IsMainThread();
if(nonmain)
NonMainLock.Enter();
EnterGMutex();
if(nonmain)
NonMain++;
LLOG("Thread " << IsMainThread() << " LOCK" << ", nonmain: " << NonMain);
}
void LeaveGuiMutex()
{
LLOG("Thread " << IsMainThread() << " trying to unlock" << ", nonmain: " << NonMain);
bool nonmain = !IsMainThread();
if(nonmain)
NonMain--;
LeaveGMutex();
if(nonmain)
NonMainLock.Leave();
LLOG("Thread " << IsMainThread() << " UNLOCK" << ", nonmain: " << NonMain);
}
struct Ctrl::CallBox {
Semaphore sem;
Callback cb;
};
void Ctrl::PerformCall(Ctrl::CallBox *cbox)
{
cbox->cb();
LLOG("Sem release");
cbox->sem.Release();
}
Callback Ctrl::CtrlCall;
static Mutex CtrlCallMutex;
void WakeUpGuiThread();
bool Ctrl::DoCall()
{
LLOG("DoCall");
GuiLock __;
{
Mutex::Lock __(CtrlCallMutex);
CtrlCall();
CtrlCall.Clear();
}
LLOG("--- DoCall, nonmain: " << NonMain);
return NonMain;
}
void Ctrl::ICall(Callback cb)
{
LLOG("Ctrl::Call " << IsMainThread() << ", nonmain: " << NonMain);
if(IsMainThread())
cb();
else {
GuiLock __;
CallBox cbox;
cbox.cb = cb;
{
Mutex::Lock __(CtrlCallMutex);
CtrlCall = callback1(PerformCall, &cbox);
}
int level = LeaveGMutexAll();
WakeUpGuiThread();
LLOG("Waiting for semaphore");
if(!Thread::IsShutdownThreads())
cbox.sem.Wait();
EnterGMutex(level);
}
LLOG("-- Ctrl::Call " << IsMainThread());
}
void Ctrl::Call(Callback cb)
{
if(IsMainThread())
cb();
else {
GuiLock __;
CallBox cbox;
cbox.cb = cb;
UPP::PostCallback(callback1(PerformCall, &cbox));
int n = NonMain;
NonMain = 0;
for(int i = 0; i < n; i++)
NonMainLock.Leave();
int level = LeaveGMutexAll();
WakeUpGuiThread();
if(!Thread::IsShutdownThreads())
cbox.sem.Wait();
for(int i = 0; i < n; i++)
NonMainLock.Enter();
EnterGMutex(level);
NonMain = n;
}
}
#else
bool Ctrl::DoCall()
{
return false;
}
void Ctrl::ICall(Callback cb)
{
cb();
}
void Ctrl::Call(Callback cb)
{
cb();
}
#endif
void Ctrl::GuiSleep(int ms)
{
Call(callback1(&Ctrl::GuiSleep0, ms));
}
void Ctrl::WndDestroy()
{
ICall(callback(this, &Ctrl::WndDestroy0));
}
void Ctrl::WndShow(bool b)
{
ICall(THISBACK1(WndShow0, b));
}
void Ctrl::WndUpdate()
{
ICall(THISBACK(WndUpdate0));
}
void Ctrl::SetWndForeground()
{
ICall(THISBACK(SetWndForeground0));
}
bool Ctrl::WndEnable(bool b)
{
ICall(THISBACK1(WndEnable0, &b));
return b;
}
bool Ctrl::SetWndFocus()
{
bool b;
ICall(THISBACK1(SetWndFocus0, &b));
return b;
}
void Ctrl::WndInvalidateRect(const Rect& r)
{
ICall(THISBACK1(WndInvalidateRect0, r));
}
void Ctrl::WndSetPos(const Rect& rect)
{
ICall(THISBACK1(WndSetPos0, rect));
}
void Ctrl::WndUpdate(const Rect& r)
{
ICall(THISBACK1(WndUpdate0r, r));
}
void Ctrl::WndScrollView(const Rect& r, int dx, int dy)
{
ICall(THISBACK3(WndScrollView0, r, dx, dy));
}
void Ctrl::EventLoop(Ctrl *ctrl)
{
Call(callback1(&Ctrl::EventLoop0, ctrl));
}
END_UPP_NAMESPACE

View file

@ -144,12 +144,6 @@ void SystemDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color col
::LineTo(handle, x2, y2);
}
void SystemDraw::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color)
{
GuiLock __;
StdDrawImage(*this, x, y, cx, cy, img, src, color);
}
#ifndef PLATFORM_WINCE
void SystemDraw::DrawPolyPolylineOp(const Point *vertices, int vertex_count,

View file

@ -144,12 +144,6 @@ void SystemDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color col
x2 + actual_offset.x, y2 + actual_offset.y);
}
void SystemDraw::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color)
{
GuiLock __;
StdDrawImage(*this, x, y, cx, cy, img, src, color);
}
void SystemDraw::DrawPolyPolylineOp(const Point *vertices, int vertex_count,
const int *counts, int count_count,
int width, Color color, Color doxor)

View file

@ -7,19 +7,12 @@
NAMESPACE_UPP
#define LTIMING(x) // RTIMING(x)
#define LLOG(x) // DLOG(x)
bool ImageFallBack
// = true
;
struct Image::Data::SystemData {
LPCSTR cursor_cheat;
HBITMAP hbmp;
HBITMAP hmask;
HBITMAP himg;
RGBA *section;
};
class BitmapInfo32__ {
Buffer<byte> data;
@ -164,34 +157,6 @@ DrawSurface::~DrawSurface()
::DeleteDC(dcMem);
}
void Image::Data::SysInitImp()
{
SystemData& sd = Sys();
sd.hbmp = sd.hmask = sd.himg = NULL;
sd.cursor_cheat = NULL;
}
void Image::Data::SysReleaseImp()
{
SystemData& sd = Sys();
if(sd.hbmp) {
GuiLock __;
DeleteObject(sd.hbmp);
ResCount -= !paintonly;
}
if(sd.hmask) {
GuiLock __;
DeleteObject(sd.hmask);
ResCount -= !paintonly;
}
if(sd.himg) {
GuiLock __;
DeleteObject(sd.himg);
ResCount -= !paintonly;
}
sd.himg = sd.hbmp = sd.hmask = NULL;
}
#ifndef PLATFORM_WINCE
typedef BOOL (WINAPI *tAlphaBlend)(HDC hdcDest, int nXOriginDest, int nYOriginDest,
int nWidthDest, int nHeightDest,
@ -212,115 +177,122 @@ static tAlphaBlend fnAlphaBlend()
}
#endif
void Image::SetCursorCheat(LPCSTR id)
struct ImageSysData {
Image img;
HBITMAP hbmp;
HBITMAP hmask;
HBITMAP himg;
RGBA *section;
int paintcount;
void Init(const Image& img);
void CreateHBMP(HDC dc, const RGBA *data);
void Paint(SystemDraw& w, int x, int y, const Rect& src, Color c);
~ImageSysData();
};
void ImageSysData::Init(const Image& _img)
{
data->Sys().cursor_cheat = id;
img = _img;
hbmp = hmask = himg = NULL;
paintcount = 0;
LLOG("ImageSysData::Init " << img.GetSerialId() << " " << img.GetSize());
}
LPCSTR Image::GetCursorCheat() const
ImageSysData::~ImageSysData()
{
return data ? data->Sys().cursor_cheat : NULL;
SysImageReleased(img);
if(hbmp) {
GuiLock __;
DeleteObject(hbmp);
}
if(hmask) {
GuiLock __;
DeleteObject(hmask);
}
if(himg) {
GuiLock __;
DeleteObject(himg);
}
hbmp = hmask = himg = NULL;
img.Clear();
}
Image::Data::SystemData& Image::Data::Sys() const
void ImageSysData::CreateHBMP(HDC dc, const RGBA *data)
{
ASSERT(sizeof(system_buffer) >= sizeof(SystemData));
return *(SystemData *)system_buffer;
}
int Image::Data::GetResCountImp() const
{
SystemData& sd = Sys();
return !!sd.hbmp + !!sd.hmask + !!sd.himg;
}
void Image::Data::CreateHBMP(HDC dc, const RGBA *data)
{
GuiLock __;
SystemData& sd = Sys();
Size sz = buffer.GetSize();
LLOG("Creating BMP for " << img.GetSerialId() << ' ' << img.GetSize());
Size sz = img.GetSize();
BitmapInfo32__ bi(sz.cx, sz.cy);
HDC dcMem = ::CreateCompatibleDC(dc);
RGBA *pixels;
HBITMAP hbmp32 = CreateDIBSection(dcMem, bi, DIB_RGB_COLORS, (void **)&pixels, NULL, 0);
HDC hbmpOld = (HDC) ::SelectObject(dcMem, hbmp32);
memcpy(pixels, data, buffer.GetLength() * sizeof(RGBA));
Copy(pixels, data, img.GetLength());
HDC dcMem2 = ::CreateCompatibleDC(dc);
sd.hbmp = ::CreateCompatibleBitmap(dc, sz.cx, sz.cy);
HBITMAP o2 = (HBITMAP)::SelectObject(dcMem2, sd.hbmp);
hbmp = ::CreateCompatibleBitmap(dc, sz.cx, sz.cy);
HBITMAP o2 = (HBITMAP)::SelectObject(dcMem2, hbmp);
::BitBlt(dcMem2, 0, 0, sz.cx, sz.cy, dcMem, 0, 0, SRCCOPY);
::SelectObject(dcMem2, o2);
::DeleteDC(dcMem2);
::SelectObject(dcMem, hbmpOld);
::DeleteObject(hbmp32);
::DeleteDC(dcMem);
ResCount++;
}
void Image::Data::PaintImp(SystemDraw& w, int x, int y, const Rect& src, Color c)
void ImageSysData::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c)
{
GuiLock __;
SystemData& sd = Sys();
ASSERT(!paintonly || IsNull(c));
int max = IsWinNT() ? 250 : 100;
while(ResCount > max) {
Image::Data *l = ResData->GetPrev();
l->SysRelease();
l->Unlink();
}
HDC dc = w.GetHandle();
Size sz = buffer.GetSize();
Size sz = img.GetSize();
int len = sz.cx * sz.cy;
Rect sr = src & sz;
Size ssz = sr.Size();
if(sr.IsEmpty())
return;
if(GetKind() == IMAGE_EMPTY)
int kind = img.GetKind();
if(kind == IMAGE_EMPTY)
return;
if(GetKind() == IMAGE_OPAQUE && !IsNull(c)) {
if(kind == IMAGE_OPAQUE && !IsNull(c)) {
w.DrawRect(x, y, sz.cx, sz.cy, c);
return;
}
if(GetKind() == IMAGE_OPAQUE && paintcount == 0 && sr == Rect(sz) && IsWinNT() && w.IsGui()) {
if(kind == IMAGE_OPAQUE && paintcount == 0 && sr == Rect(sz) && IsWinNT() && w.IsGui()) {
LTIMING("Image Opaque direct set");
SetSurface(w, x, y, sz.cx, sz.cy, buffer);
SetSurface(w, x, y, sz.cx, sz.cy, ~img);
paintcount++;
return;
}
Unlink();
LinkAfter(ResData);
if(GetKind() == IMAGE_OPAQUE) {
if(!sd.hbmp) {
if(kind == IMAGE_OPAQUE) {
if(!hbmp) {
LTIMING("Image Opaque create");
CreateHBMP(dc, buffer);
CreateHBMP(dc, ~img);
}
LTIMING("Image Opaque blit");
HDC dcMem = ::CreateCompatibleDC(dc);
HBITMAP o = (HBITMAP)::SelectObject(dcMem, sd.hbmp);
HBITMAP o = (HBITMAP)::SelectObject(dcMem, hbmp);
::BitBlt(dc, x, y, ssz.cx, ssz.cy, dcMem, sr.left, sr.top, SRCCOPY);
::SelectObject(dcMem, o);
::DeleteDC(dcMem);
PaintOnlyShrink();
SysImageRealized(img);
return;
}
if(GetKind() == IMAGE_MASK/* || GetKind() == IMAGE_OPAQUE*/) {
if(kind == IMAGE_MASK/* || GetKind() == IMAGE_OPAQUE*/) {
HDC dcMem = ::CreateCompatibleDC(dc);
if(!sd.hmask) {
if(!hmask) {
LTIMING("Image Mask create");
Buffer<RGBA> bmp(len);
sd.hmask = CreateBitMask(buffer, sz, sz, sz, bmp);
ResCount++;
if(!sd.hbmp)
hmask = CreateBitMask(~img, sz, sz, sz, bmp);
if(!hbmp)
CreateHBMP(dc, bmp);
}
LTIMING("Image Mask blt");
HBITMAP o = (HBITMAP)::SelectObject(dcMem, ::CreateCompatibleBitmap(dc, sz.cx, sz.cy));
::BitBlt(dcMem, 0, 0, ssz.cx, ssz.cy, dc, x, y, SRCCOPY);
HDC dcMem2 = ::CreateCompatibleDC(dc);
::SelectObject(dcMem2, sd.hmask);
::SelectObject(dcMem2, hmask);
::BitBlt(dcMem, 0, 0, ssz.cx, ssz.cy, dcMem2, sr.left, sr.top, SRCAND);
if(IsNull(c)) {
::SelectObject(dcMem2, sd.hbmp);
::SelectObject(dcMem2, hbmp);
::BitBlt(dcMem, 0, 0, ssz.cx, ssz.cy, dcMem2, sr.left, sr.top, SRCPAINT);
}
else {
@ -332,17 +304,16 @@ void Image::Data::PaintImp(SystemDraw& w, int x, int y, const Rect& src, Color c
::DeleteObject(::SelectObject(dcMem, o));
::DeleteDC(dcMem2);
::DeleteDC(dcMem);
PaintOnlyShrink();
SysImageRealized(img);
return;
}
#ifndef PLATFORM_WINCE
if(fnAlphaBlend() && IsNull(c) && !ImageFallBack) {
if(!sd.himg) {
if(!himg) {
LTIMING("Image Alpha create");
BitmapInfo32__ bi(sz.cx, sz.cy);
sd.himg = CreateDIBSection(ScreenHDC(), bi, DIB_RGB_COLORS, (void **)&sd.section, NULL, 0);
ResCount++;
memcpy(sd.section, ~buffer, buffer.GetLength() * sizeof(RGBA));
himg = CreateDIBSection(ScreenHDC(), bi, DIB_RGB_COLORS, (void **)&section, NULL, 0);
Copy(section, ~img, img.GetLength());
}
LTIMING("Image Alpha blit");
BLENDFUNCTION bf;
@ -351,10 +322,10 @@ void Image::Data::PaintImp(SystemDraw& w, int x, int y, const Rect& src, Color c
bf.SourceConstantAlpha = 255;
bf.AlphaFormat = AC_SRC_ALPHA;
HDC dcMem = ::CreateCompatibleDC(dc);
::SelectObject(dcMem, sd.himg);
::SelectObject(dcMem, himg);
fnAlphaBlend()(dc, x, y, ssz.cx, ssz.cy, dcMem, sr.left, sr.top, ssz.cx, ssz.cy, bf);
::DeleteDC(dcMem);
PaintOnlyShrink();
SysImageRealized(img);
}
else
#endif
@ -364,14 +335,36 @@ void Image::Data::PaintImp(SystemDraw& w, int x, int y, const Rect& src, Color c
RGBA *t = sf;
for(int i = sr.top; i < sr.bottom; i++) {
if(IsNull(c))
AlphaBlendOpaque(t, buffer[i] + sr.left, ssz.cx);
AlphaBlendOpaque(t, img[i] + sr.left, ssz.cx);
else
AlphaBlendOpaque(t, buffer[i] + sr.left, ssz.cx, c);
AlphaBlendOpaque(t, img[i] + sr.left, ssz.cx, c);
t += ssz.cx;
}
}
}
struct ImageSysDataMaker : LRUCache<ImageSysData, int64>::Maker {
Image img;
virtual int64 Key() const { return img.GetSerialId(); }
virtual int Make(ImageSysData& object) const { object.Init(img); return img.GetLength(); }
};
void SystemDraw::SysDrawImageOp(int x, int y, const Image& img, const Rect& src, Color color)
{
GuiLock __;
if(img.GetLength() == 0)
return;
LLOG("SysDrawImageOp " << img.GetSerialId() << ' ' << img.GetSize());
ImageSysDataMaker m;
static LRUCache<ImageSysData, int64> cache;
LLOG("SysImage cache pixels " << cache.GetSize() << ", count " << cache.GetCount());
Size sz = Ctrl::GetPrimaryScreenArea().GetSize();
m.img = img;
cache.Get(m).Paint(*this, x, y, src, color);
cache.Shrink(4 * sz.cx * sz.cy, IsWinNT() ? 1000 : 100);
}
void ImageDraw::Section::Init(int cx, int cy)
{
GuiLock __;
@ -546,7 +539,7 @@ alpha:
return img;
}
Image Win32IconCursor(LPCSTR id, int iconsize, bool cursor)
Image SystemDraw::Win32IconCursor(LPCSTR id, int iconsize, bool cursor)
{
HICON icon;
if(cursor)
@ -559,7 +552,7 @@ Image Win32IconCursor(LPCSTR id, int iconsize, bool cursor)
icon = LoadIcon(0, id);
Image img = sWin32Icon(icon, cursor);
if(cursor)
img.SetCursorCheat(id);
img.SetAuxData(reinterpret_cast<uint64>(id));
return img;
}
@ -573,7 +566,7 @@ Image Win32DllIcon(const char *dll, int ii, bool large)
Image Win32Icon(LPCSTR id, int iconsize)
{
return Win32IconCursor(id, iconsize, false);
return SystemDraw::Win32IconCursor(id, iconsize, false);
}
Image Win32Icon(int id, int iconsize)
@ -583,7 +576,7 @@ Image Win32Icon(int id, int iconsize)
Image Win32Cursor(LPCSTR id)
{
return Win32IconCursor(id, 0, true);
return SystemDraw::Win32IconCursor(id, 0, true);
}
Image Win32Cursor(int id)
@ -591,13 +584,13 @@ Image Win32Cursor(int id)
return Win32Cursor(MAKEINTRESOURCE(id));
}
HICON IconWin32(const Image& img, bool cursor)
HICON SystemDraw::IconWin32(const Image& img, bool cursor)
{
GuiLock __;
if(img.IsEmpty())
return NULL;
if(cursor) {
LPCSTR id = img.GetCursorCheat();
LPCSTR id = reinterpret_cast<LPCSTR>(img.GetAuxData());
if(id)
return (HICON)LoadCursor(0, id);
}
@ -638,11 +631,6 @@ HICON IconWin32(const Image& img, bool cursor)
return icon;
}
HICON SystemDraw::IconWin32(const Image& img, bool cursor)
{
return UPP::IconWin32(img, cursor);
}
#define WCURSOR_(x)\
{ Image m; INTERLOCKED { static Image img = Win32Cursor(x); m = img; } return m; }

View file

@ -1,471 +1,476 @@
#include "CtrlCore.h"
#ifdef GUI_X11
NAMESPACE_UPP
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);
ximg.width = sz.cx;
ximg.height = sz.cy;
ximg.xoffset = 0;
ximg.format = ZPixmap;
ximg.bitmap_bit_order = MSBFirst;
#ifdef CPU_LITTLE_ENDIAN
ximg.byte_order = LSBFirst;
#else
ximg.byte_order = MSBFirst;
#endif
}
void SetSurface(SystemDraw& w, const Rect& dest, const RGBA *pixels, Size srcsz, Point srcoff)
{
GuiLock __;
XImage ximg;
sInitXImage(ximg, srcsz);
ximg.bitmap_pad = 32;
ximg.bytes_per_line = sizeof(RGBA) * srcsz.cx;
ximg.bits_per_pixel = 32;
ximg.blue_mask = 0x00ff0000;
ximg.green_mask = 0x0000ff00;
ximg.red_mask = 0x000000ff;
ximg.bitmap_unit = 32;
ximg.depth = 24;
ximg.data = (char *)pixels;
XInitImage(&ximg);
Drawable dw = w.GetDrawable();
GC gc = XCreateGC(Xdisplay, dw, 0, 0);
Point p = dest.TopLeft() + w.GetOffset();
XPutImage(Xdisplay, dw, gc, &ximg, srcoff.x, srcoff.y,
p.x, p.y, dest.GetWidth(), dest.GetHeight());
XFreeGC(Xdisplay, gc);
}
void SetSurface(SystemDraw& w, int x, int y, int cx, int cy, const RGBA *pixels)
{
GuiLock __;
Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, cx, cy, 24);
XPicture picture = XRenderCreatePicture(
Xdisplay, pixmap,
XRenderFindStandardFormat(Xdisplay, PictStandardRGB24),
0, 0
);
XImage ximg;
sInitXImage(ximg, Size(cx, cy));
ximg.bitmap_pad = 32;
ximg.bytes_per_line = 4 * cx;
ximg.bits_per_pixel = 32;
ximg.blue_mask = 0x00ff0000;
ximg.green_mask = 0x0000ff00;
ximg.red_mask = 0x000000ff;
ximg.bitmap_unit = 32;
ximg.depth = 24;
ximg.data = (char *)pixels;
XInitImage(&ximg);
GC gc = XCreateGC(Xdisplay, pixmap, 0, 0);
XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, cx, cy);
XFreeGC(Xdisplay, gc);
XFreePixmap(Xdisplay, pixmap);
XRenderComposite(Xdisplay, PictOpOver,
picture, 0, XftDrawPicture(w.GetXftDraw()),
0, 0, 0, 0, x, y, cx, cy);
XRenderFreePicture(Xdisplay, picture);
}
int Image::Data::GetResCountImp() const
{
return !!Sys().picture + !!Sys().picture8;
}
void Image::Data::SysInitImp()
{
SystemData& sd = Sys();
sd.picture = 0;
sd.picture8 = 0;
sd.cursor_cheat = -1;
}
void Image::Data::SysReleaseImp()
{
SystemData& sd = Sys();
if(sd.picture) {
GuiLock __;
if(Xdisplay) XRenderFreePicture(Xdisplay, sd.picture);
ResCount -= !paintonly;
sd.picture = 0;
}
if(sd.picture8) {
GuiLock __;
if(Xdisplay) XRenderFreePicture(Xdisplay, sd.picture8);
ResCount -= !paintonly;
sd.picture8 = 0;
}
}
struct XRSolidFill {
Color color;
XPicture picture;
Pixmap pixmap;
};
enum { XRSolidFillCount = 67 };
static XRSolidFill sFill[XRSolidFillCount];
inline int s255d16(int x)
{
return (x << 8)|x;
}
static XPicture sGetSolidFill(Color c)
{
GuiLock __;
int q = GetHashValue(c) % (int)XRSolidFillCount;
XRSolidFill& f = sFill[q];
if(f.color == c && f.picture)
return f.picture;
if(f.picture)
XRenderFreePicture(Xdisplay, f.picture);
if(f.pixmap)
XFreePixmap(Xdisplay, f.pixmap);
f.pixmap = XCreatePixmap(Xdisplay, Xroot, 1, 1, 32);
XRenderPictureAttributes attr;
attr.repeat = XTrue;
f.picture = XRenderCreatePicture(Xdisplay, f.pixmap,
XRenderFindStandardFormat(Xdisplay, PictStandardARGB32),
CPRepeat, &attr);
f.color = c;
XRenderColor xc;
xc.red = s255d16(c.GetR());
xc.green = s255d16(c.GetG());
xc.blue = s255d16(c.GetB());
xc.alpha = 65535;
XRenderFillRectangle(Xdisplay, PictOpSrc, f.picture, &xc, 0, 0, 1, 1);
return f.picture;
}
void Image::Data::PaintImp(SystemDraw& w, int x, int y, const Rect& src, Color c)
{
GuiLock __;
SystemData& sd = Sys();
while(ResCount > 512) {
Image::Data *l = ResData->GetPrev();
l->SysRelease();
l->Unlink();
}
x += w.GetOffset().x;
y += w.GetOffset().y;
Size sz = buffer.GetSize();
int len = sz.cx * sz.cy;
Rect sr = src & sz;
Size ssz = sr.Size();
if(sr.IsEmpty())
return;
if(GetKind() == IMAGE_EMPTY)
return;
if(GetKind() == IMAGE_OPAQUE && !IsNull(c)) {
w.DrawRect(x, y, sz.cx, sz.cy, c);
return;
}
if(GetKind() == IMAGE_OPAQUE && paintcount == 0 && sr == Rect(sz)) {
SetSurface(w, x, y, sz.cx, sz.cy, buffer);
paintcount++;
return;
}
Unlink();
LinkAfter(ResData);
if(IsNull(c)) {
if(!sd.picture) {
bool opaque = GetKind() == IMAGE_OPAQUE;
Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, opaque ? 24 : 32);
sd.picture = XRenderCreatePicture(
Xdisplay, pixmap,
XRenderFindStandardFormat(Xdisplay, opaque ? PictStandardRGB24
: PictStandardARGB32),
0, 0
);
ResCount++;
XImage ximg;
sInitXImage(ximg, sz);
ximg.bitmap_pad = 32;
ximg.bytes_per_line = 4 * sz.cx;
ximg.bits_per_pixel = 32;
ximg.blue_mask = 0x00ff0000;
ximg.green_mask = 0x0000ff00;
ximg.red_mask = 0x000000ff;
ximg.bitmap_unit = 32;
ximg.data = (char *)~buffer;
ximg.depth = opaque ? 24 : 32;
XInitImage(&ximg);
GC gc = XCreateGC(Xdisplay, pixmap, 0, 0);
XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy);
XFreeGC(Xdisplay, gc);
XFreePixmap(Xdisplay, pixmap);
PaintOnlyShrink();
}
XRenderComposite(Xdisplay, PictOpOver,
sd.picture, 0, XftDrawPicture(w.GetXftDraw()),
sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy);
}
else {
ASSERT(!paintonly);
if(!sd.picture8) {
Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, 8);
sd.picture8 = XRenderCreatePicture(Xdisplay, pixmap,
XRenderFindStandardFormat(Xdisplay, PictStandardA8),
0, 0);
ResCount++;
Buffer<byte> ab(len);
byte *t = ab;
const RGBA *s = buffer;
const RGBA *e = s + len;
while(s < e)
*t++ = (s++)->a;
XImage ximg;
sInitXImage(ximg, sz);
ximg.data = (char *)~ab;
ximg.bitmap_unit = 8;
ximg.bitmap_pad = 8;
ximg.depth = 8;
ximg.bytes_per_line = sz.cx;
ximg.bits_per_pixel = 8;
XInitImage(&ximg);
GC gc = XCreateGC(Xdisplay, pixmap, 0, 0);
XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy);
XFreeGC(Xdisplay, gc);
XFreePixmap(Xdisplay, pixmap);
}
XRenderComposite(Xdisplay, PictOpOver,
sGetSolidFill(c), sd.picture8, XftDrawPicture(w.GetXftDraw()),
sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy);
}
}
void ImageDraw::Init()
{
GuiLock __;
dw = XCreatePixmap(Xdisplay, Xroot, max(size.cx, 1), max(size.cy, 1), Xdepth);
gc = XCreateGC(Xdisplay, dw, 0, 0);
xftdraw = XftDrawCreate(Xdisplay, (Drawable) dw, DefaultVisual(Xdisplay, Xscreenno), Xcolormap);
alpha.dw = XCreatePixmap(Xdisplay, Xroot, max(size.cx, 1), max(size.cy, 1), Xdepth);
alpha.gc = XCreateGC(Xdisplay, alpha.dw, 0, 0);
alpha.xftdraw = XftDrawCreate(Xdisplay, (Drawable) alpha.dw, DefaultVisual(Xdisplay, Xscreenno), Xcolormap);
Vector<Rect> clip;
clip.Add(RectC(0, 0, size.cx, size.cy));
SystemDraw::Init(clip, Point(0, 0));
alpha.Init(clip, Point(0, 0));
has_alpha = false;
}
ImageDraw::operator Image() const
{
GuiLock __;
XImage *xim = XGetImage(Xdisplay, dw, 0, 0, max(size.cx, 1), max(size.cy, 1), AllPlanes, ZPixmap);
if(!xim)
return Null;
Visual *v = DefaultVisual(Xdisplay, Xscreenno);
RasterFormat fmt;
RGBA palette[256];
switch(xim->depth) {
case 15:
case 16:
if(xim->byte_order == LSBFirst)
fmt.Set16le(v->red_mask, v->green_mask, v->blue_mask);
else
fmt.Set16be(v->red_mask, v->green_mask, v->blue_mask);
break;
case 8: {
int n = min(v->map_entries, 256);
XColor colors[256];
for(int i = 0; i < 256; i++) {
colors[i].pixel = i;
colors[i].flags = DoRed|DoGreen|DoBlue;
}
XQueryColors(Xdisplay, Xcolormap, colors, n);
XColor *s = colors;
XColor *e = s + n;
while(s < e) {
RGBA& t = palette[s->pixel];
t.r = s->red >> 8;
t.g = s->green >> 8;
t.b = s->blue >> 8;
t.a = 255;
s++;
}
fmt.Set8();
break;
}
default:
if(xim->bits_per_pixel == 32)
if(xim->byte_order == LSBFirst)
fmt.Set32le(v->red_mask, v->green_mask, v->blue_mask);
else
fmt.Set32be(v->red_mask, v->green_mask, v->blue_mask);
else
if(xim->byte_order == LSBFirst)
fmt.Set24le(v->red_mask, v->green_mask, v->blue_mask);
else
fmt.Set24be(v->red_mask, v->green_mask, v->blue_mask);
break;
}
ImageBuffer ib(size);
const byte *s = (const byte *)xim->data;
RGBA *t = ib;
for(int y = 0; y < size.cy; y++) {
fmt.Read(t, s, size.cx, palette);
s += xim->bytes_per_line;
t += size.cx;
}
XDestroyImage(xim);
if(has_alpha) {
xim = XGetImage(Xdisplay, alpha.dw, 0, 0, max(size.cx, 1), max(size.cy, 1), AllPlanes, ZPixmap);
if(xim) {
const byte *s = (const byte *)xim->data;
t = ib;
Buffer<RGBA> line(size.cx);
for(int y = 0; y < size.cy; y++) {
fmt.Read(line, s, size.cx, palette);
for(int x = 0; x < size.cx; x++)
(t++)->a = line[x].r;
s += xim->bytes_per_line;
}
XDestroyImage(xim);
}
}
Premultiply(ib);
return ib;
}
ImageDraw::ImageDraw(Size sz)
{
size = sz;
Init();
}
ImageDraw::ImageDraw(int cx, int cy)
{
size = Size(cx, cy);
Init();
}
ImageDraw::~ImageDraw()
{
GuiLock __;
XftDrawDestroy(xftdraw);
XFreePixmap(Xdisplay, dw);
XFreeGC(Xdisplay, gc);
XftDrawDestroy(alpha.xftdraw);
XFreePixmap(Xdisplay, alpha.dw);
XFreeGC(Xdisplay, alpha.gc);
}
Draw& ImageDraw::Alpha()
{
if(!has_alpha) {
alpha.DrawRect(size, GrayColor(0));
has_alpha = true;
}
return alpha;
}
Image X11Cursor(int c)
{
ImageBuffer b(32, 32);
Image m(b);
m.SetCursorCheat(c);
return m;
}
#include <X11/cursorfont.h>
#define FCURSOR_(x) { Image h; INTERLOCKED { static Image m = X11Cursor(x); h = m; } return h; }
Image Image::Arrow() FCURSOR_(XC_left_ptr)
Image Image::Wait() FCURSOR_(XC_watch)
Image Image::IBeam() FCURSOR_(XC_xterm)
Image Image::No() FCURSOR_(XC_circle)
Image Image::SizeAll() FCURSOR_(XC_fleur)
Image Image::SizeHorz() FCURSOR_(XC_sb_h_double_arrow)
Image Image::SizeVert() FCURSOR_(XC_double_arrow)
Image Image::SizeTopLeft() FCURSOR_(XC_top_left_corner)
Image Image::SizeTop() FCURSOR_(XC_top_side)
Image Image::SizeTopRight() FCURSOR_(XC_top_right_corner)
Image Image::SizeLeft() FCURSOR_(XC_left_side)
Image Image::SizeRight() FCURSOR_(XC_right_side)
Image Image::SizeBottomLeft() FCURSOR_(XC_bottom_left_corner)
Image Image::SizeBottom() FCURSOR_(XC_bottom_side)
Image Image::SizeBottomRight() FCURSOR_(XC_bottom_right_corner)
Image Image::Cross() FCURSOR_(XC_crosshair)
Image Image::Hand() FCURSOR_(XC_hand1)
void *CursorX11(const Image& img)
{
GuiLock __;
int q = img.GetCursorCheat();
if(q >= 0)
return (void *)XCreateFontCursor(Xdisplay, q);
int len = img.GetLength();
Size sz = img.GetSize();
Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, 32);
XPicture picture = XRenderCreatePicture(
Xdisplay, pixmap,
XRenderFindStandardFormat(Xdisplay, PictStandardARGB32),
0, 0
);
XImage ximg;
sInitXImage(ximg, sz);
ximg.bitmap_pad = 32;
ximg.bytes_per_line = 4 * sz.cx;
ximg.bits_per_pixel = 32;
ximg.blue_mask = 0x00ff0000;
ximg.green_mask = 0x0000ff00;
ximg.red_mask = 0x000000ff;
Buffer<RGBA> pma;
pma.Alloc(len);
memcpy(pma, ~img, len * sizeof(RGBA));
ximg.bitmap_unit = 32;
ximg.depth = 32;
ximg.data = (char *)~pma;
XInitImage(&ximg);
GC gc = XCreateGC(Xdisplay, pixmap, 0, 0);
XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy);
XFreeGC(Xdisplay, gc);
XFreePixmap(Xdisplay, pixmap);
Point p = img.GetHotSpot();
Cursor c = XRenderCreateCursor(Xdisplay, picture, p.x, p.y);
XRenderFreePicture(Xdisplay, picture);
return (void *)c;
}
END_UPP_NAMESPACE
#endif
#include "CtrlCore.h"
#ifdef GUI_X11
NAMESPACE_UPP
#define LLOG(x) DLOG(x)
static void sInitXImage(XImage& ximg, Size sz)
{
Zero(ximg);
ximg.width = sz.cx;
ximg.height = sz.cy;
ximg.xoffset = 0;
ximg.format = ZPixmap;
ximg.bitmap_bit_order = MSBFirst;
#ifdef CPU_LITTLE_ENDIAN
ximg.byte_order = LSBFirst;
#else
ximg.byte_order = MSBFirst;
#endif
}
void SetSurface(SystemDraw& w, const Rect& dest, const RGBA *pixels, Size srcsz, Point srcoff)
{
GuiLock __;
XImage ximg;
sInitXImage(ximg, srcsz);
ximg.bitmap_pad = 32;
ximg.bytes_per_line = sizeof(RGBA) * srcsz.cx;
ximg.bits_per_pixel = 32;
ximg.blue_mask = 0x00ff0000;
ximg.green_mask = 0x0000ff00;
ximg.red_mask = 0x000000ff;
ximg.bitmap_unit = 32;
ximg.depth = 24;
ximg.data = (char *)pixels;
XInitImage(&ximg);
Drawable dw = w.GetDrawable();
GC gc = XCreateGC(Xdisplay, dw, 0, 0);
Point p = dest.TopLeft() + w.GetOffset();
XPutImage(Xdisplay, dw, gc, &ximg, srcoff.x, srcoff.y,
p.x, p.y, dest.GetWidth(), dest.GetHeight());
XFreeGC(Xdisplay, gc);
}
void SetSurface(SystemDraw& w, int x, int y, int cx, int cy, const RGBA *pixels)
{
GuiLock __;
Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, cx, cy, 24);
XPicture picture = XRenderCreatePicture(
Xdisplay, pixmap,
XRenderFindStandardFormat(Xdisplay, PictStandardRGB24),
0, 0
);
XImage ximg;
sInitXImage(ximg, Size(cx, cy));
ximg.bitmap_pad = 32;
ximg.bytes_per_line = 4 * cx;
ximg.bits_per_pixel = 32;
ximg.blue_mask = 0x00ff0000;
ximg.green_mask = 0x0000ff00;
ximg.red_mask = 0x000000ff;
ximg.bitmap_unit = 32;
ximg.depth = 24;
ximg.data = (char *)pixels;
XInitImage(&ximg);
GC gc = XCreateGC(Xdisplay, pixmap, 0, 0);
XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, cx, cy);
XFreeGC(Xdisplay, gc);
XFreePixmap(Xdisplay, pixmap);
XRenderComposite(Xdisplay, PictOpOver,
picture, 0, XftDrawPicture(w.GetXftDraw()),
0, 0, 0, 0, x, y, cx, cy);
XRenderFreePicture(Xdisplay, picture);
}
struct ImageSysData {
Image img;
XPicture picture;
XPicture picture8;
int paintcount;
void Init(const Image& m);
void Paint(SystemDraw& w, int x, int y, const Rect& src, Color c);
~ImageSysData();
};
void ImageSysData::Init(const Image& m)
{
ASSERT(~m);
img = m;
picture = 0;
picture8 = 0;
paintcount = 0;
}
ImageSysData::~ImageSysData()
{
SysImageReleased(img);
if(Xdisplay) {
if(picture)
XRenderFreePicture(Xdisplay, picture);
if(picture8)
XRenderFreePicture(Xdisplay, picture8);
}
picture = 0;
picture8 = 0;
}
struct XRSolidFill {
Color color;
XPicture picture;
Pixmap pixmap;
};
enum { XRSolidFillCount = 67 };
static XRSolidFill sFill[XRSolidFillCount];
inline int s255d16(int x)
{
return (x << 8)|x;
}
static XPicture sGetSolidFill(Color c)
{
GuiLock __;
int q = GetHashValue(c) % (int)XRSolidFillCount;
XRSolidFill& f = sFill[q];
if(f.color == c && f.picture)
return f.picture;
if(f.picture)
XRenderFreePicture(Xdisplay, f.picture);
if(f.pixmap)
XFreePixmap(Xdisplay, f.pixmap);
f.pixmap = XCreatePixmap(Xdisplay, Xroot, 1, 1, 32);
XRenderPictureAttributes attr;
attr.repeat = XTrue;
f.picture = XRenderCreatePicture(Xdisplay, f.pixmap,
XRenderFindStandardFormat(Xdisplay, PictStandardARGB32),
CPRepeat, &attr);
f.color = c;
XRenderColor xc;
xc.red = s255d16(c.GetR());
xc.green = s255d16(c.GetG());
xc.blue = s255d16(c.GetB());
xc.alpha = 65535;
XRenderFillRectangle(Xdisplay, PictOpSrc, f.picture, &xc, 0, 0, 1, 1);
return f.picture;
}
void ImageSysData::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c)
{
GuiLock __;
x += w.GetOffset().x;
y += w.GetOffset().y;
Size sz = img.GetSize();
int len = sz.cx * sz.cy;
Rect sr = src & sz;
Size ssz = sr.Size();
if(sr.IsEmpty())
return;
int kind = img.GetKind();
if(kind == IMAGE_EMPTY)
return;
if(kind == IMAGE_OPAQUE && !IsNull(c)) {
w.DrawRect(x, y, sz.cx, sz.cy, c);
return;
}
if(kind == IMAGE_OPAQUE && paintcount == 0 && sr == Rect(sz)) {
SetSurface(w, x, y, sz.cx, sz.cy, ~img);
paintcount++;
return;
}
if(IsNull(c)) {
if(!picture) {
bool opaque = kind == IMAGE_OPAQUE;
Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, opaque ? 24 : 32);
picture = XRenderCreatePicture(
Xdisplay, pixmap,
XRenderFindStandardFormat(Xdisplay, opaque ? PictStandardRGB24
: PictStandardARGB32),
0, 0
);
XImage ximg;
sInitXImage(ximg, sz);
ximg.bitmap_pad = 32;
ximg.bytes_per_line = 4 * sz.cx;
ximg.bits_per_pixel = 32;
ximg.blue_mask = 0x00ff0000;
ximg.green_mask = 0x0000ff00;
ximg.red_mask = 0x000000ff;
ximg.bitmap_unit = 32;
ximg.data = (char *)~img;
ximg.depth = opaque ? 24 : 32;
XInitImage(&ximg);
GC gc = XCreateGC(Xdisplay, pixmap, 0, 0);
XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy);
XFreeGC(Xdisplay, gc);
XFreePixmap(Xdisplay, pixmap);
SysImageRealized(img);
}
XRenderComposite(Xdisplay, PictOpOver,
picture, 0, XftDrawPicture(w.GetXftDraw()),
sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy);
}
else {
if(!picture8) {
Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, 8);
picture8 = XRenderCreatePicture(Xdisplay, pixmap,
XRenderFindStandardFormat(Xdisplay, PictStandardA8),
0, 0);
Buffer<byte> ab(len);
byte *t = ab;
const RGBA *s = ~img;
const RGBA *e = s + len;
while(s < e)
*t++ = (s++)->a;
XImage ximg;
sInitXImage(ximg, sz);
ximg.data = (char *)~ab;
ximg.bitmap_unit = 8;
ximg.bitmap_pad = 8;
ximg.depth = 8;
ximg.bytes_per_line = sz.cx;
ximg.bits_per_pixel = 8;
XInitImage(&ximg);
GC gc = XCreateGC(Xdisplay, pixmap, 0, 0);
XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy);
XFreeGC(Xdisplay, gc);
XFreePixmap(Xdisplay, pixmap);
}
XRenderComposite(Xdisplay, PictOpOver,
sGetSolidFill(c), picture8, XftDrawPicture(w.GetXftDraw()),
sr.left, sr.top, 0, 0, x, y, ssz.cx, ssz.cy);
}
}
struct ImageSysDataMaker : LRUCache<ImageSysData, int64>::Maker {
Image img;
virtual int64 Key() const { return img.GetSerialId(); }
virtual int Make(ImageSysData& object) const { object.Init(img); return img.GetLength(); }
};
void SystemDraw::SysDrawImageOp(int x, int y, const Image& img, const Rect& src, Color color)
{
GuiLock __;
if(img.GetLength() == 0)
return;
LLOG("SysDrawImageOp " << img.GetSerialId() << ' ' << img.GetSize());
ImageSysDataMaker m;
static LRUCache<ImageSysData, int64> cache;
LLOG("SysImage cache pixels " << cache.GetSize() << ", count " << cache.GetCount());
m.img = img;
cache.Get(m).Paint(*this, x, y, src, color);
Size sz = Ctrl::GetPrimaryScreenArea().GetSize();
cache.Shrink(4 * sz.cx * sz.cy, 1000); // Cache must be after Paint because of PaintOnly!
}
void ImageDraw::Init()
{
GuiLock __;
dw = XCreatePixmap(Xdisplay, Xroot, max(size.cx, 1), max(size.cy, 1), Xdepth);
gc = XCreateGC(Xdisplay, dw, 0, 0);
xftdraw = XftDrawCreate(Xdisplay, (Drawable) dw, DefaultVisual(Xdisplay, Xscreenno), Xcolormap);
alpha.dw = XCreatePixmap(Xdisplay, Xroot, max(size.cx, 1), max(size.cy, 1), Xdepth);
alpha.gc = XCreateGC(Xdisplay, alpha.dw, 0, 0);
alpha.xftdraw = XftDrawCreate(Xdisplay, (Drawable) alpha.dw, DefaultVisual(Xdisplay, Xscreenno), Xcolormap);
Vector<Rect> clip;
clip.Add(RectC(0, 0, size.cx, size.cy));
SystemDraw::Init(clip, Point(0, 0));
alpha.Init(clip, Point(0, 0));
has_alpha = false;
}
ImageDraw::operator Image() const
{
GuiLock __;
XImage *xim = XGetImage(Xdisplay, dw, 0, 0, max(size.cx, 1), max(size.cy, 1), AllPlanes, ZPixmap);
if(!xim)
return Null;
Visual *v = DefaultVisual(Xdisplay, Xscreenno);
RasterFormat fmt;
RGBA palette[256];
switch(xim->depth) {
case 15:
case 16:
if(xim->byte_order == LSBFirst)
fmt.Set16le(v->red_mask, v->green_mask, v->blue_mask);
else
fmt.Set16be(v->red_mask, v->green_mask, v->blue_mask);
break;
case 8: {
int n = min(v->map_entries, 256);
XColor colors[256];
for(int i = 0; i < 256; i++) {
colors[i].pixel = i;
colors[i].flags = DoRed|DoGreen|DoBlue;
}
XQueryColors(Xdisplay, Xcolormap, colors, n);
XColor *s = colors;
XColor *e = s + n;
while(s < e) {
RGBA& t = palette[s->pixel];
t.r = s->red >> 8;
t.g = s->green >> 8;
t.b = s->blue >> 8;
t.a = 255;
s++;
}
fmt.Set8();
break;
}
default:
if(xim->bits_per_pixel == 32)
if(xim->byte_order == LSBFirst)
fmt.Set32le(v->red_mask, v->green_mask, v->blue_mask);
else
fmt.Set32be(v->red_mask, v->green_mask, v->blue_mask);
else
if(xim->byte_order == LSBFirst)
fmt.Set24le(v->red_mask, v->green_mask, v->blue_mask);
else
fmt.Set24be(v->red_mask, v->green_mask, v->blue_mask);
break;
}
ImageBuffer ib(size);
const byte *s = (const byte *)xim->data;
RGBA *t = ib;
for(int y = 0; y < size.cy; y++) {
fmt.Read(t, s, size.cx, palette);
s += xim->bytes_per_line;
t += size.cx;
}
XDestroyImage(xim);
if(has_alpha) {
xim = XGetImage(Xdisplay, alpha.dw, 0, 0, max(size.cx, 1), max(size.cy, 1), AllPlanes, ZPixmap);
if(xim) {
const byte *s = (const byte *)xim->data;
t = ib;
Buffer<RGBA> line(size.cx);
for(int y = 0; y < size.cy; y++) {
fmt.Read(line, s, size.cx, palette);
for(int x = 0; x < size.cx; x++)
(t++)->a = line[x].r;
s += xim->bytes_per_line;
}
XDestroyImage(xim);
}
}
Premultiply(ib);
return ib;
}
ImageDraw::ImageDraw(Size sz)
{
size = sz;
Init();
}
ImageDraw::ImageDraw(int cx, int cy)
{
size = Size(cx, cy);
Init();
}
ImageDraw::~ImageDraw()
{
GuiLock __;
XftDrawDestroy(xftdraw);
XFreePixmap(Xdisplay, dw);
XFreeGC(Xdisplay, gc);
XftDrawDestroy(alpha.xftdraw);
XFreePixmap(Xdisplay, alpha.dw);
XFreeGC(Xdisplay, alpha.gc);
}
Draw& ImageDraw::Alpha()
{
if(!has_alpha) {
alpha.DrawRect(size, GrayColor(0));
has_alpha = true;
}
return alpha;
}
Image SystemDraw::X11Cursor(int c)
{
ImageBuffer b(32, 32);
Image m(b);
m.SetAuxData(c + 1);
return m;
}
Image X11Cursor(int c)
{
return SystemDraw::X11Cursor(c);
}
#include <X11/cursorfont.h>
#define FCURSOR_(x) { Image h; INTERLOCKED { static Image m = X11Cursor(x); h = m; } return h; }
Image Image::Arrow() FCURSOR_(XC_left_ptr)
Image Image::Wait() FCURSOR_(XC_watch)
Image Image::IBeam() FCURSOR_(XC_xterm)
Image Image::No() FCURSOR_(XC_circle)
Image Image::SizeAll() FCURSOR_(XC_fleur)
Image Image::SizeHorz() FCURSOR_(XC_sb_h_double_arrow)
Image Image::SizeVert() FCURSOR_(XC_double_arrow)
Image Image::SizeTopLeft() FCURSOR_(XC_top_left_corner)
Image Image::SizeTop() FCURSOR_(XC_top_side)
Image Image::SizeTopRight() FCURSOR_(XC_top_right_corner)
Image Image::SizeLeft() FCURSOR_(XC_left_side)
Image Image::SizeRight() FCURSOR_(XC_right_side)
Image Image::SizeBottomLeft() FCURSOR_(XC_bottom_left_corner)
Image Image::SizeBottom() FCURSOR_(XC_bottom_side)
Image Image::SizeBottomRight() FCURSOR_(XC_bottom_right_corner)
Image Image::Cross() FCURSOR_(XC_crosshair)
Image Image::Hand() FCURSOR_(XC_hand1)
void *CursorX11(const Image& img)
{
return SystemDraw::CursorX11(img);
}
void *SystemDraw::CursorX11(const Image& img)
{
GuiLock __;
int q = (int64)img.GetAuxData() - 1;
if(q >= 0)
return (void *)XCreateFontCursor(Xdisplay, q);
int len = img.GetLength();
Size sz = img.GetSize();
Pixmap pixmap = XCreatePixmap(Xdisplay, Xroot, sz.cx, sz.cy, 32);
XPicture picture = XRenderCreatePicture(
Xdisplay, pixmap,
XRenderFindStandardFormat(Xdisplay, PictStandardARGB32),
0, 0
);
XImage ximg;
sInitXImage(ximg, sz);
ximg.bitmap_pad = 32;
ximg.bytes_per_line = 4 * sz.cx;
ximg.bits_per_pixel = 32;
ximg.blue_mask = 0x00ff0000;
ximg.green_mask = 0x0000ff00;
ximg.red_mask = 0x000000ff;
Buffer<RGBA> pma;
pma.Alloc(len);
memcpy(pma, ~img, len * sizeof(RGBA));
ximg.bitmap_unit = 32;
ximg.depth = 32;
ximg.data = (char *)~pma;
XInitImage(&ximg);
GC gc = XCreateGC(Xdisplay, pixmap, 0, 0);
XPutImage(Xdisplay, pixmap, gc, &ximg, 0, 0, 0, 0, sz.cx, sz.cy);
XFreeGC(Xdisplay, gc);
XFreePixmap(Xdisplay, pixmap);
Point p = img.GetHotSpot();
Cursor c = XRenderCreateCursor(Xdisplay, picture, p.x, p.y);
XRenderFreePicture(Xdisplay, picture);
return (void *)c;
}
END_UPP_NAMESPACE
#endif

View file

@ -1,119 +1,76 @@
#include "CtrlCore.h"
NAMESPACE_UPP
#define LTIMING(x)
void StdDrawImage(SystemDraw& w, int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color)
{
LTIMING("DrawImageOp");
bool tonative = !w.IsNative();
if(tonative) {
w.BeginNative();
w.Native(x, y);
w.Native(cx, cy);
}
Size sz = Size(cx, cy);
if((cx > 2000 || cy > 1500) && IsNull(color) && w.IsPrinter()) {
int yy = 0;
ImageRaster ir(img);
RescaleImage rm;
rm.Create(Size(cx, cy), ir, src);
while(yy < cy) {
int ccy = min(cy - yy, 16);
ImageBuffer ib(cx, ccy);
for(int q = 0; q < ccy; q++)
rm.Get(ib[q]);
DrawImageBandRLE(w, x, y + yy, ib, 16);
yy += ccy;
}
}
else
if(src.GetSize() == sz)
img.PaintImage(w, x, y, src, color);
else {
Image h = Rescale(img, Size(cx, cy), src);
h.PaintImage(w, x, y, h.GetSize(), color);
}
if(tonative)
w.EndNative();
}
ImageBuffer::ImageBuffer(ImageDraw& iw)
{
Image m = iw;
Set(m);
}
void ImageAnyDrawSystem(Draw *(*f)(Size sz), Image (*e)(Draw *w));
static Draw *sCD(Size sz)
{
return new ImageDraw(sz);
}
static Image sED(Draw *w)
{
ImageDraw *ip = dynamic_cast<ImageDraw *>(w);
return ip ? (Image)(*ip) : Image();
}
void InstallSystemImage()
{
Image::Data::InitSystemImage(&Image::Data::SysInitImp, &Image::Data::SysReleaseImp,
&Image::Data::GetResCountImp, &Image::Data::PaintImp);
}
INITBLOCK {
ImageAnyDrawSystem(sCD, sED);
InstallSystemImage();
}
void SetSurface(SystemDraw& w, int x, int y, int cx, int cy, const RGBA *pixels);
void SetSurface(SystemDraw& w, const Rect& dest, const RGBA *pixels, Size psz, Point poff);
void SetSurface(Draw& w, const Rect& dest, const RGBA *pixels, Size srcsz, Point poff)
{
SystemDraw *sw = dynamic_cast<SystemDraw *>(&w);
if(sw && sw->CanSetSurface())
SetSurface(*sw, dest, pixels, srcsz, poff);
else {
ImageBuffer ib(dest.GetWidth(), dest.GetHeight());
for(int i = 0; i < ib.GetHeight(); i++) {
int sl = poff.y + i;
if(i >= 0 && i < srcsz.cy)
Copy(ib[i], pixels + srcsz.cx * sl + poff.x,
minmax(srcsz.cx - poff.x, 0, min(dest.GetWidth(), srcsz.cx)));
}
w.DrawImage(dest.left, dest.top, ib);
}
}
void SetSurface(Draw& w, int x, int y, int cx, int cy, const RGBA *pixels)
{
SetSurface(w, RectC(x, y, cx, cy), pixels, Size(cx, cy), Point(0, 0));
}
SystemDraw& ScreenInfo();
bool BackDraw::IsPaintingOp(const Rect& r) const
{
Rect rr = r + GetOffset();
if(!rr.Intersects(size))
return false;
return painting ? painting->IsPainting(rr + painting_offset) : true;
}
BackDraw::BackDraw()
{
painting = NULL;
painting_offset = Point(0, 0);
}
BackDraw::~BackDraw()
{
Destroy();
}
END_UPP_NAMESPACE
#include "CtrlCore.h"
NAMESPACE_UPP
#define LTIMING(x)
ImageBuffer::ImageBuffer(ImageDraw& iw)
{
Image m = iw;
Set(m);
}
void ImageAnyDrawSystem(Draw *(*f)(Size sz), Image (*e)(Draw *w));
static Draw *sCD(Size sz)
{
return new ImageDraw(sz);
}
static Image sED(Draw *w)
{
ImageDraw *ip = dynamic_cast<ImageDraw *>(w);
return ip ? (Image)(*ip) : Image();
}
INITBLOCK {
ImageAnyDrawSystem(sCD, sED);
}
void SetSurface(SystemDraw& w, int x, int y, int cx, int cy, const RGBA *pixels);
void SetSurface(SystemDraw& w, const Rect& dest, const RGBA *pixels, Size psz, Point poff);
void SetSurface(Draw& w, const Rect& dest, const RGBA *pixels, Size srcsz, Point poff)
{
SystemDraw *sw = dynamic_cast<SystemDraw *>(&w);
if(sw && sw->CanSetSurface())
SetSurface(*sw, dest, pixels, srcsz, poff);
else {
ImageBuffer ib(dest.GetWidth(), dest.GetHeight());
for(int i = 0; i < ib.GetHeight(); i++) {
int sl = poff.y + i;
if(i >= 0 && i < srcsz.cy)
Copy(ib[i], pixels + srcsz.cx * sl + poff.x,
minmax(srcsz.cx - poff.x, 0, min(dest.GetWidth(), srcsz.cx)));
}
w.DrawImage(dest.left, dest.top, ib);
}
}
void SetSurface(Draw& w, int x, int y, int cx, int cy, const RGBA *pixels)
{
SetSurface(w, RectC(x, y, cx, cy), pixels, Size(cx, cy), Point(0, 0));
}
SystemDraw& ScreenInfo();
bool BackDraw::IsPaintingOp(const Rect& r) const
{
Rect rr = r + GetOffset();
if(!rr.Intersects(size))
return false;
return painting ? painting->IsPainting(rr + painting_offset) : true;
}
BackDraw::BackDraw()
{
painting = NULL;
painting_offset = Point(0, 0);
}
BackDraw::~BackDraw()
{
Destroy();
}
END_UPP_NAMESPACE

View file

@ -156,8 +156,8 @@ void TopWindow::SyncCaption0()
DeleteIco();
#ifndef PLATFORM_WINCE //TODO!!!
if(hwnd) {
::SendMessage(hwnd, WM_SETICON, false, (LPARAM)(ico = IconWin32(icon)));
::SendMessage(hwnd, WM_SETICON, true, (LPARAM)(lico = IconWin32(largeicon)));
::SendMessage(hwnd, WM_SETICON, false, (LPARAM)(ico = SystemDraw::IconWin32(icon)));
::SendMessage(hwnd, WM_SETICON, true, (LPARAM)(lico = SystemDraw::IconWin32(largeicon)));
}
#endif
}

View file

@ -19,7 +19,7 @@ public:
virtual Rect GetPaintRect() const;
virtual void DrawRectOp(int x, int y, int cx, int cy, Color color);
virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color);
virtual void SysDrawImageOp(int x, int y, const Image& img, const Rect& src, Color color);
virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color);
virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count,
@ -111,6 +111,7 @@ public:
static void Flush() { GdiFlush(); }
static Image Win32IconCursor(LPCSTR id, int iconsize, bool cursor);
static HICON IconWin32(const Image& img, bool cursor = false);
COLORREF GetColor(Color color) const;
@ -262,7 +263,6 @@ Image Win32Icon(int id, int iconsize = 0);
Image Win32Cursor(LPCSTR id);
Image Win32Cursor(int id);
Image Win32DllIcon(const char *dll, int ii, bool large);
HICON IconWin32(const Image& img, bool cursor = false);
class BackDraw : public SystemDraw {
public:

View file

@ -422,7 +422,7 @@ void Ctrl::SetMouseCursor(const Image& image)
static Image img;
if(image.GetSerialId() != img.GetSerialId()) {
img = image;
HCURSOR hc = IconWin32(img, true);
HCURSOR hc = SystemDraw::IconWin32(img, true);
SetCursor(hc);
if(hCursor)
DestroyCursor(hCursor);

View file

@ -6,7 +6,7 @@
NAMESPACE_UPP
#define LLOG(x) // LOG(x)
#define LLOG(x) // DLOG(x)
XIM Ctrl::xim;

View file

@ -89,7 +89,7 @@ public:
virtual Rect GetPaintRect() const;
virtual void DrawRectOp(int x, int y, int cx, int cy, Color color);
virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color);
virtual void SysDrawImageOp(int x, int y, const Image& img, const Rect& src, Color color);
virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color);
virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count,
@ -154,6 +154,8 @@ private:
public:
static void Flush() { XSync(Xdisplay, false); }
static Image X11Cursor(int c);
static void *CursorX11(const Image& img);
Point GetOffset() const { return actual_offset; }

View file

@ -87,6 +87,7 @@ Size Display::GetStdSize(const Value& q) const
return Single<StdDisplayClass>().GetStdSize(q);
}
void StdDisplayClass::Paint0(Draw& w, const Rect& r, const Value& q,
Color ink, Color paper, dword s) const {
LLOG("StdDisplay::Paint0: " << q << " ink:" << ink << " paper:" << paper);

View file

@ -115,6 +115,48 @@ int Draw::GetCloffLevel() const { return 0; }
// -------------------------------
void Draw::SysDrawImageOp(int x, int y, const Image& img, const Rect& src, Color color)
{
NEVER();
}
void Draw::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color)
{
LTIMING("DrawImageOp");
bool tonative = !IsNative();
if(tonative) {
BeginNative();
Native(x, y);
Native(cx, cy);
}
Size sz = Size(cx, cy);
if((cx > 2000 || cy > 1500) && IsNull(color) && IsPrinter()) {
int yy = 0;
ImageRaster ir(img);
RescaleImage rm;
rm.Create(Size(cx, cy), ir, src);
while(yy < cy) {
int ccy = min(cy - yy, 16);
ImageBuffer ib(cx, ccy);
for(int q = 0; q < ccy; q++)
rm.Get(ib[q]);
DrawImageBandRLE(*this, x, y + yy, ib, 16);
yy += ccy;
}
}
else
if(src.GetSize() == sz)
SysDrawImageOp(x, y, img, src, color);
else {
Image h = Rescale(img, Size(cx, cy), src);
SysDrawImageOp(x, y, h, h.GetSize(), color);
}
if(tonative)
EndNative();
}
// -------------------------------
void Draw::DrawRect(const Rect& rect, Color color)
{
DrawRect(rect.left, rect.top, rect.GetWidth(), rect.GetHeight(), color);

View file

@ -13,32 +13,18 @@ class Painting;
class SystemDraw;
class ImageDraw;
#ifdef _MULTITHREADED
void EnterGMutex();
void EnterGMutex(int n);
void LeaveGMutex();
int LeaveGMutexAll();
struct DrawLock {
DrawLock() { EnterGMutex(); }
~DrawLock() { LeaveGMutex(); }
};
#else
inline void EnterGMutex() {}
inline void EnterGMutex(int n) {}
inline void LeaveGMutex() {}
inline int LeaveGMutexAll() { return 0; }
struct DrawLock {
DrawLock() {}
~DrawLock() {}
};
#endif
#include "Image.h"
const int FONT_V = 40;
struct FontGlyphConsumer {
virtual void Move(Pointf p) = 0;
virtual void Line(Pointf p) = 0;
virtual void Quadratic(Pointf p1, Pointf p2) = 0;
virtual void Cubic(Pointf p1, Pointf p2, Pointf p3) = 0;
virtual void Close() = 0;
};
#include "FontInt.h"
class FontInfo;
@ -72,7 +58,8 @@ class Font : public ValueType<Font, FONT_V, Moveable<Font> >{
const CommonFontInfo& Fi() const;
friend void sInitFonts();
friend void sInitFonts();
friend String GetFontDataSys(Font font);
public:
enum {
@ -174,12 +161,12 @@ public:
bool IsScaleable() const { return Fi().scaleable; }
bool IsSpecial() const { return !(GetFaceInfo() & SPECIAL); }
#ifdef PLATFORM_POSIX
String GetPath() const { return Fi().path; }
#endif
String GetTextFlags() const;
void ParseTextFlags(const char *s);
String GetData() const;
void Render(FontGlyphConsumer& sw, double x, double y, int ch) const;
void Serialize(Stream& s);
void Jsonize(JsonIO& jio);
@ -227,9 +214,6 @@ public:
bool IsScaleable() const { return font.IsScaleable(); }
int GetFontHeight() const { return font.GetHeight(); }
Font GetFont() const { return font; }
#ifdef PLATFORM_POSIX
String GetFileName() const { return font.GetPath(); }
#endif
};
struct ComposedGlyph {
@ -386,8 +370,8 @@ public:
void Clear() { size = Null; data.Clear(); cmd.Clear(); }
void Serialize(Stream& s) { s % cmd % data % size; }
void Xmlize(XmlIO& xio) { XmlizeBySerialize(xio, *this); }
void Jsonize(JsonIO& jio) { JsonizeBySerialize(jio, *this); }
void Xmlize(XmlIO& xio) { XmlizeBySerialize(xio, *this); }
void Jsonize(JsonIO& jio) { JsonizeBySerialize(jio, *this); }
bool IsNullInstance() const { return cmd.IsEmpty(); }
void SetNull() { size = Null; }
bool operator==(const Painting& b) const { return cmd == b.cmd && data == b.data && size == b.size; }
@ -442,7 +426,8 @@ public:
virtual Rect GetPaintRect() const;
virtual void DrawRectOp(int x, int y, int cx, int cy, Color color) = 0;
virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) = 0;
virtual void SysDrawImageOp(int x, int y, const Image& img, const Rect& src, Color color);
virtual void DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color);
virtual void DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id);
virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) = 0;
@ -652,7 +637,7 @@ public:
void Jsonize(JsonIO& jio) { JsonizeBySerialize(jio, *this); }
bool IsNullInstance() const { return data.IsEmpty(); }
void SetNull() { size = Null; }
void SetNull() { size = Null; data.Clear(); }
bool operator==(const Drawing& b) const { return val == b.val && data == b.data && size == b.size; }
String ToString() const { return "drawing " + AsString(size); }

View file

@ -22,7 +22,6 @@ library(FREEBSD) xcb;
file
Draw.h,
DrawLock.cpp,
FontInt.h,
Font.cpp,
FontCR.cpp,

View file

@ -15,17 +15,16 @@ static StaticCriticalSection sDataDrawer;
void DataDrawer::AddFormat(const char *id, Factory factory)
{
INTERLOCKED_(sDataDrawer)
Map().Add(id, (void *)factory);
Mutex::Lock __(sDataDrawer);
Map().Add(id, (void *)factory);
}
One<DataDrawer> DataDrawer::Create(const String& id)
{
INTERLOCKED_(sDataDrawer) {
Factory q = (Factory) Map().Get(id, NULL);
if(q)
return (*q)();
}
Mutex::Lock __(sDataDrawer);
Factory q = (Factory) Map().Get(id, NULL);
if(q)
return (*q)();
return NULL;
}
@ -92,7 +91,6 @@ void DrawImageBandRLE(Draw& w, int x, int y, const Image& m, int minp)
void Draw::DrawDataOp(int x, int y, int cx, int cy, const String& data, const char *id)
{
DrawLock __;
bool tonative = !IsNative();
if(tonative) {
BeginNative();
@ -102,7 +100,7 @@ void Draw::DrawDataOp(int x, int y, int cx, int cy, const String& data, const ch
One<DataDrawer> dd = DataDrawer::Create(id);
if(dd) {
dd->Open(data, cx, cy);
if((cx > 2048 || cy > 2048) && GetInfo() & DATABANDS) {
if((cx > 2048 || cy > 2048) && (GetInfo() & DATABANDS)) {
int yy = 0;
while(yy < cy) {
int ccy = min(cy - yy, 32);

View file

@ -1,51 +0,0 @@
#include "Draw.h"
#define LLOG(x)
NAMESPACE_UPP
#ifdef _MULTITHREADED
static StaticMutex sGLock;
static thread__ int sGLockLevel = 0;
void EnterGMutex()
{
if(sGLockLevel++ == 0)
sGLock.Enter();
LLOG("EnterGMutex");
}
void EnterGMutex(int n)
{
if(n > 0) {
if(sGLockLevel == 0)
sGLock.Enter();
sGLockLevel += n;
}
LLOG("EnterGMutex " << n);
}
void LeaveGMutex()
{
ASSERT(sGLockLevel > 0);
if(--sGLockLevel == 0)
sGLock.Leave();
LLOG("LeaveGMutex");
}
int LeaveGMutexAll()
{
int q = sGLockLevel;
if(q) {
sGLock.Leave();
sGLockLevel = 0;
}
LLOG("LeaveGMutex all");
return q;
}
#endif
END_UPP_NAMESPACE

File diff suppressed because it is too large Load diff

View file

@ -1,238 +1,369 @@
#include "Draw.h"
#define LLOG(x) // LOG(x)
#define LTIMING(x) // TIMING(x)
#ifdef PLATFORM_POSIX
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
NAMESPACE_UPP
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)
{
LTIMING("CreateXftFont");
int hg = abs(font.GetHeight());
if(hg == 0) hg = 10;
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);
FcConfigSubstitute(0, p, FcMatchPattern);
FcDefaultSubstitute(p);
FcResult result;
FcPattern *m = FcFontMatch(0, p, &result);
FcPatternDestroy(p);
return m;
}
FT_Face CreateFTFace(const FcPattern *pattern, String *rpath) {
FT_Face face = NULL;
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;
};
static FtFaceEntry ft_cache[FONTCACHE];
void ClearFtFaceCache()
{
for(int i = 0; i < FONTCACHE; i++)
ft_cache[i].font.Height(-30000);
}
FT_Face (*FTFaceXft)(Font fnt, String *rpath);
FT_Face FTFace(Font fnt, String *rpath = NULL)
{
LTIMING("FTFace");
if(FTFaceXft)
return (*FTFaceXft)(fnt, rpath);
ONCELOCK {
ClearFtFaceCache();
}
FtFaceEntry be;
be = ft_cache[0];
for(int i = 0; i < FONTCACHE; i++) {
FtFaceEntry e = ft_cache[i];
if(i)
ft_cache[i] = be;
if(e.font == fnt) {
if(rpath)
*rpath = e.path;
if(i)
ft_cache[0] = e;
return e.face;
}
be = e;
}
LTIMING("FTFace2");
if(be.face) {
LLOG("Removing " << be.font << " - " << (void *)be.face);
FT_Done_Face(be.face);
}
be.font = fnt;
FcPattern *p = CreateFcPattern(fnt);
be.face = CreateFTFace(p, &be.path);
FcPatternDestroy(p);
ft_cache[0] = be;
if(rpath)
*rpath = be.path;
return be.face;
}
CommonFontInfo (*GetFontInfoSysXft)(Font font);
CommonFontInfo GetFontInfoSys(Font font)
{
sInitFt();
if(GetFontInfoSysXft)
return (*GetFontInfoSysXft)(font);
CommonFontInfo fi;
String path;
FT_Face face = FTFace(font, &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;
if(path.GetCount() < 250)
strcpy(fi.path, ~path);
else
*fi.path = 0;
}
return fi;
}
#define FLOOR(x) ((x) & -64)
#define CEIL(x) (((x)+63) & -64)
#define TRUNC(x) ((x) >> 6)
#define ROUND(x) (((x)+32) & -64)
GlyphInfo (*GetGlyphInfoSysXft)(Font font, int chr);
GlyphInfo GetGlyphInfoSys(Font font, int chr)
{
LTIMING("GetGlyphInfoSys");
GlyphInfo gi;
FT_Face face = FTFace(font, NULL);
gi.lspc = gi.rspc = 0;
gi.width = 0x8000;
if(face) {
LTIMING("GetGlyphInfoSys 2");
int glyph_index = FT_Get_Char_Index(face, chr);
if(glyph_index) {
if(GetGlyphInfoSysXft)
return (*GetGlyphInfoSysXft)(font, chr);
if(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",
};
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) ? Font::SCALEABLE|Font::FIXEDPITCH : Font::SCALEABLE;
}
FcPattern *p = FcPatternCreate();
FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, FC_SPACING, FC_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;
}
END_UPP_NAMESPACE
#endif
#include "Draw.h"
#define LLOG(x) // LOG(x)
#define LTIMING(x) // TIMING(x)
#ifndef CUSTOM_FONTSYS
#ifdef PLATFORM_POSIX
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
NAMESPACE_UPP
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)
{
LTIMING("CreateXftFont");
int hg = abs(font.GetHeight());
if(hg == 0) hg = 10;
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);
FcConfigSubstitute(0, p, FcMatchPattern);
FcDefaultSubstitute(p);
FcResult result;
FcPattern *m = FcFontMatch(0, p, &result);
FcPatternDestroy(p);
return m;
}
FT_Face CreateFTFace(const FcPattern *pattern, String *rpath) {
FT_Face face = NULL;
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;
};
static FtFaceEntry ft_cache[FONTCACHE];
void ClearFtFaceCache()
{
for(int i = 0; i < FONTCACHE; i++)
ft_cache[i].font.Height(-30000);
}
FT_Face (*FTFaceXft)(Font fnt, String *rpath);
FT_Face FTFace(Font fnt, String *rpath = NULL)
{
LTIMING("FTFace");
if(FTFaceXft)
return (*FTFaceXft)(fnt, rpath);
ONCELOCK {
ClearFtFaceCache();
}
FtFaceEntry be;
be = ft_cache[0];
for(int i = 0; i < FONTCACHE; i++) {
FtFaceEntry e = ft_cache[i];
if(i)
ft_cache[i] = be;
if(e.font == fnt) {
if(rpath)
*rpath = e.path;
if(i)
ft_cache[0] = e;
return e.face;
}
be = e;
}
LTIMING("FTFace2");
if(be.face) {
LLOG("Removing " << be.font << " - " << (void *)be.face);
FT_Done_Face(be.face);
}
be.font = fnt;
FcPattern *p = CreateFcPattern(fnt);
be.face = CreateFTFace(p, &be.path);
FcPatternDestroy(p);
ft_cache[0] = be;
if(rpath)
*rpath = be.path;
return be.face;
}
CommonFontInfo (*GetFontInfoSysXft)(Font font);
CommonFontInfo GetFontInfoSys(Font font)
{
sInitFt();
if(GetFontInfoSysXft)
return (*GetFontInfoSysXft)(font);
CommonFontInfo fi;
String path;
FT_Face face = FTFace(font, &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;
if(path.GetCount() < 250)
strcpy(fi.path, ~path);
else
*fi.path = 0;
}
return fi;
}
#define FLOOR(x) ((x) & -64)
#define CEIL(x) (((x)+63) & -64)
#define TRUNC(x) ((x) >> 6)
#define ROUND(x) (((x)+32) & -64)
GlyphInfo (*GetGlyphInfoSysXft)(Font font, int chr);
GlyphInfo GetGlyphInfoSys(Font font, int chr)
{
LTIMING("GetGlyphInfoSys");
GlyphInfo gi;
FT_Face face = FTFace(font, NULL);
gi.lspc = gi.rspc = 0;
gi.width = 0x8000;
if(face) {
LTIMING("GetGlyphInfoSys 2");
int glyph_index = FT_Get_Char_Index(face, chr);
if(glyph_index) {
if(GetGlyphInfoSysXft)
return (*GetGlyphInfoSysXft)(font, chr);
if(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",
};
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) ? Font::SCALEABLE|Font::FIXEDPITCH : Font::SCALEABLE;
}
FcPattern *p = FcPatternCreate();
FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, FC_SPACING, FC_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;
}
String GetFontDataSys(Font font)
{
return LoadFile(font.Fi().path);
}
static inline double ft_dbl(int p)
{
return double(p) / 64.0;
}
bool RenderOutline(const FT_Outline& outline, FontGlyphConsumer& path, double xx, double yy)
{
FT_Vector v_last;
FT_Vector v_control;
FT_Vector v_start;
FT_Vector* point;
FT_Vector* limit;
char* tags;
int n; // index of contour in outline
char tag; // current point's state
int first = 0; // index of first point in contour
for(n = 0; n < outline.n_contours; n++) {
int last = outline.contours[n];
limit = outline.points + last;
v_start = outline.points[first];
v_last = outline.points[last];
v_control = v_start;
point = outline.points + first;
tags = outline.tags + first;
tag = FT_CURVE_TAG(tags[0]);
if(tag == FT_CURVE_TAG_CUBIC) return false;
if(tag == FT_CURVE_TAG_CONIC) {
if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) {
// start at last point if it is on the curve
v_start = v_last;
limit--;
}
else {
// if both first and last points are conic,
// start at their middle and record its position
// for closure
v_start.x = (v_start.x + v_last.x) / 2;
v_start.y = (v_start.y + v_last.y) / 2;
v_last = v_start;
}
point--;
tags--;
}
path.Move(Pointf(ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy));
while(point < limit) {
point++;
tags++;
tag = FT_CURVE_TAG(tags[0]);
switch(tag) {
case FT_CURVE_TAG_ON:
path.Line(Pointf(ft_dbl(point->x) + xx, -ft_dbl(point->y) + yy));
continue;
case FT_CURVE_TAG_CONIC:
v_control.x = point->x;
v_control.y = point->y;
Do_Conic:
if(point < limit) {
FT_Vector vec;
FT_Vector v_middle;
point++;
tags++;
tag = FT_CURVE_TAG(tags[0]);
vec.x = point->x;
vec.y = point->y;
if(tag == FT_CURVE_TAG_ON) {
path.Quadratic(Pointf(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy),
Pointf(ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy));
continue;
}
if(tag != FT_CURVE_TAG_CONIC) return false;
v_middle.x = (v_control.x + vec.x) / 2;
v_middle.y = (v_control.y + vec.y) / 2;
path.Quadratic(Pointf(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy),
Pointf(ft_dbl(v_middle.x) + xx, -ft_dbl(v_middle.y) + yy));
v_control = vec;
goto Do_Conic;
}
path.Quadratic(Pointf(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy),
Pointf(ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy));
goto Close;
default:
FT_Vector vec1, vec2;
if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC)
return false;
vec1.x = point[0].x;
vec1.y = point[0].y;
vec2.x = point[1].x;
vec2.y = point[1].y;
point += 2;
tags += 2;
if(point <= limit) {
FT_Vector vec;
vec.x = point->x;
vec.y = point->y;
path.Cubic(Pointf(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy),
Pointf(ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy),
Pointf(ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy));
continue;
}
path.Cubic(Pointf(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy),
Pointf(ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy),
Pointf(ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy));
goto Close;
}
}
Close:
path.Close();
first = last + 1;
}
return true;
}
void RenderCharacterSys(FontGlyphConsumer& sw, double x, double y, int ch, Font fnt)
{
FT_Face face = FTFace(fnt, NULL);
int glyph_index = FT_Get_Char_Index(face, ch);
if(glyph_index && FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0)
RenderOutline(face->glyph->outline, sw, x, y + fnt.GetAscent());
}
END_UPP_NAMESPACE
#endif
#endif

View file

@ -1,54 +1,62 @@
#ifndef _Draw_FontInt_h_
#define _Draw_FontInt_h_
// Internal header!
struct FaceInfo : Moveable<FaceInfo> {
String name;
dword info;
};
struct 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
char path[256];
#endif
};
class Font;
struct 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
#ifndef _Draw_FontInt_h_
#define _Draw_FontInt_h_
// Implementation header
struct FaceInfo : Moveable<FaceInfo> {
String name;
dword info;
};
struct 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;
char path[256]; // optional
};
class Font;
struct 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);
// Platform specific font interface
CommonFontInfo GetFontInfoSys(Font font);
GlyphInfo GetGlyphInfoSys(Font font, int chr);
void GetStdFontSys(String& name, int& height);
Vector<FaceInfo> GetAllFacesSys();
String GetFontDataSys(Font font);
void RenderCharacterSys(FontGlyphConsumer& sw, double x, double y, int ch, Font fnt);
#endif

View file

@ -2,6 +2,8 @@
NAMESPACE_UPP
#ifndef CUSTOM_FONTSYS
#ifdef PLATFORM_WIN32
#define LLOG(x) // LOG(x)
@ -350,6 +352,89 @@ GlyphInfo GetGlyphInfoSys(Font font, int chr)
}
#endif
String GetFontDataSys(Font font)
{
String r;
HFONT hfont = GetWin32Font(font, 0);
if(hfont) {
HDC hdc = Win32_IC();
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
DWORD size = GetFontData(hdc, 0, 0, NULL, 0);
if(size == GDI_ERROR) {
LLOG("PdfDraw::Finish: GDI_ERROR on font " << pdffont.GetKey(i));
return Null;
}
StringBuffer b(size);
GetFontData(hdc, 0, 0, b, size);
::SelectObject(hdc, ohfont);
r = b;
}
return r;
}
double fx_to_dbl(const FIXED& p) {
return double(p.value) + double(p.fract) * (1.0 / 65536.0);
}
Pointf fx_to_dbl(const Pointf& pp, const POINTFX& p) {
return Pointf(pp.x + fx_to_dbl(p.x), pp.y - fx_to_dbl(p.y));
}
void RenderCharPath(const char* gbuf, unsigned total_size, FontGlyphConsumer& sw, double xx, double yy)
{
const char* cur_glyph = gbuf;
const char* end_glyph = gbuf + total_size;
Pointf pp(xx, yy);
while(cur_glyph < end_glyph) {
const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
const char* end_poly = cur_glyph + th->cb;
const char* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
sw.Move(fx_to_dbl(pp, th->pfxStart));
while(cur_poly < end_poly) {
const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
if (pc->wType == TT_PRIM_LINE)
for(int i = 0; i < pc->cpfx; i++)
sw.Line(fx_to_dbl(pp, pc->apfx[i]));
if (pc->wType == TT_PRIM_QSPLINE)
for(int u = 0; u < pc->cpfx - 1; u++) {
Pointf b = fx_to_dbl(pp, pc->apfx[u]);
Pointf c = fx_to_dbl(pp, pc->apfx[u + 1]);
if (u < pc->cpfx - 2)
c = Mid(b, c);
sw.Quadratic(b, c);
}
cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
}
sw.Close();
cur_glyph += th->cb;
}
}
void RenderCharacterSys(FontGlyphConsumer& sw, double x, double y, int ch, Font fnt)
{
HFONT hfont = GetWin32Font(fnt, 0);
if(hfont) {
HDC hdc = Win32_IC();
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
GLYPHMETRICS gm;
MAT2 m_matrix;
memset(&m_matrix, 0, sizeof(m_matrix));
m_matrix.eM11.value = 1;
m_matrix.eM22.value = 1;
int gsz = GetGlyphOutlineW(hdc, ch, GGO_NATIVE, &gm, 0, NULL, &m_matrix);
if(gsz < 0)
return;
StringBuffer gb(gsz);
gsz = GetGlyphOutlineW(hdc, ch, GGO_NATIVE, &gm, gsz, ~gb, &m_matrix);
if(gsz < 0)
return;
RenderCharPath(~gb, gsz, sw, x, y + fnt.GetAscent());
::SelectObject(hdc, ohfont);
}
}
#endif
#endif
END_UPP_NAMESPACE

View file

@ -122,49 +122,6 @@ Size ImageBuffer::GetDPI()
return Size(dots.cx ? int(600.*size.cx/dots.cx) : 0, dots.cy ? int(600.*size.cy/dots.cy) : 0);
}
void (Image::Data::*Image::Data::sSysInit)();
void (Image::Data::*Image::Data::sSysRelease)();
int (Image::Data::*Image::Data::sGetResCount)() const;
void (Image::Data::*Image::Data::sPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c);
void Image::Data::InitSystemImage(
void (Image::Data::*fSysInit)(),
void (Image::Data::*fSysRelease)(),
int (Image::Data::*fGetResCount)() const,
void (Image::Data::*fPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c)
)
{
Image::Data::sSysInit = fSysInit;
Image::Data::sSysRelease = fSysRelease;
Image::Data::sGetResCount = fGetResCount;
Image::Data::sPaint = fPaint;
}
void Image::Data::SysInit()
{
if(sSysInit)
(this->*sSysInit)();
}
void Image::Data::SysRelease()
{
if(sSysRelease)
(this->*sSysRelease)();
}
int Image::Data::GetResCount() const
{
if(sGetResCount)
return (this->*sGetResCount)();
return 0;
}
void Image::Data::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c)
{
if(sPaint)
(this->*sPaint)(w, x, y, src, c);
}
void Image::Set(ImageBuffer& b)
{
if(b.GetWidth() == 0 || b.GetHeight() == 0)
@ -267,12 +224,6 @@ int Image::GetKind() const
return data ? data->GetKind() : IMAGE_EMPTY;
}
void Image::PaintImage(SystemDraw& w, int x, int y, const Rect& src, Color c) const
{
if(data)
data->Paint(w, x, y, src, c);
}
void Image::Serialize(Stream& s)
{
int version = 0;
@ -372,38 +323,28 @@ String Image::ToString() const
return String("Image ").Cat() << GetSize();
}
Link<Image::Data> Image::Data::ResData[1];
int Image::Data::ResCount;
Image::Data::Data(ImageBuffer& b)
: buffer(b)
{
paintcount = 0;
paintonly = false;
refcount = 1;
aux_data = 0;
INTERLOCKED {
static int64 gserial;
serial = ++gserial;
}
SysInit();
}
Image::Data::~Data()
void Image::SetAuxData(uint64 adata)
{
DrawLock __;
SysRelease();
Unlink();
if(data)
data->aux_data = adata;
}
void Image::Data::PaintOnlyShrink()
uint64 Image::GetAuxData() const
{
if(paintonly) {
LTIMING("PaintOnlyShrink");
DrawLock __;
DropPixels___(buffer);
ResCount -= GetResCount();
Unlink();
}
return data ? data->aux_data : 0;
}
static void sMultiply(ImageBuffer& b, int (*op)(RGBA *t, const RGBA *s, int len))
@ -444,12 +385,6 @@ Image Unmultiply(const Image& img)
return sMultiply(img, Unmultiply);
}
void SetPaintOnly___(Image& m)
{
if(m.data && m.data->refcount == 1)
m.data->paintonly = true;
}
void Iml::Init(int n)
{
for(int i = 0; i < n; i++)
@ -469,11 +404,13 @@ void Iml::Set(int i, const Image& img)
map[i].loaded = true;
}
static StaticMutex sImlLock;
Image Iml::Get(int i)
{
IImage& m = map[i];
if(!m.loaded) {
DrawLock __;
Mutex::Lock __(sImlLock);
if(data.GetCount()) {
int ii = 0;
for(;;) {
@ -568,13 +505,13 @@ Iml& GetIml(int i)
String GetImlName(int i)
{
DrawLock __;
Mutex::Lock __(sImlLock);
return sImgMap().GetKey(i);
}
int FindIml(const char *name)
{
DrawLock __;
Mutex::Lock __(sImlLock);
return sImgMap().Find(name);
}
@ -583,7 +520,7 @@ Image GetImlImage(const char *name)
Image m;
const char *w = strchr(name, ':');
if(w) {
DrawLock __;
Mutex::Lock __(sImlLock);
int q = FindIml(String(name, w));
if(q >= 0) {
Iml& iml = *sImgMap()[q];
@ -601,7 +538,7 @@ void SetImlImage(const char *name, const Image& m)
{
const char *w = strchr(name, ':');
if(w) {
DrawLock __;
Mutex::Lock __(sImlLock);
int q = FindIml(String(name, w));
if(q >= 0) {
Iml& iml = *sImgMap()[q];

View file

@ -1,345 +1,293 @@
#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 TransformComponents(RGBA *t, const RGBA *s, int len,
const byte r[], const byte g[], const byte b[], const byte a[]);
void MultiplyComponents(RGBA *t, const RGBA *s, int len, int num, int den = 256);
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 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 SetHotSpots(const Image& src);
void SetDots(Size sz) { dots = sz; }
Size GetDots() const { return dots; }
void SetDPI(Size sz);
Size GetDPI();
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; }
RGBA *Begin() { return pixels; }
const RGBA *Begin() const { return pixels; }
RGBA *End() { return pixels + GetLength(); }
const RGBA *End() const { return pixels + GetLength(); }
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(ImageBuffer& b);
// BW, defined in CtrlCore:
ImageBuffer(ImageDraw& iw);
};
void Premultiply(ImageBuffer& b);
void Unmultiply(ImageBuffer& b);
class Image : public ValueType< 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);
#endif
ImageBuffer buffer;
bool paintonly;
void SysInitImp();
void SysReleaseImp();
int GetResCountImp() const;
void PaintImp(SystemDraw& w, int x, int y, const Rect& src, Color c);
void SysInit();
void SysRelease();
int GetResCount() const;
void Paint(SystemDraw& w, int x, int y, const Rect& src, Color c);
int GetKind();
void PaintOnlyShrink();
Data(ImageBuffer& b);
~Data();
static void (Image::Data::*sSysInit)();
static void (Image::Data::*sSysRelease)();
static int (Image::Data::*sGetResCount)() const;
static void (Image::Data::*sPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c);
friend void InstallSystemImage();
static void InitSystemImage(
void (Image::Data::*fSysInit)(),
void (Image::Data::*fSysRelease)(),
int (Image::Data::*fGetResCount)() const,
void (Image::Data::*fPaint)(SystemDraw& w, int x, int y, const Rect& src, Color c)
);
};
Data *data;
static Link<Image::Data> ResData[1];
static int ResCount;
void Set(ImageBuffer& b);
friend class ImageBuffer;
friend struct Data;
friend void SetPaintOnly___(Image& m);
friend void DrawImageBandRLE(Draw& w, int x, int y, const Image& m, int minp);
friend void InstallSystemImage();
#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_POSIX // These are only implemented for X11...
void SetCursorCheat(int id);
int GetCursorCheat() const;
friend void *CursorX11(const Image&);
friend Image X11Cursor(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;
Size GetDPI();
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 Xmlize(XmlIO& xio) { XmlizeBySerialize(xio, *this); }
void Jsonize(JsonIO& jio) { JsonizeBySerialize(jio, *this); }
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();
void PaintImage(SystemDraw& w, int x, int y, const Rect& src, Color c) const;
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 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"
#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 TransformComponents(RGBA *t, const RGBA *s, int len,
const byte r[], const byte g[], const byte b[], const byte a[]);
void MultiplyComponents(RGBA *t, const RGBA *s, int len, int num, int den = 256);
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 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 SetHotSpots(const Image& src);
void SetDots(Size sz) { dots = sz; }
Size GetDots() const { return dots; }
void SetDPI(Size sz);
Size GetDPI();
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; }
RGBA *Begin() { return pixels; }
const RGBA *Begin() const { return pixels; }
RGBA *End() { return pixels + GetLength(); }
const RGBA *End() const { return pixels + GetLength(); }
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(ImageBuffer& b);
// BW, defined in CtrlCore:
ImageBuffer(ImageDraw& iw);
};
void Premultiply(ImageBuffer& b);
void Unmultiply(ImageBuffer& b);
class Image : public ValueType< Image, 150, Moveable<Image> > {
private:
struct Data {
Atomic refcount;
int64 serial;
uint64 aux_data;
int paintcount;
void Retain() { AtomicInc(refcount); }
void Release() { if(AtomicDec(refcount) == 0) delete this; }
ImageBuffer buffer;
bool paintonly;
int GetKind();
Data(ImageBuffer& b);
};
Data *data;
void Set(ImageBuffer& b);
friend class ImageBuffer;
friend struct Data;
friend class SystemDraw;
friend void SetPaintOnly__(Image& img) { img.data->paintonly = true; }
friend void SysImageRealized(const Image& img);
void SetAuxData(uint64 data);
uint64 GetAuxData() const;
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;
Size GetDPI();
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 Xmlize(XmlIO& xio) { XmlizeBySerialize(xio, *this); }
void Jsonize(JsonIO& jio) { JsonizeBySerialize(jio, *this); }
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); }
bool IsPaintOnly() const { return data && data->paintonly; }
Image() { data = NULL; }
Image(const Nuller&) { data = NULL; }
Image(const Value& src);
Image(const Image& img);
Image(Image (*fn)());
Image(ImageBuffer& b);
~Image();
// Defined in CtrlCore or by Rainbow:
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 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"

View file

@ -142,6 +142,9 @@ struct ImageMaker {
virtual ~ImageMaker() {}
};
void SysImageRealized(const Image& img); // SystemDraw realized Image handle in GUI
void SysImageReleased(const Image& img); // SystemDraw dropped Image handle
Image MakeImage(const ImageMaker& m);
Image MakeImage(const Image& image, Image (*make)(const Image& image));

View file

@ -1,179 +1,232 @@
#include "Draw.h"
NAMESPACE_UPP
#define LLOG(x) // LOG(x)
static StaticCriticalSection sMakeImage;
static LRUCache<Image>& sImageCache()
{
static LRUCache<Image> m;
return m;
}
struct scImageMaker : LRUCache<Image>::Maker {
const ImageMaker *m;
bool paintonly;
virtual String Key() const {
return m->Key();
}
virtual int Make(Image& object) const {
object = m->Make();
if(paintonly) {
SetPaintOnly___(object);
return object.GetLength() + 20000;
}
return object.GetLength() + 100;
}
};
static int sMaxSize;
static int sMaxSizeMax = 1000000;
void ClearMakeImageCache()
{
INTERLOCKED_(sMakeImage) {
sImageCache().Clear();
}
}
void SetMakeImageCacheMax(int m)
{
INTERLOCKED_(sMakeImage) {
sMaxSizeMax = m;
}
}
void SetMakeImageCacheSize(int m)
{
INTERLOCKED_(sMakeImage) {
sMaxSize = m;
}
}
void SweepMkImageCache()
{
INTERLOCKED_(sMakeImage) {
LRUCache<Image>& cache = sImageCache();
cache.ClearCounters();
}
}
Image MakeImage__(const ImageMaker& m, bool paintonly)
{
Image result;
INTERLOCKED_(sMakeImage) {
LRUCache<Image>& cache = sImageCache();
scImageMaker cm;
cm.m = &m;
cm.paintonly = paintonly;
result = cache.Get(cm);
int q = min(3 * (cache.GetFoundSize() + cache.GetNewSize()), sMaxSizeMax);
if(q > sMaxSize)
sMaxSize = q;
cache.Shrink(sMaxSize);
}
return result;
}
Image MakeImage(const ImageMaker& m)
{
return MakeImage__(m, false);
}
Image MakeImagePaintOnly(const ImageMaker& m)
{
return MakeImage__(m, true);
}
class SimpleImageMaker : public ImageMaker {
Image (*make)(const Image& image);
Image image;
public:
virtual String Key() const;
virtual Image Make() const;
SimpleImageMaker(const Image& image, Image (*make)(const Image& image))
: make(make),image(image) {}
};
String SimpleImageMaker::Key() const
{
String key;
int64 k = image.GetSerialId();
key.Cat((const char *)&k, sizeof(int64));
key.Cat((const char *)&make, sizeof(make));
return key;
}
Image SimpleImageMaker::Make() const
{
return (*make)(image);
}
Image MakeImage(const Image& image, Image (*make)(const Image& image))
{
return MakeImage(SimpleImageMaker(image, make));
}
struct sCachedRescale : public ImageMaker
{
Rect src;
Size sz;
Image img;
virtual String Key() const {
StringBuffer h;
RawCat(h, src.left);
RawCat(h, src.top);
RawCat(h, src.right);
RawCat(h, src.bottom);
RawCat(h, sz.cx);
RawCat(h, sz.cy);
RawCat(h, img.GetSerialId());
return h;
}
virtual Image Make() const {
return Rescale(img, sz, src);
}
};
Image CachedRescale(const Image& m, Size sz, const Rect& src)
{
if(m.GetSize() == sz)
return m;
sCachedRescale cr;
cr.sz = sz;
cr.src = src;
cr.img = m;
return MakeImage(cr);
}
Image CachedRescale(const Image& m, Size sz)
{
return CachedRescale(m, sz, m.GetSize());
}
Image CachedRescalePaintOnly(const Image& m, Size sz, const Rect& src)
{
if(m.GetSize() == sz)
return m;
sCachedRescale cr;
cr.sz = sz;
cr.src = src;
cr.img = m;
return MakeImagePaintOnly(cr);
}
Image CachedRescalePaintOnly(const Image& m, Size sz)
{
return CachedRescalePaintOnly(m, sz, m.GetSize());
}
END_UPP_NAMESPACE
#include "Draw.h"
NAMESPACE_UPP
#define LLOG(x) // DLOG(x)
static StaticCriticalSection sMakeImage;
// SystemDraw image cache can get destructed later than maker cache invoking SysImageReleased
static bool sFinished;
struct ImageMakeCacheClass : LRUCache<Image> {
~ImageMakeCacheClass() { sFinished = true; }
};
static LRUCache<Image>& sImageCache()
{
static ImageMakeCacheClass m;
return m;
}
struct scImageMaker : LRUCache<Image>::Maker {
const ImageMaker *m;
bool paintonly;
virtual String Key() const {
return m->Key();
}
virtual int Make(Image& object) const {
object = m->Make();
LLOG("ImageMaker " << object.GetSerialId() << ", size " << object.GetSize() << ", paintonly: " << paintonly);
if(paintonly)
SetPaintOnly__(object);
return object.GetLength() + 100;
}
};
static int sMaxSize;
static int sMaxSizeMax = 1000000;
int ImageSizeAdjuster(const Image& img)
{
return ~img ? img.GetLength() + 100 : 100;
}
void SysImageRealized(const Image& img)
{ // CtrlCore created handle for img, no need to keep pixels data in cache if it is paintonly kind
if(sFinished)
return;
LLOG("SysImageRealized " << img.GetSize());
if(img.data && img.data->paintonly) {
LLOG("Dropping PAINTONLY image " << img.GetSerialId() << " pixels, cache size: " << sImageCache().GetSize() << ", img " << img.GetLength());
DropPixels___(img.data->buffer);
sImageCache().AdjustSize(ImageSizeAdjuster);
LLOG("After drop, cache size: " << sImageCache().GetSize());
}
}
struct ImageRemover {
int64 serial_id;
bool operator()(const Image& img) const {
if(serial_id == img.GetSerialId()) {
LLOG("ImageCache Removing " << serial_id);
return true;
}
return false;
}
};
void SysImageReleased(const Image& img)
{ // CtrlCore removed handle for img, have to remove paintonly
if(sFinished)
return;
if(!~img) {
ImageRemover ir;
ir.serial_id = img.GetSerialId();
LLOG("SysImageReleased " << img.GetSerialId() << ", cache size: " << sImageCache().GetSize() << ", count " << sImageCache().GetCount());
int n = sImageCache().RemoveOne(ir);
LLOG("SysImageReleased count: " << n);
LLOG("SysImageReleased done cache size: " << sImageCache().GetSize() << ", count " << sImageCache().GetCount());
}
}
void ClearMakeImageCache()
{
INTERLOCKED_(sMakeImage) {
sImageCache().Clear();
}
}
void SetMakeImageCacheMax(int m)
{
INTERLOCKED_(sMakeImage) {
sMaxSizeMax = m;
}
}
void SetMakeImageCacheSize(int m)
{
INTERLOCKED_(sMakeImage) {
sMaxSize = m;
}
}
void SweepMkImageCache()
{
INTERLOCKED_(sMakeImage) {
LRUCache<Image>& cache = sImageCache();
cache.ClearCounters();
}
}
Image MakeImage__(const ImageMaker& m, bool paintonly)
{
Image result;
INTERLOCKED_(sMakeImage) {
LRUCache<Image>& cache = sImageCache();
scImageMaker cm;
cm.m = &m;
cm.paintonly = paintonly;
LLOG("MakeImage before shrink: " << cache.GetSize() << ", count " << cache.GetCount());
cache.Shrink(sMaxSize, 2000);
LLOG("MakeImage before make: " << cache.GetSize() << ", count " << cache.GetCount());
result = cache.Get(cm);
LLOG("MakeImage after make: " << cache.GetSize() << ", count " << cache.GetCount());
int q = min(3 * (cache.GetFoundSize() + cache.GetNewSize()), sMaxSizeMax);
if(q > sMaxSize)
sMaxSize = q;
}
return result;
}
Image MakeImage(const ImageMaker& m)
{
return MakeImage__(m, false);
}
Image MakeImagePaintOnly(const ImageMaker& m)
{
return MakeImage__(m, true);
}
class SimpleImageMaker : public ImageMaker {
Image (*make)(const Image& image);
Image image;
public:
virtual String Key() const;
virtual Image Make() const;
SimpleImageMaker(const Image& image, Image (*make)(const Image& image))
: make(make),image(image) {}
};
String SimpleImageMaker::Key() const
{
String key;
int64 k = image.GetSerialId();
key.Cat((const char *)&k, sizeof(int64));
key.Cat((const char *)&make, sizeof(make));
return key;
}
Image SimpleImageMaker::Make() const
{
return (*make)(image);
}
Image MakeImage(const Image& image, Image (*make)(const Image& image))
{
return MakeImage(SimpleImageMaker(image, make));
}
struct sCachedRescale : public ImageMaker
{
Rect src;
Size sz;
Image img;
virtual String Key() const {
StringBuffer h;
RawCat(h, src.left);
RawCat(h, src.top);
RawCat(h, src.right);
RawCat(h, src.bottom);
RawCat(h, sz.cx);
RawCat(h, sz.cy);
RawCat(h, img.GetSerialId());
return h;
}
virtual Image Make() const {
return Rescale(img, sz, src);
}
};
Image CachedRescale(const Image& m, Size sz, const Rect& src)
{
if(m.GetSize() == sz)
return m;
sCachedRescale cr;
cr.sz = sz;
cr.src = src;
cr.img = m;
return MakeImage(cr);
}
Image CachedRescale(const Image& m, Size sz)
{
return CachedRescale(m, sz, m.GetSize());
}
Image CachedRescalePaintOnly(const Image& m, Size sz, const Rect& src)
{
if(m.GetSize() == sz)
return m;
sCachedRescale cr;
cr.sz = sz;
cr.src = src;
cr.img = m;
return MakeImagePaintOnly(cr);
}
Image CachedRescalePaintOnly(const Image& m, Size sz)
{
return CachedRescalePaintOnly(m, sz, m.GetSize());
}
END_UPP_NAMESPACE

View file

@ -12,8 +12,8 @@ topic "Font";
[{_}
[ {{10000t/25b/25@3 [s0; [*@(229)4 Font]]}}&]
[s3; &]
[s1;:Font`:`:class: [@(0.0.255) class]_Font_:_[@(0.0.255) private]_[@3 AssignValueTypeNo]<Fo
nt, FONT`_V, [_^Moveable^ Moveable]<Font>_>&]
[s1;:Font`:`:class: [@(0.0.255) class]_[* Font]_:_[@(0.0.255) private]_[@3 AssignValueTypeNo]<
Font, FONT`_V, [_^Moveable^ Moveable]<Font>_>&]
[s9;%% Font is a concrete class that describes the appearance of
text. It is Moveable, has cheap copy operation and is Value convertible
with rich`-Value abilities.&]
@ -37,22 +37,22 @@ Draw`::SetStdFont.]
[s0; &]
[ {{10000F(128)G(128)@1 [s0;%% [* Public Member List]]}}&]
[s3; &]
[s5;:Font`:`:GetFaceCount`(`): [@(0.0.255) static] [@(0.0.255) int]_GetFaceCount()&]
[s5;:Font`:`:GetFaceCount`(`): [@(0.0.255) static] [@(0.0.255) int]_[* GetFaceCount]()&]
[s2;%% Returns the number of face`-names available.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetFaceName`(int`): [@(0.0.255) static] [_^String^ String]_GetFaceName([@(0.0.255) i
[s5;:Font`:`:GetFaceName`(int`): [@(0.0.255) static] [_^String^ String]_[* GetFaceName]([@(0.0.255) i
nt]_[@3 index])&]
[s2;%% Returns the name of face [%-*@3 index].&]
[s3; &]
[s4; &]
[s5;:Font`:`:FindFaceNameIndex`(const String`&`): [@(0.0.255) static]
[@(0.0.255) int]_FindFaceNameIndex([@(0.0.255) const]_[_^String^ String][@(0.0.255) `&]_[@3 n
ame])&]
[@(0.0.255) int]_[* FindFaceNameIndex]([@(0.0.255) const]_[_^String^ String][@(0.0.255) `&]_
[@3 name])&]
[s2;%% Finds the face index of face`-[%-*@3 name].&]
[s3;%% &]
[s4; &]
[s5;:Font`:`:GetFaceInfo`(int`): [@(0.0.255) static] [_^dword^ dword]_GetFaceInfo([@(0.0.255) i
[s5;:Font`:`:GetFaceInfo`(int`): [@(0.0.255) static] [_^dword^ dword]_[* GetFaceInfo]([@(0.0.255) i
nt]_[@3 index])&]
[s2;%% Returns the information about face [%-*@3 index] as combination
of binary flags:&]
@ -66,36 +66,36 @@ Truetype).]
fonts).]}}&]
[s3; &]
[s4; &]
[s5;:Font`:`:SetStdFont`(Font`): [@(0.0.255) static] [@(0.0.255) void]_SetStdFont([_^Font^ F
[s5;:Font`:`:SetStdFont`(Font`): [@(0.0.255) static] [@(0.0.255) void]_[* SetStdFont]([_^Font^ F
ont]_[@3 font])&]
[s2;%% Sets the standard font. U`+`+ sets the standard font to match
host platform standard. This method can be used to change this
default setting.&]
[s3;%% &]
[s4; &]
[s5;:Font`:`:GetStdFont`(`): [@(0.0.255) static] [_^Font^ Font]_GetStdFont()&]
[s5;:Font`:`:GetStdFont`(`): [@(0.0.255) static] [_^Font^ Font]_[* GetStdFont]()&]
[s2;%% Returns the standard font.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetStdFontSize`(`): [@(0.0.255) static] [_^Size^ Size]_GetStdFontSize()&]
[s5;:Font`:`:GetStdFontSize`(`): [@(0.0.255) static] [_^Size^ Size]_[* GetStdFontSize]()&]
[s2;%% Returns metrics of standard font `- height and average width
of glyphs.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetFace`(`)const: [@(0.0.255) int]_GetFace()_[@(0.0.255) const]&]
[s5;:Font`:`:GetFace`(`)const: [@(0.0.255) int]_[* GetFace]()_[@(0.0.255) const]&]
[s2;%% Face index of Font.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetHeight`(`)const: [@(0.0.255) int]_GetHeight()_[@(0.0.255) const]&]
[s5;:Font`:`:GetHeight`(`)const: [@(0.0.255) int]_[* GetHeight]()_[@(0.0.255) const]&]
[s2;%% Returns the requested height of font.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetWidth`(`)const: [@(0.0.255) int]_GetWidth()_[@(0.0.255) const]&]
[s5;:Font`:`:GetWidth`(`)const: [@(0.0.255) int]_[* GetWidth]()_[@(0.0.255) const]&]
[s2;%% Return the width of font or 0 for default width.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetFaceName`(`)const: [_^String^ String]_GetFaceName()[@(64) _][@(0.0.255) con
st]&]
[s5;:Font`:`:GetFaceName`(`)const: [_^String^ String]_[* GetFaceName]()[@(64) _][@(0.0.255) c
onst]&]
[s2;%% Returns the face`-name text for current instance.&]
[s3; &]
[s4; &]
@ -106,65 +106,67 @@ onst]&]
instead of real names.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetFaceInfo`(`)const: [_^dword^ dword]_GetFaceInfo()[@(64) _][@(0.0.255) const
]&]
[s5;:Font`:`:GetFaceInfo`(`)const: [_^dword^ dword]_[* GetFaceInfo]()[@(64) _][@(0.0.255) con
st]&]
[s2;%% Same as GetFaceInfo(GetFace()).&]
[s3; &]
[s4; &]
[s5;:Font`:`:AsInt64`(`)const: [_^int64^ int64]_AsInt64()[@(64) _][@(0.0.255) const]&]
[s2;%% Returns 64`-bit number representing the font.&]
[s5;:Font`:`:AsInt64`(`)const: [_^int64^ int64]_[* AsInt64]()[@(64) _][@(0.0.255) const]&]
[s2;%% Returns 64`-bit number representing the font. All font attributes
are expressed as bitfields of this number.&]
[s3; &]
[s4; &]
[s5;:Font`:`:Face`(int`): [_^Font^ Font][@(0.0.255) `&]_Face([@(0.0.255) int]_[@3 n])&]
[s5;:Font`:`:Face`(int`): [_^Font^ Font][@(0.0.255) `&]_[* Face]([@(0.0.255) int]_[@3 n])&]
[s2;%% Sets the face index.&]
[s3; &]
[s4; &]
[s5;:Font`:`:Height`(int`): [_^Font^ Font][@(0.0.255) `&]_Height([@(0.0.255) int]_[@3 n])&]
[s5;:Font`:`:Height`(int`): [_^Font^ Font][@(0.0.255) `&]_[* Height]([@(0.0.255) int]_[@3 n])&]
[s2;%% Sets the font height (in pixels/dots).&]
[s3; &]
[s4; &]
[s5;:Font`:`:Width`(int`): [_^Font^ Font][@(0.0.255) `&]_Width([@(0.0.255) int]_[@3 n])&]
[s5;:Font`:`:Width`(int`): [_^Font^ Font][@(0.0.255) `&]_[* Width]([@(0.0.255) int]_[@3 n])&]
[s2;%% Sets the font width. Use 0 for default width (in pixels/dots).&]
[s3; &]
[s4; &]
[s5;:Font`:`:Bold`(`): [_^Font^ Font][@(0.0.255) `&]_Bold()&]
[s5;:Font`:`:NoBold`(`): [_^Font^ Font][@(0.0.255) `&]_NoBold()&]
[s5;:Font`:`:Bold`(bool`): [_^Font^ Font][@(0.0.255) `&]_Bold([@(0.0.255) bool]_[@3 b])&]
[s5;:Font`:`:Italic`(`): [_^Font^ Font][@(0.0.255) `&]_Italic()&]
[s5;:Font`:`:NoItalic`(`): [_^Font^ Font][@(0.0.255) `&]_NoItalic()&]
[s5;:Font`:`:Italic`(bool`): [_^Font^ Font][@(0.0.255) `&]_Italic([@(0.0.255) bool]_[@3 b])&]
[s5;:Font`:`:Underline`(`): [_^Font^ Font][@(0.0.255) `&]_Underline()&]
[s5;:Font`:`:NoUnderline`(`): [_^Font^ Font][@(0.0.255) `&]_NoUnderline()&]
[s5;:Font`:`:Underline`(bool`): [_^Font^ Font][@(0.0.255) `&]_Underline([@(0.0.255) bool]_[@3 b
])&]
[s5;:Font`:`:Strikeout`(`): [_^Font^ Font][@(0.0.255) `&]_Strikeout()&]
[s5;:Font`:`:NoStrikeout`(`): [_^Font^ Font][@(0.0.255) `&]_NoStrikeout()&]
[s5;:Font`:`:Strikeout`(bool`): [_^Font^ Font][@(0.0.255) `&]_Strikeout([@(0.0.255) bool]_[@3 b
])&]
[s5;:Font`:`:Bold`(`): [_^Font^ Font][@(0.0.255) `&]_[* Bold]()&]
[s5;:Font`:`:NoBold`(`): [_^Font^ Font][@(0.0.255) `&]_[* NoBold]()&]
[s5;:Font`:`:Bold`(bool`): [_^Font^ Font][@(0.0.255) `&]_[* Bold]([@(0.0.255) bool]_[@3 b])&]
[s5;:Font`:`:Italic`(`): [_^Font^ Font][@(0.0.255) `&]_[* Italic]()&]
[s5;:Font`:`:NoItalic`(`): [_^Font^ Font][@(0.0.255) `&]_[* NoItalic]()&]
[s5;:Font`:`:Italic`(bool`): [_^Font^ Font][@(0.0.255) `&]_[* Italic]([@(0.0.255) bool]_[@3 b])
&]
[s5;:Font`:`:Underline`(`): [_^Font^ Font][@(0.0.255) `&]_[* Underline]()&]
[s5;:Font`:`:NoUnderline`(`): [_^Font^ Font][@(0.0.255) `&]_[* NoUnderline]()&]
[s5;:Font`:`:Underline`(bool`): [_^Font^ Font][@(0.0.255) `&]_[* Underline]([@(0.0.255) bool]_
[@3 b])&]
[s5;:Font`:`:Strikeout`(`): [_^Font^ Font][@(0.0.255) `&]_[* Strikeout]()&]
[s5;:Font`:`:NoStrikeout`(`): [_^Font^ Font][@(0.0.255) `&]_[* NoStrikeout]()&]
[s5;:Font`:`:Strikeout`(bool`): [_^Font^ Font][@(0.0.255) `&]_[* Strikeout]([@(0.0.255) bool]_
[@3 b])&]
[s2; Sets or unsets bold/italic/undeline/strikeout modes.&]
[s3; &]
[s4; &]
[s5;:Font`:`:NonAntiAliased`(`): [_^Font^ Font][@(0.0.255) `&]_NonAntiAliased()&]
[s5;:Font`:`:NoNonAntiAliased`(`): [_^Font^ Font][@(0.0.255) `&]_NoNonAntiAliased()&]
[s5;:Font`:`:NonAntiAliased`(bool`): [_^Font^ Font][@(0.0.255) `&]_NonAntiAliased([@(0.0.255) b
[s5;:Font`:`:NonAntiAliased`(`): [_^Font^ Font][@(0.0.255) `&]_[* NonAntiAliased]()&]
[s5;:Font`:`:NoNonAntiAliased`(`): [_^Font^ Font][@(0.0.255) `&]_[* NoNonAntiAliased]()&]
[s5;:Font`:`:NonAntiAliased`(bool`): [_^Font^ Font][@(0.0.255) `&]_[* NonAntiAliased]([@(0.0.255) b
ool]_[@3 b])&]
[s2;%% Sets/unsets non`-anti`-aliased flag. This indicates that anti`-aliasing
should not be used when painting the font.&]
[s3; &]
[s4; &]
[s5;:Font`:`:IsBold`(`)const: [@(0.0.255) bool]_IsBold()_[@(0.0.255) const]&]
[s5;:Font`:`:IsItalic`(`)const: [@(0.0.255) bool]_IsItalic()_[@(0.0.255) const]&]
[s5;:Font`:`:IsUnderline`(`)const: [@(0.0.255) bool]_IsUnderline()_[@(0.0.255) const]&]
[s5;:Font`:`:IsStrikeout`(`)const: [@(0.0.255) bool]_IsStrikeout()_[@(0.0.255) const]&]
[s5;:Font`:`:IsBold`(`)const: [@(0.0.255) bool]_[* IsBold]()_[@(0.0.255) const]&]
[s5;:Font`:`:IsItalic`(`)const: [@(0.0.255) bool]_[* IsItalic]()_[@(0.0.255) const]&]
[s5;:Font`:`:IsUnderline`(`)const: [@(0.0.255) bool]_[* IsUnderline]()_[@(0.0.255) const]&]
[s5;:Font`:`:IsStrikeout`(`)const: [@(0.0.255) bool]_[* IsStrikeout]()_[@(0.0.255) const]&]
[s2; Tests whether bold/italic/underline/strikeout is active.&]
[s3; &]
[s4; &]
[s5;:Font`:`:IsNonAntiAliased`(`)const: [@(0.0.255) bool]_IsNonAntiAliased()_[@(0.0.255) c
[s5;:Font`:`:IsNonAntiAliased`(`)const: [@(0.0.255) bool]_[* IsNonAntiAliased]()_[@(0.0.255) c
onst]&]
[s2;%% True if NonAntiAliased is active.&]
[s3; &]
[s4; &]
[s5;:Font`:`:FaceName`(const String`&`): [_^Font^ Font][@(0.0.255) `&]_FaceName([@(0.0.255) c
[s5;:Font`:`:FaceName`(const String`&`): [_^Font^ Font][@(0.0.255) `&]_[* FaceName]([@(0.0.255) c
onst]_[_^String^ String][@(0.0.255) `&]_[@3 name])&]
[s2;%% Sets the face to [%-*@3 name]. If name is not valid face`-name,
Font is set to Null. Method is able to recognize generic names
@ -182,92 +184,107 @@ nt]_[@3 n])_[@(0.0.255) const]&]
[s2;%% Returns a copy of Font, with height changed to [%-*@3 n].&]
[s3; &]
[s4; &]
[s5;:Font`:`:Serialize`(Stream`&`): [@(0.0.255) void]_Serialize([_^Stream^ Stream][@(0.0.255) `&
[s5;:Font`:`:Serialize`(Stream`&`): [@(0.0.255) void]_[* Serialize]([_^Stream^ Stream][@(0.0.255) `&
]_[@3 s])&]
[s2;%% Serializes the font value (face index is stored as face`-name
text).&]
[s3; &]
[s4; &]
[s5;:Font`:`:operator`=`=`(Font`)const: [@(0.0.255) bool]_operator`=`=([_^Font^ Font]_[@3 f
])_[@(0.0.255) const]&]
[s3; &]
[s5;:Font`:`:Jsonize`(JsonIO`&`): [@(0.0.255) void]_[* Jsonize]([_^JsonIO^ JsonIO][@(0.0.255) `&
]_[*@3 jio])&]
[s2;%% Stores/load font to/from JSON.&]
[s3;%% &]
[s4; &]
[s5;:Font`:`:operator`!`=`(Font`)const: [@(0.0.255) bool]_operator!`=([_^Font^ Font]_[@3 f])
_[@(0.0.255) const]&]
[s5;:Font`:`:Xmlize`(XmlIO`&`): [@(0.0.255) void]_[* Xmlize]([_^XmlIO^ XmlIO][@(0.0.255) `&]_
[*@3 xio])&]
[s2;%% Stores/load font to/from JSON..&]
[s3;%% &]
[s4; &]
[s5;:Font`:`:operator`=`=`(Font`)const: [@(0.0.255) bool]_[@(0.0.255) operator`=`=]([_^Font^ F
ont]_[@3 f])_[@(0.0.255) const]&]
[s5;:Font`:`:operator`!`=`(Font`)const: [@(0.0.255) bool]_[@(0.0.255) operator!`=]([_^Font^ F
ont]_[@3 f])_[@(0.0.255) const]&]
[s2;%% Compares two Font instances.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetHashValue`(`)const: [_^dword^ dword]_GetHashValue()[@(64) _][@(0.0.255) con
st]&]
[s5;:Font`:`:GetHashValue`(`)const: [_^dword^ dword]_[* GetHashValue]()[@(64) _][@(0.0.255) c
onst]&]
[s2;%% Returns the font hash value.&]
[s3; &]
[s4; &]
[s5;:Font`:`:IsNull`(`)const: [@(0.0.255) bool]_IsNull()_[@(0.0.255) const]&]
[s2;%% True if Font is Null.&]
[s5;:Font`:`:IsNullInstance`(`)const: [@(0.0.255) bool]_[* IsNullInstance]()_[@(0.0.255) co
nst]&]
[s2;%% True if Font is Null. (This method is used by default IsNull
template).&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetAscent`(`)const: [@(0.0.255) int]_GetAscent()_[@(0.0.255) const]&]
[s5;:Font`:`:SetNull`(`): [@(0.0.255) void]_[* SetNull]()&]
[s2;%% Sets the Font to Null.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetAscent`(`)const: [@(0.0.255) int]_[* GetAscent]()_[@(0.0.255) const]&]
[s2;%% Returns the character cell extend above the baseline.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetDescent`(`)const: [@(0.0.255) int]_GetDescent()_[@(0.0.255) const]&]
[s5;:Font`:`:GetDescent`(`)const: [@(0.0.255) int]_[* GetDescent]()_[@(0.0.255) const]&]
[s2;%% Returns the character cell extend below the baseline.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetCy`(`)const: [@(0.0.255) int]_GetCy()_[@(0.0.255) const]&]
[s5;:Font`:`:GetCy`(`)const: [@(0.0.255) int]_[* GetCy]()_[@(0.0.255) const]&]
[s2;%% Same as GetDescent() `+ GetAscent().&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetExternal`(`)const: [@(0.0.255) int]_GetExternal()_[@(0.0.255) const]&]
[s5;:Font`:`:GetExternal`(`)const: [@(0.0.255) int]_[* GetExternal]()_[@(0.0.255) const]&]
[s2;%% Returns the additional space that font description recommends
to insert between two lines of text. Rarely used.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetInternal`(`)const: [@(0.0.255) int]_GetInternal()_[@(0.0.255) const]&]
[s5;:Font`:`:GetInternal`(`)const: [@(0.0.255) int]_[* GetInternal]()_[@(0.0.255) const]&]
[s2;%% Returns the mostly free space inside GetAscent value. Rarely
used.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetHeight`(`)const: [@(0.0.255) int]_GetHeight()_[@(0.0.255) const]&]
[s5;:Font`:`:GetHeight`(`)const: [@(0.0.255) int]_[* GetHeight]()_[@(0.0.255) const]&]
[s2;%% Returns GetAscent() `+ GetDescent() `- the height of the line
of text.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetLineHeight`(`)const: [@(0.0.255) int]_GetLineHeight()_[@(0.0.255) const]&]
[s5;:Font`:`:GetLineHeight`(`)const: [@(0.0.255) int]_[* GetLineHeight]()_[@(0.0.255) const
]&]
[s2;%% Returns GetHeight() `+ GetExternal().&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetOverhang`(`)const: [@(0.0.255) int]_GetOverhang()_[@(0.0.255) const]&]
[s5;:Font`:`:GetOverhang`(`)const: [@(0.0.255) int]_[* GetOverhang]()_[@(0.0.255) const]&]
[s2;%% Returns overhang of font.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetAveWidth`(`)const: [@(0.0.255) int]_GetAveWidth()_[@(0.0.255) const]&]
[s5;:Font`:`:GetAveWidth`(`)const: [@(0.0.255) int]_[* GetAveWidth]()_[@(0.0.255) const]&]
[s2;%% Returns the average width of character.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetMaxWidth`(`)const: [@(0.0.255) int]_GetMaxWidth()_[@(0.0.255) const]&]
[s5;:Font`:`:GetMaxWidth`(`)const: [@(0.0.255) int]_[* GetMaxWidth]()_[@(0.0.255) const]&]
[s2;%% Returns the maximal width of character.&]
[s3; &]
[s4; &]
[s5;:Font`:`:IsNormal`(int`)const: [@(0.0.255) bool]_IsNormal([@(0.0.255) int]_[@3 ch])_[@(0.0.255) c
[s5;:Font`:`:IsNormal`(int`)const: [@(0.0.255) bool]_[* IsNormal]([@(0.0.255) int]_[@3 ch])_[@(0.0.255) c
onst]&]
[s2;%% Returns true if [%-*@3 ch] exists as regular glyph in the font.&]
[s3;%% &]
[s4; &]
[s5;:Font`:`:IsComposed`(int`)const: [@(0.0.255) bool]_IsComposed([@(0.0.255) int]_[@3 ch])
_[@(0.0.255) const]&]
[s5;:Font`:`:IsComposed`(int`)const: [@(0.0.255) bool]_[* IsComposed]([@(0.0.255) int]_[@3 ch
])_[@(0.0.255) const]&]
[s2;%% Returns true if [%-*@3 ch].is to be rendered as composition
of 2 other glyphs (ASCII letter and diacritical mark).&]
[s3;%% &]
[s4; &]
[s5;:Font`:`:IsReplaced`(int`)const: [@(0.0.255) bool]_IsReplaced([@(0.0.255) int]_[@3 ch])
_[@(0.0.255) const]&]
[s5;:Font`:`:IsReplaced`(int`)const: [@(0.0.255) bool]_[* IsReplaced]([@(0.0.255) int]_[@3 ch
])_[@(0.0.255) const]&]
[s2;%% Returns true [%-*@3 ch] is to be rendered using character from
some other font.&]
[s3;%% &]
[s4; &]
[s5;:Font`:`:IsMissing`(int`)const: [@(0.0.255) bool]_IsMissing([@(0.0.255) int]_[@3 ch])_[@(0.0.255) c
onst]&]
[s5;:Font`:`:IsMissing`(int`)const: [@(0.0.255) bool]_[* IsMissing]([@(0.0.255) int]_[@3 ch])
_[@(0.0.255) const]&]
[s2;%% Returns true if [%-*@3 ch] cannot be rendered.&]
[s3;%% &]
[s4; &]
@ -276,18 +293,18 @@ onst]&]
[s2;%% Returns true if [%-*@3 ch] can be rendered (in any way).&]
[s3;%% &]
[s4; &]
[s5;:Font`:`:GetWidth`(int`)const: [@(0.0.255) int]_GetWidth([@(0.0.255) int]_[@3 c])_[@(0.0.255) c
[s5;:Font`:`:GetWidth`(int`)const: [@(0.0.255) int]_[* GetWidth]([@(0.0.255) int]_[@3 c])_[@(0.0.255) c
onst]&]
[s2;%% Returns the total advance with of character [%-*@3 c] (encoded
in unicode).&]
[s3; &]
[s4; &]
[s5;:Font`:`:operator`[`]`(int`)const: [@(0.0.255) int]_operator`[`]([@(0.0.255) int]_[@3 c
])_[@(0.0.255) const]&]
[s5;:Font`:`:operator`[`]`(int`)const: [@(0.0.255) int]_[@(0.0.255) operator`[`]]([@(0.0.255) i
nt]_[@3 c])_[@(0.0.255) const]&]
[s2;%% Same as GetWidth([%-*@3 c]).&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetLeftSpace`(int`)const: [@(0.0.255) int]_GetLeftSpace([@(0.0.255) int]_[@3 c
[s5;:Font`:`:GetLeftSpace`(int`)const: [@(0.0.255) int]_[* GetLeftSpace]([@(0.0.255) int]_[@3 c
])_[@(0.0.255) const]&]
[s2;%% Describes the relation of left side of character cell and
leftmost area painted for character [%-*@3 c]. Negative value means
@ -295,34 +312,27 @@ that character extends character cell, positive value means that
there is a space inside the cell not used for glyph.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetRightSpace`(int`)const: [@(0.0.255) int]_GetRightSpace([@(0.0.255) int]_[@3 c
])_[@(0.0.255) const]&]
[s5;:Font`:`:GetRightSpace`(int`)const: [@(0.0.255) int]_[* GetRightSpace]([@(0.0.255) int]_
[@3 c])_[@(0.0.255) const]&]
[s2;%% Similar to GetLeftSpace for the right edge of character cell.&]
[s3; &]
[s4; &]
[s5;:Font`:`:IsFixedPitch`(`)const: [@(0.0.255) bool]_IsFixedPitch()_[@(0.0.255) const]&]
[s5;:Font`:`:IsFixedPitch`(`)const: [@(0.0.255) bool]_[* IsFixedPitch]()_[@(0.0.255) const]&]
[s2;%% True if font is mono`-spaced.&]
[s3; &]
[s4; &]
[s5;:Font`:`:IsScaleable`(`)const: [@(0.0.255) bool]_IsScaleable()_[@(0.0.255) const]&]
[s5;:Font`:`:IsScaleable`(`)const: [@(0.0.255) bool]_[* IsScaleable]()_[@(0.0.255) const]&]
[s2;%% True if font is freely scaleable.&]
[s3; &]
[s4; &]
[s5;:Font`:`:IsSpecial`(`)const: [@(0.0.255) bool]_IsSpecial()_[@(0.0.255) const]&]
[s5;:Font`:`:IsSpecial`(`)const: [@(0.0.255) bool]_[* IsSpecial]()_[@(0.0.255) const]&]
[s2;%% Returns true if font does not use unicode placement of glyphs,
for example some symbol fonts have this issue.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetPath`(`)const: [_^String^ String]_GetPath()[@(64) _][@(0.0.255) const]&]
[s5;:Font`:`:GetPath`(`)const: [_^String^ String]_[* GetPath]()[@(64) _][@(0.0.255) const]&]
[s2;%% [/ POSIX specific:] Returns the path of font file.&]
[s3; &]
[s0; &]
[ {{10000t/25b/25@1 [s0; [* Constructor Detail]]}}&]
[s3; &]
[s5;:Font`:`:Font`(`): Font()&]
[s2;%% Initializes Font to STDFONT, default height, all attributes
not active.&]
[s3; &]
[s4; &]
[s5;:Font`:`:GetTextFlags`(`)const: [_^String^ String]_[* GetTextFlags]()_[@(0.0.255) const
]&]
@ -335,6 +345,22 @@ onst]_[@(0.0.255) char]_`*[*@3 s])&]
[s2;%% Sets font flags based on text in format created by GetTextFlags.&]
[s3;%% &]
[s4; &]
[s5;:Font`:`:GetData`(`)const: [_^String^ String]_[* GetData]()_[@(0.0.255) const]&]
[s2;%% Returns the raw content of font file.&]
[s3; &]
[s4; &]
[s5;:Font`:`:Render`(FontGlyphConsumer`&`,double`,double`,int`)const: [@(0.0.255) void]_
[* Render]([_^FontGlyphConsumer^ FontGlyphConsumer][@(0.0.255) `&]_[*@3 sw],
[@(0.0.255) double]_[*@3 x], [@(0.0.255) double]_[*@3 y], [@(0.0.255) int]_[*@3 ch])_[@(0.0.255) c
onst]&]
[s2;%% For true`-type fonts, renders the character glyph.&]
[s3;%% &]
[s4; &]
[s5;:Font`:`:Font`(`): [* Font]()&]
[s2;%% Initializes Font to STDFONT, default height, all attributes
not active.&]
[s3; &]
[s4; &]
[s5;:Font`:`:Font`(int`,int`): Font([@(0.0.255) int]_[@3 face], [@(0.0.255) int]_[@3 height])
&]
[s2;%% Initializes font to [%-*@3 face] index and [%-*@3 height].&]
@ -353,4 +379,4 @@ onst]_[@(0.0.255) char]_`*[*@3 s])&]
[@3 q])&]
[s2;%% Converts the Value to the Font.&]
[s3; &]
[s0; ]
[s0; ]]

View file

@ -21,74 +21,6 @@ NAMESPACE_UPP
#ifdef PLATFORM_WIN32
double fx_to_dbl(const FIXED& p) {
return double(p.value) + double(p.fract) * (1.0 / 65536.0);
}
Pointf fx_to_dbl(const Pointf& pp, const POINTFX& p) {
return Pointf(pp.x + fx_to_dbl(p.x), pp.y - fx_to_dbl(p.y));
}
void RenderCharPath(const char* gbuf, unsigned total_size, Painter& sw, double xx, double yy)
{
PAINTER_TIMING("RenderCharPath");
const char* cur_glyph = gbuf;
const char* end_glyph = gbuf + total_size;
Pointf pp(xx, yy);
while(cur_glyph < end_glyph) {
const TTPOLYGONHEADER* th = (TTPOLYGONHEADER*)cur_glyph;
const char* end_poly = cur_glyph + th->cb;
const char* cur_poly = cur_glyph + sizeof(TTPOLYGONHEADER);
sw.Move(fx_to_dbl(pp, th->pfxStart));
while(cur_poly < end_poly) {
const TTPOLYCURVE* pc = (const TTPOLYCURVE*)cur_poly;
if (pc->wType == TT_PRIM_LINE)
for(int i = 0; i < pc->cpfx; i++)
sw.Line(fx_to_dbl(pp, pc->apfx[i]));
if (pc->wType == TT_PRIM_QSPLINE)
for(int u = 0; u < pc->cpfx - 1; u++) {
Pointf b = fx_to_dbl(pp, pc->apfx[u]);
Pointf c = fx_to_dbl(pp, pc->apfx[u + 1]);
if (u < pc->cpfx - 2)
c = Mid(b, c);
sw.Quadratic(b, c);
}
cur_poly += sizeof(WORD) * 2 + sizeof(POINTFX) * pc->cpfx;
}
sw.Close();
cur_glyph += th->cb;
}
}
HFONT GetWin32Font(Font fnt, int angle);
HDC Win32_IC();
void PaintCharacterSys(Painter& sw, double x, double y, int ch, Font fnt)
{
PAINTER_TIMING("CharacterOp");
DrawLock __;
HFONT hfont = GetWin32Font(fnt, 0);
if(hfont) {
HDC hdc = Win32_IC();
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
GLYPHMETRICS gm;
MAT2 m_matrix;
memset(&m_matrix, 0, sizeof(m_matrix));
m_matrix.eM11.value = 1;
m_matrix.eM22.value = 1;
int gsz = GetGlyphOutlineW(hdc, ch, GGO_NATIVE, &gm, 0, NULL, &m_matrix);
if(gsz < 0)
return;
StringBuffer gb(gsz);
gsz = GetGlyphOutlineW(hdc, ch, GGO_NATIVE, &gm, gsz, ~gb, &m_matrix);
if(gsz < 0)
return;
RenderCharPath(~gb, gsz, sw, x, y + fnt.GetAscent());
sw.EvenOdd(true);
::SelectObject(hdc, ohfont);
}
}
#endif
END_UPP_NAMESPACE

View file

@ -2,26 +2,49 @@
NAMESPACE_UPP
struct PaintCharPath : FontGlyphConsumer {
Painter *sw;
virtual void Move(Pointf p) {
sw->Move(p);
}
virtual void Line(Pointf p) {
sw->Line(p);
}
virtual void Quadratic(Pointf p1, Pointf p2) {
sw->Quadratic(p1, p2);
}
virtual void Cubic(Pointf p1, Pointf p2, Pointf p3) {
sw->Cubic(p1, p2, p3);
}
virtual void Close() {
sw->Close();
}
};
void PaintCharacter(Painter& sw, const Pointf& p, int chr, Font font)
{
GlyphInfo gi = GetGlyphInfo(font, chr);
PaintCharPath pw;
pw.sw = &sw;
if(gi.IsNormal())
PaintCharacterSys(sw, p.x, p.y, chr, font);
font.Render(pw, p.x, p.y, chr);
else
if(gi.IsReplaced()) {
Font fnt = font;
fnt.Face(gi.lspc);
fnt.Height(gi.rspc);
PaintCharacterSys(sw, p.x, p.y + font.GetAscent() - fnt.GetAscent(), chr, fnt);
fnt.Render(pw, p.x, p.y + font.GetAscent() - fnt.GetAscent(), chr);
}
else
if(gi.IsComposed()) {
ComposedGlyph cg;
Compose(font, chr, cg);
PaintCharacterSys(sw, p.x, p.y, cg.basic_char, font);
font.Render(pw, p.x, p.y, cg.basic_char);
sw.Div();
PaintCharacterSys(sw, p.x + cg.mark_pos.x, p.y + cg.mark_pos.y, cg.mark_char, cg.mark_font);
cg.mark_font.Render(pw, p.x + cg.mark_pos.x, p.y + cg.mark_pos.y, cg.mark_char);
}
sw.EvenOdd(true);
}
Painter& Painter::Move(const Pointf& p)

View file

@ -313,7 +313,6 @@ public:
Painter& RectPath(const Rect& r);
};
void PaintCharacterSys(Painter& sw, double x, double y, int ch, Font fnt);
void PaintCharacter(Painter& sw, const Pointf& p, int ch, Font fnt);
#include "Painter.hpp"

View file

@ -10,7 +10,6 @@ file
SvgArc.cpp,
PainterPath.cpp,
FontWin32.cpp,
FontX11.cpp,
DrawOp.cpp,
Painting.h,
Painting.cpp,

View file

@ -6,7 +6,6 @@ NAMESPACE_UPP
#define LLOG(x) // LOG(x)
#define PDF_COMPRESS
#define USE_TTF
static const char ICC_ColorSpaceInfo[] =
"H\211\234\226yTSw\026\307\177o\311\236\220\225\260\303c\r[\200\260\006\2205la\221"
@ -344,10 +343,6 @@ void PdfDraw::PutFontHeight(int fi, double ht)
page << "/F" << ((fontid = fi) + 1) << ' ' << Pt(textht = ht) << " Tf\n";
}
#ifdef PLATFORM_WIN32
HFONT GetWin32Font(Font fnt, int angle);
HDC Win32_IC();
#endif
PdfDraw::OutlineInfo PdfDraw::GetOutlineInfo(Font fnt)
{
@ -358,44 +353,11 @@ PdfDraw::OutlineInfo PdfDraw::GetOutlineInfo(Font fnt)
OutlineInfo of;
of.sitalic = of.ttf = false;
#ifdef USE_TTF
#ifdef PLATFORM_WIN32
{
DrawLock __;
HFONT hfont = GetWin32Font(fnt, 0);
if(hfont) {
HDC hdc = Win32_IC();
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
TEXTMETRIC tm;
::GetTextMetrics(hdc, &tm);
if(tm.tmPitchAndFamily & TMPF_TRUETYPE) {
of.ttf = true;
int c = GetOutlineTextMetrics(hdc, 0, NULL);
if(c > 0) {
Buffer<byte> h(c);
OUTLINETEXTMETRIC *otm = (OUTLINETEXTMETRIC *)~h;
GetOutlineTextMetrics(hdc, c, otm);
of.sitalic = otm->otmItalicAngle == 0 && fnt.IsItalic();
}
}
::SelectObject(hdc, ohfont);
}
TTFReader ttf;
if(ttf.Open(fnt.GetData(), false, true)) {
of.ttf = true;
of.sitalic = ttf.post.italicAngle == 0 && fnt.IsItalic();
}
#endif
#ifdef PLATFORM_POSIX
FontInfo fi = fnt.Info();
String fn = fi.GetFileName();
String ext = ToLower(GetFileExt(fn));
if(ext == ".ttf" || ext == ".otf") {
String data = LoadFile(fn);
TTFReader ttf;
if(ttf.Open(data, false, true)) {
of.ttf = true;
of.sitalic = ttf.post.italicAngle == 0 && fnt.IsItalic();
}
}
#endif
#endif
outline_info.Add(fnt, of);
@ -410,13 +372,8 @@ void PdfDraw::DrawTextOp(int x, int y, int angle, const wchar *s, Font fnt,
if(!n) return;
if(fnt.GetHeight() == 0)
fnt.Height(100);
FontInfo ff = fnt.Info();
#ifdef PLATFORM_WIN32
int fh = ff.GetHeight() - ff.GetInternal();//TODO
#endif
#ifdef PLATFORM_POSIX
Font ff = fnt;
int fh = fnt.GetHeight();
#endif
OutlineInfo of = GetOutlineInfo(fnt);
if(of.ttf)
fnt.Height(FONTHEIGHT_TTF);
@ -439,7 +396,7 @@ void PdfDraw::DrawTextOp(int x, int y, int angle, const wchar *s, Font fnt,
Pointf prev(0, 0);
for(int i = 0; i < n; i++) {
Pointf next(Pt(x + posx * cosa + fround(ff.GetAscent() * sina)),
Pt(pgsz.cy - (y - posx * sina) - fround(ff.GetAscent() * cosa)));
Pt(pgsz.cy - (y - posx * sina) - fround(ff.GetAscent() * cosa)));
CharPos fp = GetCharPos(fnt, s[i]);
if(fi != fp.fi) {
fi = fp.fi;
@ -984,35 +941,12 @@ String PdfDraw::Finish()
}
else {
String fontbuffer;
#ifdef PLATFORM_POSIX
FontInfo fi = pdffont.GetKey(i).Info();
fontbuffer = LoadFile(fi.GetFileName());
#endif
#ifdef PLATFORM_WIN32
{
DrawLock __;
HFONT hfont = GetWin32Font(pdffont.GetKey(i), 0);
if(hfont) {
HDC hdc = Win32_IC();
HFONT ohfont = (HFONT) ::SelectObject(hdc, hfont);
DWORD size = GetFontData(hdc, 0, 0, NULL, 0);
if(size == GDI_ERROR) {
LLOG("PdfDraw::Finish: GDI_ERROR on font " << pdffont.GetKey(i));
return Null;
}
StringBuffer b(size);
GetFontData(hdc, 0, 0, b, size);
::SelectObject(hdc, ohfont);
fontbuffer = b;
}
}
#endif
fontbuffer = pdffont.GetKey(i).GetData();
TTFReader ttf;
if(!ttf.Open(fontbuffer))
return Null;
String name = FormatIntAlpha(i + 1, true);
name.Cat('A', 6 - name.GetLength());
name << '+' << ttf.ps_name;

View file

@ -306,6 +306,7 @@ private:
int lineascent, Zoom z, bool highlight);
int PosInLine(int x, const Rect& page, const Lines& pl, int lni) const;
static StaticMutex cache_lock;
static Array<RichPara>& Cache();
struct StorePart;

View file

@ -2,6 +2,8 @@
NAMESPACE_UPP
StaticMutex RichPara::cache_lock;
Array<RichPara>& RichPara::Cache()
{
static Array<RichPara> x;
@ -24,7 +26,7 @@ RichPara::RichPara()
RichPara::~RichPara()
{
if(cacheid && !part.IsPicked() && !incache) {
DrawLock __;
Mutex::Lock __(cache_lock);
Array<RichPara>& cache = Cache();
incache = true;
cache.InsertPick(0, *this);
@ -566,7 +568,7 @@ void RichPara::Unpack(const String& data, const Array<RichObject>& obj,
format = style;
if(cacheid) {
DrawLock __;
Mutex::Lock __(cache_lock);
Array<RichPara>& cache = Cache();
for(int i = 0; i < cache.GetCount(); i++)
if(cache[i].cacheid == cacheid) {

View file

@ -215,7 +215,7 @@ Array<RichPara::Lines>& RichPara::Lines::Cache()
RichPara::Lines::~Lines()
{
if(cacheid && !line.IsPicked() && !incache) {
DrawLock __;
Mutex::Lock __(cache_lock);
Array<Lines>& cache = Cache();
incache = true;
cache.Insert(0) = *this;
@ -236,7 +236,7 @@ RichPara::Lines RichPara::FormatLines(int acx) const
{
Lines lines;
if(cacheid) {
DrawLock __;
Mutex::Lock __(cache_lock);
Array<Lines>& cache = Lines::Cache();
for(int i = 0; i < cache.GetCount(); i++)
if(cache[i].cacheid == cacheid && cache[i].cx == acx) {

View file

@ -94,7 +94,7 @@ mainconfig
"" = "GUI HEAPDBG CHECKINIT",
"" = "GUI TESTINSTALL",
"" = "GUI CHECKCLIPBOARD",
"" = "GUI SVO_VALUE";
"" = "GUI MT";
custom() "",
"",