/************************************************************************
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.

                        All Rights Reserved

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
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 Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.

DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL 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.

************************************************************************/
/* The panoramix components contained the following notice */
/*
Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software.

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of Digital Equipment Corporation
shall not be used in advertising or otherwise to promote the sale, use or other
dealings in this Software without prior written authorization from Digital
Equipment Corporation.

******************************************************************/

#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

#include <nx-X11/X.h>
#include <nx-X11/Xmd.h>
#include <nx-X11/Xproto.h>
#include "scrnintstr.h"
#include "resource.h"
#include "dixstruct.h"
#include "cursorstr.h"
#include "list.h"
#include "misc.h"
#include "opaque.h"
#include "dixfontstr.h"
#include "closestr.h"
#ifdef HAS_XFONT2
# include <X11/fonts/libxfont2.h>
#endif /* HAS_XFONT2 */

#ifdef DEBUG
#include	<stdio.h>
#endif

#ifdef PANORAMIX
#include "panoramiX.h"
#endif

#ifdef XF86BIGFONT
#define _XF86BIGFONT_SERVER_
#include <nx-X11/extensions/xf86bigfont.h>
#endif

#define QUERYCHARINFO(pci, pr)  *(pr) = (pci)->metrics

#ifndef HAS_XFONT2
extern void register_fpe_functions(void);
#endif

extern void * fosNaturalParams;
extern FontPtr defaultFont;

static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
static int  num_fpes = 0;
#ifdef HAS_XFONT2
xfont2_fpe_funcs_rec const **fpe_functions;
#else
FPEFunctions *fpe_functions = (FPEFunctions *) 0;
#endif
static int  num_fpe_types = 0;

static unsigned char *font_path_string;

static int  num_slept_fpes = 0;
static int  size_slept_fpes = 0;
static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
#ifdef HAS_XFONT2
xfont2_pattern_cache_ptr patternCache;
#else
static FontPatternCachePtr patternCache;
#endif /* HAS_FONT2 */

int
FontToXError(err)
    int         err;
{
    switch (err) {
    case Successful:
	return Success;
    case AllocError:
	return BadAlloc;
    case BadFontName:
	return BadName;
    case BadFontPath:
    case BadFontFormat:	/* is there something better? */
    case BadCharRange:
	return BadValue;
    default:
	return err;
    }
}


/*
 * adding RT_FONT prevents conflict with default cursor font
 */
Bool
SetDefaultFont(char *defaultfontname)
{
    int         err;
    FontPtr     pf;
    XID         fid;

    fid = FakeClientID(0);
    err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync,
		   (unsigned) strlen(defaultfontname), defaultfontname);
    if (err != Success)
	return FALSE;
    pf = (FontPtr) LookupIDByType(fid, RT_FONT);
    if (pf == (FontPtr) NULL)
	return FALSE;
    defaultFont = pf;
    return TRUE;
}

/*
 * note that the font wakeup queue is not refcounted.  this is because
 * an fpe needs to be added when it's inited, and removed when it's finally
 * freed, in order to handle any data that isn't requested, like FS events.
 *
 * since the only thing that should call these routines is the renderer's
 * init_fpe() and free_fpe(), there shouldn't be any problem in using
 * freed data.
 */
void
QueueFontWakeup(FontPathElementPtr fpe)
{
    int         i;
    FontPathElementPtr *new;

    for (i = 0; i < num_slept_fpes; i++) {
	if (slept_fpes[i] == fpe) {

#ifdef DEBUG
	    fprintf(stderr, "re-queueing fpe wakeup\n");
#endif

	    return;
	}
    }
    if (num_slept_fpes == size_slept_fpes) {
	new = (FontPathElementPtr *)
	    realloc(slept_fpes,
		     sizeof(FontPathElementPtr) * (size_slept_fpes + 4));
	if (!new)
	    return;
	slept_fpes = new;
	size_slept_fpes += 4;
    }
    slept_fpes[num_slept_fpes] = fpe;
    num_slept_fpes++;
}

void
RemoveFontWakeup(FontPathElementPtr fpe)
{
    int         i,
                j;

    for (i = 0; i < num_slept_fpes; i++) {
	if (slept_fpes[i] == fpe) {
	    for (j = i; j < num_slept_fpes; j++) {
		slept_fpes[j] = slept_fpes[j + 1];
	    }
	    num_slept_fpes--;
	    return;
	}
    }
}

void
FontWakeup(void * data, int count, void * LastSelectMask)
{
    int         i;
    FontPathElementPtr fpe;

    if (count < 0)
	return;
    /* wake up any fpe's that may be waiting for information */
    for (i = 0; i < num_slept_fpes; i++) {
	fpe = slept_fpes[i];
#ifdef HAS_XFONT2
	(void) (*fpe_functions[fpe->type]->wakeup_fpe) (fpe);
#else
	(void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask);
#endif /* HAS_XFONT2 */
    }
}

/* XXX -- these two funcs may want to be broken into macros */
static void
UseFPE(FontPathElementPtr fpe)
{
    fpe->refcount++;
}

static void
FreeFPE (FontPathElementPtr fpe)
{
    fpe->refcount--;
    if (fpe->refcount == 0) {
#ifdef HAS_XFONT2
	(*fpe_functions[fpe->type]->free_fpe) (fpe);
#else
	(*fpe_functions[fpe->type].free_fpe) (fpe);
#endif
	free(fpe->name);
	free(fpe);
    }
}

