xref: /haiku/headers/libs/agg/agg_font_cache_manager.h (revision 24159a0c7d6d6dcba9f2a0c1a7c08d2c8167f21b)
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.2
3 // Copyright (C) 2002-2004 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            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 = 16384-16 };
53 
54         //--------------------------------------------------------------------
55         font_cache(const char* font_signature) :
56             m_allocator(block_size),
57             m_font_signature(0)
58         {
59             m_font_signature = (char*)m_allocator.allocate(strlen(font_signature) + 1);
60             strcpy(m_font_signature, font_signature);
61             memset(m_glyphs, 0, sizeof(m_glyphs));
62         }
63 
64         //--------------------------------------------------------------------
65         bool font_is(const char* font_signature) const
66         {
67             return strcmp(font_signature, m_font_signature) == 0;
68         }
69 
70         //--------------------------------------------------------------------
71         const glyph_cache* find_glyph(unsigned glyph_code) const
72         {
73             unsigned msb = (glyph_code >> 8) & 0xFF;
74             if(m_glyphs[msb])
75             {
76                 return m_glyphs[msb][glyph_code & 0xFF];
77             }
78             return 0;
79         }
80 
81         //--------------------------------------------------------------------
82         glyph_cache* cache_glyph(unsigned        glyph_code,
83                                  unsigned        glyph_index,
84                                  unsigned        data_size,
85                                  glyph_data_type data_type,
86                                  const rect&     bounds,
87                                  double          advance_x,
88                                  double          advance_y)
89         {
90             unsigned msb = (glyph_code >> 8) & 0xFF;
91             if(m_glyphs[msb] == 0)
92             {
93                 m_glyphs[msb] =
94                     (glyph_cache**)m_allocator.allocate(sizeof(glyph_cache*) * 256,
95                                                         sizeof(glyph_cache*));
96                 memset(m_glyphs[msb], 0, sizeof(glyph_cache*) * 256);
97             }
98 
99             unsigned lsb = glyph_code & 0xFF;
100             if(m_glyphs[msb][lsb]) return 0; // Already exists, do not overwrite
101 
102             glyph_cache* glyph =
103                 (glyph_cache*)m_allocator.allocate(sizeof(glyph_cache),
104                                                    sizeof(double));
105 
106             glyph->glyph_index = glyph_index;
107             glyph->data        = m_allocator.allocate(data_size);
108             glyph->data_size   = data_size;
109             glyph->data_type   = data_type;
110             glyph->bounds      = bounds;
111             glyph->advance_x   = advance_x;
112             glyph->advance_y   = advance_y;
113             return m_glyphs[msb][lsb] = glyph;
114         }
115 
116     private:
117         pod_allocator   m_allocator;
118         glyph_cache**   m_glyphs[256];
119         char*           m_font_signature;
120     };
121 
122 
123 
124 
125 
126 
127 
128     //---------------------------------------------------------font_cache_pool
129     class font_cache_pool
130     {
131     public:
132         //--------------------------------------------------------------------
133         ~font_cache_pool()
134         {
135             unsigned i;
136             for(i = 0; i < m_num_fonts; ++i)
137             {
138                 delete m_fonts[i];
139             }
140             delete [] m_fonts;
141         }
142 
143         //--------------------------------------------------------------------
144         font_cache_pool(unsigned max_fonts=32) :
145             m_fonts(new font_cache* [max_fonts]),
146             m_max_fonts(max_fonts),
147             m_num_fonts(0),
148             m_cur_font(0)
149         {}
150 
151 
152         //--------------------------------------------------------------------
153         void font(const char* font_signature, bool reset_cache = false)
154         {
155             int idx = find_font(font_signature);
156             if(idx >= 0)
157             {
158                 if(reset_cache)
159                 {
160                     delete m_fonts[idx];
161                     m_fonts[idx] = new font_cache(font_signature);
162                 }
163                 m_cur_font = m_fonts[idx];
164             }
165             else
166             {
167                 if(m_num_fonts >= m_max_fonts)
168                 {
169                     delete m_fonts[0];
170                     memcpy(m_fonts,
171                            m_fonts + 1,
172                            (m_max_fonts - 1) * sizeof(font_cache*));
173                     m_num_fonts = m_max_fonts - 1;
174                 }
175                 m_fonts[m_num_fonts] = new font_cache(font_signature);
176                 m_cur_font = m_fonts[m_num_fonts];
177                 ++m_num_fonts;
178             }
179         }
180 
181         //--------------------------------------------------------------------
182         const font_cache* font() const
183         {
184             return m_cur_font;
185         }
186 
187         //--------------------------------------------------------------------
188         const glyph_cache* find_glyph(unsigned glyph_code) const
189         {
190             if(m_cur_font) return m_cur_font->find_glyph(glyph_code);
191             return 0;
192         }
193 
194         //--------------------------------------------------------------------
195         glyph_cache* cache_glyph(unsigned        glyph_code,
196                                  unsigned        glyph_index,
197                                  unsigned        data_size,
198                                  glyph_data_type data_type,
199                                  const rect&     bounds,
200                                  double          advance_x,
201                                  double          advance_y)
202         {
203             if(m_cur_font)
204             {
205                 return m_cur_font->cache_glyph(glyph_code,
206                                                glyph_index,
207                                                data_size,
208                                                data_type,
209                                                bounds,
210                                                advance_x,
211                                                advance_y);
212             }
213             return 0;
214         }
215 
216 
217         //--------------------------------------------------------------------
218         int find_font(const char* font_signature)
219         {
220             unsigned i;
221             for(i = 0; i < m_num_fonts; i++)
222             {
223                 if(m_fonts[i]->font_is(font_signature)) return int(i);
224             }
225             return -1;
226         }
227 
228     private:
229         font_cache** m_fonts;
230         unsigned     m_max_fonts;
231         unsigned     m_num_fonts;
232         font_cache*  m_cur_font;
233     };
234 
235 
236 
237 
238     //------------------------------------------------------------------------
239     enum glyph_rendering
240     {
241         glyph_ren_native_mono,
242         glyph_ren_native_gray8,
243         glyph_ren_outline,
244         glyph_ren_agg_mono,
245         glyph_ren_agg_gray8
246     };
247 
248 
249 
250 
251     //------------------------------------------------------font_cache_manager
252     template<class FontEngine> class font_cache_manager
253     {
254     public:
255         typedef FontEngine font_engine_type;
256         typedef font_cache_manager<FontEngine> self_type;
257         typedef typename font_engine_type::path_adaptor_type   path_adaptor_type;
258         typedef typename font_engine_type::gray8_adaptor_type  gray8_adaptor_type;
259         typedef typename gray8_adaptor_type::embedded_scanline gray8_scanline_type;
260         typedef typename font_engine_type::mono_adaptor_type   mono_adaptor_type;
261         typedef typename mono_adaptor_type::embedded_scanline  mono_scanline_type;
262 
263         //--------------------------------------------------------------------
264         font_cache_manager(font_engine_type& engine, unsigned max_fonts=32) :
265             m_fonts(max_fonts),
266             m_engine(engine),
267             m_change_stamp(-1),
268             m_prev_glyph(0),
269             m_last_glyph(0)
270         {}
271 
272         //--------------------------------------------------------------------
273         const glyph_cache* glyph(unsigned glyph_code)
274         {
275             synchronize();
276             const glyph_cache* gl = m_fonts.find_glyph(glyph_code);
277             if(gl)
278             {
279                 m_prev_glyph = m_last_glyph;
280                 return m_last_glyph = gl;
281             }
282             else
283             {
284                 if(m_engine.prepare_glyph(glyph_code))
285                 {
286                     m_prev_glyph = m_last_glyph;
287                     m_last_glyph = m_fonts.cache_glyph(glyph_code,
288                                                        m_engine.glyph_index(),
289                                                        m_engine.data_size(),
290                                                        m_engine.data_type(),
291                                                        m_engine.bounds(),
292                                                        m_engine.advance_x(),
293                                                        m_engine.advance_y());
294                     m_engine.write_glyph_to(m_last_glyph->data);
295                     return m_last_glyph;
296                 }
297             }
298             return 0;
299         }
300 
301         //--------------------------------------------------------------------
302         void init_embedded_adaptors(const glyph_cache* gl,
303                                     double x, double y,
304                                     double scale=1.0)
305         {
306             if(gl)
307             {
308                 switch(gl->data_type)
309                 {
310                 default: return;
311                 case glyph_data_mono:
312                     m_mono_adaptor.init(gl->data, gl->data_size, x, y);
313                     break;
314 
315                 case glyph_data_gray8:
316                     m_gray8_adaptor.init(gl->data, gl->data_size, x, y);
317                     break;
318 
319                 case glyph_data_outline:
320                     m_path_adaptor.init(gl->data, gl->data_size, x, y, scale);
321                     break;
322                 }
323             }
324         }
325 
326 
327         //--------------------------------------------------------------------
328         path_adaptor_type&   path_adaptor()   { return m_path_adaptor;   }
329         gray8_adaptor_type&  gray8_adaptor()  { return m_gray8_adaptor;  }
330         gray8_scanline_type& gray8_scanline() { return m_gray8_scanline; }
331         mono_adaptor_type&   mono_adaptor()   { return m_mono_adaptor;   }
332         mono_scanline_type&  mono_scanline()  { return m_mono_scanline;  }
333 
334         //--------------------------------------------------------------------
335         const glyph_cache* perv_glyph() const { return m_prev_glyph; }
336         const glyph_cache* last_glyph() const { return m_last_glyph; }
337 
338         //--------------------------------------------------------------------
339         bool add_kerning(double* x, double* y)
340         {
341             if(m_prev_glyph && m_last_glyph)
342             {
343                 return m_engine.add_kerning(m_prev_glyph->glyph_index,
344                                             m_last_glyph->glyph_index,
345                                             x, y);
346             }
347             return false;
348         }
349 
350         //--------------------------------------------------------------------
351         void precache(unsigned from, unsigned to)
352         {
353             for(; from <= to; ++from) glyph(from);
354         }
355 
356         //--------------------------------------------------------------------
357         void reset_cache()
358         {
359             m_fonts.font(m_engine.font_signature(), true);
360             m_change_stamp = m_engine.change_stamp();
361             m_prev_glyph = m_last_glyph = 0;
362         }
363 
364     private:
365         //--------------------------------------------------------------------
366         font_cache_manager(const self_type&);
367         const self_type& operator = (const self_type&);
368 
369         //--------------------------------------------------------------------
370         void synchronize()
371         {
372             if(m_change_stamp != m_engine.change_stamp())
373             {
374                 m_fonts.font(m_engine.font_signature());
375                 m_change_stamp = m_engine.change_stamp();
376                 m_prev_glyph = m_last_glyph = 0;
377             }
378         }
379 
380         font_cache_pool     m_fonts;
381         font_engine_type&   m_engine;
382         int                 m_change_stamp;
383         double              m_dx;
384         double              m_dy;
385         const glyph_cache*  m_prev_glyph;
386         const glyph_cache*  m_last_glyph;
387         path_adaptor_type   m_path_adaptor;
388         gray8_adaptor_type  m_gray8_adaptor;
389         gray8_scanline_type m_gray8_scanline;
390         mono_adaptor_type   m_mono_adaptor;
391         mono_scanline_type  m_mono_scanline;
392     };
393 
394 }
395 
396 #endif
397 
398