dixfonts.c revision 05b261ec
105b261ecSmrg/************************************************************************
205b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
305b261ecSmrg
405b261ecSmrg                        All Rights Reserved
505b261ecSmrg
605b261ecSmrgPermission to use, copy, modify, and distribute this software and its
705b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
805b261ecSmrgprovided that the above copyright notice appear in all copies and that
905b261ecSmrgboth that copyright notice and this permission notice appear in
1005b261ecSmrgsupporting documentation, and that the name of Digital not be
1105b261ecSmrgused in advertising or publicity pertaining to distribution of the
1205b261ecSmrgsoftware without specific, written prior permission.
1305b261ecSmrg
1405b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1505b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1605b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1705b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1805b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1905b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2005b261ecSmrgSOFTWARE.
2105b261ecSmrg
2205b261ecSmrg************************************************************************/
2305b261ecSmrg/* The panoramix components contained the following notice */
2405b261ecSmrg/*
2505b261ecSmrgCopyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
2605b261ecSmrg
2705b261ecSmrgPermission is hereby granted, free of charge, to any person obtaining a copy
2805b261ecSmrgof this software and associated documentation files (the "Software"), to deal
2905b261ecSmrgin the Software without restriction, including without limitation the rights
3005b261ecSmrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3105b261ecSmrgcopies of the Software.
3205b261ecSmrg
3305b261ecSmrgThe above copyright notice and this permission notice shall be included in
3405b261ecSmrgall copies or substantial portions of the Software.
3505b261ecSmrg
3605b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3705b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3805b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
3905b261ecSmrgDIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
4005b261ecSmrgBUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
4205b261ecSmrgIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4305b261ecSmrg
4405b261ecSmrgExcept as contained in this notice, the name of Digital Equipment Corporation
4505b261ecSmrgshall not be used in advertising or otherwise to promote the sale, use or other
4605b261ecSmrgdealings in this Software without prior written authorization from Digital
4705b261ecSmrgEquipment Corporation.
4805b261ecSmrg
4905b261ecSmrg******************************************************************/
5005b261ecSmrg
5105b261ecSmrg#define NEED_REPLIES
5205b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5305b261ecSmrg#include <dix-config.h>
5405b261ecSmrg#endif
5505b261ecSmrg
5605b261ecSmrg#include <X11/X.h>
5705b261ecSmrg#include <X11/Xmd.h>
5805b261ecSmrg#include <X11/Xproto.h>
5905b261ecSmrg#include "scrnintstr.h"
6005b261ecSmrg#include "resource.h"
6105b261ecSmrg#include "dixstruct.h"
6205b261ecSmrg#include "cursorstr.h"
6305b261ecSmrg#include "misc.h"
6405b261ecSmrg#include "opaque.h"
6505b261ecSmrg#include "dixfontstr.h"
6605b261ecSmrg#include "closestr.h"
6705b261ecSmrg#include "dixfont.h"
6805b261ecSmrg
6905b261ecSmrg#ifdef DEBUG
7005b261ecSmrg#include	<stdio.h>
7105b261ecSmrg#endif
7205b261ecSmrg
7305b261ecSmrg#ifdef PANORAMIX
7405b261ecSmrg#include "panoramiX.h"
7505b261ecSmrg#endif
7605b261ecSmrg
7705b261ecSmrg#ifdef XF86BIGFONT
7805b261ecSmrg#define _XF86BIGFONT_SERVER_
7905b261ecSmrg#include <X11/extensions/xf86bigfont.h>
8005b261ecSmrg#endif
8105b261ecSmrg
8205b261ecSmrg#define QUERYCHARINFO(pci, pr)  *(pr) = (pci)->metrics
8305b261ecSmrg
8405b261ecSmrgextern pointer fosNaturalParams;
8505b261ecSmrgextern FontPtr defaultFont;
8605b261ecSmrg
8705b261ecSmrgstatic FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
8805b261ecSmrgstatic int  num_fpes = 0;
8905b261ecSmrg_X_EXPORT FPEFunctions *fpe_functions = (FPEFunctions *) 0;
9005b261ecSmrgstatic int  num_fpe_types = 0;
9105b261ecSmrg
9205b261ecSmrgstatic unsigned char *font_path_string;
9305b261ecSmrg
9405b261ecSmrgstatic int  num_slept_fpes = 0;
9505b261ecSmrgstatic int  size_slept_fpes = 0;
9605b261ecSmrgstatic FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
9705b261ecSmrgstatic FontPatternCachePtr patternCache;
9805b261ecSmrg
9905b261ecSmrg_X_EXPORT int
10005b261ecSmrgFontToXError(err)
10105b261ecSmrg    int         err;
10205b261ecSmrg{
10305b261ecSmrg    switch (err) {
10405b261ecSmrg    case Successful:
10505b261ecSmrg	return Success;
10605b261ecSmrg    case AllocError:
10705b261ecSmrg	return BadAlloc;
10805b261ecSmrg    case BadFontName:
10905b261ecSmrg	return BadName;
11005b261ecSmrg    case BadFontPath:
11105b261ecSmrg    case BadFontFormat:	/* is there something better? */
11205b261ecSmrg    case BadCharRange:
11305b261ecSmrg	return BadValue;
11405b261ecSmrg    default:
11505b261ecSmrg	return err;
11605b261ecSmrg    }
11705b261ecSmrg}
11805b261ecSmrg
11905b261ecSmrg
12005b261ecSmrg/*
12105b261ecSmrg * adding RT_FONT prevents conflict with default cursor font
12205b261ecSmrg */
12305b261ecSmrgBool
12405b261ecSmrgSetDefaultFont(char *defaultfontname)
12505b261ecSmrg{
12605b261ecSmrg    int         err;
12705b261ecSmrg    FontPtr     pf;
12805b261ecSmrg    XID         fid;
12905b261ecSmrg
13005b261ecSmrg    fid = FakeClientID(0);
13105b261ecSmrg    err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync,
13205b261ecSmrg		   (unsigned) strlen(defaultfontname), defaultfontname);
13305b261ecSmrg    if (err != Success)
13405b261ecSmrg	return FALSE;
13505b261ecSmrg    pf = (FontPtr) LookupIDByType(fid, RT_FONT);
13605b261ecSmrg    if (pf == (FontPtr) NULL)
13705b261ecSmrg	return FALSE;
13805b261ecSmrg    defaultFont = pf;
13905b261ecSmrg    return TRUE;
14005b261ecSmrg}
14105b261ecSmrg
14205b261ecSmrg/*
14305b261ecSmrg * note that the font wakeup queue is not refcounted.  this is because
14405b261ecSmrg * an fpe needs to be added when it's inited, and removed when it's finally
14505b261ecSmrg * freed, in order to handle any data that isn't requested, like FS events.
14605b261ecSmrg *
14705b261ecSmrg * since the only thing that should call these routines is the renderer's
14805b261ecSmrg * init_fpe() and free_fpe(), there shouldn't be any problem in using
14905b261ecSmrg * freed data.
15005b261ecSmrg */
15105b261ecSmrgvoid
15205b261ecSmrgQueueFontWakeup(FontPathElementPtr fpe)
15305b261ecSmrg{
15405b261ecSmrg    int         i;
15505b261ecSmrg    FontPathElementPtr *new;
15605b261ecSmrg
15705b261ecSmrg    for (i = 0; i < num_slept_fpes; i++) {
15805b261ecSmrg	if (slept_fpes[i] == fpe) {
15905b261ecSmrg	    return;
16005b261ecSmrg	}
16105b261ecSmrg    }
16205b261ecSmrg    if (num_slept_fpes == size_slept_fpes) {
16305b261ecSmrg	new = (FontPathElementPtr *)
16405b261ecSmrg	    xrealloc(slept_fpes,
16505b261ecSmrg		     sizeof(FontPathElementPtr) * (size_slept_fpes + 4));
16605b261ecSmrg	if (!new)
16705b261ecSmrg	    return;
16805b261ecSmrg	slept_fpes = new;
16905b261ecSmrg	size_slept_fpes += 4;
17005b261ecSmrg    }
17105b261ecSmrg    slept_fpes[num_slept_fpes] = fpe;
17205b261ecSmrg    num_slept_fpes++;
17305b261ecSmrg}
17405b261ecSmrg
17505b261ecSmrgvoid
17605b261ecSmrgRemoveFontWakeup(FontPathElementPtr fpe)
17705b261ecSmrg{
17805b261ecSmrg    int         i,
17905b261ecSmrg                j;
18005b261ecSmrg
18105b261ecSmrg    for (i = 0; i < num_slept_fpes; i++) {
18205b261ecSmrg	if (slept_fpes[i] == fpe) {
18305b261ecSmrg	    for (j = i; j < num_slept_fpes; j++) {
18405b261ecSmrg		slept_fpes[j] = slept_fpes[j + 1];
18505b261ecSmrg	    }
18605b261ecSmrg	    num_slept_fpes--;
18705b261ecSmrg	    return;
18805b261ecSmrg	}
18905b261ecSmrg    }
19005b261ecSmrg}
19105b261ecSmrg
19205b261ecSmrgvoid
19305b261ecSmrgFontWakeup(pointer data, int count, pointer LastSelectMask)
19405b261ecSmrg{
19505b261ecSmrg    int         i;
19605b261ecSmrg    FontPathElementPtr fpe;
19705b261ecSmrg
19805b261ecSmrg    if (count < 0)
19905b261ecSmrg	return;
20005b261ecSmrg    /* wake up any fpe's that may be waiting for information */
20105b261ecSmrg    for (i = 0; i < num_slept_fpes; i++) {
20205b261ecSmrg	fpe = slept_fpes[i];
20305b261ecSmrg	(void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask);
20405b261ecSmrg    }
20505b261ecSmrg}
20605b261ecSmrg
20705b261ecSmrg/* XXX -- these two funcs may want to be broken into macros */
20805b261ecSmrgstatic void
20905b261ecSmrgUseFPE(FontPathElementPtr fpe)
21005b261ecSmrg{
21105b261ecSmrg    fpe->refcount++;
21205b261ecSmrg}
21305b261ecSmrg
21405b261ecSmrgstatic void
21505b261ecSmrgFreeFPE (FontPathElementPtr fpe)
21605b261ecSmrg{
21705b261ecSmrg    fpe->refcount--;
21805b261ecSmrg    if (fpe->refcount == 0) {
21905b261ecSmrg	(*fpe_functions[fpe->type].free_fpe) (fpe);
22005b261ecSmrg	xfree(fpe->name);
22105b261ecSmrg	xfree(fpe);
22205b261ecSmrg    }
22305b261ecSmrg}
22405b261ecSmrg
22505b261ecSmrgstatic Bool
22605b261ecSmrgdoOpenFont(ClientPtr client, OFclosurePtr c)
22705b261ecSmrg{
22805b261ecSmrg    FontPtr     pfont = NullFont;
22905b261ecSmrg    FontPathElementPtr fpe = NULL;
23005b261ecSmrg    ScreenPtr   pScr;
23105b261ecSmrg    int         err = Successful;
23205b261ecSmrg    int         i;
23305b261ecSmrg    char       *alias,
23405b261ecSmrg               *newname;
23505b261ecSmrg    int         newlen;
23605b261ecSmrg    int		aliascount = 20;
23705b261ecSmrg    /*
23805b261ecSmrg     * Decide at runtime what FontFormat to use.
23905b261ecSmrg     */
24005b261ecSmrg    Mask FontFormat =
24105b261ecSmrg
24205b261ecSmrg	((screenInfo.imageByteOrder == LSBFirst) ?
24305b261ecSmrg	    BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) |
24405b261ecSmrg
24505b261ecSmrg	((screenInfo.bitmapBitOrder == LSBFirst) ?
24605b261ecSmrg	    BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) |
24705b261ecSmrg
24805b261ecSmrg	BitmapFormatImageRectMin |
24905b261ecSmrg
25005b261ecSmrg#if GLYPHPADBYTES == 1
25105b261ecSmrg	BitmapFormatScanlinePad8 |
25205b261ecSmrg#endif
25305b261ecSmrg
25405b261ecSmrg#if GLYPHPADBYTES == 2
25505b261ecSmrg	BitmapFormatScanlinePad16 |
25605b261ecSmrg#endif
25705b261ecSmrg
25805b261ecSmrg#if GLYPHPADBYTES == 4
25905b261ecSmrg	BitmapFormatScanlinePad32 |
26005b261ecSmrg#endif
26105b261ecSmrg
26205b261ecSmrg#if GLYPHPADBYTES == 8
26305b261ecSmrg	BitmapFormatScanlinePad64 |
26405b261ecSmrg#endif
26505b261ecSmrg
26605b261ecSmrg	BitmapFormatScanlineUnit8;
26705b261ecSmrg
26805b261ecSmrg    if (client->clientGone)
26905b261ecSmrg    {
27005b261ecSmrg	if (c->current_fpe < c->num_fpes)
27105b261ecSmrg	{
27205b261ecSmrg	    fpe = c->fpe_list[c->current_fpe];
27305b261ecSmrg	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
27405b261ecSmrg	}
27505b261ecSmrg	err = Successful;
27605b261ecSmrg	goto bail;
27705b261ecSmrg    }
27805b261ecSmrg    while (c->current_fpe < c->num_fpes) {
27905b261ecSmrg	fpe = c->fpe_list[c->current_fpe];
28005b261ecSmrg	err = (*fpe_functions[fpe->type].open_font)
28105b261ecSmrg	    ((pointer) client, fpe, c->flags,
28205b261ecSmrg	     c->fontname, c->fnamelen, FontFormat,
28305b261ecSmrg	     BitmapFormatMaskByte |
28405b261ecSmrg	     BitmapFormatMaskBit |
28505b261ecSmrg	     BitmapFormatMaskImageRectangle |
28605b261ecSmrg	     BitmapFormatMaskScanLinePad |
28705b261ecSmrg	     BitmapFormatMaskScanLineUnit,
28805b261ecSmrg	     c->fontid, &pfont, &alias,
28905b261ecSmrg	     c->non_cachable_font && c->non_cachable_font->fpe == fpe ?
29005b261ecSmrg		 c->non_cachable_font :
29105b261ecSmrg		 (FontPtr)0);
29205b261ecSmrg
29305b261ecSmrg	if (err == FontNameAlias && alias) {
29405b261ecSmrg	    newlen = strlen(alias);
29505b261ecSmrg	    newname = (char *) xrealloc(c->fontname, newlen);
29605b261ecSmrg	    if (!newname) {
29705b261ecSmrg		err = AllocError;
29805b261ecSmrg		break;
29905b261ecSmrg	    }
30005b261ecSmrg	    memmove(newname, alias, newlen);
30105b261ecSmrg	    c->fontname = newname;
30205b261ecSmrg	    c->fnamelen = newlen;
30305b261ecSmrg	    c->current_fpe = 0;
30405b261ecSmrg	    if (--aliascount <= 0)
30505b261ecSmrg		break;
30605b261ecSmrg	    continue;
30705b261ecSmrg	}
30805b261ecSmrg	if (err == BadFontName) {
30905b261ecSmrg	    c->current_fpe++;
31005b261ecSmrg	    continue;
31105b261ecSmrg	}
31205b261ecSmrg	if (err == Suspended) {
31305b261ecSmrg	    if (!c->slept) {
31405b261ecSmrg		c->slept = TRUE;
31505b261ecSmrg		ClientSleep(client, (ClientSleepProcPtr)doOpenFont, (pointer) c);
31605b261ecSmrg	    }
31705b261ecSmrg	    return TRUE;
31805b261ecSmrg	}
31905b261ecSmrg	break;
32005b261ecSmrg    }
32105b261ecSmrg
32205b261ecSmrg    if (err != Successful)
32305b261ecSmrg	goto bail;
32405b261ecSmrg    if (!pfont) {
32505b261ecSmrg	err = BadFontName;
32605b261ecSmrg	goto bail;
32705b261ecSmrg    }
32805b261ecSmrg    /* check values for firstCol, lastCol, firstRow, and lastRow */
32905b261ecSmrg    if (pfont->info.firstCol > pfont->info.lastCol ||
33005b261ecSmrg       pfont->info.firstRow > pfont->info.lastRow ||
33105b261ecSmrg       pfont->info.lastCol - pfont->info.firstCol > 255) {
33205b261ecSmrg       err = AllocError;
33305b261ecSmrg       goto bail;
33405b261ecSmrg    }
33505b261ecSmrg    if (!pfont->fpe)
33605b261ecSmrg	pfont->fpe = fpe;
33705b261ecSmrg    pfont->refcnt++;
33805b261ecSmrg    if (pfont->refcnt == 1) {
33905b261ecSmrg	UseFPE(pfont->fpe);
34005b261ecSmrg	for (i = 0; i < screenInfo.numScreens; i++) {
34105b261ecSmrg	    pScr = screenInfo.screens[i];
34205b261ecSmrg	    if (pScr->RealizeFont)
34305b261ecSmrg	    {
34405b261ecSmrg		if (!(*pScr->RealizeFont) (pScr, pfont))
34505b261ecSmrg		{
34605b261ecSmrg		    CloseFont (pfont, (Font) 0);
34705b261ecSmrg		    err = AllocError;
34805b261ecSmrg		    goto bail;
34905b261ecSmrg		}
35005b261ecSmrg	    }
35105b261ecSmrg	}
35205b261ecSmrg    }
35305b261ecSmrg    if (!AddResource(c->fontid, RT_FONT, (pointer) pfont)) {
35405b261ecSmrg	err = AllocError;
35505b261ecSmrg	goto bail;
35605b261ecSmrg    }
35705b261ecSmrg    if (patternCache && pfont != c->non_cachable_font)
35805b261ecSmrg	CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen,
35905b261ecSmrg			 pfont);
36005b261ecSmrgbail:
36105b261ecSmrg    if (err != Successful && c->client != serverClient) {
36205b261ecSmrg	SendErrorToClient(c->client, X_OpenFont, 0,
36305b261ecSmrg			  c->fontid, FontToXError(err));
36405b261ecSmrg    }
36505b261ecSmrg    if (c->slept)
36605b261ecSmrg	ClientWakeup(c->client);
36705b261ecSmrg    for (i = 0; i < c->num_fpes; i++) {
36805b261ecSmrg	FreeFPE(c->fpe_list[i]);
36905b261ecSmrg    }
37005b261ecSmrg    xfree(c->fpe_list);
37105b261ecSmrg    xfree(c->fontname);
37205b261ecSmrg    xfree(c);
37305b261ecSmrg    return TRUE;
37405b261ecSmrg}
37505b261ecSmrg
37605b261ecSmrgint
37705b261ecSmrgOpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, char *pfontname)
37805b261ecSmrg{
37905b261ecSmrg    OFclosurePtr c;
38005b261ecSmrg    int         i;
38105b261ecSmrg    FontPtr     cached = (FontPtr)0;
38205b261ecSmrg
38305b261ecSmrg#ifdef FONTDEBUG
38405b261ecSmrg    char *f;
38505b261ecSmrg    f = (char *)xalloc(lenfname + 1);
38605b261ecSmrg    memmove(f, pfontname, lenfname);
38705b261ecSmrg    f[lenfname] = '\0';
38805b261ecSmrg    ErrorF("OpenFont: fontname is \"%s\"\n", f);
38905b261ecSmrg    xfree(f);
39005b261ecSmrg#endif
39105b261ecSmrg    if (!lenfname || lenfname > XLFDMAXFONTNAMELEN)
39205b261ecSmrg	return BadName;
39305b261ecSmrg    if (patternCache)
39405b261ecSmrg    {
39505b261ecSmrg
39605b261ecSmrg    /*
39705b261ecSmrg    ** Check name cache.  If we find a cached version of this font that
39805b261ecSmrg    ** is cachable, immediately satisfy the request with it.  If we find
39905b261ecSmrg    ** a cached version of this font that is non-cachable, we do not
40005b261ecSmrg    ** satisfy the request with it.  Instead, we pass the FontPtr to the
40105b261ecSmrg    ** FPE's open_font code (the fontfile FPE in turn passes the
40205b261ecSmrg    ** information to the rasterizer; the fserve FPE ignores it).
40305b261ecSmrg    **
40405b261ecSmrg    ** Presumably, the font is marked non-cachable because the FPE has
40505b261ecSmrg    ** put some licensing restrictions on it.  If the FPE, using
40605b261ecSmrg    ** whatever logic it relies on, determines that it is willing to
40705b261ecSmrg    ** share this existing font with the client, then it has the option
40805b261ecSmrg    ** to return the FontPtr we passed it as the newly-opened font.
40905b261ecSmrg    ** This allows the FPE to exercise its licensing logic without
41005b261ecSmrg    ** having to create another instance of a font that already exists.
41105b261ecSmrg    */
41205b261ecSmrg
41305b261ecSmrg	cached = FindCachedFontPattern(patternCache, pfontname, lenfname);
41405b261ecSmrg	if (cached && cached->info.cachable)
41505b261ecSmrg	{
41605b261ecSmrg	    if (!AddResource(fid, RT_FONT, (pointer) cached))
41705b261ecSmrg		return BadAlloc;
41805b261ecSmrg	    cached->refcnt++;
41905b261ecSmrg	    return Success;
42005b261ecSmrg	}
42105b261ecSmrg    }
42205b261ecSmrg    c = (OFclosurePtr) xalloc(sizeof(OFclosureRec));
42305b261ecSmrg    if (!c)
42405b261ecSmrg	return BadAlloc;
42505b261ecSmrg    c->fontname = (char *) xalloc(lenfname);
42605b261ecSmrg    c->origFontName = pfontname;
42705b261ecSmrg    c->origFontNameLen = lenfname;
42805b261ecSmrg    if (!c->fontname) {
42905b261ecSmrg	xfree(c);
43005b261ecSmrg	return BadAlloc;
43105b261ecSmrg    }
43205b261ecSmrg    /*
43305b261ecSmrg     * copy the current FPE list, so that if it gets changed by another client
43405b261ecSmrg     * while we're blocking, the request still appears atomic
43505b261ecSmrg     */
43605b261ecSmrg    c->fpe_list = (FontPathElementPtr *)
43705b261ecSmrg	xalloc(sizeof(FontPathElementPtr) * num_fpes);
43805b261ecSmrg    if (!c->fpe_list) {
43905b261ecSmrg	xfree(c->fontname);
44005b261ecSmrg	xfree(c);
44105b261ecSmrg	return BadAlloc;
44205b261ecSmrg    }
44305b261ecSmrg    memmove(c->fontname, pfontname, lenfname);
44405b261ecSmrg    for (i = 0; i < num_fpes; i++) {
44505b261ecSmrg	c->fpe_list[i] = font_path_elements[i];
44605b261ecSmrg	UseFPE(c->fpe_list[i]);
44705b261ecSmrg    }
44805b261ecSmrg    c->client = client;
44905b261ecSmrg    c->fontid = fid;
45005b261ecSmrg    c->current_fpe = 0;
45105b261ecSmrg    c->num_fpes = num_fpes;
45205b261ecSmrg    c->fnamelen = lenfname;
45305b261ecSmrg    c->slept = FALSE;
45405b261ecSmrg    c->flags = flags;
45505b261ecSmrg    c->non_cachable_font = cached;
45605b261ecSmrg
45705b261ecSmrg    (void) doOpenFont(client, c);
45805b261ecSmrg    return Success;
45905b261ecSmrg}
46005b261ecSmrg
46105b261ecSmrg/**
46205b261ecSmrg * Decrement font's ref count, and free storage if ref count equals zero
46305b261ecSmrg *
46405b261ecSmrg *  \param value must conform to DeleteType
46505b261ecSmrg */
46605b261ecSmrg_X_EXPORT int
46705b261ecSmrgCloseFont(pointer value, XID fid)
46805b261ecSmrg{
46905b261ecSmrg    int         nscr;
47005b261ecSmrg    ScreenPtr   pscr;
47105b261ecSmrg    FontPathElementPtr fpe;
47205b261ecSmrg    FontPtr     pfont = (FontPtr)value;
47305b261ecSmrg
47405b261ecSmrg    if (pfont == NullFont)
47505b261ecSmrg	return (Success);
47605b261ecSmrg    if (--pfont->refcnt == 0) {
47705b261ecSmrg	if (patternCache)
47805b261ecSmrg	    RemoveCachedFontPattern (patternCache, pfont);
47905b261ecSmrg	/*
48005b261ecSmrg	 * since the last reference is gone, ask each screen to free any
48105b261ecSmrg	 * storage it may have allocated locally for it.
48205b261ecSmrg	 */
48305b261ecSmrg	for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
48405b261ecSmrg	    pscr = screenInfo.screens[nscr];
48505b261ecSmrg	    if (pscr->UnrealizeFont)
48605b261ecSmrg		(*pscr->UnrealizeFont) (pscr, pfont);
48705b261ecSmrg	}
48805b261ecSmrg	if (pfont == defaultFont)
48905b261ecSmrg	    defaultFont = NULL;
49005b261ecSmrg#ifdef XF86BIGFONT
49105b261ecSmrg	XF86BigfontFreeFontShm(pfont);
49205b261ecSmrg#endif
49305b261ecSmrg	fpe = pfont->fpe;
49405b261ecSmrg	(*fpe_functions[fpe->type].close_font) (fpe, pfont);
49505b261ecSmrg	FreeFPE(fpe);
49605b261ecSmrg    }
49705b261ecSmrg    return (Success);
49805b261ecSmrg}
49905b261ecSmrg
50005b261ecSmrg
50105b261ecSmrg/***====================================================================***/
50205b261ecSmrg
50305b261ecSmrg/**
50405b261ecSmrg * Sets up pReply as the correct QueryFontReply for pFont with the first
50505b261ecSmrg * nProtoCCIStructs char infos.
50605b261ecSmrg *
50705b261ecSmrg *  \param pReply caller must allocate this storage
50805b261ecSmrg  */
50905b261ecSmrgvoid
51005b261ecSmrgQueryFont(FontPtr pFont, xQueryFontReply *pReply, int nProtoCCIStructs)
51105b261ecSmrg{
51205b261ecSmrg    FontPropPtr      pFP;
51305b261ecSmrg    int              r,
51405b261ecSmrg                     c,
51505b261ecSmrg                     i;
51605b261ecSmrg    xFontProp       *prFP;
51705b261ecSmrg    xCharInfo       *prCI;
51805b261ecSmrg    xCharInfo       *charInfos[256];
51905b261ecSmrg    unsigned char    chars[512];
52005b261ecSmrg    int              ninfos;
52105b261ecSmrg    unsigned long    ncols;
52205b261ecSmrg    unsigned long    count;
52305b261ecSmrg
52405b261ecSmrg    /* pr->length set in dispatch */
52505b261ecSmrg    pReply->minCharOrByte2 = pFont->info.firstCol;
52605b261ecSmrg    pReply->defaultChar = pFont->info.defaultCh;
52705b261ecSmrg    pReply->maxCharOrByte2 = pFont->info.lastCol;
52805b261ecSmrg    pReply->drawDirection = pFont->info.drawDirection;
52905b261ecSmrg    pReply->allCharsExist = pFont->info.allExist;
53005b261ecSmrg    pReply->minByte1 = pFont->info.firstRow;
53105b261ecSmrg    pReply->maxByte1 = pFont->info.lastRow;
53205b261ecSmrg    pReply->fontAscent = pFont->info.fontAscent;
53305b261ecSmrg    pReply->fontDescent = pFont->info.fontDescent;
53405b261ecSmrg
53505b261ecSmrg    pReply->minBounds = pFont->info.ink_minbounds;
53605b261ecSmrg    pReply->maxBounds = pFont->info.ink_maxbounds;
53705b261ecSmrg
53805b261ecSmrg    pReply->nFontProps = pFont->info.nprops;
53905b261ecSmrg    pReply->nCharInfos = nProtoCCIStructs;
54005b261ecSmrg
54105b261ecSmrg    for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]);
54205b261ecSmrg	    i < pFont->info.nprops;
54305b261ecSmrg	    i++, pFP++, prFP++) {
54405b261ecSmrg	prFP->name = pFP->name;
54505b261ecSmrg	prFP->value = pFP->value;
54605b261ecSmrg    }
54705b261ecSmrg
54805b261ecSmrg    ninfos = 0;
54905b261ecSmrg    ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1);
55005b261ecSmrg    prCI = (xCharInfo *) (prFP);
55105b261ecSmrg    for (r = pFont->info.firstRow;
55205b261ecSmrg	    ninfos < nProtoCCIStructs && r <= (int)pFont->info.lastRow;
55305b261ecSmrg	    r++) {
55405b261ecSmrg	i = 0;
55505b261ecSmrg	for (c = pFont->info.firstCol; c <= (int)pFont->info.lastCol; c++) {
55605b261ecSmrg	    chars[i++] = r;
55705b261ecSmrg	    chars[i++] = c;
55805b261ecSmrg	}
55905b261ecSmrg	(*pFont->get_metrics) (pFont, ncols, chars,
56005b261ecSmrg				TwoD16Bit, &count, charInfos);
56105b261ecSmrg	i = 0;
56205b261ecSmrg	for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) {
56305b261ecSmrg	    *prCI = *charInfos[i];
56405b261ecSmrg	    prCI++;
56505b261ecSmrg	    ninfos++;
56605b261ecSmrg	}
56705b261ecSmrg    }
56805b261ecSmrg    return;
56905b261ecSmrg}
57005b261ecSmrg
57105b261ecSmrgstatic Bool
57205b261ecSmrgdoListFontsAndAliases(ClientPtr client, LFclosurePtr c)
57305b261ecSmrg{
57405b261ecSmrg    FontPathElementPtr fpe;
57505b261ecSmrg    int         err = Successful;
57605b261ecSmrg    FontNamesPtr names = NULL;
57705b261ecSmrg    char       *name, *resolved=NULL;
57805b261ecSmrg    int         namelen, resolvedlen;
57905b261ecSmrg    int		nnames;
58005b261ecSmrg    int         stringLens;
58105b261ecSmrg    int         i;
58205b261ecSmrg    xListFontsReply reply;
58305b261ecSmrg    char	*bufptr;
58405b261ecSmrg    char	*bufferStart;
58505b261ecSmrg    int		aliascount = 0;
58605b261ecSmrg
58705b261ecSmrg    if (client->clientGone)
58805b261ecSmrg    {
58905b261ecSmrg	if (c->current.current_fpe < c->num_fpes)
59005b261ecSmrg	{
59105b261ecSmrg	    fpe = c->fpe_list[c->current.current_fpe];
59205b261ecSmrg	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
59305b261ecSmrg	}
59405b261ecSmrg	err = Successful;
59505b261ecSmrg	goto bail;
59605b261ecSmrg    }
59705b261ecSmrg
59805b261ecSmrg    if (!c->current.patlen)
59905b261ecSmrg	goto finish;
60005b261ecSmrg
60105b261ecSmrg    while (c->current.current_fpe < c->num_fpes) {
60205b261ecSmrg	fpe = c->fpe_list[c->current.current_fpe];
60305b261ecSmrg	err = Successful;
60405b261ecSmrg
60505b261ecSmrg	if (!fpe_functions[fpe->type].start_list_fonts_and_aliases)
60605b261ecSmrg	{
60705b261ecSmrg	    /* This FPE doesn't support/require list_fonts_and_aliases */
60805b261ecSmrg
60905b261ecSmrg	    err = (*fpe_functions[fpe->type].list_fonts)
61005b261ecSmrg		((pointer) c->client, fpe, c->current.pattern,
61105b261ecSmrg		 c->current.patlen, c->current.max_names - c->names->nnames,
61205b261ecSmrg		 c->names);
61305b261ecSmrg
61405b261ecSmrg	    if (err == Suspended) {
61505b261ecSmrg		if (!c->slept) {
61605b261ecSmrg		    c->slept = TRUE;
61705b261ecSmrg		    ClientSleep(client,
61805b261ecSmrg			(ClientSleepProcPtr)doListFontsAndAliases,
61905b261ecSmrg			(pointer) c);
62005b261ecSmrg		}
62105b261ecSmrg		return TRUE;
62205b261ecSmrg	    }
62305b261ecSmrg
62405b261ecSmrg	    err = BadFontName;
62505b261ecSmrg	}
62605b261ecSmrg	else
62705b261ecSmrg	{
62805b261ecSmrg	    /* Start of list_fonts_and_aliases functionality.  Modeled
62905b261ecSmrg	       after list_fonts_with_info in that it resolves aliases,
63005b261ecSmrg	       except that the information collected from FPEs is just
63105b261ecSmrg	       names, not font info.  Each list_next_font_or_alias()
63205b261ecSmrg	       returns either a name into name/namelen or an alias into
63305b261ecSmrg	       name/namelen and its target name into resolved/resolvedlen.
63405b261ecSmrg	       The code at this level then resolves the alias by polling
63505b261ecSmrg	       the FPEs.  */
63605b261ecSmrg
63705b261ecSmrg	    if (!c->current.list_started) {
63805b261ecSmrg		err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases)
63905b261ecSmrg		    ((pointer) c->client, fpe, c->current.pattern,
64005b261ecSmrg		     c->current.patlen, c->current.max_names - c->names->nnames,
64105b261ecSmrg		     &c->current.private);
64205b261ecSmrg		if (err == Suspended) {
64305b261ecSmrg		    if (!c->slept) {
64405b261ecSmrg			ClientSleep(client,
64505b261ecSmrg				    (ClientSleepProcPtr)doListFontsAndAliases,
64605b261ecSmrg				    (pointer) c);
64705b261ecSmrg			c->slept = TRUE;
64805b261ecSmrg		    }
64905b261ecSmrg		    return TRUE;
65005b261ecSmrg		}
65105b261ecSmrg		if (err == Successful)
65205b261ecSmrg		    c->current.list_started = TRUE;
65305b261ecSmrg	    }
65405b261ecSmrg	    if (err == Successful) {
65505b261ecSmrg		char    *tmpname;
65605b261ecSmrg		name = 0;
65705b261ecSmrg		err = (*fpe_functions[fpe->type].list_next_font_or_alias)
65805b261ecSmrg		    ((pointer) c->client, fpe, &name, &namelen, &tmpname,
65905b261ecSmrg		     &resolvedlen, c->current.private);
66005b261ecSmrg		if (err == Suspended) {
66105b261ecSmrg		    if (!c->slept) {
66205b261ecSmrg			ClientSleep(client,
66305b261ecSmrg				    (ClientSleepProcPtr)doListFontsAndAliases,
66405b261ecSmrg				    (pointer) c);
66505b261ecSmrg			c->slept = TRUE;
66605b261ecSmrg		    }
66705b261ecSmrg		    return TRUE;
66805b261ecSmrg		}
66905b261ecSmrg		if (err == FontNameAlias) {
67005b261ecSmrg		    if (resolved) xfree(resolved);
67105b261ecSmrg		    resolved = (char *) xalloc(resolvedlen + 1);
67205b261ecSmrg		    if (resolved)
67305b261ecSmrg			memmove(resolved, tmpname, resolvedlen + 1);
67405b261ecSmrg		}
67505b261ecSmrg	    }
67605b261ecSmrg
67705b261ecSmrg	    if (err == Successful)
67805b261ecSmrg	    {
67905b261ecSmrg		if (c->haveSaved)
68005b261ecSmrg		{
68105b261ecSmrg		    if (c->savedName)
68205b261ecSmrg			(void)AddFontNamesName(c->names, c->savedName,
68305b261ecSmrg					       c->savedNameLen);
68405b261ecSmrg		}
68505b261ecSmrg		else
68605b261ecSmrg		    (void)AddFontNamesName(c->names, name, namelen);
68705b261ecSmrg	    }
68805b261ecSmrg
68905b261ecSmrg	    /*
69005b261ecSmrg	     * When we get an alias back, save our state and reset back to
69105b261ecSmrg	     * the start of the FPE looking for the specified name.  As
69205b261ecSmrg	     * soon as a real font is found for the alias, pop back to the
69305b261ecSmrg	     * old state
69405b261ecSmrg	     */
69505b261ecSmrg	    else if (err == FontNameAlias) {
69605b261ecSmrg		char	tmp_pattern[XLFDMAXFONTNAMELEN];
69705b261ecSmrg		/*
69805b261ecSmrg		 * when an alias recurses, we need to give
69905b261ecSmrg		 * the last FPE a chance to clean up; so we call
70005b261ecSmrg		 * it again, and assume that the error returned
70105b261ecSmrg		 * is BadFontName, indicating the alias resolution
70205b261ecSmrg		 * is complete.
70305b261ecSmrg		 */
70405b261ecSmrg		memmove(tmp_pattern, resolved, resolvedlen);
70505b261ecSmrg		if (c->haveSaved)
70605b261ecSmrg		{
70705b261ecSmrg		    char    *tmpname;
70805b261ecSmrg		    int     tmpnamelen;
70905b261ecSmrg
71005b261ecSmrg		    tmpname = 0;
71105b261ecSmrg		    (void) (*fpe_functions[fpe->type].list_next_font_or_alias)
71205b261ecSmrg			((pointer) c->client, fpe, &tmpname, &tmpnamelen,
71305b261ecSmrg			 &tmpname, &tmpnamelen, c->current.private);
71405b261ecSmrg		    if (--aliascount <= 0)
71505b261ecSmrg		    {
71605b261ecSmrg			err = BadFontName;
71705b261ecSmrg			goto ContBadFontName;
71805b261ecSmrg		    }
71905b261ecSmrg		}
72005b261ecSmrg		else
72105b261ecSmrg		{
72205b261ecSmrg		    c->saved = c->current;
72305b261ecSmrg		    c->haveSaved = TRUE;
72405b261ecSmrg		    if (c->savedName)
72505b261ecSmrg			xfree(c->savedName);
72605b261ecSmrg		    c->savedName = (char *)xalloc(namelen + 1);
72705b261ecSmrg		    if (c->savedName)
72805b261ecSmrg			memmove(c->savedName, name, namelen + 1);
72905b261ecSmrg		    c->savedNameLen = namelen;
73005b261ecSmrg		    aliascount = 20;
73105b261ecSmrg		}
73205b261ecSmrg		memmove(c->current.pattern, tmp_pattern, resolvedlen);
73305b261ecSmrg		c->current.patlen = resolvedlen;
73405b261ecSmrg		c->current.max_names = c->names->nnames + 1;
73505b261ecSmrg		c->current.current_fpe = -1;
73605b261ecSmrg		c->current.private = 0;
73705b261ecSmrg		err = BadFontName;
73805b261ecSmrg	    }
73905b261ecSmrg	}
74005b261ecSmrg	/*
74105b261ecSmrg	 * At the end of this FPE, step to the next.  If we've finished
74205b261ecSmrg	 * processing an alias, pop state back. If we've collected enough
74305b261ecSmrg	 * font names, quit.
74405b261ecSmrg	 */
74505b261ecSmrg	if (err == BadFontName) {
74605b261ecSmrg	  ContBadFontName: ;
74705b261ecSmrg	    c->current.list_started = FALSE;
74805b261ecSmrg	    c->current.current_fpe++;
74905b261ecSmrg	    err = Successful;
75005b261ecSmrg	    if (c->haveSaved)
75105b261ecSmrg	    {
75205b261ecSmrg		if (c->names->nnames == c->current.max_names ||
75305b261ecSmrg			c->current.current_fpe == c->num_fpes) {
75405b261ecSmrg		    c->haveSaved = FALSE;
75505b261ecSmrg		    c->current = c->saved;
75605b261ecSmrg		    /* Give the saved namelist a chance to clean itself up */
75705b261ecSmrg		    continue;
75805b261ecSmrg		}
75905b261ecSmrg	    }
76005b261ecSmrg	    if (c->names->nnames == c->current.max_names)
76105b261ecSmrg		break;
76205b261ecSmrg	}
76305b261ecSmrg    }
76405b261ecSmrg
76505b261ecSmrg    /*
76605b261ecSmrg     * send the reply
76705b261ecSmrg     */
76805b261ecSmrg    if (err != Successful) {
76905b261ecSmrg	SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err));
77005b261ecSmrg	goto bail;
77105b261ecSmrg    }
77205b261ecSmrg
77305b261ecSmrgfinish:
77405b261ecSmrg
77505b261ecSmrg    names = c->names;
77605b261ecSmrg    nnames = names->nnames;
77705b261ecSmrg    client = c->client;
77805b261ecSmrg    stringLens = 0;
77905b261ecSmrg    for (i = 0; i < nnames; i++)
78005b261ecSmrg	stringLens += (names->length[i] <= 255) ? names->length[i] : 0;
78105b261ecSmrg
78205b261ecSmrg    reply.type = X_Reply;
78305b261ecSmrg    reply.length = (stringLens + nnames + 3) >> 2;
78405b261ecSmrg    reply.nFonts = nnames;
78505b261ecSmrg    reply.sequenceNumber = client->sequence;
78605b261ecSmrg
78705b261ecSmrg    bufptr = bufferStart = (char *) ALLOCATE_LOCAL(reply.length << 2);
78805b261ecSmrg
78905b261ecSmrg    if (!bufptr && reply.length) {
79005b261ecSmrg	SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc);
79105b261ecSmrg	goto bail;
79205b261ecSmrg    }
79305b261ecSmrg    /*
79405b261ecSmrg     * since WriteToClient long word aligns things, copy to temp buffer and
79505b261ecSmrg     * write all at once
79605b261ecSmrg     */
79705b261ecSmrg    for (i = 0; i < nnames; i++) {
79805b261ecSmrg	if (names->length[i] > 255)
79905b261ecSmrg	    reply.nFonts--;
80005b261ecSmrg	else
80105b261ecSmrg	{
80205b261ecSmrg	    *bufptr++ = names->length[i];
80305b261ecSmrg	    memmove( bufptr, names->names[i], names->length[i]);
80405b261ecSmrg	    bufptr += names->length[i];
80505b261ecSmrg	}
80605b261ecSmrg    }
80705b261ecSmrg    nnames = reply.nFonts;
80805b261ecSmrg    reply.length = (stringLens + nnames + 3) >> 2;
80905b261ecSmrg    client->pSwapReplyFunc = ReplySwapVector[X_ListFonts];
81005b261ecSmrg    WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply);
81105b261ecSmrg    (void) WriteToClient(client, stringLens + nnames, bufferStart);
81205b261ecSmrg    DEALLOCATE_LOCAL(bufferStart);
81305b261ecSmrg
81405b261ecSmrgbail:
81505b261ecSmrg    if (c->slept)
81605b261ecSmrg	ClientWakeup(client);
81705b261ecSmrg    for (i = 0; i < c->num_fpes; i++)
81805b261ecSmrg	FreeFPE(c->fpe_list[i]);
81905b261ecSmrg    xfree(c->fpe_list);
82005b261ecSmrg    if (c->savedName) xfree(c->savedName);
82105b261ecSmrg    FreeFontNames(names);
82205b261ecSmrg    xfree(c);
82305b261ecSmrg    if (resolved) xfree(resolved);
82405b261ecSmrg    return TRUE;
82505b261ecSmrg}
82605b261ecSmrg
82705b261ecSmrgint
82805b261ecSmrgListFonts(ClientPtr client, unsigned char *pattern, unsigned length,
82905b261ecSmrg          unsigned max_names)
83005b261ecSmrg{
83105b261ecSmrg    int         i;
83205b261ecSmrg    LFclosurePtr c;
83305b261ecSmrg
83405b261ecSmrg    /*
83505b261ecSmrg     * The right error to return here would be BadName, however the
83605b261ecSmrg     * specification does not allow for a Name error on this request.
83705b261ecSmrg     * Perhaps a better solution would be to return a nil list, i.e.
83805b261ecSmrg     * a list containing zero fontnames.
83905b261ecSmrg     */
84005b261ecSmrg    if (length > XLFDMAXFONTNAMELEN)
84105b261ecSmrg	return BadAlloc;
84205b261ecSmrg
84305b261ecSmrg    if (!(c = (LFclosurePtr) xalloc(sizeof *c)))
84405b261ecSmrg	return BadAlloc;
84505b261ecSmrg    c->fpe_list = (FontPathElementPtr *)
84605b261ecSmrg	xalloc(sizeof(FontPathElementPtr) * num_fpes);
84705b261ecSmrg    if (!c->fpe_list) {
84805b261ecSmrg	xfree(c);
84905b261ecSmrg	return BadAlloc;
85005b261ecSmrg    }
85105b261ecSmrg    c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100);
85205b261ecSmrg    if (!c->names)
85305b261ecSmrg    {
85405b261ecSmrg	xfree(c->fpe_list);
85505b261ecSmrg	xfree(c);
85605b261ecSmrg	return BadAlloc;
85705b261ecSmrg    }
85805b261ecSmrg    memmove( c->current.pattern, pattern, length);
85905b261ecSmrg    for (i = 0; i < num_fpes; i++) {
86005b261ecSmrg	c->fpe_list[i] = font_path_elements[i];
86105b261ecSmrg	UseFPE(c->fpe_list[i]);
86205b261ecSmrg    }
86305b261ecSmrg    c->client = client;
86405b261ecSmrg    c->num_fpes = num_fpes;
86505b261ecSmrg    c->current.patlen = length;
86605b261ecSmrg    c->current.current_fpe = 0;
86705b261ecSmrg    c->current.max_names = max_names;
86805b261ecSmrg    c->current.list_started = FALSE;
86905b261ecSmrg    c->current.private = 0;
87005b261ecSmrg    c->haveSaved = FALSE;
87105b261ecSmrg    c->slept = FALSE;
87205b261ecSmrg    c->savedName = 0;
87305b261ecSmrg    doListFontsAndAliases(client, c);
87405b261ecSmrg    return Success;
87505b261ecSmrg}
87605b261ecSmrg
87705b261ecSmrgint
87805b261ecSmrgdoListFontsWithInfo(ClientPtr client, LFWIclosurePtr c)
87905b261ecSmrg{
88005b261ecSmrg    FontPathElementPtr fpe;
88105b261ecSmrg    int         err = Successful;
88205b261ecSmrg    char       *name;
88305b261ecSmrg    int         namelen;
88405b261ecSmrg    int         numFonts;
88505b261ecSmrg    FontInfoRec fontInfo,
88605b261ecSmrg               *pFontInfo;
88705b261ecSmrg    xListFontsWithInfoReply *reply;
88805b261ecSmrg    int         length;
88905b261ecSmrg    xFontProp  *pFP;
89005b261ecSmrg    int         i;
89105b261ecSmrg    int		aliascount = 0;
89205b261ecSmrg    xListFontsWithInfoReply finalReply;
89305b261ecSmrg
89405b261ecSmrg    if (client->clientGone)
89505b261ecSmrg    {
89605b261ecSmrg	if (c->current.current_fpe < c->num_fpes)
89705b261ecSmrg 	{
89805b261ecSmrg	    fpe = c->fpe_list[c->current.current_fpe];
89905b261ecSmrg	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
90005b261ecSmrg	}
90105b261ecSmrg	err = Successful;
90205b261ecSmrg	goto bail;
90305b261ecSmrg    }
90405b261ecSmrg    client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo];
90505b261ecSmrg    if (!c->current.patlen)
90605b261ecSmrg	goto finish;
90705b261ecSmrg    while (c->current.current_fpe < c->num_fpes)
90805b261ecSmrg    {
90905b261ecSmrg	fpe = c->fpe_list[c->current.current_fpe];
91005b261ecSmrg	err = Successful;
91105b261ecSmrg	if (!c->current.list_started)
91205b261ecSmrg 	{
91305b261ecSmrg	    err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
91405b261ecSmrg		(client, fpe, c->current.pattern, c->current.patlen,
91505b261ecSmrg		 c->current.max_names, &c->current.private);
91605b261ecSmrg	    if (err == Suspended)
91705b261ecSmrg 	    {
91805b261ecSmrg		if (!c->slept)
91905b261ecSmrg 		{
92005b261ecSmrg		    ClientSleep(client, (ClientSleepProcPtr)doListFontsWithInfo, c);
92105b261ecSmrg		    c->slept = TRUE;
92205b261ecSmrg		}
92305b261ecSmrg		return TRUE;
92405b261ecSmrg	    }
92505b261ecSmrg	    if (err == Successful)
92605b261ecSmrg		c->current.list_started = TRUE;
92705b261ecSmrg	}
92805b261ecSmrg	if (err == Successful)
92905b261ecSmrg 	{
93005b261ecSmrg	    name = 0;
93105b261ecSmrg	    pFontInfo = &fontInfo;
93205b261ecSmrg	    err = (*fpe_functions[fpe->type].list_next_font_with_info)
93305b261ecSmrg		(client, fpe, &name, &namelen, &pFontInfo,
93405b261ecSmrg		 &numFonts, c->current.private);
93505b261ecSmrg	    if (err == Suspended)
93605b261ecSmrg 	    {
93705b261ecSmrg		if (!c->slept)
93805b261ecSmrg 		{
93905b261ecSmrg		    ClientSleep(client,
94005b261ecSmrg		    	     (ClientSleepProcPtr)doListFontsWithInfo,
94105b261ecSmrg			     c);
94205b261ecSmrg		    c->slept = TRUE;
94305b261ecSmrg		}
94405b261ecSmrg		return TRUE;
94505b261ecSmrg	    }
94605b261ecSmrg	}
94705b261ecSmrg	/*
94805b261ecSmrg	 * When we get an alias back, save our state and reset back to the
94905b261ecSmrg	 * start of the FPE looking for the specified name.  As soon as a real
95005b261ecSmrg	 * font is found for the alias, pop back to the old state
95105b261ecSmrg	 */
95205b261ecSmrg	if (err == FontNameAlias)
95305b261ecSmrg 	{
95405b261ecSmrg	    /*
95505b261ecSmrg	     * when an alias recurses, we need to give
95605b261ecSmrg	     * the last FPE a chance to clean up; so we call
95705b261ecSmrg	     * it again, and assume that the error returned
95805b261ecSmrg	     * is BadFontName, indicating the alias resolution
95905b261ecSmrg	     * is complete.
96005b261ecSmrg	     */
96105b261ecSmrg	    if (c->haveSaved)
96205b261ecSmrg	    {
96305b261ecSmrg		char	*tmpname;
96405b261ecSmrg		int	tmpnamelen;
96505b261ecSmrg		FontInfoPtr tmpFontInfo;
96605b261ecSmrg
96705b261ecSmrg	    	tmpname = 0;
96805b261ecSmrg	    	tmpFontInfo = &fontInfo;
96905b261ecSmrg	    	(void) (*fpe_functions[fpe->type].list_next_font_with_info)
97005b261ecSmrg		    (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
97105b261ecSmrg		     &numFonts, c->current.private);
97205b261ecSmrg		if (--aliascount <= 0)
97305b261ecSmrg		{
97405b261ecSmrg		    err = BadFontName;
97505b261ecSmrg		    goto ContBadFontName;
97605b261ecSmrg		}
97705b261ecSmrg	    }
97805b261ecSmrg	    else
97905b261ecSmrg	    {
98005b261ecSmrg		c->saved = c->current;
98105b261ecSmrg		c->haveSaved = TRUE;
98205b261ecSmrg		c->savedNumFonts = numFonts;
98305b261ecSmrg		if (c->savedName)
98405b261ecSmrg		  xfree(c->savedName);
98505b261ecSmrg		c->savedName = (char *)xalloc(namelen + 1);
98605b261ecSmrg		if (c->savedName)
98705b261ecSmrg		  memmove(c->savedName, name, namelen + 1);
98805b261ecSmrg		aliascount = 20;
98905b261ecSmrg	    }
99005b261ecSmrg	    memmove(c->current.pattern, name, namelen);
99105b261ecSmrg	    c->current.patlen = namelen;
99205b261ecSmrg	    c->current.max_names = 1;
99305b261ecSmrg	    c->current.current_fpe = 0;
99405b261ecSmrg	    c->current.private = 0;
99505b261ecSmrg	    c->current.list_started = FALSE;
99605b261ecSmrg	}
99705b261ecSmrg	/*
99805b261ecSmrg	 * At the end of this FPE, step to the next.  If we've finished
99905b261ecSmrg	 * processing an alias, pop state back.  If we've sent enough font
100005b261ecSmrg	 * names, quit.  Always wait for BadFontName to let the FPE
100105b261ecSmrg	 * have a chance to clean up.
100205b261ecSmrg	 */
100305b261ecSmrg	else if (err == BadFontName)
100405b261ecSmrg 	{
100505b261ecSmrg	  ContBadFontName: ;
100605b261ecSmrg	    c->current.list_started = FALSE;
100705b261ecSmrg	    c->current.current_fpe++;
100805b261ecSmrg	    err = Successful;
100905b261ecSmrg	    if (c->haveSaved)
101005b261ecSmrg 	    {
101105b261ecSmrg		if (c->current.max_names == 0 ||
101205b261ecSmrg			c->current.current_fpe == c->num_fpes)
101305b261ecSmrg 		{
101405b261ecSmrg		    c->haveSaved = FALSE;
101505b261ecSmrg		    c->saved.max_names -= (1 - c->current.max_names);
101605b261ecSmrg		    c->current = c->saved;
101705b261ecSmrg		}
101805b261ecSmrg	    }
101905b261ecSmrg	    else if (c->current.max_names == 0)
102005b261ecSmrg		break;
102105b261ecSmrg	}
102205b261ecSmrg 	else if (err == Successful)
102305b261ecSmrg 	{
102405b261ecSmrg	    length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
102505b261ecSmrg	    reply = c->reply;
102605b261ecSmrg	    if (c->length < length)
102705b261ecSmrg 	    {
102805b261ecSmrg		reply = (xListFontsWithInfoReply *) xrealloc(c->reply, length);
102905b261ecSmrg		if (!reply)
103005b261ecSmrg 		{
103105b261ecSmrg		    err = AllocError;
103205b261ecSmrg		    break;
103305b261ecSmrg		}
103405b261ecSmrg		c->reply = reply;
103505b261ecSmrg		c->length = length;
103605b261ecSmrg	    }
103705b261ecSmrg	    if (c->haveSaved)
103805b261ecSmrg 	    {
103905b261ecSmrg		numFonts = c->savedNumFonts;
104005b261ecSmrg		name = c->savedName;
104105b261ecSmrg		namelen = strlen(name);
104205b261ecSmrg	    }
104305b261ecSmrg	    reply->type = X_Reply;
104405b261ecSmrg	    reply->length = (sizeof *reply - sizeof(xGenericReply) +
104505b261ecSmrg			     pFontInfo->nprops * sizeof(xFontProp) +
104605b261ecSmrg			     namelen + 3) >> 2;
104705b261ecSmrg	    reply->sequenceNumber = client->sequence;
104805b261ecSmrg	    reply->nameLength = namelen;
104905b261ecSmrg	    reply->minBounds = pFontInfo->ink_minbounds;
105005b261ecSmrg	    reply->maxBounds = pFontInfo->ink_maxbounds;
105105b261ecSmrg	    reply->minCharOrByte2 = pFontInfo->firstCol;
105205b261ecSmrg	    reply->maxCharOrByte2 = pFontInfo->lastCol;
105305b261ecSmrg	    reply->defaultChar = pFontInfo->defaultCh;
105405b261ecSmrg	    reply->nFontProps = pFontInfo->nprops;
105505b261ecSmrg	    reply->drawDirection = pFontInfo->drawDirection;
105605b261ecSmrg	    reply->minByte1 = pFontInfo->firstRow;
105705b261ecSmrg	    reply->maxByte1 = pFontInfo->lastRow;
105805b261ecSmrg	    reply->allCharsExist = pFontInfo->allExist;
105905b261ecSmrg	    reply->fontAscent = pFontInfo->fontAscent;
106005b261ecSmrg	    reply->fontDescent = pFontInfo->fontDescent;
106105b261ecSmrg	    reply->nReplies = numFonts;
106205b261ecSmrg	    pFP = (xFontProp *) (reply + 1);
106305b261ecSmrg	    for (i = 0; i < pFontInfo->nprops; i++)
106405b261ecSmrg 	    {
106505b261ecSmrg		pFP->name = pFontInfo->props[i].name;
106605b261ecSmrg		pFP->value = pFontInfo->props[i].value;
106705b261ecSmrg		pFP++;
106805b261ecSmrg	    }
106905b261ecSmrg	    WriteSwappedDataToClient(client, length, reply);
107005b261ecSmrg	    (void) WriteToClient(client, namelen, name);
107105b261ecSmrg	    if (pFontInfo == &fontInfo)
107205b261ecSmrg 	    {
107305b261ecSmrg		xfree(fontInfo.props);
107405b261ecSmrg		xfree(fontInfo.isStringProp);
107505b261ecSmrg	    }
107605b261ecSmrg	    --c->current.max_names;
107705b261ecSmrg	}
107805b261ecSmrg    }
107905b261ecSmrgfinish:
108005b261ecSmrg    length = sizeof(xListFontsWithInfoReply);
108105b261ecSmrg    bzero((char *) &finalReply, sizeof(xListFontsWithInfoReply));
108205b261ecSmrg    finalReply.type = X_Reply;
108305b261ecSmrg    finalReply.sequenceNumber = client->sequence;
108405b261ecSmrg    finalReply.length = (sizeof(xListFontsWithInfoReply)
108505b261ecSmrg		     - sizeof(xGenericReply)) >> 2;
108605b261ecSmrg    WriteSwappedDataToClient(client, length, &finalReply);
108705b261ecSmrgbail:
108805b261ecSmrg    if (c->slept)
108905b261ecSmrg	ClientWakeup(client);
109005b261ecSmrg    for (i = 0; i < c->num_fpes; i++)
109105b261ecSmrg	FreeFPE(c->fpe_list[i]);
109205b261ecSmrg    xfree(c->reply);
109305b261ecSmrg    xfree(c->fpe_list);
109405b261ecSmrg    if (c->savedName) xfree(c->savedName);
109505b261ecSmrg    xfree(c);
109605b261ecSmrg    return TRUE;
109705b261ecSmrg}
109805b261ecSmrg
109905b261ecSmrgint
110005b261ecSmrgStartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern,
110105b261ecSmrg                       int max_names)
110205b261ecSmrg{
110305b261ecSmrg    int		    i;
110405b261ecSmrg    LFWIclosurePtr  c;
110505b261ecSmrg
110605b261ecSmrg    /*
110705b261ecSmrg     * The right error to return here would be BadName, however the
110805b261ecSmrg     * specification does not allow for a Name error on this request.
110905b261ecSmrg     * Perhaps a better solution would be to return a nil list, i.e.
111005b261ecSmrg     * a list containing zero fontnames.
111105b261ecSmrg     */
111205b261ecSmrg    if (length > XLFDMAXFONTNAMELEN)
111305b261ecSmrg	return BadAlloc;
111405b261ecSmrg
111505b261ecSmrg    if (!(c = (LFWIclosurePtr) xalloc(sizeof *c)))
111605b261ecSmrg	goto badAlloc;
111705b261ecSmrg    c->fpe_list = (FontPathElementPtr *)
111805b261ecSmrg	xalloc(sizeof(FontPathElementPtr) * num_fpes);
111905b261ecSmrg    if (!c->fpe_list)
112005b261ecSmrg    {
112105b261ecSmrg	xfree(c);
112205b261ecSmrg	goto badAlloc;
112305b261ecSmrg    }
112405b261ecSmrg    memmove(c->current.pattern, pattern, length);
112505b261ecSmrg    for (i = 0; i < num_fpes; i++)
112605b261ecSmrg    {
112705b261ecSmrg	c->fpe_list[i] = font_path_elements[i];
112805b261ecSmrg	UseFPE(c->fpe_list[i]);
112905b261ecSmrg    }
113005b261ecSmrg    c->client = client;
113105b261ecSmrg    c->num_fpes = num_fpes;
113205b261ecSmrg    c->reply = 0;
113305b261ecSmrg    c->length = 0;
113405b261ecSmrg    c->current.patlen = length;
113505b261ecSmrg    c->current.current_fpe = 0;
113605b261ecSmrg    c->current.max_names = max_names;
113705b261ecSmrg    c->current.list_started = FALSE;
113805b261ecSmrg    c->current.private = 0;
113905b261ecSmrg    c->savedNumFonts = 0;
114005b261ecSmrg    c->haveSaved = FALSE;
114105b261ecSmrg    c->slept = FALSE;
114205b261ecSmrg    c->savedName = 0;
114305b261ecSmrg    doListFontsWithInfo(client, c);
114405b261ecSmrg    return Success;
114505b261ecSmrgbadAlloc:
114605b261ecSmrg    return BadAlloc;
114705b261ecSmrg}
114805b261ecSmrg
114905b261ecSmrg#define TextEltHeader 2
115005b261ecSmrg#define FontShiftSize 5
115105b261ecSmrgstatic XID clearGC[] = { CT_NONE };
115205b261ecSmrg#define clearGCmask (GCClipMask)
115305b261ecSmrg
115405b261ecSmrgint
115505b261ecSmrgdoPolyText(ClientPtr client, PTclosurePtr c)
115605b261ecSmrg{
115705b261ecSmrg    FontPtr pFont = c->pGC->font, oldpFont;
115805b261ecSmrg    Font	fid, oldfid;
115905b261ecSmrg    int err = Success, lgerr;	/* err is in X error, not font error, space */
116005b261ecSmrg    enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state = NEVER_SLEPT;
116105b261ecSmrg    FontPathElementPtr fpe;
116205b261ecSmrg    GC *origGC = NULL;
116305b261ecSmrg
116405b261ecSmrg    if (client->clientGone)
116505b261ecSmrg    {
116605b261ecSmrg	fpe = c->pGC->font->fpe;
116705b261ecSmrg	(*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
116805b261ecSmrg
116905b261ecSmrg	if (c->slept)
117005b261ecSmrg	{
117105b261ecSmrg	    /* Client has died, but we cannot bail out right now.  We
117205b261ecSmrg	       need to clean up after the work we did when going to
117305b261ecSmrg	       sleep.  Setting the drawable pointer to 0 makes this
117405b261ecSmrg	       happen without any attempts to render or perform other
117505b261ecSmrg	       unnecessary activities.  */
117605b261ecSmrg	    c->pDraw = (DrawablePtr)0;
117705b261ecSmrg	}
117805b261ecSmrg	else
117905b261ecSmrg	{
118005b261ecSmrg	    err = Success;
118105b261ecSmrg	    goto bail;
118205b261ecSmrg	}
118305b261ecSmrg    }
118405b261ecSmrg
118505b261ecSmrg    /* Make sure our drawable hasn't disappeared while we slept. */
118605b261ecSmrg    if (c->slept &&
118705b261ecSmrg	c->pDraw &&
118805b261ecSmrg	c->pDraw != (DrawablePtr)SecurityLookupIDByClass(client, c->did,
118905b261ecSmrg					RC_DRAWABLE, DixWriteAccess))
119005b261ecSmrg    {
119105b261ecSmrg	/* Our drawable has disappeared.  Treat like client died... ask
119205b261ecSmrg	   the FPE code to clean up after client and avoid further
119305b261ecSmrg	   rendering while we clean up after ourself.  */
119405b261ecSmrg	fpe = c->pGC->font->fpe;
119505b261ecSmrg	(*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
119605b261ecSmrg	c->pDraw = (DrawablePtr)0;
119705b261ecSmrg    }
119805b261ecSmrg
119905b261ecSmrg    client_state = c->slept ? SLEEPING : NEVER_SLEPT;
120005b261ecSmrg
120105b261ecSmrg    while (c->endReq - c->pElt > TextEltHeader)
120205b261ecSmrg    {
120305b261ecSmrg	if (*c->pElt == FontChange)
120405b261ecSmrg        {
120505b261ecSmrg	    if (c->endReq - c->pElt < FontShiftSize)
120605b261ecSmrg	    {
120705b261ecSmrg		 err = BadLength;
120805b261ecSmrg		 goto bail;
120905b261ecSmrg	    }
121005b261ecSmrg
121105b261ecSmrg	    oldpFont = pFont;
121205b261ecSmrg	    oldfid = fid;
121305b261ecSmrg
121405b261ecSmrg	    fid =  ((Font)*(c->pElt+4))		/* big-endian */
121505b261ecSmrg		 | ((Font)*(c->pElt+3)) << 8
121605b261ecSmrg		 | ((Font)*(c->pElt+2)) << 16
121705b261ecSmrg		 | ((Font)*(c->pElt+1)) << 24;
121805b261ecSmrg	    pFont = (FontPtr)SecurityLookupIDByType(client, fid, RT_FONT,
121905b261ecSmrg						    DixReadAccess);
122005b261ecSmrg	    if (!pFont)
122105b261ecSmrg	    {
122205b261ecSmrg		client->errorValue = fid;
122305b261ecSmrg		err = BadFont;
122405b261ecSmrg		/* restore pFont and fid for step 4 (described below) */
122505b261ecSmrg		pFont = oldpFont;
122605b261ecSmrg		fid = oldfid;
122705b261ecSmrg
122805b261ecSmrg		/* If we're in START_SLEEP mode, the following step
122905b261ecSmrg		   shortens the request...  in the unlikely event that
123005b261ecSmrg		   the fid somehow becomes valid before we come through
123105b261ecSmrg		   again to actually execute the polytext, which would
123205b261ecSmrg		   then mess up our refcounting scheme badly.  */
123305b261ecSmrg		c->err = err;
123405b261ecSmrg		c->endReq = c->pElt;
123505b261ecSmrg
123605b261ecSmrg		goto bail;
123705b261ecSmrg	    }
123805b261ecSmrg
123905b261ecSmrg	    /* Step 3 (described below) on our new font */
124005b261ecSmrg	    if (client_state == START_SLEEP)
124105b261ecSmrg		pFont->refcnt++;
124205b261ecSmrg	    else
124305b261ecSmrg	    {
124405b261ecSmrg		if (pFont != c->pGC->font && c->pDraw)
124505b261ecSmrg		{
124605b261ecSmrg		    ChangeGC( c->pGC, GCFont, &fid);
124705b261ecSmrg		    ValidateGC(c->pDraw, c->pGC);
124805b261ecSmrg		    if (c->reqType == X_PolyText8)
124905b261ecSmrg			c->polyText = (PolyTextPtr) c->pGC->ops->PolyText8;
125005b261ecSmrg		    else
125105b261ecSmrg			c->polyText = (PolyTextPtr) c->pGC->ops->PolyText16;
125205b261ecSmrg		}
125305b261ecSmrg
125405b261ecSmrg		/* Undo the refcnt++ we performed when going to sleep */
125505b261ecSmrg		if (client_state == SLEEPING)
125605b261ecSmrg		    (void)CloseFont(c->pGC->font, (Font)0);
125705b261ecSmrg	    }
125805b261ecSmrg	    c->pElt += FontShiftSize;
125905b261ecSmrg	}
126005b261ecSmrg	else	/* print a string */
126105b261ecSmrg	{
126205b261ecSmrg	    unsigned char *pNextElt;
126305b261ecSmrg	    pNextElt = c->pElt + TextEltHeader + (*c->pElt)*c->itemSize;
126405b261ecSmrg	    if ( pNextElt > c->endReq)
126505b261ecSmrg	    {
126605b261ecSmrg		err = BadLength;
126705b261ecSmrg		goto bail;
126805b261ecSmrg	    }
126905b261ecSmrg	    if (client_state == START_SLEEP)
127005b261ecSmrg	    {
127105b261ecSmrg		c->pElt = pNextElt;
127205b261ecSmrg		continue;
127305b261ecSmrg	    }
127405b261ecSmrg	    if (c->pDraw)
127505b261ecSmrg	    {
127605b261ecSmrg		lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, c->itemSize,
127705b261ecSmrg				   c->pElt + TextEltHeader);
127805b261ecSmrg	    }
127905b261ecSmrg	    else lgerr = Successful;
128005b261ecSmrg
128105b261ecSmrg	    if (lgerr == Suspended)
128205b261ecSmrg	    {
128305b261ecSmrg		if (!c->slept) {
128405b261ecSmrg		    int len;
128505b261ecSmrg		    GC *pGC;
128605b261ecSmrg		    PTclosurePtr new_closure;
128705b261ecSmrg
128805b261ecSmrg    /*  We're putting the client to sleep.  We need to do a few things
128905b261ecSmrg	to ensure successful and atomic-appearing execution of the
129005b261ecSmrg	remainder of the request.  First, copy the remainder of the
129105b261ecSmrg	request into a safe malloc'd area.  Second, create a scratch GC
129205b261ecSmrg	to use for the remainder of the request.  Third, mark all fonts
129305b261ecSmrg	referenced in the remainder of the request to prevent their
129405b261ecSmrg	deallocation.  Fourth, make the original GC look like the
129505b261ecSmrg	request has completed...  set its font to the final font value
129605b261ecSmrg	from this request.  These GC manipulations are for the unlikely
129705b261ecSmrg	(but possible) event that some other client is using the GC.
129805b261ecSmrg	Steps 3 and 4 are performed by running this procedure through
129905b261ecSmrg	the remainder of the request in a special no-render mode
130005b261ecSmrg	indicated by client_state = START_SLEEP.  */
130105b261ecSmrg
130205b261ecSmrg		    /* Step 1 */
130305b261ecSmrg		    /* Allocate a malloc'd closure structure to replace
130405b261ecSmrg		       the local one we were passed */
130505b261ecSmrg		    new_closure = (PTclosurePtr) xalloc(sizeof(PTclosureRec));
130605b261ecSmrg		    if (!new_closure)
130705b261ecSmrg		    {
130805b261ecSmrg			err = BadAlloc;
130905b261ecSmrg			goto bail;
131005b261ecSmrg		    }
131105b261ecSmrg		    *new_closure = *c;
131205b261ecSmrg		    c = new_closure;
131305b261ecSmrg
131405b261ecSmrg		    len = c->endReq - c->pElt;
131505b261ecSmrg		    c->data = (unsigned char *)xalloc(len);
131605b261ecSmrg		    if (!c->data)
131705b261ecSmrg		    {
131805b261ecSmrg			xfree(c);
131905b261ecSmrg			err = BadAlloc;
132005b261ecSmrg			goto bail;
132105b261ecSmrg		    }
132205b261ecSmrg		    memmove(c->data, c->pElt, len);
132305b261ecSmrg		    c->pElt = c->data;
132405b261ecSmrg		    c->endReq = c->pElt + len;
132505b261ecSmrg
132605b261ecSmrg		    /* Step 2 */
132705b261ecSmrg
132805b261ecSmrg		    pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
132905b261ecSmrg		    if (!pGC)
133005b261ecSmrg		    {
133105b261ecSmrg			xfree(c->data);
133205b261ecSmrg			xfree(c);
133305b261ecSmrg			err = BadAlloc;
133405b261ecSmrg			goto bail;
133505b261ecSmrg		    }
133605b261ecSmrg		    if ((err = CopyGC(c->pGC, pGC, GCFunction |
133705b261ecSmrg				      GCPlaneMask | GCForeground |
133805b261ecSmrg				      GCBackground | GCFillStyle |
133905b261ecSmrg				      GCTile | GCStipple |
134005b261ecSmrg				      GCTileStipXOrigin |
134105b261ecSmrg				      GCTileStipYOrigin | GCFont |
134205b261ecSmrg				      GCSubwindowMode | GCClipXOrigin |
134305b261ecSmrg				      GCClipYOrigin | GCClipMask)) !=
134405b261ecSmrg				      Success)
134505b261ecSmrg		    {
134605b261ecSmrg			FreeScratchGC(pGC);
134705b261ecSmrg			xfree(c->data);
134805b261ecSmrg			xfree(c);
134905b261ecSmrg			err = BadAlloc;
135005b261ecSmrg			goto bail;
135105b261ecSmrg		    }
135205b261ecSmrg		    origGC = c->pGC;
135305b261ecSmrg		    c->pGC = pGC;
135405b261ecSmrg		    ValidateGC(c->pDraw, c->pGC);
135505b261ecSmrg
135605b261ecSmrg		    c->slept = TRUE;
135705b261ecSmrg		    ClientSleep(client,
135805b261ecSmrg		    	     (ClientSleepProcPtr)doPolyText,
135905b261ecSmrg			     (pointer) c);
136005b261ecSmrg
136105b261ecSmrg		    /* Set up to perform steps 3 and 4 */
136205b261ecSmrg		    client_state = START_SLEEP;
136305b261ecSmrg		    continue;	/* on to steps 3 and 4 */
136405b261ecSmrg		}
136505b261ecSmrg		return TRUE;
136605b261ecSmrg	    }
136705b261ecSmrg	    else if (lgerr != Successful)
136805b261ecSmrg	    {
136905b261ecSmrg		err = FontToXError(lgerr);
137005b261ecSmrg		goto bail;
137105b261ecSmrg	    }
137205b261ecSmrg	    if (c->pDraw)
137305b261ecSmrg	    {
137405b261ecSmrg		c->xorg += *((INT8 *)(c->pElt + 1));	/* must be signed */
137505b261ecSmrg		c->xorg = (* c->polyText)(c->pDraw, c->pGC, c->xorg, c->yorg,
137605b261ecSmrg		    *c->pElt, c->pElt + TextEltHeader);
137705b261ecSmrg	    }
137805b261ecSmrg	    c->pElt = pNextElt;
137905b261ecSmrg	}
138005b261ecSmrg    }
138105b261ecSmrg
138205b261ecSmrgbail:
138305b261ecSmrg
138405b261ecSmrg    if (client_state == START_SLEEP)
138505b261ecSmrg    {
138605b261ecSmrg	/* Step 4 */
138705b261ecSmrg	if (pFont != origGC->font)
138805b261ecSmrg	{
138905b261ecSmrg	    ChangeGC(origGC, GCFont, &fid);
139005b261ecSmrg	    ValidateGC(c->pDraw, origGC);
139105b261ecSmrg	}
139205b261ecSmrg
139305b261ecSmrg	/* restore pElt pointer for execution of remainder of the request */
139405b261ecSmrg	c->pElt = c->data;
139505b261ecSmrg	return TRUE;
139605b261ecSmrg    }
139705b261ecSmrg
139805b261ecSmrg    if (c->err != Success) err = c->err;
139905b261ecSmrg    if (err != Success && c->client != serverClient) {
140005b261ecSmrg#ifdef PANORAMIX
140105b261ecSmrg        if (noPanoramiXExtension || !c->pGC->pScreen->myNum)
140205b261ecSmrg#endif
140305b261ecSmrg	    SendErrorToClient(c->client, c->reqType, 0, 0, err);
140405b261ecSmrg    }
140505b261ecSmrg    if (c->slept)
140605b261ecSmrg    {
140705b261ecSmrg	ClientWakeup(c->client);
140805b261ecSmrg	ChangeGC(c->pGC, clearGCmask, clearGC);
140905b261ecSmrg
141005b261ecSmrg	/* Unreference the font from the scratch GC */
141105b261ecSmrg	CloseFont(c->pGC->font, (Font)0);
141205b261ecSmrg	c->pGC->font = NullFont;
141305b261ecSmrg
141405b261ecSmrg	FreeScratchGC(c->pGC);
141505b261ecSmrg	xfree(c->data);
141605b261ecSmrg	xfree(c);
141705b261ecSmrg    }
141805b261ecSmrg    return TRUE;
141905b261ecSmrg}
142005b261ecSmrg
142105b261ecSmrgint
142205b261ecSmrgPolyText(ClientPtr client, DrawablePtr pDraw, GC *pGC, unsigned char *pElt,
142305b261ecSmrg         unsigned char *endReq, int xorg, int yorg, int reqType, XID did)
142405b261ecSmrg{
142505b261ecSmrg    PTclosureRec local_closure;
142605b261ecSmrg
142705b261ecSmrg    local_closure.pElt = pElt;
142805b261ecSmrg    local_closure.endReq = endReq;
142905b261ecSmrg    local_closure.client = client;
143005b261ecSmrg    local_closure.pDraw = pDraw;
143105b261ecSmrg    local_closure.xorg = xorg;
143205b261ecSmrg    local_closure.yorg = yorg;
143305b261ecSmrg    if ((local_closure.reqType = reqType) == X_PolyText8)
143405b261ecSmrg    {
143505b261ecSmrg	local_closure.polyText = (PolyTextPtr) pGC->ops->PolyText8;
143605b261ecSmrg	local_closure.itemSize = 1;
143705b261ecSmrg    }
143805b261ecSmrg    else
143905b261ecSmrg    {
144005b261ecSmrg	local_closure.polyText =  (PolyTextPtr) pGC->ops->PolyText16;
144105b261ecSmrg	local_closure.itemSize = 2;
144205b261ecSmrg    }
144305b261ecSmrg    local_closure.pGC = pGC;
144405b261ecSmrg    local_closure.did = did;
144505b261ecSmrg    local_closure.err = Success;
144605b261ecSmrg    local_closure.slept = FALSE;
144705b261ecSmrg
144805b261ecSmrg    (void) doPolyText(client, &local_closure);
144905b261ecSmrg    return Success;
145005b261ecSmrg}
145105b261ecSmrg
145205b261ecSmrg
145305b261ecSmrg#undef TextEltHeader
145405b261ecSmrg#undef FontShiftSize
145505b261ecSmrg
145605b261ecSmrgint
145705b261ecSmrgdoImageText(ClientPtr client, ITclosurePtr c)
145805b261ecSmrg{
145905b261ecSmrg    int err = Success, lgerr;	/* err is in X error, not font error, space */
146005b261ecSmrg    FontPathElementPtr fpe;
146105b261ecSmrg
146205b261ecSmrg    if (client->clientGone)
146305b261ecSmrg    {
146405b261ecSmrg	fpe = c->pGC->font->fpe;
146505b261ecSmrg	(*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
146605b261ecSmrg	err = Success;
146705b261ecSmrg	goto bail;
146805b261ecSmrg    }
146905b261ecSmrg
147005b261ecSmrg    /* Make sure our drawable hasn't disappeared while we slept. */
147105b261ecSmrg    if (c->slept &&
147205b261ecSmrg	c->pDraw &&
147305b261ecSmrg	c->pDraw != (DrawablePtr)SecurityLookupIDByClass(client, c->did,
147405b261ecSmrg					RC_DRAWABLE, DixWriteAccess))
147505b261ecSmrg    {
147605b261ecSmrg	/* Our drawable has disappeared.  Treat like client died... ask
147705b261ecSmrg	   the FPE code to clean up after client. */
147805b261ecSmrg	fpe = c->pGC->font->fpe;
147905b261ecSmrg	(*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
148005b261ecSmrg	err = Success;
148105b261ecSmrg	goto bail;
148205b261ecSmrg    }
148305b261ecSmrg
148405b261ecSmrg    lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, c->itemSize, c->data);
148505b261ecSmrg    if (lgerr == Suspended)
148605b261ecSmrg    {
148705b261ecSmrg        if (!c->slept) {
148805b261ecSmrg	    GC *pGC;
148905b261ecSmrg	    unsigned char *data;
149005b261ecSmrg	    ITclosurePtr new_closure;
149105b261ecSmrg
149205b261ecSmrg	    /* We're putting the client to sleep.  We need to
149305b261ecSmrg	       save some state.  Similar problem to that handled
149405b261ecSmrg	       in doPolyText, but much simpler because the
149505b261ecSmrg	       request structure is much simpler. */
149605b261ecSmrg
149705b261ecSmrg	    new_closure = (ITclosurePtr) xalloc(sizeof(ITclosureRec));
149805b261ecSmrg	    if (!new_closure)
149905b261ecSmrg	    {
150005b261ecSmrg		err = BadAlloc;
150105b261ecSmrg		goto bail;
150205b261ecSmrg	    }
150305b261ecSmrg	    *new_closure = *c;
150405b261ecSmrg	    c = new_closure;
150505b261ecSmrg
150605b261ecSmrg	    data = (unsigned char *)xalloc(c->nChars * c->itemSize);
150705b261ecSmrg	    if (!data)
150805b261ecSmrg	    {
150905b261ecSmrg		xfree(c);
151005b261ecSmrg		err = BadAlloc;
151105b261ecSmrg		goto bail;
151205b261ecSmrg	    }
151305b261ecSmrg	    memmove(data, c->data, c->nChars * c->itemSize);
151405b261ecSmrg	    c->data = data;
151505b261ecSmrg
151605b261ecSmrg	    pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
151705b261ecSmrg	    if (!pGC)
151805b261ecSmrg	    {
151905b261ecSmrg		xfree(c->data);
152005b261ecSmrg		xfree(c);
152105b261ecSmrg		err = BadAlloc;
152205b261ecSmrg		goto bail;
152305b261ecSmrg	    }
152405b261ecSmrg	    if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask |
152505b261ecSmrg			      GCForeground | GCBackground | GCFillStyle |
152605b261ecSmrg			      GCTile | GCStipple | GCTileStipXOrigin |
152705b261ecSmrg			      GCTileStipYOrigin | GCFont |
152805b261ecSmrg			      GCSubwindowMode | GCClipXOrigin |
152905b261ecSmrg			      GCClipYOrigin | GCClipMask)) != Success)
153005b261ecSmrg	    {
153105b261ecSmrg		FreeScratchGC(pGC);
153205b261ecSmrg		xfree(c->data);
153305b261ecSmrg		xfree(c);
153405b261ecSmrg		err = BadAlloc;
153505b261ecSmrg		goto bail;
153605b261ecSmrg	    }
153705b261ecSmrg	    c->pGC = pGC;
153805b261ecSmrg	    ValidateGC(c->pDraw, c->pGC);
153905b261ecSmrg
154005b261ecSmrg	    c->slept = TRUE;
154105b261ecSmrg            ClientSleep(client, (ClientSleepProcPtr)doImageText, (pointer) c);
154205b261ecSmrg        }
154305b261ecSmrg        return TRUE;
154405b261ecSmrg    }
154505b261ecSmrg    else if (lgerr != Successful)
154605b261ecSmrg    {
154705b261ecSmrg        err = FontToXError(lgerr);
154805b261ecSmrg        goto bail;
154905b261ecSmrg    }
155005b261ecSmrg    if (c->pDraw)
155105b261ecSmrg    {
155205b261ecSmrg	(* c->imageText)(c->pDraw, c->pGC, c->xorg, c->yorg,
155305b261ecSmrg	    c->nChars, c->data);
155405b261ecSmrg    }
155505b261ecSmrg
155605b261ecSmrgbail:
155705b261ecSmrg
155805b261ecSmrg    if (err != Success && c->client != serverClient) {
155905b261ecSmrg	SendErrorToClient(c->client, c->reqType, 0, 0, err);
156005b261ecSmrg    }
156105b261ecSmrg    if (c->slept)
156205b261ecSmrg    {
156305b261ecSmrg	ClientWakeup(c->client);
156405b261ecSmrg	ChangeGC(c->pGC, clearGCmask, clearGC);
156505b261ecSmrg
156605b261ecSmrg	/* Unreference the font from the scratch GC */
156705b261ecSmrg	CloseFont(c->pGC->font, (Font)0);
156805b261ecSmrg	c->pGC->font = NullFont;
156905b261ecSmrg
157005b261ecSmrg	FreeScratchGC(c->pGC);
157105b261ecSmrg	xfree(c->data);
157205b261ecSmrg	xfree(c);
157305b261ecSmrg    }
157405b261ecSmrg    return TRUE;
157505b261ecSmrg}
157605b261ecSmrg
157705b261ecSmrgint
157805b261ecSmrgImageText(ClientPtr client, DrawablePtr pDraw, GC *pGC, int nChars,
157905b261ecSmrg          unsigned char *data, int xorg, int yorg, int reqType, XID did)
158005b261ecSmrg{
158105b261ecSmrg    ITclosureRec local_closure;
158205b261ecSmrg
158305b261ecSmrg    local_closure.client = client;
158405b261ecSmrg    local_closure.pDraw = pDraw;
158505b261ecSmrg    local_closure.pGC = pGC;
158605b261ecSmrg    local_closure.nChars = nChars;
158705b261ecSmrg    local_closure.data = data;
158805b261ecSmrg    local_closure.xorg = xorg;
158905b261ecSmrg    local_closure.yorg = yorg;
159005b261ecSmrg    if ((local_closure.reqType = reqType) == X_ImageText8)
159105b261ecSmrg    {
159205b261ecSmrg	local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText8;
159305b261ecSmrg	local_closure.itemSize = 1;
159405b261ecSmrg    }
159505b261ecSmrg    else
159605b261ecSmrg    {
159705b261ecSmrg	local_closure.imageText = (ImageTextPtr) pGC->ops->ImageText16;
159805b261ecSmrg	local_closure.itemSize = 2;
159905b261ecSmrg    }
160005b261ecSmrg    local_closure.did = did;
160105b261ecSmrg    local_closure.slept = FALSE;
160205b261ecSmrg
160305b261ecSmrg    (void) doImageText(client, &local_closure);
160405b261ecSmrg    return Success;
160505b261ecSmrg}
160605b261ecSmrg
160705b261ecSmrg
160805b261ecSmrg/* does the necessary magic to figure out the fpe type */
160905b261ecSmrgstatic int
161005b261ecSmrgDetermineFPEType(char *pathname)
161105b261ecSmrg{
161205b261ecSmrg    int         i;
161305b261ecSmrg
161405b261ecSmrg    for (i = 0; i < num_fpe_types; i++) {
161505b261ecSmrg	if ((*fpe_functions[i].name_check) (pathname))
161605b261ecSmrg	    return i;
161705b261ecSmrg    }
161805b261ecSmrg    return -1;
161905b261ecSmrg}
162005b261ecSmrg
162105b261ecSmrg
162205b261ecSmrgstatic void
162305b261ecSmrgFreeFontPath(FontPathElementPtr *list, int n, Bool force)
162405b261ecSmrg{
162505b261ecSmrg    int         i;
162605b261ecSmrg
162705b261ecSmrg    for (i = 0; i < n; i++) {
162805b261ecSmrg	if (force) {
162905b261ecSmrg	    /* Sanity check that all refcounts will be 0 by the time
163005b261ecSmrg	       we get to the end of the list. */
163105b261ecSmrg	    int found = 1;	/* the first reference is us */
163205b261ecSmrg	    int j;
163305b261ecSmrg	    for (j = i+1; j < n; j++) {
163405b261ecSmrg		if (list[j] == list[i])
163505b261ecSmrg		    found++;
163605b261ecSmrg	    }
163705b261ecSmrg	    if (list[i]->refcount != found) {
163805b261ecSmrg		ErrorF("FreeFontPath: FPE \"%.*s\" refcount is %d, should be %d; fixing.\n",
163905b261ecSmrg		       list[i]->name_length, list[i]->name,
164005b261ecSmrg		       list[i]->refcount, found);
164105b261ecSmrg		list[i]->refcount = found; /* ensure it will get freed */
164205b261ecSmrg	    }
164305b261ecSmrg	}
164405b261ecSmrg	FreeFPE(list[i]);
164505b261ecSmrg    }
164605b261ecSmrg    xfree((char *) list);
164705b261ecSmrg}
164805b261ecSmrg
164905b261ecSmrgstatic FontPathElementPtr
165005b261ecSmrgfind_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len)
165105b261ecSmrg{
165205b261ecSmrg    FontPathElementPtr fpe;
165305b261ecSmrg    int         i;
165405b261ecSmrg
165505b261ecSmrg    for (i = 0; i < num; i++) {
165605b261ecSmrg	fpe = list[i];
165705b261ecSmrg	if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0)
165805b261ecSmrg	    return fpe;
165905b261ecSmrg    }
166005b261ecSmrg    return (FontPathElementPtr) 0;
166105b261ecSmrg}
166205b261ecSmrg
166305b261ecSmrg
166405b261ecSmrgstatic int
166505b261ecSmrgSetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist)
166605b261ecSmrg{
166705b261ecSmrg    int         i, err = 0;
166805b261ecSmrg    int         valid_paths = 0;
166905b261ecSmrg    unsigned int len;
167005b261ecSmrg    unsigned char *cp = paths;
167105b261ecSmrg    FontPathElementPtr fpe = NULL, *fplist;
167205b261ecSmrg
167305b261ecSmrg    fplist = (FontPathElementPtr *)
167405b261ecSmrg	xalloc(sizeof(FontPathElementPtr) * npaths);
167505b261ecSmrg    if (!fplist) {
167605b261ecSmrg	*bad = 0;
167705b261ecSmrg	return BadAlloc;
167805b261ecSmrg    }
167905b261ecSmrg    for (i = 0; i < num_fpe_types; i++) {
168005b261ecSmrg	if (fpe_functions[i].set_path_hook)
168105b261ecSmrg	    (*fpe_functions[i].set_path_hook) ();
168205b261ecSmrg    }
168305b261ecSmrg    for (i = 0; i < npaths; i++)
168405b261ecSmrg    {
168505b261ecSmrg	len = (unsigned int) (*cp++);
168605b261ecSmrg
168705b261ecSmrg	if (len == 0)
168805b261ecSmrg	{
168905b261ecSmrg	    if (persist)
169005b261ecSmrg		ErrorF ("Removing empty element from the valid list of fontpaths\n");
169105b261ecSmrg	    err = BadValue;
169205b261ecSmrg	}
169305b261ecSmrg	else
169405b261ecSmrg	{
169505b261ecSmrg	    /* if it's already in our active list, just reset it */
169605b261ecSmrg	    /*
169705b261ecSmrg	     * note that this can miss FPE's in limbo -- may be worth catching
169805b261ecSmrg	     * them, though it'd muck up refcounting
169905b261ecSmrg	     */
170005b261ecSmrg	    fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
170105b261ecSmrg	    if (fpe)
170205b261ecSmrg	    {
170305b261ecSmrg		err = (*fpe_functions[fpe->type].reset_fpe) (fpe);
170405b261ecSmrg		if (err == Successful)
170505b261ecSmrg		{
170605b261ecSmrg		    UseFPE(fpe);/* since it'll be decref'd later when freed
170705b261ecSmrg				 * from the old list */
170805b261ecSmrg		}
170905b261ecSmrg		else
171005b261ecSmrg		    fpe = 0;
171105b261ecSmrg	    }
171205b261ecSmrg	    /* if error or can't do it, act like it's a new one */
171305b261ecSmrg	    if (!fpe)
171405b261ecSmrg	    {
171505b261ecSmrg		fpe = (FontPathElementPtr) xalloc(sizeof(FontPathElementRec));
171605b261ecSmrg		if (!fpe)
171705b261ecSmrg		{
171805b261ecSmrg		    err = BadAlloc;
171905b261ecSmrg		    goto bail;
172005b261ecSmrg		}
172105b261ecSmrg		fpe->name = (char *) xalloc(len + 1);
172205b261ecSmrg		if (!fpe->name)
172305b261ecSmrg		{
172405b261ecSmrg		    xfree(fpe);
172505b261ecSmrg		    err = BadAlloc;
172605b261ecSmrg		    goto bail;
172705b261ecSmrg		}
172805b261ecSmrg		fpe->refcount = 1;
172905b261ecSmrg
173005b261ecSmrg		strncpy(fpe->name, (char *) cp, (int) len);
173105b261ecSmrg		fpe->name[len] = '\0';
173205b261ecSmrg		fpe->name_length = len;
173305b261ecSmrg		fpe->type = DetermineFPEType(fpe->name);
173405b261ecSmrg		if (fpe->type == -1)
173505b261ecSmrg		    err = BadValue;
173605b261ecSmrg		else
173705b261ecSmrg		    err = (*fpe_functions[fpe->type].init_fpe) (fpe);
173805b261ecSmrg		if (err != Successful)
173905b261ecSmrg		{
174005b261ecSmrg		    if (persist)
174105b261ecSmrg		    {
174205b261ecSmrg			ErrorF("Could not init font path element %s, removing from list!\n",
174305b261ecSmrg			       fpe->name);
174405b261ecSmrg		    }
174505b261ecSmrg		    xfree (fpe->name);
174605b261ecSmrg		    xfree (fpe);
174705b261ecSmrg		}
174805b261ecSmrg	    }
174905b261ecSmrg	}
175005b261ecSmrg	if (err != Successful)
175105b261ecSmrg	{
175205b261ecSmrg	    if (!persist)
175305b261ecSmrg		goto bail;
175405b261ecSmrg	}
175505b261ecSmrg	else
175605b261ecSmrg	{
175705b261ecSmrg	    fplist[valid_paths++] = fpe;
175805b261ecSmrg	}
175905b261ecSmrg	cp += len;
176005b261ecSmrg    }
176105b261ecSmrg
176205b261ecSmrg    FreeFontPath(font_path_elements, num_fpes, FALSE);
176305b261ecSmrg    font_path_elements = fplist;
176405b261ecSmrg    if (patternCache)
176505b261ecSmrg	EmptyFontPatternCache(patternCache);
176605b261ecSmrg    num_fpes = valid_paths;
176705b261ecSmrg
176805b261ecSmrg    return Success;
176905b261ecSmrgbail:
177005b261ecSmrg    *bad = i;
177105b261ecSmrg    while (--valid_paths >= 0)
177205b261ecSmrg	FreeFPE(fplist[valid_paths]);
177305b261ecSmrg    xfree(fplist);
177405b261ecSmrg    return FontToXError(err);
177505b261ecSmrg}
177605b261ecSmrg
177705b261ecSmrg/* XXX -- do we need to pass error down to each renderer? */
177805b261ecSmrgint
177905b261ecSmrgSetFontPath(ClientPtr client, int npaths, unsigned char *paths, int *error)
178005b261ecSmrg{
178105b261ecSmrg    int   err = Success;
178205b261ecSmrg
178305b261ecSmrg    if (npaths == 0) {
178405b261ecSmrg	if (SetDefaultFontPath(defaultFontPath) != Success)
178505b261ecSmrg	    return BadValue;
178605b261ecSmrg    } else {
178705b261ecSmrg	err = SetFontPathElements(npaths, paths, error, FALSE);
178805b261ecSmrg    }
178905b261ecSmrg    return err;
179005b261ecSmrg}
179105b261ecSmrg
179205b261ecSmrgint
179305b261ecSmrgSetDefaultFontPath(char *path)
179405b261ecSmrg{
179505b261ecSmrg    unsigned char *cp,
179605b261ecSmrg               *pp,
179705b261ecSmrg               *nump,
179805b261ecSmrg               *newpath;
179905b261ecSmrg    int         num = 1,
180005b261ecSmrg                len,
180105b261ecSmrg                err,
180205b261ecSmrg                size = 0,
180305b261ecSmrg                bad;
180405b261ecSmrg
180505b261ecSmrg    /* get enough for string, plus values -- use up commas */
180605b261ecSmrg    len = strlen(path) + 1;
180705b261ecSmrg    nump = cp = newpath = (unsigned char *) ALLOCATE_LOCAL(len);
180805b261ecSmrg    if (!newpath)
180905b261ecSmrg	return BadAlloc;
181005b261ecSmrg    pp = (unsigned char *) path;
181105b261ecSmrg    cp++;
181205b261ecSmrg    while (*pp) {
181305b261ecSmrg	if (*pp == ',') {
181405b261ecSmrg	    *nump = (unsigned char) size;
181505b261ecSmrg	    nump = cp++;
181605b261ecSmrg	    pp++;
181705b261ecSmrg	    num++;
181805b261ecSmrg	    size = 0;
181905b261ecSmrg	} else {
182005b261ecSmrg	    *cp++ = *pp++;
182105b261ecSmrg	    size++;
182205b261ecSmrg	}
182305b261ecSmrg    }
182405b261ecSmrg    *nump = (unsigned char) size;
182505b261ecSmrg
182605b261ecSmrg    err = SetFontPathElements(num, newpath, &bad, TRUE);
182705b261ecSmrg
182805b261ecSmrg    DEALLOCATE_LOCAL(newpath);
182905b261ecSmrg
183005b261ecSmrg    return err;
183105b261ecSmrg}
183205b261ecSmrg
183305b261ecSmrgunsigned char *
183405b261ecSmrgGetFontPath(int *count, int *length)
183505b261ecSmrg{
183605b261ecSmrg    int			i;
183705b261ecSmrg    unsigned char       *c;
183805b261ecSmrg    int			len;
183905b261ecSmrg    FontPathElementPtr	fpe;
184005b261ecSmrg
184105b261ecSmrg    len = 0;
184205b261ecSmrg    for (i = 0; i < num_fpes; i++) {
184305b261ecSmrg	fpe = font_path_elements[i];
184405b261ecSmrg	len += fpe->name_length + 1;
184505b261ecSmrg    }
184605b261ecSmrg    font_path_string = (unsigned char *) xrealloc(font_path_string, len);
184705b261ecSmrg    if (!font_path_string)
184805b261ecSmrg	return NULL;
184905b261ecSmrg
185005b261ecSmrg    c = font_path_string;
185105b261ecSmrg    *length = 0;
185205b261ecSmrg    for (i = 0; i < num_fpes; i++) {
185305b261ecSmrg	fpe = font_path_elements[i];
185405b261ecSmrg	*c = fpe->name_length;
185505b261ecSmrg	*length += *c++;
185605b261ecSmrg	memmove(c, fpe->name, fpe->name_length);
185705b261ecSmrg	c += fpe->name_length;
185805b261ecSmrg    }
185905b261ecSmrg    *count = num_fpes;
186005b261ecSmrg    return font_path_string;
186105b261ecSmrg}
186205b261ecSmrg
186305b261ecSmrg_X_EXPORT int
186405b261ecSmrgLoadGlyphs(ClientPtr client, FontPtr pfont, unsigned nchars, int item_size, unsigned char *data)
186505b261ecSmrg{
186605b261ecSmrg    if (fpe_functions[pfont->fpe->type].load_glyphs)
186705b261ecSmrg	return (*fpe_functions[pfont->fpe->type].load_glyphs)
186805b261ecSmrg	    (client, pfont, 0, nchars, item_size, data);
186905b261ecSmrg    else
187005b261ecSmrg	return Successful;
187105b261ecSmrg}
187205b261ecSmrg
187305b261ecSmrgvoid
187405b261ecSmrgDeleteClientFontStuff(ClientPtr client)
187505b261ecSmrg{
187605b261ecSmrg    int			i;
187705b261ecSmrg    FontPathElementPtr	fpe;
187805b261ecSmrg
187905b261ecSmrg    for (i = 0; i < num_fpes; i++)
188005b261ecSmrg    {
188105b261ecSmrg	fpe = font_path_elements[i];
188205b261ecSmrg	if (fpe_functions[fpe->type].client_died)
188305b261ecSmrg	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
188405b261ecSmrg    }
188505b261ecSmrg}
188605b261ecSmrg
188705b261ecSmrgvoid
188805b261ecSmrgInitFonts (void)
188905b261ecSmrg{
189005b261ecSmrg    patternCache = MakeFontPatternCache();
189105b261ecSmrg
189205b261ecSmrg#ifndef BUILTIN_FONTS
189305b261ecSmrg    if (screenInfo.numScreens > screenInfo.numVideoScreens) {
189405b261ecSmrg	PrinterFontRegisterFpeFunctions();
189505b261ecSmrg	FontFileCheckRegisterFpeFunctions();
189605b261ecSmrg	check_fs_register_fpe_functions();
189705b261ecSmrg    } else
189805b261ecSmrg#endif
189905b261ecSmrg    {
190005b261ecSmrg#ifdef BUILTIN_FONTS
190105b261ecSmrg        BuiltinRegisterFpeFunctions();
190205b261ecSmrg#else
190305b261ecSmrg	FontFileRegisterFpeFunctions();
190405b261ecSmrg#endif
190505b261ecSmrg#ifndef NOFONTSERVERACCESS
190605b261ecSmrg	fs_register_fpe_functions();
190705b261ecSmrg#endif
190805b261ecSmrg    }
190905b261ecSmrg}
191005b261ecSmrg
191105b261ecSmrgint
191205b261ecSmrgGetDefaultPointSize ()
191305b261ecSmrg{
191405b261ecSmrg    return 120;
191505b261ecSmrg}
191605b261ecSmrg
191705b261ecSmrg
191805b261ecSmrgFontResolutionPtr
191905b261ecSmrgGetClientResolutions (int *num)
192005b261ecSmrg{
192105b261ecSmrg    if (requestingClient && requestingClient->fontResFunc != NULL &&
192205b261ecSmrg	!requestingClient->clientGone)
192305b261ecSmrg    {
192405b261ecSmrg	return (*requestingClient->fontResFunc)(requestingClient, num);
192505b261ecSmrg    }
192605b261ecSmrg    else {
192705b261ecSmrg	static struct _FontResolution res;
192805b261ecSmrg	ScreenPtr   pScreen;
192905b261ecSmrg
193005b261ecSmrg	pScreen = screenInfo.screens[0];
193105b261ecSmrg	res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth;
193205b261ecSmrg	/*
193305b261ecSmrg	 * XXX - we'll want this as long as bitmap instances are prevalent
193405b261ecSmrg	 so that we can match them from scalable fonts
193505b261ecSmrg	 */
193605b261ecSmrg	if (res.x_resolution < 88)
193705b261ecSmrg	    res.x_resolution = 75;
193805b261ecSmrg	else
193905b261ecSmrg	    res.x_resolution = 100;
194005b261ecSmrg	res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight;
194105b261ecSmrg	if (res.y_resolution < 88)
194205b261ecSmrg	    res.y_resolution = 75;
194305b261ecSmrg	else
194405b261ecSmrg	    res.y_resolution = 100;
194505b261ecSmrg	res.point_size = 120;
194605b261ecSmrg	*num = 1;
194705b261ecSmrg	return &res;
194805b261ecSmrg    }
194905b261ecSmrg}
195005b261ecSmrg
195105b261ecSmrg/*
195205b261ecSmrg * returns the type index of the new fpe
195305b261ecSmrg *
195405b261ecSmrg * should be called (only once!) by each type of fpe when initialized
195505b261ecSmrg */
195605b261ecSmrg
195705b261ecSmrgint
195805b261ecSmrgRegisterFPEFunctions(NameCheckFunc name_func,
195905b261ecSmrg		     InitFpeFunc init_func,
196005b261ecSmrg		     FreeFpeFunc free_func,
196105b261ecSmrg		     ResetFpeFunc reset_func,
196205b261ecSmrg		     OpenFontFunc open_func,
196305b261ecSmrg		     CloseFontFunc close_func,
196405b261ecSmrg		     ListFontsFunc list_func,
196505b261ecSmrg		     StartLfwiFunc start_lfwi_func,
196605b261ecSmrg		     NextLfwiFunc next_lfwi_func,
196705b261ecSmrg		     WakeupFpeFunc wakeup_func,
196805b261ecSmrg		     ClientDiedFunc client_died,
196905b261ecSmrg		     LoadGlyphsFunc load_glyphs,
197005b261ecSmrg		     StartLaFunc start_list_alias_func,
197105b261ecSmrg		     NextLaFunc next_list_alias_func,
197205b261ecSmrg		     SetPathFunc set_path_func)
197305b261ecSmrg{
197405b261ecSmrg    FPEFunctions *new;
197505b261ecSmrg
197605b261ecSmrg    /* grow the list */
197705b261ecSmrg    new = (FPEFunctions *) xrealloc(fpe_functions,
197805b261ecSmrg				 (num_fpe_types + 1) * sizeof(FPEFunctions));
197905b261ecSmrg    if (!new)
198005b261ecSmrg	return -1;
198105b261ecSmrg    fpe_functions = new;
198205b261ecSmrg
198305b261ecSmrg    fpe_functions[num_fpe_types].name_check = name_func;
198405b261ecSmrg    fpe_functions[num_fpe_types].open_font = open_func;
198505b261ecSmrg    fpe_functions[num_fpe_types].close_font = close_func;
198605b261ecSmrg    fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func;
198705b261ecSmrg    fpe_functions[num_fpe_types].list_fonts = list_func;
198805b261ecSmrg    fpe_functions[num_fpe_types].start_list_fonts_with_info =
198905b261ecSmrg	start_lfwi_func;
199005b261ecSmrg    fpe_functions[num_fpe_types].list_next_font_with_info =
199105b261ecSmrg	next_lfwi_func;
199205b261ecSmrg    fpe_functions[num_fpe_types].init_fpe = init_func;
199305b261ecSmrg    fpe_functions[num_fpe_types].free_fpe = free_func;
199405b261ecSmrg    fpe_functions[num_fpe_types].reset_fpe = reset_func;
199505b261ecSmrg    fpe_functions[num_fpe_types].client_died = client_died;
199605b261ecSmrg    fpe_functions[num_fpe_types].load_glyphs = load_glyphs;
199705b261ecSmrg    fpe_functions[num_fpe_types].start_list_fonts_and_aliases =
199805b261ecSmrg	start_list_alias_func;
199905b261ecSmrg    fpe_functions[num_fpe_types].list_next_font_or_alias =
200005b261ecSmrg	next_list_alias_func;
200105b261ecSmrg    fpe_functions[num_fpe_types].set_path_hook = set_path_func;
200205b261ecSmrg
200305b261ecSmrg    return num_fpe_types++;
200405b261ecSmrg}
200505b261ecSmrg
200605b261ecSmrgvoid
200705b261ecSmrgFreeFonts(void)
200805b261ecSmrg{
200905b261ecSmrg    if (patternCache) {
201005b261ecSmrg	FreeFontPatternCache(patternCache);
201105b261ecSmrg	patternCache = 0;
201205b261ecSmrg    }
201305b261ecSmrg    FreeFontPath(font_path_elements, num_fpes, TRUE);
201405b261ecSmrg    font_path_elements = 0;
201505b261ecSmrg    num_fpes = 0;
201605b261ecSmrg    xfree(fpe_functions);
201705b261ecSmrg    num_fpe_types = 0;
201805b261ecSmrg    fpe_functions = (FPEFunctions *) 0;
201905b261ecSmrg}
202005b261ecSmrg
202105b261ecSmrg/* convenience functions for FS interface */
202205b261ecSmrg
202305b261ecSmrgFontPtr
202405b261ecSmrgfind_old_font(XID id)
202505b261ecSmrg{
202605b261ecSmrg    return (FontPtr) SecurityLookupIDByType(NullClient, id, RT_NONE,
202705b261ecSmrg					    DixUnknownAccess);
202805b261ecSmrg}
202905b261ecSmrg
203005b261ecSmrgFont
203105b261ecSmrgGetNewFontClientID()
203205b261ecSmrg{
203305b261ecSmrg    return FakeClientID(0);
203405b261ecSmrg}
203505b261ecSmrg
203605b261ecSmrgint
203705b261ecSmrgStoreFontClientFont(FontPtr pfont, Font id)
203805b261ecSmrg{
203905b261ecSmrg    return AddResource(id, RT_NONE, (pointer) pfont);
204005b261ecSmrg}
204105b261ecSmrg
204205b261ecSmrgvoid
204305b261ecSmrgDeleteFontClientID(Font id)
204405b261ecSmrg{
204505b261ecSmrg    FreeResource(id, RT_NONE);
204605b261ecSmrg}
204705b261ecSmrg
204805b261ecSmrgint
204905b261ecSmrgclient_auth_generation(ClientPtr client)
205005b261ecSmrg{
205105b261ecSmrg    return 0;
205205b261ecSmrg}
205305b261ecSmrg
205405b261ecSmrgstatic int  fs_handlers_installed = 0;
205505b261ecSmrgstatic unsigned int last_server_gen;
205605b261ecSmrg
205705b261ecSmrgint
205805b261ecSmrginit_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler)
205905b261ecSmrg{
206005b261ecSmrg    /* if server has reset, make sure the b&w handlers are reinstalled */
206105b261ecSmrg    if (last_server_gen < serverGeneration) {
206205b261ecSmrg	last_server_gen = serverGeneration;
206305b261ecSmrg	fs_handlers_installed = 0;
206405b261ecSmrg    }
206505b261ecSmrg    if (fs_handlers_installed == 0) {
206605b261ecSmrg	if (!RegisterBlockAndWakeupHandlers(block_handler,
206705b261ecSmrg					    FontWakeup, (pointer) 0))
206805b261ecSmrg	    return AllocError;
206905b261ecSmrg	fs_handlers_installed++;
207005b261ecSmrg    }
207105b261ecSmrg    QueueFontWakeup(fpe);
207205b261ecSmrg    return Successful;
207305b261ecSmrg}
207405b261ecSmrg
207505b261ecSmrgvoid
207605b261ecSmrgremove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, Bool all)
207705b261ecSmrg{
207805b261ecSmrg    if (all) {
207905b261ecSmrg	/* remove the handlers if no one else is using them */
208005b261ecSmrg	if (--fs_handlers_installed == 0) {
208105b261ecSmrg	    RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
208205b261ecSmrg					 (pointer) 0);
208305b261ecSmrg	}
208405b261ecSmrg    }
208505b261ecSmrg    RemoveFontWakeup(fpe);
208605b261ecSmrg}
2087