#ifndef NXAGENT_SERVER
static Bool
doOpenFont(ClientPtr client, OFclosurePtr c)
{
    FontPtr     pfont = NullFont;
    FontPathElementPtr fpe = NULL;
    ScreenPtr   pScr;
    int         err = Successful;
    int         i;
    char       *alias,
               *newname;
    int         newlen;
    int		aliascount = 20;
    /*
     * Decide at runtime what FontFormat to use.
     */
    Mask FontFormat = 

	((screenInfo.imageByteOrder == LSBFirst) ?
	    BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) |

	((screenInfo.bitmapBitOrder == LSBFirst) ?
	    BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) |

	BitmapFormatImageRectMin |

#if GLYPHPADBYTES == 1
	BitmapFormatScanlinePad8 |
#endif

#if GLYPHPADBYTES == 2
	BitmapFormatScanlinePad16 |
#endif

#if GLYPHPADBYTES == 4
	BitmapFormatScanlinePad32 |
#endif

#if GLYPHPADBYTES == 8
	BitmapFormatScanlinePad64 |
#endif

	BitmapFormatScanlineUnit8;

    if (client->clientGone)
    {
	if (c->current_fpe < c->num_fpes)
	{
	    fpe = c->fpe_list[c->current_fpe];
#ifdef HAS_XFONT2
	    (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	    (*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif /* HAS_XFONT2 */
	}
	err = Successful;
	goto bail;
    }
    while (c->current_fpe < c->num_fpes) {
	fpe = c->fpe_list[c->current_fpe];
#ifdef HAS_XFONT2
	err = (*fpe_functions[fpe->type]->open_font)
#else
	err = (*fpe_functions[fpe->type].open_font)
#endif /* HAS_XFONT2 */
	    ((void *) client, fpe, c->flags,
	     c->fontname, c->fnamelen, FontFormat,
	     BitmapFormatMaskByte |
	     BitmapFormatMaskBit |
	     BitmapFormatMaskImageRectangle |
	     BitmapFormatMaskScanLinePad |
	     BitmapFormatMaskScanLineUnit,
	     c->fontid, &pfont, &alias,
	     c->non_cachable_font && c->non_cachable_font->fpe == fpe ?
		 c->non_cachable_font :
		 (FontPtr)0);

	if (err == FontNameAlias && alias) {
	    newlen = strlen(alias);
	    newname = (char *) realloc(c->fontname, newlen);
	    if (!newname) {
		err = AllocError;
		break;
	    }
	    memmove(newname, alias, newlen);
	    c->fontname = newname;
	    c->fnamelen = newlen;
	    c->current_fpe = 0;
	    if (--aliascount <= 0)
		break;
	    continue;
	}
	if (err == BadFontName) {
	    c->current_fpe++;
	    continue;
	}
	if (err == Suspended) {
	    if (!c->slept) {
		c->slept = TRUE;
		ClientSleep(client, (ClientSleepProcPtr)doOpenFont, (void *) c);
	    }
	    return TRUE;
	}
	break;
    }

    if (err != Successful)
	goto bail;
    if (!pfont) {
	err = BadFontName;
	goto bail;
    }
    /* check values for firstCol, lastCol, firstRow, and lastRow */
    if (pfont->info.firstCol > pfont->info.lastCol ||
       pfont->info.firstRow > pfont->info.lastRow ||
       pfont->info.lastCol - pfont->info.firstCol > 255) {
       err = AllocError;
       goto bail;
    }
    if (!pfont->fpe)
	pfont->fpe = fpe;
    pfont->refcnt++;
    if (pfont->refcnt == 1) {
	UseFPE(pfont->fpe);
	for (i = 0; i < screenInfo.numScreens; i++) {
	    pScr = screenInfo.screens[i];
	    if (pScr->RealizeFont)
	    {
		if (!(*pScr->RealizeFont) (pScr, pfont))
		{
		    CloseFont (pfont, (Font) 0);
		    err = AllocError;
		    goto bail;
		}
	    }
	}
    }
    if (!AddResource(c->fontid, RT_FONT, (void *) pfont)) {
	err = AllocError;
	goto bail;
    }
    if (patternCache && pfont != c->non_cachable_font)
#ifdef HAS_XFONT2
	xfont2_cache_font_pattern(patternCache, c->origFontName, c->origFontNameLen,
#else
	CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen,
#endif /* HAS_XFONT2 */
			 pfont);
bail:
    if (err != Successful && c->client != serverClient) {
	SendErrorToClient(c->client, X_OpenFont, 0,
			  c->fontid, FontToXError(err));
    }
    if (c->slept)
	ClientWakeup(c->client);
    for (i = 0; i < c->num_fpes; i++) {
	FreeFPE(c->fpe_list[i]);
    }
    free(c->fpe_list);
    free(c->fontname);
    free(c);
    return TRUE;
}
#endif /* NXAGENT_SERVER */

int
OpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, char *pfontname)
{
    OFclosurePtr c;
    int         i;
    FontPtr     cached = (FontPtr)0;

#ifdef FONTDEBUG
    char *f;
    f = (char *)malloc(lenfname + 1);
    memmove(f, pfontname, lenfname);
    f[lenfname] = '\0';
    ErrorF("OpenFont: fontname is \"%s\"\n", f);
    free(f);
#endif
    if (!lenfname || lenfname > XLFDMAXFONTNAMELEN)
	return BadName;
    if (patternCache)
    {

    /*
    ** Check name cache.  If we find a cached version of this font that
    ** is cachable, immediately satisfy the request with it.  If we find
    ** a cached version of this font that is non-cachable, we do not
    ** satisfy the request with it.  Instead, we pass the FontPtr to the
    ** FPE's open_font code (the fontfile FPE in turn passes the
    ** information to the rasterizer; the fserve FPE ignores it).
    **
    ** Presumably, the font is marked non-cachable because the FPE has
    ** put some licensing restrictions on it.  If the FPE, using
    ** whatever logic it relies on, determines that it is willing to
    ** share this existing font with the client, then it has the option
    ** to return the FontPtr we passed it as the newly-opened font.
    ** This allows the FPE to exercise its licensing logic without
    ** having to create another instance of a font that already exists.
    */

#ifdef HAS_XFONT2
	cached = xfont2_find_cached_font_pattern(patternCache, pfontname, lenfname);
#else
	cached = FindCachedFontPattern(patternCache, pfontname, lenfname);
#endif /* HAS_XFONT2 */
	if (cached && cached->info.cachable)
	{
	    if (!AddResource(fid, RT_FONT, (void *) cached))
		return BadAlloc;
	    cached->refcnt++;
	    return Success;
	}
    }
    c = (OFclosurePtr) malloc(sizeof(OFclosureRec));
    if (!c)
	return BadAlloc;
    c->fontname = (char *) malloc(lenfname);
    c->origFontName = pfontname;
    c->origFontNameLen = lenfname;
    if (!c->fontname) {
	free(c);
	return BadAlloc;
    }
    /*
     * copy the current FPE list, so that if it gets changed by another client
     * while we're blocking, the request still appears atomic
     */
    c->fpe_list = (FontPathElementPtr *)
	malloc(sizeof(FontPathElementPtr) * num_fpes);
    if (!c->fpe_list) {
	free(c->fontname);
	free(c);
	return BadAlloc;
    }
    memmove(c->fontname, pfontname, lenfname);
    for (i = 0; i < num_fpes; i++) {
	c->fpe_list[i] = font_path_elements[i];
	UseFPE(c->fpe_list[i]);
    }
    c->client = client;
    c->fontid = fid;
    c->current_fpe = 0;
    c->num_fpes = num_fpes;
    c->fnamelen = lenfname;
    c->slept = FALSE;
    c->flags = flags;
    c->non_cachable_font = cached;

    (void) doOpenFont(client, c);
    return Success;
}

/**
 * Decrement font's ref count, and free storage if ref count equals zero
 *
 *  \param value must conform to DeleteType
 */
int
CloseFont(void * value, XID fid)
{
    int         nscr;
    ScreenPtr   pscr;
    FontPathElementPtr fpe;
    FontPtr     pfont = (FontPtr)value;

    if (pfont == NullFont)
	return (Success);
    if (--pfont->refcnt == 0) {
	if (patternCache)
#ifdef HAS_XFONT2
	    xfont2_remove_cached_font_pattern(patternCache, pfont);
#else
	    RemoveCachedFontPattern (patternCache, pfont);
#endif /* HAS_XFONT2 */
	/*
	 * since the last reference is gone, ask each screen to free any
	 * storage it may have allocated locally for it.
	 */
	for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
	    pscr = screenInfo.screens[nscr];
	    if (pscr->UnrealizeFont)
		(*pscr->UnrealizeFont) (pscr, pfont);
	}
	if (pfont == defaultFont)
	    defaultFont = NULL;
#ifdef XF86BIGFONT
	XF86BigfontFreeFontShm(pfont);
#endif
	fpe = pfont->fpe;
#ifdef HAS_XFONT2
	(*fpe_functions[fpe->type]->close_font) (fpe, pfont);
#else
	(*fpe_functions[fpe->type].close_font) (fpe, pfont);
#endif
	FreeFPE(fpe);
    }
    return (Success);
}


/***====================================================================***/

/**
 * Sets up pReply as the correct QueryFontReply for pFont with the first
 * nProtoCCIStructs char infos.
 *
 *  \param pReply caller must allocate this storage
  */
void
QueryFont(FontPtr pFont, xQueryFontReply *pReply, int nProtoCCIStructs)
{
    FontPropPtr      pFP;
    int              r,
                     c,
                     i;
    xFontProp       *prFP;
    xCharInfo       *prCI;
    xCharInfo       *charInfos[256];
    unsigned char    chars[512];
    int              ninfos;
    unsigned long    ncols;
    unsigned long    count;

    /* pr->length set in dispatch */
    pReply->minCharOrByte2 = pFont->info.firstCol;
    pReply->defaultChar = pFont->info.defaultCh;
    pReply->maxCharOrByte2 = pFont->info.lastCol;
    pReply->drawDirection = pFont->info.drawDirection;
    pReply->allCharsExist = pFont->info.allExist;
    pReply->minByte1 = pFont->info.firstRow;
    pReply->maxByte1 = pFont->info.lastRow;
    pReply->fontAscent = pFont->info.fontAscent;
    pReply->fontDescent = pFont->info.fontDescent;

    pReply->minBounds = pFont->info.ink_minbounds;
    pReply->maxBounds = pFont->info.ink_maxbounds;

    pReply->nFontProps = pFont->info.nprops;
    pReply->nCharInfos = nProtoCCIStructs;

    for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]);
	    i < pFont->info.nprops;
	    i++, pFP++, prFP++) {
	prFP->name = pFP->name;
	prFP->value = pFP->value;
    }

    ninfos = 0;
    ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1);
    prCI = (xCharInfo *) (prFP);
    for (r = pFont->info.firstRow;
	    ninfos < nProtoCCIStructs && r <= (int)pFont->info.lastRow;
	    r++) {
	i = 0;
	for (c = pFont->info.firstCol; c <= (int)pFont->info.lastCol; c++) {
	    chars[i++] = r;
	    chars[i++] = c;
	}
	(*pFont->get_metrics) (pFont, ncols, chars, 
				TwoD16Bit, &count, charInfos);
	i = 0;
	for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) {
	    *prCI = *charInfos[i];
	    prCI++;
	    ninfos++;
	}
    }
    return;
}

