Painter: OnPath, text optimizations

git-svn-id: svn://ultimatepp.org/upp/trunk@916 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2009-03-06 16:32:40 +00:00
parent 35058c97fa
commit 81e1a7d802
23 changed files with 598 additions and 171 deletions

View file

@ -87,6 +87,8 @@ inline void LockLog() {}
inline void UnlockLog() {}
#endif
#define STATIC_ASSERT(x)
#ifdef _DEBUG
#define _DBG_

View file

@ -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<byte> type;
Vector<byte> data;
};
struct PathLine : Moveable<PathLine> {
Pointf p;
double len;
};
struct Attr : Moveable<Attr> {
Xform2D mtx;
double tolerance;
bool evenodd;
byte join;
byte cap;
@ -296,9 +308,11 @@ public:
WithDeepCopy< Vector<RGBA> > stop_color;
double dash_start;
double opacity;
int cliplevel;
bool hasclip;
bool mask;
bool onpath;
};
ImageBuffer& ib;
@ -311,6 +325,8 @@ public:
Array<Attr> attrstack;
Vector< Buffer<ClipLine> > clip;
Array< ImageBuffer > mask;
Vector< Vector<PathLine> > onpathstack;
Vector<double> 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<RGBA> span;
Vector<PathLine> onpath;
double pathlen;
struct OnPathTarget;
friend struct OnPathTarget;
void *PathAddRaw(int type, int size);
template <class T> 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<ClipLine> 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);

View file

@ -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;

View file

@ -93,7 +93,7 @@ struct sMakeCharOutline : LRUCache<String, FontChar>::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

View file

@ -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

View file

@ -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());
}

33
uppsrc/Painter/OnPath.cpp Normal file
View file

@ -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

View file

@ -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;
}
}
}

View file

@ -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<double>& 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

View file

@ -3,7 +3,7 @@
#include <Draw/Draw.h>
#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<double>& 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

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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<CharData>(CHAR);
m.p = EndPoint(p, false);
m.ch = ch;
m.fnt = fnt;
ischar = true;
EvenOdd();
#endif
}
END_UPP_NAMESPACE

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -8,20 +8,53 @@ void BufferPainter::ClearOp(const RGBA& color)
UPP::Fill(~ib, color, ib.GetLength());
}
struct BufferPainter::OnPathTarget : LinearPathConsumer {
Vector<BufferPainter::PathLine> 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<ClipLine> BufferPainter::RenderPath(double width, SpanSource *ss, const RGBA& color)
{
Buffer<ClipLine> 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<ClipLine> 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<ClipLine> 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<ClipLine> 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<ClipLine> 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<ClipLine> 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<ClipLine> 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<ClipLine> newclip = RenderPath(-2, NULL, RGBAZero());
Buffer<ClipLine> newclip = RenderPath(CLIP, NULL, RGBAZero());
if(attr.hasclip)
clip.Top() = newclip;
else {

View file

@ -0,0 +1,127 @@
#include "Painter.h"
NAMESPACE_UPP
struct GlyphPainter : NilPainter, LinearPathConsumer {
Vector<float> 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<Value, GlyphKey>::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<Value, GlyphKey> 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<float>& g = chp.glyph;
#else
const Vector<float>& g = ValueTo< Vector<float> >(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

View file

@ -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

View file

@ -14,6 +14,8 @@ bool Sqlite3PerformScript(const String& text,
Gate2<int, int> 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<Sqlite3Connection> 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

View file

@ -7,7 +7,7 @@ NAMESPACE_UPP
#define LLOG(x) // LOG(x)
class Sqlite3Connection : public SqlConnection {
class Sqlite3Connection : public SqlConnection, public Link<Sqlite3Connection> {
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)