Logo Search packages:      
Sourcecode: ia32-libs-gtk version File versions  Download package

xftglyphs.c

/*
 * $Id: xftglyphs.c,v 1.4 2005/07/03 07:00:57 daniels Exp $
 *
 * Copyright © 2000 Keith Packard
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Keith Packard not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Keith Packard makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include "xftint.h"
#include <freetype/ftoutln.h>

static const int    filters[3][3] = {
    /* red */
#if 0
{    65538*4/7,65538*2/7,65538*1/7 },
    /* green */
{    65536*1/4, 65536*2/4, 65537*1/4 },
    /* blue */
{    65538*1/7,65538*2/7,65538*4/7 },
#endif
{    65538*9/13,65538*3/13,65538*1/13 },
    /* green */
{    65538*1/6, 65538*4/6, 65538*1/6 },
    /* blue */
{    65538*1/13,65538*3/13,65538*9/13 },
};

/*
 * Validate the memory info for a font
 */

static void
_XftFontValidateMemory (Display *dpy, XftFont *public)
{
    XftFontInt        *font = (XftFontInt *) public;
    unsigned long   glyph_memory;
    FT_UInt     glyphindex;
    XftGlyph          *xftg;

    glyph_memory = 0;
    for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++)
    {
      xftg = font->glyphs[glyphindex];
      if (xftg)
      {
          glyph_memory += xftg->glyph_memory;
      }
    }
    if (glyph_memory != font->glyph_memory)
      printf ("Font glyph cache incorrect has %ld bytes, should have %ld\n",
            font->glyph_memory, glyph_memory);
}

