1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 //          mcseemagg@yahoo.com
13 //          http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 
16 #ifndef AGG_FONT_CACHE_MANAGER_INCLUDED
17 #define AGG_FONT_CACHE_MANAGER_INCLUDED
18 
19 #include <string.h>
20 #include "agg_array.h"
21 
22 namespace agg
23 {
24 
25     //---------------------------------------------------------glyph_data_type
26     enum glyph_data_type
27     {
28         glyph_data_invalid = 0,
29         glyph_data_mono    = 1,
30         glyph_data_gray8   = 2,
31         glyph_data_outline = 3
32     };
33 
34 
35     //-------------------------------------------------------------glyph_cache
36     struct glyph_cache
37     {
38         unsigned        glyph_index;
39         int8u*          data;
40         unsigned        data_size;
41         glyph_data_type data_type;
42         rect_i          bounds;
43         double          advance_x;
44         double          advance_y;
45     };
46 
47 
48     //--------------------------------------------------------------font_cache
49     class font_cache
50     {
51     public:
52         enum block_size_e { block_size = 16384-16 };
53 
54         //--------------------------------------------------------------------
font_cache()55         font_cache() :
56             m_allocator(block_size),
57             m_font_signature(0)
58         {}
59 
60         //--------------------------------------------------------------------
signature(const char * font_signature)61         void signature(const char* font_signature)
62         {
63             m_font_signature = (char*)m_allocator.allocate(strlen(font_signature) + 1);
64             strcpy(m_font_signature, font_signature);
65             memset(m_glyphs, 0, sizeof(m_glyphs));
66         }
67 
68         //--------------------------------------------------------------------
font_is(const char * font_signature)69         bool font_is(const char* font_signature) const
70         {
71             return strcmp(font_signature, m_font_signature) == 0;
72         }
73 
74         //--------------------------------------------------------------------
find_glyph(unsigned glyph_code)75         const glyph_cache* find_glyph(unsigned glyph_code) const
76         {
77             unsigned msb = (glyph_code >> 8) & 0xFF;
78             if(m_glyphs[msb])
79             {
80                 return m_glyphs[msb][glyph_code & 0xFF];
81             }
82             return 0;
83         }
84 
85         //--------------------------------------------------------------------
cache_glyph(unsigned glyph_code,unsigned glyph_index,unsigned data_size,glyph_data_type data_type,const rect_i & bounds,double advance_x,double advance_y)86         glyph_cache* cache_glyph(unsigned        glyph_code,
87                                  unsigned        glyph_index,
88                                  unsigned        data_size,
89                                  glyph_data_type data_type,
90                                  const rect_i&   bounds,
91                                  double          advance_x,
92                                  double          advance_y)
93         {
94             unsigned msb = (glyph_code >> 8) & 0xFF;
95             if(m_glyphs[msb] == 0)
96             {
97                 m_glyphs[msb] =
98                     (glyph_cache**)m_allocator.allocate(sizeof(glyph_cache*) * 256,
99                                                         sizeof(glyph_cache*));
100                 memset(m_glyphs[msb], 0, sizeof(glyph_cache*) * 256);
101             }
102 
103             unsigned lsb = glyph_code & 0xFF;
104             if(m_glyphs[msb][lsb]) return 0; // Already exists, do not overwrite
105 
106             glyph_cache* glyph =
107                 (glyph_cache*)m_allocator.allocate(sizeof(glyph_cache),
108                                                    sizeof(double));
109 
110             glyph->glyph_index        = glyph_index;
111             glyph->data               = m_allocator.allocate(data_size);
112             glyph->data_size          = data_size;
113             glyph->data_type          = data_type;
114             glyph->bounds             = bounds;
115             glyph->advance_x          = advance_x;
116             glyph->advance_y          = advance_y;
117             return m_glyphs[msb][lsb] = glyph;
118         }
119 
120     private:
121         block_allocator m_allocator;
122         glyph_cache**   m_glyphs[256];
123         char*           m_font_signature;
124     };
125 
126 
127 
128 
129 
130 
131 
132     //---------------------------------------------------------font_cache_pool
133     class font_cache_pool
134     {
135     public:
136         //--------------------------------------------------------------------
~font_cache_pool()137         ~font_cache_pool()
138         {
139             unsigned i;
140             for(i = 0; i < m_num_fonts; ++i)
141             {
142                 obj_allocator<font_cache>::deallocate(m_fonts[i]);
143             }
144             pod_allocator<font_cache*>::deallocate(m_fonts, m_max_fonts);
145         }
146 
147         //--------------------------------------------------------------------
148         font_cache_pool(unsigned max_fonts=32) :
m_fonts(pod_allocator<font_cache * >::allocate (max_fonts))149             m_fonts(pod_allocator<font_cache*>::allocate(max_fonts)),
150             m_max_fonts(max_fonts),
151             m_num_fonts(0),
152             m_cur_font(0)
153         {}
154 
155 
156         //--------------------------------------------------------------------
157         void font(const char* font_signature, bool reset_cache = false)
158         {
159             int idx = find_font(font_signature);
160             if(idx >= 0)
161             {
162                 if(reset_cache)
163                 {
164                     obj_allocator<font_cache>::deallocate(m_fonts[idx]);
165                     m_fonts[idx] = obj_allocator<font_cache>::allocate();
166                     m_fonts[idx]->signature(font_signature);
167                 }
168                 m_cur_font = m_fonts[idx];
169             }
170             else
171             {
172                 if(m_num_fonts >= m_max_fonts)
173                 {
174                     obj_allocator<font_cache>::deallocate(m_fonts[0]);
175                     memcpy(m_fonts,
176                            m_fonts + 1,
177                            (m_max_fonts - 1) * sizeof(font_cache*));
178                     m_num_fonts = m_max_fonts - 1;
179                 }
180                 m_fonts[m_num_fonts] = obj_allocator<font_cache>::allocate();
181                 m_fonts[m_num_fonts]->signature(font_signature);
182                 m_cur_font = m_fonts[m_num_fonts];
183                 ++m_num_fonts;
184             }
185         }
186 
187         //--------------------------------------------------------------------
font()188         const font_cache* font() const
189         {
190             return m_cur_font;
191         }
192 
193         //--------------------------------------------------------------------
find_glyph(unsigned glyph_code)194         const glyph_cache* find_glyph(unsigned glyph_code) const
195         {
196             if(m_cur_font) return m_cur_font->find_glyph(glyph_code);
197             return 0;
198         }
199 
200         //--------------------------------------------------------------------
cache_glyph(unsigned glyph_code,unsigned glyph_index,unsigned data_size,glyph_data_type data_type,const rect_i & bounds,double advance_x,double advance_y)201         glyph_cache* cache_glyph(unsigned        glyph_code,
202                                  unsigned        glyph_index,
203                                  unsigned        data_size,
204                                  glyph_data_type data_type,
205                                  const rect_i&   bounds,
206                                  double          advance_x,
207                                  double          advance_y)
208         {
209             if(m_cur_font)
210             {
211                 return m_cur_font->cache_glyph(glyph_code,
212                                                glyph_index,
213                                                data_size,
214                                                data_type,
215                                                bounds,
216                                                advance_x,
217                                                advance_y);
218             }
219             return 0;
220         }
221 
222 
223         //--------------------------------------------------------------------
find_font(const char * font_signature)224         int find_font(const char* font_signature)
225         {
226             unsigned i;
227             for(i = 0; i < m_num_fonts; i++)
228             {
229                 if(m_fonts[i]->font_is(font_signature)) return int(i);
230             }
231             return -1;
232         }
233 
234     private:
235         font_cache** m_fonts;
236         unsigned     m_max_fonts;
237         unsigned     m_num_fonts;
238         font_cache*  m_cur_font;
239     };
240 
241 
242 
243 
244     //------------------------------------------------------------------------
245     enum glyph_rendering
246     {
247         glyph_ren_native_mono,
248         glyph_ren_native_gray8,
249         glyph_ren_outline,
250         glyph_ren_agg_mono,
251         glyph_ren_agg_gray8
252     };
253 
254 
255 
256 
257     //------------------------------------------------------font_cache_manager
258     template<class FontEngine> class font_cache_manager
259     {
260     public:
261         typedef FontEngine font_engine_type;
262         typedef font_cache_manager<FontEngine> self_type;
263         typedef typename font_engine_type::path_adaptor_type   path_adaptor_type;
264         typedef typename font_engine_type::gray8_adaptor_type  gray8_adaptor_type;
265         typedef typename gray8_adaptor_type::embedded_scanline gray8_scanline_type;
266         typedef typename font_engine_type::mono_adaptor_type   mono_adaptor_type;
267         typedef typename mono_adaptor_type::embedded_scanline  mono_scanline_type;
268 
269         //--------------------------------------------------------------------
270         font_cache_manager(font_engine_type& engine, unsigned max_fonts=32) :
m_fonts(max_fonts)271             m_fonts(max_fonts),
272             m_engine(engine),
273             m_change_stamp(-1),
274             m_prev_glyph(0),
275             m_last_glyph(0)
276         {}
277 
278         //--------------------------------------------------------------------
reset_last_glyph()279         void reset_last_glyph()
280         {
281             m_prev_glyph = m_last_glyph = 0;
282         }
283 
284         //--------------------------------------------------------------------
glyph(unsigned glyph_code)285         const glyph_cache* glyph(unsigned glyph_code)
286         {
287             synchronize();
288             const glyph_cache* gl = m_fonts.find_glyph(glyph_code);
289             if(gl)
290             {
291                 m_prev_glyph = m_last_glyph;
292                 return m_last_glyph = gl;
293             }
294             else
295             {
296                 if(m_engine.prepare_glyph(glyph_code))
297                 {
298                     m_prev_glyph = m_last_glyph;
299                     m_last_glyph = m_fonts.cache_glyph(glyph_code,
300                                                        m_engine.glyph_index(),
301                                                        m_engine.data_size(),
302                                                        m_engine.data_type(),
303                                                        m_engine.bounds(),
304                                                        m_engine.advance_x(),
305                                                        m_engine.advance_y());
306                     m_engine.write_glyph_to(m_last_glyph->data);
307                     return m_last_glyph;
308                 }
309             }
310             return 0;
311         }
312 
313         //--------------------------------------------------------------------
314         void init_embedded_adaptors(const glyph_cache* gl,
315                                     double x, double y,
316                                     double scale=1.0)
317         {
318             if(gl)
319             {
320                 switch(gl->data_type)
321                 {
322                 default: return;
323                 case glyph_data_mono:
324                     m_mono_adaptor.init(gl->data, gl->data_size, x, y);
325                     break;
326 
327                 case glyph_data_gray8:
328                     m_gray8_adaptor.init(gl->data, gl->data_size, x, y);
329                     break;
330 
331                 case glyph_data_outline:
332                     m_path_adaptor.init(gl->data, gl->data_size, x, y, scale);
333                     break;
334                 }
335             }
336         }
337 
338 
339         //--------------------------------------------------------------------
path_adaptor()340         path_adaptor_type&   path_adaptor()   { return m_path_adaptor;   }
gray8_adaptor()341         gray8_adaptor_type&  gray8_adaptor()  { return m_gray8_adaptor;  }
gray8_scanline()342         gray8_scanline_type& gray8_scanline() { return m_gray8_scanline; }
mono_adaptor()343         mono_adaptor_type&   mono_adaptor()   { return m_mono_adaptor;   }
mono_scanline()344         mono_scanline_type&  mono_scanline()  { return m_mono_scanline;  }
345 
346         //--------------------------------------------------------------------
perv_glyph()347         const glyph_cache* perv_glyph() const { return m_prev_glyph; }
last_glyph()348         const glyph_cache* last_glyph() const { return m_last_glyph; }
349 
350         //--------------------------------------------------------------------
add_kerning(double * x,double * y)351         bool add_kerning(double* x, double* y)
352         {
353             if(m_prev_glyph && m_last_glyph)
354             {
355                 return m_engine.add_kerning(m_prev_glyph->glyph_index,
356                                             m_last_glyph->glyph_index,
357                                             x, y);
358             }
359             return false;
360         }
361 
362         //--------------------------------------------------------------------
precache(unsigned from,unsigned to)363         void precache(unsigned from, unsigned to)
364         {
365             for(; from <= to; ++from) glyph(from);
366         }
367 
368         //--------------------------------------------------------------------
reset_cache()369         void reset_cache()
370         {
371             m_fonts.font(m_engine.font_signature(), true);
372             m_change_stamp = m_engine.change_stamp();
373             m_prev_glyph = m_last_glyph = 0;
374         }
375 
376     private:
377         //--------------------------------------------------------------------
378         font_cache_manager(const self_type&);
379         const self_type& operator = (const self_type&);
380 
381         //--------------------------------------------------------------------
synchronize()382         void synchronize()
383         {
384             if(m_change_stamp != m_engine.change_stamp())
385             {
386                 m_fonts.font(m_engine.font_signature());
387                 m_change_stamp = m_engine.change_stamp();
388                 m_prev_glyph = m_last_glyph = 0;
389             }
390         }
391 
392         font_cache_pool     m_fonts;
393         font_engine_type&   m_engine;
394         int                 m_change_stamp;
395         double              m_dx;
396         double              m_dy;
397         const glyph_cache*  m_prev_glyph;
398         const glyph_cache*  m_last_glyph;
399         path_adaptor_type   m_path_adaptor;
400         gray8_adaptor_type  m_gray8_adaptor;
401         gray8_scanline_type m_gray8_scanline;
402         mono_adaptor_type   m_mono_adaptor;
403         mono_scanline_type  m_mono_scanline;
404     };
405 
406 }
407 
408 #endif
409 
410