Blame src/xftglyphs.c

Packit b749da
/*
Packit b749da
 * Copyright © 2000 Keith Packard
Packit b749da
 *
Packit b749da
 * Permission to use, copy, modify, distribute, and sell this software and its
Packit b749da
 * documentation for any purpose is hereby granted without fee, provided that
Packit b749da
 * the above copyright notice appear in all copies and that both that
Packit b749da
 * copyright notice and this permission notice appear in supporting
Packit b749da
 * documentation, and that the name of Keith Packard not be used in
Packit b749da
 * advertising or publicity pertaining to distribution of the software without
Packit b749da
 * specific, written prior permission.  Keith Packard makes no
Packit b749da
 * representations about the suitability of this software for any purpose.  It
Packit b749da
 * is provided "as is" without express or implied warranty.
Packit b749da
 *
Packit b749da
 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
Packit b749da
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
Packit b749da
 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
Packit b749da
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
Packit b749da
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
Packit b749da
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
Packit b749da
 * PERFORMANCE OF THIS SOFTWARE.
Packit b749da
 */
Packit b749da
Packit b749da
#include "xftint.h"
Packit b749da
#include FT_OUTLINE_H
Packit b749da
#include FT_LCD_FILTER_H
Packit b749da
Packit b749da
#include FT_SYNTHESIS_H
Packit b749da
Packit b749da
/*
Packit b749da
 * Validate the memory info for a font
Packit b749da
 */
Packit b749da
Packit b749da
static void
Packit b749da
_XftFontValidateMemory (Display *dpy, XftFont *public)
Packit b749da
{
Packit b749da
    XftFontInt	    *font = (XftFontInt *) public;
Packit b749da
    unsigned long   glyph_memory;
Packit b749da
    FT_UInt	    glyphindex;
Packit b749da
    XftGlyph	    *xftg;
Packit b749da
Packit b749da
    glyph_memory = 0;
Packit b749da
    for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++)
Packit b749da
    {
Packit b749da
	xftg = font->glyphs[glyphindex];
Packit b749da
	if (xftg)
Packit b749da
	{
Packit b749da
	    glyph_memory += xftg->glyph_memory;
Packit b749da
	}
Packit b749da
    }
Packit b749da
    if (glyph_memory != font->glyph_memory)
Packit b749da
	printf ("Font glyph cache incorrect has %ld bytes, should have %ld\n",
Packit b749da
		font->glyph_memory, glyph_memory);
Packit b749da
}
Packit b749da
Packit b749da
/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot
Packit b749da
 * into a different format. For example, we want to convert a
Packit b749da
 * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit
Packit b749da
 * ARGB or ABGR bitmap.
Packit b749da
 *
Packit b749da
 * this function prepares a target descriptor for this operation.
Packit b749da
 *
Packit b749da
 * input :: target bitmap descriptor. The function will set its
Packit b749da
 *          'width', 'rows' and 'pitch' fields, and only these
Packit b749da
 *
Packit b749da
 * slot  :: the glyph slot containing the source bitmap. this
Packit b749da
 *          function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP
Packit b749da
 *
Packit b749da
 * mode  :: the requested final rendering mode. supported values are
Packit b749da
 *          MONO, NORMAL (i.e. gray), LCD and LCD_V
Packit b749da
 *
Packit b749da
 * the function returns the size in bytes of the corresponding buffer,
Packit b749da
 * it's up to the caller to allocate the corresponding memory block
Packit b749da
 * before calling _fill_xrender_bitmap
Packit b749da
 *
Packit b749da
 * it also returns -1 in case of error (e.g. incompatible arguments,
Packit b749da
 * like trying to convert a gray bitmap into a monochrome one)
Packit b749da
 */
Packit b749da
static int
Packit b749da
_compute_xrender_bitmap_size( FT_Bitmap*	target,
Packit b749da
			      FT_GlyphSlot	slot,
Packit b749da
			      FT_Render_Mode	mode )