void
XftFontLoadGlyphs (Display        *dpy,
               XftFont      *pub,
               FcBool       need_bitmaps,
               _Xconst FT_UInt  *glyphs,
               int                nglyph)
{
    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
    XftFontInt        *font = (XftFontInt *) pub;
    FT_Error          error;
    FT_UInt     glyphindex;
    FT_GlyphSlot    glyphslot;
    XftGlyph          *xftg;
    Glyph       glyph;
    unsigned char   bufLocal[4096];
    unsigned char   *bufBitmap = bufLocal;
    int               bufSize = sizeof (bufLocal);
    int               size, pitch;
    unsigned char   bufLocalRgba[4096];
    unsigned char   *bufBitmapRgba = bufLocalRgba;
    int               bufSizeRgba = sizeof (bufLocalRgba);
    int               sizergba, pitchrgba, widthrgba;
    int               width;
    int               height;
    int               left, right, top, bottom;
    int               hmul = 1;
    int               vmul = 1;
    FT_Bitmap         ftbit;
    FT_Matrix         matrix;
    FT_Vector         vector;
    Bool        subpixel = False;
    FT_Face     face;

    if (!info)
      return;

    face = XftLockFace (&font->public);
    
    if (!face)
      return;

    matrix.xx = matrix.yy = 0x10000L;
    matrix.xy = matrix.yx = 0;

    if (font->info.antialias)
    {
      switch (font->info.rgba) {
      case FC_RGBA_RGB:
      case FC_RGBA_BGR:
          matrix.xx *= 3;
          subpixel = True;
          hmul = 3;
          break;
      case FC_RGBA_VRGB:
      case FC_RGBA_VBGR:
          matrix.yy *= 3;
          vmul = 3;
          subpixel = True;
          break;
      }
    }

    while (nglyph--)
    {
      glyphindex = *glyphs++;
      xftg = font->glyphs[glyphindex];
      if (!xftg)
          continue;
      
      if (XftDebug() & XFT_DBG_CACHE)
          _XftFontValidateMemory (dpy, pub);
      /*
       * Check to see if this glyph has just been loaded,
       * this happens when drawing the same glyph twice
       * in a single string
       */
      if (xftg->glyph_memory)
          continue;
      
      error = FT_Load_Glyph (face, glyphindex, font->info.load_flags);
      if (error)
      {
          /*
           * If anti-aliasing or transforming glyphs and
           * no outline version exists, fallback to the
           * bitmap and let things look bad instead of
           * missing the glyph
           */
          if (font->info.load_flags & FT_LOAD_NO_BITMAP)
            error = FT_Load_Glyph (face, glyphindex,
                               font->info.load_flags & ~FT_LOAD_NO_BITMAP);
          if (error)
            continue;
      }

#define FLOOR(x)    ((x) & -64)
#define CEIL(x)       (((x)+63) & -64)
#define TRUNC(x)    ((x) >> 6)
#define ROUND(x)    (((x)+32) & -64)
            
      glyphslot = face->glyph;

#if HAVE_FT_GLYPHSLOT_EMBOLDEN
      /*
       * Embolden if required
       */
      if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot);
#endif

      /*
       * Compute glyph metrics from FreeType information
       */
      if(font->info.transform && glyphslot->format != ft_glyph_format_bitmap) 
      {
          /*
           * calculate the true width by transforming all four corners.
           */
          int xc, yc;
          left = right = top = bottom = 0;
          for(xc = 0; xc <= 1; xc ++) {
            for(yc = 0; yc <= 1; yc++) {
                vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width;
                vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height;
                FT_Vector_Transform(&vector, &font->info.matrix);   
                if (XftDebug() & XFT_DBG_GLYPH)
                  printf("Trans %d %d: %d %d\n", (int) xc, (int) yc, 
                         (int) vector.x, (int) vector.y);
                if(xc == 0 && yc == 0) {
                  left = right = vector.x;
                  top = bottom = vector.y;
                } else {
                  if(left > vector.x) left = vector.x;
                  if(right < vector.x) right = vector.x;
                  if(bottom > vector.y) bottom = vector.y;
                  if(top < vector.y) top = vector.y;
                }

            }
          }
          left = FLOOR(left);
          right = CEIL(right);
          bottom = FLOOR(bottom);
          top = CEIL(top);

      } else {
          left  = FLOOR( glyphslot->metrics.horiBearingX );
          right = CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width );

          top    = CEIL( glyphslot->metrics.horiBearingY );
          bottom = FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height );
      }

      width = TRUNC(right - left);
      height = TRUNC( top - bottom );

      /*
       * Clip charcell glyphs to the bounding box
       * XXX transformed?
       */
      if (font->info.spacing >= FC_CHARCELL && !font->info.transform)
      {
          if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
          {
            if (TRUNC(bottom) > font->public.max_advance_width)
            {
                int adjust;
    
                adjust = bottom - (font->public.max_advance_width << 6);
                if (adjust > top)
                  adjust = top;
                top -= adjust;
                bottom -= adjust;
                height = font->public.max_advance_width;
            }
          }
          else
          {
            if (TRUNC(right) > font->public.max_advance_width)
            {
                int adjust;
    
                adjust = right - (font->public.max_advance_width << 6);
                if (adjust > left)
                  adjust = left;
                left -= adjust;
                right -= adjust;
                width = font->public.max_advance_width;
            }
          }
      }

      if (font->info.antialias)
          pitch = (width * hmul + 3) & ~3;
      else
          pitch = ((width + 31) & ~31) >> 3;

      size = pitch * height * vmul;

      xftg->metrics.width = width;
      xftg->metrics.height = height;
      xftg->metrics.x = -TRUNC(left);
      xftg->metrics.y = TRUNC(top);

      if (font->info.spacing >= FC_MONO)
      {
          if (font->info.transform)
          {
            if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
            {
                vector.x = 0;
                vector.y = -face->size->metrics.max_advance;
            }
            else
            {
                vector.x = face->size->metrics.max_advance;
                vector.y = 0;
            }
            FT_Vector_Transform (&vector, &font->info.matrix);
            xftg->metrics.xOff = vector.x >> 6;
            xftg->metrics.yOff = -(vector.y >> 6);
          }
          else
          {
            if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
            {
                xftg->metrics.xOff = 0;
                xftg->metrics.yOff = -font->public.max_advance_width;
            }
            else
            {
                xftg->metrics.xOff = font->public.max_advance_width;
                xftg->metrics.yOff = 0;
            }
          }
      }
      else
      {
          xftg->metrics.xOff = TRUNC(ROUND(glyphslot->advance.x));
          xftg->metrics.yOff = -TRUNC(ROUND(glyphslot->advance.y));
      }
      
      /*
       * If the glyph is relatively large (> 1% of server memory),
       * don't send it until necessary
       */
      if (!need_bitmaps && size > info->max_glyph_memory / 100)
          continue;
      
      /*
       * Make sure there's enough buffer space for the glyph
       */
      if (size > bufSize)
      {
          if (bufBitmap != bufLocal)
            free (bufBitmap);
          bufBitmap = (unsigned char *) malloc (size);
          if (!bufBitmap)
            continue;
          bufSize = size;
      }
      memset (bufBitmap, 0, size);

      /*
       * Rasterize into the local buffer
       */
      switch (glyphslot->format) {
      case ft_glyph_format_outline:
          ftbit.width      = width * hmul;
          ftbit.rows       = height * vmul;
          ftbit.pitch      = pitch;
          if (font->info.antialias)
            ftbit.pixel_mode = ft_pixel_mode_grays;
          else
            ftbit.pixel_mode = ft_pixel_mode_mono;
          
          ftbit.buffer     = bufBitmap;
          
          if (subpixel)
            FT_Outline_Transform (&glyphslot->outline, &matrix);

          FT_Outline_Translate ( &glyphslot->outline, -left*hmul, -bottom*vmul );

          FT_Outline_Get_Bitmap( _XftFTlibrary, &glyphslot->outline, &ftbit );
          break;
      case ft_glyph_format_bitmap:
          if (font->info.antialias)
          {
            unsigned char     *srcLine, *dstLine;
            int         height;
            int         x;
            int       h, v;

            srcLine = glyphslot->bitmap.buffer;
            dstLine = bufBitmap;
            height = glyphslot->bitmap.rows;
            while (height--)
            {
                for (x = 0; x < glyphslot->bitmap.width; x++)
                {
                  /* always MSB bitmaps */
                  unsigned char     a = ((srcLine[x >> 3] & (0x80 >> (x & 7))) ?
                                   0xff : 0x00);
                  if (subpixel)
                  {
                      for (v = 0; v < vmul; v++)
                        for (h = 0; h < hmul; h++)
                            dstLine[v * pitch + x*hmul + h] = a;
                  }
                  else
                      dstLine[x] = a;
                }
                dstLine += pitch * vmul;
                srcLine += glyphslot->bitmap.pitch;
            }
          }
          else
          {
            unsigned char     *srcLine, *dstLine;
            int         h, bytes;

            srcLine = glyphslot->bitmap.buffer;
            dstLine = bufBitmap;
            h = glyphslot->bitmap.rows;
            bytes = (glyphslot->bitmap.width + 7) >> 3;
            while (h--)
            {
                memcpy (dstLine, srcLine, bytes);
                dstLine += pitch;
                srcLine += glyphslot->bitmap.pitch;
            }
          }
          break;
      default:
          if (XftDebug() & XFT_DBG_GLYPH)
            printf ("glyph %d is not in a usable format\n",
                  (int) glyphindex);
          continue;
      }
      
      if (XftDebug() & XFT_DBG_GLYPH)
      {
          printf ("glyph %d:\n", (int) glyphindex);
          printf (" xywh (%d %d %d %d), trans (%d %d %d %d) wh (%d %d)\n",
                (int) glyphslot->metrics.horiBearingX,
                (int) glyphslot->metrics.horiBearingY,
                (int) glyphslot->metrics.width,
                (int) glyphslot->metrics.height,
                left, right, top, bottom,
                width, height);
          if (XftDebug() & XFT_DBG_GLYPHV)
          {
            int         x, y;
            unsigned char     *line;

            line = bufBitmap;
            for (y = 0; y < height * vmul; y++)
            {
                if (font->info.antialias) 
                {
                  static char    den[] = { " .:;=+*#" };
                  for (x = 0; x < pitch; x++)
                      printf ("%c", den[line[x] >> 5]);
                }
                else
                {
                  for (x = 0; x < pitch * 8; x++)
                  {
                      printf ("%c", line[x>>3] & (1 << (x & 7)) ? '#' : ' ');
                  }
                }
                printf ("|\n");
                line += pitch;
            }
            printf ("\n");
          }
      }

      /*
       * Use the glyph index as the wire encoding; it
       * might be more efficient for some locales to map
       * these by first usage to smaller values, but that
       * would require persistently storing the map when
       * glyphs were freed.
       */
      glyph = (Glyph) glyphindex;

      if (subpixel)
      {
          int               x, y;
          unsigned char   *in_line, *out_line, *in;
          unsigned int    *out;
          unsigned int    red, green, blue;
          int               rf, gf, bf;
          int               s;
          int               o, os;
          
          /*
           * Filter the glyph to soften the color fringes
           */
          widthrgba = width;
          pitchrgba = (widthrgba * 4 + 3) & ~3;
          sizergba = pitchrgba * height;

          os = 1;
          switch (font->info.rgba) {
          case FC_RGBA_VRGB:
            os = pitch;
          case FC_RGBA_RGB:
          default:
            rf = 0;
            gf = 1;
            bf = 2;
            break;
          case FC_RGBA_VBGR:
            os = pitch;
          case FC_RGBA_BGR:
            bf = 0;
            gf = 1;
            rf = 2;
            break;
          }
          if (sizergba > bufSizeRgba)
          {
            if (bufBitmapRgba != bufLocalRgba)
                free (bufBitmapRgba);
            bufBitmapRgba = (unsigned char *) malloc (sizergba);
            if (!bufBitmapRgba)
                continue;
            bufSizeRgba = sizergba;
          }
          memset (bufBitmapRgba, 0, sizergba);
          in_line = bufBitmap;
          out_line = bufBitmapRgba;
          for (y = 0; y < height; y++)
          {
            in = in_line;
            out = (unsigned int *) out_line;
            in_line += pitch * vmul;
            out_line += pitchrgba;
            for (x = 0; x < width * hmul; x += hmul)
            {
                red = green = blue = 0;
                o = 0;
                for (s = 0; s < 3; s++)
                {
                  red += filters[rf][s]*in[x+o];
                  green += filters[gf][s]*in[x+o];
                  blue += filters[bf][s]*in[x+o];
                  o += os;
                }
                red = red / 65536;
                green = green / 65536;
                blue = blue / 65536;
                *out++ = (green << 24) | (red << 16) | (green << 8) | blue;
            }
          }
          
          xftg->glyph_memory = sizergba + sizeof (XftGlyph);
          if (font->format)
          {
            if (!font->glyphset)
                font->glyphset = XRenderCreateGlyphSet (dpy, font->format);
            if (ImageByteOrder (dpy) != XftNativeByteOrder ())
                XftSwapCARD32 ((CARD32 *) bufBitmapRgba, sizergba >> 2);
            XRenderAddGlyphs (dpy, font->glyphset, &glyph,
                          &xftg->metrics, 1, 
                          (char *) bufBitmapRgba, sizergba);
          }
          else
          {
            if (sizergba)
            {
                xftg->bitmap = malloc (sizergba);
                if (xftg->bitmap)
                  memcpy (xftg->bitmap, bufBitmapRgba, sizergba);
            }
            else
                xftg->bitmap = 0;
          }
      }
      else
      {
          xftg->glyph_memory = size + sizeof (XftGlyph);
          if (font->format)
          {
            /*
             * swap bit order around; FreeType is always MSBFirst
             */
            if (!font->info.antialias)
            {
                if (BitmapBitOrder (dpy) != MSBFirst)
                {
                  unsigned char   *line;
                  unsigned char   c;
                  int             i;

                  line = (unsigned char *) bufBitmap;
                  i = size;
                  while (i--)
                  {
                      c = *line;
                      c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
                      c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
                      c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
                      *line++ = c;
                  }
                }
            }
            if (!font->glyphset)
                font->glyphset = XRenderCreateGlyphSet (dpy, font->format);
            XRenderAddGlyphs (dpy, font->glyphset, &glyph,
                          &xftg->metrics, 1, 
                          (char *) bufBitmap, size);
          }
          else
          {
            if (size)
            {
                xftg->bitmap = malloc (size);
                if (xftg->bitmap)
                  memcpy (xftg->bitmap, bufBitmap, size);
            }
            else
                xftg->bitmap = 0;
          }
      }
      font->glyph_memory += xftg->glyph_memory;
      info->glyph_memory += xftg->glyph_memory;
      if (XftDebug() & XFT_DBG_CACHE)
          _XftFontValidateMemory (dpy, pub);
      if (XftDebug() & XFT_DBG_CACHEV)
          printf ("Caching glyph 0x%x size %ld\n", glyphindex,
                xftg->glyph_memory);
    }
    if (bufBitmap != bufLocal)
      free (bufBitmap);
    if (bufBitmapRgba != bufLocalRgba)
      free (bufBitmapRgba);
    XftUnlockFace (&font->public);
}