#ifndef NXAGENT_SERVER
static Bool
doListFontsAndAliases(ClientPtr client, LFclosurePtr c)
{
    FontPathElementPtr fpe;
    int         err = Successful;
    FontNamesPtr names = NULL;
    char       *name, *resolved=NULL;
    int         namelen, resolvedlen;
    int		nnames;
    int         stringLens;
    int         i;
    xListFontsReply reply;
    char	*bufptr;
    char	*bufferStart;
    int		aliascount = 0;

    if (client->clientGone)
    {
	if (c->current.current_fpe < c->num_fpes)
	{
	    fpe = c->fpe_list[c->current.current_fpe];
#ifdef HAS_XFONT2
	    (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	    (*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif /* HAS_XFONT2 */
	}
	err = Successful;
	goto bail;
    }

    if (!c->current.patlen)
	goto finish;

    while (c->current.current_fpe < c->num_fpes) {
	fpe = c->fpe_list[c->current.current_fpe];
	err = Successful;

#ifdef HAS_XFONT2
	if (!fpe_functions[fpe->type]->start_list_fonts_and_aliases)
#else
	if (!fpe_functions[fpe->type].start_list_fonts_and_aliases)
#endif /* HAS_XFONT2 */
	{
	    /* This FPE doesn't support/require list_fonts_and_aliases */

#ifdef HAS_XFONT2
	    err = (*fpe_functions[fpe->type]->list_fonts)
#else
	    err = (*fpe_functions[fpe->type].list_fonts)
#endif /* HAS_XFONT2 */
		((void *) c->client, fpe, c->current.pattern,
		 c->current.patlen, c->current.max_names - c->names->nnames,
		 c->names);

	    if (err == Suspended) {
		if (!c->slept) {
		    c->slept = TRUE;
		    ClientSleep(client,
			(ClientSleepProcPtr)doListFontsAndAliases,
			(void *) c);
		}
		return TRUE;
	    }

	    err = BadFontName;
	}
	else
	{
	    /* Start of list_fonts_and_aliases functionality.  Modeled
	       after list_fonts_with_info in that it resolves aliases,
	       except that the information collected from FPEs is just
	       names, not font info.  Each list_next_font_or_alias()
	       returns either a name into name/namelen or an alias into
	       name/namelen and its target name into resolved/resolvedlen.
	       The code at this level then resolves the alias by polling
	       the FPEs.  */

	    if (!c->current.list_started) {
#ifdef HAS_XFONT2
		err = (*fpe_functions[fpe->type]->start_list_fonts_and_aliases)
#else
		err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases)
#endif /* HAS_XFONT2 */
		    ((void *) c->client, fpe, c->current.pattern,
		     c->current.patlen, c->current.max_names - c->names->nnames,
		     &c->current.private);
		if (err == Suspended) {
		    if (!c->slept) {
			ClientSleep(client,
				    (ClientSleepProcPtr)doListFontsAndAliases,
				    (void *) c);
			c->slept = TRUE;
		    }
		    return TRUE;
		}
		if (err == Successful)
		    c->current.list_started = TRUE;
	    }
	    if (err == Successful) {
		char    *tmpname;
		name = 0;
#ifdef HAS_XFONT2
		err = (*fpe_functions[fpe->type]->list_next_font_or_alias)
#else
		err = (*fpe_functions[fpe->type].list_next_font_or_alias)
#endif /* HAS_XFONT2 */
		    ((void *) c->client, fpe, &name, &namelen, &tmpname,
		     &resolvedlen, c->current.private);
		if (err == Suspended) {
		    if (!c->slept) {
			ClientSleep(client,
				    (ClientSleepProcPtr)doListFontsAndAliases,
				    (void *) c);
			c->slept = TRUE;
		    }
		    return TRUE;
		}
		if (err == FontNameAlias) {
		    free(resolved);
		    resolved = (char *) malloc(resolvedlen + 1);
		    if (resolved)
			memmove(resolved, tmpname, resolvedlen + 1);
		}
	    }

	    if (err == Successful)
	    {
		if (c->haveSaved)
		{
		    if (c->savedName)
#ifdef HAS_XFONT2
			(void)xfont2_add_font_names_name(c->names, c->savedName,
#else
			(void)AddFontNamesName(c->names, c->savedName,
#endif /* HAS_XFONT2 */
					       c->savedNameLen);
		}
		else
#ifdef HAS_XFONT2
		    (void)xfont2_add_font_names_name(c->names, name, namelen);
#else
		    (void)AddFontNamesName(c->names, name, namelen);
#endif /* HAS_XFONT2 */
	    }

	    /*
	     * When we get an alias back, save our state and reset back to
	     * the start of the FPE looking for the specified name.  As
	     * soon as a real font is found for the alias, pop back to the
	     * old state
	     */
	    else if (err == FontNameAlias) {
		char	tmp_pattern[XLFDMAXFONTNAMELEN];
		/*
		 * when an alias recurses, we need to give
		 * the last FPE a chance to clean up; so we call
		 * it again, and assume that the error returned
		 * is BadFontName, indicating the alias resolution
		 * is complete.
		 */
		memmove(tmp_pattern, resolved, resolvedlen);
		if (c->haveSaved)
		{
		    char    *tmpname;
		    int     tmpnamelen;

		    tmpname = 0;
#ifdef HAS_XFONT2
		    (void) (*fpe_functions[fpe->type]->list_next_font_or_alias)
#else
		    (void) (*fpe_functions[fpe->type].list_next_font_or_alias)
#endif /* HAS_XFONT2 */
			((void *) c->client, fpe, &tmpname, &tmpnamelen,
			 &tmpname, &tmpnamelen, c->current.private);
		    if (--aliascount <= 0)
		    {
			err = BadFontName;
			goto ContBadFontName;
		    }
		}
		else
		{
		    c->saved = c->current;
		    c->haveSaved = TRUE;
		    free(c->savedName);
		    c->savedName = (char *)malloc(namelen + 1);
		    if (c->savedName)
			memmove(c->savedName, name, namelen + 1);
		    c->savedNameLen = namelen;
		    aliascount = 20;
		}
		memmove(c->current.pattern, tmp_pattern, resolvedlen);
		c->current.patlen = resolvedlen;
		c->current.max_names = c->names->nnames + 1;
		c->current.current_fpe = -1;
		c->current.private = 0;
		err = BadFontName;
	    }
	}
	/*
	 * At the end of this FPE, step to the next.  If we've finished
	 * processing an alias, pop state back. If we've collected enough
	 * font names, quit.
	 */
	if (err == BadFontName) {
	  ContBadFontName: ;
	    c->current.list_started = FALSE;
	    c->current.current_fpe++;
	    err = Successful;
	    if (c->haveSaved)
	    {
		if (c->names->nnames == c->current.max_names ||
			c->current.current_fpe == c->num_fpes) {
		    c->haveSaved = FALSE;
		    c->current = c->saved;
		    /* Give the saved namelist a chance to clean itself up */
		    continue;
		}
	    }
	    if (c->names->nnames == c->current.max_names)
		break;
	}
    }

    /*
     * send the reply
     */
    if (err != Successful) {
	SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err));
	goto bail;
    }

finish:

    names = c->names;
    nnames = names->nnames;
    client = c->client;
    stringLens = 0;
    for (i = 0; i < nnames; i++)
	stringLens += (names->length[i] <= 255) ? names->length[i] : 0;

    memset(&reply, 0, sizeof(xListFontsReply));
    reply.type = X_Reply;
    reply.length = (stringLens + nnames + 3) >> 2;
    reply.nFonts = nnames;
    reply.sequenceNumber = client->sequence;

    bufptr = bufferStart = (char *) malloc(reply.length << 2);

    if (!bufptr && reply.length) {
	SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc);
	goto bail;
    }
    /*
     * since WriteToClient long word aligns things, copy to temp buffer and
     * write all at once
     */
    for (i = 0; i < nnames; i++) {
	if (names->length[i] > 255)
	    reply.nFonts--;
	else
	{
	    *bufptr++ = names->length[i];
	    memmove( bufptr, names->names[i], names->length[i]);
	    bufptr += names->length[i];
	}
    }
    nnames = reply.nFonts;
    reply.length = (stringLens + nnames + 3) >> 2;
    client->pSwapReplyFunc = ReplySwapVector[X_ListFonts];
    WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply);
    WriteToClient(client, stringLens + nnames, bufferStart);
    free(bufferStart);

bail:
    if (c->slept)
	ClientWakeup(client);
    for (i = 0; i < c->num_fpes; i++)
	FreeFPE(c->fpe_list[i]);
    free(c->fpe_list);
    free(c->savedName);
#ifdef HAS_XFONT2
    xfont2_free_font_names(names);
#else
    FreeFontNames(names);
#endif /* HAS_XFONT2 */
    free(c);
    free(resolved);
    return TRUE;
}

int
ListFonts(ClientPtr client, unsigned char *pattern, unsigned length, 
          unsigned max_names)
{
    int         i;
    LFclosurePtr c;

    /* 
     * The right error to return here would be BadName, however the
     * specification does not allow for a Name error on this request.
     * Perhaps a better solution would be to return a nil list, i.e.
     * a list containing zero fontnames.
     */
    if (length > XLFDMAXFONTNAMELEN)
	return BadAlloc;

    if (!(c = (LFclosurePtr) calloc(1, sizeof *c)))
	return BadAlloc;
    c->fpe_list = (FontPathElementPtr *)
	malloc(sizeof(FontPathElementPtr) * num_fpes);
    if (!c->fpe_list) {
	free(c);
	return BadAlloc;
    }
#ifdef HAS_XFONT2
    c->names = xfont2_make_font_names_record(max_names < 100 ? max_names : 100);
#else
    c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100);
#endif /* HAS_XFONT2 */
    if (!c->names)
    {
	free(c->fpe_list);
	free(c);
	return BadAlloc;
    }
    memmove( c->current.pattern, pattern, length);
    for (i = 0; i < num_fpes; i++) {
	c->fpe_list[i] = font_path_elements[i];
	UseFPE(c->fpe_list[i]);
    }
    c->client = client;
    c->num_fpes = num_fpes;
    c->current.patlen = length;
    c->current.current_fpe = 0;
    c->current.max_names = max_names;
    c->current.list_started = FALSE;
    c->current.private = 0;
    c->haveSaved = FALSE;
    c->slept = FALSE;
    c->savedName = 0;
    doListFontsAndAliases(client, c);
    return Success;
}

