mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-08-22 06:12:32 -06:00
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:
parent
fa5f9ec55e
commit
bd87a04fda
37 changed files with 2704 additions and 2655 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 **)§ion, 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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
NAMESPACE_UPP
|
||||
|
||||
#define LLOG(x) // LOG(x)
|
||||
#define LLOG(x) // DLOG(x)
|
||||
|
||||
XIM Ctrl::xim;
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ library(FREEBSD) xcb;
|
|||
|
||||
file
|
||||
Draw.h,
|
||||
DrawLock.cpp,
|
||||
FontInt.h,
|
||||
Font.cpp,
|
||||
FontCR.cpp,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
1037
uppsrc/Draw/Font.cpp
1037
uppsrc/Draw/Font.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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; ]]
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ file
|
|||
SvgArc.cpp,
|
||||
PainterPath.cpp,
|
||||
FontWin32.cpp,
|
||||
FontX11.cpp,
|
||||
DrawOp.cpp,
|
||||
Painting.h,
|
||||
Painting.cpp,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ mainconfig
|
|||
"" = "GUI HEAPDBG CHECKINIT",
|
||||
"" = "GUI TESTINSTALL",
|
||||
"" = "GUI CHECKCLIPBOARD",
|
||||
"" = "GUI SVO_VALUE";
|
||||
"" = "GUI MT";
|
||||
|
||||
custom() "",
|
||||
"",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue