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 //-------------------------------------------------------------------- glyph(unsigned glyph_code)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 //-------------------------------------------------------------------- path_adaptor()334 path_adaptor_type& path_adaptor() { return m_path_adaptor; } gray8_adaptor()335 gray8_adaptor_type& gray8_adaptor() { return m_gray8_adaptor; } gray8_scanline()336 gray8_scanline_type& gray8_scanline() { return m_gray8_scanline; } mono_adaptor()337 mono_adaptor_type& mono_adaptor() { return m_mono_adaptor; } mono_scanline()338 mono_scanline_type& mono_scanline() { return m_mono_scanline; } 339 340 //-------------------------------------------------------------------- perv_glyph()341 const glyph_cache* perv_glyph() const { return m_prev_glyph; } last_glyph()342 const glyph_cache* last_glyph() const { return m_last_glyph; } 343 344 //-------------------------------------------------------------------- add_kerning(double * x,double * y)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 //-------------------------------------------------------------------- precache(unsigned from,unsigned to)357 void precache(unsigned from, unsigned to) 358 { 359 for(; from <= to; ++from) glyph(from); 360 } 361 362 //-------------------------------------------------------------------- reset_cache()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 //-------------------------------------------------------------------- reset()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 //-------------------------------------------------------------------- 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