void
XftFontUnloadGlyphs (Display        *dpy,
                 XftFont            *pub,
                 _Xconst FT_UInt    *glyphs,
                 int          nglyph)
{
    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
    XftFontInt        *font = (XftFontInt *) pub;
    XftGlyph          *xftg;
    FT_UInt     glyphindex;
    Glyph       glyphBuf[1024];
    int               nused;
    
    nused = 0;
    while (nglyph--)
    {
      glyphindex = *glyphs++;
      xftg = font->glyphs[glyphindex];
      if (!xftg)
          continue;
      if (xftg->glyph_memory)
      {
          if (font->format)
          {
            if (font->glyphset)
            {
                glyphBuf[nused++] = (Glyph) glyphindex;
                if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0]))
                {
                  XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused);
                  nused = 0;
                }
            }
          }
          else
          {
            if (xftg->bitmap)
                free (xftg->bitmap);
          }
          font->glyph_memory -= xftg->glyph_memory;
          if (info)
            info->glyph_memory -= xftg->glyph_memory;
      }
      free (xftg);
      XftMemFree (XFT_MEM_GLYPH, sizeof (XftGlyph));
      font->glyphs[glyphindex] = 0;
    }    
    if (font->glyphset && nused)
      XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused);
}

FcBool
XftFontCheckGlyph (Display    *dpy,
               XftFont  *pub,
               FcBool   need_bitmaps,
               FT_UInt  glyph,
               FT_UInt  *missing,
               int            *nmissing)
{
    XftFontInt        *font = (XftFontInt *) pub;
    XftGlyph          *xftg;
    int               n;
    
    if (glyph >= font->num_glyphs)
      return FcFalse;
    xftg = font->glyphs[glyph];
    if (!xftg || (need_bitmaps && !xftg->glyph_memory))
    {
      if (!xftg)
      {
          xftg = (XftGlyph *) malloc (sizeof (XftGlyph));
          if (!xftg)
            return FcFalse;
          XftMemAlloc (XFT_MEM_GLYPH, sizeof (XftGlyph));
          xftg->bitmap = 0;
          xftg->glyph_memory = 0;
          font->glyphs[glyph] = xftg;
      }
      n = *nmissing;
      missing[n++] = glyph;
      if (n == XFT_NMISSING)
      {
          XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n);
          n = 0;
      }
      *nmissing = n;
      return FcTrue;
    }
    else
      return FcFalse;
}

