diff --git a/newdraw/Draw/BackDraw.cpp b/newdraw/Draw/BackDraw.cpp index c9a6cb8bd..370d447ae 100644 --- a/newdraw/Draw/BackDraw.cpp +++ b/newdraw/Draw/BackDraw.cpp @@ -37,7 +37,7 @@ bool ScreenInPaletteMode() Size GetScreenSize() { - return ScreenInfo().GetPagePixels(); + return ScreenInfo().GetPageSize(); } END_UPP_NAMESPACE diff --git a/newdraw/Draw/Draw.cpp b/newdraw/Draw/Draw.cpp index ca07c3d66..c52db208a 100644 --- a/newdraw/Draw/Draw.cpp +++ b/newdraw/Draw/Draw.cpp @@ -33,26 +33,24 @@ Draw::~Draw() {} Size Draw::GetPixelsPerInch() const { - return Dots() ? Size(600, 600) : Size(96, 96); + return IsNative() ? GetNativeDpi() : Dots() ? Size(600, 600) : Size(96, 96); } Size Draw::GetPageMMs() const { - return GetPagePixels() * 254 / (10 * GetPixelsPerInch()); + return GetPageSize() * 254 / (10 * GetPixelsPerInch()); } int Draw::GetNativeX(int x) const { - Size inchPixels = GetPixelsPerInch(); - Size nativeDpi = GetNativeDpi(); - return inchPixels != nativeDpi ? iscale(x, nativeDpi.cx, 600) : x; + Size sz = GetNativeDpi(); + return Dots() && sz.cx != 600 ? iscale(x, sz.cx, 600) : x; } int Draw::GetNativeY(int y) const { - Size inchPixels = GetPixelsPerInch(); - Size nativeDpi = GetNativeDpi(); - return inchPixels != nativeDpi ? iscale(y, nativeDpi.cy, 600) : y; + Size sz = GetNativeDpi(); + return Dots() && sz.cx != 600 ? iscale(y, sz.cy, 600) : y; } void Draw::Native(int& x, int& y) const @@ -95,6 +93,8 @@ void LeaveDraw() { sDrawLock.Leave(); } +Size Draw::GetPageSize() const { return Size(0, 0); } + void Draw::StartPage() {} void Draw::EndPage() {} @@ -431,7 +431,7 @@ void Draw::Flush() // --------------------------- dword NilDraw::GetInfo() const { return DOTS; } -Size NilDraw::GetPagePixels() const { return Size(0, 0); } +Size NilDraw::GetPageSize() const { return Size(0, 0); } void NilDraw::BeginOp() {} void NilDraw::EndOp() {} void NilDraw::OffsetOp(Point p) {} diff --git a/newdraw/Draw/Draw.h b/newdraw/Draw/Draw.h index 9dd34c09e..4f0faf5a0 100644 --- a/newdraw/Draw/Draw.h +++ b/newdraw/Draw/Draw.h @@ -1,6 +1,8 @@ #ifndef DRAW_H #define DRAW_H +#define SYSTEMDRAW 1 + #include #ifdef PLATFORM_X11 @@ -563,8 +565,8 @@ public: }; virtual dword GetInfo() const = 0; - virtual Size GetPagePixels() const = 0; + virtual Size GetPageSize() const; virtual void StartPage(); virtual void EndPage(); @@ -808,7 +810,7 @@ public: class DrawingDraw : public Draw { public: virtual dword GetInfo() const; - virtual Size GetPagePixels() const; + virtual Size GetPageSize() const; virtual void BeginOp(); virtual void EndOp(); virtual void OffsetOp(Point p); @@ -863,7 +865,7 @@ public: class NilDraw : public Draw { public: virtual dword GetInfo() const; - virtual Size GetPagePixels() const; + virtual Size GetPageSize() const; virtual void BeginOp(); virtual void EndOp(); virtual void OffsetOp(Point p); @@ -991,6 +993,8 @@ DrawingToPdfFnType GetDrawingToPdfFn(); #include "Debug.h" #include "Cham.h" +typedef ImageDraw SystemImageDraw; + END_UPP_NAMESPACE #endif diff --git a/newdraw/Draw/DrawWin32.cpp b/newdraw/Draw/DrawWin32.cpp index 083b1e637..ea23d04ef 100644 --- a/newdraw/Draw/DrawWin32.cpp +++ b/newdraw/Draw/DrawWin32.cpp @@ -11,17 +11,17 @@ static COLORREF sLightGray; dword SystemDraw::GetInfo() const { - return native ? style|NATIVE : style; + return native || !(style & DOTS) ? style|NATIVE : style; } -Size SystemDraw::GetPagePixels() const +Size SystemDraw::GetPageSize() const { - return pagePixels; + return native && Dots() ? nativeSize : pageSize; } Size SystemDraw::GetNativeDpi() const { - return nativeDpi; + return Dots() ? nativeDpi : Size(96, 96); } void StaticExitDraw_() @@ -257,7 +257,7 @@ void SystemDraw::LoadCaps() { palette = (GetDeviceCaps(handle, RASTERCAPS) & RC_PALETTE); if(palette) color16 = GetDeviceCaps(handle, SIZEPALETTE) != 256; - pagePixels = GetSizeCaps(HORZRES, VERTRES); + nativeSize = pageSize = GetSizeCaps(HORZRES, VERTRES); nativeDpi = GetSizeCaps(LOGPIXELSX, LOGPIXELSY); is_mono = GetDeviceCaps(handle, BITSPIXEL) == 1 && GetDeviceCaps(handle, PLANES) == 1; } @@ -420,6 +420,8 @@ void PrintDraw::InitPrinter() native = 0; actual_offset = Point(0, 0); aborted = false; + pageSize.cx = 600 * nativeSize.cx / nativeDpi.cx; + pageSize.cy = 600 * nativeSize.cy / nativeDpi.cy; } void PrintDraw::StartPage() diff --git a/newdraw/Draw/DrawWin32.h b/newdraw/Draw/DrawWin32.h index 235187f3d..d4310c791 100644 --- a/newdraw/Draw/DrawWin32.h +++ b/newdraw/Draw/DrawWin32.h @@ -3,7 +3,7 @@ class SystemDraw : public Draw { public: virtual dword GetInfo() const; - virtual Size GetPagePixels() const; + virtual Size GetPageSize() const; virtual void BeginOp(); virtual void EndOp(); @@ -39,7 +39,8 @@ public: virtual int GetCloffLevel() const; private: - Size pagePixels; + Size pageSize; + Size nativeSize; Size nativeDpi; bool palette:1; bool color16:1; @@ -135,22 +136,28 @@ public: }; #ifndef PLATFORM_WINCE -class WinMetaFile { +class WinMetaFile/* : NoCopy */{ Size size; - mutable HENHMETAFILE hemf; + /*mutable */HENHMETAFILE hemf; //TODO: Remove picks - void ChkP() const { ASSERT(!IsPicked()); } + void ChkP() const { /*ASSERT(!IsPicked());*/ } void Init(); - void Pick(pick_ WinMetaFile& src); - void Copy(const WinMetaFile& src); +// void Pick(pick_ WinMetaFile& src); +// void Copy(const WinMetaFile& src); public: void Attach(HENHMETAFILE emf); HENHMETAFILE *Detach(); + + void Set(const void *data, int len); + void Set(const String& data) { Set(~data, data.GetCount()); } + + String Get() const; - bool IsPicked() const { return (uintptr_t) hemf == 0xffffffff; } +// bool IsPicked() const { return (uintptr_t) hemf == 0xffffffff; } operator bool() const { ChkP(); return hemf; } + void SetSize(const Size& sz) { size = sz; } Size GetSize() const { ChkP(); return hemf ? size : Size(0, 0); } void Clear(); @@ -162,17 +169,19 @@ public: void ReadClipboard(); void WriteClipboard() const; - bool Load(const char *file); + void Load(const char *file) { Set(LoadFile(file)); } - WinMetaFile() { Init(); } + WinMetaFile() { Init(); } WinMetaFile(HENHMETAFILE hemf); WinMetaFile(HENHMETAFILE hemf, Size sz); WinMetaFile(const char *file); + WinMetaFile(void *data, int len); + WinMetaFile(const String& data); - WinMetaFile(pick_ WinMetaFile& src) { Pick(src); } - WinMetaFile(const WinMetaFile& src, int) { Copy(src); } - void operator=(pick_ WinMetaFile& src) { Clear(); Pick(src); } - void operator<<=(const WinMetaFile& src) { Clear(); Copy(src); } +// WinMetaFile(pick_ WinMetaFile& src) { Pick(src); } +// WinMetaFile(const WinMetaFile& src, int) { Copy(src); } +// void operator=(pick_ WinMetaFile& src) { Clear(); Pick(src); } +// void operator<<=(const WinMetaFile& src) { Clear(); Copy(src); } ~WinMetaFile() { Clear(); } @@ -192,6 +201,14 @@ public: WinMetaFileDraw(int cx, int cy, const char *app = NULL, const char *name = NULL, const char *file = NULL); ~WinMetaFileDraw(); }; + +void DrawWMF(Draw& w, int x, int y, int cx, int cy, const String& wmf); +void DrawWMF(Draw& w, int x, int y, const String& wmf); +Drawing LoadWMF(const char *path, int cx, int cy); +Drawing LoadWMF(const char *path); + +String AsWMF(const Drawing& iw); + #endif class ScreenDraw : public SystemDraw { diff --git a/newdraw/Draw/DrawX11.h b/newdraw/Draw/DrawX11.h index 37c1e5c79..6b7ba3447 100644 --- a/newdraw/Draw/DrawX11.h +++ b/newdraw/Draw/DrawX11.h @@ -189,7 +189,7 @@ public: bool PaletteMode() const { return palette; } bool IsMono() const { return is_mono; } - Size GetPagePixels() const { return native ? pagePixels : pageDots; } + Size GetPageSize() const { return native ? pagePixels : pageDots; } Size GetPixelsPerInch() const { return native ? nativeDpi : inchPixels; } Size GetPageMMs() const { return pageMMs; } @@ -219,7 +219,7 @@ public: bool IsDrawing() const; virtual dword GetInfo() const; - virtual Size GetPagePixels() const; + virtual Size GetPageSize() const; virtual void StartPage(); virtual void EndPage(); @@ -539,7 +539,7 @@ public: bool IsDrawing() const; virtual dword GetInfo() const; - virtual Size GetPagePixels() const; + virtual Size GetPageSize() const; virtual void StartPage(); virtual void EndPage(); diff --git a/newdraw/Draw/Drawing.cpp b/newdraw/Draw/Drawing.cpp index 7808c962a..cc1947ef0 100644 --- a/newdraw/Draw/Drawing.cpp +++ b/newdraw/Draw/Drawing.cpp @@ -109,7 +109,7 @@ dword DrawingDraw::GetInfo() const return DOTS; } -Size DrawingDraw::GetPagePixels() const +Size DrawingDraw::GetPageSize() const { return size; } diff --git a/newdraw/Draw/MetaFile.cpp b/newdraw/Draw/MetaFile.cpp index 803038200..fbf20199e 100644 --- a/newdraw/Draw/MetaFile.cpp +++ b/newdraw/Draw/MetaFile.cpp @@ -11,9 +11,17 @@ void WinMetaFile::Init() { void WinMetaFile::Paint(Draw& w, const Rect& r) const { ChkP(); + if(!hemf) + return; SystemDraw *h = dynamic_cast(&w); - if(hemf && h) + if(h) PlayEnhMetaFile(h->GetHandle(), hemf, r); + else { + Size sz = r.GetSize(); + SystemImageDraw iw(sz); + Paint(iw, sz); + w.DrawImage(r.left, r.top, iw); + } } void WinMetaFile::Paint(Draw& w, int x, int y, int cx, int cy) const { @@ -38,11 +46,12 @@ void WinMetaFile::WriteClipboard() const { } void WinMetaFile::Clear() { - if(hemf && !IsPicked()) + if(hemf/* && !IsPicked()*/) //TODO ::DeleteEnhMetaFile(hemf); hemf = NULL; } +/* TODO: Remove picks void WinMetaFile::Pick(pick_ WinMetaFile& src) { hemf = src.hemf; size = src.size; @@ -53,7 +62,7 @@ void WinMetaFile::Copy(const WinMetaFile& src) { hemf = ::CopyEnhMetaFile(src.hemf, NULL); size = src.size; } - +*/ void WinMetaFile::Attach(HENHMETAFILE _hemf) { Clear(); ENHMETAHEADER info; @@ -64,8 +73,9 @@ void WinMetaFile::Attach(HENHMETAFILE _hemf) { if(_hemf && ::GetEnhMetaFileHeader(_hemf, sizeof(info), &info) && info.rclFrame.left < info.rclFrame.right && info.rclFrame.top < info.rclFrame.bottom) { - size.cx = 600 * (info.rclFrame.right - info.rclFrame.left) / 2540; - size.cy = 600 * (info.rclFrame.bottom - info.rclFrame.top) / 2540; + size.cx = info.rclFrame.right - info.rclFrame.left; + size.cy = info.rclFrame.bottom - info.rclFrame.top; + size = 600 * size / 2540; hemf = _hemf; } } @@ -82,52 +92,35 @@ struct PLACEABLE_METAFILEHEADER }; #pragma pack(pop) -bool WinMetaFile::Load(const char* path) { +void WinMetaFile::Set(const void *data, int len) +{ Clear(); - FileIn file(path); - if(!file.Open(path) || file.GetSize() <= sizeof(ENHMETAHEADER)) - return false; - int first = file.Get32le(); - file.Seek(0); + if(len <= sizeof(ENHMETAHEADER)) + return; + + int first = Peek32le(data); HENHMETAFILE hemf; - HMETAFILE hMF; - Size sz(1000, 1000); - - if(first == 0x9AC6CDD7) { - PLACEABLE_METAFILEHEADER mfh; - file.Get(&mfh, 22); - String bits = LoadStream(file); - if((hMF = ::SetMetaFileBitsEx(bits.GetLength(), bits)) == NULL) - return false; - sz = Size(mfh.right - mfh.left, mfh.bottom - mfh.top); - } - else - if((hemf = ::GetEnhMetaFile(path)) != NULL) { + if((hemf = ::SetEnhMetaFileBits(len, (const BYTE *)data)) != NULL) Attach(hemf); - return true; + else + if(first == 0x9AC6CDD7) { + const PLACEABLE_METAFILEHEADER *mfh = (const PLACEABLE_METAFILEHEADER *)data; + Attach(::SetWinMetaFileBits(len - 22, (const BYTE *)data + 22, NULL, NULL)); + size = 600 * Size(mfh->right - mfh->left, mfh->bottom - mfh->top) / 2540; + return; } else - if((LOWORD(first) == 1 || LOWORD(first) == 2) && HIWORD(first) >= sizeof(METAHEADER) / 2) { - METAHEADER mh; - if(!file.GetAll(&mh, sizeof(mh))) - return false; - if(mh.mtVersion != 0x100 && mh.mtVersion != 0x300) - return false; - if((hMF = ::GetMetaFile(path)) == NULL) - return false; - } - else - return false; + Attach(::SetWinMetaFileBits(len, (const BYTE *)data, NULL, NULL)); +} - dword len = ::GetMetaFileBitsEx(hMF, 0, NULL); - Buffer bits(len); - ::GetMetaFileBitsEx(hMF, len, bits); - Attach(::SetWinMetaFileBits(len, bits, NULL, NULL)); - ::DeleteMetaFile(hMF); - size = sz; - return true; +String WinMetaFile::Get() const +{ + int size = ::GetEnhMetaFileBits(hemf, 0, 0); + StringBuffer b(size); + ::GetEnhMetaFileBits(hemf, size, (BYTE *)~b); + return b; } void WinMetaFile::Serialize(Stream& s) { @@ -155,6 +148,18 @@ void WinMetaFile::Serialize(Stream& s) { } } +WinMetaFile::WinMetaFile(void *data, int len) +{ + Init(); + Set(data, len); +} + +WinMetaFile::WinMetaFile(const String& data) +{ + Init(); + Set(data); +} + WinMetaFile::WinMetaFile(HENHMETAFILE hemf) { Init(); Attach(hemf); @@ -171,6 +176,71 @@ WinMetaFile::WinMetaFile(const char *file) { Load(file); } +struct cDrawWMF : DataDrawer { + int y; + Size sz; + WinMetaFile wmf; + + virtual void Open(const String& data, int cx, int cy); + virtual void Render(ImageBuffer& ib); +}; + +void cDrawWMF::Open(const String& data, int cx, int cy) +{ + y = 0; + wmf.Set(data); + sz = Size(cx, cy); +} + +void cDrawWMF::Render(ImageBuffer& ib) +{ + if(wmf) { + ImageDraw iw(ib.GetSize()); + wmf.Paint(iw, 0, -y, sz.cx, sz.cy); + y += ib.GetHeight(); + ib = (Image)iw; + } + else + Fill(~ib, RGBAZero(), ib.GetLength()); +} + +INITBLOCK +{ + DataDrawer::Register("wmf"); +}; + +void DrawWMF(Draw& w, int x, int y, int cx, int cy, const String& wmf) +{ + w.DrawData(x, y, cx, cy, wmf, "wmf"); +} + +void DrawWMF(Draw& w, int x, int y, const String& wmf) +{ + WinMetaFile h(wmf); + Size sz = h.GetSize(); + DrawWMF(w, x, y, sz.cx, sz.cy, wmf); +} + +Drawing LoadWMF(const char *path, int cx, int cy) +{ + DrawingDraw iw(cx, cy); + DrawWMF(iw, 0, 0, cx, cy, LoadFile(path)); + return iw; +} + +Drawing LoadWMF(const char *path) +{ + String wmf = LoadFile(path); + WinMetaFile h(wmf); + if(h) { + Size sz = h.GetSize(); + DrawingDraw iw(sz.cx, sz.cy); + DrawWMF(iw, 0, 0, sz.cx, sz.cy, wmf); + return iw; + } + return Null; +} + bool WinMetaFileDraw::Create(HDC hdc, int cx, int cy, const char *app, const char *name, const char *file) { if(handle) Close(); @@ -240,6 +310,14 @@ WinMetaFileDraw::WinMetaFileDraw(int cx, int cy, const char *app, const char *na Create(cx, cy, app, name, file); } +String AsWMF(const Drawing& iw) +{ + Size sz = iw.GetSize(); + WinMetaFileDraw wd(sz.cx, sz.cy); + wd.DrawDrawing(0, 0, sz.cx, sz.cy, iw); + return wd.Close().Get(); +} + #endif #endif diff --git a/newdraw/Painter/Approximate.cpp b/newdraw/Painter/Approximate.cpp new file mode 100644 index 000000000..735f904ec --- /dev/null +++ b/newdraw/Painter/Approximate.cpp @@ -0,0 +1,74 @@ +#include "Painter.h" + +NAMESPACE_UPP + +static void sQuadratic(LinearPathConsumer& t, const Pointf& p1, const Pointf& p2, const Pointf& p3, + double qt, int lvl) +{ + if(lvl < 16) { + PAINTER_TIMING("Quadratic approximation"); + Pointf d = p3 - p1; + double q = Squared(d); + if(q > 1e-30) { + Pointf pd = p2 - p1; + double u = (pd.x * d.x + pd.y * d.y) / q; + if(u <= 0 || u >= 1 || SquaredDistance(u * d, pd) > qt) { + Pointf p12 = Mid(p1, p2); + Pointf p23 = Mid(p2, p3); + Pointf div = Mid(p12, p23); + sQuadratic(t, p1, p12, div, qt, lvl + 1); + sQuadratic(t, div, p23, p3, qt, lvl + 1); + return; + } + } + } + t.Line(p3); +} + +void ApproximateQuadratic(LinearPathConsumer& t, const Pointf& p1, const Pointf& p2, const Pointf& p3, + double tolerance) +{ + sQuadratic(t, p1, p2, p3, tolerance * tolerance, 0); +// t.Line(p3); +} + +static void sCubic(LinearPathConsumer& t, + const Pointf& p1, const Pointf& p2, const Pointf& p3, const Pointf& p4, + double qt, int lvl) +{ + if(lvl < 16) { + PAINTER_TIMING("Cubic approximation"); + Pointf d = p4 - p1; + double q = d.x * d.x + d.y * d.y; + if(q >= 1e-30) { + Pointf d2 = p2 - p1; + Pointf d3 = p3 - p1; + double u1 = (d2.x * d.x + d2.y * d.y) / q; + double u2 = (d3.x * d.x + d3.y * d.y) / q; + if(u1 <= 0 || u1 >= 1 || u2 <= 0 || u2 >= 1 || + SquaredDistance(u1 * d, d2) > qt || SquaredDistance(u2 * d, d3) > qt) { + Pointf p12 = Mid(p1, p2); + Pointf p23 = Mid(p2, p3); + Pointf p34 = Mid(p3, p4); + Pointf p123 = Mid(p12, p23); + Pointf p234 = Mid(p23, p34); + Pointf div = Mid(p123, p234); + Pointf p14 = Mid(p1, p4); + sCubic(t, p1, p12, p123, div, qt, lvl + 1); + sCubic(t, div, p234, p34, p4, qt, lvl + 1); + return; + } + } + } + t.Line(p4); +} + +void ApproximateCubic(LinearPathConsumer& t, + const Pointf& p1, const Pointf& p2, const Pointf& p3, const Pointf& p4, + double tolerance) +{ + sCubic(t, p1, p2, p3, p4, tolerance * tolerance, 0); + t.Line(p4); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/BufferPainter.h b/newdraw/Painter/BufferPainter.h new file mode 100644 index 000000000..803117545 --- /dev/null +++ b/newdraw/Painter/BufferPainter.h @@ -0,0 +1,361 @@ +struct LinearPathConsumer { + virtual void Move(const Pointf& p) = 0; + virtual void Line(const Pointf& p) = 0; + virtual void End(); +}; + +void ApproximateQuadratic(LinearPathConsumer& t, + const Pointf& p1, const Pointf& p2, const Pointf& p3, + double tolerance); +void ApproximateCubic(LinearPathConsumer& t, + const Pointf& x0, const Pointf& x1, const Pointf& x2, const Pointf& x, + double tolerance); + +struct LinearPathFilter : LinearPathConsumer { + virtual void End(); + + LinearPathConsumer *target; + + void PutMove(const Pointf& p) { target->Move(p); } + void PutLine(const Pointf& p) { target->Line(p); } + void PutEnd() { target->End(); } +}; + +class Stroker : public LinearPathFilter { +public: + virtual void Move(const Pointf& p); + virtual void Line(const Pointf& p); + virtual void End(); + +private: + double w2; + double qmiter; + double fid; + + Pointf p0, v0, o0, a0, b0; + Pointf p1, v1, o1, a1, b1; + Pointf p2; + int linecap; + int linejoin; + + void Finish(); + void Round(const Pointf& p, const Pointf& v1, const Pointf& v2, double r); + void Cap(const Pointf& p0, const Pointf& v0, const Pointf& o0, + const Pointf& a0, const Pointf& b0); + +public: + void Init(double width, double miterlimit, double tolerance, int linecap, int linejoin); +}; + +class Dasher : public LinearPathFilter { +public: + virtual void Move(const Pointf& p); + virtual void Line(const Pointf& p); + +private: + const Vector *pattern; + int patterni; + double sum, rem; + bool flag; + Pointf p0; + + void Put(const Pointf& p); + +public: + void Init(const Vector& pattern, double distance); +}; + +struct Transformer : public LinearPathFilter { +public: + virtual void Move(const Pointf& p); + virtual void Line(const Pointf& p); + +private: + const Xform2D& xform; + +public: + Transformer(const Xform2D& xform) : xform(xform) {} +}; + +inline RGBA Mul8(const RGBA& s, int mul) +{ + RGBA t; + t.r = (mul * s.r) >> 8; + t.g = (mul * s.g) >> 8; + t.b = (mul * s.b) >> 8; + t.a = (mul * s.a) >> 8; + return t; +} + +inline void AlphaBlend(RGBA& t, const RGBA& c) +{ + int alpha = 256 - (c.a + (c.a >> 7)); + t.r = c.r + (alpha * t.r >> 8); + t.g = c.g + (alpha * t.g >> 8); + t.b = c.b + (alpha * t.b >> 8); + t.a = c.a + (alpha * t.a >> 8); +} + +inline void AlphaBlendCover8(RGBA& t, const RGBA& c, int cover) +{ + int a = c.a * cover >> 8; + int alpha = 256 - a - (a >> 7); + t.r = (c.r * cover >> 8) + (alpha * t.r >> 8); + t.g = (c.g * cover >> 8) + (alpha * t.g >> 8); + t.b = (c.b * cover >> 8) + (alpha * t.b >> 8); + t.a = a + (alpha * t.a >> 8); +} + +class Rasterizer : public LinearPathConsumer { +public: + virtual void Move(const Pointf& p); + virtual void Line(const Pointf& p); + +private: + struct Cell : Moveable { + int16 x; + int16 cover; + int area; + + bool operator<(const Cell& b) const { return x < b.x; } + }; + + Rectf cliprect; + Pointf p0; + Buffer< Vector > cell; + int min_y; + int max_y; + Size sz; + double mx; + + void Init(); + Cell *AddCells(int y, int n); + void RenderHLine(int ey, int x1, int y1, int x2, int y2); + void LineClip(double x1, double y1, double x2, double y2); + int CvX(double x); + int CvY(double y); + void CvLine(double x1, double y1, double x2, double y2); + bool BeginRender(int y, const Cell *&c, const Cell *&e); + + static int Q8Y(double y) { return int(y * 256 + 0.5); } + int Q8X(double x) { return int(x * mx + 0.5); } + +public: + struct Filler { + virtual void Start(int x, int len) = 0; + virtual void Render(int val) = 0; + virtual void Render(int val, int len) = 0; + virtual void End(); + }; + + void LineRaw(int x1, int y1, int x2, int y2); + + void SetClip(const Rectf& rect); + + int MinY() const { return min_y; } + int MaxY() const { return max_y; } + void Render(int y, Filler& g, bool evenodd); + + void Reset(); + + Rasterizer(int cx, int cy, bool subpixel); +}; + +struct SpanSource { + virtual void Get(RGBA *span, int x, int y, unsigned len) = 0; +}; + +class ClipLine : NoCopy { + byte *data; + +public: + void Clear() { if(!IsFull()) delete[] data; data = NULL; } + void Set(const byte *s, int len) { data = new byte[len]; memcpy(data, s, len); } + void SetFull() { ASSERT(!data); data = (byte *)1; } + + bool IsEmpty() const { return !data; } + bool IsFull() const { return data == (byte *)1; } + operator const byte*() const { return data; } + + ClipLine() { data = NULL; } + ~ClipLine() { Clear(); } +}; + +Image MipMap(const Image& img); +Image MakeMipMap(const Image& img, int level); + +class LinearInterpolator { + struct Dda2 { + int count, lift, rem, mod, p; + + void Set(int a, int b, int len); + int Get(); + }; + + Xform2D xform; + Dda2 ddax, dday; + + static int Q8(double x) { return int(256 * x + 0.5); } + +public: + void Set(const Xform2D& m) { xform = m; } + + void Begin(int x, int y, int len); + Point Get(); +}; + +class BufferPainter : public Painter { +protected: + virtual void ClearOp(const RGBA& color); + + virtual void MoveOp(const Pointf& p, bool rel); + virtual void LineOp(const Pointf& p, bool rel); + virtual void QuadraticOp(const Pointf& p1, const Pointf& p, bool rel); + virtual void QuadraticOp(const Pointf& p, bool rel); + virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel); + virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel); + virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel); + virtual void SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep, + const Pointf& p, bool rel); + virtual void CloseOp(); + virtual void DivOp(); + + virtual void CharacterOp(const Pointf& p, int ch, Font fnt); + + virtual void FillOp(const RGBA& color); + virtual void FillOp(const Image& image, const Xform2D& transsrc, dword flags); + virtual void FillOp(const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, + int style); + virtual void FillOp(const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, + int style); + + virtual void StrokeOp(double width, const RGBA& rgba); + virtual void StrokeOp(double width, const Image& image, const Xform2D& transsrc, + dword flags); + virtual void StrokeOp(double width, const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, + int style); + virtual void StrokeOp(double width, const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, + int style); + + virtual void ClipOp(); + + virtual void ColorStopOp(double pos, const RGBA& color); + virtual void ClearStopsOp(); + + virtual void OpacityOp(double o); + virtual void LineCapOp(int linecap); + virtual void LineJoinOp(int linejoin); + virtual void MiterLimitOp(double l); + virtual void EvenOddOp(bool evenodd); + virtual void DashOp(const Vector& dash, double start); + + virtual void TransformOp(const Xform2D& m); + + virtual void BeginOp(); + virtual void EndOp(); + + virtual void BeginMaskOp(); + virtual void BeginOnPathOp(double q, bool abs); + +private: + enum { + MOVE, LINE, QUADRATIC, CUBIC, DIV, CHAR + }; + struct LinearData { + Pointf p; + }; + struct QuadraticData : LinearData { + Pointf p1; + }; + struct CubicData : QuadraticData { + Pointf p2; + }; + struct CharData : LinearData { + int ch; + int _filler; + Font fnt; + }; + struct Path { + Vector type; + Vector data; + }; + struct PathLine : Moveable { + Pointf p; + double len; + }; + struct Attr : Moveable { + Xform2D mtx; + bool evenodd; + byte join; + byte cap; + double miter_limit; + WithDeepCopy< Vector > dash; + WithDeepCopy< Vector > stop; + WithDeepCopy< Vector > stop_color; + double dash_start; + double opacity; + + int cliplevel; + bool hasclip; + bool mask; + bool onpath; + }; + + ImageBuffer& ib; + int mode; + Buffer subpixel; + int render_cx; + + Attr attr; + Attr pathattr; + Array attrstack; + Vector< Buffer > clip; + Array< ImageBuffer > mask; + Vector< Vector > onpathstack; + Vector pathlenstack; + + Image gradient; + RGBA gradient1, gradient2; + int gradientn; + + Path path; + Pointf current, ccontrol, qcontrol, move; + Rectf pathrect; + bool ischar; + + Rasterizer rasterizer; + Buffer span; + + Vector onpath; + double pathlen; + + struct OnPathTarget; + friend struct OnPathTarget; + + void *PathAddRaw(int type, int size); + template T& PathAdd(int type) { return *(T *)PathAddRaw(type, sizeof(T)); } + + Pointf PathPoint(const Pointf& p, bool rel); + Pointf EndPoint(const Pointf& p, bool rel); + void DoMove0(); + void ClearPath(); + void ApproximateChar(LinearPathConsumer& t, const CharData& ch, double tolerance); + Buffer RenderPath(double width, SpanSource *ss, const RGBA& color); + void RenderImage(double width, const Image& image, const Xform2D& transsrc, + dword flags); + void RenderRadial(double width, const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, int style); + void MakeGradient(RGBA color1, RGBA color2, int cx); + void Gradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2); + void ColorStop0(Attr& a, double pos, const RGBA& color); + void FinishMask(); + + enum { FILL = -1, CLIP = -2, ONPATH = -3 }; + +public: + BufferPainter(ImageBuffer& ib, int mode = MODE_ANTIALIASED); +}; diff --git a/newdraw/Painter/Context.cpp b/newdraw/Painter/Context.cpp new file mode 100644 index 000000000..b4bbe03bc --- /dev/null +++ b/newdraw/Painter/Context.cpp @@ -0,0 +1,133 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void BufferPainter::BeginOp() +{ + attr.onpath = false; + attrstack.Add(attr); + attr.hasclip = false; +} + +void BufferPainter::EndOp() +{ + if(attrstack.GetCount() == 0) { + NEVER_("Painter::End: attribute stack is empty"); + return; + } + pathattr = attr = attrstack.Top(); + attrstack.Drop(); + clip.SetCount(attr.cliplevel); + if(attr.mask) + FinishMask(); + if(attr.onpath) { + attr.onpath = false; + onpath = onpathstack.Top(); + onpathstack.Drop(); + pathlen = pathlenstack.Pop(); + } +} + +void BufferPainter::TransformOp(const Xform2D& m) +{ + ASSERT_(IsNull(current), "Cannot change transformation during path definition"); + pathattr.mtx = attr.mtx = m * attr.mtx; +} + +void BufferPainter::OpacityOp(double o) +{ + pathattr.opacity *= o; + if(IsNull(current)) + attr.opacity *= o; +} + +void BufferPainter::LineCapOp(int linecap) +{ + pathattr.cap = linecap; + if(IsNull(current)) + attr.cap = linecap; +} + +void BufferPainter::LineJoinOp(int linejoin) +{ + pathattr.join = linejoin; + if(IsNull(current)) + attr.join = linejoin; +} + +void BufferPainter::MiterLimitOp(double l) +{ + pathattr.miter_limit = l; + if(IsNull(current)) + attr.miter_limit = l; +} + +void BufferPainter::EvenOddOp(bool evenodd) +{ + pathattr.evenodd = evenodd; + if(IsNull(current)) + attr.evenodd = evenodd; +} + +void BufferPainter::DashOp(const Vector& dash, double start) +{ + pathattr.dash <<= dash; + pathattr.dash_start = start; + if(IsNull(current)) { + attr.dash <<= dash; + attr.dash_start = start; + } +} + +void BufferPainter::ColorStop0(Attr& a, double pos, const RGBA& color) +{ + pos = minmax(pos, 0.0, 1.0); + int i = FindLowerBound(a.stop, pos); + a.stop.Insert(i, pos); + a.stop_color.Insert(i, color); +} + +void BufferPainter::ColorStopOp(double pos, const RGBA& color) +{ + ColorStop0(pathattr, pos, color); + if(IsNull(current)) + ColorStop0(attr, pos, color); +} + +void BufferPainter::ClearStopsOp() +{ + pathattr.stop.Clear(); + pathattr.stop_color.Clear(); + if(IsNull(current)) { + attr.stop.Clear(); + attr.stop_color.Clear(); + } +} + +BufferPainter::BufferPainter(ImageBuffer& ib, int mode) +: ib(ib), + mode(mode), + rasterizer(ib.GetWidth(), ib.GetHeight(), mode == MODE_SUBPIXEL) +{ + ClearPath(); + + render_cx = ib.GetWidth(); + if(mode == MODE_SUBPIXEL) { + render_cx *= 3; + subpixel.Alloc(render_cx + 30); + } + attr.cap = LINECAP_BUTT; + attr.join = LINEJOIN_MITER; + attr.miter_limit = 4; + attr.evenodd = false; + attr.hasclip = false; + attr.cliplevel = 0; + attr.dash_start = 0.0; + attr.opacity = 1.0; + attr.mask = false; + pathattr = attr; + + gradientn = Null; +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Copying b/newdraw/Painter/Copying new file mode 100644 index 000000000..f3ef3b75c --- /dev/null +++ b/newdraw/Painter/Copying @@ -0,0 +1,21 @@ +Copyright 1998-2009 The U++ Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted +provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE U++ PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/newdraw/Painter/Dasher.cpp b/newdraw/Painter/Dasher.cpp new file mode 100644 index 000000000..0fd7997ed --- /dev/null +++ b/newdraw/Painter/Dasher.cpp @@ -0,0 +1,62 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void Dasher::Put(const Pointf& p) +{ + if(flag) + PutLine(p); + else + PutMove(p); +} + +void Dasher::Move(const Pointf& p) +{ + PutMove(p); + p0 = p; +} + +void Dasher::Line(const Pointf& p) +{ + if(sum == 0) { + PutLine(p); + return; + } + Pointf v = p - p0; + double len = Length(v); + double pos = 0; + while(pos + rem < len) { + pos += rem; + Put(pos / len * v + p0); + flag = !flag; + rem = (*pattern)[patterni]; + patterni = (patterni + 1) % pattern->GetCount(); + } + rem -= len - pos; + Put(p); + p0 = p; +} + +void Dasher::Init(const Vector& p, double distance) +{ + pattern = &p; + sum = Sum0(p); + if(sum == 0) + return; + distance -= int(distance / sum) * sum; + patterni = 0; + flag = false; + for(;;) { + rem = (*pattern)[patterni]; + patterni = (patterni + 1) % pattern->GetCount(); + flag = !flag; + if(rem > distance) { + rem -= distance; + break; + } + distance -= rem; + } + p0 = Pointf(0, 0); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/DrawOp.cpp b/newdraw/Painter/DrawOp.cpp new file mode 100644 index 000000000..5927128d3 --- /dev/null +++ b/newdraw/Painter/DrawOp.cpp @@ -0,0 +1,137 @@ +#include "Painter.h" + +NAMESPACE_UPP + +dword Painter::GetInfo() const +{ + return DOTS; +} + +void Painter::OffsetOp(Point p) +{ + Begin(); + Translate(p.x, p.y); +} + +void Painter::RectPath(int x, int y, int cx, int cy) +{ + Move(x, y).Line(x + cx, y).Line(x + cx, y + cy).Line(x, y + cy).Close(); +} + +void Painter::RectPath(const Rect& r) +{ + RectPath(r.left, r.top, r.GetWidth(), r.GetHeight()); +} + +bool Painter::ClipOp(const Rect& r) +{ + Begin(); + RectPath(r); + Clip(); + return true; +} + +bool Painter::ClipoffOp(const Rect& r) +{ + Begin(); + RectPath(r); + Clip(); + Translate(r.left, r.top); + return true; +} + +bool Painter::ExcludeClipOp(const Rect& r) +{ + return true; +} + +bool Painter::IntersectClipOp(const Rect& r) +{ + return true; + RectPath(r); + Clip(); + return true; +} + +bool Painter::IsPaintingOp(const Rect& r) const +{ + return true; +} + +void Painter::DrawRectOp(int x, int y, int cx, int cy, Color color) +{ + RectPath(x, y, cx, cy); + Fill(color); +} + +void Painter::DrawImageOp(int x, int y, int cx, int cy, const Image& img, const Rect& src, Color color) +{ + // Color and src support!!! + RectPath(x, y, cx, cy); + Fill(img, Xform2D::Translation(x, y)); +} + +void Painter::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) +{ + double h = width / 2; + Move(x1 + h, y1 + h); + Line(x2 + h, y2 + h); + Stroke(max(width, 0), color); +} + +void Painter::DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts, + int count_count, int width, Color color, Color doxor) +{ +} + +void Painter::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int scc, const int *disjunct_polygon_counts, + int dpcc, Color color, int width, Color outline, uint64 pattern, Color doxor) +{ +} + +void Painter::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) +{ +} + +void Painter::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) +{ + Sizef sz = r.GetSize(); + Ellipse(r.left + sz.cx / 2, r.top + sz.cy / 2, sz.cx / 2, sz.cy / 2); + Fill(color); + Stroke(max(pen, 0), pencolor); +} + +void Painter::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) +{ + Begin(); + EvenOdd(true); + if(angle) + Rotate(angle * M_2PI / 36000); + if(n < 0) + n = wstrlen(text); + double *ddx = NULL; + Buffer h; + if(dx) { + h.Alloc(n); + ddx = h; + for(int i = 0; i < n; i++) + ddx[i] = dx[i]; + } + Text(x, y, text, font, n, ddx); + Fill(ink); + End(); +} + +void Painter::DrawPaintingOp(const Rect& target, const Painting& p) +{ + Size sz = target.GetSize(); + Sizef psz = p.GetSize(); + Begin(); + Translate(target.left, target.top); + Scale(sz.cx / psz.cx, sz.cy / psz.cy); + Paint(p); + End(); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Fillers.cpp b/newdraw/Painter/Fillers.cpp new file mode 100644 index 000000000..01597101f --- /dev/null +++ b/newdraw/Painter/Fillers.cpp @@ -0,0 +1,465 @@ +#include "Painter.h" +#include "Fillers.h" + +NAMESPACE_UPP + +void FillRGBA(RGBA *t, RGBA c, int len) +{ + while(len >= 16) { + t[0] = c; t[1] = c; t[2] = c; t[3] = c; + t[4] = c; t[5] = c; t[6] = c; t[7] = c; + t[8] = c; t[9] = c; t[10] = c; t[11] = c; + t[12] = c; t[13] = c; t[14] = c; t[15] = c; + t += 16; + len -= 16; + } + switch(len) { + case 15: t[14] = c; + case 14: t[13] = c; + case 13: t[12] = c; + case 12: t[11] = c; + case 11: t[10] = c; + case 10: t[9] = c; + case 9: t[8] = c; + case 8: t[7] = c; + case 7: t[6] = c; + case 6: t[5] = c; + case 5: t[4] = c; + case 4: t[3] = c; + case 3: t[2] = c; + case 2: t[1] = c; + case 1: t[0] = c; + } +} + +void SolidFiller::Start(int minx, int maxx) +{ + t += minx; +} + +void SolidFiller::Render(int val) +{ + AlphaBlendCover8(*t++, c, val); +} + +void SolidFiller::Render(int val, int len) +{ + if(val == 0) { + t += len; + return; + } + if(((val - 256) | (c.a - 255)) == 0) { + FillRGBA(t, c, len); + t += len; + } + else { + RGBA c1; + if(val != 256) + c1 = Mul8(c, val); + else + c1 = c; + RGBA *e = t + len; + while(t < e) + AlphaBlend(*t++, c1); + } +} + +void SubpixelFiller::Start(int minx, int maxx) +{ + int x = minx / 3; + if(x > 0) { + begin = sbuffer; + x--; + } + else + begin = sbuffer + 3; + t += x; + sbuffer[0] = sbuffer[1] = sbuffer[2] = sbuffer[3] = + sbuffer[4] = sbuffer[5] = sbuffer[6] = sbuffer[7] = 0; + v = sbuffer + 3 + minx % 3; + if(ss) { + int xx = maxx / 3; + ss->Get(buffer, x, y, xx - x + 2); + s = buffer; + } +} + +void SubpixelFiller::Render(int val) +{ + int16 *w = v; + int h = val / 9; + int h2 = h + h; + w[-2] += h; + w[2] += h; + w[-1] += h2; + w[1] += h2; + w[0] += val - h2 - h2 - h2; + w[3] = 0; + v++; +} + +void SubpixelFiller::RenderN(int val, int h, int n) +{ + int16 *w = v; + int h2 = h + h; + int hv2 = val - h2 - h2; + int h3 = h2 + h; + int hh; + v += n; + switch(n) { + case 1: + w[-2] += h; + w[-1] += h2; + w[1] += h2; + w[0] += hv2 - h2; + w[2] += h; + w[3] = 0; + break; + case 2: + w[-2] += h; + w[3] = h; + w[-1] += h3; + w[2] += h3; + w[0] += hv2; + w[1] += hv2; + w[4] = 0; + break; + case 3: + w[-2] += h; + w[4] = h; + w[-1] += h3; + w[3] = h3; + hh = hv2 + h; + w[0] += hh; + w[2] += hh; + w[1] += hv2 + h2; + w[5] = 0; + break; + case 4: + w[-2] += h; + w[5] = h; + w[-1] += h3; + w[4] = h3; + hh = hv2 + h; + w[0] += hh; + w[3] = hh; + hh = hv2 + h3; + w[1] += hh; + w[2] += hh; + w[6] = 0; + break; + case 5: + w[-2] += h; + w[6] = h; + w[-1] += h3; + w[5] = h3; + hh = hv2 + h; + w[0] += hh; + w[4] = hh; + hh = h3 + hv2; + w[1] += hh; + w[3] = hh; + w[2] += h3 + hv2 + h; + w[7] = 0; + break; + case 6: + w[-2] += h; + w[7] = h; + w[-1] += h3; + w[6] = h3; + hh = hv2 + h; + w[0] += hh; + w[5] = hh; + hh = h3 + hv2; + w[1] += hh; + w[4] = hh; + hh = h3 + hv2 + h; + w[2] += hh; + w[3] = hh; + w[8] = 0; + break; + } +} + +void SubpixelFiller::Render(int val, int len) +{ + int h = val / 9; + if(len > 6) { + int q = (3333333 - (v + 2 - begin)) % 3; + len -= q + 2; + int l = v + 2 + q - begin; + RenderN(val, h, q + 4); + Write(l / 3); + l = len / 3; + len -= 3 * l; + RGBA *e = min(t + l, end); + if(val == 256) + if(!ss && color.a == 255) { + FillRGBA(t, color, e - t); + t = e; + } + else + while(t < e) + AlphaBlend(*t++, ss ? Mul8(*s++, alpha) : color); + else + if(ss) + while(t < e) + AlphaBlendCover8(*t++, Mul8(*s++, alpha), val); + else { + RGBA c = Mul8(color, val); + while(t < e) + AlphaBlend(*t++, c); + } + v = begin = sbuffer + 3; + v[0] = h + h + h; + v[1] = h; + v[2] = 0; + } + RenderN(val, h, len); +} + +void SubpixelFiller::Write(int len) +{ + RGBA *e = min(t + len, end); + int16 *q = begin; + while(t < e) { + RGBA c = ss ? Mul8(*s++, alpha) : color; + int a; + if(t->a != 255) + AlphaBlendCover8(*t, c, (q[0] + q[1] + q[2]) / 3); + else + if(c.a == 255) { + t->r = (c.r * q[0] >> 8) + ((257 - q[0]) * t->r >> 8); + t->g = (c.g * q[1] >> 8) + ((257 - q[1]) * t->g >> 8); + t->b = (c.b * q[2] >> 8) + ((257 - q[2]) * t->b >> 8); + } + else { + a = c.a * q[0] >> 8; + t->r = (c.r * q[0] >> 8) + ((256 - a - (a >> 7)) * t->r >> 8); + a = c.a * q[1] >> 8; + t->g = (c.g * q[1] >> 8) + ((256 - a - (a >> 7)) * t->g >> 8); + a = c.a * q[2] >> 8; + t->b = (c.b * q[2] >> 8) + ((256 - a - (a >> 7)) * t->b >> 8); + } + t++; + q += 3; + } +} + +void SubpixelFiller::End() +{ + v[3] = v[4] = v[5] = 0; + Write((v + 3 - begin) / 3); +} + +void SpanFiller::Start(int minx, int maxx) +{ + t += minx; + ss->Get(buffer, minx, y, maxx - minx + 1); + s = buffer; +} + +void SpanFiller::Render(int val) +{ + if(alpha != 256) + val = alpha * val >> 8; + AlphaBlendCover8(*t++, *s++, val); +} + +void SpanFiller::Render(int val, int len) +{ + if(val == 0) { + t += len; + s += len; + return; + } + const RGBA *e = t + len; + if(alpha != 256) + val = alpha * val >> 8; + if(val == 256) + while(t < e) { + if(s->a == 255) + *t++ = *s++; + else + AlphaBlend(*t++, *s++); + } + else + while(t < e) + AlphaBlendCover8(*t++, *s++, val); +} + +ClipFiller::ClipFiller(int _cx) +{ + cx = _cx; + buffer.Alloc(2 * cx); +} + +void ClipFiller::Clear() +{ + t = ~buffer; + x = 0; + empty = true; + full = true; + last = -1; +} + +void ClipFiller::Start(int xmin, int xmax) +{ + Render(0, xmin); +} + +void ClipFiller::Span(int val, int len) +{ + int v = val >> 1; + if(last == val) { + int n = min(v + 128 - *lastn - 1, len); + *lastn += n; + len -= n; + } + last = -1; + while(len > 128) { + int n = min(len, 128); + *t++ = 0; + *t++ = v + n - 1; + len -= n; + } + if(len) { + *t++ = 0; + last = val; + lastn = t; + *t++ = v + len - 1; + } +} + +void ClipFiller::Render(int val, int len) +{ + if(val == 256) { + Span(256, len); + empty = false; + } + else { + full = false; + if(val == 0) + Span(0, len); + else { + memset(t, val, len); + t += len; + empty = false; + last = -1; + } + } + x += len; +} + +void ClipFiller::Render(int val) +{ + Render(val, 1); +} + +void ClipFiller::Finish(ClipLine& cl) +{ + if(empty) + return; + while(x < cx) { + int n = min(cx - x, 128); + *t++ = 0; + *t++ = n - 1; + x += n; + full = false; + } + if(full) + cl.SetFull(); + else + cl.Set(~buffer, t - ~buffer); +} + +void MaskFillerFilter::Render(int val) +{ + for(;;) { + if(empty) { + t->Render(0); + empty--; + return; + } + if(full) { + t->Render(val); + full--; + return; + } + byte m = *mask++; + if(m) { + t->Render(val * m >> 8); + return; + } + m = *mask++; + if(m < 128) + empty = m + 1; + else + full = m - 128 + 1; + } +} + +void MaskFillerFilter::Render(int val, int len) +{ + while(len) + if(empty) { + int n = min(len, empty); + t->Render(0, n); + empty -= n; + len -= n; + } + else + if(full) { + int n = min(len, full); + t->Render(val, n); + full -= n; + len -= n; + } + else { + byte m = *mask++; + if(m) { + t->Render(val * m >> 8); + len--; + } + else { + m = *mask++; + if(m < 128) + empty = m + 1; + else + full = m - 128 + 1; + } + } +} + +struct NilFiller : Rasterizer::Filler { + void Start(int minx, int maxx) {} + void Render(int val, int len) {} + void Render(int val) {} +}; + +void MaskFillerFilter::Start(int minx, int maxx) +{ + t->Start(minx, maxx); + Rasterizer::Filler *h = t; + NilFiller nil; + t = &nil; + Render(0, minx); + t = h; +} + +void NoAAFillerFilter::Start(int minx, int maxx) +{ + t->Start(minx, maxx); +} + +void NoAAFillerFilter::Render(int val, int len) +{ + t->Render(val < 128 ? 0 : 256, len); +} + +void NoAAFillerFilter::Render(int val) +{ + t->Render(val < 128 ? 0 : 256); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Fillers.h b/newdraw/Painter/Fillers.h new file mode 100644 index 000000000..b08c3a9d0 --- /dev/null +++ b/newdraw/Painter/Fillers.h @@ -0,0 +1,93 @@ +NAMESPACE_UPP + +struct SolidFiller : Rasterizer::Filler { + RGBA *t; + RGBA c; + + void Start(int minx, int maxx); + void Render(int val); + void Render(int val, int len); +}; + +struct SpanFiller : Rasterizer::Filler { + RGBA *t; + const RGBA *s; + int y; + RGBA *buffer; + SpanSource *ss; + int alpha; + + void Start(int minx, int maxx); + void Render(int val); + void Render(int val, int len); +}; + +struct SubpixelFiller : Rasterizer::Filler { + int16 *sbuffer; + int16 *begin; + RGBA *t, *end; + int16 *v; + RGBA *s; + RGBA color; + SpanSource *ss; + int alpha; + RGBA *buffer; + int y; + + void Write(int len); + void RenderN(int val, int h, int n); + + void Start(int minx, int maxx); + void Render(int val); + void Render(int val, int len); + void End(); +}; + +struct ClipFiller : Rasterizer::Filler { + Buffer buffer; + byte *t; + int x; + int cx; + int last; + byte *lastn; + bool empty; + bool full; + + void Span(int c, int len); + + virtual void Render(int val); + virtual void Render(int val, int len); + virtual void Start(int x, int len); + + void Clear(); + void Finish(ClipLine& cl); + + ClipFiller(int cx); +}; + +struct MaskFillerFilter : Rasterizer::Filler { + Rasterizer::Filler *t; + const byte *mask; + int empty; + int full; + + void Start(int minx, int maxx); + void Render(int val, int len); + void Render(int val); + void End() { t->End(); } + + void Set(Rasterizer::Filler *f, const byte *m) { t = f; mask = m; empty = full = 0; } +}; + +struct NoAAFillerFilter : Rasterizer::Filler { + Rasterizer::Filler *t; + + void Start(int minx, int maxx); + void Render(int val, int len); + void Render(int val); + void End() { t->End(); } + + void Set(Rasterizer::Filler *f) { t = f; } +}; + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/FontWin32.cpp b/newdraw/Painter/FontWin32.cpp new file mode 100644 index 000000000..bf06d72ad --- /dev/null +++ b/newdraw/Painter/FontWin32.cpp @@ -0,0 +1,86 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all coM_PIes. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- + +// Recycled for U++ by Miroslav Fidler 2008 + +#include "Painter.h" + +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; + } +} + +void PaintCharacter(Painter& sw, const Pointf& p, int ch, Font fnt) +{ + PAINTER_TIMING("CharacterOp"); + static ScreenDraw w; + w.SetFont(fnt); + 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(w.GetHandle(), ch, GGO_NATIVE, &gm, 0, NULL, &m_matrix); + if(gsz < 0) + return; + StringBuffer gb(gsz); + gsz = GetGlyphOutlineW(w.GetHandle(), ch, GGO_NATIVE, &gm, gsz, ~gb, &m_matrix); + if(gsz < 0) + return; + RenderCharPath(~gb, gsz, sw, p.x, p.y + fnt.Info().GetAscent()); + sw.EvenOdd(true); +} + +#endif + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/FontX11.cpp b/newdraw/Painter/FontX11.cpp new file mode 100644 index 000000000..25a0a400a --- /dev/null +++ b/newdraw/Painter/FontX11.cpp @@ -0,0 +1,153 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all coM_PIes. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- + +// Recycled for U++ by Miroslav Fidler 2008 + +#include "Painter.h" + +NAMESPACE_UPP + +#ifdef PLATFORM_X11 + +static inline double ft_dbl(int p) +{ + return double(p) / 64.0; +} + +bool RenderOutline(const FT_Outline& outline, Painter& path, double xx, double yy) +{ + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + double x1, y1, x2, y2, x3, y3; + 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(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(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(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + 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(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + ft_dbl(v_middle.x) + xx, -ft_dbl(v_middle.y) + yy); + v_control = vec; + goto Do_Conic; + } + path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + 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(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy, + ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy, + ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy); + continue; + } + path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy, + ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy, + ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); + goto Close; + } + } + Close: + path.Close(); + first = last + 1; + } + return true; +} + +void PaintCharacter(Painter& sw, const Pointf& p, int ch, Font fnt) +{ + PAINTER_TIMING("CharacterOp"); + FontInfo fi = fnt.Info(); + FT_Face face = XftLockFace(fi.GetXftFont()); + int glyph_index = FT_Get_Char_Index(face, ch); + if(FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0) + RenderOutline(face->glyph->outline, sw, p.x, p.y + fnt.Info().GetAscent()); + XftUnlockFace(fi.GetXftFont()); + sw.EvenOdd(true); +} + +#endif + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Gradient.cpp b/newdraw/Painter/Gradient.cpp new file mode 100644 index 000000000..bbe4c5c09 --- /dev/null +++ b/newdraw/Painter/Gradient.cpp @@ -0,0 +1,65 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void BufferPainter::MakeGradient(RGBA color1, RGBA color2, int n) +{ + if(n == gradientn && color1 == gradient1 && color2 == gradient2) + return; + gradientn = n; + gradient1 = color1; + gradient2 = color2; + ImageBuffer ib(n, 1); + RGBA *t = ib[0]; + int l = 0; + RGBA cl = color1; + for(int i = 0; i <= pathattr.stop.GetCount(); i++) { + int h; + RGBA ch; + if(i < pathattr.stop.GetCount()) { + h = (int)(pathattr.stop[i] * (n - 1)); + ch = pathattr.stop_color[i]; + } + else { + h = n - 1; + ch = color2; + } + int w = h - l; + for(int j = 0; j < w; j++) { + t->r = ((w - j) * cl.r + j * ch.r) / w; + t->g = ((w - j) * cl.g + j * ch.g) / w; + t->b = ((w - j) * cl.b + j * ch.b) / w; + t->a = ((w - j) * cl.a + j * ch.a) / w; + t++; + } + cl = ch; + l = h; + } + *t = cl; + gradient = ib; +} + +void BufferPainter::Gradient(const RGBA& color1, const RGBA& color2, const Pointf& p1, const Pointf& p2) +{ + MakeGradient(color1, color2, minmax(int(Distance(p1, p2) * pathattr.mtx.GetScale()), 2, 4096)); +} + +void BufferPainter::FillOp(const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style) +{ + Gradient(color1, color2, p1, p2); + Fill(gradient, p1, p2, + FILL_VPAD | FILL_FAST | + (style == GRADIENT_PAD ? FILL_HPAD : style == GRADIENT_REPEAT + ? FILL_HREPEAT : FILL_HREFLECT)); +} + +void BufferPainter::StrokeOp(double width, const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style) +{ + Gradient(color1, color2, p1, p2); + Stroke(width, gradient, p1, p2, + FILL_VPAD | FILL_FAST | + (style == GRADIENT_PAD ? FILL_HPAD : style == GRADIENT_REPEAT + ? FILL_HREPEAT : FILL_HREFLECT)); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Image.cpp b/newdraw/Painter/Image.cpp new file mode 100644 index 000000000..2f6b6fe55 --- /dev/null +++ b/newdraw/Painter/Image.cpp @@ -0,0 +1,239 @@ +#include "Painter.h" + +NAMESPACE_UPP + +#if 0 // does not seem to help... + +Image MipMap(const Image& img) +{ + Size ssz = img.GetSize() / 2; + Size msz = (img.GetSize() + 1) / 2; + ImageBuffer ib(msz); + for(int y = 0; y < ssz.cy; y++) { + const RGBA *s1 = img[2 * y]; + const RGBA *s2 = img[2 * y + 1]; + const RGBA *e = s1 + 2 * ssz.cx; + RGBA *t = ib[y]; + while(s1 < e) { + t->r = (s1[0].r + s1[1].r + s2[0].r + s2[1].r) >> 2; + t->g = (s1[0].g + s1[1].g + s2[0].g + s2[1].g) >> 2; + t->b = (s1[0].b + s1[1].b + s2[0].b + s2[1].b) >> 2; + t->a = (s1[0].a + s1[1].a + s2[0].a + s2[1].a) >> 2; + t++; + s1 += 2; + s2 += 2; + } + if(ssz.cx < msz.cx) { + t->r = (s1[0].r + s2[0].r) >> 2; + t->g = (s1[0].g + s2[0].g) >> 2; + t->b = (s1[0].b + s2[0].b) >> 2; + t->a = (s1[0].a + s2[0].a) >> 2; + } + } + if(ssz.cy < msz.cy) { + const RGBA *s1 = img[img.GetSize().cy - 1]; + const RGBA *e = s1 + 2 * ssz.cx; + RGBA *t = ib[msz.cy - 1]; + while(s1 < e) { + t->r = (s1[0].r + s1[1].r) >> 2; + t->g = (s1[0].g + s1[1].g) >> 2; + t->b = (s1[0].b + s1[1].b) >> 2; + t->a = (s1[0].a + s1[1].a) >> 2; + t++; + s1 += 2; + } + if(ssz.cx < msz.cx) { + t->r = s1[0].r >> 2; + t->g = s1[0].g >> 2; + t->b = s1[0].b >> 2; + t->a = s1[0].a >> 2; + } + } + return ib; +} + +Image MakeMipMap(const Image& m, int level); + +struct MipMapMaker : ImageMaker { + int level; + Image image; + + virtual String Key() const { + String h; + RawCat(h, image.GetSerialId()); + RawCat(h, level); + return h; + } + virtual Image Make() const { + Size sz = image.GetSize(); + if(sz.cx && sz.cx) { + if(level <= 0) + return image; + return MipMap(MakeMipMap(image, level - 1)); + } + return Image(); + } +}; + +Image MakeMipMap(const Image& img, int level) +{ + MipMapMaker m; + m.image = img; + m.level = level; + return MakeImage(m); +} + +#endif + +struct PainterImageSpan : SpanSource { + struct RGBAV { + dword r, g, b, a; + + void Set(dword v) { r = g = b = a = v; } + void Put(dword weight, const RGBA& src) { + r += weight * src.r; + g += weight * src.g; + b += weight * src.b; + a += weight * src.a; + } + }; + + LinearInterpolator interpolator; + int ax, ay, cx, cy, maxx, maxy; + byte style; + byte hstyle, vstyle; + bool fast; + bool fixed; + Image image; + + void Set(const Xform2D& m, const Image& img) { + int level = 0; +#if 0 // no mipmap for now + double q = 1; + if(!fast) { + double q = 1; + Pointf sc = m.GetScaleXY(); + if(sc.x >= 0.01 && sc.y >= 0.01) + while(sc.x < 0.5 && sc.y < 0.5) { + level++; + sc.x *= 2; + sc.y *= 2; + q /= 2; + } + } + if(q != 1) + interpolator.Set(Inverse(m) * Xform2D::Scale(q)); + else +#endif + interpolator.Set(Inverse(m)); + image = img; +// image = MakeMipMap(img, level); + cx = image.GetWidth(); + cy = image.GetHeight(); + maxx = cx - 1; + maxy = cy - 1; + ax = 6000000 / cx * cx * 2; + ay = 6000000 / cy * cy * 2; + } + + RGBA Pixel(int x, int y) { return image[y][x]; } + + RGBA GetPixel(int x, int y) { + if(hstyle == FILL_HPAD) + x = minmax(x, 0, maxx); + else + if(hstyle == FILL_HREFLECT) + x = (x + ax) / cx & 1 ? (ax - x - 1) % cx : (x + ax) % cx; + else + if(hstyle == FILL_HREPEAT) + x = (x + ax) % cx; + if(vstyle == FILL_VPAD) + y = minmax(y, 0, maxy); + else + if(vstyle == FILL_VREFLECT) + y = (y + ay) / cy & 1 ? (ay - y - 1) % cy : (y + ay) % cy; + else + if(vstyle == FILL_VREPEAT) + y = (y + ay) % cy; + return fixed || (x >= 0 && x < cx && y >= 0 && y < cy) ? image[y][x] : RGBAZero(); + } + + virtual void Get(RGBA *span, int x, int y, unsigned len) + { + interpolator.Begin(x, y, len); + fixed = hstyle && vstyle; + while(len--) { + Point h = interpolator.Get(); + // h -= 128; + Point l = h >> 8; + if(hstyle == FILL_HREPEAT) + l.x = (l.x + ax) % cx; + if(vstyle == FILL_VREPEAT) + l.y = (l.y + ay) % cy; + if(fast) { + if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy) + *span = Pixel(l.x, l.y); + else + if(style == 0 && (l.x < -1 || l.x > cx || l.y < -1 || l.y > cy)) + *span = RGBAZero(); + else + *span = GetPixel(l.x, l.y); + } + else { + RGBAV v; + v.Set(0); + // v.Set(256 * 256 / 2); + h.x &= 255; + h.y &= 255; + Point u = -h + 256; + if(l.x > 0 && l.x < maxx && l.y > 0 && l.y < maxy) { + v.Put(u.x * u.y, Pixel(l.x, l.y)); + v.Put(h.x * u.y, Pixel(l.x + 1, l.y)); + v.Put(u.x * h.y, Pixel(l.x, l.y + 1)); + v.Put(h.x * h.y, Pixel(l.x + 1, l.y + 1)); + } + else + if(style == 0 && (l.x < -1 || l.x > cx || l.y < -1 || l.y > cy)) + v.Set(0); + else { + v.Put(u.x * u.y, GetPixel(l.x, l.y)); + v.Put(h.x * u.y, GetPixel(l.x + 1, l.y)); + v.Put(u.x * h.y, GetPixel(l.x, l.y + 1)); + v.Put(h.x * h.y, GetPixel(l.x + 1, l.y + 1)); + } + span->r = byte(v.r >> 16); + span->g = byte(v.g >> 16); + span->b = byte(v.b >> 16); + span->a = byte(v.a >> 16); + } + ++span; + } + } +}; + +void BufferPainter::RenderImage(double width, const Image& image, const Xform2D& transsrc, dword flags) +{ + if(image.GetWidth() == 0 || image.GetHeight() == 0) + return; + PainterImageSpan ss; + ss.style = byte(flags & 15); + ss.hstyle = byte(flags & 3); + ss.vstyle = byte(flags & 12); + ss.fast = flags & FILL_FAST; + Xform2D m = transsrc * pathattr.mtx; + ss.Set(m, image); + RenderPath(width, &ss, RGBAZero()); +} + +void BufferPainter::FillOp(const Image& image, const Xform2D& transsrc, dword flags) +{ + Close(); + RenderImage(-1, image, transsrc, flags); +} + +void BufferPainter::StrokeOp(double width, const Image& image, const Xform2D& transsrc, dword flags) +{ + RenderImage(width, image, transsrc, flags); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Interpolator.cpp b/newdraw/Painter/Interpolator.cpp new file mode 100644 index 000000000..e2e5d5090 --- /dev/null +++ b/newdraw/Painter/Interpolator.cpp @@ -0,0 +1,45 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void LinearInterpolator::Dda2::Set(int p1, int p2, int len) +{ + count = len <= 0 ? 1 : len; + lift = (p2 - p1) / count; + rem = (p2 - p1) % count; + mod = rem; + p = p1; + if(mod <= 0) { + mod += count; + rem += count; + lift--; + } + mod -= count; +} + +int LinearInterpolator::Dda2::Get() +{ + int pp = p; + mod += rem; + p += lift; + if(mod > 0) { + mod -= count; + p++; + } + return pp; +} + +void LinearInterpolator::Begin(int x, int y, int len) +{ + Pointf p1 = xform.Transform(Pointf(x, y)/* + 0.5*/); + Pointf p2 = xform.Transform(Pointf(x + len, y)/* + 0.5*/); + ddax.Set(Q8(p1.x), Q8(p2.x), len); + dday.Set(Q8(p1.y), Q8(p2.y), len); +} + +Point LinearInterpolator::Get() +{ + return Point(ddax.Get(), dday.Get()); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Mask.cpp b/newdraw/Painter/Mask.cpp new file mode 100644 index 000000000..a3ba1944b --- /dev/null +++ b/newdraw/Painter/Mask.cpp @@ -0,0 +1,90 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void BufferPainter::BeginMaskOp() +{ + attr.mask = true; + Size sz = ib.GetSize(); + mask.Add() = ib; + ib.Create(sz); + Clear(RGBAZero()); + Begin(); +} + +static inline byte *sSpan(byte *t, int c, int& len) +{ + while(len > 128) { + int n = min(len, 128); + *t++ = 0; + *t++ = c + n - 1; + len -= n; + } + if(len) { + *t++ = 0; + *t++ = c + len - 1; + len = 0; + } + return t; +} + +void BufferPainter::FinishMask() +{ + Buffer wb(mode == MODE_SUBPIXEL ? 6 * ib.GetWidth() : 2 * ib.GetWidth()); + bool creating = false; + if(!attr.hasclip) { + clip.Add().Alloc(ib.GetHeight()); + attr.hasclip = true; + attr.cliplevel = clip.GetCount(); + creating = true; + } + Buffer& cl = clip.Top(); + for(int y = 0; y < ib.GetHeight(); y++) + if(creating || !cl[y].IsEmpty()) { + bool full = true; + bool empty = true; + int c0 = 0; + int c256 = 0; + const RGBA *s = ib[y]; + const RGBA *e = ib[y] + ib.GetWidth(); + byte *t = wb; + while(s < e) { + int val = s->a * (56 * s->r + 183 * s->g + 20 * s->b) >> 16; + if(val == 0) { + if(c256) t = sSpan(t, 128, c256); + c0++; + if(mode == MODE_SUBPIXEL) + c0 += 2; + full = false; + } + else + if(val == 256) { + if(c0) t = sSpan(t, 0, c0); + c256++; + if(mode == MODE_SUBPIXEL) + c256 += 2; + empty = false; + } + else { + if(c256) t = sSpan(t, 128, c256); + if(c0) t = sSpan(t, 0, c0); + *t++ = val; + if(mode == MODE_SUBPIXEL) { + *t++ = val; + *t++ = val; + } + full = empty = false; + } + s++; + } + if(c256) t = sSpan(t, 128, c256); + if(c0) t = sSpan(t, 0, c0); + cl[y].Clear(); + cl[y].Set(~wb, t - ~wb); + } + ib = mask.Top(); + mask.Drop(); + attr.mask = false; +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/OnPath.cpp b/newdraw/Painter/OnPath.cpp new file mode 100644 index 000000000..16bfa63db --- /dev/null +++ b/newdraw/Painter/OnPath.cpp @@ -0,0 +1,33 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void BufferPainter::BeginOnPathOp(double q, bool abs) +{ + if(onpath.GetCount() == 0) + RenderPath(ONPATH, NULL, RGBAZero()); + Begin(); + if(pathlen > 0) { + if(!abs) + q *= pathlen; + Pointf pos(0, 0); + for(int i = 0; i < onpath.GetCount(); i++) { + PathLine& l = onpath[i]; + if(l.len > 0 && (l.len > q || q >= 1.0 && i == onpath.GetCount() - 1)) { + Pointf v = l.p - pos; + Translate(q / l.len * v + pos); + Rotate(Bearing(v)); + break; + } + q -= l.len; + pos = l.p; + } + } + attrstack.Top().onpath = true; + onpathstack.Add() = onpath; + pathlenstack.Add(pathlen); + onpath.Clear(); + pathlen = 0; +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/PaintPainting.icpp b/newdraw/Painter/PaintPainting.icpp new file mode 100644 index 000000000..b8555f046 --- /dev/null +++ b/newdraw/Painter/PaintPainting.icpp @@ -0,0 +1,269 @@ +#include "Painter.h" + +NAMESPACE_UPP + +template +void sGet(T& r, StringStream& ss) +{ + ss.Get(&r, sizeof(T)); +} + + +template +T sGet(StringStream& ss) +{ + T r; + ss.Get(&r, sizeof(T)); + return r; +} + +void Painter::Paint(const Painting& pic) +{ + StringStream ss(pic.cmd); + Pointf p, p1, p2; + RGBA c, c1; + Value v; + int f, ch, n, hasdx; + Xform2D m; + double r, w; + Font fnt; + int ii = 0; + bool large, sweep; + for(;;) { + int cmd = ss.Get(); + if(cmd < 0) + return; + bool rel = cmd & 1; + switch(cmd) { + case PAINTING_CLEAR: + ClearOp(sGet(ss)); + break; + case PAINTING_MOVE: + case PAINTING_MOVE_REL: + sGet(p, ss); + MoveOp(p, rel); + break; + case PAINTING_LINE: + case PAINTING_LINE_REL: + sGet(p, ss); + LineOp(p, rel); + break; + case PAINTING_QUADRATIC: + case PAINTING_QUADRATIC_REL: + sGet(p1, ss); + sGet(p, ss); + QuadraticOp(p1, p, rel); + break; + case PAINTING_QUADRATIC_S: + case PAINTING_QUADRATIC_S_REL: + sGet(p, ss); + QuadraticOp(p, rel); + break; + case PAINTING_CUBIC: + case PAINTING_CUBIC_REL: + sGet(p1, ss); + sGet(p2, ss); + sGet(p, ss); + CubicOp(p1, p2, p, rel); + break; + case PAINTING_CUBIC_S: + case PAINTING_CUBIC_S_REL: + sGet(p2, ss); + sGet(p, ss); + CubicOp(p2, p, rel); + break; + case PAINTING_ARC: + case PAINTING_ARC_REL: + sGet(p, ss); + sGet(p1, ss); + sGet(r, ss); + sGet(w, ss); + ArcOp(p, p1, r, w, rel); + break; + case PAINTING_SVGARC: + case PAINTING_SVGARC_REL: + sGet(p1, ss); + sGet(r, ss); + sGet(large, ss); + sGet(sweep, ss); + sGet(p, ss); + SvgArcOp(p1, r, large, sweep, p, rel); + break; + case PAINTING_CLOSE: + CloseOp(); + break; + case PAINTING_DIV: + DivOp(); + break; + case PAINTING_FILL_SOLID: + FillOp(sGet(ss)); + break; + case PAINTING_FILL_IMAGE: + sGet(m, ss); + f = ss.Get(); + if(ii >= pic.data.GetCount()) + return; + v = pic.data[ii++]; + if(!v.Is()) + return; + FillOp((Image)v, m, f); + break; + case PAINTING_FILL_GRADIENT: + sGet(p, ss); + sGet(c, ss); + sGet(p1, ss); + sGet(c1, ss); + f = ss.Get(); + FillOp(p, c, p1, c1, f); + break; + case PAINTING_FILL_RADIAL: + sGet(p, ss); + sGet(c, ss); + sGet(p1, ss); + sGet(r, ss); + sGet(c1, ss); + f = ss.Get(); + FillOp(p, c, p1, r, c1, f); + break; + case PAINTING_STROKE_SOLID: + sGet(w, ss); + sGet(c, ss); + StrokeOp(w, c); + break; + case PAINTING_STROKE_IMAGE: + sGet(w, ss); + sGet(m, ss); + f = ss.Get(); + if(ii >= pic.data.GetCount()) + return; + v = pic.data[ii++]; + if(!v.Is()) + return; + StrokeOp(w, (Image)v, m, f); + break; + case PAINTING_STROKE_GRADIENT: + sGet(w, ss); + sGet(p, ss); + sGet(c, ss); + sGet(p1, ss); + sGet(c1, ss); + f = ss.Get(); + StrokeOp(w, p, c, p1, c1, f); + break; + case PAINTING_STROKE_RADIAL: + sGet(w, ss); + sGet(p, ss); + sGet(c, ss); + sGet(p1, ss); + sGet(r, ss); + sGet(c1, ss); + f = ss.Get(); + StrokeOp(w, p, c, p1, r, c1, f); + break; + case PAINTING_CLIP: + ClipOp(); + break; + case PAINTING_CHARACTER: + sGet(p, ss); + ch = ss.Get32(); + sGet(fnt, ss); + CharacterOp(p, ch, fnt); + break; + case PAINTING_TEXT: + { + sGet(p, ss); + n = ss.Get32(); + hasdx = ss.Get(); + sGet(fnt, ss); + Buffer txt(n); + Buffer dx(hasdx * n); + for(int i = 0; i < n; i++) { + txt[i] = ss.Get32(); + if(hasdx) + sGet(dx[i], ss); + } + TextOp(p, txt, fnt, n, hasdx ? ~dx : NULL); + } + break; + case PAINTING_COLORSTOP: + sGet(r, ss); + sGet(c, ss); + ColorStopOp(r, c); + break; + case PAINTING_CLEARSTOPS: + ClearStopsOp(); + break; + case PAINTING_OPACITY: + OpacityOp(sGet(ss)); + break; + case PAINTING_LINECAP: + LineCapOp(ss.Get()); + break; + case PAINTING_LINEJOIN: + LineJoinOp(ss.Get()); + break; + case PAINTING_MITERLIMIT: + MiterLimitOp(ss.Get()); + break; + case PAINTING_EVENODD: + EvenOddOp(ss.Get()); + break; + case PAINTING_DASH: + { + n = ss.Get32(); + Vector dash; + for(int i = 0; i < n; i++) + dash.Add(sGet(ss)); + r = sGet(ss); + DashOp(dash, r); + } + break; + case PAINTING_TRANSFORM: + sGet(m, ss); + TransformOp(m); + break; + case PAINTING_BEGIN: + BeginOp(); + break; + case PAINTING_END: + EndOp(); + break; + case PAINTING_BEGINMASK: + BeginMaskOp(); + break; + case PAINTING_BEGINONPATH: + sGet(r, ss); + BeginOnPathOp(r, ss.Get()); + break; + } + } +} + +void PaintImageBufferPaintingFn(ImageBuffer& ib, const Painting& p, Size sz, Point pos, int mode) +{ + BufferPainter sw(ib, mode); + Sizef psz = p.GetSize(); + sw.Translate(-pos.x, -pos.y); + sw.Scale(sz.cx / psz.cx, sz.cy / psz.cy); + sw.Paint(p); +} + +void PaintImageBufferDrawingFn(ImageBuffer& ib, const Drawing& iw, int mode) +{ + BufferPainter sw(ib, mode); + Sizef sz = ib.GetSize(); + Size isz = iw.GetSize(); + sw.Scale(sz.cx / isz.cx, sz.cy / isz.cy); + sw.DrawDrawing(0, 0, isz.cx, isz.cy, iw); +} + +void RegisterPaintingFns__(void (*ig)(ImageBuffer& ib, const Painting& pw, Size sz, Point pos, int mode), + void (*iw)(ImageBuffer& ib, const Drawing& p, int mode)); + + +INITBLOCK +{ + RegisterPaintingFns__(PaintImageBufferPaintingFn, PaintImageBufferDrawingFn); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Painter.cpp b/newdraw/Painter/Painter.cpp new file mode 100644 index 000000000..60f8d760a --- /dev/null +++ b/newdraw/Painter/Painter.cpp @@ -0,0 +1,554 @@ +#include "Painter.h" + +NAMESPACE_UPP + +Painter& Painter::Move(const Pointf& p) +{ + Move(p, false); + return *this; +} + +Painter& Painter::Line(const Pointf& p) +{ + Line(p, false); + return *this; +} + +Painter& Painter::Quadratic(const Pointf& p1, const Pointf& p) +{ + QuadraticOp(p1, p, false); + return *this; +} + +Painter& Painter::Quadratic(const Pointf& p) +{ + QuadraticOp(p, false); + return *this; +} + +Painter& Painter::Cubic(const Pointf& p1, const Pointf& p2, const Pointf& p) +{ + CubicOp(p1, p2, p, false); + return *this; +} + +Painter& Painter::Cubic(const Pointf& p2, const Pointf& p) +{ + CubicOp(p2, p, false); + return *this; +} + +Painter& Painter::RelMove(const Pointf& p) +{ + MoveOp(p, true); + return *this; +} + +Painter& Painter::RelLine(const Pointf& p) +{ + LineOp(p, true); + return *this; +} + +Painter& Painter::RelQuadratic(const Pointf& p1, const Pointf& p) +{ + QuadraticOp(p1, p, true); + return *this; +} + +Painter& Painter::RelQuadratic(const Pointf& p) +{ + QuadraticOp(p, true); + return *this; +} + +Painter& Painter::RelCubic(const Pointf& p1, const Pointf& p2, const Pointf& p) +{ + CubicOp(p1, p2, p, true); + return *this; +} + +Painter& Painter::RelCubic(const Pointf& p2, const Pointf& p) +{ + CubicOp(p2, p, true); + return *this; +} + +Painter& Painter::Move(double x, double y, bool rel) +{ + MoveOp(Pointf(x, y), rel); + return *this; +} + +Painter& Painter::Line(double x, double y, bool rel) +{ + LineOp(Pointf(x, y), rel); + return *this; +} + +Painter& Painter::Quadratic(double x1, double y1, double x, double y, bool rel) +{ + QuadraticOp(Pointf(x1, y1), Pointf(x, y), rel); + return *this; +} + +Painter& Painter::Quadratic(double x, double y, bool rel) +{ + QuadraticOp(Pointf(x, y), rel); + return *this; +} + +Painter& Painter::Cubic(double x1, double y1, double x2, double y2, double x, double y, bool rel) +{ + CubicOp(Pointf(x1, y1), Pointf(x2, y2), Pointf(x, y), rel); + return *this; +} + +Painter& Painter::Cubic(double x2, double y2, double x, double y, bool rel) +{ + CubicOp(Pointf(x2, y2), Pointf(x, y), rel); + return *this; +} + +Painter& Painter::Move(double x, double y) +{ + Move(x, y, false); + return *this; +} + +Painter& Painter::Line(double x, double y) +{ + Line(x, y, false); + return *this; +} + +Painter& Painter::Quadratic(double x1, double y1, double x, double y) +{ + Quadratic(x1, y1, x, y, false); + return *this; +} + +Painter& Painter::Quadratic(double x, double y) +{ + Quadratic(x, y, false); + return *this; +} + +Painter& Painter::Cubic(double x1, double y1, double x2, double y2, double x, double y) +{ + Cubic(x1, y1, x2, y2, x, y, false); + return *this; +} + +Painter& Painter::Cubic(double x2, double y2, double x, double y) +{ + Cubic(x2, y2, x, y, false); + return *this; +} + +Painter& Painter::RelMove(double x, double y) +{ + Move(x, y, true); + return *this; +} + +Painter& Painter::RelLine(double x, double y) +{ + Line(x, y, true); + return *this; +} + +Painter& Painter::RelQuadratic(double x1, double y1, double x, double y) +{ + Quadratic(x1, y1, x, y, true); + return *this; +} + +Painter& Painter::RelQuadratic(double x, double y) +{ + Quadratic(x, y, true); + return *this; +} + +Painter& Painter::RelCubic(double x1, double y1, double x2, double y2, double x, double y) +{ + Cubic(x1, y1, x2, y2, x, y, true); + return *this; +} + +Painter& Painter::RelCubic(double x2, double y2, double x, double y) +{ + Cubic(x2, y2, x, y, true); + return *this; +} + +Painter& Painter::Arc(const Pointf& c, double rx, double ry, double angle, double sweep, bool rel) +{ + return Arc(c, Pointf(rx, ry), angle, sweep, rel); +} + +Painter& Painter::Arc(const Pointf& c, double r, double angle, double sweep, bool rel) +{ + return Arc(c, Pointf(r, r), angle, sweep, rel); +} + +Painter& Painter::Arc(double x, double y, double rx, double ry, double angle, double sweep, bool rel) +{ + return Arc(Pointf(x, y), rx, ry, angle, sweep, rel); +} + +Painter& Painter::Arc(double x, double y, double r, double angle, double sweep, bool rel) +{ + return Arc(Pointf(x, y), r, angle, sweep, rel); +} + +Painter& Painter::Arc(const Pointf& c, const Pointf& r, double angle, double sweep) +{ + return Arc(c, r, angle, sweep, false); +} + +Painter& Painter::Arc(const Pointf& c, double rx, double ry, double angle, double sweep) +{ + return Arc(c, rx, ry, angle, sweep, false); +} + +Painter& Painter::Arc(const Pointf& c, double r, double angle, double sweep) +{ + return Arc(c, r, angle, sweep, false); +} + +Painter& Painter::Arc(double x, double y, double rx, double ry, double angle, double sweep) +{ + return Arc(x, y, rx, ry, angle, sweep, false); +} + +Painter& Painter::Arc(double x, double y, double r, double angle, double sweep) +{ + return Arc(x, y, r, angle, sweep, false); +} + + +Painter& Painter::RelArc(const Pointf& c, const Pointf& r, double angle, double sweep) +{ + return Arc(c, r, angle, sweep, true); +} + +Painter& Painter::RelArc(const Pointf& c, double rx, double ry, double angle, double sweep) +{ + return Arc(c, rx, ry, angle, sweep, true); +} + +Painter& Painter::RelArc(const Pointf& c, double r, double angle, double sweep) +{ + return Arc(c, r, angle, sweep, true); +} + +Painter& Painter::RelArc(double x, double y, double rx, double ry, double angle, double sweep) +{ + return Arc(x, y, rx, ry, angle, sweep, true); +} + +Painter& Painter::RelArc(double x, double y, double r, double angle, double sweep) +{ + return Arc(x, y, r, angle, sweep, true); +} + +Painter& Painter::SvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p, bool rel) +{ + return SvgArc(Pointf(rx, ry), xangle, large, sweep, p, rel); +} + +Painter& Painter::SvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y, bool rel) +{ + return SvgArc(Pointf(rx, ry), xangle, large, sweep, Pointf(x, y), rel); +} + +Painter& Painter::SvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p) +{ + return SvgArc(r, xangle, large, sweep, p, false); +} + +Painter& Painter::SvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p) +{ + return SvgArc(rx, ry, xangle, large, sweep, p, false); +} + +Painter& Painter::SvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y) +{ + return SvgArc(rx, ry, xangle, large, sweep, x, y, false); +} + +Painter& Painter::RelSvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p) +{ + return SvgArc(r, xangle, large, sweep, p, true); +} + +Painter& Painter::RelSvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p) +{ + return SvgArc(rx, ry, xangle, large, sweep, p, true); +} + +Painter& Painter::RelSvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y) +{ + return SvgArc(rx, ry, xangle, large, sweep, x, y, true); +} + +Xform2D GetLineSzXform(const Pointf& p1, const Pointf& p2, const Sizef& sz) +{ + Xform2D m = Xform2D::Scale(Distance(p1, p2) / sz.cx); + m = m * Xform2D::Rotation(Bearing(p2 - p1)); + m = m * Xform2D::Translation(p1.x, p1.y); + return m; +} + +Painter& Painter::Fill(const Image& image, Pointf p1, Pointf p2, dword flags) +{ + return Fill(image, GetLineSzXform(p1, p2, image.GetSize()), flags); +} + +Painter& Painter::Fill(const Image& image, double x1, double y1, + double x2, double y2, dword flags) +{ + return Fill(image, Pointf(x1, y1), Pointf(x2, y2), flags); +} + +Painter& Painter::Fill(double x1, double y1, const RGBA& color1, double x2, double y2, const RGBA& color2, int style) +{ + return Fill(Pointf(x1, y1), color1, Pointf(x2, y2), color2, style); +} + +Painter& Painter::Fill(double fx, double fy, const RGBA& color1, double cx, double cy, double r, const RGBA& color2, int style) +{ + return Fill(Pointf(fx, fy), color1, Pointf(cx, cy), r, color2, style); +} + +Painter& Painter::Fill(const Pointf& c, const RGBA& color1, double r, const RGBA& color2, int style) +{ + return Fill(c, color1, c, r, color2, style); +} + +Painter& Painter::Fill(double x, double y, const RGBA& color1, double r, const RGBA& color2, int style) +{ + return Fill(Pointf(x, y), color1, r, color2, style); +} + +Painter& Painter::Translate(double x, double y) +{ + Transform(Xform2D::Translation(x, y)); + return *this; +} + +Painter& Painter::Translate(const Pointf& p) +{ + return Translate(p.x, p.y); +} + +Painter& Painter::Stroke(double width, const Image& image, const Pointf& p1, const Pointf& p2, dword flags) +{ + return Stroke(width, image, GetLineSzXform(p1, p2, image.GetSize()), flags); +} + +Painter& Painter::Stroke(double width, const Image& image, double x1, double y1, double x2, double y2, dword flags) +{ + return Stroke(width, image, Pointf(x1, y1), Pointf(x2, y2), flags); +} + +Painter& Painter::Stroke(double width, double x1, double y1, const RGBA& color1, double x2, double y2, const RGBA& color2, int style) +{ + return Stroke(width, Pointf(x1, y1), color1, Pointf(x2, y2), color2, style); +} + +Painter& Painter::Stroke(double width, double fx, double fy, const RGBA& color1, double cx, double cy, double r, const RGBA& color2, int style) +{ + return Stroke(width, Pointf(fx, fy), color1, Pointf(cx, cy), r, color2, style); +} + +Painter& Painter::Stroke(double width, const Pointf& c, const RGBA& color1, double r, const RGBA& color2, int style) +{ + return Stroke(width, c, color1, c, r, color2, style); +} + +Painter& Painter::Stroke(double width, double x, double y, const RGBA& color1, double r, const RGBA& color2, int style) +{ + return Stroke(width, Pointf(x, y), color1, r, color2, style); +} + +Painter& Painter::Rotate(double a) +{ + Transform(Xform2D::Rotation(a)); + return *this; +} + +Painter& Painter::Scale(double scalex, double scaley) +{ + Transform(Xform2D::Scale(scalex, scaley)); + return *this; +} + +Painter& Painter::Scale(double scale) +{ + Scale(scale, scale); + return *this; +} + +Painter& Painter::Dash(const char *dash, double start) +{ + Vector d; + CParser p(dash); + try { + while(!p.IsEof()) + if(p.Char(':')) + start = p.ReadDouble(); + else + d.Add(p.ReadDouble()); + } + catch(CParser::Error) {} + Dash(d, start); + return *this; +} + +Painter& Painter::Character(double x, double y, int ch, Font fnt) +{ + return Character(Pointf(x, y), ch, fnt); +} + +void Painter::TextOp(const Pointf& p, const wchar *text, Font fnt, int n, double *dx) +{ + if(n == 0) { + Move(0, 0); + return; + } + FontInfo fi = fnt.Info(); + double x = p.x; + while(n) { + int ch = *text++; + Character(x, p.y, ch, fnt); + Div(); + if(dx) + x += *dx++; + else + x += fi[ch]; + n--; + } +} + +Painter& Painter::Text(double x, double y, const wchar *text, Font fnt, int n, double *dx) +{ + return Text(Pointf(x, y), text, fnt, n < 0 ? wstrlen(text) : n, dx); +} + +Painter& Painter::Text(const Pointf& p, const WString& s, Font fnt, double *dx) +{ + return Text(p, ~s, fnt, s.GetLength(), dx); +} + +Painter& Painter::Text(double x, double y, const WString& s, Font fnt, double *dx) +{ + return Text(Pointf(x, y), s, fnt, dx); +} + +Painter& Painter::Text(const Pointf& p, const String& s, Font fnt, double *dx) +{ + return Text(p, s.ToWString(), fnt, dx); +} + +Painter& Painter::Text(double x, double y, const String& s, Font fnt, double *dx) +{ + return Text(Pointf(x, y), s, fnt, dx); +} + +Painter& Painter::Text(const Pointf& p, const char *text, Font fnt, int n, double *dx) +{ + if(n < 0) + n = strlen(text); + return Text(p, ToUnicode(text, n, CHARSET_DEFAULT), fnt, n, dx); +} + +Painter& Painter::Text(double x, double y, const char *text, Font fnt, int n, double *dx) +{ + return Text(Pointf(x, y), text, fnt, n, dx); +} + +Painter& Painter::Rectangle(double x, double y, double cx, double cy) +{ + if (cx < 0) { x += cx; cx = -cx;} + if (cy < 0) { y += cy; cy = -cy;} + return Move(x, y).RelLine(cx, 0).RelLine(0, cy).RelLine(-cx, 0).Close(); +} + +Painter& Painter::RoundedRectangle(double x, double y, double cx, double cy, double r) +{ + ASSERT(r >= 0); + if (cx < 0) { x += cx; cx = -cx;} + if (cy < 0) { y += cy; cy = -cy;} + Move(x + r, y).Arc(x + r, y + r, r, r, -M_PI / 2, -M_PI / 2) + .Line(x, y + cy - r).Arc(x + r, y + cy - r, r, r, M_PI, -M_PI / 2) + .Line(x + cx - r, y + cy).Arc(x + cx - r, y + cy - r, r, r, M_PI / 2, -M_PI / 2) + .Line(x + cx, y + r).Arc(x + cx - r, y + r, r, r, 0, -M_PI / 2).Line(x + r, y); + return *this; +} + +Painter& Painter::Ellipse(double x, double y, double rx, double ry) +{ + return Move(x + rx, y).Arc(x, y, rx, ry, 0, 2 * M_PI).Close(); +} + +Painter& Painter::Circle(double x, double y, double r) +{ + return Ellipse(x, y, r, r); +} + +void NilPainter::ClearOp(const RGBA& color) {} +void NilPainter::MoveOp(const Pointf& p, bool rel) {} +void NilPainter::LineOp(const Pointf& p, bool rel) {} +void NilPainter::QuadraticOp(const Pointf& p1, const Pointf& p, bool rel) {} +void NilPainter::QuadraticOp(const Pointf& p, bool rel) {} +void NilPainter::CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel) {} +void NilPainter::CubicOp(const Pointf& p2, const Pointf& p, bool rel) {} +void NilPainter::ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel) {} +void NilPainter::SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p, bool rel) {} +void NilPainter::CloseOp() {} +void NilPainter::DivOp() {} +void NilPainter::FillOp(const RGBA& color) {} +void NilPainter::FillOp(const Image& image, const Xform2D& transsrc, dword flags) {} +void NilPainter::FillOp(const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style) {} +void NilPainter::FillOp(const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style) {} +void NilPainter::StrokeOp(double width, const RGBA& rgba) {} +void NilPainter::StrokeOp(double width, const Image& image, const Xform2D& transsrc, dword flags) {} +void NilPainter::StrokeOp(double width, const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style) {} +void NilPainter::StrokeOp(double width, const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style) {} +void NilPainter::ClipOp() {} +void NilPainter::CharacterOp(const Pointf& p, int ch, Font fnt) {} +void NilPainter::TextOp(const Pointf& p, const wchar *text, Font fnt, int n, double *dx) {} +void NilPainter::ColorStopOp(double pos, const RGBA& color) {} +void NilPainter::ClearStopsOp() {} +void NilPainter::OpacityOp(double o) {} +void NilPainter::LineCapOp(int linecap) {} +void NilPainter::LineJoinOp(int linejoin) {} +void NilPainter::MiterLimitOp(double l) {} +void NilPainter::EvenOddOp(bool evenodd) {} +void NilPainter::DashOp(const Vector& dash, double start) {} +void NilPainter::TransformOp(const Xform2D& m) {} +void NilPainter::BeginOp() {} +void NilPainter::EndOp() {} +void NilPainter::BeginMaskOp() {} +void NilPainter::BeginOnPathOp(double, bool) {} + +ImagePainter::ImagePainter(Size sz, int mode) +: ImageBuffer__(sz), BufferPainter(ImageBuffer__::ib, mode) +{} + +ImagePainter::ImagePainter(int cx, int cy, int mode) +: ImageBuffer__(Size(cx, cy)), BufferPainter(ImageBuffer__::ib, mode) +{} + +DrawPainter::DrawPainter(Draw& w, Size sz, int mode) +: ImagePainter(sz, mode), w(w) +{} + +DrawPainter::~DrawPainter() +{ + w.DrawImage(0, 0, *this); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Painter.h b/newdraw/Painter/Painter.h new file mode 100644 index 000000000..57aa34f7d --- /dev/null +++ b/newdraw/Painter/Painter.h @@ -0,0 +1,404 @@ +#ifndef _Painter_Painter_h_ +#define _Painter_Painter_h_ + +#include + +#define PAINTER_TIMING(x) // RTIMING(x) + +NAMESPACE_UPP + +struct Xform2D { + Pointf x, y, t; + + Pointf GetScaleXY() const; + double GetScale() const; + bool IsRegular() const; + Pointf Transform(const Pointf& f) const; + Pointf Transform(double x, double y) const; + + static Xform2D Identity(); + static Xform2D Translation(double x, double y); + static Xform2D Scale(double sx, double sy); + static Xform2D Scale(double scale); + static Xform2D Rotation(double fi); + static Xform2D Sheer(double fi); + + Xform2D(); +}; + +Xform2D operator*(const Xform2D& a, const Xform2D& b); +Xform2D Inverse(const Xform2D& m); + +enum { + LINECAP_BUTT, + LINECAP_SQUARE, + LINECAP_ROUND, + + LINEJOIN_MITER, + LINEJOIN_ROUND, + LINEJOIN_BEVEL, + + FILL_EXACT = 0, + + FILL_HPAD = 1, + FILL_HREPEAT = 2, + FILL_HREFLECT = 3, + + FILL_VPAD = 4, + FILL_VREPEAT = 8, + FILL_VREFLECT = 12, + + FILL_PAD = FILL_HPAD|FILL_VPAD, + FILL_REPEAT = FILL_HREPEAT|FILL_VREPEAT, + FILL_REFLECT = FILL_HREFLECT|FILL_VREFLECT, + + FILL_FAST = 128, + + GRADIENT_PAD = 0, + GRADIENT_REPEAT = 1, + GRADIENT_REFLECT = 2, +}; + +class Painter : public Draw { +public: + virtual dword GetInfo() const; + + virtual void OffsetOp(Point p); + virtual void RectPath(int x, int y, int cx, int cy); + virtual void RectPath(const Rect& r); + virtual bool ClipOp(const Rect& r); + virtual bool ClipoffOp(const Rect& r); + virtual bool ExcludeClipOp(const Rect& r); + virtual bool IntersectClipOp(const Rect& r); + virtual bool IsPaintingOp(const Rect& r) 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 DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color); + virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts, + int count_count, int width, Color color, Color doxor); + virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, + const int *subpolygon_counts, int scc, + const int *disjunct_polygon_counts, int dpcc, Color color, + int width, Color outline, uint64 pattern, Color doxor); + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color); + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor); + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx); + virtual void DrawPaintingOp(const Rect& target, const Painting& p); + +protected: + virtual void ClearOp(const RGBA& color) = 0; + + virtual void MoveOp(const Pointf& p, bool rel) = 0; + virtual void LineOp(const Pointf& p, bool rel) = 0; + virtual void QuadraticOp(const Pointf& p1, const Pointf& p, bool rel) = 0; + virtual void QuadraticOp(const Pointf& p, bool rel) = 0; + virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel) = 0; + virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel) = 0; + virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel) = 0; + virtual void SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep, + const Pointf& p, bool rel) = 0; + virtual void CloseOp() = 0; + virtual void DivOp() = 0; + + virtual void FillOp(const RGBA& color) = 0; + virtual void FillOp(const Image& image, const Xform2D& transsrc, dword flags) = 0; + virtual void FillOp(const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, + int style) = 0; + virtual void FillOp(const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, + int style) = 0; + + virtual void StrokeOp(double width, const RGBA& rgba) = 0; + virtual void StrokeOp(double width, const Image& image, const Xform2D& transsrc, + dword flags) = 0; + virtual void StrokeOp(double width, const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, + int style) = 0; + virtual void StrokeOp(double width, const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, + int style) = 0; + + virtual void ClipOp() = 0; + + virtual void CharacterOp(const Pointf& p, int ch, Font fnt) = 0; + virtual void TextOp(const Pointf& p, const wchar *text, Font fnt, int n = -1, + double *dx = NULL); + + virtual void ColorStopOp(double pos, const RGBA& color) = 0; + virtual void ClearStopsOp() = 0; + + virtual void OpacityOp(double o) = 0; + virtual void LineCapOp(int linecap) = 0; + virtual void LineJoinOp(int linejoin) = 0; + virtual void MiterLimitOp(double l) = 0; + virtual void EvenOddOp(bool evenodd) = 0; + virtual void DashOp(const Vector& dash, double start = 0) = 0; + + virtual void TransformOp(const Xform2D& m) = 0; + + virtual void BeginOp() = 0; + virtual void EndOp() = 0; + + virtual void BeginMaskOp() = 0; + virtual void BeginOnPathOp(double q, bool absolute) = 0; + +protected: + static bool ReadBool(CParser& p); + static double ReadDouble(CParser& p); + static Pointf ReadPoint(CParser& p); + void DoArc0(double theta, double th_sweep, const Xform2D& m); + void DoArc(const Pointf& c, const Pointf& r, double angle, double sweep, double xangle); + void DoSvgArc(const Pointf& rr, double xangle, int large, int sweep, + const Pointf& p, const Pointf& p0); + +public: + void Clear(const RGBA& color); + + Painter& Move(const Pointf& p, bool rel); + Painter& Move(const Pointf& p); + Painter& Move(double x, double y, bool rel); + Painter& Move(double x, double y); + Painter& RelMove(const Pointf& p); + Painter& RelMove(double x, double y); + + Painter& Line(const Pointf& p, bool rel); + Painter& Line(const Pointf& p); + Painter& Line(double x, double y, bool rel); + Painter& Line(double x, double y); + Painter& RelLine(const Pointf& p); + Painter& RelLine(double x, double y); + + Painter& Quadratic(const Pointf& p1, const Pointf& p, bool rel); + Painter& Quadratic(const Pointf& p1, const Pointf& p); + Painter& Quadratic(const Pointf& p); + Painter& Quadratic(double x, double y, bool rel); + Painter& Quadratic(double x1, double y1, double x, double y, bool rel); + Painter& Quadratic(const Pointf& p, bool rel); + Painter& Quadratic(double x1, double y1, double x, double y); + Painter& Quadratic(double x, double y); + Painter& RelQuadratic(const Pointf& p1, const Pointf& p); + Painter& RelQuadratic(double x1, double y1, double x, double y); + Painter& RelQuadratic(double x, double y); + Painter& RelQuadratic(const Pointf& p); + + Painter& Cubic(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel); + Painter& Cubic(const Pointf& p2, const Pointf& p, bool rel); + Painter& Cubic(const Pointf& p1, const Pointf& p2, const Pointf& p); + Painter& Cubic(const Pointf& p2, const Pointf& p); + Painter& Cubic(double x1, double y1, double x2, double y2, double x, double y, bool rel); + Painter& Cubic(double x2, double y2, double x, double y, bool rel); + Painter& Cubic(double x1, double y1, double x2, double y2, double x, double y); + Painter& Cubic(double x2, double y2, double x, double y); + Painter& RelCubic(const Pointf& p1, const Pointf& p2, const Pointf& p); + Painter& RelCubic(const Pointf& p2, const Pointf& p); + Painter& RelCubic(double x1, double y1, double x2, double y2, double x, double y); + Painter& RelCubic(double x2, double y2, double x, double y); + + Painter& Arc(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel); + Painter& Arc(const Pointf& c, double rx, double ry, double angle, double sweep, bool rel); + Painter& Arc(const Pointf& c, double r, double angle, double sweep, bool rel); + Painter& Arc(double x, double y, double rx, double ry, double angle, double sweep, bool rel); + Painter& Arc(double x, double y, double r, double angle, double sweep, bool rel); + Painter& Arc(const Pointf& c, const Pointf& r, double angle, double sweep); + Painter& Arc(const Pointf& c, double rx, double ry, double angle, double sweep); + Painter& Arc(const Pointf& c, double r, double angle, double sweep); + Painter& Arc(double x, double y, double rx, double ry, double angle, double sweep); + Painter& Arc(double x, double y, double r, double angle, double sweep); + Painter& RelArc(const Pointf& c, const Pointf& r, double angle, double sweep); + Painter& RelArc(const Pointf& c, double rx, double ry, double angle, double sweep); + Painter& RelArc(const Pointf& c, double r, double angle, double sweep); + Painter& RelArc(double x, double y, double rx, double ry, double angle, double sweep); + Painter& RelArc(double x, double y, double r, double angle, double sweep); + + Painter& SvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p, bool rel); + Painter& SvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p, bool rel); + Painter& SvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y, bool rel); + Painter& SvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p); + Painter& SvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p); + Painter& SvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y); + Painter& RelSvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p); + Painter& RelSvgArc(double rx, double ry, double xangle, bool large, bool sweep, const Pointf& p); + Painter& RelSvgArc(double rx, double ry, double xangle, bool large, bool sweep, double x, double y); + + Painter& Close(); + Painter& Div(); + + Painter& Path(CParser& p); + Painter& Path(const char *path); + + Painter& Fill(const RGBA& color); + Painter& Fill(const Image& image, const Xform2D& transsrc = Xform2D::Identity(), dword flags = 0); + Painter& Fill(const Image& image, Pointf p1, Pointf p2, dword flags = 0); + Painter& Fill(const Image& image, double x1, double y1, double x2, double y2, + dword flags = 0); + Painter& Fill(const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Fill(double x1, double y1, const RGBA& color1, + double x2, double y2, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Fill(const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Fill(double fx, double fy, const RGBA& color1, + double cx, double cy, double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Fill(const Pointf& c, const RGBA& color1, + double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Fill(double x, double y, const RGBA& color1, + double r, const RGBA& color2, int style = GRADIENT_PAD); + + Painter& Stroke(double width, const RGBA& color); + Painter& Stroke(double width, const Image& image, const Xform2D& transsrc, dword flags = 0); + Painter& Stroke(double width, const Image& image, const Pointf& p1, const Pointf& p2, + dword flags = 0); + Painter& Stroke(double width, const Image& image, double x1, double y1, double x2, double y2, + dword flags = 0); + Painter& Stroke(double width, const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Stroke(double width, double x1, double y1, const RGBA& color1, + double x2, double y2, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Stroke(double width, const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Stroke(double width, double fx, double fy, const RGBA& color1, + double cx, double cy, double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Stroke(double width, const Pointf& c, const RGBA& color1, + double r, const RGBA& color2, int style = GRADIENT_PAD); + Painter& Stroke(double width, double x, double y, const RGBA& color1, + double r, const RGBA& color2, int style = GRADIENT_PAD); + + Painter& Clip(); + + Painter& Character(const Pointf& p, int ch, Font fnt); + Painter& Character(double x, double y, int ch, Font fnt); + Painter& Text(const Pointf& p, const wchar *text, Font fnt, int n = -1, double *dx = NULL); + Painter& Text(double x, double y, const wchar *text, Font fnt, int n = -1, double *dx = NULL); + Painter& Text(const Pointf& p, const WString& s, Font fnt, double *dx = NULL); + Painter& Text(double x, double y, const WString& s, Font fnt, double *dx = NULL); + Painter& Text(const Pointf& p, const String& s, Font fnt, double *dx = NULL); + Painter& Text(double x, double y, const String& s, Font fnt, double *dx = NULL); + Painter& Text(const Pointf& p, const char *text, Font fnt, int n = -1, double *dx = NULL); + Painter& Text(double x, double y, const char *text, Font fnt, int n = -1, double *dx = NULL); + + void Begin(); + void End(); + + void BeginMask(); + void BeginOnPath(double q, bool absolute = false); + + Painter& ColorStop(double pos, const RGBA& color); + Painter& ClearStops(); + Painter& Opacity(double o); + Painter& LineCap(int linecap); + Painter& LineJoin(int linejoin); + Painter& MiterLimit(double l); + Painter& EvenOdd(bool evenodd = true); + Painter& Dash(const Vector& dash, double start); + Painter& Dash(const char *dash, double start = 0); + + Painter& Transform(const Xform2D& m); + Painter& Translate(double x, double y); + Painter& Translate(const Pointf& p); + Painter& Rotate(double a); + Painter& Scale(double scalex, double scaley); + Painter& Scale(double scale); + + void Paint(const Painting& p); + + Painter& Rectangle(double x, double y, double cx, double cy); + Painter& RoundedRectangle(double x, double y, double cx, double cy, double r); + Painter& Ellipse(double x, double y, double rx, double ry); + Painter& Circle(double x, double y, double r); +}; + +void PaintCharacter(Painter& sw, const Pointf& p, int ch, Font fnt); + +#include "Painter.hpp" +#include "Painting.h" +#include "BufferPainter.h" + +class ImageBuffer__ { +protected: + ImageBuffer ib; + +public: + ImageBuffer__(Size sz) : ib(sz) {} +}; + +class ImagePainter : private ImageBuffer__, public BufferPainter { +public: + ImagePainter(Size sz, int mode = MODE_ANTIALIASED); + ImagePainter(int cx, int cy, int mode = MODE_ANTIALIASED); + + Image GetResult() { return ImageBuffer__::ib; } + operator Image() { return GetResult(); } +}; + +class DrawPainter : public ImagePainter { + Draw& w; + +public: + DrawPainter(Draw& w, Size sz, int mode = MODE_ANTIALIASED); + ~DrawPainter(); +}; + +class NilPainter : public Painter { +protected: + virtual void ClearOp(const RGBA& color); + + virtual void MoveOp(const Pointf& p, bool rel); + virtual void LineOp(const Pointf& p, bool rel); + virtual void QuadraticOp(const Pointf& p1, const Pointf& p, bool rel); + virtual void QuadraticOp(const Pointf& p, bool rel); + virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel); + virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel); + virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel); + virtual void SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep, + const Pointf& p, bool rel); + virtual void CloseOp(); + virtual void DivOp(); + + virtual void FillOp(const RGBA& color); + virtual void FillOp(const Image& image, const Xform2D& transsrc, dword flags); + virtual void FillOp(const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, + int style); + virtual void FillOp(const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, + int style); + + virtual void StrokeOp(double width, const RGBA& rgba); + virtual void StrokeOp(double width, const Image& image, const Xform2D& transsrc, + dword flags); + virtual void StrokeOp(double width, const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, + int style); + virtual void StrokeOp(double width, const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, + int style); + + virtual void ClipOp(); + + virtual void CharacterOp(const Pointf& p, int ch, Font fnt); + virtual void TextOp(const Pointf& p, const wchar *text, Font fnt, int n = -1, + double *dx = NULL); + + virtual void ColorStopOp(double pos, const RGBA& color); + virtual void ClearStopsOp(); + + virtual void OpacityOp(double o); + virtual void LineCapOp(int linecap); + virtual void LineJoinOp(int linejoin); + virtual void MiterLimitOp(double l); + virtual void EvenOddOp(bool evenodd); + virtual void DashOp(const Vector& dash, double start); + + virtual void TransformOp(const Xform2D& m); + + virtual void BeginOp(); + virtual void EndOp(); + + virtual void BeginMaskOp(); + virtual void BeginOnPathOp(double q, bool abs); +}; + +END_UPP_NAMESPACE + +#endif diff --git a/newdraw/Painter/Painter.hpp b/newdraw/Painter/Painter.hpp new file mode 100644 index 000000000..1bc9f1141 --- /dev/null +++ b/newdraw/Painter/Painter.hpp @@ -0,0 +1,232 @@ +inline +void Painter::Clear(const RGBA& color) +{ + ClearOp(color); +} + +inline +Painter& Painter::Move(const Pointf& p, bool rel) +{ + MoveOp(p, rel); + return *this; +} + +inline +Painter& Painter::Line(const Pointf& p, bool rel) +{ + LineOp(p, rel); + return *this; +} + +inline +Painter& Painter::Quadratic(const Pointf& p1, const Pointf& p, bool rel) +{ + QuadraticOp(p1, p, rel); + return *this; +} + +inline +Painter& Painter::Quadratic(const Pointf& p, bool rel) +{ + QuadraticOp(p, rel); + return *this; +} + +inline +Painter& Painter::Cubic(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel) +{ + CubicOp(p1, p2, p, rel); + return *this; +} + +inline +Painter& Painter::Cubic(const Pointf& p2, const Pointf& p, bool rel) +{ + CubicOp(p2, p, rel); + return *this; +} + +inline +Painter& Painter::Arc(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel) +{ + ArcOp(c, r, angle, sweep, rel); + return *this; +} + +inline +Painter& Painter::SvgArc(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p, bool rel) +{ + SvgArcOp(r, xangle, large, sweep, p, rel); + return *this; +} + +inline +Painter& Painter::Close() +{ + CloseOp(); + return *this; +} + +inline +Painter& Painter::Div() +{ + DivOp(); + return *this; +} + +inline +Painter& Painter::Fill(const RGBA& color) +{ + FillOp(color); + return *this; +} + +inline +Painter& Painter::Fill(const Image& image, const Xform2D& transsrc, dword flags) +{ + FillOp(image, transsrc, flags); + return *this; +} + +inline +Painter& Painter::Fill(const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style) +{ + FillOp(p1, color1, p2, color2, style); + return *this; +} + +inline +Painter& Painter::Fill(const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style) +{ + FillOp(f, color1, c, r, color2, style); + return *this; +} + +inline +Painter& Painter::Stroke(double width, const RGBA& color) +{ + StrokeOp(width, color); + return *this; +} + +inline +Painter& Painter::Stroke(double width, const Image& image, const Xform2D& transsrc, dword flags) +{ + StrokeOp(width, image, transsrc, flags); + return *this; +} + +inline +Painter& Painter::Stroke(double width, const Pointf& p1, const RGBA& color1, const Pointf& p2, const RGBA& color2, int style) +{ + StrokeOp(width, p1, color1, p2, color2, style); + return *this; +} + +inline +Painter& Painter::Stroke(double width, const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style) +{ + StrokeOp(width, f, color1, c, r, color2, style); + return *this; +} + +inline +Painter& Painter::Clip() +{ + ClipOp(); + return *this; +} + +inline Painter& Painter::ColorStop(double pos, const RGBA& color) +{ + ColorStopOp(pos, color); + return *this; +} + +inline Painter& Painter::ClearStops() +{ + ClearStopsOp(); + return *this; +} + +inline Painter& Painter::Opacity(double o) +{ + OpacityOp(o); + return *this; +} + +inline Painter& Painter::LineCap(int linecap) +{ + LineCapOp(linecap); + return *this; +} + +inline Painter& Painter::LineJoin(int linejoin) +{ + LineJoinOp(linejoin); + return *this; +} + +inline Painter& Painter::MiterLimit(double l) +{ + MiterLimitOp(l); + return *this; +} + +inline Painter& Painter::EvenOdd(bool evenodd) +{ + EvenOddOp(evenodd); + return *this; +} + +inline Painter& Painter::Dash(const Vector& dash, double start) +{ + if(dash.GetCount() & 1) { + Vector dash1; + dash1.Append(dash); + dash1.Append(dash); + DashOp(dash1, start); + } + else + DashOp(dash, start); + return *this; +} + +inline Painter& Painter::Transform(const Xform2D& m) +{ + TransformOp(m); + return *this; +} + +inline void Painter::Begin() +{ + BeginOp(); +} + +inline void Painter::End() +{ + EndOp(); +} + +inline void Painter::BeginMask() +{ + BeginMaskOp(); +} + +inline void Painter::BeginOnPath(double q, bool abs) +{ + BeginOnPathOp(q, abs); +} + +inline Painter& Painter::Character(const Pointf& p, int ch, Font fnt) +{ + CharacterOp(p, ch, fnt); + return *this; +} + +inline +Painter& Painter::Text(const Pointf& p, const wchar *text, Font fnt, int n, double *dx) +{ + TextOp(p, text, fnt, n, dx); + return *this; +} diff --git a/newdraw/Painter/Painter.upp b/newdraw/Painter/Painter.upp new file mode 100644 index 000000000..b384ee688 --- /dev/null +++ b/newdraw/Painter/Painter.upp @@ -0,0 +1,42 @@ +description "2D software rendering with PDF/SVG strength\377"; + +uses + Core, + CtrlLib; + +file + Painter.h, + Painter.hpp, + Painter.cpp, + SvgArc.cpp, + PainterPath.cpp, + FontWin32.cpp, + FontX11.cpp, + DrawOp.cpp, + Painting.h, + Painting.cpp, + PaintPainting.icpp, + BufferPainter.h, + Xform2D.cpp, + Approximate.cpp, + Stroker.cpp, + Dasher.cpp, + Transformer.cpp, + Interpolator.cpp optimize_speed, + Rasterizer.cpp optimize_speed, + RasterizerClip.cpp optimize_speed, + Path.cpp optimize_speed, + Context.cpp, + Fillers.h, + Fillers.cpp optimize_speed, + RenderChar.cpp, + Render.cpp optimize_speed, + Image.cpp optimize_speed, + Mask.cpp optimize_speed, + Gradient.cpp optimize_speed, + RadialGradient.cpp optimize_speed, + OnPath.cpp, + srcimp.tpp, + Info readonly separator, + Copying; + diff --git a/newdraw/Painter/PainterPath.cpp b/newdraw/Painter/PainterPath.cpp new file mode 100644 index 000000000..71a9d0cbf --- /dev/null +++ b/newdraw/Painter/PainterPath.cpp @@ -0,0 +1,107 @@ +#include "Painter.h" + +NAMESPACE_UPP + +bool Painter::ReadBool(CParser& p) +{ + while(p.Char(',')); + if(p.Char('1')) return true; + p.Char('0'); + return false; +} + +double Painter::ReadDouble(CParser& p) +{ + while(p.Char(',')); + return p.IsDouble() ? p.ReadDouble() : 0; +} + +Pointf Painter::ReadPoint(CParser& p) +{ + Pointf t; + t.x = ReadDouble(p); + t.y = ReadDouble(p); + return t; +} + +Painter& Painter::Path(CParser& p) +{ + while(!p.IsEof()) { + int c = p.GetChar(); + p.Spaces(); + bool rel = IsLower(c); + Pointf t, t1, t2; + switch(ToUpper(c)) { + case 'M': + t = ReadPoint(p); + Move(t, rel); + case 'L': + while(p.IsDouble()) { + t = ReadPoint(p); + Line(t, rel); + } + break; + case 'Z': + Close(); + break; + case 'H': + while(p.IsDouble()) + Line(p.ReadDouble(), Null, rel); + break; + case 'V': + while(p.IsDouble()) + Line(Null, p.ReadDouble(), rel); + break; + case 'C': + while(p.IsDouble()) { + t1 = ReadPoint(p); + t2 = ReadPoint(p); + t = ReadPoint(p); + Cubic(t1, t2, t, rel); + } + break; + case 'S': + while(p.IsDouble()) { + t2 = ReadPoint(p); + t = ReadPoint(p); + Cubic(t2, t, rel); + } + break; + case 'Q': + while(p.IsDouble()) { + t1 = ReadPoint(p); + t = ReadPoint(p); + Quadratic(t1, t, rel); + } + break; + case 'T': + while(p.IsDouble()) { + t = ReadPoint(p); + Quadratic(t, rel); + } + break; + case 'A': + while(p.IsDouble()) { + t1 = ReadPoint(p); + double xangle = ReadDouble(p); + bool large = ReadBool(p); + bool sweep = ReadBool(p); + t = ReadPoint(p); + SvgArc(t1, xangle * M_PI / 180.0, large, sweep, t, rel); + } + break; + default: + return *this; + } + } + return *this; +} + +Painter& Painter::Path(const char *path) +{ + CParser p(path); + Path(p); + return *this; +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Painting.cpp b/newdraw/Painter/Painting.cpp new file mode 100644 index 000000000..d4f02d176 --- /dev/null +++ b/newdraw/Painter/Painting.cpp @@ -0,0 +1,287 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void PaintingPainter::ClearOp(const RGBA& color) +{ + Put(PAINTING_CLEAR); + Put(color); +} + +void PaintingPainter::MoveOp(const Pointf& p, bool rel) +{ + Put(PAINTING_MOVE + rel); + Putf(p); +} + +void PaintingPainter::LineOp(const Pointf& p, bool rel) +{ + Put(PAINTING_LINE + rel); + Putf(p); +} + +void PaintingPainter::QuadraticOp(const Pointf& p1, const Pointf& p, bool rel) +{ + Put(PAINTING_QUADRATIC + rel); + Putf(p1); + Putf(p); +} + +void PaintingPainter::QuadraticOp(const Pointf& p, bool rel) +{ + Put(PAINTING_QUADRATIC_S + rel); + Putf(p); +} + +void PaintingPainter::CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel) +{ + Put(PAINTING_CUBIC + rel); + Putf(p1); + Putf(p2); + Putf(p); +} + +void PaintingPainter::CubicOp(const Pointf& p2, const Pointf& p, bool rel) +{ + Put(PAINTING_CUBIC_S + rel); + Putf(p2); + Putf(p); +} + +void PaintingPainter::ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel) +{ + Put(PAINTING_ARC + rel); + Putf(c); + Putf(r); + Putf(angle); + Putf(sweep); +} + +void PaintingPainter::SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep, const Pointf& p, bool rel) +{ + Put(PAINTING_SVGARC + rel); + Putf(r); + Putf(xangle); + Put(large); + Put(sweep); + Putf(p); +} + +void PaintingPainter::CloseOp() +{ + Put(PAINTING_CLOSE); +} + +void PaintingPainter::DivOp() +{ + Put(PAINTING_DIV); +} + +void PaintingPainter::FillOp(const RGBA& color) +{ + Put(PAINTING_FILL_SOLID); + Put(color); +} + +void PaintingPainter::FillOp(const Image& image, const Xform2D& transsrc, dword flags) +{ + Put(PAINTING_FILL_IMAGE); + Putf(transsrc); + Put(flags); + data.Add(image); +} + +void PaintingPainter::FillOp(const Pointf& p1, const RGBA& color1, const Pointf& p2, + const RGBA& color2, int style) +{ + Put(PAINTING_FILL_GRADIENT); + Putf(p1); + Put(color1); + Putf(p2); + Put(color2); + Put(style); +} + +void PaintingPainter::FillOp(const Pointf& f, const RGBA& color1, + const Pointf& p, double r, const RGBA& color2, int style) +{ + Put(PAINTING_FILL_RADIAL); + Putf(f); + Put(color1); + Putf(p); + Putf(r); + Put(color2); + Put(style); +} + +void PaintingPainter::StrokeOp(double width, const RGBA& color) +{ + Put(PAINTING_STROKE_SOLID); + Putf(width); + Put(color); +} + +void PaintingPainter::StrokeOp(double width, const Image& image, + const Xform2D& transsrc, dword flags) +{ + Put(PAINTING_STROKE_IMAGE); + Putf(width); + Putf(transsrc); + Put(flags); + data.Add(image); +} + +void PaintingPainter::StrokeOp(double width, const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, int style) +{ + Put(PAINTING_STROKE_GRADIENT); + Putf(width); + Putf(p1); + Put(color1); + Putf(p2); + Put(color2); + Put(style); +} + +void PaintingPainter::StrokeOp(double width, const Pointf& f, + const RGBA& color1, const Pointf& p, double r, + const RGBA& color2, int style) +{ + Put(PAINTING_STROKE_RADIAL); + Putf(width); + Putf(f); + Put(color1); + Putf(p); + Putf(r); + Put(color2); + Put(style); +} + +void PaintingPainter::ClipOp() +{ + Put(PAINTING_CLIP); +} + +void PaintingPainter::CharacterOp(const Pointf& p, int ch, Font fnt) +{ + Put(PAINTING_CHARACTER); + Putf(p); + Put32(ch); + Put(fnt); +} + +void PaintingPainter::TextOp(const Pointf& p, const wchar *text, Font fnt, int n, double *dx) +{ + Put(PAINTING_TEXT); + Putf(p); + Put32(n); + Put((bool)dx); + Put(fnt); + for(int i = 0; i < n; i++) { + Put32(text[i]); + if(dx) + Putf(dx[i]); + } +} + +void PaintingPainter::ColorStopOp(double pos, const RGBA& color) +{ + Put(PAINTING_COLORSTOP); + Putf(pos); + Put(color); +} + +void PaintingPainter::ClearStopsOp() +{ + Put(PAINTING_CLEARSTOPS); +} + +void PaintingPainter::OpacityOp(double o) +{ + Put(PAINTING_OPACITY); + Putf(o); +} + +void PaintingPainter::LineCapOp(int linecap) +{ + Put(PAINTING_LINECAP); + Put(linecap); +} + +void PaintingPainter::LineJoinOp(int linejoin) +{ + Put(PAINTING_LINEJOIN); + Put(linejoin); +} + +void PaintingPainter::MiterLimitOp(double l) +{ + Put(PAINTING_MITERLIMIT); + Putf(l); +} + +void PaintingPainter::EvenOddOp(bool evenodd) +{ + Put(PAINTING_EVENODD); + Put(evenodd); +} + +void PaintingPainter::DashOp(const Vector& dash, double start) +{ + Put(PAINTING_DASH); + Put32(dash.GetCount()); + for(int i = 0; i < dash.GetCount(); i++) + Putf(dash[i]); + Putf(start); +} + +void PaintingPainter::TransformOp(const Xform2D& m) +{ + Put(PAINTING_TRANSFORM); + Putf(m); +} + +void PaintingPainter::BeginOp() +{ + Put(PAINTING_BEGIN); +} + +void PaintingPainter::EndOp() +{ + Put(PAINTING_END); +} + +void PaintingPainter::BeginMaskOp() +{ + Put(PAINTING_BEGINMASK); +} + +void PaintingPainter::BeginOnPathOp(double q, bool abs) +{ + Put(PAINTING_BEGINONPATH); + Putf(q); + Put(abs); +} + +Painting PaintingPainter::GetResult() +{ + Painting p; + p.cmd = cmd.GetResult(); + p.data = data; + p.size = size; + return p; +} + +void PaintingPainter::Create(double cx, double cy) +{ + cmd.Create(); + size.cx = cx; + size.cy = cy; +} + +void PaintingPainter::Create(Sizef sz) +{ + Create(sz.cx, sz.cy); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Painting.h b/newdraw/Painter/Painting.h new file mode 100644 index 000000000..1ee9657e0 --- /dev/null +++ b/newdraw/Painter/Painting.h @@ -0,0 +1,137 @@ +enum { + PAINTING_CLEAR, + + PAINTING_MOVE = 4, + PAINTING_MOVE_REL, + PAINTING_LINE, + PAINTING_LINE_REL, + PAINTING_QUADRATIC, + PAINTING_QUADRATIC_REL, + PAINTING_QUADRATIC_S, + PAINTING_QUADRATIC_S_REL, + PAINTING_CUBIC, + PAINTING_CUBIC_REL, + PAINTING_CUBIC_S, + PAINTING_CUBIC_S_REL, + PAINTING_ARC, + PAINTING_ARC_REL, + PAINTING_SVGARC, + PAINTING_SVGARC_REL, + PAINTING_CLOSE, + PAINTING_DIV, + + PAINTING_FILL_SOLID, + PAINTING_FILL_IMAGE, + PAINTING_FILL_GRADIENT, + PAINTING_FILL_RADIAL, + + PAINTING_STROKE_SOLID, + PAINTING_STROKE_IMAGE, + PAINTING_STROKE_GRADIENT, + PAINTING_STROKE_RADIAL, + + PAINTING_CLIP, + + PAINTING_CHARACTER, + PAINTING_TEXT, + + PAINTING_COLORSTOP, + PAINTING_CLEARSTOPS, + PAINTING_OPACITY, + PAINTING_LINECAP, + PAINTING_LINEJOIN, + PAINTING_MITERLIMIT, + PAINTING_EVENODD, + PAINTING_DASH, + + PAINTING_TRANSFORM, + PAINTING_BEGIN, + PAINTING_END, + PAINTING_BEGINMASK, + PAINTING_BEGINONPATH, +}; + +class PaintingPainter : public Painter { + StringStream cmd; + ValueArray data; + Sizef size; + + void Put(int c) { cmd.Put(c); } + void Put32(int c) { cmd.Put32(c); } + void Put(const RGBA& c) { cmd.Put(&c, sizeof(RGBA)); } + void Putf(const double& d) { cmd.Put(&d, sizeof(double)); } + void Putf(const Pointf& p) { cmd.Put(&p, sizeof(p)); } + void Putf(const Xform2D& m) { cmd.Put(&m, sizeof(m)); } + void Put(const Font& f) { cmd.Put(&f, sizeof(Font)); } + +protected: + virtual void ClearOp(const RGBA& color); + + virtual void MoveOp(const Pointf& p, bool rel); + virtual void LineOp(const Pointf& p, bool rel); + virtual void QuadraticOp(const Pointf& p1, const Pointf& p, bool rel); + virtual void QuadraticOp(const Pointf& p, bool rel); + virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel); + virtual void CubicOp(const Pointf& p2, const Pointf& p, bool rel); + virtual void ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel); + virtual void SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep, + const Pointf& p, bool rel); + virtual void CloseOp(); + virtual void DivOp(); + + virtual void FillOp(const RGBA& color); + virtual void FillOp(const Image& image, const Xform2D& transsrc, dword flags); + virtual void FillOp(const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, + int style); + virtual void FillOp(const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, + int style); + + virtual void StrokeOp(double width, const RGBA& rgba); + virtual void StrokeOp(double width, const Image& image, const Xform2D& transsrc, + dword flags); + virtual void StrokeOp(double width, const Pointf& p1, const RGBA& color1, + const Pointf& p2, const RGBA& color2, + int style); + virtual void StrokeOp(double width, const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, + int style); + + virtual void ClipOp(); + + virtual void CharacterOp(const Pointf& p, int ch, Font fnt); + virtual void TextOp(const Pointf& p, const wchar *text, Font fnt, int n = -1, + double *dx = NULL); + + virtual void ColorStopOp(double pos, const RGBA& color); + virtual void ClearStopsOp(); + + virtual void OpacityOp(double o); + virtual void LineCapOp(int linecap); + virtual void LineJoinOp(int linejoin); + virtual void MiterLimitOp(double l); + virtual void EvenOddOp(bool evenodd); + virtual void DashOp(const Vector& dash, double start); + + virtual void TransformOp(const Xform2D& m); + + virtual void BeginOp(); + virtual void EndOp(); + + virtual void BeginMaskOp(); + virtual void BeginOnPathOp(double q, bool abs); + +public: + Painting GetResult(); + operator Painting() { return GetResult(); } + + void Create(double cx, double cy); + void Create(Sizef sz); + + Sizef GetSize() const { return size; } + + PaintingPainter() {} + PaintingPainter(double cx, double cy) { Create(cx, cy); } + PaintingPainter(Sizef sz) { Create(sz); } +}; diff --git a/newdraw/Painter/Path.cpp b/newdraw/Painter/Path.cpp new file mode 100644 index 000000000..f36b4581f --- /dev/null +++ b/newdraw/Painter/Path.cpp @@ -0,0 +1,136 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void BufferPainter::ClearPath() +{ + path.type.Clear(); + path.data.Clear(); + current = move = Null; + ccontrol = qcontrol = Pointf(0, 0); + ischar = false; +} + +Pointf BufferPainter::PathPoint(const Pointf& p, bool rel) +{ + Pointf r; + r.x = IsNull(p.x) ? current.x : rel ? p.x + current.x : p.x; + r.y = IsNull(p.y) ? current.y : rel ? p.y + current.y : p.y; + if(IsNull(current)) { + ClearPath(); + pathrect.left = pathrect.right = r.x; + pathrect.top = pathrect.bottom = r.y; + pathattr = attr; + } + else { + pathrect.left = min(pathrect.left, r.x); + pathrect.top = min(pathrect.top, r.y); + pathrect.right = max(pathrect.right, r.x); + pathrect.bottom = max(pathrect.bottom, r.y); + } + return r; +} + +Pointf BufferPainter::EndPoint(const Pointf& p, bool rel) +{ + return current = PathPoint(p, rel); +} + +void *BufferPainter::PathAddRaw(int type, int size) +{ + int q = path.data.GetCount(); + path.type.Add(type); + path.data.SetCount(q + size); + return &path.data[q]; +} + +void BufferPainter::MoveOp(const Pointf& p, bool rel) +{ + move = ccontrol = qcontrol = EndPoint(p, rel); + PathAdd(MOVE).p = move; +} + +void BufferPainter::DoMove0() +{ + if(IsNull(move)) + MoveOp(Pointf(0, 0), false); +} + +void BufferPainter::LineOp(const Pointf& p, bool rel) +{ + DoMove0(); + PathAdd(LINE).p = ccontrol = qcontrol = EndPoint(p, rel); +} + +void BufferPainter::QuadraticOp(const Pointf& p1, const Pointf& p, bool rel) +{ + DoMove0(); + QuadraticData& m = PathAdd(QUADRATIC); + qcontrol = m.p1 = PathPoint(p1, rel); + m.p = EndPoint(p, rel); +} + +void BufferPainter::QuadraticOp(const Pointf& p, bool rel) +{ + QuadraticOp(2.0 * current - qcontrol, p, rel); +} + +void BufferPainter::CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool rel) +{ + DoMove0(); + CubicData& m = PathAdd(CUBIC); + m.p1 = PathPoint(p1, rel); + ccontrol = m.p2 = PathPoint(p2, rel); + m.p = EndPoint(p, rel); +} + +void BufferPainter::CubicOp(const Pointf& p2, const Pointf& p, bool rel) +{ + CubicOp(2.0 * current - ccontrol, p2, p, rel); +} + +void BufferPainter::ArcOp(const Pointf& c, const Pointf& r, double angle, double sweep, bool rel) +{ + DoMove0(); + DoArc(PathPoint(c, rel), r, angle, sweep, 0); +} + +void BufferPainter::SvgArcOp(const Pointf& r, double xangle, bool large, bool sweep, + const Pointf& p, bool rel) +{ + DoMove0(); + Pointf c = current; + DoSvgArc(r, xangle, large, sweep, EndPoint(p, rel), c); +} + +void BufferPainter::CloseOp() +{ + if(!IsNull(move) && !IsNull(current) && current != move) { + Line(move); + move = Null; + } +} + +void BufferPainter::DivOp() +{ + CloseOp(); + path.type.Add(DIV); +} + +void BufferPainter::CharacterOp(const Pointf& p, int ch, Font fnt) +{ +#if 0 + DoMove0(); + PaintCharacter(*this, p, ch, fnt); +#else + move = current = EndPoint(p, false); + CharData& m = PathAdd(CHAR); + m.p = EndPoint(p, false); + m.ch = ch; + m.fnt = fnt; + ischar = true; + EvenOdd(); +#endif +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/RadialGradient.cpp b/newdraw/Painter/RadialGradient.cpp new file mode 100644 index 000000000..34ba32a67 --- /dev/null +++ b/newdraw/Painter/RadialGradient.cpp @@ -0,0 +1,82 @@ +#include "Painter.h" + +NAMESPACE_UPP + +struct PainterRadialSpan : SpanSource { + LinearInterpolator interpolator; + double cx, cy, r, fx, fy; + int style; + int alpha; + const RGBA *gradient; + double C; + + void Set(double _x, double _y, double _r, double _fx, double _fy) + { + cx = _x; + cy = _y; + r = _r; + fx = _fx; + fy = _fy; + fx -= cx; + fy -= cy; + double fx2 = double(fx) * double(fx); + double fy2 = double(fy) * double(fy); + C = fx * fx + fy * fy - r * r; + } + + void Get(RGBA *_span, int x, int y, unsigned len) + { + if(r <= 0) + return; + interpolator.Begin(x, y, len); + RGBA *span = (RGBA *)_span; + while(len--) { + Point p = interpolator.Get(); + int h; + const double q256 = 1 / 256.0; + double dx = q256 * p.x - cx - fx; + double dy = q256 * p.y - cy - fy; + if(dx == 0 && dy == 0) + h = 0; + else { + double A = dx * dx + dy * dy; + double b = (fx * dx + fy * dy); + double t = (sqrt(b * b - A * C) - b) / (A); + h = t >= 0.001 ? int(2047 / t) : 2047; + } + if(style == GRADIENT_REPEAT) + h = h & 2047; + else + if(style == GRADIENT_REFLECT) + h = (h & 2048) ? (2047 - h & 2047) : (h & 2047); + else + h = minmax(h, 0, 2047); + *span++ = gradient[h]; + } + } +}; + +void BufferPainter::RenderRadial(double width, const Pointf& f, const RGBA& color1, + const Pointf& c, double r, const RGBA& color2, int style) +{ + PainterRadialSpan sg; + Xform2D m = pathattr.mtx; + sg.interpolator.Set(Inverse(m)); + sg.style = style; + sg.Set(c.x, c.y, r, f.x, f.y); + MakeGradient(color1, color2, 2048); + sg.gradient = gradient[0]; + RenderPath(width, &sg, RGBAZero()); +} + +void BufferPainter::FillOp(const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style) +{ + RenderRadial(-1, f, color1, c, r, color2, style); +} + +void BufferPainter::StrokeOp(double width, const Pointf& f, const RGBA& color1, const Pointf& c, double r, const RGBA& color2, int style) +{ + RenderRadial(width, f, color1, c, r, color2, style); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Rasterizer.cpp b/newdraw/Painter/Rasterizer.cpp new file mode 100644 index 000000000..3ceb4a5a2 --- /dev/null +++ b/newdraw/Painter/Rasterizer.cpp @@ -0,0 +1,356 @@ +#include "Painter.h" + +// This code is based in AGG rasterizer with this original information: + +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// +// The author gratefully acknowleges the support of David Turner, +// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType +// libray - in producing this work. See http://www.freetype.org for details. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- + +#define LLOG(x) // LOG(x) + +NAMESPACE_UPP + +void Rasterizer::Init() +{ + p0 = Pointf(0, 0); + min_y = INT_MAX; + max_y = INT_MIN; +} + +void Rasterizer::Reset() +{ + PAINTER_TIMING("Rasterizer::Reset"); + for(int i = min_y; i <= max_y; i++) + cell[i].SetCount(0); + Init(); +} + +void Rasterizer::SetClip(const Rectf& rect) +{ + cliprect = rect & Sizef(sz); +} + +Rasterizer::Rasterizer(int cx, int cy, bool subpixel) +{ + mx = subpixel ? 3 * 256 : 256; + sz.cx = subpixel ? 3 * cx : cx; + sz.cy = cy; + cell.Alloc(sz.cy + 1); + cliprect = Sizef(sz); + Init(); + Reset(); +} + +inline Rasterizer::Cell *Rasterizer::AddCells(int y, int n) +{ + Vector& v = cell[y]; + if(v.GetAlloc() == 0) { + v.Reserve(16); + v.SetCount(n); + return &v[0]; + } + y = v.GetCount(); + v.SetCount(y + n); + return &v[y]; +} + +inline void Rasterizer::RenderHLine(int ey, int x1, int y1, int x2, int y2) +{ + int ex1 = x1 >> 8; + int ex2 = x2 >> 8; + int fx1 = x1 & 255; + int fx2 = x2 & 255; + Cell *c; + if(y1 == y2) + return; + int dy = y2 - y1; + if(ex1 == ex2) { + c = AddCells(ey, 1); + c->x = ex1; + c->cover = dy; + c->area = (fx1 + fx2) * dy; + return; + } + int dx = x2 - x1; + if(dx < 0) { + int p = fx1 * dy; + dx = -dx; + int delta = p / dx; + int mod = p % dx; + if(mod < 0) { + delta--; + mod += dx; + } + c = AddCells(ey, abs(ex2 - ex1) + 1); + c->x = ex1; + c->cover = delta; + c->area = fx1 * delta; + c++; + ex1--; + y1 += delta; + if(ex1 != ex2) { + p = (y2 - y1 + delta) * 256; + int lift = p / dx; + int rem = p % dx; + if (rem < 0) { + lift--; + rem += dx; + } + mod -= dx; + while(ex1 != ex2) { + delta = lift; + mod += rem; + if(mod >= 0) { + mod -= dx; + delta++; + } + c->x = ex1; + c->cover = delta; + c->area = delta * 256; + c++; + y1 += delta; + ex1--; + } + } + c->x = ex2; + dy = y2 - y1; + c->cover = dy; + c->area = (fx2 + 256) * dy; + } + else { + int p = (256 - fx1) * dy; + int delta = p / dx; + int mod = p % dx; + if(mod < 0) { + delta--; + mod += dx; + } + c = AddCells(ey, abs(ex2 - ex1) + 1); + c->x = ex1; + c->cover = delta; + c->area = (fx1 + 256) * delta; + c++; + ex1++; + y1 += delta; + if(ex1 != ex2) { + p = (y2 - y1 + delta) * 256; + int lift = p / dx; + int rem = p % dx; + if (rem < 0) { + lift--; + rem += dx; + } + mod -= dx; + while(ex1 != ex2) { + delta = lift; + mod += rem; + if(mod >= 0) { + mod -= dx; + delta++; + } + c->x = ex1; + c->cover = delta; + c->area = delta * 256; + c++; + y1 += delta; + ex1++; + } + } + c->x = ex2; + dy = y2 - y1; + c->cover = dy; + c->area = fx2 * dy; + } +} + +void Rasterizer::LineRaw(int x1, int y1, int x2, int y2) +{ + PAINTER_TIMING("LineRaw"); + LLOG("Rasterizer::LineRaw " << x1 / 256.0 << ':' << y1 / 256.0 + << " - " << x2 / 256.0 << ':' << y2 / 256.0); + int ex1 = x1 >> 8; + int ex2 = x2 >> 8; + int ey1 = y1 >> 8; + int ey2 = y2 >> 8; + + ASSERT(ey1 >= 0 && ey1 <= sz.cy && ey2 >= 0 && ey2 <= sz.cy); + + if(ey1 < min_y) { + if(ey1 < 0) return; + min_y = ey1; + } + if(ey1 > max_y) { + if(ey1 > sz.cy) return; + max_y = min(ey1, sz.cy - 1); + } + if(ey2 < min_y) { + if(ey2 < 0) return; + min_y = ey2; + } + if(ey2 > max_y) { + if(ey2 > sz.cy) return; + max_y = min(ey2, sz.cy - 1); + } + + enum dx_limit_e { dx_limit = 16384 << 8 }; + int dx = x2 - x1; + if(dx >= dx_limit || dx <= -dx_limit) { + int cx = (x1 + x2) >> 1; + int cy = (y1 + y2) >> 1; + LineRaw(x1, y1, cx, cy); + LineRaw(cx, cy, x2, y2); + return; + } + int dy = y2 - y1; + int fy1 = y1 & 255; + int fy2 = y2 & 255; + + + Cell *c; + int x_from, x_to; + int p, rem, mod, lift, delta, first, incr; + + if(ey1 == ey2) { + RenderHLine(ey1, x1, fy1, x2, fy2); + return; + } + incr = 1; + if(dx == 0) { + int ex = x1 >> 8; + int two_fx = (x1 - (ex << 8)) << 1; + int area; + first = 256; + if(dy < 0) { + first = 0; + incr = -1; + } + x_from = x1; + delta = first - fy1; + c = AddCells(ey1, 1); + c->x = ex1; + c->cover = delta; + c->area = two_fx * delta; + ey1 += incr; + delta = first + first - 256; + area = two_fx * delta; + while(ey1 != ey2) { + c = AddCells(ey1, 1); + c->x = ex1; + c->cover = delta; + c->area = area; + ey1 += incr; + } + delta = fy2 - 256 + first; + c = AddCells(ey1, 1); + c->x = ex1; + c->cover = delta; + c->area = two_fx * delta; + return; + } + p = (256 - fy1) * dx; + first = 256; + if(dy < 0) { + p = fy1 * dx; + first = 0; + incr = -1; + dy = -dy; + } + delta = p / dy; + mod = p % dy; + if(mod < 0) { + delta--; + mod += dy; + } + x_from = x1 + delta; + RenderHLine(ey1, x1, fy1, x_from, first); + ey1 += incr; + if(ey1 != ey2) { + p = dx << 8; + lift = p / dy; + rem = p % dy; + if(rem < 0) { + lift--; + rem += dy; + } + mod -= dy; + while(ey1 != ey2) { + delta = lift; + mod += rem; + if(mod >= 0) { + mod -= dy; + delta++; + } + x_to = x_from + delta; + RenderHLine(ey1, x_from, 256 - first, x_to, first); + x_from = x_to; + ey1 += incr; + } + } + RenderHLine(ey1, x_from, 256 - first, x2, fy2); +} + +void Rasterizer::Filler::End() {} + +void Rasterizer::Render(int y, Rasterizer::Filler& g, bool evenodd) +{ + PAINTER_TIMING("Render"); + const Cell *c, *e; + if(y < min_y || y > max_y) return; + Vector& cl = cell[y]; + if(cl.GetCount() == 0) return; + Sort(cl); + c = cl; + e = cl.End(); + g.Start(c->x, (e - 1)->x); + int cover = 0; + while(c < e) { + int x = c->x; + int area = c->area; + cover += c->cover; + c++; + while(c < e && c->x == x) { + area += c->area; + cover += c->cover; + c++; + } + if(evenodd) { + if(area) { + int h = abs(((cover << 9) - area) >> 9) & 511; + g.Render(h > 256 ? 512 - h : h); + x++; + } + if(c < e && c->x > x) { + int h = abs(cover) & 511; + g.Render(h > 256 ? 512 - h : h, c->x - x); + } + } + else { + if(area) { + g.Render(min(abs(((cover << 9) - area) >> 9), 256)); + x++; + } + if(c < e && c->x > x) + g.Render(min(abs(cover), 256), c->x - x); + } + } + g.End(); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Rasterizer3.h b/newdraw/Painter/Rasterizer3.h new file mode 100644 index 000000000..e940d40dc --- /dev/null +++ b/newdraw/Painter/Rasterizer3.h @@ -0,0 +1,45 @@ +class Rasterizer { + Rectf cliprect; + double x1, y1; + Buffer< Vector > cell; + int xmax, ymax; + int min_y; + int max_y; + Size sz; + + inline dword Cell(int x, int w, int c) { return (x << 18) + (w << 9) + c; } + inline int GetX(dword cell) { return cell >> 18; } + inline int GetW(dword cell) { return (cell >> 9) & 511; } + inline int GetC(dword cell) { return (cell & 256) ? -512 | (cell & 511) : (cell & 511); } + + void Init(); + dword *AddCells(int y, int n); + void RenderHLine(int ey, int x1, int y1, int x2, int y2); + void LineClip(double x1, double y1, double x2, double y2); + int CvX(double x); + int CvY(double y); + void CvLine(double x1, double y1, double x2, double y2); + +public: + struct Target { + virtual void Start(int x, int len) = 0; + virtual void Render(int val) = 0; + virtual void Render(int val, int len) = 0; + }; + + void LineRaw(int x1, int y1, int x2, int y2); + + void Move(double x, double y); + void Line(double x, double y); + + int MinY() const { return min_y; } + int MaxY() const { return max_y; } + + void SetClip(const Rectf& rect); + + void Render(int y, Target& g); + + void Reset(); + + Rasterizer(int cx, int cy); +}; diff --git a/newdraw/Painter/RasterizerClip.cpp b/newdraw/Painter/RasterizerClip.cpp new file mode 100644 index 000000000..29790618e --- /dev/null +++ b/newdraw/Painter/RasterizerClip.cpp @@ -0,0 +1,103 @@ +#include "Painter.h" + +#define LLOG(x) // DLOG(x) + +NAMESPACE_UPP + +void Rasterizer::CvLine(double x1, double y1, double x2, double y2) +{ + LLOG("CvLine " << x1 << ", " << y1 << " - " << x2 << ", " << y2); + LineRaw(Q8X(x1), Q8Y(y1), Q8X(x2), Q8Y(y2)); +} + +void Rasterizer::LineClip(double x1, double y1, double x2, double y2) +{ + if(y1 < cliprect.top) { + if(y2 < cliprect.top) + return; + x1 = (x2 - x1) * (cliprect.top - y1) / (y2 - y1) + x1; + y1 = cliprect.top; + } + else + if(y1 > cliprect.bottom) { + if(y2 > cliprect.bottom) + return; + x1 = (x2 - x1) * (cliprect.bottom - y1) / (y2 - y1) + x1; + y1 = cliprect.bottom; + } + if(y2 < cliprect.top) { + x2 = (x2 - x1) * (cliprect.top - y1) / (y2 - y1) + x1; + y2 = cliprect.top; + } + else + if(y2 > cliprect.bottom) { + x2 = (x2 - x1) * (cliprect.bottom - y1) / (y2 - y1) + x1; + y2 = cliprect.bottom; + } + double y, yy; + if(x1 < cliprect.left) { + if(x2 < cliprect.left) { + CvLine(cliprect.left, y1, cliprect.left, y2); + return; + } + y = (y2 - y1) * (cliprect.left - x1) / (x2 - x1) + y1; + if(x2 > cliprect.right) { + yy = (y2 - y1) * (cliprect.right - x1) / (x2 - x1) + y1; + CvLine(cliprect.left, y1, cliprect.left, y); + CvLine(cliprect.left, y, cliprect.right, yy); + CvLine(cliprect.right, yy, cliprect.right, y2); + return; + } + CvLine(cliprect.left, y1, cliprect.left, y); + CvLine(cliprect.left, y, x2, y2); + return; + } + else + if(x1 > cliprect.right) { + if(x2 > cliprect.right) { + CvLine(cliprect.right, y1, cliprect.right, y2); + return; + } + y = (y2 - y1) * (cliprect.right - x1) / (x2 - x1) + y1; + if(x2 < cliprect.left) { + yy = (y2 - y1) * (cliprect.left - x1) / (x2 - x1) + y1; + CvLine(cliprect.right, y1, cliprect.right, y); + CvLine(cliprect.right, y, cliprect.left, yy); + CvLine(cliprect.left, yy, cliprect.left, y2); + return; + } + CvLine(cliprect.right, y1, cliprect.right, y); + CvLine(cliprect.right, y, x2, y2); + return; + } + if(x2 < cliprect.left) { + y = (y2 - y1) * (cliprect.left - x1) / (x2 - x1) + y1; + CvLine(x1, y1, cliprect.left, y); + CvLine(cliprect.left, y, cliprect.left, y2); + return; + } + else + if(x2 > cliprect.right) { + y = (y2 - y1) * (cliprect.right - x1) / (x2 - x1) + y1; + CvLine(x1, y1, cliprect.right, y); + CvLine(cliprect.right, y, cliprect.right, y2); + return; + } + CvLine(x1, y1, x2, y2); +} + +void Rasterizer::Move(const Pointf& p) +{ + LLOG("Rasterizer::Move " << p); + p0 = p; +} + +void Rasterizer::Line(const Pointf& p) +{ + PAINTER_TIMING("Line"); + LLOG("Rasterizer::Line " << p); + LineClip(p0.x, p0.y, p.x, p.y); + p0 = p; +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Render.cpp b/newdraw/Painter/Render.cpp new file mode 100644 index 000000000..936b53c3b --- /dev/null +++ b/newdraw/Painter/Render.cpp @@ -0,0 +1,230 @@ +#include "Painter.h" +#include "Fillers.h" + +NAMESPACE_UPP + +void BufferPainter::ClearOp(const RGBA& color) +{ + UPP::Fill(~ib, color, ib.GetLength()); +} + +struct BufferPainter::OnPathTarget : LinearPathConsumer { + Vector path; + Pointf pos; + double len; + + virtual void Move(const Pointf& p) { + BufferPainter::PathLine& t = path.Add(); + t.len = 0; + pos = t.p = p; + } + virtual void Line(const Pointf& p) { + BufferPainter::PathLine& t = path.Add(); + len += (t.len = Distance(pos, p)); + pos = t.p = p; + } + + OnPathTarget() { len = 0; pos = Pointf(0, 0); } +}; + +Buffer BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color) +{ + Buffer newclip; + if(width == 0) + return newclip; + Transformer trans(pathattr.mtx); + Stroker stroker; + Dasher dasher; + OnPathTarget onpathtarget; + bool evenodd = pathattr.evenodd; + bool regular = pathattr.mtx.IsRegular() && width < 0 && !ischar; + double tolerance; + LinearPathConsumer *g = &rasterizer; + if(regular) + tolerance = 0.3; + else { + trans.target = g; + g = &trans; + tolerance = 0.3 / attr.mtx.GetScale(); + } + if(width == ONPATH) { + g = &onpathtarget; + regular = false; + } + else + if(width > 0) { + stroker.Init(width, pathattr.miter_limit, tolerance, pathattr.cap, pathattr.join); + stroker.target = g; + if(pathattr.dash.GetCount()) { + dasher.Init(pathattr.dash, pathattr.dash_start); + dasher.target = &stroker; + g = &dasher; + } + else + g = &stroker; + evenodd = false; + } + else + Close(); + byte *data = path.data; + int opacity = int(256 * pathattr.opacity); + Pointf pos = Pointf(0, 0); + int i = 0; + Rasterizer::Filler *rg; + SpanFiller span_filler; + SolidFiller solid_filler; + SubpixelFiller subpixel_filler; + ClipFiller clip_filler(render_cx); + NoAAFillerFilter noaa_filler; + MaskFillerFilter mf; + bool doclip = width == CLIP; + subpixel_filler.sbuffer = subpixel; + if(doclip) { + rg = &clip_filler; + newclip.Alloc(ib.GetHeight()); + } + else + if(ss) { + if(!span) + span.Alloc((subpixel ? 3 : 1) * ib.GetWidth() + 3); + if(subpixel) { + subpixel_filler.ss = ss; + subpixel_filler.buffer = span; + subpixel_filler.alpha = opacity; + rg = &subpixel_filler; + } + else { + span_filler.ss = ss; + span_filler.buffer = span; + span_filler.alpha = opacity; + rg = &span_filler; + } + } + else { + if(subpixel) { + subpixel_filler.color = Mul8(color, opacity); + subpixel_filler.ss = NULL; + rg = &subpixel_filler; + } + else { + solid_filler.c = Mul8(color, opacity); + rg = &solid_filler; + } + } + if(mode == MODE_NOAA) { + noaa_filler.Set(rg); + rg = &noaa_filler; + } + for(;;) { + if(i >= path.type.GetCount() || path.type[i] == DIV) { + g->End(); + if(width != ONPATH) { + for(int y = rasterizer.MinY(); y <= rasterizer.MaxY(); y++) { + solid_filler.t = subpixel_filler.t = span_filler.t = ib[y]; + subpixel_filler.end = subpixel_filler.t + ib.GetWidth(); + span_filler.y = subpixel_filler.y = y; + Rasterizer::Filler *rf = rg; + if(clip.GetCount()) { + const ClipLine& s = clip.Top()[y]; + if(s.IsEmpty()) goto empty; + if(!s.IsFull()) { + mf.Set(rg, s); + rf = &mf; + } + } + if(doclip) + clip_filler.Clear(); + rasterizer.Render(y, *rf, evenodd); + if(doclip) + clip_filler.Finish(newclip[y]); + empty:; + } + rasterizer.Reset(); + } + if(i >= path.type.GetCount()) + break; + } + else + switch(path.type[i]) { + case MOVE: { + const LinearData *d = (LinearData *)data; + data += sizeof(LinearData); + g->Move(pos = regular ? pathattr.mtx.Transform(d->p) : d->p); + break; + } + case LINE: { + const LinearData *d = (LinearData *)data; + data += sizeof(LinearData); + g->Line(pos = regular ? pathattr.mtx.Transform(d->p) : d->p); + break; + } + case QUADRATIC: { + const QuadraticData *d = (QuadraticData *)data; + data += sizeof(QuadraticData); + if(regular) { + Pointf p = pathattr.mtx.Transform(d->p); + ApproximateQuadratic(*g, pos, pathattr.mtx.Transform(d->p1), p, tolerance); + pos = p; + } + else { + ApproximateQuadratic(*g, pos, d->p1, d->p, tolerance); + pos = d->p; + } + break; + } + case CUBIC: { + const CubicData *d = (CubicData *)data; + data += sizeof(CubicData); + if(regular) { + Pointf p = pathattr.mtx.Transform(d->p); + ApproximateCubic(*g, pos, pathattr.mtx.Transform(d->p1), + pathattr.mtx.Transform(d->p2), p, tolerance); + pos = p; + } + else { + ApproximateCubic(*g, pos, d->p1, d->p2, d->p, tolerance); + pos = d->p; + } + break; + } + case CHAR: + ApproximateChar(*g, *(CharData *)data, tolerance); + data += sizeof(CharData); + break; + default: + NEVER(); + return newclip; + } + i++; + } + current = Null; + if(width == ONPATH) { + onpath = onpathtarget.path; + pathlen = onpathtarget.len; + } + return newclip; +} + +void BufferPainter::FillOp(const RGBA& color) +{ + RenderPath(FILL, NULL, color); +} + +void BufferPainter::StrokeOp(double width, const RGBA& color) +{ + RenderPath(width, NULL, color); +} + +void BufferPainter::ClipOp() +{ + Buffer newclip = RenderPath(CLIP, NULL, RGBAZero()); + if(attr.hasclip) + clip.Top() = newclip; + else { + clip.Add() = newclip; + attr.hasclip = true; + attr.cliplevel = clip.GetCount(); + } +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/RenderChar.cpp b/newdraw/Painter/RenderChar.cpp new file mode 100644 index 000000000..9f39e320a --- /dev/null +++ b/newdraw/Painter/RenderChar.cpp @@ -0,0 +1,127 @@ +#include "Painter.h" + +NAMESPACE_UPP + +struct GlyphPainter : NilPainter, LinearPathConsumer { + Vector glyph; + double tolerance; + Pointf pos, move; + + virtual void LineOp(const Pointf& p, bool); + virtual void MoveOp(const Pointf& p, bool); + virtual void QuadraticOp(const Pointf& p1, const Pointf& p, bool); + virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool); + virtual void CloseOp(); + + virtual void Line(const Pointf& p); + virtual void Move(const Pointf& p); +}; + +void GlyphPainter::Move(const Pointf& p) +{ + glyph.Add((float)1e31); + Line(p); + move = pos; +} + +void GlyphPainter::Line(const Pointf& p) +{ + glyph.Add((float)p.x); + glyph.Add((float)p.y); + pos = p; +} + +void GlyphPainter::MoveOp(const Pointf& p, bool) +{ + Move(p); +} + +void GlyphPainter::LineOp(const Pointf& p, bool) +{ + Line(p); +} + +void GlyphPainter::QuadraticOp(const Pointf& p1, const Pointf& p, bool) +{ + ApproximateQuadratic(*this, pos, p1, p, tolerance); + pos = p; +} + +void GlyphPainter::CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool) +{ + ApproximateCubic(*this, pos, p1, p2, p, tolerance); + pos = p; +} + +void GlyphPainter::CloseOp() +{ + if(move != pos && !IsNull(move)) + Line(move); +} + +struct GlyphKey { + Font fnt; + int chr; + double tolerance; + + bool operator==(const GlyphKey& b) const { + return fnt == b.fnt && chr == b.chr && tolerance == b.tolerance; + } + unsigned GetHashValue() const { + return CombineHash(fnt, chr, tolerance); + } +}; + +struct sMakeGlyph : LRUCache::Maker { + GlyphKey gk; + + GlyphKey Key() const { return gk; } + int Make(Value& v) const { + GlyphPainter gp; + gp.move = gp.pos = Null; + gp.tolerance = gk.tolerance; + PaintCharacter(gp, Pointf(0, 0), gk.chr, gk.fnt); + int sz = gp.glyph.GetCount() * 4; + v = RawPickToValue(gp.glyph); + return sz; + } +}; + +void BufferPainter::ApproximateChar(LinearPathConsumer& t, const CharData& ch, double tolerance) +{ + Value v; + INTERLOCKED { + static LRUCache cache; + cache.Shrink(500000); + sMakeGlyph h; + h.gk.fnt = ch.fnt; + h.gk.chr = ch.ch; + h.gk.tolerance = tolerance; + v = cache.Get(h); + } +#if 0 + GlyphPainter chp; + chp.move = chp.pos = Null; + chp.tolerance = tolerance; + PaintCharacter(chp, ch.p, ch.ch, ch.fnt); + Vector& g = chp.glyph; +#else + const Vector& g = ValueTo< Vector >(v); +#endif + int i = 0; + while(i < g.GetCount()) { + Pointf p; + p.x = g[i++]; + if(p.x > 1e30) { + p.x = g[i++]; + p.y = g[i++]; + t.Move(p + ch.p); + } + else { + p.y = g[i++]; + t.Line(p + ch.p); + } + } +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Stroker.cpp b/newdraw/Painter/Stroker.cpp new file mode 100644 index 000000000..e7e3192c5 --- /dev/null +++ b/newdraw/Painter/Stroker.cpp @@ -0,0 +1,162 @@ +#include "Painter.h" + +#define LLOG(x) // DLOG(x) + +NAMESPACE_UPP + +void Stroker::Init(double width, double miterlimit, double tolerance, int _linecap, int _linejoin) +{ + linecap = _linecap; + linejoin = _linejoin; + w2 = width / 2; + qmiter = miterlimit * w2; + qmiter *= qmiter; + fid = acos(1 - tolerance / w2); + p0 = p1 = p2 = Null; +} + +void Stroker::Move(const Pointf& p) +{ + LLOG("Stroker::Move " << p); + Finish(); + p1 = p; + p0 = p2 = Null; +} + +void Stroker::Round(const Pointf& p, const Pointf& v1, const Pointf& v2, double r) +{ + double a1 = Bearing(v1); + double a2 = Bearing(v2); + if(a1 < a2) + a1 += 2 * M_PI; + while(a1 > a2) { + PutLine(Polar(p, r, a1)); + a1 -= fid; + } +} + +void Stroker::Line(const Pointf& p3) +{ + LLOG("Stroker::Line " << p3); + if(IsNull(p1)) { + Move(p3); + return; + } + if(IsNull(p2)) { + Pointf v = p3 - p1; + double l = Length(v); + if(l < 1e-30) + return; + p2 = p3; + v1 = v; + o1 = Orthogonal(v1) * w2 / l; + a1 = p1 + o1; + b1 = p1 - o1; + if(IsNull(p0)) { + p0 = p1; + v0 = v1; + o0 = o1; + a0 = a1; + b0 = b1; + } + return; + } + + Pointf v2 = p3 - p2; + double l = Length(v2); + if(l < 1e-30) + return; + Pointf o2 = Orthogonal(v2) * w2 / l; + Pointf a2 = p2 + o2; + Pointf b2 = p2 - o2; + + double d = v1.y * v2.x - v2.y * v1.x; + if(d > 1e-30) { + Pointf ts = a1 + v1 * (v2.y * (a1.x - a2.x) - v2.x * (a1.y - a2.y)) / d; + PutMove(a1); + if(linejoin != LINEJOIN_MITER || SquaredDistance(ts, p2) > qmiter) { + PutLine(a1 + v1); + if(linejoin == LINEJOIN_ROUND) + Round(p2, o1, o2, w2); + } + else + PutLine(ts); + PutLine(a2); + PutMove(b2); + PutLine(p2); + PutLine(b1 + v1); + PutLine(b1); + } + else + if(d < -1e-30) { + Pointf ts = b2 + v2 * (v1.y * (a2.x - a1.x) - v1.x * (a2.y - a1.y)) / d; + PutMove(b2); + if(linejoin != LINEJOIN_MITER || SquaredDistance(ts, p2) > qmiter) { + if(linejoin == LINEJOIN_ROUND) + Round(p2, -o2, -o1, w2); + PutLine(b1 + v1); + } + else + PutLine(ts); + PutLine(b1); + PutMove(a1); + PutLine(a1 + v1); + PutLine(p2); + PutLine(a2); + } + else { + PutMove(a1); + PutLine(a1 + v1); + if(linejoin == LINEJOIN_ROUND) + Round(p2, o1, o2, w2); + PutLine(a2); + PutMove(b2); + PutLine(b1 + v1); + PutLine(b1); + } + p1 = p2; + v1 = v2; + o1 = o2; + a1 = a2; + b1 = b2; + p2 = p3; +} + +void Stroker::Cap(const Pointf& p, const Pointf& v, const Pointf& o, + const Pointf& a, const Pointf& b) +{ + PutMove(a); + if(linecap == LINECAP_SQUARE) { + Pointf nv = Orthogonal(o); + PutLine(a + nv); + PutLine(b + nv); + } + if(linecap == LINECAP_ROUND) + Round(p, -o, o, w2); + PutLine(b); +} + +void Stroker::Finish() +{ + if(IsNull(p1) || IsNull(p2) || IsNull(p0)) + return; + if(p2 == p0) + Line(p0 + v0); + else { + PutMove(a1); + PutLine(a1 + v1); + PutMove(b1 + v1); + PutLine(b1); + Cap(p0, v0, o0, b0, a0); + Cap(p2, -v1, -o1, a1 + v1, b1 + v1); + } + p0 = p1 = p2 = Null; +} + +void Stroker::End() +{ + Finish(); + PutEnd(); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/SvgArc.cpp b/newdraw/Painter/SvgArc.cpp new file mode 100644 index 000000000..970d0ffd9 --- /dev/null +++ b/newdraw/Painter/SvgArc.cpp @@ -0,0 +1,67 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void Painter::DoArc0(double theta, double th_sweep, const Xform2D& m) +{ + int nsegs = int(ceil(fabs(th_sweep / (M_PI * 0.5 + 0.001)))); + for(int i = 0; i < nsegs; i++) { + double th0 = theta + i * th_sweep / nsegs; + double th1 = theta + (i + 1) * th_sweep / nsegs; + double thHalf = 0.5 * (th1 - th0); + double t = (8.0 / 3.0) * sin(thHalf * 0.5) * sin(thHalf * 0.5) / sin(thHalf); + double x3 = cos(th1); + double y3 = sin(th1); + Cubic(m.Transform(cos(th0) - t * sin(th0), sin(th0) + t * cos(th0)), + m.Transform(x3 + t * sin(th1), y3 - t * cos(th1)), + m.Transform(x3, y3)); + } +} + +void Painter::DoArc(const Pointf& c, const Pointf& r, double angle, double sweep, double xangle) +{ + Xform2D m = Xform2D::Scale(r.x, r.y); + m = m * Xform2D::Translation(c.x, c.y); + Line(m.Transform(cos(angle), sin(angle))); + DoArc0(angle, sweep, m); +} + +void Painter::DoSvgArc(const Pointf& rr, double xangle, int large, int sweep, + const Pointf& p1, const Pointf& p0) +{ + Pointf r(fabs(rr.x), fabs(rr.y)); + Xform2D m = Xform2D::Rotation(-xangle); + Pointf d1 = m.Transform(0.5 * (p0 - p1)); + Pointf pr = r * r; + Pointf p = d1 * d1; + double check = p.x / pr.x + p.y / pr.y; + if(check > 1) + r *= sqrt(check); + m.x /= r.x; + m.y /= r.y; + Pointf q0 = m.Transform(p0); + Pointf q1 = m.Transform(p1); + double d = SquaredDistance(q0, q1); + double sfactor_sq = 1.0 / d - 0.25; + if(sfactor_sq < 0) + sfactor_sq = 0; + double sfactor = sqrt(sfactor_sq); + if(sweep == large) + sfactor = -sfactor; + Pointf c(0.5 * (q0.x + q1.x) - sfactor * (q1.y - q0.y), + 0.5 * (q0.y + q1.y) + sfactor * (q1.x - q0.x)); + double theta = Bearing(q0 - c); + double th_sweep = Bearing(q1 - c) - theta; + if(th_sweep < 0 && sweep) + th_sweep += 2 * M_PI; + else + if(th_sweep > 0 && !sweep) + th_sweep -= 2 * M_PI; + m = Xform2D::Rotation(xangle); + m.x *= r; + m.y *= r; + m = Xform2D::Translation(c.x, c.y) * m; + DoArc0(theta, th_sweep, m); +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/Transformer.cpp b/newdraw/Painter/Transformer.cpp new file mode 100644 index 000000000..ae4de0aff --- /dev/null +++ b/newdraw/Painter/Transformer.cpp @@ -0,0 +1,24 @@ +#include "Painter.h" + +NAMESPACE_UPP + +void LinearPathConsumer::End() +{ +} + +void LinearPathFilter::End() +{ + PutEnd(); +} + +void Transformer::Move(const Pointf& p) +{ + PutMove(xform.Transform(p)); +} + +void Transformer::Line(const Pointf& p) +{ + PutLine(xform.Transform(p)); +} + +END_UPP_NAMESPACE \ No newline at end of file diff --git a/newdraw/Painter/Xform2D.cpp b/newdraw/Painter/Xform2D.cpp new file mode 100644 index 000000000..479c3ccdd --- /dev/null +++ b/newdraw/Painter/Xform2D.cpp @@ -0,0 +1,115 @@ +#include "Painter.h" + +NAMESPACE_UPP + +Pointf Xform2D::Transform(const Pointf& f) const +{ + PAINTER_TIMING("Transform"); + return Pointf(f.x * x.x + f.y * x.y + t.x, f.x * y.x + f.y * y.y + t.y); +} + +Pointf Xform2D::Transform(double x, double y) const +{ + return Transform(Pointf(x, y)); +} + +Pointf Xform2D::GetScaleXY() const +{ + return Pointf(sqrt(x.x * x.x + y.x * y.x), sqrt(x.y * x.y + y.y * y.y)); +} + +double Xform2D::GetScale() const +{ + Pointf d = GetScaleXY(); + return Length(d) / M_SQRT2; +} + +bool Xform2D::IsRegular() const +{ + Pointf d = GetScaleXY(); + return fabs(d.x - d.y) < 1e-10 * fabs(max(d.x, d.y)); +} + +Xform2D::Xform2D() +{ + x.x = y.y = 1; + x.y = y.x = t.x = t.y = 0; +} + +Xform2D operator*(const Xform2D& a, const Xform2D& b) +{ + Xform2D r; + r.x.x = a.x.x * b.x.x + a.y.x * b.x.y; + r.x.y = a.x.y * b.x.x + a.y.y * b.x.y; + r.y.x = a.x.x * b.y.x + a.y.x * b.y.y; + r.y.y = a.x.y * b.y.x + a.y.y * b.y.y; + r.t.x = a.t.x * b.x.x + a.t.y * b.x.y + b.t.x; + r.t.y = a.t.x * b.y.x + a.t.y * b.y.y + b.t.y; + return r; +} + +Xform2D Xform2D::Translation(double x, double y) +{ + Xform2D m; + m.x.x = m.y.y = 1; + m.t = Pointf(x, y); + return m; +} + +Xform2D Xform2D::Scale(double sx, double sy) +{ + Xform2D m; + m.x.x = sx; + m.y.y = sy; + return m; +} + +Xform2D Xform2D::Scale(double scale) +{ + return Scale(scale, scale); +} + +Xform2D Xform2D::Rotation(double fi) +{ + double cosf = cos(fi); + double sinf = sin(fi); + Xform2D m; + m.x.x = cosf; + m.x.y = -sinf; + m.y.x = sinf; + m.y.y = cosf; + m.t.x = m.t.y = 0; + return m; +} + +Xform2D Xform2D::Sheer(double fi) +{ + Xform2D m; + m.x.x = m.y.y = 1; + m.x.y = atan(fi); + return m; +} + +Xform2D Xform2D::Identity() +{ + Xform2D m; + return m; +} + +double Determinant(const Xform2D& m) +{ + return m.x.x * m.y.y - m.y.x * m.x.y; +} + +Xform2D Inverse(const Xform2D& m) +{ + Xform2D r; + double det = Determinant(m); + r.x = Pointf(m.y.y, -m.x.y) / det; + r.y = Pointf(-m.y.x, m.x.x) / det; + r.t.x = -m.t.x * r.x.x - m.t.y * r.x.y; + r.t.y = -m.t.x * r.y.x - m.t.y * r.y.y; + return r; +} + +END_UPP_NAMESPACE diff --git a/newdraw/Painter/init b/newdraw/Painter/init new file mode 100644 index 000000000..8afab654c --- /dev/null +++ b/newdraw/Painter/init @@ -0,0 +1,8 @@ +#ifndef _Painter_icpp_init_stub +#define _Painter_icpp_init_stub +#include "Core/init" +#include "CtrlLib/init" +#define BLITZ_INDEX__ FE26D1A011428E19BAEAFE2F1E9FA2F00 +#include "PaintPainting.icpp" +#undef BLITZ_INDEX__ +#endif diff --git a/newdraw/Painter/srcimp.tpp/SubpixelFiller$en-us.tpp b/newdraw/Painter/srcimp.tpp/SubpixelFiller$en-us.tpp new file mode 100644 index 000000000..353ed6c66 --- /dev/null +++ b/newdraw/Painter/srcimp.tpp/SubpixelFiller$en-us.tpp @@ -0,0 +1,29 @@ +topic ""; +[ $$0,0#00000000000000000000000000000000:Default] +[H6;0 $$1,0#05600065144404261032431302351956:begin] +[i448;a25;kKO9;2 $$2,0#37138531426314131252341829483370:codeitem] +[l288;2 $$3,0#27521748481378242620020725143825:desc] +[0 $$4,0#96390100711032703541132217272105:end] +[{_}%EN-US +[s1;%- &] +[s2;:SubpixelFiller`:`:Write`(int`):%- [@(0.0.255) void]_[* Write]([@(0.0.255) int]_[*@3 len]) +&] +[s3; This function writes the filtered subpixel buffer to RGBA output, +performing per`-channel (subpixel) alpha blending. Note that +it is only possible to do correct per`-channel blending when +target is opaque (a `=`= 255). If it is not, normal anti`-aliasing +is used, using average.&] +[s3; Important note: due to rounding errors during filtering, sometimes +the subpixel value can be 257. This is remedied by using 257 +instead of 256 in the pixel blending command.&] +[s0; &] +[s4; &] +[s1;%- &] +[s2;:SubpixelFiller`:`:RenderN`(int`,int`,int`):%- [@(0.0.255) void]_[* RenderN]([@(0.0.255) i +nt]_[*@3 val], [@(0.0.255) int]_[*@3 h], [@(0.0.255) int]_[*@3 n])&] +[s3; This function adds 1 `- 6 val values to filtered subpixel buffer +in single pass (6 is just enough needed for Render optimizations). +Case variants are created by adding shifted Render filtering +procedures.&] +[s4; &] +[s0; ] \ No newline at end of file diff --git a/newdraw/PdfDraw/PdfDraw.cpp b/newdraw/PdfDraw/PdfDraw.cpp index eccedfa76..b50f4b12e 100644 --- a/newdraw/PdfDraw/PdfDraw.cpp +++ b/newdraw/PdfDraw/PdfDraw.cpp @@ -13,7 +13,7 @@ dword PdfDraw::GetInfo() const return DOTS; } -Size PdfDraw::GetPagePixels() const +Size PdfDraw::GetPageSize() const { return pgsz; } diff --git a/newdraw/PdfDraw/PdfDraw.h b/newdraw/PdfDraw/PdfDraw.h index ce00b919c..98876e751 100644 --- a/newdraw/PdfDraw/PdfDraw.h +++ b/newdraw/PdfDraw/PdfDraw.h @@ -228,7 +228,7 @@ public: class PdfDraw : public Draw { public: virtual dword GetInfo() const; - virtual Size GetPagePixels() const; + virtual Size GetPageSize() const; virtual void StartPage(); virtual void EndPage();