int
doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c)
{
    FontPathElementPtr fpe;
    int         err = Successful;
    char       *name;
    int         namelen;
    int         numFonts;
    FontInfoRec fontInfo,
               *pFontInfo;
    xListFontsWithInfoReply *reply;
    int         length;
    xFontProp  *pFP;
    int         i;
    int		aliascount = 0;
    xListFontsWithInfoReply finalReply;

    if (client->clientGone)
    {
	if (c->current.current_fpe < c->num_fpes)
 	{
	    fpe = c->fpe_list[c->current.current_fpe];
#ifdef HAS_XFONT2
	    (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	    (*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif /* HAS_XFONT2 */
	}
	err = Successful;
	goto bail;
    }
    client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo];
    if (!c->current.patlen)
	goto finish;
    while (c->current.current_fpe < c->num_fpes)
    {
	fpe = c->fpe_list[c->current.current_fpe];
	err = Successful;
	if (!c->current.list_started)
 	{
#ifdef HAS_XFONT2
	    err = (*fpe_functions[fpe->type]->start_list_fonts_with_info)
#else
	    err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
#endif /* HAS_XFONT2 */
		(client, fpe, c->current.pattern, c->current.patlen,
		 c->current.max_names, &c->current.private);
	    if (err == Suspended)
 	    {
		if (!c->slept)
 		{
		    ClientSleep(client, (ClientSleepProcPtr)doListFontsWithInfo, c);
		    c->slept = TRUE;
		}
		return TRUE;
	    }
	    if (err == Successful)
		c->current.list_started = TRUE;
	}
	if (err == Successful)
 	{
	    name = 0;
	    pFontInfo = &fontInfo;
#ifdef HAS_XFONT2
	    err = (*fpe_functions[fpe->type]->list_next_font_with_info)
#else
	    err = (*fpe_functions[fpe->type].list_next_font_with_info)
#endif /* HAS_XFONT2 */
		(client, fpe, &name, &namelen, &pFontInfo,
		 &numFonts, c->current.private);
	    if (err == Suspended)
 	    {
		if (!c->slept)
 		{
		    ClientSleep(client,
		    	     (ClientSleepProcPtr)doListFontsWithInfo,
			     c);
		    c->slept = TRUE;
		}
		return TRUE;
	    }
	}
	/*
	 * When we get an alias back, save our state and reset back to the
	 * start of the FPE looking for the specified name.  As soon as a real
	 * font is found for the alias, pop back to the old state
	 */
	if (err == FontNameAlias)
 	{
	    /*
	     * when an alias recurses, we need to give
	     * the last FPE a chance to clean up; so we call
	     * it again, and assume that the error returned
	     * is BadFontName, indicating the alias resolution
	     * is complete.
	     */
	    if (c->haveSaved)
	    {
		char	*tmpname;
		int	tmpnamelen;
		FontInfoPtr tmpFontInfo;

	    	tmpname = 0;
	    	tmpFontInfo = &fontInfo;
#ifdef HAS_XFONT2
		(void) (*fpe_functions[fpe->type]->list_next_font_with_info)
#else
		(void) (*fpe_functions[fpe->type].list_next_font_with_info)
#endif /* HAS_XFONT2 */
		    (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
		     &numFonts, c->current.private);
		if (--aliascount <= 0)
		{
		    err = BadFontName;
		    goto ContBadFontName;
		}
	    }
	    else
	    {
		c->saved = c->current;
		c->haveSaved = TRUE;
		c->savedNumFonts = numFonts;
		free(c->savedName);
		c->savedName = (char *)malloc(namelen + 1);
		if (c->savedName)
		  memmove(c->savedName, name, namelen + 1);
		aliascount = 20;
	    }
	    memmove(c->current.pattern, name, namelen);
	    c->current.patlen = namelen;
	    c->current.max_names = 1;
	    c->current.current_fpe = 0;
	    c->current.private = 0;
	    c->current.list_started = FALSE;
	}
	/*
	 * At the end of this FPE, step to the next.  If we've finished
	 * processing an alias, pop state back.  If we've sent enough font
	 * names, quit.  Always wait for BadFontName to let the FPE
	 * have a chance to clean up.
	 */
	else if (err == BadFontName)
 	{
	  ContBadFontName: ;
	    c->current.list_started = FALSE;
	    c->current.current_fpe++;
	    err = Successful;
	    if (c->haveSaved)
 	    {
		if (c->current.max_names == 0 ||
			c->current.current_fpe == c->num_fpes)
 		{
		    c->haveSaved = FALSE;
		    c->saved.max_names -= (1 - c->current.max_names);
		    c->current = c->saved;
		}
	    }
	    else if (c->current.max_names == 0)
		break;
	}
 	else if (err == Successful)
 	{
	    length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
	    reply = c->reply;
	    if (c->length < length)
 	    {
		reply = (xListFontsWithInfoReply *) realloc(c->reply, length);
		if (!reply)
 		{
		    err = AllocError;
		    break;
		}
		memset(reply + c->length, 0, length - c->length);
		c->reply = reply;
		c->length = length;
	    }
	    if (c->haveSaved)
 	    {
		numFonts = c->savedNumFonts;
		name = c->savedName;
		namelen = strlen(name);
	    }
	    reply->type = X_Reply;
	    reply->length = (sizeof *reply - sizeof(xGenericReply) +
			     pFontInfo->nprops * sizeof(xFontProp) +
			     namelen + 3) >> 2;
	    reply->sequenceNumber = client->sequence;
	    reply->nameLength = namelen;
	    reply->minBounds = pFontInfo->ink_minbounds;
	    reply->maxBounds = pFontInfo->ink_maxbounds;
	    reply->minCharOrByte2 = pFontInfo->firstCol;
	    reply->maxCharOrByte2 = pFontInfo->lastCol;
	    reply->defaultChar = pFontInfo->defaultCh;
	    reply->nFontProps = pFontInfo->nprops;
	    reply->drawDirection = pFontInfo->drawDirection;
	    reply->minByte1 = pFontInfo->firstRow;
	    reply->maxByte1 = pFontInfo->lastRow;
	    reply->allCharsExist = pFontInfo->allExist;
	    reply->fontAscent = pFontInfo->fontAscent;
	    reply->fontDescent = pFontInfo->fontDescent;
	    reply->nReplies = numFonts;
	    pFP = (xFontProp *) (reply + 1);
	    for (i = 0; i < pFontInfo->nprops; i++)
 	    {
		pFP->name = pFontInfo->props[i].name;
		pFP->value = pFontInfo->props[i].value;
		pFP++;
	    }
	    WriteSwappedDataToClient(client, length, reply);
	    WriteToClient(client, namelen, name);
	    if (pFontInfo == &fontInfo)
 	    {
		free(fontInfo.props);
		free(fontInfo.isStringProp);
	    }
	    --c->current.max_names;
	}
    }
finish:
    length = sizeof(xListFontsWithInfoReply);
    bzero((char *) &finalReply, sizeof(xListFontsWithInfoReply));
    finalReply.type = X_Reply;
    finalReply.sequenceNumber = client->sequence;
    finalReply.length = (sizeof(xListFontsWithInfoReply)
		     - sizeof(xGenericReply)) >> 2;
    WriteSwappedDataToClient(client, length, &finalReply);
bail:
    if (c->slept)
	ClientWakeup(client);
    for (i = 0; i < c->num_fpes; i++)
	FreeFPE(c->fpe_list[i]);
    free(c->reply);
    free(c->fpe_list);
    free(c->savedName);
    free(c);
    return TRUE;
}
#endif /* NXAGENT_SERVER */

int
StartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern, 
                       int max_names)
{
    int		    i;
    LFWIclosurePtr  c;

    /* 
     * The right error to return here would be BadName, however the
     * specification does not allow for a Name error on this request.
     * Perhaps a better solution would be to return a nil list, i.e.
     * a list containing zero fontnames.
     */
    if (length > XLFDMAXFONTNAMELEN)
	return BadAlloc;

    if (!(c = (LFWIclosurePtr) malloc(sizeof *c)))
	goto badAlloc;
    c->fpe_list = (FontPathElementPtr *)
	malloc(sizeof(FontPathElementPtr) * num_fpes);
    if (!c->fpe_list)
    {
	free(c);
	goto badAlloc;
    }
    memmove(c->current.pattern, pattern, length);
    for (i = 0; i < num_fpes; i++)
    {
	c->fpe_list[i] = font_path_elements[i];
	UseFPE(c->fpe_list[i]);
    }
    c->client = client;
    c->num_fpes = num_fpes;
    c->reply = 0;
    c->length = 0;
    c->current.patlen = length;
    c->current.current_fpe = 0;
    c->current.max_names = max_names;
    c->current.list_started = FALSE;
    c->current.private = 0;
    c->savedNumFonts = 0;
    c->haveSaved = FALSE;
    c->slept = FALSE;
    c->savedName = 0;
    doListFontsWithInfo(client, c);
    return Success;
badAlloc:
    return BadAlloc;
}

#define TextEltHeader 2
#define FontShiftSize 5
static XID clearGC[] = { CT_NONE };
#define clearGCmask (GCClipMask)

