1 #include "Painter.h"
2
3 namespace Upp {
4
5 struct GlyphPainter : NilPainter, LinearPathConsumer {
6 Vector<float> glyph;
7 double tolerance;
8 Pointf pos, move;
9
10 virtual void LineOp(const Pointf& p, bool);
11 virtual void MoveOp(const Pointf& p, bool);
12 virtual void QuadraticOp(const Pointf& p1, const Pointf& p, bool);
13 virtual void CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool);
14 virtual void CloseOp();
15
16 virtual void Line(const Pointf& p);
17 virtual void Move(const Pointf& p);
18 };
19
Move(const Pointf & p)20 void GlyphPainter::Move(const Pointf& p)
21 {
22 glyph.Add((float)1e31);
23 Line(p);
24 move = pos;
25 }
26
Line(const Pointf & p)27 void GlyphPainter::Line(const Pointf& p)
28 {
29 glyph.Add((float)p.x);
30 glyph.Add((float)p.y);
31 pos = p;
32 }
33
MoveOp(const Pointf & p,bool)34 void GlyphPainter::MoveOp(const Pointf& p, bool)
35 {
36 Move(p);
37 }
38
LineOp(const Pointf & p,bool)39 void GlyphPainter::LineOp(const Pointf& p, bool)
40 {
41 Line(p);
42 }
43
QuadraticOp(const Pointf & p1,const Pointf & p,bool)44 void GlyphPainter::QuadraticOp(const Pointf& p1, const Pointf& p, bool)
45 {
46 ApproximateQuadratic(*this, pos, p1, p, tolerance);
47 pos = p;
48 }
49
CubicOp(const Pointf & p1,const Pointf & p2,const Pointf & p,bool)50 void GlyphPainter::CubicOp(const Pointf& p1, const Pointf& p2, const Pointf& p, bool)
51 {
52 ApproximateCubic(*this, pos, p1, p2, p, tolerance);
53 pos = p;
54 }
55
CloseOp()56 void GlyphPainter::CloseOp()
57 {
58 if(move != pos && !IsNull(move))
59 Line(move);
60 }
61
62 struct GlyphKey {
63 Font fnt;
64 int chr;
65 double tolerance;
66
operator ==Upp::GlyphKey67 bool operator==(const GlyphKey& b) const {
68 return fnt == b.fnt && chr == b.chr && tolerance == b.tolerance;
69 }
GetHashValueUpp::GlyphKey70 hash_t GetHashValue() const {
71 return CombineHash(fnt, chr, tolerance);
72 }
73 };
74
75 struct sMakeGlyph : LRUCache<Value, GlyphKey>::Maker {
76 GlyphKey gk;
77
KeyUpp::sMakeGlyph78 GlyphKey Key() const { return gk; }
MakeUpp::sMakeGlyph79 int Make(Value& v) const {
80 GlyphPainter gp;
81 gp.move = gp.pos = Null;
82 gp.tolerance = gk.tolerance;
83 PaintCharacter(gp, Pointf(0, 0), gk.chr, gk.fnt);
84 int sz = gp.glyph.GetCount() * 4;
85 v = RawPickToValue(pick(gp.glyph));
86 return sz;
87 }
88 };
89
ApproximateChar(LinearPathConsumer & t,Pointf at,int ch,Font fnt,double tolerance)90 void ApproximateChar(LinearPathConsumer& t, Pointf at, int ch, Font fnt, double tolerance)
91 {
92 PAINTER_TIMING("ApproximateChar");
93 Value v;
94 INTERLOCKED {
95 PAINTER_TIMING("ApproximateChar::Fetch");
96 static LRUCache<Value, GlyphKey> cache;
97 cache.Shrink(500000);
98 sMakeGlyph h;
99 h.gk.fnt = fnt;
100 h.gk.chr = ch;
101 h.gk.tolerance = tolerance;
102 v = cache.Get(h);
103 #ifdef _DEBUG0
104 DLOG("==== ApproximateChar " << ch << " " << (char)ch << " " << fnt << ", tolerance: " << tolerance);
105 DDUMP(ValueTo< Vector<float> >(v));
106 GlyphPainter chp;
107 chp.move = chp.pos = Null;
108 chp.tolerance = tolerance;
109 PaintCharacter(chp, Pointf(0, 0), ch, fnt);
110 DDUMP(chp.glyph);
111 ASSERT(ValueTo< Vector<float> >(v) == chp.glyph);
112 #endif
113 }
114 const Vector<float>& g = ValueTo< Vector<float> >(v);
115 int i = 0;
116 while(i < g.GetCount()) {
117 Pointf p;
118 p.x = g[i++];
119 if(p.x > 1e30) {
120 p.x = g[i++];
121 p.y = g[i++];
122 t.Move(p + at);
123 }
124 else {
125 PAINTER_TIMING("ApproximateChar::Line");
126 p.y = g[i++];
127 t.Line(p + at);
128 }
129 }
130 }
131
132 }
133