freetype
[Top][All Lists]
Advanced

[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;
}





reply via email to

[Prev in Thread] Current Thread [Next in Thread]