Packit b749da
{
Packit b749da
    FT_Bitmap*	ftbit;
Packit b749da
    int		width, height, pitch;
Packit b749da
Packit b749da
    if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
Packit b749da
	return -1;
Packit b749da
Packit b749da
    // compute the size of the final bitmap
Packit b749da
    ftbit = &slot->bitmap;
Packit b749da
Packit b749da
    width = ftbit->width;
Packit b749da
    height = ftbit->rows;
Packit b749da
    pitch = (width+3) & ~3;
Packit b749da
Packit b749da
    switch ( ftbit->pixel_mode )
Packit b749da
    {
Packit b749da
    case FT_PIXEL_MODE_MONO:
Packit b749da
	if ( mode == FT_RENDER_MODE_MONO )
Packit b749da
	{
Packit b749da
	    pitch = (((width+31) & ~31) >> 3);
Packit b749da
	    break;
Packit b749da
	}
Packit b749da
	/* fall-through */
Packit b749da
Packit b749da
    case FT_PIXEL_MODE_GRAY:
Packit b749da
	if ( mode == FT_RENDER_MODE_LCD ||
Packit b749da
	     mode == FT_RENDER_MODE_LCD_V )
Packit b749da
	{
Packit b749da
	    /* each pixel is replicated into a 32-bit ARGB value */
Packit b749da
	    pitch = width*4;
Packit b749da
	}
Packit b749da
	break;
Packit b749da
Packit b749da
    case FT_PIXEL_MODE_LCD:
Packit b749da
	if ( mode != FT_RENDER_MODE_LCD )
Packit b749da
	    return -1;
Packit b749da
Packit b749da
	/* horz pixel triplets are packed into 32-bit ARGB values */
Packit b749da
	width /= 3;
Packit b749da
	pitch = width*4;
Packit b749da
	break;
Packit b749da
Packit b749da
    case FT_PIXEL_MODE_LCD_V:
Packit b749da
	if ( mode != FT_RENDER_MODE_LCD_V )
Packit b749da
	    return -1;
Packit b749da
Packit b749da
	/* vert pixel triplets are packed into 32-bit ARGB values */
Packit b749da
	height /= 3;
Packit b749da
	pitch = width*4;
Packit b749da
	break;
Packit b749da
Packit b749da
    default:  /* unsupported source format */
Packit b749da
	return -1;
Packit b749da
    }
Packit b749da
Packit b749da
    target->width = width;
Packit b749da
    target->rows = height;
Packit b749da
    target->pitch = pitch;
Packit b749da
    target->buffer = NULL;
Packit b749da
Packit b749da
    return pitch * height;
Packit b749da
}
Packit b749da
Packit b749da
/* this functions converts the glyph bitmap found in a FT_GlyphSlot
Packit b749da
 * into a different format (see _compute_xrender_bitmap_size)
Packit b749da
 *
Packit b749da
 * you should call this function after _compute_xrender_bitmap_size
Packit b749da
 *
Packit b749da
 * target :: target bitmap descriptor. Note that its 'buffer' pointer
Packit b749da
 *           must point to memory allocated by the caller
Packit b749da
 *
Packit b749da
 * slot   :: the glyph slot containing the source bitmap
Packit b749da
 *
Packit b749da
 * mode   :: the requested final rendering mode
Packit b749da
 *
Packit b749da
 * bgr    :: boolean, set if BGR or VBGR pixel ordering is needed
Packit b749da
 */
Packit b749da
static void
Packit b749da
_fill_xrender_bitmap( FT_Bitmap*	target,
Packit b749da
		      FT_GlyphSlot	slot,
Packit b749da
		      FT_Render_Mode	mode,
Packit b749da
		      int		bgr )