int
doPolyText(ClientPtr client, register PTclosurePtr c)
{
    register FontPtr pFont = c->pGC->font, oldpFont;
    Font	fid, oldfid;
    int err = Success, lgerr;	/* err is in X error, not font error, space */
    enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state = NEVER_SLEPT;
    FontPathElementPtr fpe;
    GC *origGC = NULL;

    if (client->clientGone)
    {
	fpe = c->pGC->font->fpe;
#ifdef HAS_XFONT2
	(*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	(*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif /* HAS_XFONT2 */

	if (c->slept)
	{
	    /* Client has died, but we cannot bail out right now.  We
	       need to clean up after the work we did when going to
	       sleep.  Setting the drawable pointer to 0 makes this
	       happen without any attempts to render or perform other
	       unnecessary activities.  */
	    c->pDraw = (DrawablePtr)0;
	}
	else
	{
	    err = Success;
	    goto bail;
	}
    }

    /* Make sure our drawable hasn't disappeared while we slept. */
    if (c->slept &&
	c->pDraw &&
	c->pDraw != (DrawablePtr)SecurityLookupIDByClass(client, c->did,
					RC_DRAWABLE, DixWriteAccess))
    {
	/* Our drawable has disappeared.  Treat like client died... ask
	   the FPE code to clean up after client and avoid further
	   rendering while we clean up after ourself.  */
	fpe = c->pGC->font->fpe;
#ifdef HAS_XFONT2
	(*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	(*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif /* HAS_XFONT2 */
	c->pDraw = (DrawablePtr)0;
    }

    client_state = c->slept ? SLEEPING : NEVER_SLEPT;

    while (c->endReq - c->pElt > TextEltHeader)
    {
	if (*c->pElt == FontChange)
        {
	    if (c->endReq - c->pElt < FontShiftSize)
	    {
		 err = BadLength;
		 goto bail;
	    }

	    oldpFont = pFont;
	    oldfid = fid;

	    fid =  ((Font)*(c->pElt+4))		/* big-endian */
		 | ((Font)*(c->pElt+3)) << 8
		 | ((Font)*(c->pElt+2)) << 16
		 | ((Font)*(c->pElt+1)) << 24;
	    pFont = (FontPtr)SecurityLookupIDByType(client, fid, RT_FONT,
						    DixReadAccess);
	    if (!pFont)
	    {
		client->errorValue = fid;
		err = BadFont;
		/* restore pFont and fid for step 4 (described below) */
		pFont = oldpFont;
		fid = oldfid;

		/* If we're in START_SLEEP mode, the following step
		   shortens the request...  in the unlikely event that
		   the fid somehow becomes valid before we come through
		   again to actually execute the polytext, which would
		   then mess up our refcounting scheme badly.  */
		c->err = err;
		c->endReq = c->pElt;

		goto bail;
	    }

	    /* Step 3 (described below) on our new font */
	    if (client_state == START_SLEEP)
		pFont->refcnt++;
	    else
	    {
		if (pFont != c->pGC->font && c->pDraw)
		{
		    ChangeGC( c->pGC, GCFont, &fid);
		    ValidateGC(c->pDraw, c->pGC);
		    if (c->reqType == X_PolyText8)
			c->polyText = (PolyTextPtr) c->pGC->ops->PolyText8;
		    else
			c->polyText = (PolyTextPtr) c->pGC->ops->PolyText16;
		}

		/* Undo the refcnt++ we performed when going to sleep */
		if (client_state == SLEEPING)
		    (void)CloseFont(c->pGC->font, (Font)0);
	    }
	    c->pElt += FontShiftSize;
	}
	else	/* print a string */
	{
	    unsigned char *pNextElt;
	    pNextElt = c->pElt + TextEltHeader + (*c->pElt)*c->itemSize;
	    if ( pNextElt > c->endReq)
	    {
		err = BadLength;
		goto bail;
	    }
	    if (client_state == START_SLEEP)
	    {
		c->pElt = pNextElt;
		continue;
	    }
	    if (c->pDraw)
	    {
		lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, c->itemSize,
				   c->pElt + TextEltHeader);
	    }
	    else lgerr = Successful;

	    if (lgerr == Suspended)
	    {
		if (!c->slept) {
		    int len;
		    GC *pGC;
		    PTclosurePtr new_closure;

    /*  We're putting the client to sleep.  We need to do a few things
	to ensure successful and atomic-appearing execution of the
	remainder of the request.  First, copy the remainder of the
	request into a safe malloc'd area.  Second, create a scratch GC
	to use for the remainder of the request.  Third, mark all fonts
	referenced in the remainder of the request to prevent their
	deallocation.  Fourth, make the original GC look like the
	request has completed...  set its font to the final font value
	from this request.  These GC manipulations are for the unlikely
	(but possible) event that some other client is using the GC.
	Steps 3 and 4 are performed by running this procedure through
	the remainder of the request in a special no-render mode
	indicated by client_state = START_SLEEP.  */

		    /* Step 1 */
		    /* Allocate a malloc'd closure structure to replace
		       the local one we were passed */
		    new_closure = (PTclosurePtr) malloc(sizeof(PTclosureRec));
		    if (!new_closure)
		    {
			err = BadAlloc;
			goto bail;
		    }
		    *new_closure = *c;
		    c = new_closure;

		    len = c->endReq - c->pElt;
		    c->data = (unsigned char *)malloc(len);
		    if (!c->data)
		    {
			free(c);
			err = BadAlloc;
			goto bail;
		    }
		    memmove(c->data, c->pElt, len);
		    c->pElt = c->data;
		    c->endReq = c->pElt + len;

		    /* Step 2 */

		    pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
		    if (!pGC)
		    {
			free(c->data);
			free(c);
			err = BadAlloc;
			goto bail;
		    }

#ifdef NXAGENT_SERVER
		    pGC->tileIsPixel = TRUE;
		    pGC->tile.pixel = 0;
		    pGC->stipple = NullPixmap;
#endif

		    if ((err = CopyGC(c->pGC, pGC, GCFunction |
				      GCPlaneMask | GCForeground |
				      GCBackground | GCFillStyle |
				      GCTile | GCStipple |
				      GCTileStipXOrigin |
				      GCTileStipYOrigin | GCFont |
				      GCSubwindowMode | GCClipXOrigin |
				      GCClipYOrigin | GCClipMask)) !=
				      Success)
		    {
			FreeScratchGC(pGC);
			free(c->data);
			free(c);
			err = BadAlloc;
			goto bail;
		    }
		    origGC = c->pGC;
		    c->pGC = pGC;
		    ValidateGC(c->pDraw, c->pGC);
		    
		    c->slept = TRUE;
		    ClientSleep(client,
		    	     (ClientSleepProcPtr)doPolyText,
			     (void *) c);

		    /* Set up to perform steps 3 and 4 */
		    client_state = START_SLEEP;
		    continue;	/* on to steps 3 and 4 */
		}
		return TRUE;
	    }
	    else if (lgerr != Successful)
	    {
		err = FontToXError(lgerr);
		goto bail;
	    }
	    if (c->pDraw)
	    {
		c->xorg += *((INT8 *)(c->pElt + 1));	/* must be signed */
		c->xorg = (* c->polyText)(c->pDraw, c->pGC, c->xorg, c->yorg,
		    *c->pElt, c->pElt + TextEltHeader);
	    }
	    c->pElt = pNextElt;
	}
    }

bail:

    if (client_state == START_SLEEP)
    {
	/* Step 4 */
	if (pFont != origGC->font)
	{
	    ChangeGC(origGC, GCFont, &fid);
	    ValidateGC(c->pDraw, origGC);
	}

	/* restore pElt pointer for execution of remainder of the request */
	c->pElt = c->data;
	return TRUE;
    }

    if (c->err != Success) err = c->err;
    if (err != Success && c->client != serverClient) {
#ifdef PANORAMIX
        if (noPanoramiXExtension || !c->pGC->pScreen->myNum)
#endif
	    SendErrorToClient(c->client, c->reqType, 0, 0, err);
    }
    if (c->slept)
    {
	ClientWakeup(c->client);
	ChangeGC(c->pGC, clearGCmask, clearGC);

	/* Unreference the font from the scratch GC */
	CloseFont(c->pGC->font, (Font)0);
	c->pGC->font = NullFont;

	FreeScratchGC(c->pGC);
	free(c->data);
	free(c);
    }
    return TRUE;
}

int
PolyText(ClientPtr client, DrawablePtr pDraw, GC *pGC, unsigned char *pElt, 
         unsigned char *endReq, int xorg, int yorg, int reqType, XID did)
{
    PTclosureRec local_closure;

    local_closure.pElt = pElt;
    local_closure.endReq = endReq;
    local_closure.client = client;
    local_closure.pDraw = pDraw;
    local_closure.xorg = xorg;
    local_closure.yorg = yorg;
    if ((local_closure.reqType = reqType) == X_PolyText8)
    {
	local_closure.polyText = (PolyTextPtr) pGC->ops->PolyText8;
	local_closure.itemSize = 1;
    }
    else
    {
	local_closure.polyText =  (PolyTextPtr) pGC->ops->PolyText16;
	local_closure.itemSize = 2;
    }
    local_closure.pGC = pGC;
    local_closure.did = did;
    local_closure.err = Success;
    local_closure.slept = FALSE;

    (void) doPolyText(client, &local_closure);
    return Success;
}


#undef TextEltHeader
#undef FontShiftSize

int
doImageText(ClientPtr client, register ITclosurePtr c)
{
    int err = Success, lgerr;	/* err is in X error, not font error, space */
    FontPathElementPtr fpe;

    if (client->clientGone)
    {
	fpe = c->pGC->font->fpe;
#ifdef HAS_XFONT2
	(*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	(*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif
	err = Success;
	goto bail;
    }

    /* Make sure our drawable hasn't disappeared while we slept. */
    if (c->slept &&
	c->pDraw &&
	c->pDraw != (DrawablePtr)SecurityLookupIDByClass(client, c->did,
					RC_DRAWABLE, DixWriteAccess))
    {
	/* Our drawable has disappeared.  Treat like client died... ask
	   the FPE code to clean up after client. */
	fpe = c->pGC->font->fpe;
#ifdef HAS_XFONT2
	(*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	(*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif /* HAS_XFONT2 */
	err = Success;
	goto bail;
    }

    lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, c->itemSize, c->data);
    if (lgerr == Suspended)
    {
        if (!c->slept) {
	    GC *pGC;
	    unsigned char *data;
	    ITclosurePtr new_closure;
	    ITclosurePtr old_closure;

	    /* We're putting the client to sleep.  We need to
	       save some state.  Similar problem to that handled
	       in doPolyText, but much simpler because the
	       request structure is much simpler. */

	    new_closure = (ITclosurePtr) malloc(sizeof(ITclosureRec));
	    if (!new_closure)
	    {
		err = BadAlloc;
		goto bail;
	    }
	    old_closure = c;
	    *new_closure = *c;
	    c = new_closure;

	    data = (unsigned char *)malloc(c->nChars * c->itemSize);
	    if (!data)
	    {
		free(c);
		c = old_closure;
		err = BadAlloc;
		goto bail;
	    }
	    memmove(data, c->data, c->nChars * c->itemSize);
	    c->data = data;

	    pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
	    if (!pGC)
	    {
		free(c->data);
		free(c);
		c = old_closure;
		err = BadAlloc;
		goto bail;
	    }

#ifdef NXAGENT_SERVER
	    pGC->tileIsPixel = TRUE;
	    pGC->tile.pixel = 0;
	    pGC->stipple = NullPixmap;
#endif

	    if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask |
			      GCForeground | GCBackground | GCFillStyle |
			      GCTile | GCStipple | GCTileStipXOrigin |
			      GCTileStipYOrigin | GCFont |
			      GCSubwindowMode | GCClipXOrigin |
			      GCClipYOrigin | GCClipMask)) != Success)
	    {
		FreeScratchGC(pGC);
		free(c->data);
		free(c);
		c = old_closure;
		err = BadAlloc;
		goto bail;
	    }
	    c->pGC = pGC;
	    ValidateGC(c->pDraw, c->pGC);

	    c->slept = TRUE;
            ClientSleep(client, (ClientSleepProcPtr)doImageText, (void *) c);
        }
        return TRUE;
    }
    else if (lgerr != Successful)
    {
        err = FontToXError(lgerr);
        goto bail;
    }
    if (c->pDraw)
    {
	(* c->imageText)(c->pDraw, c->pGC, c->xorg, c->yorg,
	    c->nChars, c->data);
    }

bail:

    if (err != Success && c->client != serverClient) {
	SendErrorToClient(c->client, c->reqType, 0, 0, err);
    }
    if (c->slept)
    {
	ClientWakeup(c->client);
	ChangeGC(c->pGC, clearGCmask, clearGC);

	/* Unreference the font from the scratch GC */
	CloseFont(c->pGC->font, (Font)0);
	c->pGC->font = NullFont;

	FreeScratchGC(c->pGC);
	free(c->data);
	free(c);
    }
    return TRUE;
}

int
ImageText(ClientPtr client, DrawablePtr pDraw, GC *pGC, int nChars, 
          unsigned char *data, int xorg, int yorg, int reqType, XID did)
{
    ITclosureRec local_closure;

    local_closure.client = client;
    local_closure.pDraw = pDraw;
    local_closure.pGC = pGC;
    local_closure.nChars = nChars;
    local_closure.data = data;
    local_closure.xorg = xorg;
    local_closure.yorg = yorg;
    if ((local_closure.reqType = reqType) == X_ImageText8)
    {
	local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText8;
	local_closure.itemSize = 1;
    }
    else
    {
	local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText16;
	local_closure.itemSize = 2;
    }
    local_closure.did = did;
    local_closure.slept = FALSE;

    (void) doImageText(client, &local_closure);
    return Success;
}


/* does the necessary magic to figure out the fpe type */
static int
DetermineFPEType(char *pathname)
{
    int         i;

    for (i = 0; i < num_fpe_types; i++) {
#ifdef HAS_XFONT2
	if ((*fpe_functions[i]->name_check) (pathname))
#else
	if ((*fpe_functions[i].name_check) (pathname))
#endif /* HAS_XFONT2 */
	    return i;
    }
    return -1;
}


static void
FreeFontPath(FontPathElementPtr *list, int n, Bool force)
{
    int         i;

    for (i = 0; i < n; i++) {
	if (force) {
	    /* Sanity check that all refcounts will be 0 by the time
	       we get to the end of the list. */
	    int found = 1;	/* the first reference is us */
	    int j;
	    for (j = i+1; j < n; j++) {
		if (list[j] == list[i])
		    found++;
	    }
	    if (list[i]->refcount != found) {
		ErrorF("FreeFontPath: FPE \"%.*s\" refcount is %d, should be %d; fixing.\n",
		       list[i]->name_length, list[i]->name,
		       list[i]->refcount, found);
		list[i]->refcount = found; /* ensure it will get freed */
	    }
	}
	FreeFPE(list[i]);
    }
    free((char *) list);
}

static FontPathElementPtr
find_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len)
{
    FontPathElementPtr fpe;
    int         i;

    for (i = 0; i < num; i++) {
	fpe = list[i];
	if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0)
	    return fpe;
    }
    return (FontPathElementPtr) 0;
}

static int
SetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist)
{
    int         i, err = 0;
    int         valid_paths = 0;
    unsigned int len;
    unsigned char *cp = paths;
    FontPathElementPtr fpe = NULL, *fplist;

    fplist = (FontPathElementPtr *)
	malloc(sizeof(FontPathElementPtr) * npaths);
    if (!fplist) {
	*bad = 0;
	return BadAlloc;
    }
    for (i = 0; i < num_fpe_types; i++) {
#ifdef HAS_XFONT2
	if (fpe_functions[i]->set_path_hook)
	    (*fpe_functions[i]->set_path_hook) ();
#else
	if (fpe_functions[i].set_path_hook)
	    (*fpe_functions[i].set_path_hook) ();
#endif /* HAS_XFONT2 */
    }
    for (i = 0; i < npaths; i++) 
    {
	len = (unsigned int) (*cp++);

	if (len == 0) 
	{
	    if (persist)
		ErrorF ("Removing empty element from the valid list of fontpaths\n");
	    err = BadValue;
	}
	else
	{
	    /* if it's already in our active list, just reset it */
	    /*
	     * note that this can miss FPE's in limbo -- may be worth catching
	     * them, though it'd muck up refcounting
	     */
	    fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
	    if (fpe) 
	    {
#ifdef HAS_XFONT2
		err = (*fpe_functions[fpe->type]->reset_fpe) (fpe);
#else
		err = (*fpe_functions[fpe->type].reset_fpe) (fpe);
#endif /* HAS_XFONT2 */
		if (err == Successful) 
		{
		    UseFPE(fpe);/* since it'll be decref'd later when freed
				 * from the old list */
		}
		else
		    fpe = 0;
	    }
	    /* if error or can't do it, act like it's a new one */
	    if (!fpe)
	    {
		fpe = (FontPathElementPtr) malloc(sizeof(FontPathElementRec));
		if (!fpe) 
		{
		    err = BadAlloc;
		    goto bail;
		}
		fpe->name = (char *) malloc(len + 1);
		if (!fpe->name) 
		{
		    free(fpe);
		    err = BadAlloc;
		    goto bail;
		}
		fpe->refcount = 1;
    
		strncpy(fpe->name, (char *) cp, (int) len);
		fpe->name[len] = '\0';
		fpe->name_length = len;
		fpe->type = DetermineFPEType(fpe->name);
		if (fpe->type == -1)
		    err = BadValue;
		else
#ifdef HAS_XFONT2
		    err = (*fpe_functions[fpe->type]->init_fpe) (fpe);
#else
		    err = (*fpe_functions[fpe->type].init_fpe) (fpe);
#endif /* HAS_XFONT2 */
		if (err != Successful)
		{
#ifndef NXAGENT_SERVER
		    if (persist)
		    {
			ErrorF("Could not init font path element %s, removing from list!\n",
			       fpe->name);
		    }
#endif /* NXAGENT_SERVER */
		    free (fpe->name);
		    free (fpe);
		}
	    }
	}
	if (err != Successful)
	{
	    if (!persist)
		goto bail;
	}
	else
	{
	    fplist[valid_paths++] = fpe;
	}
	cp += len;
    }

    FreeFontPath(font_path_elements, num_fpes, FALSE);
    font_path_elements = fplist;
    if (patternCache)
#ifdef HAS_XFONT2
	xfont2_empty_font_pattern_cache(patternCache);
#else
	EmptyFontPatternCache(patternCache);
#endif /* HAS_XFONT2 */
    num_fpes = valid_paths;

    return Success;
bail:
    *bad = i;
    while (--valid_paths >= 0)
	FreeFPE(fplist[valid_paths]);
    free(fplist);
    return FontToXError(err);
}

