diff --git a/uppsrc/Core/Diag.h b/uppsrc/Core/Diag.h index bd038cee6..02ead7d2e 100644 --- a/uppsrc/Core/Diag.h +++ b/uppsrc/Core/Diag.h @@ -87,6 +87,8 @@ inline void LockLog() {} inline void UnlockLog() {} #endif +#define STATIC_ASSERT(x) + #ifdef _DEBUG #define _DBG_ diff --git a/uppsrc/Painter/BufferPainter.h b/uppsrc/Painter/BufferPainter.h index 9e5946c65..451c4145c 100644 --- a/uppsrc/Painter/BufferPainter.h +++ b/uppsrc/Painter/BufferPainter.h @@ -116,11 +116,6 @@ inline void AlphaBlendCover8(RGBA& t, const RGBA& c, int cover) t.a = a + (alpha * t.a >> 8); } -inline int Q8(double x) -{ - return int(x * 256 + 0.5); -} - class Rasterizer : public LinearPathConsumer { public: virtual void Move(const Pointf& p); @@ -141,6 +136,7 @@ private: int min_y; int max_y; Size sz; + double mx; void Init(); Cell *AddCells(int y, int n); @@ -151,6 +147,9 @@ private: 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; @@ -169,7 +168,7 @@ public: void Reset(); - Rasterizer(int cx, int cy); + Rasterizer(int cx, int cy, bool subpixel); }; struct SpanSource { @@ -205,6 +204,8 @@ class LinearInterpolator { Xform2D xform; Dda2 ddax, dday; + + static int Q8(double x) { return int(256 * x + 0.5); } public: void Set(const Xform2D& m) { xform = m; } @@ -229,6 +230,8 @@ protected: 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, @@ -266,10 +269,11 @@ protected: virtual void EndOp(); virtual void BeginMaskOp(); + virtual void BeginOnPathOp(double q, bool abs); -public: +private: enum { - MOVE, LINE, QUADRATIC, CUBIC, DIV + MOVE, LINE, QUADRATIC, CUBIC, DIV, CHAR }; struct LinearData { Pointf p; @@ -280,13 +284,21 @@ public: 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; - double tolerance; bool evenodd; byte join; byte cap; @@ -296,9 +308,11 @@ public: WithDeepCopy< Vector > stop_color; double dash_start; double opacity; + int cliplevel; bool hasclip; bool mask; + bool onpath; }; ImageBuffer& ib; @@ -311,6 +325,8 @@ public: Array attrstack; Vector< Buffer > clip; Array< ImageBuffer > mask; + Vector< Vector > onpathstack; + Vector pathlenstack; Image gradient; RGBA gradient1, gradient2; @@ -319,9 +335,16 @@ public: 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)); } @@ -330,6 +353,7 @@ public: 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); @@ -339,6 +363,8 @@ public: 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 = 0); diff --git a/uppsrc/Painter/Context.cpp b/uppsrc/Painter/Context.cpp index 828211e50..007487af5 100644 --- a/uppsrc/Painter/Context.cpp +++ b/uppsrc/Painter/Context.cpp @@ -6,6 +6,7 @@ void BufferPainter::BeginOp() { attrstack.Add(attr); attr.hasclip = false; + attr.onpath = false; } void BufferPainter::EndOp() @@ -19,13 +20,18 @@ void BufferPainter::EndOp() 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; - pathattr.tolerance = attr.tolerance = 0.3 / attr.mtx.GetScale(); } void BufferPainter::OpacityOp(double o) @@ -101,7 +107,7 @@ void BufferPainter::ClearStopsOp() BufferPainter::BufferPainter(ImageBuffer& ib, int mode) : ib(ib), mode(mode), - rasterizer(mode == MODE_SUBPIXEL ? 3 * ib.GetWidth() : ib.GetWidth(), ib.GetHeight()) + rasterizer(ib.GetWidth(), ib.GetHeight(), mode == MODE_SUBPIXEL) { ClearPath(); @@ -110,8 +116,6 @@ BufferPainter::BufferPainter(ImageBuffer& ib, int mode) render_cx *= 3; subpixel.Alloc(render_cx + 30); } - attr.mtx = Xform2D::Scale(subpixel ? 3 : 1, 1); - attr.tolerance = 0.3; attr.cap = LINECAP_BUTT; attr.join = LINEJOIN_MITER; attr.miter_limit = 4; diff --git a/uppsrc/Painter/FontWin32.cpp b/uppsrc/Painter/FontWin32.cpp index cfa6ff1fb..b9b24c0d5 100644 --- a/uppsrc/Painter/FontWin32.cpp +++ b/uppsrc/Painter/FontWin32.cpp @@ -93,7 +93,7 @@ struct sMakeCharOutline : LRUCache::Maker { } }; -void Painter::CharacterOp(const Pointf& p, int ch, Font fnt) +void PaintCharacter(Painter& sw, const Pointf& p, int ch, Font fnt) { PAINTER_TIMING("CharacterOp"); String s; @@ -105,8 +105,8 @@ void Painter::CharacterOp(const Pointf& p, int ch, Font fnt) h.fc.chr = ch; s = cache.Get(h); } - RenderCharPath(s, s.GetLength(), *this, p.x, p.y + fnt.Info().GetAscent()); - EvenOdd(true); + RenderCharPath(s, s.GetLength(), sw, p.x, p.y + fnt.Info().GetAscent()); + sw.EvenOdd(true); } #endif diff --git a/uppsrc/Painter/FontX11.cpp b/uppsrc/Painter/FontX11.cpp index f6587fc64..25a0a400a 100644 --- a/uppsrc/Painter/FontX11.cpp +++ b/uppsrc/Painter/FontX11.cpp @@ -136,15 +136,16 @@ bool RenderOutline(const FT_Outline& outline, Painter& path, double xx, double y return true; } -void Painter::CharacterOp(const Pointf& p, int ch, Font fnt) +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, *this, p.x, p.y + fnt.Info().GetAscent()); + RenderOutline(face->glyph->outline, sw, p.x, p.y + fnt.Info().GetAscent()); XftUnlockFace(fi.GetXftFont()); + sw.EvenOdd(true); } #endif diff --git a/uppsrc/Painter/Image.cpp b/uppsrc/Painter/Image.cpp index 07eb22072..2f6b6fe55 100644 --- a/uppsrc/Painter/Image.cpp +++ b/uppsrc/Painter/Image.cpp @@ -221,8 +221,6 @@ void BufferPainter::RenderImage(double width, const Image& image, const Xform2D& ss.vstyle = byte(flags & 12); ss.fast = flags & FILL_FAST; Xform2D m = transsrc * pathattr.mtx; - if(subpixel) - m = m * Xform2D::Scale(1 / 3.0, 1); ss.Set(m, image); RenderPath(width, &ss, RGBAZero()); } diff --git a/uppsrc/Painter/OnPath.cpp b/uppsrc/Painter/OnPath.cpp new file mode 100644 index 000000000..16bfa63db --- /dev/null +++ b/uppsrc/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/uppsrc/Painter/PaintPainting.icpp b/uppsrc/Painter/PaintPainting.icpp index 0fd015d46..b8555f046 100644 --- a/uppsrc/Painter/PaintPainting.icpp +++ b/uppsrc/Painter/PaintPainting.icpp @@ -231,6 +231,10 @@ void Painter::Paint(const Painting& pic) case PAINTING_BEGINMASK: BeginMaskOp(); break; + case PAINTING_BEGINONPATH: + sGet(r, ss); + BeginOnPathOp(r, ss.Get()); + break; } } } diff --git a/uppsrc/Painter/Painter.cpp b/uppsrc/Painter/Painter.cpp index 09b2f8041..e77afe605 100644 --- a/uppsrc/Painter/Painter.cpp +++ b/uppsrc/Painter/Painter.cpp @@ -338,6 +338,11 @@ Painter& Painter::Translate(double x, double 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); @@ -475,4 +480,40 @@ 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) {} + END_UPP_NAMESPACE diff --git a/uppsrc/Painter/Painter.h b/uppsrc/Painter/Painter.h index 7f3b67623..0b4743b6f 100644 --- a/uppsrc/Painter/Painter.h +++ b/uppsrc/Painter/Painter.h @@ -3,7 +3,7 @@ #include -#define PAINTER_TIMING(x) // RTIMING(x) +#define PAINTER_TIMING(x) RTIMING(x) NAMESPACE_UPP @@ -120,7 +120,7 @@ protected: virtual void ClipOp() = 0; - virtual void CharacterOp(const Pointf& p, int ch, Font fnt); + 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); @@ -140,6 +140,7 @@ protected: virtual void EndOp() = 0; virtual void BeginMaskOp() = 0; + virtual void BeginOnPathOp(double q, bool absolute) = 0; protected: static bool ReadBool(CParser& p); @@ -279,6 +280,7 @@ public: void End(); void BeginMask(); + void BeginOnPath(double q, bool absolute = false); Painter& ColorStop(double pos, const RGBA& color); Painter& ClearStops(); @@ -292,6 +294,7 @@ public: 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); @@ -303,10 +306,72 @@ public: 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 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/uppsrc/Painter/Painter.hpp b/uppsrc/Painter/Painter.hpp index c4007946a..1bc9f1141 100644 --- a/uppsrc/Painter/Painter.hpp +++ b/uppsrc/Painter/Painter.hpp @@ -213,6 +213,11 @@ 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); diff --git a/uppsrc/Painter/Painter.upp b/uppsrc/Painter/Painter.upp index 39f7051b1..aad0c8df7 100644 --- a/uppsrc/Painter/Painter.upp +++ b/uppsrc/Painter/Painter.upp @@ -30,11 +30,13 @@ file 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/uppsrc/Painter/Painting.cpp b/uppsrc/Painter/Painting.cpp index 8a4043fee..d4f02d176 100644 --- a/uppsrc/Painter/Painting.cpp +++ b/uppsrc/Painter/Painting.cpp @@ -256,6 +256,13 @@ 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; diff --git a/uppsrc/Painter/Painting.h b/uppsrc/Painter/Painting.h index 8cd7b3326..1ee9657e0 100644 --- a/uppsrc/Painter/Painting.h +++ b/uppsrc/Painter/Painting.h @@ -48,6 +48,7 @@ enum { PAINTING_BEGIN, PAINTING_END, PAINTING_BEGINMASK, + PAINTING_BEGINONPATH, }; class PaintingPainter : public Painter { @@ -119,6 +120,7 @@ protected: virtual void EndOp(); virtual void BeginMaskOp(); + virtual void BeginOnPathOp(double q, bool abs); public: Painting GetResult(); diff --git a/uppsrc/Painter/Path.cpp b/uppsrc/Painter/Path.cpp index ce56f9d4d..f36b4581f 100644 --- a/uppsrc/Painter/Path.cpp +++ b/uppsrc/Painter/Path.cpp @@ -8,6 +8,7 @@ void BufferPainter::ClearPath() path.data.Clear(); current = move = Null; ccontrol = qcontrol = Pointf(0, 0); + ischar = false; } Pointf BufferPainter::PathPoint(const Pointf& p, bool rel) @@ -116,4 +117,20 @@ void BufferPainter::DivOp() 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/uppsrc/Painter/RadialGradient.cpp b/uppsrc/Painter/RadialGradient.cpp index d0eb25a99..34ba32a67 100644 --- a/uppsrc/Painter/RadialGradient.cpp +++ b/uppsrc/Painter/RadialGradient.cpp @@ -10,8 +10,6 @@ struct PainterRadialSpan : SpanSource { const RGBA *gradient; double C; - void prepare() {} - void Set(double _x, double _y, double _r, double _fx, double _fy) { cx = _x; @@ -63,8 +61,6 @@ void BufferPainter::RenderRadial(double width, const Pointf& f, const RGBA& colo { PainterRadialSpan sg; Xform2D m = pathattr.mtx; - if(subpixel) - m = m * Xform2D::Scale(1.0 / 3, 1); sg.interpolator.Set(Inverse(m)); sg.style = style; sg.Set(c.x, c.y, r, f.x, f.y); diff --git a/uppsrc/Painter/Rasterizer.cpp b/uppsrc/Painter/Rasterizer.cpp index 0f44af929..3ceb4a5a2 100644 --- a/uppsrc/Painter/Rasterizer.cpp +++ b/uppsrc/Painter/Rasterizer.cpp @@ -47,9 +47,10 @@ void Rasterizer::SetClip(const Rectf& rect) cliprect = rect & Sizef(sz); } -Rasterizer::Rasterizer(int cx, int cy) +Rasterizer::Rasterizer(int cx, int cy, bool subpixel) { - sz.cx = cx; + mx = subpixel ? 3 * 256 : 256; + sz.cx = subpixel ? 3 * cx : cx; sz.cy = cy; cell.Alloc(sz.cy + 1); cliprect = Sizef(sz); diff --git a/uppsrc/Painter/RasterizerClip.cpp b/uppsrc/Painter/RasterizerClip.cpp index 90a4115d4..29790618e 100644 --- a/uppsrc/Painter/RasterizerClip.cpp +++ b/uppsrc/Painter/RasterizerClip.cpp @@ -1,103 +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(Q8(x1), Q8(y1), Q8(x2), Q8(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 +#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/uppsrc/Painter/Render.cpp b/uppsrc/Painter/Render.cpp index a451d6aa3..936b53c3b 100644 --- a/uppsrc/Painter/Render.cpp +++ b/uppsrc/Painter/Render.cpp @@ -8,20 +8,53 @@ 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); - trans.target = &rasterizer; - LinearPathConsumer *g; 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, pathattr.tolerance, pathattr.cap, pathattr.join); - stroker.target = &trans; + 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; @@ -31,10 +64,8 @@ Buffer BufferPainter::RenderPath(double width, SpanSource *ss, const R g = &stroker; evenodd = false; } - else { + else Close(); - g = &trans; - } byte *data = path.data; int opacity = int(256 * pathattr.opacity); Pointf pos = Pointf(0, 0); @@ -46,7 +77,7 @@ Buffer BufferPainter::RenderPath(double width, SpanSource *ss, const R ClipFiller clip_filler(render_cx); NoAAFillerFilter noaa_filler; MaskFillerFilter mf; - bool doclip = width == -2; + bool doclip = width == CLIP; subpixel_filler.sbuffer = subpixel; if(doclip) { rg = &clip_filler; @@ -55,7 +86,7 @@ Buffer BufferPainter::RenderPath(double width, SpanSource *ss, const R else if(ss) { if(!span) - span.Alloc(ib.GetWidth() + 3); + span.Alloc((subpixel ? 3 : 1) * ib.GetWidth() + 3); if(subpixel) { subpixel_filler.ss = ss; subpixel_filler.buffer = span; @@ -87,27 +118,29 @@ Buffer BufferPainter::RenderPath(double width, SpanSource *ss, const R for(;;) { if(i >= path.type.GetCount() || path.type[i] == DIV) { g->End(); - 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(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:; } - if(doclip) - clip_filler.Clear(); - rasterizer.Render(y, *rf, evenodd); - if(doclip) - clip_filler.Finish(newclip[y]); - empty:; + rasterizer.Reset(); } - rasterizer.Reset(); if(i >= path.type.GetCount()) break; } @@ -116,29 +149,48 @@ Buffer BufferPainter::RenderPath(double width, SpanSource *ss, const R case MOVE: { const LinearData *d = (LinearData *)data; data += sizeof(LinearData); - g->Move(pos = d->p); + 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 = d->p); + g->Line(pos = regular ? pathattr.mtx.Transform(d->p) : d->p); break; } case QUADRATIC: { const QuadraticData *d = (QuadraticData *)data; data += sizeof(QuadraticData); - ApproximateQuadratic(*g, pos, d->p1, d->p, pathattr.tolerance); - pos = d->p; + 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); - ApproximateCubic(*g, pos, d->p1, d->p2, d->p, pathattr.tolerance); - pos = d->p; + 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; @@ -146,12 +198,16 @@ Buffer BufferPainter::RenderPath(double width, SpanSource *ss, const R i++; } current = Null; + if(width == ONPATH) { + onpath = onpathtarget.path; + pathlen = onpathtarget.len; + } return newclip; } void BufferPainter::FillOp(const RGBA& color) { - RenderPath(-1, NULL, color); + RenderPath(FILL, NULL, color); } void BufferPainter::StrokeOp(double width, const RGBA& color) @@ -161,7 +217,7 @@ void BufferPainter::StrokeOp(double width, const RGBA& color) void BufferPainter::ClipOp() { - Buffer newclip = RenderPath(-2, NULL, RGBAZero()); + Buffer newclip = RenderPath(CLIP, NULL, RGBAZero()); if(attr.hasclip) clip.Top() = newclip; else { diff --git a/uppsrc/Painter/RenderChar.cpp b/uppsrc/Painter/RenderChar.cpp new file mode 100644 index 000000000..9f39e320a --- /dev/null +++ b/uppsrc/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/uppsrc/Painter/init b/uppsrc/Painter/init index 356309386..0ac6454fa 100644 --- a/uppsrc/Painter/init +++ b/uppsrc/Painter/init @@ -2,7 +2,7 @@ #define _Painter_icpp_init_stub #include "Core/init" #include "CtrlLib/init" -#define BLITZ_INDEX__ F18922416C44F220B741A74F8D9F1A79C +#define BLITZ_INDEX__ F1639763DEC2ACC960A83B650F7C86CE2 #include "PaintPainting.icpp" #undef BLITZ_INDEX__ #endif diff --git a/uppsrc/plugin/sqlite3/Sqlite3.h b/uppsrc/plugin/sqlite3/Sqlite3.h index 31b35ac7e..aad9f0dde 100644 --- a/uppsrc/plugin/sqlite3/Sqlite3.h +++ b/uppsrc/plugin/sqlite3/Sqlite3.h @@ -14,6 +14,8 @@ bool Sqlite3PerformScript(const String& text, Gate2 progress_canceled = false ); +class Sqlite3Connection; + class Sqlite3Session : public SqlSession { public: virtual bool IsOpen() const { return NULL != db; } @@ -32,9 +34,14 @@ protected: virtual SqlConnection *CreateConnection(); private: + friend class Sqlite3Connection; + sqlite3 *db; String current_filename; String current_dbname; + Link clink; + + void Reset(); public: bool Open(const char *filename); @@ -46,8 +53,8 @@ public: virtual void Commit(); virtual void Rollback(); - Sqlite3Session() { db = NULL; Dialect(SQLITE3); } - ~Sqlite3Session() { Close(); } + Sqlite3Session(); + ~Sqlite3Session(); }; END_UPP_NAMESPACE diff --git a/uppsrc/plugin/sqlite3/Sqlite3upp.cpp b/uppsrc/plugin/sqlite3/Sqlite3upp.cpp index 463984561..aaae6498d 100644 --- a/uppsrc/plugin/sqlite3/Sqlite3upp.cpp +++ b/uppsrc/plugin/sqlite3/Sqlite3upp.cpp @@ -7,7 +7,7 @@ NAMESPACE_UPP #define LLOG(x) // LOG(x) -class Sqlite3Connection : public SqlConnection { +class Sqlite3Connection : public SqlConnection, public Link { protected: virtual void SetParam(int i, const Value& r); virtual bool Execute(); @@ -34,6 +34,7 @@ private: friend class Sqlite3Session; void BindParam(int i, const Value& r); + void Reset(); public: Sqlite3Connection(Sqlite3Session& the_session, sqlite3 *the_db); @@ -42,11 +43,14 @@ public: Sqlite3Connection::Sqlite3Connection(Sqlite3Session& the_session, sqlite3 *the_db) : session(the_session), db(the_db), current_stmt(NULL), got_first_row(false), got_row_data(false) -{} +{ + LinkBefore(&session.clink); +} Sqlite3Connection::~Sqlite3Connection() { Cancel(); + Unlink(); } void Sqlite3Connection::Cancel() @@ -58,9 +62,16 @@ void Sqlite3Connection::Cancel() session.SetError(sqlite3_errmsg(db), "Finalizing statement: "+ current_stmt_string); current_stmt = NULL; current_stmt_string.Clear(); + parse = true; } } +void Sqlite3Connection::Reset() +{ + if(current_stmt && sqlite3_reset(current_stmt) != SQLITE_OK) + session.SetError(sqlite3_errmsg(db), "Resetting statement: " + current_stmt_string); +} + void Sqlite3Connection::SetParam(int i, const Value& r) { LLOG(Format("SetParam(%d,%s)",i,r.ToString())); @@ -299,20 +310,42 @@ void Sqlite3Session::Close() { SqlConnection *Sqlite3Session::CreateConnection() { return new Sqlite3Connection(*this, db); } + +void Sqlite3Session::Reset() +{ + for(Sqlite3Connection *s = clink.GetNext(); s != &clink; s = s->GetNext()) + s->Reset(); +} + +Sqlite3Session::Sqlite3Session() +{ + db = NULL; + Dialect(SQLITE3); +} + +Sqlite3Session::~Sqlite3Session() +{ + Close(); +} + void Sqlite3Session::Begin() { static const char begin[] = "BEGIN;"; if(trace) *trace << begin << "\n"; + Reset(); if(SQLITE_OK != sqlite3_exec(db,begin,NULL,NULL,NULL)) SetError(sqlite3_errmsg(db), begin); } + void Sqlite3Session::Commit() { static const char commit[] = "COMMIT;"; if(trace) *trace << commit << "\n"; + Reset(); if(SQLITE_OK != sqlite3_exec(db,commit,NULL,NULL,NULL)) SetError(sqlite3_errmsg(db), commit); } + void Sqlite3Session::Rollback() { static const char rollback[] = "ROLLBACK;"; if(trace)