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
22namespace 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        //--------------------------------------------------------------------
55        font_cache() :
56            m_allocator(block_size),
57            m_font_signature(0)
58        {}
59
60        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
69        bool font_is(const char* font_signature) const
70        {
71            return strcmp(font_signature, m_font_signature) == 0;
72        }
73
74        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
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) :
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        //--------------------------------------------------------------------
188        const font_cache* font() const
189        {
190            return m_cur_font;
191        }
192
193        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
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        //--------------------------------------------------------------------
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) :
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        //--------------------------------------------------------------------
279        const glyph_cache* glyph(unsigned glyph_code)
280        {
281            synchronize();
282            const glyph_cache* gl = m_fonts.find_glyph(glyph_code);
283            if(gl)
284            {
285                m_prev_glyph = m_last_glyph;
286                return m_last_glyph = gl;
287            }
288            else
289            {
290                if(m_engine.prepare_glyph(glyph_code))
291                {
292                    m_prev_glyph = m_last_glyph;
293                    m_last_glyph = m_fonts.cache_glyph(glyph_code,
294                                                       m_engine.glyph_index(),
295                                                       m_engine.data_size(),
296                                                       m_engine.data_type(),
297                                                       m_engine.bounds(),
298                                                       m_engine.advance_x(),
299                                                       m_engine.advance_y());
300                    m_engine.write_glyph_to(m_last_glyph->data);
301                    return m_last_glyph;
302                }
303            }
304            return 0;
305        }
306
307        //--------------------------------------------------------------------
308        void init_embedded_adaptors(const glyph_cache* gl,
309                                    double x, double y,
310                                    double scale=1.0)
311        {
312            if(gl)
313            {
314                switch(gl->data_type)
315                {
316                default: return;
317                case glyph_data_mono:
318                    m_mono_adaptor.init(gl->data, gl->data_size, x, y);
319                    break;
320
321                case glyph_data_gray8:
322                    m_gray8_adaptor.init(gl->data, gl->data_size, x, y);
323                    break;
324
325                case glyph_data_outline:
326                    m_path_adaptor.init(gl->data, gl->data_size, x, y, scale);
327                    break;
328                }
329            }
330        }
331
332
333        //--------------------------------------------------------------------
334        path_adaptor_type&   path_adaptor()   { return m_path_adaptor;   }
335        gray8_adaptor_type&  gray8_adaptor()  { return m_gray8_adaptor;  }
336        gray8_scanline_type& gray8_scanline() { return m_gray8_scanline; }
337        mono_adaptor_type&   mono_adaptor()   { return m_mono_adaptor;   }
338        mono_scanline_type&  mono_scanline()  { return m_mono_scanline;  }
339
340        //--------------------------------------------------------------------
341        const glyph_cache* perv_glyph() const { return m_prev_glyph; }
342        const glyph_cache* last_glyph() const { return m_last_glyph; }
343
344        //--------------------------------------------------------------------
345        bool add_kerning(double* x, double* y)
346        {
347            if(m_prev_glyph && m_last_glyph)
348            {
349                return m_engine.add_kerning(m_prev_glyph->glyph_index,
350                                            m_last_glyph->glyph_index,
351                                            x, y);
352            }
353            return false;
354        }
355
356        //--------------------------------------------------------------------
357        void precache(unsigned from, unsigned to)
358        {
359            for(; from <= to; ++from) glyph(from);
360        }
361
362        //--------------------------------------------------------------------
363        void reset_cache()
364        {
365            m_fonts.font(m_engine.font_signature(), true);
366            m_change_stamp = m_engine.change_stamp();
367            m_prev_glyph = m_last_glyph = 0;
368        }
369
370        //--------------------------------------------------------------------
371        void reset()
372        {
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        //--------------------------------------------------------------------
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