int
SetFontPath(ClientPtr client, int npaths, unsigned char *paths)
{
    int   err = Success;

    if (npaths == 0) {
	if (SetDefaultFontPath(defaultFontPath) != Success)
	    return BadValue;
    } else {
	int bad;
	err = SetFontPathElements(npaths, paths, &bad, FALSE);
	client->errorValue = bad;
    }
    return err;
}

#ifndef NXAGENT_SERVER
int
SetDefaultFontPath(char *path)
{
    char       *temp_path,
               *start,
               *end;
    unsigned char *cp,
               *pp,
               *nump,
               *newpath;
    int         num = 1,
                len,
                err,
                size = 0,
                bad;

    /* ensure temp_path contains "built-ins" */
    start = path;
    while (1) {
	start = strstr(start, "built-ins");
	if (start == NULL)
	    break;
	end = start + strlen("built-ins");
	if ((start == path || start[-1] == ',') && (!*end || *end == ','))
	    break;
	start = end;
    }
    if (!start) {
	if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "")
	   == -1)
	   temp_path = NULL;
    }
    else {
	temp_path = strdup(path);
    }
    if (!temp_path)
	return BadAlloc;

    /* get enough for string, plus values -- use up commas */
    len = strlen(temp_path) + 1;
    nump = cp = newpath = (unsigned char *) malloc(len);
    if (!newpath) {
	free(temp_path);
	return BadAlloc;
    }
    pp = (unsigned char *) temp_path;
    cp++;
    while (*pp) {
	if (*pp == ',') {
	    *nump = (unsigned char) size;
	    nump = cp++;
	    pp++;
	    num++;
	    size = 0;
	} else {
	    *cp++ = *pp++;
	    size++;
	}
    }
    *nump = (unsigned char) size;

    err = SetFontPathElements(num, newpath, &bad, TRUE);

    free(newpath);
    free(temp_path);

    return err;
}
#endif /* NXAGENT_SERVER */