FcBool
XftCharExists (Display      *dpy,
             XftFont        *pub,
             FcChar32    ucs4)
{
    if (pub->charset)
      return FcCharSetHasChar (pub->charset, ucs4);
    return FcFalse;
}

#define Missing       ((FT_UInt) ~0)

FT_UInt
XftCharIndex (Display       *dpy, 
            XftFont         *pub,
            FcChar32        ucs4)
{
    XftFontInt    *font = (XftFontInt *) pub;
    FcChar32      ent, offset;
    FT_Face face;
    
    if (!font->hash_value)
      return 0;

    ent = ucs4 % font->hash_value;
    offset = 0;
    while (font->hash_table[ent].ucs4 != ucs4)
    {
      if (font->hash_table[ent].ucs4 == (FcChar32) ~0)
      {
          if (!XftCharExists (dpy, pub, ucs4))
            return 0;
          face  = XftLockFace (pub);
          if (!face)
            return 0;
          font->hash_table[ent].ucs4 = ucs4;
          font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4);
          XftUnlockFace (pub);
          break;
      }
      if (!offset)
      {
          offset = ucs4 % font->rehash_value;
          if (!offset)
            offset = 1;
      }
      ent = ent + offset;
      if (ent >= font->hash_value)
          ent -= font->hash_value;
    }
    return font->hash_table[ent].glyph;
}

