[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Sample code for caching glyphs
From: |
graydon hoare |
Subject: |
Re: Sample code for caching glyphs |
Date: |
Thu, 15 Jun 2000 16:57:04 -0400 (EDT) |
yes, in berlin we use a simple LRU cache for freetype glyphs, and the
speed improvement is stunning.
here's the basics (you can get all the files in berlin CVS if you like):
#include <map>
#include <list>
template
<class kT, class vT, class factoryT, class cacheT = map<kT,vT> >
class LRUCache {
private:
int max;
cacheT cache;
list<kT> queue;
factoryT factory;
public:
LRUCache(factoryT fact, int i = 256) : max(i), factory(fact) {}
void get(const kT &k, vT &v) throw ()
{
typename cacheT::iterator iter = cache.find(k);
if (iter != cache.end()) {
v = iter->second;
return;
} else {
v = factory.produce(k);
cache.insert(pair<kT,vT>(k,v));
queue.push_front(k);
if (queue.size() >= max) {
kT victim = queue.back();
factory.recycle(cache[victim]);
cache.erase(victim);
queue.pop_back();
}
}
}
};
typedef pair<atom,atom> FamStyle;
typedef pair<PtSize,FamStyle> FaceSpec;
typedef pair<Unichar,FaceSpec> GlyphSpec;
class GlyphFactory {
private:
LibArtFTFont *font_;
FT_Library *lib_;
public:
GlyphFactory(LibArtFTFont *f, FT_Library *l) : font_(f), lib_(l) {};
ArtPixBuf *produce(const GlyphSpec &cs);
void recycle(ArtPixBuf *pb) {art_pixbuf_free(pb);};
};
//... then in implementation
LRUCache<GlyphSpec,ArtPixBuf *, GlyphFactory> myGlyphCache;
void LibArtFTFont::getPixBuf(const Unichar ch, ArtPixBuf *&pb) {
GlyphSpec key(ch,FaceSpec(mySize,FamStyle(myFam,myStyle)));
myGlyphCache.get(key,pb);
}
ArtPixBuf *
LibArtFTFont::GlyphFactory::produce(const LibArtFTFont::GlyphSpec &gs)
{
FT_Face newface;
font_->setup_face(newface);
font_->setup_size(newface);
Unichar ch = gs.first;
DrawingKit::GlyphMetrics gm = font_->metrics(ch);
int width = (int) (gm.width >> 6);
int height = (int) (gm.height >> 6);
art_u8 *pixels = new art_u8[width * height];
// this is a lie -- we're going to use it as a greymap
ArtPixBuf *pb = art_pixbuf_new_rgb (pixels, width, height, width);
font_->load_glyph(ch,newface);
render_pixbuf(pb,newface->glyph,*lib_);
return pb;
}
void LibArtFTFont::setup_face(FT_Face &f)
{
FamStyle spec(myFam,myStyle);
if (myFaceMap.find(spec) != myFaceMap.end()) f = myFaceMap[spec];
else f = myFace;
}
void LibArtFTFont::setup_size(FT_Face &f) {
FT_Set_Char_Size
( f, // handle to face object
mySize << 6, // char_width in 1/64th of points
mySize << 6, // char_height in 1/64th of points
(unsigned int)xdpi, // horizontal device resolution
(unsigned int)ydpi ); // vertical device resolution
}
bool LibArtFTFont::load_glyph(Unichar c, FT_Face &f) {
FT_CharMap found = 0;
FT_CharMap charmap;
for (int n = 0; n < f->num_charmaps; n++ ){
charmap = f->charmaps[n];
if (charmap->encoding == ft_encoding_unicode) {
found = charmap;
break;
}
}
if (!found) {
// no way of translating!
return false;
}
/* now, select the charmap for the face object */
if (FT_Set_Charmap( f, found )) return false;
int idx = FT_Get_Char_Index(f,(unsigned char)c);
if (FT_Load_Glyph (f,idx,0)) {
return false;
}
return true;
}