unsigned char *
GetFontPath(int *count, int *length)
{
    int			i;
    unsigned char       *c;
    int			len;
    FontPathElementPtr	fpe;

    len = 0;
    for (i = 0; i < num_fpes; i++) {
	fpe = font_path_elements[i];
	len += fpe->name_length + 1;
    }
    c = realloc(font_path_string, len);
    if (c == NULL) {
	free(font_path_string);
	font_path_string = NULL;
	return NULL;
    }

    font_path_string = c;
    *length = 0;
    for (i = 0; i < num_fpes; i++) {
	fpe = font_path_elements[i];
	*c = fpe->name_length;
	*length += *c++;
	memmove(c, fpe->name, fpe->name_length);
	c += fpe->name_length;
    }
    *count = num_fpes;
    return font_path_string;
}

int
LoadGlyphs(ClientPtr client, FontPtr pfont, unsigned nchars, int item_size, unsigned char *data)
{
#ifdef HAS_XFONT2
    if (fpe_functions[pfont->fpe->type]->load_glyphs)
	return (*fpe_functions[pfont->fpe->type]->load_glyphs)
#else
    if (fpe_functions[pfont->fpe->type].load_glyphs)
	return (*fpe_functions[pfont->fpe->type].load_glyphs)
#endif
	    (client, pfont, 0, nchars, item_size, data);
    else
	return Successful;
}

void
#ifdef HAS_XFONT2
GetGlyphs(FontPtr font, unsigned long count, unsigned char *chars,
          FontEncoding fontEncoding,
          unsigned long *glyphcount,    /* RETURN */
          CharInfoPtr *glyphs)          /* RETURN */
#else
dixGetGlyphs(FontPtr font, unsigned long count, unsigned char *chars,
             FontEncoding fontEncoding,
             unsigned long *glyphcount,    /* RETURN */
             CharInfoPtr *glyphs)          /* RETURN */
#endif /* HAS_XFONT2 */
 {
     (*font->get_glyphs) (font, count, chars, fontEncoding, glyphcount, glyphs);
 }