/*
 * Pick a random glyph from the font and remove it from the cache
 */
void
_XftFontUncacheGlyph (Display *dpy, XftFont *pub)
{
    XftFontInt        *font = (XftFontInt *) pub;
    unsigned long   glyph_memory;
    FT_UInt     glyphindex;
    XftGlyph          *xftg;
    
    if (!font->glyph_memory)
      return;
    if (font->use_free_glyphs)
    {
      glyph_memory = rand() % font->glyph_memory;
    }
    else
    {
      if (font->glyphset)
      {
          XRenderFreeGlyphSet (dpy, font->glyphset);
          font->glyphset = 0;
      }
      glyph_memory = 0;
    }
      
    if (XftDebug() & XFT_DBG_CACHE)
      _XftFontValidateMemory (dpy, pub);
    for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++)
    {
      xftg = font->glyphs[glyphindex];
      if (xftg)
      {
          if (xftg->glyph_memory > glyph_memory)
          {
            if (XftDebug() & XFT_DBG_CACHEV)
                printf ("Uncaching glyph 0x%x size %ld\n",
                      glyphindex, xftg->glyph_memory);
            XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1);
            if (!font->use_free_glyphs)
                continue;
            break;
          }
          glyph_memory -= xftg->glyph_memory;
      }
    }
    if (XftDebug() & XFT_DBG_CACHE)
      _XftFontValidateMemory (dpy, pub);
}

void
_XftFontManageMemory (Display *dpy, XftFont *pub)
{
    XftFontInt    *font = (XftFontInt *) pub;

    if (font->max_glyph_memory)
    {
      if (XftDebug() & XFT_DBG_CACHE)
      {
          if (font->glyph_memory > font->max_glyph_memory)
            printf ("Reduce memory for font 0x%lx from %ld to %ld\n",
                  font->glyphset ? font->glyphset : (unsigned long) font,
                  font->glyph_memory, font->max_glyph_memory);
      }
      while (font->glyph_memory > font->max_glyph_memory)
          _XftFontUncacheGlyph (dpy, pub);
    }
    _XftDisplayManageMemory (dpy);
}

Generated by  Doxygen 1.6.0   Back to index