Packit b749da
{
Packit b749da
    FT_Bitmap*   ftbit = &slot->bitmap;
Packit b749da
Packit b749da
    {
Packit b749da
	unsigned char*	srcLine	= ftbit->buffer;
Packit b749da
        unsigned char*	dstLine	= target->buffer;
Packit b749da
        int		src_pitch = ftbit->pitch;
Packit b749da
        int		width = target->width;
Packit b749da
        int		height = target->rows;
Packit b749da
        int		pitch = target->pitch;
Packit b749da
        int		subpixel;
Packit b749da
        int		h;
Packit b749da
Packit b749da
        subpixel = ( mode == FT_RENDER_MODE_LCD ||
Packit b749da
		     mode == FT_RENDER_MODE_LCD_V );
Packit b749da
Packit b749da
	if ( src_pitch < 0 )
Packit b749da
	    srcLine -= src_pitch*(ftbit->rows-1);
Packit b749da
Packit b749da
	switch ( ftbit->pixel_mode )
Packit b749da
	{
Packit b749da
	case FT_PIXEL_MODE_MONO:
Packit b749da
	    if ( subpixel )  /* convert mono to ARGB32 values */
Packit b749da
	    {
Packit b749da
		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
Packit b749da
		{
Packit b749da
		    int x;
Packit b749da
Packit b749da
		    for ( x = 0; x < width; x++ )
Packit b749da
		    {
Packit b749da
			if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) )
Packit b749da
			    ((unsigned int*)dstLine)[x] = 0xffffffffU;
Packit b749da
		    }
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	    else if ( mode == FT_RENDER_MODE_NORMAL )  /* convert mono to 8-bit gray */
Packit b749da
	    {
Packit b749da
		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
Packit b749da
		{
Packit b749da
		    int x;
Packit b749da
Packit b749da
		    for ( x = 0; x < width; x++ )
Packit b749da
		    {
Packit b749da
			if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) )
Packit b749da
			    dstLine[x] = 0xff;
Packit b749da
		    }
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	    else  /* copy mono to mono */
Packit b749da
	    {
Packit b749da
		int bytes = (width+7) >> 3;
Packit b749da
Packit b749da
		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
Packit b749da
		    memcpy( dstLine, srcLine, bytes );
Packit b749da
	    }
Packit b749da
	    break;
Packit b749da
Packit b749da
	case FT_PIXEL_MODE_GRAY:
Packit b749da
	    if ( subpixel )  /* convert gray to ARGB32 values */
Packit b749da
	    {
Packit b749da
		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
Packit b749da
		{
Packit b749da
		    int		   x;
Packit b749da
		    unsigned int*  dst = (unsigned int*)dstLine;
Packit b749da
Packit b749da
		    for ( x = 0; x < width; x++ )
Packit b749da
		    {
Packit b749da
			unsigned int pix = srcLine[x];
Packit b749da
Packit b749da
			pix |= (pix << 8);
Packit b749da
			pix |= (pix << 16);
Packit b749da
Packit b749da
			dst[x] = pix;
Packit b749da
		    }
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	    else  /* copy gray into gray */
Packit b749da
	    {
Packit b749da
		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
Packit b749da
		    memcpy( dstLine, srcLine, width );
Packit b749da
	    }
Packit b749da
	    break;
Packit b749da
Packit b749da
	case FT_PIXEL_MODE_LCD:
Packit b749da
	    if ( !bgr )
Packit b749da
	    {
Packit b749da
		/* convert horizontal RGB into ARGB32 */
Packit b749da
		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
Packit b749da
		{
Packit b749da
		    int		   x;
Packit b749da
		    unsigned char* src = srcLine;
Packit b749da
		    unsigned int*  dst = (unsigned int*)dstLine;
Packit b749da
Packit b749da
		    for ( x = 0; x < width; x++, src += 3 )
Packit b749da
		    {
Packit b749da
			unsigned int pix;
Packit b749da
Packit b749da
			pix = ((unsigned int)src[0] << 16) |
Packit b749da
			      ((unsigned int)src[1] <<  8) |
Packit b749da
			      ((unsigned int)src[2]      ) |
Packit b749da
			      ((unsigned int)src[1] << 24) ;
Packit b749da
Packit b749da
			dst[x] = pix;
Packit b749da
		    }
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	    else
Packit b749da
	    {
Packit b749da
		/* convert horizontal BGR into ARGB32 */
Packit b749da
		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
Packit b749da
		{
Packit b749da
		    int		   x;
Packit b749da
		    unsigned char* src = srcLine;
Packit b749da
		    unsigned int*  dst = (unsigned int*)dstLine;
Packit b749da
Packit b749da
		    for ( x = 0; x < width; x++, src += 3 )
Packit b749da
		    {
Packit b749da
			unsigned int pix;
Packit b749da
Packit b749da
			pix = ((unsigned int)src[2] << 16) |
Packit b749da
			      ((unsigned int)src[1] <<  8) |
Packit b749da
			      ((unsigned int)src[0]      ) |
Packit b749da
			      ((unsigned int)src[1] << 24) ;
Packit b749da
Packit b749da
			dst[x] = pix;
Packit b749da
		    }
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	    break;
Packit b749da
Packit b749da
	default:  /* FT_PIXEL_MODE_LCD_V */
Packit b749da
	    /* convert vertical RGB into ARGB32 */
Packit b749da
	    if ( !bgr )
Packit b749da
	    {
Packit b749da
		for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch )
Packit b749da
		{
Packit b749da
		    int		   x;
Packit b749da
		    unsigned char* src = srcLine;
Packit b749da
		    unsigned int*  dst = (unsigned int*)dstLine;
Packit b749da
Packit b749da
		    for ( x = 0; x < width; x++, src += 1 )
Packit b749da
		    {
Packit b749da
			unsigned int  pix;
Packit b749da
Packit b749da
			pix = ((unsigned int)src[0]           << 16) |
Packit b749da
			      ((unsigned int)src[src_pitch]   <<  8) |
Packit b749da
			      ((unsigned int)src[src_pitch*2]      ) |
Packit b749da
			      ((unsigned int)src[src_pitch]   << 24) ;
Packit b749da
Packit b749da
			dst[x] = pix;
Packit b749da
		    }
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	    else
Packit b749da
	    {
Packit b749da
	    for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch )
Packit b749da
		{
Packit b749da
		    int		   x;
Packit b749da
		    unsigned char* src = srcLine;
Packit b749da
		    unsigned int*  dst = (unsigned int*)dstLine;
Packit b749da
Packit b749da
		    for ( x = 0; x < width; x++, src += 1 )
Packit b749da
		    {
Packit b749da
			unsigned int  pix;
Packit b749da
Packit b749da
			pix = ((unsigned int)src[src_pitch*2] << 16) |
Packit b749da
			      ((unsigned int)src[src_pitch]   <<  8) |
Packit b749da
			      ((unsigned int)src[0]                ) |
Packit b749da
			      ((unsigned int)src[src_pitch]   << 24) ;
Packit b749da
Packit b749da
			dst[x] = pix;
Packit b749da
		    }
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	}
Packit b749da
    }
Packit b749da
}
Packit b749da
Packit b749da
_X_EXPORT void
Packit b749da
XftFontLoadGlyphs (Display	    *dpy,
Packit b749da
		   XftFont	    *pub,
Packit b749da
		   FcBool	    need_bitmaps,
Packit b749da
		   _Xconst FT_UInt  *glyphs,
Packit b749da
		   int		    nglyph)
Packit b749da
{
Packit b749da
    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
Packit b749da
    XftFontInt	    *font = (XftFontInt *) pub;
Packit b749da
    FT_Error	    error;
Packit b749da
    FT_UInt	    glyphindex;
Packit b749da
    FT_GlyphSlot    glyphslot;
Packit b749da
    XftGlyph	    *xftg;
Packit b749da
    Glyph	    glyph;
Packit b749da
    unsigned char   bufLocal[4096];
Packit b749da
    unsigned char   *bufBitmap = bufLocal;
Packit b749da
    int		    bufSize = sizeof (bufLocal);
Packit b749da
    int		    size;
Packit b749da
    int		    width;
Packit b749da
    int		    height;
Packit b749da
    int		    left, right, top, bottom;
Packit b749da
    FT_Bitmap*	    ftbit;
Packit b749da
    FT_Bitmap	    local;
Packit b749da
    FT_Vector	    vector;
Packit b749da
    FT_Face	    face;
Packit b749da
    FT_Render_Mode  mode = FT_RENDER_MODE_MONO;
Packit b749da
Packit b749da
    if (!info)
Packit b749da
	return;
Packit b749da
Packit b749da
    face = XftLockFace (&font->public);
Packit b749da
Packit b749da
    if (!face)
Packit b749da
	return;
Packit b749da
Packit b749da
    if (font->info.antialias)
Packit b749da
    {
Packit b749da
	switch (font->info.rgba) {
Packit b749da
	case FC_RGBA_RGB:
Packit b749da
	case FC_RGBA_BGR:
Packit b749da
	    mode = FT_RENDER_MODE_LCD;
Packit b749da
	    break;
Packit b749da
	case FC_RGBA_VRGB:
Packit b749da
	case FC_RGBA_VBGR:
Packit b749da
	    mode = FT_RENDER_MODE_LCD_V;
Packit b749da
	    break;
Packit b749da
	default:
Packit b749da
	    mode = FT_RENDER_MODE_NORMAL;
Packit b749da
	}
Packit b749da
    }
Packit b749da
Packit b749da
    while (nglyph--)
Packit b749da
    {
Packit b749da
	glyphindex = *glyphs++;
Packit b749da
	xftg = font->glyphs[glyphindex];
Packit b749da
	if (!xftg)
Packit b749da
	    continue;
Packit b749da
Packit b749da
	if (XftDebug() & XFT_DBG_CACHE)
Packit b749da
	    _XftFontValidateMemory (dpy, pub);
Packit b749da
	/*
Packit b749da
	 * Check to see if this glyph has just been loaded,
Packit b749da
	 * this happens when drawing the same glyph twice
Packit b749da
	 * in a single string
Packit b749da
	 */
Packit b749da
	if (xftg->glyph_memory)
Packit b749da
	    continue;
Packit b749da
Packit b749da
	FT_Library_SetLcdFilter( _XftFTlibrary, font->info.lcd_filter);
Packit b749da
Packit b749da
	error = FT_Load_Glyph (face, glyphindex, font->info.load_flags);
Packit b749da
	if (error)
Packit b749da
	{
Packit b749da
	    /*
Packit b749da
	     * If anti-aliasing or transforming glyphs and
Packit b749da
	     * no outline version exists, fallback to the
Packit b749da
	     * bitmap and let things look bad instead of
Packit b749da
	     * missing the glyph
Packit b749da
	     */
Packit b749da
	    if (font->info.load_flags & FT_LOAD_NO_BITMAP)
Packit b749da
		error = FT_Load_Glyph (face, glyphindex,
Packit b749da
				       font->info.load_flags & ~FT_LOAD_NO_BITMAP);
Packit b749da
	    if (error)
Packit b749da
		continue;
Packit b749da
	}
Packit b749da
Packit b749da
#define FLOOR(x)    ((x) & -64)
Packit b749da
#define CEIL(x)	    (((x)+63) & -64)
Packit b749da
#define TRUNC(x)    ((x) >> 6)
Packit b749da
#define ROUND(x)    (((x)+32) & -64)
Packit b749da
Packit b749da
	glyphslot = face->glyph;
Packit b749da
Packit b749da
	/*
Packit b749da
	 * Embolden if required
Packit b749da
	 */
Packit b749da
	if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot);
Packit b749da
Packit b749da
	/*
Packit b749da
	 * Compute glyph metrics from FreeType information
Packit b749da
	 */
Packit b749da
	if(font->info.transform && glyphslot->format != FT_GLYPH_FORMAT_BITMAP)
Packit b749da
	{
Packit b749da
	    /*
Packit b749da
	     * calculate the true width by transforming all four corners.
Packit b749da
	     */
Packit b749da
	    int xc, yc;
Packit b749da
	    left = right = top = bottom = 0;
Packit b749da
	    for(xc = 0; xc <= 1; xc ++) {
Packit b749da
		for(yc = 0; yc <= 1; yc++) {
Packit b749da
		    vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width;
Packit b749da
		    vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height;
Packit b749da
		    FT_Vector_Transform(&vector, &font->info.matrix);
Packit b749da
		    if (XftDebug() & XFT_DBG_GLYPH)
Packit b749da
			printf("Trans %d %d: %d %d\n", (int) xc, (int) yc,
Packit b749da
			       (int) vector.x, (int) vector.y);
Packit b749da
		    if(xc == 0 && yc == 0) {
Packit b749da
			left = right = vector.x;
Packit b749da
			top = bottom = vector.y;
Packit b749da
		    } else {
Packit b749da
			if(left > vector.x) left = vector.x;
Packit b749da
			if(right < vector.x) right = vector.x;
Packit b749da
			if(bottom > vector.y) bottom = vector.y;
Packit b749da
			if(top < vector.y) top = vector.y;
Packit b749da
		    }
Packit b749da
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	    left = FLOOR(left);
Packit b749da
	    right = CEIL(right);
Packit b749da
	    bottom = FLOOR(bottom);
Packit b749da
	    top = CEIL(top);
Packit b749da
Packit b749da
	} else {
Packit b749da
	    left  = FLOOR( glyphslot->metrics.horiBearingX );
Packit b749da
	    right = CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width );
Packit b749da
Packit b749da
	    top    = CEIL( glyphslot->metrics.horiBearingY );
Packit b749da
	    bottom = FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height );
Packit b749da
	}
Packit b749da
Packit b749da
	width = TRUNC(right - left);
Packit b749da
	height = TRUNC( top - bottom );
Packit b749da
Packit b749da
	/*
Packit b749da
	 * Clip charcell glyphs to the bounding box
Packit b749da
	 * XXX transformed?
Packit b749da
	 */
Packit b749da
	if (font->info.spacing >= FC_CHARCELL && !font->info.transform)
Packit b749da
	{
Packit b749da
	    if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
Packit b749da
	    {
Packit b749da
		if (TRUNC(bottom) > font->public.max_advance_width)
Packit b749da
		{
Packit b749da
		    int adjust;
Packit b749da
Packit b749da
		    adjust = bottom - (font->public.max_advance_width << 6);
Packit b749da
		    if (adjust > top)
Packit b749da
			adjust = top;
Packit b749da
		    top -= adjust;
Packit b749da
		    bottom -= adjust;
Packit b749da
		    height = font->public.max_advance_width;
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	    else
Packit b749da
	    {
Packit b749da
		if (TRUNC(right) > font->public.max_advance_width)
Packit b749da
		{
Packit b749da
		    int adjust;
Packit b749da
Packit b749da
		    adjust = right - (font->public.max_advance_width << 6);
Packit b749da
		    if (adjust > left)
Packit b749da
			adjust = left;
Packit b749da
		    left -= adjust;
Packit b749da
		    right -= adjust;
Packit b749da
		    width = font->public.max_advance_width;
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	}
Packit b749da
Packit b749da
	if ( glyphslot->format != FT_GLYPH_FORMAT_BITMAP )
Packit b749da
	{
Packit b749da
	    error = FT_Render_Glyph( face->glyph, mode );
Packit b749da
	    if (error)
Packit b749da
		continue;
Packit b749da
	}
Packit b749da
Packit b749da
	FT_Library_SetLcdFilter( _XftFTlibrary, FT_LCD_FILTER_NONE );
Packit b749da
Packit b749da
	if (font->info.spacing >= FC_MONO)
Packit b749da
	{
Packit b749da
	    if (font->info.transform)
Packit b749da
	    {
Packit b749da
		if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
Packit b749da
		{
Packit b749da
		    vector.x = 0;
Packit b749da
		    vector.y = -face->size->metrics.max_advance;
Packit b749da
		}
Packit b749da
		else
Packit b749da
		{
Packit b749da
		    vector.x = face->size->metrics.max_advance;
Packit b749da
		    vector.y = 0;
Packit b749da
		}
Packit b749da
		FT_Vector_Transform (&vector, &font->info.matrix);
Packit b749da
		xftg->metrics.xOff = vector.x >> 6;
Packit b749da
		xftg->metrics.yOff = -(vector.y >> 6);
Packit b749da
	    }
Packit b749da
	    else
Packit b749da
	    {
Packit b749da
		if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
Packit b749da
		{
Packit b749da
		    xftg->metrics.xOff = 0;
Packit b749da
		    xftg->metrics.yOff = -font->public.max_advance_width;
Packit b749da
		}
Packit b749da
		else
Packit b749da
		{
Packit b749da
		    xftg->metrics.xOff = font->public.max_advance_width;
Packit b749da
		    xftg->metrics.yOff = 0;
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	}
Packit b749da
	else
Packit b749da
	{
Packit b749da
	    xftg->metrics.xOff = TRUNC(ROUND(glyphslot->advance.x));
Packit b749da
	    xftg->metrics.yOff = -TRUNC(ROUND(glyphslot->advance.y));
Packit b749da
	}
Packit b749da
Packit b749da
	// compute the size of the final bitmap
Packit b749da
	ftbit = &glyphslot->bitmap;
Packit b749da
Packit b749da
	width = ftbit->width;
Packit b749da
	height = ftbit->rows;
Packit b749da
Packit b749da
	if (XftDebug() & XFT_DBG_GLYPH)
Packit b749da
	{
Packit b749da
	    printf ("glyph %d:\n", (int) glyphindex);
Packit b749da
	    printf (" xywh (%d %d %d %d), trans (%d %d %d %d) wh (%d %d)\n",
Packit b749da
		    (int) glyphslot->metrics.horiBearingX,
Packit b749da
		    (int) glyphslot->metrics.horiBearingY,
Packit b749da
		    (int) glyphslot->metrics.width,
Packit b749da
		    (int) glyphslot->metrics.height,
Packit b749da
		    left, right, top, bottom,
Packit b749da
		    width, height);
Packit b749da
	    if (XftDebug() & XFT_DBG_GLYPHV)
Packit b749da
	    {
Packit b749da
		int		x, y;
Packit b749da
		unsigned char	*line;
Packit b749da
Packit b749da
		line = ftbit->buffer;
Packit b749da
		if (ftbit->pitch < 0)
Packit b749da
		    line -= ftbit->pitch*(height-1);
Packit b749da
Packit b749da
		for (y = 0; y < height; y++)
Packit b749da
		{
Packit b749da
		    if (font->info.antialias)
Packit b749da
		    {
Packit b749da
			static const char    den[] = { " .:;=+*#" };
Packit b749da
			for (x = 0; x < width; x++)
Packit b749da
			    printf ("%c", den[line[x] >> 5]);
Packit b749da
		    }
Packit b749da
		    else
Packit b749da
		    {
Packit b749da
			for (x = 0; x < width * 8; x++)
Packit b749da
			{
Packit b749da
			    printf ("%c", line[x>>3] & (1 << (x & 7)) ? '#' : ' ');
Packit b749da
			}
Packit b749da
		    }
Packit b749da
		    printf ("|\n");
Packit b749da
		    line += ftbit->pitch;
Packit b749da
		}
Packit b749da
		printf ("\n");
Packit b749da
	    }
Packit b749da
	}
Packit b749da
Packit b749da
	size = _compute_xrender_bitmap_size( &local, glyphslot, mode );
Packit b749da
	if ( size < 0 )
Packit b749da
	    continue;
Packit b749da
Packit b749da
	xftg->metrics.width  = local.width;
Packit b749da
	xftg->metrics.height = local.rows;
Packit b749da
	xftg->metrics.x      = - glyphslot->bitmap_left;
Packit b749da
	xftg->metrics.y      =   glyphslot->bitmap_top;
Packit b749da
Packit b749da
	/*
Packit b749da
	 * If the glyph is relatively large (> 1% of server memory),
Packit b749da
	 * don't send it until necessary.
Packit b749da
	 */
Packit b749da
	if (!need_bitmaps && size > info->max_glyph_memory / 100)
Packit b749da
	    continue;
Packit b749da
Packit b749da
	/*
Packit b749da
	 * Make sure there is enough buffer space for the glyph.
Packit b749da
	 */
Packit b749da
	if (size > bufSize)
Packit b749da
	{
Packit b749da
	    if (bufBitmap != bufLocal)
Packit b749da
		free (bufBitmap);
Packit b749da
	    bufBitmap = (unsigned char *) malloc (size);
Packit b749da
	    if (!bufBitmap)
Packit b749da
		continue;
Packit b749da
	    bufSize = size;
Packit b749da
	}
Packit b749da
	memset (bufBitmap, 0, size);
Packit b749da
Packit b749da
	local.buffer = bufBitmap;
Packit b749da
Packit b749da
	_fill_xrender_bitmap( &local, glyphslot, mode,
Packit b749da
			      (font->info.rgba == FC_RGBA_BGR ||
Packit b749da
			       font->info.rgba == FC_RGBA_VBGR ) );
Packit b749da
Packit b749da
	/*
Packit b749da
	 * Copy or convert into local buffer.
Packit b749da
	 */
Packit b749da
Packit b749da
	/*
Packit b749da
	 * Use the glyph index as the wire encoding; it
Packit b749da
	 * might be more efficient for some locales to map
Packit b749da
	 * these by first usage to smaller values, but that
Packit b749da
	 * would require persistently storing the map when
Packit b749da
	 * glyphs were freed.
Packit b749da
	 */
Packit b749da
	glyph = (Glyph) glyphindex;
Packit b749da
Packit b749da
	xftg->glyph_memory = size + sizeof (XftGlyph);
Packit b749da
	if (font->format)
Packit b749da
	{
Packit b749da
	    if (!font->glyphset)
Packit b749da
		font->glyphset = XRenderCreateGlyphSet (dpy, font->format);
Packit b749da
	    if ( mode == FT_RENDER_MODE_MONO )
Packit b749da
	    {
Packit b749da
		/* swap bits in each byte */
Packit b749da
		if (BitmapBitOrder (dpy) != MSBFirst)
Packit b749da
		{
Packit b749da
		    unsigned char   *line = (unsigned char*)bufBitmap;
Packit b749da
		    int		    i = size;
Packit b749da
Packit b749da
		    while (i--)
Packit b749da
		    {
Packit b749da
			int c = *line;
Packit b749da
			c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
Packit b749da
			c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
Packit b749da
			c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
Packit b749da
			*line++ = c;
Packit b749da
		    }
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	    else if ( mode != FT_RENDER_MODE_NORMAL )
Packit b749da
	    {
Packit b749da
		/* invert ARGB <=> BGRA */
Packit b749da
		if (ImageByteOrder (dpy) != XftNativeByteOrder ())
Packit b749da
		    XftSwapCARD32 ((CARD32 *) bufBitmap, size >> 2);
Packit b749da
	    }
Packit b749da
	    XRenderAddGlyphs (dpy, font->glyphset, &glyph,
Packit b749da
			      &xftg->metrics, 1,
Packit b749da
			      (char *) bufBitmap, size);
Packit b749da
	}
Packit b749da
	else
Packit b749da
	{
Packit b749da
	    if (size)
Packit b749da
	    {
Packit b749da
		xftg->bitmap = malloc (size);
Packit b749da
		if (xftg->bitmap)
Packit b749da
		    memcpy (xftg->bitmap, bufBitmap, size);
Packit b749da
	    }
Packit b749da
	    else
Packit b749da
		xftg->bitmap = NULL;
Packit b749da
	}
Packit b749da
Packit b749da
	font->glyph_memory += xftg->glyph_memory;
Packit b749da
	info->glyph_memory += xftg->glyph_memory;
Packit b749da
	if (XftDebug() & XFT_DBG_CACHE)
Packit b749da
	    _XftFontValidateMemory (dpy, pub);
Packit b749da
	if (XftDebug() & XFT_DBG_CACHEV)
Packit b749da
	    printf ("Caching glyph 0x%x size %ld\n", glyphindex,
Packit b749da
		    xftg->glyph_memory);
Packit b749da
    }
Packit b749da
    if (bufBitmap != bufLocal)
Packit b749da
	free (bufBitmap);
Packit b749da
    XftUnlockFace (&font->public);
Packit b749da
}
Packit b749da
Packit b749da
_X_EXPORT void
Packit b749da
XftFontUnloadGlyphs (Display		*dpy,
Packit b749da
		     XftFont		*pub,
Packit b749da
		     _Xconst FT_UInt	*glyphs,
Packit b749da
		     int		nglyph)
Packit b749da
{
Packit b749da
    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
Packit b749da
    XftFontInt	    *font = (XftFontInt *) pub;
Packit b749da
    XftGlyph	    *xftg;
Packit b749da
    FT_UInt	    glyphindex;
Packit b749da
    Glyph	    glyphBuf[1024];
Packit b749da
    int		    nused;
Packit b749da
Packit b749da
    nused = 0;
Packit b749da
    while (nglyph--)
Packit b749da
    {
Packit b749da
	glyphindex = *glyphs++;
Packit b749da
	xftg = font->glyphs[glyphindex];
Packit b749da
	if (!xftg)
Packit b749da
	    continue;
Packit b749da
	if (xftg->glyph_memory)
Packit b749da
	{
Packit b749da
	    if (font->format)
Packit b749da
	    {
Packit b749da
		if (font->glyphset)
Packit b749da
		{
Packit b749da
		    glyphBuf[nused++] = (Glyph) glyphindex;
Packit b749da
		    if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0]))
Packit b749da
		    {
Packit b749da
			XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused);
Packit b749da
			nused = 0;
Packit b749da
		    }
Packit b749da
		}
Packit b749da
	    }
Packit b749da
	    else
Packit b749da
	    {
Packit b749da
		if (xftg->bitmap)
Packit b749da
		    free (xftg->bitmap);
Packit b749da
	    }
Packit b749da
	    font->glyph_memory -= xftg->glyph_memory;
Packit b749da
	    if (info)
Packit b749da
		info->glyph_memory -= xftg->glyph_memory;
Packit b749da
	}
Packit b749da
	free (xftg);
Packit b749da
	XftMemFree (XFT_MEM_GLYPH, sizeof (XftGlyph));
Packit b749da
	font->glyphs[glyphindex] = NULL;
Packit b749da
    }
Packit b749da
    if (font->glyphset && nused)
Packit b749da
	XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused);
Packit b749da
}
Packit b749da
Packit b749da
_X_EXPORT FcBool
Packit b749da
XftFontCheckGlyph (Display	*dpy,
Packit b749da
		   XftFont	*pub,
Packit b749da
		   FcBool	need_bitmaps,
Packit b749da
		   FT_UInt	glyph,
Packit b749da
		   FT_UInt	*missing,
Packit b749da
		   int		*nmissing)
Packit b749da
{
Packit b749da
    XftFontInt	    *font = (XftFontInt *) pub;
Packit b749da
    XftGlyph	    *xftg;
Packit b749da
    int		    n;
Packit b749da
Packit b749da
    if (glyph >= font->num_glyphs)
Packit b749da
	return FcFalse;
Packit b749da
    xftg = font->glyphs[glyph];
Packit b749da
    if (!xftg || (need_bitmaps && !xftg->glyph_memory))
Packit b749da
    {
Packit b749da
	if (!xftg)
Packit b749da
	{
Packit b749da
	    xftg = (XftGlyph *) malloc (sizeof (XftGlyph));
Packit b749da
	    if (!xftg)
Packit b749da
		return FcFalse;
Packit b749da
	    XftMemAlloc (XFT_MEM_GLYPH, sizeof (XftGlyph));
Packit b749da
	    xftg->bitmap = NULL;
Packit b749da
	    xftg->glyph_memory = 0;
Packit b749da
	    font->glyphs[glyph] = xftg;
Packit b749da
	}
Packit b749da
	n = *nmissing;
Packit b749da
	missing[n++] = glyph;
Packit b749da
	if (n == XFT_NMISSING)
Packit b749da
	{
Packit b749da
	    XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n);
Packit b749da
	    n = 0;
Packit b749da
	}
Packit b749da
	*nmissing = n;
Packit b749da
	return FcTrue;
Packit b749da
    }
Packit b749da
    else
Packit b749da
	return FcFalse;
Packit b749da
}
Packit b749da
Packit b749da
_X_EXPORT FcBool
Packit b749da
XftCharExists (Display	    *dpy,
Packit b749da
	       XftFont	    *pub,
Packit b749da
	       FcChar32    ucs4)
Packit b749da
{
Packit b749da
    if (pub->charset)
Packit b749da
	return FcCharSetHasChar (pub->charset, ucs4);
Packit b749da
    return FcFalse;
Packit b749da
}
Packit b749da
Packit b749da
#define Missing	    ((FT_UInt) ~0)
Packit b749da
Packit b749da
_X_EXPORT FT_UInt
Packit b749da
XftCharIndex (Display	    *dpy,
Packit b749da
	      XftFont	    *pub,
Packit b749da
	      FcChar32	    ucs4)
Packit b749da
{
Packit b749da
    XftFontInt	*font = (XftFontInt *) pub;
Packit b749da
    FcChar32	ent, offset;
Packit b749da
    FT_Face	face;
Packit b749da
Packit b749da
    if (!font->hash_value)
Packit b749da
	return 0;
Packit b749da
Packit b749da
    ent = ucs4 % font->hash_value;
Packit b749da
    offset = 0;
Packit b749da
    while (font->hash_table[ent].ucs4 != ucs4)
Packit b749da
    {
Packit b749da
	if (font->hash_table[ent].ucs4 == (FcChar32) ~0)
Packit b749da
	{
Packit b749da
	    if (!XftCharExists (dpy, pub, ucs4))
Packit b749da
		return 0;
Packit b749da
	    face  = XftLockFace (pub);
Packit b749da
	    if (!face)
Packit b749da
		return 0;
Packit b749da
	    font->hash_table[ent].ucs4 = ucs4;
Packit b749da
	    font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4);
Packit b749da
	    XftUnlockFace (pub);
Packit b749da
	    break;
Packit b749da
	}
Packit b749da
	if (!offset)
Packit b749da
	{
Packit b749da
	    offset = ucs4 % font->rehash_value;
Packit b749da
	    if (!offset)
Packit b749da
		offset = 1;
Packit b749da
	}
Packit b749da
	ent = ent + offset;
Packit b749da
	if (ent >= font->hash_value)
Packit b749da
	    ent -= font->hash_value;
Packit b749da
    }
Packit b749da
    return font->hash_table[ent].glyph;
Packit b749da
}
Packit b749da
Packit b749da
/*
Packit b749da
 * Pick a random glyph from the font and remove it from the cache
Packit b749da
 */
Packit b749da
_X_HIDDEN void
Packit b749da
_XftFontUncacheGlyph (Display *dpy, XftFont *pub)
Packit b749da
{
Packit b749da
    XftFontInt	    *font = (XftFontInt *) pub;
Packit b749da
    unsigned long   glyph_memory;
Packit b749da
    FT_UInt	    glyphindex;
Packit b749da
    XftGlyph	    *xftg;
Packit b749da
Packit b749da
    if (!font->glyph_memory)
Packit b749da
	return;
Packit b749da
    if (font->use_free_glyphs)
Packit b749da
    {
Packit b749da
	glyph_memory = rand() % font->glyph_memory;
Packit b749da
    }
Packit b749da
    else
Packit b749da
    {
Packit b749da
	if (font->glyphset)
Packit b749da
	{
Packit b749da
	    XRenderFreeGlyphSet (dpy, font->glyphset);
Packit b749da
	    font->glyphset = 0;
Packit b749da
	}
Packit b749da
	glyph_memory = 0;
Packit b749da
    }
Packit b749da
Packit b749da
    if (XftDebug() & XFT_DBG_CACHE)
Packit b749da
	_XftFontValidateMemory (dpy, pub);
Packit b749da
    for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++)
Packit b749da
    {
Packit b749da
	xftg = font->glyphs[glyphindex];
Packit b749da
	if (xftg)
Packit b749da
	{
Packit b749da
	    if (xftg->glyph_memory > glyph_memory)
Packit b749da
	    {
Packit b749da
		if (XftDebug() & XFT_DBG_CACHEV)
Packit b749da
		    printf ("Uncaching glyph 0x%x size %ld\n",
Packit b749da
			    glyphindex, xftg->glyph_memory);
Packit b749da
		XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1);
Packit b749da
		if (!font->use_free_glyphs)
Packit b749da
		    continue;
Packit b749da
		break;
Packit b749da
	    }
Packit b749da
	    glyph_memory -= xftg->glyph_memory;
Packit b749da
	}
Packit b749da
    }
Packit b749da
    if (XftDebug() & XFT_DBG_CACHE)
Packit b749da
	_XftFontValidateMemory (dpy, pub);
Packit b749da
}
Packit b749da
Packit b749da
_X_HIDDEN void
Packit b749da
_XftFontManageMemory (Display *dpy, XftFont *pub)
Packit b749da
{
Packit b749da
    XftFontInt	*font = (XftFontInt *) pub;
Packit b749da
Packit b749da
    if (font->max_glyph_memory)
Packit b749da
    {
Packit b749da
	if (XftDebug() & XFT_DBG_CACHE)
Packit b749da
	{
Packit b749da
	    if (font->glyph_memory > font->max_glyph_memory)
Packit b749da
		printf ("Reduce memory for font 0x%lx from %ld to %ld\n",
Packit b749da
			font->glyphset ? font->glyphset : (unsigned long) font,
Packit b749da
			font->glyph_memory, font->max_glyph_memory);
Packit b749da
	}
Packit b749da
	while (font->glyph_memory > font->max_glyph_memory)
Packit b749da
	    _XftFontUncacheGlyph (dpy, pub);
Packit b749da
    }
Packit b749da
    _XftDisplayManageMemory (dpy);
Packit b749da
}