From bd87a04fda9a8ff6cac474da5fabb4824ef99dc7 Mon Sep 17 00:00:00 2001 From: cxl Date: Sun, 11 Nov 2012 12:33:47 +0000 Subject: [PATCH] Draw, CtrlCore: Major refactor of Draw git-svn-id: svn://ultimatepp.org/upp/trunk@5545 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/BuildAll/BuildAll.cpp | 1 + uppsrc/CtrlCore/CtrlCore.h | 4 + uppsrc/CtrlCore/CtrlMt.cpp | 428 ++++++------ uppsrc/CtrlCore/DrawOpWin32.cpp | 6 - uppsrc/CtrlCore/DrawOpX11.cpp | 6 - uppsrc/CtrlCore/ImageWin32.cpp | 206 +++--- uppsrc/CtrlCore/ImageX11.cpp | 947 ++++++++++++------------- uppsrc/CtrlCore/SystemDraw.cpp | 195 ++---- uppsrc/CtrlCore/TopWin32.cpp | 4 +- uppsrc/CtrlCore/Win32Gui.h | 4 +- uppsrc/CtrlCore/Win32Wnd.cpp | 2 +- uppsrc/CtrlCore/X11App.cpp | 2 +- uppsrc/CtrlCore/X11Gui.h | 4 +- uppsrc/Draw/Display.cpp | 1 + uppsrc/Draw/Draw.cpp | 42 ++ uppsrc/Draw/Draw.h | 53 +- uppsrc/Draw/Draw.upp | 1 - uppsrc/Draw/DrawData.cpp | 16 +- uppsrc/Draw/DrawLock.cpp | 51 -- uppsrc/Draw/Font.cpp | 1037 ++++++++++++++-------------- uppsrc/Draw/FontFc.cpp | 607 +++++++++------- uppsrc/Draw/FontInt.h | 116 ++-- uppsrc/Draw/FontWin32.cpp | 85 +++ uppsrc/Draw/Image.cpp | 89 +-- uppsrc/Draw/Image.h | 638 ++++++++--------- uppsrc/Draw/ImageOp.h | 3 + uppsrc/Draw/MakeCache.cpp | 411 ++++++----- uppsrc/Draw/src.tpp/Font$en-us.tpp | 206 +++--- uppsrc/Painter/FontWin32.cpp | 68 -- uppsrc/Painter/Painter.cpp | 31 +- uppsrc/Painter/Painter.h | 1 - uppsrc/Painter/Painter.upp | 1 - uppsrc/PdfDraw/PdfDraw.cpp | 80 +-- uppsrc/RichText/Para.h | 1 + uppsrc/RichText/ParaData.cpp | 6 +- uppsrc/RichText/ParaType.cpp | 4 +- uppsrc/ide/ide.upp | 2 +- 37 files changed, 2704 insertions(+), 2655 deletions(-) delete mode 100644 uppsrc/Draw/DrawLock.cpp diff --git a/uppsrc/BuildAll/BuildAll.cpp b/uppsrc/BuildAll/BuildAll.cpp index 21437ce4c..7820e508c 100644 --- a/uppsrc/BuildAll/BuildAll.cpp +++ b/uppsrc/BuildAll/BuildAll.cpp @@ -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 { diff --git a/uppsrc/CtrlCore/CtrlCore.h b/uppsrc/CtrlCore/CtrlCore.h index 636e944c1..acdf4edb3 100644 --- a/uppsrc/CtrlCore/CtrlCore.h +++ b/uppsrc/CtrlCore/CtrlCore.h @@ -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 diff --git a/uppsrc/CtrlCore/CtrlMt.cpp b/uppsrc/CtrlCore/CtrlMt.cpp index 9b24bd16a..dfc4547db 100644 --- a/uppsrc/CtrlCore/CtrlMt.cpp +++ b/uppsrc/CtrlCore/CtrlMt.cpp @@ -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 diff --git a/uppsrc/CtrlCore/DrawOpWin32.cpp b/uppsrc/CtrlCore/DrawOpWin32.cpp index 661f865f5..a6e964adc 100644 --- a/uppsrc/CtrlCore/DrawOpWin32.cpp +++ b/uppsrc/CtrlCore/DrawOpWin32.cpp @@ -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, diff --git a/uppsrc/CtrlCore/DrawOpX11.cpp b/uppsrc/CtrlCore/DrawOpX11.cpp index f1b1a8662..39edb1fb2 100644 --- a/uppsrc/CtrlCore/DrawOpX11.cpp +++ b/uppsrc/CtrlCore/DrawOpX11.cpp @@ -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) diff --git a/uppsrc/CtrlCore/ImageWin32.cpp b/uppsrc/CtrlCore/ImageWin32.cpp index 096e98bdb..e3ad628c5 100644 --- a/uppsrc/CtrlCore/ImageWin32.cpp +++ b/uppsrc/CtrlCore/ImageWin32.cpp @@ -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 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 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::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 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(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(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; } diff --git a/uppsrc/CtrlCore/ImageX11.cpp b/uppsrc/CtrlCore/ImageX11.cpp index 09547a05f..66f83d2e8 100644 --- a/uppsrc/CtrlCore/ImageX11.cpp +++ b/uppsrc/CtrlCore/ImageX11.cpp @@ -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 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 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 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 - -#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 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 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::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 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 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 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 + +#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 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 diff --git a/uppsrc/CtrlCore/SystemDraw.cpp b/uppsrc/CtrlCore/SystemDraw.cpp index 1d93626e1..a1ec51d63 100644 --- a/uppsrc/CtrlCore/SystemDraw.cpp +++ b/uppsrc/CtrlCore/SystemDraw.cpp @@ -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(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(&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(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(&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 diff --git a/uppsrc/CtrlCore/TopWin32.cpp b/uppsrc/CtrlCore/TopWin32.cpp index 30b4aef3e..1c365d667 100644 --- a/uppsrc/CtrlCore/TopWin32.cpp +++ b/uppsrc/CtrlCore/TopWin32.cpp @@ -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 } diff --git a/uppsrc/CtrlCore/Win32Gui.h b/uppsrc/CtrlCore/Win32Gui.h index 5627b7c5a..c38049b5f 100644 --- a/uppsrc/CtrlCore/Win32Gui.h +++ b/uppsrc/CtrlCore/Win32Gui.h @@ -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: diff --git a/uppsrc/CtrlCore/Win32Wnd.cpp b/uppsrc/CtrlCore/Win32Wnd.cpp index b2482eac3..e659433cf 100644 --- a/uppsrc/CtrlCore/Win32Wnd.cpp +++ b/uppsrc/CtrlCore/Win32Wnd.cpp @@ -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); diff --git a/uppsrc/CtrlCore/X11App.cpp b/uppsrc/CtrlCore/X11App.cpp index f05ab510a..6c0621141 100644 --- a/uppsrc/CtrlCore/X11App.cpp +++ b/uppsrc/CtrlCore/X11App.cpp @@ -6,7 +6,7 @@ NAMESPACE_UPP -#define LLOG(x) // LOG(x) +#define LLOG(x) // DLOG(x) XIM Ctrl::xim; diff --git a/uppsrc/CtrlCore/X11Gui.h b/uppsrc/CtrlCore/X11Gui.h index f4ebb5d3e..1bc6b55d9 100644 --- a/uppsrc/CtrlCore/X11Gui.h +++ b/uppsrc/CtrlCore/X11Gui.h @@ -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; } diff --git a/uppsrc/Draw/Display.cpp b/uppsrc/Draw/Display.cpp index 9faa90f92..067efd3bc 100644 --- a/uppsrc/Draw/Display.cpp +++ b/uppsrc/Draw/Display.cpp @@ -87,6 +87,7 @@ Size Display::GetStdSize(const Value& q) const return Single().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); diff --git a/uppsrc/Draw/Draw.cpp b/uppsrc/Draw/Draw.cpp index f1fad5e00..2a9219049 100644 --- a/uppsrc/Draw/Draw.cpp +++ b/uppsrc/Draw/Draw.cpp @@ -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); diff --git a/uppsrc/Draw/Draw.h b/uppsrc/Draw/Draw.h index 0ef433728..7eae53be1 100644 --- a/uppsrc/Draw/Draw.h +++ b/uppsrc/Draw/Draw.h @@ -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 >{ 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); } diff --git a/uppsrc/Draw/Draw.upp b/uppsrc/Draw/Draw.upp index bf82eac11..caeacd461 100644 --- a/uppsrc/Draw/Draw.upp +++ b/uppsrc/Draw/Draw.upp @@ -22,7 +22,6 @@ library(FREEBSD) xcb; file Draw.h, - DrawLock.cpp, FontInt.h, Font.cpp, FontCR.cpp, diff --git a/uppsrc/Draw/DrawData.cpp b/uppsrc/Draw/DrawData.cpp index 3edb2225f..f78d6f1d5 100644 --- a/uppsrc/Draw/DrawData.cpp +++ b/uppsrc/Draw/DrawData.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::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 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); diff --git a/uppsrc/Draw/DrawLock.cpp b/uppsrc/Draw/DrawLock.cpp deleted file mode 100644 index 8617031fc..000000000 --- a/uppsrc/Draw/DrawLock.cpp +++ /dev/null @@ -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 diff --git a/uppsrc/Draw/Font.cpp b/uppsrc/Draw/Font.cpp index 20ff204a0..0379f9f2b 100644 --- a/uppsrc/Draw/Font.cpp +++ b/uppsrc/Draw/Font.cpp @@ -1,514 +1,523 @@ -#include "Draw.h" - -#define LLOG(x) - -NAMESPACE_UPP - -CommonFontInfo GetFontInfoSys(Font font); -GlyphInfo GetGlyphInfoSys(Font font, int chr); -void GetStdFontSys(String& name, int& height); -Vector GetAllFacesSys(); - -bool Replace(Font fnt, int chr, Font& rfnt); - -void Std(Font& font) -{ - if(IsNull(font)) - font = StdFont(); - if(font.GetFace() == 0) - font.Face(GetStdFont().GetFace()); - if(font.GetHeight() == 0) - font.Height(GetStdFont().GetHeight()); -} - -Size Font::StdFontSize; -Font Font::AStdFont; - -INITBLOCK { - Value::Register("Font"); -} - -const Vector& Font::List() -{ - static Vector *q; - ONCELOCK { - static Vector x; - x = GetAllFacesSys(); - q = &x; - } - return *q; -} - -void sInitFonts() -{ - Font::List(); - GetStdFont(); -} - -INITBLOCK { - sInitFonts(); -} - -int Font::GetFaceCount() -{ - return List().GetCount(); -} - -String Font::GetFaceName(int index) -{ - if(index == 0) - return "STDFONT"; - const Vector& l = List(); - if(index >= 0 && index < l.GetCount()) - return l[index].name; - return Null; -} - -dword Font::GetFaceInfo(int index) -{ - const Vector& l = List(); - if(index >= 0 && index < l.GetCount()) - return l[index].info; - return 0; -} - -int FontFilter(int c) -{ - return c >= 'a' && c <= 'z' || c >= '0' && c <= '9' ? c : c >= 'A' && c <= 'Z' ? ToLower(c) : 0; -} - -int Font::FindFaceNameIndex(const String& name) { - if(name == "STDFONT") - return 0; - for(int i = 1; i < GetFaceCount(); i++) - if(GetFaceName(i) == name) - return i; - String n = Filter(name, FontFilter); - for(int i = 1; i < GetFaceCount(); i++) - if(Filter(GetFaceName(i), FontFilter) == n) - return i; - if(n == "serif") - return SERIF; - if(n == "sansserif") - return SANSSERIF; - if(n == "monospace") - return MONOSPACE; - if(n == "stdfont") - return STDFONT; - return 0; -} - -void Font::SyncStdFont() -{ - DrawLock __; - StdFontSize = Size(AStdFont.GetAveWidth(), AStdFont().Bold().GetCy()); -} - -void (*whenSetStdFont)(); - -void Font::SetStdFont(Font font) -{ - DrawLock __; - static int x = 0; - if(x) return; - x++; - InitStdFont(); - AStdFont = font; - SyncStdFont(); - if(whenSetStdFont) - (*whenSetStdFont)(); - x--; -} - -void Font::InitStdFont() -{ - ONCELOCK { - DrawLock __; - List(); - AStdFont = Arial(12); - String name; - int height = 0; - GetStdFontSys(name, height); -#ifdef PLATFORM_WIN32 -#ifdef flagWINGL - AStdFont = Font(FindFaceNameIndex("Tahoma"), 12); -#else - int q = FindFaceNameIndex(name); - if(q <= 0) - q = FindFaceNameIndex("Tahoma"); - if(q <= 0) - q = FindFaceNameIndex("Microsoft Sans Serif"); - if(q <= 0) - q = FindFaceNameIndex("MS Sans Serif"); - if(q > 0) - AStdFont = Font(q, max(height, 1)); -#endif - SyncStdFont(); -#endif - } -} - -Font Font::GetStdFont() -{ - InitStdFont(); - return AStdFont; -} - -Size Font::GetStdFontSize() -{ - InitStdFont(); - return StdFontSize; -} - -Font StdFont() -{ - return Font(0, -32000); -} - -int Font::GetHeight() const -{ - return v.height == -32000 ? GetStdFont().GetHeight() : v.height; -} - -String Font::GetFaceName() const { - if(IsNullInstance()) return String(); - if(GetFace() == 0) - return "STDFONT"; - return GetFaceName(GetFace()); -} - -dword Font::GetFaceInfo() const { - if(IsNullInstance()) return 0; - return GetFaceInfo(GetFace()); -} - -Font& Font::FaceName(const String& name) { - int n = FindFaceNameIndex(name); - Face(n < 0 ? 0xffff : n); - return *this; -} - -void Font::Serialize(Stream& s) { - int version = 1; - s / version; - if(version >= 1) { - enum { - OLD_STDFONT, OLD_SCREEN_SERIF, OLD_SCREEN_SANS, OLD_SCREEN_FIXED, - OLD_ROMAN, - OLD_ARIAL, - OLD_COURIER, - }; - int f = GetFace(); - if(f > COURIER) - f = -1; - s / f; - String name; - if(f == OLD_ROMAN) - f = ROMAN; - if(f == OLD_ARIAL) - f = ARIAL; - if(f == OLD_COURIER) - f = COURIER; - if(f < 0) { - name = GetFaceName(); - s % name; - } - if(s.IsLoading()) - if(f >= 0) - Face(f); - else { - FaceName(name); - if(IsNull(name)) - SetNull(); - } - } - else { - String name = GetFaceName(); - s % name; - if(s.IsLoading()) { - FaceName(name); - if(IsNullInstance()) - Face(COURIER); - } - } - s % v.flags % v.height % v.width; -} - -String Font::GetTextFlags() const -{ - String txt; - if(IsBold()) - txt << "bold "; - if(IsItalic()) - txt << "italic "; - if(IsUnderline()) - txt << "underline "; - if(IsStrikeout()) - txt << "strikeout "; - if(IsNonAntiAliased()) - txt << "noaa "; - if(IsTrueTypeOnly()) - txt << "ttonly "; - if(txt.GetCount()) - txt.Trim(txt.GetCount() - 1); - return txt; -} - -void Font::ParseTextFlags(const char *s) -{ - CParser p(s); - v.flags = 0; - while(!p.IsEof()) { - if(p.Id("bold")) - Bold(); - else - if(p.Id("italic")) - Italic(); - else - if(p.Id("underline")) - Underline(); - else - if(p.Id("strikeout")) - Strikeout(); - else - if(p.Id("noaa")) - NonAntiAliased(); - else - if(p.Id("ttonly")) - TrueTypeOnly(); - else - p.SkipTerm(); - } -} - -String Font::GetFaceNameStd() const -{ - switch(GetFace()) { - case STDFONT: return "STDFONT"; - case SERIF: return "serif"; - case SANSSERIF: return "sansserif"; - case MONOSPACE: return "monospace"; - } - return GetFaceName(); -} - -void Font::Jsonize(JsonIO& jio) -{ - String n, tf; - if(jio.IsStoring()) { - n = GetFaceNameStd(); - tf = GetTextFlags(); - if(IsNullInstance()) - n.Clear(); - } - jio("face", n)("height", v.height)("width", v.width)("flags", tf); - if(IsNull(n)) - SetNull(); - else { - FaceName(n); - ParseTextFlags(tf); - } -} - -void Font::Xmlize(XmlIO& xio) -{ - String n, tf; - if(xio.IsStoring()) { - n = GetFaceNameStd(); - tf = GetTextFlags(); - if(IsNullInstance()) - n.Clear(); - } - xio.Attr("face", n) - .Attr("height", v.height) - .Attr("width", v.width) - .Attr("flags", tf); - if(IsNull(n)) - SetNull(); - else { - FaceName(n); - ParseTextFlags(tf); - } -} - -template<> -String AsString(const Font& f) { - if(IsNull(f)) return ""; - String s = "<" + f.GetFaceName() + Format(":%d", f.GetHeight()); - if(f.IsBold()) - s += " Bold"; - if(f.IsItalic()) - s += " Italic"; - if(f.IsUnderline()) - s += " Underline"; - if(f.IsStrikeout()) - s += " Strikeout"; - return s + '>'; -} - -struct CharEntry { - int64 font; - GlyphInfo info; - word chr; -}; - -CharEntry fc_cache_global[4093]; - -bool IsNormal(Font font, int chr) -{ - DrawLock __; - CharEntry& e = fc_cache_global[CombineHash(font.GetHashValue(), chr) % 4093]; - if(e.font == font.AsInt64() || e.chr == chr) - return e.info.IsNormal(); - return GetGlyphInfoSys(font, chr).IsNormal(); -} - -CharEntry GetGlyphEntry(Font font, int chr, unsigned hash) -{ - DrawLock __; - CharEntry& e = fc_cache_global[hash % 4093]; - if(e.font != font.AsInt64() || e.chr != chr) { - e.font = font.AsInt64(); - e.chr = chr; - e.info = GetGlyphInfoSys(font, chr); - if(!e.info.IsNormal()) { - ComposedGlyph cg; - Font rfnt; - if(Compose(font, chr, cg)) { - e.info.lspc = -1; - e.info.rspc = cg.basic_char; - } - else - if(Replace(font, chr, rfnt)) { - e.info.lspc = rfnt.GetFace(); - e.info.rspc = rfnt.GetHeight(); - } - else - e.info.lspc = -2; - } - } - return e; -} - -thread__ CharEntry fc_cache[512]; - -GlyphInfo GetGlyphInfo(Font font, int chr) -{ - Std(font); - unsigned hash = CombineHash(font.GetHashValue(), chr); - CharEntry& e = fc_cache[hash & 511]; - if(e.font != font.AsInt64() || e.chr != chr) - e = GetGlyphEntry(font, chr, hash); - return e.info; -} - -bool Font::IsNormal(int ch) const -{ - return GetGlyphInfo(*this, ch).IsNormal(); -} - -bool Font::IsComposed(int ch) const -{ - return GetGlyphInfo(*this, ch).IsComposed(); -} - -bool Font::IsReplaced(int ch) const -{ - return GetGlyphInfo(*this, ch).IsReplaced(); -} - -bool Font::IsMissing(int ch) const -{ - return GetGlyphInfo(*this, ch).IsMissing(); -} - -int Font::HasChar(int ch) const -{ - return !GetGlyphInfo(*this, ch).IsMissing(); -} - -void GlyphMetrics(GlyphInfo& f, Font font, int chr) -{ - if(f.IsReplaced()) - f = GetGlyphInfo(font().Face(f.lspc).Height(f.rspc), chr); - if(f.IsComposed()) { - f = GetGlyphInfo(font, f.rspc); - if(f.IsComposedLM()) - f.rspc += f.width / 2; - } -} - -GlyphInfo GetGlyphMetrics(Font font, int chr) -{ - GlyphInfo f = GetGlyphInfo(font, chr); - if(f.IsMissing()) - f = GetGlyphInfo(font, '?'); - GlyphMetrics(f, font, chr); - return f; -} - -struct FontEntry { - CommonFontInfo info; - int64 font; -}; - -thread__ FontEntry fi_cache[64]; - -const CommonFontInfo& GetFontInfo(Font font) -{ - Std(font); - unsigned hash = font.GetHashValue() & 63; - FontEntry& e = fi_cache[hash]; - if(e.font != font.AsInt64()) { - DrawLock __; - e.font = font.AsInt64(); - e.info = GetFontInfoSys(font); - } - return e.info; -} - -int Font::GetWidth(int c) const { - return GetGlyphMetrics(*this, c).width; -} - -int Font::GetLeftSpace(int c) const { - return GetGlyphMetrics(*this, c).lspc; -} - -int Font::GetRightSpace(int c) const { - return GetGlyphMetrics(*this, c).rspc; -} - -thread__ int64 lastFiFont = INT_MIN; -thread__ CommonFontInfo lastFontInfo; -thread__ int64 lastStdFont = INT_MIN; - - -const CommonFontInfo& Font::Fi() const -{ -#ifdef PLATFORM_OSX11 -// known leak on MacOSX here: getAllCarbonLazyValues2000 calls Core.h op new() -// should not call UPP op new() -// from GetFontInfo() ... XftFontOpenPattern() ... getAllCarbonLazyValues2000() -> new() - MemoryIgnoreLeaksBlock __; -#endif - - if(lastStdFont != AStdFont.AsInt64()) { - lastFiFont = INT_MIN; - lastStdFont = AStdFont.AsInt64(); - } - if(AsInt64() == lastFiFont) - return lastFontInfo; - lastFontInfo = GetFontInfo(*this); - lastFiFont = AsInt64(); - return lastFontInfo; -} - -FontInfo Font::Info() const -{ - FontInfo h; - h.font = *this; - return h; -} - -END_UPP_NAMESPACE +#include "Draw.h" + +#define LLOG(x) + +NAMESPACE_UPP + +bool Replace(Font fnt, int chr, Font& rfnt); + +void Std(Font& font) +{ + if(IsNull(font)) + font = StdFont(); + if(font.GetFace() == 0) + font.Face(GetStdFont().GetFace()); + if(font.GetHeight() == 0) + font.Height(GetStdFont().GetHeight()); +} + +Size Font::StdFontSize; +Font Font::AStdFont; + +INITBLOCK { + Value::Register("Font"); +} + +const Vector& Font::List() +{ + static Vector *q; + ONCELOCK { + static Vector x; + x = GetAllFacesSys(); + q = &x; + } + return *q; +} + +void sInitFonts() +{ + Font::List(); + GetStdFont(); +} + +INITBLOCK { + sInitFonts(); +} + +int Font::GetFaceCount() +{ + return List().GetCount(); +} + +String Font::GetFaceName(int index) +{ + if(index == 0) + return "STDFONT"; + const Vector& l = List(); + if(index >= 0 && index < l.GetCount()) + return l[index].name; + return Null; +} + +dword Font::GetFaceInfo(int index) +{ + const Vector& l = List(); + if(index >= 0 && index < l.GetCount()) + return l[index].info; + return 0; +} + +int FontFilter(int c) +{ + return c >= 'a' && c <= 'z' || c >= '0' && c <= '9' ? c : c >= 'A' && c <= 'Z' ? ToLower(c) : 0; +} + +int Font::FindFaceNameIndex(const String& name) { + if(name == "STDFONT") + return 0; + for(int i = 1; i < GetFaceCount(); i++) + if(GetFaceName(i) == name) + return i; + String n = Filter(name, FontFilter); + for(int i = 1; i < GetFaceCount(); i++) + if(Filter(GetFaceName(i), FontFilter) == n) + return i; + if(n == "serif") + return SERIF; + if(n == "sansserif") + return SANSSERIF; + if(n == "monospace") + return MONOSPACE; + if(n == "stdfont") + return STDFONT; + return 0; +} + +static StaticMutex sFontLock; + +void Font::SyncStdFont() +{ + Mutex::Lock __(sFontLock); + StdFontSize = Size(AStdFont.GetAveWidth(), AStdFont().Bold().GetCy()); +} + +void (*whenSetStdFont)(); + +void Font::SetStdFont(Font font) +{ + Mutex::Lock __(sFontLock); + static int x = 0; + if(x) return; + x++; + InitStdFont(); + AStdFont = font; + SyncStdFont(); + if(whenSetStdFont) + (*whenSetStdFont)(); + x--; +} + +void Font::InitStdFont() +{ + ONCELOCK { + Mutex::Lock __(sFontLock); + List(); + AStdFont = Arial(12); + String name; + int height = 0; + GetStdFontSys(name, height); +#ifdef PLATFORM_WIN32 +#ifdef flagWINGL + AStdFont = Font(FindFaceNameIndex("Tahoma"), 12); +#else + int q = FindFaceNameIndex(name); + if(q <= 0) + q = FindFaceNameIndex("Tahoma"); + if(q <= 0) + q = FindFaceNameIndex("Microsoft Sans Serif"); + if(q <= 0) + q = FindFaceNameIndex("MS Sans Serif"); + if(q > 0) + AStdFont = Font(q, max(height, 1)); +#endif + SyncStdFont(); +#endif + } +} + +Font Font::GetStdFont() +{ + InitStdFont(); + return AStdFont; +} + +Size Font::GetStdFontSize() +{ + InitStdFont(); + return StdFontSize; +} + +Font StdFont() +{ + return Font(0, -32000); +} + +int Font::GetHeight() const +{ + return v.height == -32000 ? GetStdFont().GetHeight() : v.height; +} + +String Font::GetFaceName() const { + if(IsNullInstance()) return String(); + if(GetFace() == 0) + return "STDFONT"; + return GetFaceName(GetFace()); +} + +dword Font::GetFaceInfo() const { + if(IsNullInstance()) return 0; + return GetFaceInfo(GetFace()); +} + +Font& Font::FaceName(const String& name) { + int n = FindFaceNameIndex(name); + Face(n < 0 ? 0xffff : n); + return *this; +} + +void Font::Serialize(Stream& s) { + int version = 1; + s / version; + if(version >= 1) { + enum { + OLD_STDFONT, OLD_SCREEN_SERIF, OLD_SCREEN_SANS, OLD_SCREEN_FIXED, + OLD_ROMAN, + OLD_ARIAL, + OLD_COURIER, + }; + int f = GetFace(); + if(f > COURIER) + f = -1; + s / f; + String name; + if(f == OLD_ROMAN) + f = ROMAN; + if(f == OLD_ARIAL) + f = ARIAL; + if(f == OLD_COURIER) + f = COURIER; + if(f < 0) { + name = GetFaceName(); + s % name; + } + if(s.IsLoading()) + if(f >= 0) + Face(f); + else { + FaceName(name); + if(IsNull(name)) + SetNull(); + } + } + else { + String name = GetFaceName(); + s % name; + if(s.IsLoading()) { + FaceName(name); + if(IsNullInstance()) + Face(COURIER); + } + } + s % v.flags % v.height % v.width; +} + +String Font::GetTextFlags() const +{ + String txt; + if(IsBold()) + txt << "bold "; + if(IsItalic()) + txt << "italic "; + if(IsUnderline()) + txt << "underline "; + if(IsStrikeout()) + txt << "strikeout "; + if(IsNonAntiAliased()) + txt << "noaa "; + if(IsTrueTypeOnly()) + txt << "ttonly "; + if(txt.GetCount()) + txt.Trim(txt.GetCount() - 1); + return txt; +} + +void Font::ParseTextFlags(const char *s) +{ + CParser p(s); + v.flags = 0; + while(!p.IsEof()) { + if(p.Id("bold")) + Bold(); + else + if(p.Id("italic")) + Italic(); + else + if(p.Id("underline")) + Underline(); + else + if(p.Id("strikeout")) + Strikeout(); + else + if(p.Id("noaa")) + NonAntiAliased(); + else + if(p.Id("ttonly")) + TrueTypeOnly(); + else + p.SkipTerm(); + } +} + +String Font::GetFaceNameStd() const +{ + switch(GetFace()) { + case STDFONT: return "STDFONT"; + case SERIF: return "serif"; + case SANSSERIF: return "sansserif"; + case MONOSPACE: return "monospace"; + } + return GetFaceName(); +} + +void Font::Jsonize(JsonIO& jio) +{ + String n, tf; + if(jio.IsStoring()) { + n = GetFaceNameStd(); + tf = GetTextFlags(); + if(IsNullInstance()) + n.Clear(); + } + jio("face", n)("height", v.height)("width", v.width)("flags", tf); + if(IsNull(n)) + SetNull(); + else { + FaceName(n); + ParseTextFlags(tf); + } +} + +void Font::Xmlize(XmlIO& xio) +{ + String n, tf; + if(xio.IsStoring()) { + n = GetFaceNameStd(); + tf = GetTextFlags(); + if(IsNullInstance()) + n.Clear(); + } + xio.Attr("face", n) + .Attr("height", v.height) + .Attr("width", v.width) + .Attr("flags", tf); + if(IsNull(n)) + SetNull(); + else { + FaceName(n); + ParseTextFlags(tf); + } +} + +template<> +String AsString(const Font& f) { + if(IsNull(f)) return ""; + String s = "<" + f.GetFaceName() + Format(":%d", f.GetHeight()); + if(f.IsBold()) + s += " Bold"; + if(f.IsItalic()) + s += " Italic"; + if(f.IsUnderline()) + s += " Underline"; + if(f.IsStrikeout()) + s += " Strikeout"; + return s + '>'; +} + +struct CharEntry { + int64 font; + GlyphInfo info; + word chr; +}; + +CharEntry fc_cache_global[4093]; + +bool IsNormal(Font font, int chr) +{ + Mutex::Lock __(sFontLock); + CharEntry& e = fc_cache_global[CombineHash(font.GetHashValue(), chr) % 4093]; + if(e.font == font.AsInt64() || e.chr == chr) + return e.info.IsNormal(); + return GetGlyphInfoSys(font, chr).IsNormal(); +} + +CharEntry GetGlyphEntry(Font font, int chr, unsigned hash) +{ + Mutex::Lock __(sFontLock); + CharEntry& e = fc_cache_global[hash % 4093]; + if(e.font != font.AsInt64() || e.chr != chr) { + e.font = font.AsInt64(); + e.chr = chr; + e.info = GetGlyphInfoSys(font, chr); + if(!e.info.IsNormal()) { + ComposedGlyph cg; + Font rfnt; + if(Compose(font, chr, cg)) { + e.info.lspc = -1; + e.info.rspc = cg.basic_char; + } + else + if(Replace(font, chr, rfnt)) { + e.info.lspc = rfnt.GetFace(); + e.info.rspc = rfnt.GetHeight(); + } + else + e.info.lspc = -2; + } + } + return e; +} + +thread__ CharEntry fc_cache[512]; + +GlyphInfo GetGlyphInfo(Font font, int chr) +{ + Std(font); + unsigned hash = CombineHash(font.GetHashValue(), chr); + CharEntry& e = fc_cache[hash & 511]; + if(e.font != font.AsInt64() || e.chr != chr) + e = GetGlyphEntry(font, chr, hash); + return e.info; +} + +bool Font::IsNormal(int ch) const +{ + return GetGlyphInfo(*this, ch).IsNormal(); +} + +bool Font::IsComposed(int ch) const +{ + return GetGlyphInfo(*this, ch).IsComposed(); +} + +bool Font::IsReplaced(int ch) const +{ + return GetGlyphInfo(*this, ch).IsReplaced(); +} + +bool Font::IsMissing(int ch) const +{ + return GetGlyphInfo(*this, ch).IsMissing(); +} + +int Font::HasChar(int ch) const +{ + return !GetGlyphInfo(*this, ch).IsMissing(); +} + +void GlyphMetrics(GlyphInfo& f, Font font, int chr) +{ + if(f.IsReplaced()) + f = GetGlyphInfo(font().Face(f.lspc).Height(f.rspc), chr); + if(f.IsComposed()) { + f = GetGlyphInfo(font, f.rspc); + if(f.IsComposedLM()) + f.rspc += f.width / 2; + } +} + +GlyphInfo GetGlyphMetrics(Font font, int chr) +{ + GlyphInfo f = GetGlyphInfo(font, chr); + if(f.IsMissing()) + f = GetGlyphInfo(font, '?'); + GlyphMetrics(f, font, chr); + return f; +} + +struct FontEntry { + CommonFontInfo info; + int64 font; +}; + +thread__ FontEntry fi_cache[64]; + +const CommonFontInfo& GetFontInfo(Font font) +{ + Std(font); + unsigned hash = font.GetHashValue() & 63; + FontEntry& e = fi_cache[hash]; + if(e.font != font.AsInt64()) { + Mutex::Lock __(sFontLock); + e.font = font.AsInt64(); + e.info = GetFontInfoSys(font); + } + return e.info; +} + +int Font::GetWidth(int c) const { + return GetGlyphMetrics(*this, c).width; +} + +int Font::GetLeftSpace(int c) const { + return GetGlyphMetrics(*this, c).lspc; +} + +int Font::GetRightSpace(int c) const { + return GetGlyphMetrics(*this, c).rspc; +} + +thread__ int64 lastFiFont = INT_MIN; +thread__ CommonFontInfo lastFontInfo; +thread__ int64 lastStdFont = INT_MIN; + + +const CommonFontInfo& Font::Fi() const +{ +#ifdef PLATFORM_OSX11 +// known leak on MacOSX here: getAllCarbonLazyValues2000 calls Core.h op new() +// should not call UPP op new() +// from GetFontInfo() ... XftFontOpenPattern() ... getAllCarbonLazyValues2000() -> new() + MemoryIgnoreLeaksBlock __; +#endif + + if(lastStdFont != AStdFont.AsInt64()) { + lastFiFont = INT_MIN; + lastStdFont = AStdFont.AsInt64(); + } + if(AsInt64() == lastFiFont) + return lastFontInfo; + lastFontInfo = GetFontInfo(*this); + lastFiFont = AsInt64(); + return lastFontInfo; +} + +String Font::GetData() const +{ + Mutex::Lock __(sFontLock); + return GetFontDataSys(*this); +} + +void Font::Render(FontGlyphConsumer& sw, double x, double y, int ch) const +{ + Mutex::Lock __(sFontLock); + RenderCharacterSys(sw, x, y, ch, *this); +} + +FontInfo Font::Info() const +{ + FontInfo h; + h.font = *this; + return h; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/FontFc.cpp b/uppsrc/Draw/FontFc.cpp index edf92d606..cdf23f777 100644 --- a/uppsrc/Draw/FontFc.cpp +++ b/uppsrc/Draw/FontFc.cpp @@ -1,238 +1,369 @@ -#include "Draw.h" - -#define LLOG(x) // LOG(x) -#define LTIMING(x) // TIMING(x) - -#ifdef PLATFORM_POSIX - -#include -#include - -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 GetAllFacesSys() -{ - static const char *basic_fonts[] = { - "sans-serif", - "serif", - "sans-serif", - "monospace", - }; - - Vector 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 +#include + +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 GetAllFacesSys() +{ + static const char *basic_fonts[] = { + "sans-serif", + "serif", + "sans-serif", + "monospace", + }; + + Vector 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 diff --git a/uppsrc/Draw/FontInt.h b/uppsrc/Draw/FontInt.h index 876cd2741..edbab4c27 100644 --- a/uppsrc/Draw/FontInt.h +++ b/uppsrc/Draw/FontInt.h @@ -1,54 +1,62 @@ -#ifndef _Draw_FontInt_h_ -#define _Draw_FontInt_h_ - -// Internal header! - -struct FaceInfo : Moveable { - 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 { + 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 GetAllFacesSys(); +String GetFontDataSys(Font font); + +void RenderCharacterSys(FontGlyphConsumer& sw, double x, double y, int ch, Font fnt); + +#endif diff --git a/uppsrc/Draw/FontWin32.cpp b/uppsrc/Draw/FontWin32.cpp index adabe44e6..5ec30bcd3 100644 --- a/uppsrc/Draw/FontWin32.cpp +++ b/uppsrc/Draw/FontWin32.cpp @@ -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 diff --git a/uppsrc/Draw/Image.cpp b/uppsrc/Draw/Image.cpp index 7e37e3577..ee67bb45f 100644 --- a/uppsrc/Draw/Image.cpp +++ b/uppsrc/Draw/Image.cpp @@ -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::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]; diff --git a/uppsrc/Draw/Image.h b/uppsrc/Draw/Image.h index 4c69fff96..87df2ea4f 100644 --- a/uppsrc/Draw/Image.h +++ b/uppsrc/Draw/Image.h @@ -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 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 > { -private: - struct Data : Link { - Atomic refcount; - int64 serial; - int paintcount; - - static Link 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 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(*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 UnpackImlData(const void *ptr, int len); -Vector UnpackImlData(const String& d); - -class Iml { - struct IImage : Moveable { - bool loaded; - Image image; - - IImage() { loaded = false; } - }; - struct Data : Moveable { - const char *data; - int len, count; - }; - Vector data; - VectorMap 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 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 > { +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(*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 UnpackImlData(const void *ptr, int len); +Vector UnpackImlData(const String& d); + +class Iml { + struct IImage : Moveable { + bool loaded; + Image image; + + IImage() { loaded = false; } + }; + struct Data : Moveable { + const char *data; + int len, count; + }; + Vector data; + VectorMap 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" diff --git a/uppsrc/Draw/ImageOp.h b/uppsrc/Draw/ImageOp.h index 7f2b40b87..fab8c12ce 100644 --- a/uppsrc/Draw/ImageOp.h +++ b/uppsrc/Draw/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)); diff --git a/uppsrc/Draw/MakeCache.cpp b/uppsrc/Draw/MakeCache.cpp index 6b458422b..9fe322de5 100644 --- a/uppsrc/Draw/MakeCache.cpp +++ b/uppsrc/Draw/MakeCache.cpp @@ -1,179 +1,232 @@ -#include "Draw.h" - -NAMESPACE_UPP - -#define LLOG(x) // LOG(x) - -static StaticCriticalSection sMakeImage; - -static LRUCache& sImageCache() -{ - static LRUCache m; - return m; -} - -struct scImageMaker : LRUCache::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& cache = sImageCache(); - cache.ClearCounters(); - } -} - -Image MakeImage__(const ImageMaker& m, bool paintonly) -{ - Image result; - INTERLOCKED_(sMakeImage) { - LRUCache& 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 { + ~ImageMakeCacheClass() { sFinished = true; } +}; + +static LRUCache& sImageCache() +{ + static ImageMakeCacheClass m; + return m; +} + +struct scImageMaker : LRUCache::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& cache = sImageCache(); + cache.ClearCounters(); + } +} + +Image MakeImage__(const ImageMaker& m, bool paintonly) +{ + Image result; + INTERLOCKED_(sMakeImage) { + LRUCache& 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 diff --git a/uppsrc/Draw/src.tpp/Font$en-us.tpp b/uppsrc/Draw/src.tpp/Font$en-us.tpp index 83d925227..e4612f6a1 100644 --- a/uppsrc/Draw/src.tpp/Font$en-us.tpp +++ b/uppsrc/Draw/src.tpp/Font$en-us.tpp @@ -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]_>&] +[s1;:Font`:`:class: [@(0.0.255) class]_[* Font]_:_[@(0.0.255) private]_[@3 AssignValueTypeNo]< +Font, FONT`_V, [_^Moveable^ Moveable]_>&] [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; ] \ No newline at end of file +[s0; ]] \ No newline at end of file diff --git a/uppsrc/Painter/FontWin32.cpp b/uppsrc/Painter/FontWin32.cpp index 954a533f9..7c1c7aa52 100644 --- a/uppsrc/Painter/FontWin32.cpp +++ b/uppsrc/Painter/FontWin32.cpp @@ -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 diff --git a/uppsrc/Painter/Painter.cpp b/uppsrc/Painter/Painter.cpp index 6c5223127..2ab4d6ad8 100644 --- a/uppsrc/Painter/Painter.cpp +++ b/uppsrc/Painter/Painter.cpp @@ -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) diff --git a/uppsrc/Painter/Painter.h b/uppsrc/Painter/Painter.h index 04749b72c..78517259e 100644 --- a/uppsrc/Painter/Painter.h +++ b/uppsrc/Painter/Painter.h @@ -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" diff --git a/uppsrc/Painter/Painter.upp b/uppsrc/Painter/Painter.upp index b0d912323..44e676445 100644 --- a/uppsrc/Painter/Painter.upp +++ b/uppsrc/Painter/Painter.upp @@ -10,7 +10,6 @@ file SvgArc.cpp, PainterPath.cpp, FontWin32.cpp, - FontX11.cpp, DrawOp.cpp, Painting.h, Painting.cpp, diff --git a/uppsrc/PdfDraw/PdfDraw.cpp b/uppsrc/PdfDraw/PdfDraw.cpp index f6a44d1da..a805881fe 100644 --- a/uppsrc/PdfDraw/PdfDraw.cpp +++ b/uppsrc/PdfDraw/PdfDraw.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 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; diff --git a/uppsrc/RichText/Para.h b/uppsrc/RichText/Para.h index da60c2b1d..4aa7c0303 100644 --- a/uppsrc/RichText/Para.h +++ b/uppsrc/RichText/Para.h @@ -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& Cache(); struct StorePart; diff --git a/uppsrc/RichText/ParaData.cpp b/uppsrc/RichText/ParaData.cpp index 37d2aa468..2cd2321df 100644 --- a/uppsrc/RichText/ParaData.cpp +++ b/uppsrc/RichText/ParaData.cpp @@ -2,6 +2,8 @@ NAMESPACE_UPP +StaticMutex RichPara::cache_lock; + Array& RichPara::Cache() { static Array x; @@ -24,7 +26,7 @@ RichPara::RichPara() RichPara::~RichPara() { if(cacheid && !part.IsPicked() && !incache) { - DrawLock __; + Mutex::Lock __(cache_lock); Array& cache = Cache(); incache = true; cache.InsertPick(0, *this); @@ -566,7 +568,7 @@ void RichPara::Unpack(const String& data, const Array& obj, format = style; if(cacheid) { - DrawLock __; + Mutex::Lock __(cache_lock); Array& cache = Cache(); for(int i = 0; i < cache.GetCount(); i++) if(cache[i].cacheid == cacheid) { diff --git a/uppsrc/RichText/ParaType.cpp b/uppsrc/RichText/ParaType.cpp index e68a53865..9e459cd7b 100644 --- a/uppsrc/RichText/ParaType.cpp +++ b/uppsrc/RichText/ParaType.cpp @@ -215,7 +215,7 @@ Array& RichPara::Lines::Cache() RichPara::Lines::~Lines() { if(cacheid && !line.IsPicked() && !incache) { - DrawLock __; + Mutex::Lock __(cache_lock); Array& 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& cache = Lines::Cache(); for(int i = 0; i < cache.GetCount(); i++) if(cache[i].cacheid == cacheid && cache[i].cx == acx) { diff --git a/uppsrc/ide/ide.upp b/uppsrc/ide/ide.upp index 10912a347..05439f676 100644 --- a/uppsrc/ide/ide.upp +++ b/uppsrc/ide/ide.upp @@ -94,7 +94,7 @@ mainconfig "" = "GUI HEAPDBG CHECKINIT", "" = "GUI TESTINSTALL", "" = "GUI CHECKCLIPBOARD", - "" = "GUI SVO_VALUE"; + "" = "GUI MT"; custom() "", "",