void
DeleteClientFontStuff(ClientPtr client)
{
    int			i;
    FontPathElementPtr	fpe;

    for (i = 0; i < num_fpes; i++)
    {
	fpe = font_path_elements[i];
#ifdef HAS_XFONT2
	if (fpe_functions[fpe->type]->client_died)
	    (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
#else
	if (fpe_functions[fpe->type].client_died)
	    (*fpe_functions[fpe->type].client_died) ((void *) client, fpe);
#endif /* HAS_XFONT2 */
    }
}

#ifdef HAS_XFONT2
static int
register_fpe_funcs(const xfont2_fpe_funcs_rec *funcs)
{
    xfont2_fpe_funcs_rec const **new;

    /* grow the list */
    new = reallocarray(fpe_functions, num_fpe_types + 1, sizeof(xfont2_fpe_funcs_ptr));
    if (!new)
        return -1;
    fpe_functions = new;

    fpe_functions[num_fpe_types] = funcs;

    return num_fpe_types++;
}
#else
void
InitFonts ()
{
    patternCache = MakeFontPatternCache();

    ResetFontPrivateIndex();

#ifdef LEGACY_XFONT1
    BuiltinRegisterFpeFunctions();
    FontFileRegisterFpeFunctions();
    fs_register_fpe_functions();
#else
    register_fpe_functions();
#endif
}
#endif /* HAS_XFONT2 */

#ifdef HAS_XFONT2
static unsigned long
get_server_generation(void)
{
    return serverGeneration;
}

static void *
get_server_client(void)
{
    return serverClient;
}

static int
get_default_point_size(void)
#else
int
GetDefaultPointSize ()
#endif /* HAS_XFONT2 */
{
    return 120;
}

#ifdef HAS_XFONT2
static FontResolutionPtr
get_client_resolutions(int *num)
#else
FontResolutionPtr
GetClientResolutions (int *num)
#endif /* HAS_XFONT2 */
{
    static struct _FontResolution res;
    ScreenPtr   pScreen;

    pScreen = screenInfo.screens[0];
    res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth;
    /*
     * XXX - we'll want this as long as bitmap instances are prevalent
     so that we can match them from scalable fonts
     */
    if (res.x_resolution < 88)
        res.x_resolution = 75;
    else
        res.x_resolution = 100;
    res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight;
    if (res.y_resolution < 88)
        res.y_resolution = 75;
    else
        res.y_resolution = 100;
    res.point_size = 120;
    *num = 1;
    return &res;
}

#ifndef HAS_XFONT2
/*
 * returns the type index of the new fpe
 *
 * should be called (only once!) by each type of fpe when initialized
 */

int
RegisterFPEFunctions(NameCheckFunc name_func, 
		     InitFpeFunc init_func, 
		     FreeFpeFunc free_func, 
		     ResetFpeFunc reset_func, 
		     OpenFontFunc open_func, 
		     CloseFontFunc close_func, 
		     ListFontsFunc list_func, 
		     StartLfwiFunc start_lfwi_func, 
		     NextLfwiFunc next_lfwi_func, 
		     WakeupFpeFunc wakeup_func, 
		     ClientDiedFunc client_died, 
		     LoadGlyphsFunc load_glyphs, 
		     StartLaFunc start_list_alias_func, 
		     NextLaFunc next_list_alias_func, 
		     SetPathFunc set_path_func)
{
    FPEFunctions *new;

    /* grow the list */
    new = (FPEFunctions *) realloc(fpe_functions,
				 (num_fpe_types + 1) * sizeof(FPEFunctions));
    if (!new)
	return -1;
    fpe_functions = new;

    fpe_functions[num_fpe_types].name_check = name_func;
    fpe_functions[num_fpe_types].open_font = open_func;
    fpe_functions[num_fpe_types].close_font = close_func;
    fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func;
    fpe_functions[num_fpe_types].list_fonts = list_func;
    fpe_functions[num_fpe_types].start_list_fonts_with_info =
	start_lfwi_func;
    fpe_functions[num_fpe_types].list_next_font_with_info =
	next_lfwi_func;
    fpe_functions[num_fpe_types].init_fpe = init_func;
    fpe_functions[num_fpe_types].free_fpe = free_func;
    fpe_functions[num_fpe_types].reset_fpe = reset_func;
    fpe_functions[num_fpe_types].client_died = client_died;
    fpe_functions[num_fpe_types].load_glyphs = load_glyphs;
    fpe_functions[num_fpe_types].start_list_fonts_and_aliases =
	start_list_alias_func;
    fpe_functions[num_fpe_types].list_next_font_or_alias =
	next_list_alias_func;
    fpe_functions[num_fpe_types].set_path_hook = set_path_func;

    return num_fpe_types++;
}
#endif /* !HAS_XFONT2 */

void
FreeFonts()
{
    if (patternCache) {
#ifdef HAS_XFONT2
	xfont2_free_font_pattern_cache(patternCache);
#else
	FreeFontPatternCache(patternCache);
#endif /* HAS_XFONT2 */
	patternCache = 0;
    }
    FreeFontPath(font_path_elements, num_fpes, TRUE);
    font_path_elements = 0;
    num_fpes = 0;
    free(fpe_functions);
    num_fpe_types = 0;
#ifdef HAS_XFONT2
    fpe_functions = NULL;
#else
    fpe_functions = (FPEFunctions *) 0;
#endif /* HAS_XFONT2 */
}

/* convenience functions for FS interface */

#ifdef HAS_XFONT2
static
#endif /* HAS_XFONT2 */
FontPtr
find_old_font(XID id)
{
    return (FontPtr) SecurityLookupIDByType(NullClient, id, RT_NONE,
					    DixUnknownAccess);
}

#ifdef HAS_XFONT2
static Font
get_new_font_client_id(void)
#else
Font
GetNewFontClientID()
#endif /* HAS_XFONT2 */
{
    return FakeClientID(0);
}

#ifdef HAS_XFONT2
static int
store_font_Client_font(FontPtr pfont, Font id)
#else
int
StoreFontClientFont(FontPtr pfont, Font id)
#endif /* HAS_XFONT2 */
{
    return AddResource(id, RT_NONE, (void *) pfont);
}

#ifdef HAS_XFONT2
static void
delete_font_client_id(Font id)
#else
void
DeleteFontClientID(Font id)
#endif /* HAS_XFONT2 */
{
    FreeResource(id, RT_NONE);
}

#ifdef HAS_XFONT2
static int
_client_auth_generation(ClientPtr client)
#else
int
client_auth_generation(ClientPtr client)
#endif /* HAS_XFONT2 */
{
    return 0;
}

static int  fs_handlers_installed = 0;
static unsigned int last_server_gen;

#ifdef HAS_XFONT2
static void
fs_block_handler(void *blockData, OSTimePtr timeout, void *readmask)
{
    FontBlockHandlerProcPtr block_handler = blockData;

    (*block_handler)(timeout);
}

struct fs_fd_entry {
    struct xorg_list            entry;
    int                         fd;
    void                        *data;
    FontFdHandlerProcPtr        handler;
};

static void
fs_fd_handler(int fd, int ready, void *data)
{
    struct fs_fd_entry    *entry = data;

    entry->handler(fd, entry->data);
}

static struct xorg_list fs_fd_list;

static int
add_fs_fd(int fd, FontFdHandlerProcPtr handler, void *data)
{
    struct fs_fd_entry  *entry = calloc(1, sizeof (struct fs_fd_entry));

    if (!entry)
        return FALSE;

    entry->fd = fd;
    entry->data = data;
    entry->handler = handler;
    if (!SetNotifyFd(fd, fs_fd_handler, X_NOTIFY_READ, entry)) {
        free(entry);
        return FALSE;
    }
    xorg_list_add(&entry->entry, &fs_fd_list);
    return TRUE;
}

static void
remove_fs_fd(int fd)
{
    struct fs_fd_entry  *entry, *temp;

    xorg_list_for_each_entry_safe(entry, temp, &fs_fd_list, entry) {
	if (entry->fd == fd) {
	    xorg_list_del(&entry->entry);
	    free(entry);
	    break;
	}
    }
    RemoveNotifyFd(fd);
}

static void
adjust_fs_wait_for_delay(void *wt, unsigned long newdelay)
{
    AdjustWaitForDelay(wt, newdelay);
}

static int
_init_fs_handlers(FontPathElementPtr fpe, FontBlockHandlerProcPtr block_handler)
#else
int
init_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler)
#endif /* HAS_XFONT2 */
{
    /* if server has reset, make sure the b&w handlers are reinstalled */
    if (last_server_gen < serverGeneration) {
	last_server_gen = serverGeneration;
	fs_handlers_installed = 0;
    }
    if (fs_handlers_installed == 0) {

#ifdef DEBUG
	fprintf(stderr, "adding FS b & w handlers\n");
#endif

#ifdef HAS_XFONT2
	if (!RegisterBlockAndWakeupHandlers(fs_block_handler,
					    FontWakeup, (void *) block_handler))
#else
	if (!RegisterBlockAndWakeupHandlers(block_handler,
					    FontWakeup, (void *) 0))
#endif /* HAS_XFONT2 */
	    return AllocError;
#ifdef HAS_XFONT2
	xorg_list_init(&fs_fd_list);
#endif /* HAS_XFONT2 */
	fs_handlers_installed++;
    }
    QueueFontWakeup(fpe);
    return Successful;
}

#ifdef HAS_XFONT2
static void
_remove_fs_handlers(FontPathElementPtr fpe, FontBlockHandlerProcPtr block_handler, Bool all)
#else
void
remove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, Bool all)
#endif /* HAS_XFONT2 */
{
    if (all) {
	/* remove the handlers if no one else is using them */
	if (--fs_handlers_installed == 0) {

#ifdef DEBUG
	    fprintf(stderr, "removing FS b & w handlers\n");
#endif

#ifdef HAS_XFONT2
	    RemoveBlockAndWakeupHandlers(fs_block_handler, FontWakeup,
					 (void *) block_handler);
#else
	    RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
					 (void *) 0);
#endif /* HAS_XFONT2 */
	}
    }
    RemoveFontWakeup(fpe);
}

#ifdef HAS_XFONT2
static const xfont2_client_funcs_rec xfont2_client_funcs = {
    .version = XFONT2_CLIENT_FUNCS_VERSION,
    .client_auth_generation = _client_auth_generation,
    .client_signal = ClientSignal,
    .delete_font_client_id = delete_font_client_id,
    .verrorf = VErrorF,
    .find_old_font = find_old_font,
    .get_client_resolutions = get_client_resolutions,
    .get_default_point_size = get_default_point_size,
    .get_new_font_client_id = get_new_font_client_id,
    .get_time_in_millis = GetTimeInMillis,
    .init_fs_handlers = _init_fs_handlers,
    .register_fpe_funcs = register_fpe_funcs,
    .remove_fs_handlers = _remove_fs_handlers,
    .get_server_client = get_server_client,
    .set_font_authorizations = set_font_authorizations,
    .store_font_client_font = store_font_Client_font,
    .make_atom = MakeAtom,
    .valid_atom = ValidAtom,
    .name_for_atom = NameForAtom,
    .get_server_generation = get_server_generation,
    .add_fs_fd = add_fs_fd,
    .remove_fs_fd = remove_fs_fd,
    .adjust_fs_wait_for_delay = adjust_fs_wait_for_delay,
};

xfont2_pattern_cache_ptr fontPatternCache;

void
InitFonts(void)
{
    if (fontPatternCache)
       xfont2_free_font_pattern_cache(fontPatternCache);
    fontPatternCache = xfont2_make_font_pattern_cache();
    xfont2_init(&xfont2_client_funcs);
}
#endif /* HAS_XFONT2 */

#ifdef DEBUG
#define GLWIDTHBYTESPADDED(bits,nbytes) \
	((nbytes) == 1 ? (((bits)+7)>>3)        /* pad to 1 byte */ \
	:(nbytes) == 2 ? ((((bits)+15)>>3)&~1)  /* pad to 2 bytes */ \
	:(nbytes) == 4 ? ((((bits)+31)>>3)&~3)  /* pad to 4 bytes */ \
	:(nbytes) == 8 ? ((((bits)+63)>>3)&~7)  /* pad to 8 bytes */ \
	: 0)

#define GLYPH_SIZE(ch, nbytes)          \
	GLWIDTHBYTESPADDED((ch)->metrics.rightSideBearing - \
			(ch)->metrics.leftSideBearing, (nbytes))
void
dump_char_ascii(CharInfoPtr cip)
{
    int         r,
                l;
    int         bpr;
    int         byte;
    static unsigned maskTab[] = {
	(1 << 7), (1 << 6), (1 << 5), (1 << 4),
	(1 << 3), (1 << 2), (1 << 1), (1 << 0),
    };

    bpr = GLYPH_SIZE(cip, 4);
    for (r = 0; r < (cip->metrics.ascent + cip->metrics.descent); r++) {
	void *     row = (void *) cip->bits + r * bpr;

	byte = 0;
	for (l = 0; l <= (cip->metrics.rightSideBearing -
			  cip->metrics.leftSideBearing); l++) {
	    if (maskTab[l & 7] & (((int*)row)[l >> 3]))
		putchar('X');
	    else
		putchar('.');
	}
	putchar('\n');
    }
}

#endif
