2006-02-01 00:09:52 +01:00
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// Anti-Grain Geometry - Version 2.4
|
|
|
|
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
|
|
|
//
|
|
|
|
// Permission to copy, use, modify, sell and distribute this software
|
|
|
|
// is granted provided this copyright notice appears in all copies.
|
|
|
|
// This software is provided "as is" without express or implied
|
|
|
|
// warranty, and with no claim as to its suitability for any purpose.
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
// Contact: mcseem@antigrain.com
|
|
|
|
// mcseemagg@yahoo.com
|
|
|
|
// http://www.antigrain.com
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#ifndef AGG_FONT_CACHE_MANAGER_INCLUDED
|
|
|
|
#define AGG_FONT_CACHE_MANAGER_INCLUDED
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include "agg_array.h"
|
|
|
|
|
|
|
|
namespace agg
|
|
|
|
{
|
|
|
|
|
|
|
|
//---------------------------------------------------------glyph_data_type
|
|
|
|
enum glyph_data_type
|
|
|
|
{
|
|
|
|
glyph_data_invalid = 0,
|
|
|
|
glyph_data_mono = 1,
|
|
|
|
glyph_data_gray8 = 2,
|
|
|
|
glyph_data_outline = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------glyph_cache
|
|
|
|
struct glyph_cache
|
|
|
|
{
|
|
|
|
unsigned glyph_index;
|
|
|
|
int8u* data;
|
|
|
|
unsigned data_size;
|
|
|
|
glyph_data_type data_type;
|
|
|
|
rect_i bounds;
|
|
|
|
double advance_x;
|
|
|
|
double advance_y;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------font_cache
|
|
|
|
class font_cache
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum block_size_e { block_size = 16384-16 };
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
2006-11-10 00:44:34 +01:00
|
|
|
font_cache() :
|
2006-02-01 00:09:52 +01:00
|
|
|
m_allocator(block_size),
|
|
|
|
m_font_signature(0)
|
2006-11-10 00:44:34 +01:00
|
|
|
{}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
void signature(const char* font_signature)
|
2006-02-01 00:09:52 +01:00
|
|
|
{
|
|
|
|
m_font_signature = (char*)m_allocator.allocate(strlen(font_signature) + 1);
|
|
|
|
strcpy(m_font_signature, font_signature);
|
|
|
|
memset(m_glyphs, 0, sizeof(m_glyphs));
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
bool font_is(const char* font_signature) const
|
|
|
|
{
|
|
|
|
return strcmp(font_signature, m_font_signature) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
const glyph_cache* find_glyph(unsigned glyph_code) const
|
|
|
|
{
|
|
|
|
unsigned msb = (glyph_code >> 8) & 0xFF;
|
|
|
|
if(m_glyphs[msb])
|
|
|
|
{
|
|
|
|
return m_glyphs[msb][glyph_code & 0xFF];
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
glyph_cache* 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)
|
|
|
|
{
|
|
|
|
unsigned msb = (glyph_code >> 8) & 0xFF;
|
|
|
|
if(m_glyphs[msb] == 0)
|
|
|
|
{
|
|
|
|
m_glyphs[msb] =
|
|
|
|
(glyph_cache**)m_allocator.allocate(sizeof(glyph_cache*) * 256,
|
|
|
|
sizeof(glyph_cache*));
|
|
|
|
memset(m_glyphs[msb], 0, sizeof(glyph_cache*) * 256);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned lsb = glyph_code & 0xFF;
|
|
|
|
if(m_glyphs[msb][lsb]) return 0; // Already exists, do not overwrite
|
|
|
|
|
|
|
|
glyph_cache* glyph =
|
|
|
|
(glyph_cache*)m_allocator.allocate(sizeof(glyph_cache),
|
|
|
|
sizeof(double));
|
|
|
|
|
2006-11-10 00:44:34 +01:00
|
|
|
glyph->glyph_index = glyph_index;
|
|
|
|
glyph->data = m_allocator.allocate(data_size);
|
|
|
|
glyph->data_size = data_size;
|
|
|
|
glyph->data_type = data_type;
|
|
|
|
glyph->bounds = bounds;
|
|
|
|
glyph->advance_x = advance_x;
|
|
|
|
glyph->advance_y = advance_y;
|
2006-02-01 00:09:52 +01:00
|
|
|
return m_glyphs[msb][lsb] = glyph;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2006-11-10 00:44:34 +01:00
|
|
|
block_allocator m_allocator;
|
2006-02-01 00:09:52 +01:00
|
|
|
glyph_cache** m_glyphs[256];
|
|
|
|
char* m_font_signature;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------font_cache_pool
|
|
|
|
class font_cache_pool
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
~font_cache_pool()
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
for(i = 0; i < m_num_fonts; ++i)
|
|
|
|
{
|
2006-11-10 00:44:34 +01:00
|
|
|
obj_allocator<font_cache>::deallocate(m_fonts[i]);
|
2006-02-01 00:09:52 +01:00
|
|
|
}
|
2006-11-10 00:44:34 +01:00
|
|
|
pod_allocator<font_cache*>::deallocate(m_fonts, m_max_fonts);
|
2006-02-01 00:09:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
font_cache_pool(unsigned max_fonts=32) :
|
2006-11-10 00:44:34 +01:00
|
|
|
m_fonts(pod_allocator<font_cache*>::allocate(max_fonts)),
|
2006-02-01 00:09:52 +01:00
|
|
|
m_max_fonts(max_fonts),
|
|
|
|
m_num_fonts(0),
|
|
|
|
m_cur_font(0)
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
void font(const char* font_signature, bool reset_cache = false)
|
|
|
|
{
|
|
|
|
int idx = find_font(font_signature);
|
|
|
|
if(idx >= 0)
|
|
|
|
{
|
|
|
|
if(reset_cache)
|
|
|
|
{
|
2006-11-10 00:44:34 +01:00
|
|
|
obj_allocator<font_cache>::deallocate(m_fonts[idx]);
|
|
|
|
m_fonts[idx] = obj_allocator<font_cache>::allocate();
|
|
|
|
m_fonts[idx]->signature(font_signature);
|
2006-02-01 00:09:52 +01:00
|
|
|
}
|
|
|
|
m_cur_font = m_fonts[idx];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(m_num_fonts >= m_max_fonts)
|
|
|
|
{
|
2006-11-10 00:44:34 +01:00
|
|
|
obj_allocator<font_cache>::deallocate(m_fonts[0]);
|
2006-02-01 00:09:52 +01:00
|
|
|
memcpy(m_fonts,
|
|
|
|
m_fonts + 1,
|
|
|
|
(m_max_fonts - 1) * sizeof(font_cache*));
|
|
|
|
m_num_fonts = m_max_fonts - 1;
|
|
|
|
}
|
2006-11-10 00:44:34 +01:00
|
|
|
m_fonts[m_num_fonts] = obj_allocator<font_cache>::allocate();
|
|
|
|
m_fonts[m_num_fonts]->signature(font_signature);
|
2006-02-01 00:09:52 +01:00
|
|
|
m_cur_font = m_fonts[m_num_fonts];
|
|
|
|
++m_num_fonts;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
const font_cache* font() const
|
|
|
|
{
|
|
|
|
return m_cur_font;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
const glyph_cache* find_glyph(unsigned glyph_code) const
|
|
|
|
{
|
|
|
|
if(m_cur_font) return m_cur_font->find_glyph(glyph_code);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
glyph_cache* 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)
|
|
|
|
{
|
|
|
|
if(m_cur_font)
|
|
|
|
{
|
|
|
|
return m_cur_font->cache_glyph(glyph_code,
|
|
|
|
glyph_index,
|
|
|
|
data_size,
|
|
|
|
data_type,
|
|
|
|
bounds,
|
|
|
|
advance_x,
|
|
|
|
advance_y);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
int find_font(const char* font_signature)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
for(i = 0; i < m_num_fonts; i++)
|
|
|
|
{
|
|
|
|
if(m_fonts[i]->font_is(font_signature)) return int(i);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
font_cache** m_fonts;
|
|
|
|
unsigned m_max_fonts;
|
|
|
|
unsigned m_num_fonts;
|
|
|
|
font_cache* m_cur_font;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
enum glyph_rendering
|
|
|
|
{
|
|
|
|
glyph_ren_native_mono,
|
|
|
|
glyph_ren_native_gray8,
|
|
|
|
glyph_ren_outline,
|
|
|
|
glyph_ren_agg_mono,
|
|
|
|
glyph_ren_agg_gray8
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------font_cache_manager
|
|
|
|
template<class FontEngine> class font_cache_manager
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef FontEngine font_engine_type;
|
|
|
|
typedef font_cache_manager<FontEngine> self_type;
|
|
|
|
typedef typename font_engine_type::path_adaptor_type path_adaptor_type;
|
|
|
|
typedef typename font_engine_type::gray8_adaptor_type gray8_adaptor_type;
|
|
|
|
typedef typename gray8_adaptor_type::embedded_scanline gray8_scanline_type;
|
|
|
|
typedef typename font_engine_type::mono_adaptor_type mono_adaptor_type;
|
|
|
|
typedef typename mono_adaptor_type::embedded_scanline mono_scanline_type;
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
font_cache_manager(font_engine_type& engine, unsigned max_fonts=32) :
|
|
|
|
m_fonts(max_fonts),
|
|
|
|
m_engine(engine),
|
|
|
|
m_change_stamp(-1),
|
|
|
|
m_prev_glyph(0),
|
|
|
|
m_last_glyph(0)
|
|
|
|
{}
|
|
|
|
|
2006-11-10 00:44:34 +01:00
|
|
|
//--------------------------------------------------------------------
|
|
|
|
void reset_last_glyph()
|
|
|
|
{
|
|
|
|
m_prev_glyph = m_last_glyph = 0;
|
|
|
|
}
|
|
|
|
|
2006-02-01 00:09:52 +01:00
|
|
|
//--------------------------------------------------------------------
|
|
|
|
const glyph_cache* glyph(unsigned glyph_code)
|
|
|
|
{
|
|
|
|
synchronize();
|
|
|
|
const glyph_cache* gl = m_fonts.find_glyph(glyph_code);
|
|
|
|
if(gl)
|
|
|
|
{
|
|
|
|
m_prev_glyph = m_last_glyph;
|
|
|
|
return m_last_glyph = gl;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(m_engine.prepare_glyph(glyph_code))
|
|
|
|
{
|
|
|
|
m_prev_glyph = m_last_glyph;
|
|
|
|
m_last_glyph = m_fonts.cache_glyph(glyph_code,
|
|
|
|
m_engine.glyph_index(),
|
|
|
|
m_engine.data_size(),
|
|
|
|
m_engine.data_type(),
|
|
|
|
m_engine.bounds(),
|
|
|
|
m_engine.advance_x(),
|
|
|
|
m_engine.advance_y());
|
|
|
|
m_engine.write_glyph_to(m_last_glyph->data);
|
|
|
|
return m_last_glyph;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
void init_embedded_adaptors(const glyph_cache* gl,
|
|
|
|
double x, double y,
|
|
|
|
double scale=1.0)
|
|
|
|
{
|
|
|
|
if(gl)
|
|
|
|
{
|
|
|
|
switch(gl->data_type)
|
|
|
|
{
|
|
|
|
default: return;
|
|
|
|
case glyph_data_mono:
|
|
|
|
m_mono_adaptor.init(gl->data, gl->data_size, x, y);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case glyph_data_gray8:
|
|
|
|
m_gray8_adaptor.init(gl->data, gl->data_size, x, y);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case glyph_data_outline:
|
|
|
|
m_path_adaptor.init(gl->data, gl->data_size, x, y, scale);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
path_adaptor_type& path_adaptor() { return m_path_adaptor; }
|
|
|
|
gray8_adaptor_type& gray8_adaptor() { return m_gray8_adaptor; }
|
|
|
|
gray8_scanline_type& gray8_scanline() { return m_gray8_scanline; }
|
|
|
|
mono_adaptor_type& mono_adaptor() { return m_mono_adaptor; }
|
|
|
|
mono_scanline_type& mono_scanline() { return m_mono_scanline; }
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
const glyph_cache* perv_glyph() const { return m_prev_glyph; }
|
|
|
|
const glyph_cache* last_glyph() const { return m_last_glyph; }
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
bool add_kerning(double* x, double* y)
|
|
|
|
{
|
|
|
|
if(m_prev_glyph && m_last_glyph)
|
|
|
|
{
|
|
|
|
return m_engine.add_kerning(m_prev_glyph->glyph_index,
|
|
|
|
m_last_glyph->glyph_index,
|
|
|
|
x, y);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
void precache(unsigned from, unsigned to)
|
|
|
|
{
|
|
|
|
for(; from <= to; ++from) glyph(from);
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
void reset_cache()
|
|
|
|
{
|
|
|
|
m_fonts.font(m_engine.font_signature(), true);
|
|
|
|
m_change_stamp = m_engine.change_stamp();
|
|
|
|
m_prev_glyph = m_last_glyph = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
font_cache_manager(const self_type&);
|
|
|
|
const self_type& operator = (const self_type&);
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
void synchronize()
|
|
|
|
{
|
|
|
|
if(m_change_stamp != m_engine.change_stamp())
|
|
|
|
{
|
|
|
|
m_fonts.font(m_engine.font_signature());
|
|
|
|
m_change_stamp = m_engine.change_stamp();
|
|
|
|
m_prev_glyph = m_last_glyph = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
font_cache_pool m_fonts;
|
|
|
|
font_engine_type& m_engine;
|
|
|
|
int m_change_stamp;
|
|
|
|
double m_dx;
|
|
|
|
double m_dy;
|
|
|
|
const glyph_cache* m_prev_glyph;
|
|
|
|
const glyph_cache* m_last_glyph;
|
|
|
|
path_adaptor_type m_path_adaptor;
|
|
|
|
gray8_adaptor_type m_gray8_adaptor;
|
|
|
|
gray8_scanline_type m_gray8_scanline;
|
|
|
|
mono_adaptor_type m_mono_adaptor;
|
|
|
|
mono_scanline_type m_mono_scanline;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|