dixfonts.c revision 2717a907
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#ifdef HAVE_DIX_CONFIG_H
5205b261ecSmrg#include <dix-config.h>
5305b261ecSmrg#endif
5405b261ecSmrg
5505b261ecSmrg#include <X11/X.h>
5605b261ecSmrg#include <X11/Xmd.h>
5705b261ecSmrg#include <X11/Xproto.h>
5805b261ecSmrg#include "scrnintstr.h"
5905b261ecSmrg#include "resource.h"
6005b261ecSmrg#include "dixstruct.h"
6105b261ecSmrg#include "cursorstr.h"
6205b261ecSmrg#include "misc.h"
6305b261ecSmrg#include "opaque.h"
6405b261ecSmrg#include "dixfontstr.h"
6505b261ecSmrg#include "closestr.h"
6605b261ecSmrg#include "dixfont.h"
674642e01fSmrg#include "xace.h"
6805b261ecSmrg
6905b261ecSmrg#ifdef XF86BIGFONT
706747b715Smrg#include "xf86bigfontsrv.h"
7105b261ecSmrg#endif
7205b261ecSmrg
7305b261ecSmrgextern pointer fosNaturalParams;
7405b261ecSmrgextern FontPtr defaultFont;
7505b261ecSmrg
7605b261ecSmrgstatic FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
7705b261ecSmrgstatic int  num_fpes = 0;
784642e01fSmrgstatic FPEFunctions *fpe_functions = (FPEFunctions *) 0;
7905b261ecSmrgstatic int  num_fpe_types = 0;
8005b261ecSmrg
8105b261ecSmrgstatic unsigned char *font_path_string;
8205b261ecSmrg
8305b261ecSmrgstatic int  num_slept_fpes = 0;
8405b261ecSmrgstatic int  size_slept_fpes = 0;
8505b261ecSmrgstatic FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
8605b261ecSmrgstatic FontPatternCachePtr patternCache;
8705b261ecSmrg
884642e01fSmrgstatic int
894642e01fSmrgFontToXError(int err)
9005b261ecSmrg{
9105b261ecSmrg    switch (err) {
9205b261ecSmrg    case Successful:
9305b261ecSmrg	return Success;
9405b261ecSmrg    case AllocError:
9505b261ecSmrg	return BadAlloc;
9605b261ecSmrg    case BadFontName:
9705b261ecSmrg	return BadName;
9805b261ecSmrg    case BadFontPath:
9905b261ecSmrg    case BadFontFormat:	/* is there something better? */
10005b261ecSmrg    case BadCharRange:
10105b261ecSmrg	return BadValue;
10205b261ecSmrg    default:
10305b261ecSmrg	return err;
10405b261ecSmrg    }
10505b261ecSmrg}
10605b261ecSmrg
1074642e01fSmrgstatic int
1084642e01fSmrgLoadGlyphs(ClientPtr client, FontPtr pfont, unsigned nchars, int item_size,
1094642e01fSmrg	   unsigned char *data)
1104642e01fSmrg{
1114642e01fSmrg    if (fpe_functions[pfont->fpe->type].load_glyphs)
1124642e01fSmrg	return (*fpe_functions[pfont->fpe->type].load_glyphs)
1134642e01fSmrg	    (client, pfont, 0, nchars, item_size, data);
1144642e01fSmrg    else
1154642e01fSmrg	return Successful;
1164642e01fSmrg}
11705b261ecSmrg
11805b261ecSmrg/*
11905b261ecSmrg * adding RT_FONT prevents conflict with default cursor font
12005b261ecSmrg */
12105b261ecSmrgBool
12205b261ecSmrgSetDefaultFont(char *defaultfontname)
12305b261ecSmrg{
12405b261ecSmrg    int         err;
12505b261ecSmrg    FontPtr     pf;
12605b261ecSmrg    XID         fid;
12705b261ecSmrg
12805b261ecSmrg    fid = FakeClientID(0);
12905b261ecSmrg    err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync,
13005b261ecSmrg		   (unsigned) strlen(defaultfontname), defaultfontname);
13105b261ecSmrg    if (err != Success)
13205b261ecSmrg	return FALSE;
1336747b715Smrg    err = dixLookupResourceByType((pointer *)&pf, fid, RT_FONT, serverClient,
1346747b715Smrg				  DixReadAccess);
1356747b715Smrg    if (err != Success)
13605b261ecSmrg	return FALSE;
13705b261ecSmrg    defaultFont = pf;
13805b261ecSmrg    return TRUE;
13905b261ecSmrg}
14005b261ecSmrg
14105b261ecSmrg/*
14205b261ecSmrg * note that the font wakeup queue is not refcounted.  this is because
14305b261ecSmrg * an fpe needs to be added when it's inited, and removed when it's finally
14405b261ecSmrg * freed, in order to handle any data that isn't requested, like FS events.
14505b261ecSmrg *
14605b261ecSmrg * since the only thing that should call these routines is the renderer's
14705b261ecSmrg * init_fpe() and free_fpe(), there shouldn't be any problem in using
14805b261ecSmrg * freed data.
14905b261ecSmrg */
15005b261ecSmrgvoid
15105b261ecSmrgQueueFontWakeup(FontPathElementPtr fpe)
15205b261ecSmrg{
15305b261ecSmrg    int         i;
15405b261ecSmrg    FontPathElementPtr *new;
15505b261ecSmrg
15605b261ecSmrg    for (i = 0; i < num_slept_fpes; i++) {
15705b261ecSmrg	if (slept_fpes[i] == fpe) {
15805b261ecSmrg	    return;
15905b261ecSmrg	}
16005b261ecSmrg    }
16105b261ecSmrg    if (num_slept_fpes == size_slept_fpes) {
16205b261ecSmrg	new = (FontPathElementPtr *)
1636747b715Smrg	    realloc(slept_fpes,
16405b261ecSmrg		     sizeof(FontPathElementPtr) * (size_slept_fpes + 4));
16505b261ecSmrg	if (!new)
16605b261ecSmrg	    return;
16705b261ecSmrg	slept_fpes = new;
16805b261ecSmrg	size_slept_fpes += 4;
16905b261ecSmrg    }
17005b261ecSmrg    slept_fpes[num_slept_fpes] = fpe;
17105b261ecSmrg    num_slept_fpes++;
17205b261ecSmrg}
17305b261ecSmrg
17405b261ecSmrgvoid
17505b261ecSmrgRemoveFontWakeup(FontPathElementPtr fpe)
17605b261ecSmrg{
17705b261ecSmrg    int         i,
17805b261ecSmrg                j;
17905b261ecSmrg
18005b261ecSmrg    for (i = 0; i < num_slept_fpes; i++) {
18105b261ecSmrg	if (slept_fpes[i] == fpe) {
18205b261ecSmrg	    for (j = i; j < num_slept_fpes; j++) {
18305b261ecSmrg		slept_fpes[j] = slept_fpes[j + 1];
18405b261ecSmrg	    }
18505b261ecSmrg	    num_slept_fpes--;
18605b261ecSmrg	    return;
18705b261ecSmrg	}
18805b261ecSmrg    }
18905b261ecSmrg}
19005b261ecSmrg
19105b261ecSmrgvoid
19205b261ecSmrgFontWakeup(pointer data, int count, pointer LastSelectMask)
19305b261ecSmrg{
19405b261ecSmrg    int         i;
19505b261ecSmrg    FontPathElementPtr fpe;
19605b261ecSmrg
19705b261ecSmrg    if (count < 0)
19805b261ecSmrg	return;
19905b261ecSmrg    /* wake up any fpe's that may be waiting for information */
20005b261ecSmrg    for (i = 0; i < num_slept_fpes; i++) {
20105b261ecSmrg	fpe = slept_fpes[i];
20205b261ecSmrg	(void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask);
20305b261ecSmrg    }
20405b261ecSmrg}
20505b261ecSmrg
20605b261ecSmrg/* XXX -- these two funcs may want to be broken into macros */
20705b261ecSmrgstatic void
20805b261ecSmrgUseFPE(FontPathElementPtr fpe)
20905b261ecSmrg{
21005b261ecSmrg    fpe->refcount++;
21105b261ecSmrg}
21205b261ecSmrg
21305b261ecSmrgstatic void
21405b261ecSmrgFreeFPE (FontPathElementPtr fpe)
21505b261ecSmrg{
21605b261ecSmrg    fpe->refcount--;
21705b261ecSmrg    if (fpe->refcount == 0) {
21805b261ecSmrg	(*fpe_functions[fpe->type].free_fpe) (fpe);
2196747b715Smrg	free(fpe->name);
2206747b715Smrg	free(fpe);
22105b261ecSmrg    }
22205b261ecSmrg}
22305b261ecSmrg
22405b261ecSmrgstatic Bool
22505b261ecSmrgdoOpenFont(ClientPtr client, OFclosurePtr c)
22605b261ecSmrg{
22705b261ecSmrg    FontPtr     pfont = NullFont;
22805b261ecSmrg    FontPathElementPtr fpe = NULL;
22905b261ecSmrg    ScreenPtr   pScr;
23005b261ecSmrg    int         err = Successful;
23105b261ecSmrg    int         i;
23205b261ecSmrg    char       *alias,
23305b261ecSmrg               *newname;
23405b261ecSmrg    int         newlen;
23505b261ecSmrg    int		aliascount = 20;
23605b261ecSmrg    /*
23705b261ecSmrg     * Decide at runtime what FontFormat to use.
23805b261ecSmrg     */
23905b261ecSmrg    Mask FontFormat =
24005b261ecSmrg
24105b261ecSmrg	((screenInfo.imageByteOrder == LSBFirst) ?
24205b261ecSmrg	    BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) |
24305b261ecSmrg
24405b261ecSmrg	((screenInfo.bitmapBitOrder == LSBFirst) ?
24505b261ecSmrg	    BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) |
24605b261ecSmrg
24705b261ecSmrg	BitmapFormatImageRectMin |
24805b261ecSmrg
24905b261ecSmrg#if GLYPHPADBYTES == 1
25005b261ecSmrg	BitmapFormatScanlinePad8 |
25105b261ecSmrg#endif
25205b261ecSmrg
25305b261ecSmrg#if GLYPHPADBYTES == 2
25405b261ecSmrg	BitmapFormatScanlinePad16 |
25505b261ecSmrg#endif
25605b261ecSmrg
25705b261ecSmrg#if GLYPHPADBYTES == 4
25805b261ecSmrg	BitmapFormatScanlinePad32 |
25905b261ecSmrg#endif
26005b261ecSmrg
26105b261ecSmrg#if GLYPHPADBYTES == 8
26205b261ecSmrg	BitmapFormatScanlinePad64 |
26305b261ecSmrg#endif
26405b261ecSmrg
26505b261ecSmrg	BitmapFormatScanlineUnit8;
26605b261ecSmrg
26705b261ecSmrg    if (client->clientGone)
26805b261ecSmrg    {
26905b261ecSmrg	if (c->current_fpe < c->num_fpes)
27005b261ecSmrg	{
27105b261ecSmrg	    fpe = c->fpe_list[c->current_fpe];
27205b261ecSmrg	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
27305b261ecSmrg	}
27405b261ecSmrg	err = Successful;
27505b261ecSmrg	goto bail;
27605b261ecSmrg    }
27705b261ecSmrg    while (c->current_fpe < c->num_fpes) {
27805b261ecSmrg	fpe = c->fpe_list[c->current_fpe];
27905b261ecSmrg	err = (*fpe_functions[fpe->type].open_font)
28005b261ecSmrg	    ((pointer) client, fpe, c->flags,
28105b261ecSmrg	     c->fontname, c->fnamelen, FontFormat,
28205b261ecSmrg	     BitmapFormatMaskByte |
28305b261ecSmrg	     BitmapFormatMaskBit |
28405b261ecSmrg	     BitmapFormatMaskImageRectangle |
28505b261ecSmrg	     BitmapFormatMaskScanLinePad |
28605b261ecSmrg	     BitmapFormatMaskScanLineUnit,
28705b261ecSmrg	     c->fontid, &pfont, &alias,
28805b261ecSmrg	     c->non_cachable_font && c->non_cachable_font->fpe == fpe ?
28905b261ecSmrg		 c->non_cachable_font :
29005b261ecSmrg		 (FontPtr)0);
29105b261ecSmrg
29205b261ecSmrg	if (err == FontNameAlias && alias) {
29305b261ecSmrg	    newlen = strlen(alias);
2946747b715Smrg	    newname = (char *) realloc(c->fontname, newlen);
29505b261ecSmrg	    if (!newname) {
29605b261ecSmrg		err = AllocError;
29705b261ecSmrg		break;
29805b261ecSmrg	    }
29905b261ecSmrg	    memmove(newname, alias, newlen);
30005b261ecSmrg	    c->fontname = newname;
30105b261ecSmrg	    c->fnamelen = newlen;
30205b261ecSmrg	    c->current_fpe = 0;
3034642e01fSmrg	    if (--aliascount <= 0) {
3044642e01fSmrg		/* We've tried resolving this alias 20 times, we're
3054642e01fSmrg 		 * probably stuck in an infinite loop of aliases pointing
3064642e01fSmrg 		 * to each other - time to take emergency exit!
3074642e01fSmrg 		 */
3084642e01fSmrg 		err = BadImplementation;
30905b261ecSmrg		break;
3104642e01fSmrg	    }
31105b261ecSmrg	    continue;
31205b261ecSmrg	}
31305b261ecSmrg	if (err == BadFontName) {
31405b261ecSmrg	    c->current_fpe++;
31505b261ecSmrg	    continue;
31605b261ecSmrg	}
31705b261ecSmrg	if (err == Suspended) {
3186747b715Smrg	    if (!ClientIsAsleep(client))
3196747b715Smrg		ClientSleep(client, (ClientSleepProcPtr)doOpenFont, c);
3206747b715Smrg	    else
3216747b715Smrg		goto xinerama_sleep;
32205b261ecSmrg	    return TRUE;
32305b261ecSmrg	}
32405b261ecSmrg	break;
32505b261ecSmrg    }
32605b261ecSmrg
32705b261ecSmrg    if (err != Successful)
32805b261ecSmrg	goto bail;
32905b261ecSmrg    if (!pfont) {
33005b261ecSmrg	err = BadFontName;
33105b261ecSmrg	goto bail;
33205b261ecSmrg    }
33305b261ecSmrg    /* check values for firstCol, lastCol, firstRow, and lastRow */
33405b261ecSmrg    if (pfont->info.firstCol > pfont->info.lastCol ||
33505b261ecSmrg       pfont->info.firstRow > pfont->info.lastRow ||
33605b261ecSmrg       pfont->info.lastCol - pfont->info.firstCol > 255) {
33705b261ecSmrg       err = AllocError;
33805b261ecSmrg       goto bail;
33905b261ecSmrg    }
34005b261ecSmrg    if (!pfont->fpe)
34105b261ecSmrg	pfont->fpe = fpe;
34205b261ecSmrg    pfont->refcnt++;
34305b261ecSmrg    if (pfont->refcnt == 1) {
34405b261ecSmrg	UseFPE(pfont->fpe);
34505b261ecSmrg	for (i = 0; i < screenInfo.numScreens; i++) {
34605b261ecSmrg	    pScr = screenInfo.screens[i];
34705b261ecSmrg	    if (pScr->RealizeFont)
34805b261ecSmrg	    {
34905b261ecSmrg		if (!(*pScr->RealizeFont) (pScr, pfont))
35005b261ecSmrg		{
35105b261ecSmrg		    CloseFont (pfont, (Font) 0);
35205b261ecSmrg		    err = AllocError;
35305b261ecSmrg		    goto bail;
35405b261ecSmrg		}
35505b261ecSmrg	    }
35605b261ecSmrg	}
35705b261ecSmrg    }
35805b261ecSmrg    if (!AddResource(c->fontid, RT_FONT, (pointer) pfont)) {
35905b261ecSmrg	err = AllocError;
36005b261ecSmrg	goto bail;
36105b261ecSmrg    }
36205b261ecSmrg    if (patternCache && pfont != c->non_cachable_font)
36305b261ecSmrg	CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen,
36405b261ecSmrg			 pfont);
36505b261ecSmrgbail:
36605b261ecSmrg    if (err != Successful && c->client != serverClient) {
36705b261ecSmrg	SendErrorToClient(c->client, X_OpenFont, 0,
36805b261ecSmrg			  c->fontid, FontToXError(err));
36905b261ecSmrg    }
3706747b715Smrg    ClientWakeup(c->client);
3716747b715Smrgxinerama_sleep:
37205b261ecSmrg    for (i = 0; i < c->num_fpes; i++) {
37305b261ecSmrg	FreeFPE(c->fpe_list[i]);
37405b261ecSmrg    }
3756747b715Smrg    free(c->fpe_list);
3766747b715Smrg    free(c->fontname);
3776747b715Smrg    free(c);
37805b261ecSmrg    return TRUE;
37905b261ecSmrg}
38005b261ecSmrg
38105b261ecSmrgint
38205b261ecSmrgOpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, char *pfontname)
38305b261ecSmrg{
38405b261ecSmrg    OFclosurePtr c;
38505b261ecSmrg    int         i;
38605b261ecSmrg    FontPtr     cached = (FontPtr)0;
38705b261ecSmrg
38805b261ecSmrg    if (!lenfname || lenfname > XLFDMAXFONTNAMELEN)
38905b261ecSmrg	return BadName;
39005b261ecSmrg    if (patternCache)
39105b261ecSmrg    {
39205b261ecSmrg
39305b261ecSmrg    /*
39405b261ecSmrg    ** Check name cache.  If we find a cached version of this font that
39505b261ecSmrg    ** is cachable, immediately satisfy the request with it.  If we find
39605b261ecSmrg    ** a cached version of this font that is non-cachable, we do not
39705b261ecSmrg    ** satisfy the request with it.  Instead, we pass the FontPtr to the
39805b261ecSmrg    ** FPE's open_font code (the fontfile FPE in turn passes the
39905b261ecSmrg    ** information to the rasterizer; the fserve FPE ignores it).
40005b261ecSmrg    **
40105b261ecSmrg    ** Presumably, the font is marked non-cachable because the FPE has
40205b261ecSmrg    ** put some licensing restrictions on it.  If the FPE, using
40305b261ecSmrg    ** whatever logic it relies on, determines that it is willing to
40405b261ecSmrg    ** share this existing font with the client, then it has the option
40505b261ecSmrg    ** to return the FontPtr we passed it as the newly-opened font.
40605b261ecSmrg    ** This allows the FPE to exercise its licensing logic without
40705b261ecSmrg    ** having to create another instance of a font that already exists.
40805b261ecSmrg    */
40905b261ecSmrg
41005b261ecSmrg	cached = FindCachedFontPattern(patternCache, pfontname, lenfname);
41105b261ecSmrg	if (cached && cached->info.cachable)
41205b261ecSmrg	{
41305b261ecSmrg	    if (!AddResource(fid, RT_FONT, (pointer) cached))
41405b261ecSmrg		return BadAlloc;
41505b261ecSmrg	    cached->refcnt++;
41605b261ecSmrg	    return Success;
41705b261ecSmrg	}
41805b261ecSmrg    }
4196747b715Smrg    c = malloc(sizeof(OFclosureRec));
42005b261ecSmrg    if (!c)
42105b261ecSmrg	return BadAlloc;
4226747b715Smrg    c->fontname = malloc(lenfname);
42305b261ecSmrg    c->origFontName = pfontname;
42405b261ecSmrg    c->origFontNameLen = lenfname;
42505b261ecSmrg    if (!c->fontname) {
4266747b715Smrg	free(c);
42705b261ecSmrg	return BadAlloc;
42805b261ecSmrg    }
42905b261ecSmrg    /*
43005b261ecSmrg     * copy the current FPE list, so that if it gets changed by another client
43105b261ecSmrg     * while we're blocking, the request still appears atomic
43205b261ecSmrg     */
4336747b715Smrg    c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes);
43405b261ecSmrg    if (!c->fpe_list) {
4356747b715Smrg	free(c->fontname);
4366747b715Smrg	free(c);
43705b261ecSmrg	return BadAlloc;
43805b261ecSmrg    }
43905b261ecSmrg    memmove(c->fontname, pfontname, lenfname);
44005b261ecSmrg    for (i = 0; i < num_fpes; i++) {
44105b261ecSmrg	c->fpe_list[i] = font_path_elements[i];
44205b261ecSmrg	UseFPE(c->fpe_list[i]);
44305b261ecSmrg    }
44405b261ecSmrg    c->client = client;
44505b261ecSmrg    c->fontid = fid;
44605b261ecSmrg    c->current_fpe = 0;
44705b261ecSmrg    c->num_fpes = num_fpes;
44805b261ecSmrg    c->fnamelen = lenfname;
44905b261ecSmrg    c->flags = flags;
45005b261ecSmrg    c->non_cachable_font = cached;
45105b261ecSmrg
45205b261ecSmrg    (void) doOpenFont(client, c);
45305b261ecSmrg    return Success;
45405b261ecSmrg}
45505b261ecSmrg
45605b261ecSmrg/**
45705b261ecSmrg * Decrement font's ref count, and free storage if ref count equals zero
45805b261ecSmrg *
45905b261ecSmrg *  \param value must conform to DeleteType
46005b261ecSmrg */
4614642e01fSmrgint
46205b261ecSmrgCloseFont(pointer value, XID fid)
46305b261ecSmrg{
46405b261ecSmrg    int         nscr;
46505b261ecSmrg    ScreenPtr   pscr;
46605b261ecSmrg    FontPathElementPtr fpe;
46705b261ecSmrg    FontPtr     pfont = (FontPtr)value;
46805b261ecSmrg
46905b261ecSmrg    if (pfont == NullFont)
4706747b715Smrg	return Success;
47105b261ecSmrg    if (--pfont->refcnt == 0) {
47205b261ecSmrg	if (patternCache)
47305b261ecSmrg	    RemoveCachedFontPattern (patternCache, pfont);
47405b261ecSmrg	/*
47505b261ecSmrg	 * since the last reference is gone, ask each screen to free any
47605b261ecSmrg	 * storage it may have allocated locally for it.
47705b261ecSmrg	 */
47805b261ecSmrg	for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
47905b261ecSmrg	    pscr = screenInfo.screens[nscr];
48005b261ecSmrg	    if (pscr->UnrealizeFont)
48105b261ecSmrg		(*pscr->UnrealizeFont) (pscr, pfont);
48205b261ecSmrg	}
48305b261ecSmrg	if (pfont == defaultFont)
48405b261ecSmrg	    defaultFont = NULL;
48505b261ecSmrg#ifdef XF86BIGFONT
48605b261ecSmrg	XF86BigfontFreeFontShm(pfont);
48705b261ecSmrg#endif
48805b261ecSmrg	fpe = pfont->fpe;
48905b261ecSmrg	(*fpe_functions[fpe->type].close_font) (fpe, pfont);
49005b261ecSmrg	FreeFPE(fpe);
49105b261ecSmrg    }
4926747b715Smrg    return Success;
49305b261ecSmrg}
49405b261ecSmrg
49505b261ecSmrg
49605b261ecSmrg/***====================================================================***/
49705b261ecSmrg
49805b261ecSmrg/**
49905b261ecSmrg * Sets up pReply as the correct QueryFontReply for pFont with the first
50005b261ecSmrg * nProtoCCIStructs char infos.
50105b261ecSmrg *
50205b261ecSmrg *  \param pReply caller must allocate this storage
50305b261ecSmrg  */
50405b261ecSmrgvoid
50505b261ecSmrgQueryFont(FontPtr pFont, xQueryFontReply *pReply, int nProtoCCIStructs)
50605b261ecSmrg{
50705b261ecSmrg    FontPropPtr      pFP;
50805b261ecSmrg    int              r,
50905b261ecSmrg                     c,
51005b261ecSmrg                     i;
51105b261ecSmrg    xFontProp       *prFP;
51205b261ecSmrg    xCharInfo       *prCI;
51305b261ecSmrg    xCharInfo       *charInfos[256];
51405b261ecSmrg    unsigned char    chars[512];
51505b261ecSmrg    int              ninfos;
51605b261ecSmrg    unsigned long    ncols;
51705b261ecSmrg    unsigned long    count;
51805b261ecSmrg
51905b261ecSmrg    /* pr->length set in dispatch */
52005b261ecSmrg    pReply->minCharOrByte2 = pFont->info.firstCol;
52105b261ecSmrg    pReply->defaultChar = pFont->info.defaultCh;
52205b261ecSmrg    pReply->maxCharOrByte2 = pFont->info.lastCol;
52305b261ecSmrg    pReply->drawDirection = pFont->info.drawDirection;
52405b261ecSmrg    pReply->allCharsExist = pFont->info.allExist;
52505b261ecSmrg    pReply->minByte1 = pFont->info.firstRow;
52605b261ecSmrg    pReply->maxByte1 = pFont->info.lastRow;
52705b261ecSmrg    pReply->fontAscent = pFont->info.fontAscent;
52805b261ecSmrg    pReply->fontDescent = pFont->info.fontDescent;
52905b261ecSmrg
53005b261ecSmrg    pReply->minBounds = pFont->info.ink_minbounds;
53105b261ecSmrg    pReply->maxBounds = pFont->info.ink_maxbounds;
53205b261ecSmrg
53305b261ecSmrg    pReply->nFontProps = pFont->info.nprops;
53405b261ecSmrg    pReply->nCharInfos = nProtoCCIStructs;
53505b261ecSmrg
53605b261ecSmrg    for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]);
53705b261ecSmrg	    i < pFont->info.nprops;
53805b261ecSmrg	    i++, pFP++, prFP++) {
53905b261ecSmrg	prFP->name = pFP->name;
54005b261ecSmrg	prFP->value = pFP->value;
54105b261ecSmrg    }
54205b261ecSmrg
54305b261ecSmrg    ninfos = 0;
54405b261ecSmrg    ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1);
54505b261ecSmrg    prCI = (xCharInfo *) (prFP);
54605b261ecSmrg    for (r = pFont->info.firstRow;
54705b261ecSmrg	    ninfos < nProtoCCIStructs && r <= (int)pFont->info.lastRow;
54805b261ecSmrg	    r++) {
54905b261ecSmrg	i = 0;
55005b261ecSmrg	for (c = pFont->info.firstCol; c <= (int)pFont->info.lastCol; c++) {
55105b261ecSmrg	    chars[i++] = r;
55205b261ecSmrg	    chars[i++] = c;
55305b261ecSmrg	}
55405b261ecSmrg	(*pFont->get_metrics) (pFont, ncols, chars,
55505b261ecSmrg				TwoD16Bit, &count, charInfos);
55605b261ecSmrg	i = 0;
55705b261ecSmrg	for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) {
55805b261ecSmrg	    *prCI = *charInfos[i];
55905b261ecSmrg	    prCI++;
56005b261ecSmrg	    ninfos++;
56105b261ecSmrg	}
56205b261ecSmrg    }
56305b261ecSmrg    return;
56405b261ecSmrg}
56505b261ecSmrg
56605b261ecSmrgstatic Bool
56705b261ecSmrgdoListFontsAndAliases(ClientPtr client, LFclosurePtr c)
56805b261ecSmrg{
56905b261ecSmrg    FontPathElementPtr fpe;
57005b261ecSmrg    int         err = Successful;
57105b261ecSmrg    FontNamesPtr names = NULL;
57205b261ecSmrg    char       *name, *resolved=NULL;
57305b261ecSmrg    int         namelen, resolvedlen;
57405b261ecSmrg    int		nnames;
57505b261ecSmrg    int         stringLens;
57605b261ecSmrg    int         i;
57705b261ecSmrg    xListFontsReply reply;
57805b261ecSmrg    char	*bufptr;
57905b261ecSmrg    char	*bufferStart;
58005b261ecSmrg    int		aliascount = 0;
58105b261ecSmrg
58205b261ecSmrg    if (client->clientGone)
58305b261ecSmrg    {
58405b261ecSmrg	if (c->current.current_fpe < c->num_fpes)
58505b261ecSmrg	{
58605b261ecSmrg	    fpe = c->fpe_list[c->current.current_fpe];
58705b261ecSmrg	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
58805b261ecSmrg	}
58905b261ecSmrg	err = Successful;
59005b261ecSmrg	goto bail;
59105b261ecSmrg    }
59205b261ecSmrg
59305b261ecSmrg    if (!c->current.patlen)
59405b261ecSmrg	goto finish;
59505b261ecSmrg
59605b261ecSmrg    while (c->current.current_fpe < c->num_fpes) {
59705b261ecSmrg	fpe = c->fpe_list[c->current.current_fpe];
59805b261ecSmrg	err = Successful;
59905b261ecSmrg
60005b261ecSmrg	if (!fpe_functions[fpe->type].start_list_fonts_and_aliases)
60105b261ecSmrg	{
60205b261ecSmrg	    /* This FPE doesn't support/require list_fonts_and_aliases */
60305b261ecSmrg
60405b261ecSmrg	    err = (*fpe_functions[fpe->type].list_fonts)
60505b261ecSmrg		((pointer) c->client, fpe, c->current.pattern,
60605b261ecSmrg		 c->current.patlen, c->current.max_names - c->names->nnames,
60705b261ecSmrg		 c->names);
60805b261ecSmrg
60905b261ecSmrg	    if (err == Suspended) {
6106747b715Smrg		if (!ClientIsAsleep(client))
61105b261ecSmrg		    ClientSleep(client,
6126747b715Smrg				(ClientSleepProcPtr)doListFontsAndAliases,
6136747b715Smrg				c);
6146747b715Smrg		else
6156747b715Smrg		    goto xinerama_sleep;
61605b261ecSmrg		return TRUE;
61705b261ecSmrg	    }
61805b261ecSmrg
61905b261ecSmrg	    err = BadFontName;
62005b261ecSmrg	}
62105b261ecSmrg	else
62205b261ecSmrg	{
62305b261ecSmrg	    /* Start of list_fonts_and_aliases functionality.  Modeled
62405b261ecSmrg	       after list_fonts_with_info in that it resolves aliases,
62505b261ecSmrg	       except that the information collected from FPEs is just
62605b261ecSmrg	       names, not font info.  Each list_next_font_or_alias()
62705b261ecSmrg	       returns either a name into name/namelen or an alias into
62805b261ecSmrg	       name/namelen and its target name into resolved/resolvedlen.
62905b261ecSmrg	       The code at this level then resolves the alias by polling
63005b261ecSmrg	       the FPEs.  */
63105b261ecSmrg
63205b261ecSmrg	    if (!c->current.list_started) {
63305b261ecSmrg		err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases)
63405b261ecSmrg		    ((pointer) c->client, fpe, c->current.pattern,
63505b261ecSmrg		     c->current.patlen, c->current.max_names - c->names->nnames,
63605b261ecSmrg		     &c->current.private);
63705b261ecSmrg		if (err == Suspended) {
6386747b715Smrg		    if (!ClientIsAsleep(client))
63905b261ecSmrg			ClientSleep(client,
64005b261ecSmrg				    (ClientSleepProcPtr)doListFontsAndAliases,
6416747b715Smrg				    c);
6426747b715Smrg		    else
6436747b715Smrg			goto xinerama_sleep;
64405b261ecSmrg		    return TRUE;
64505b261ecSmrg		}
64605b261ecSmrg		if (err == Successful)
64705b261ecSmrg		    c->current.list_started = TRUE;
64805b261ecSmrg	    }
64905b261ecSmrg	    if (err == Successful) {
65005b261ecSmrg		char    *tmpname;
65105b261ecSmrg		name = 0;
65205b261ecSmrg		err = (*fpe_functions[fpe->type].list_next_font_or_alias)
65305b261ecSmrg		    ((pointer) c->client, fpe, &name, &namelen, &tmpname,
65405b261ecSmrg		     &resolvedlen, c->current.private);
65505b261ecSmrg		if (err == Suspended) {
6569ace9065Smrg		    if (!ClientIsAsleep(client))
65705b261ecSmrg			ClientSleep(client,
65805b261ecSmrg				    (ClientSleepProcPtr)doListFontsAndAliases,
6596747b715Smrg				    c);
6606747b715Smrg		    else
6616747b715Smrg			goto xinerama_sleep;
66205b261ecSmrg		    return TRUE;
66305b261ecSmrg		}
66405b261ecSmrg		if (err == FontNameAlias) {
6656747b715Smrg		    free(resolved);
6666747b715Smrg		    resolved = malloc(resolvedlen + 1);
66705b261ecSmrg		    if (resolved)
66805b261ecSmrg			memmove(resolved, tmpname, resolvedlen + 1);
66905b261ecSmrg		}
67005b261ecSmrg	    }
67105b261ecSmrg
67205b261ecSmrg	    if (err == Successful)
67305b261ecSmrg	    {
67405b261ecSmrg		if (c->haveSaved)
67505b261ecSmrg		{
67605b261ecSmrg		    if (c->savedName)
67705b261ecSmrg			(void)AddFontNamesName(c->names, c->savedName,
67805b261ecSmrg					       c->savedNameLen);
67905b261ecSmrg		}
68005b261ecSmrg		else
68105b261ecSmrg		    (void)AddFontNamesName(c->names, name, namelen);
68205b261ecSmrg	    }
68305b261ecSmrg
68405b261ecSmrg	    /*
68505b261ecSmrg	     * When we get an alias back, save our state and reset back to
68605b261ecSmrg	     * the start of the FPE looking for the specified name.  As
68705b261ecSmrg	     * soon as a real font is found for the alias, pop back to the
68805b261ecSmrg	     * old state
68905b261ecSmrg	     */
69005b261ecSmrg	    else if (err == FontNameAlias) {
69105b261ecSmrg		char	tmp_pattern[XLFDMAXFONTNAMELEN];
69205b261ecSmrg		/*
69305b261ecSmrg		 * when an alias recurses, we need to give
69405b261ecSmrg		 * the last FPE a chance to clean up; so we call
69505b261ecSmrg		 * it again, and assume that the error returned
69605b261ecSmrg		 * is BadFontName, indicating the alias resolution
69705b261ecSmrg		 * is complete.
69805b261ecSmrg		 */
69905b261ecSmrg		memmove(tmp_pattern, resolved, resolvedlen);
70005b261ecSmrg		if (c->haveSaved)
70105b261ecSmrg		{
70205b261ecSmrg		    char    *tmpname;
70305b261ecSmrg		    int     tmpnamelen;
70405b261ecSmrg
70505b261ecSmrg		    tmpname = 0;
70605b261ecSmrg		    (void) (*fpe_functions[fpe->type].list_next_font_or_alias)
70705b261ecSmrg			((pointer) c->client, fpe, &tmpname, &tmpnamelen,
70805b261ecSmrg			 &tmpname, &tmpnamelen, c->current.private);
70905b261ecSmrg		    if (--aliascount <= 0)
71005b261ecSmrg		    {
71105b261ecSmrg			err = BadFontName;
71205b261ecSmrg			goto ContBadFontName;
71305b261ecSmrg		    }
71405b261ecSmrg		}
71505b261ecSmrg		else
71605b261ecSmrg		{
71705b261ecSmrg		    c->saved = c->current;
71805b261ecSmrg		    c->haveSaved = TRUE;
7196747b715Smrg		    free(c->savedName);
7206747b715Smrg		    c->savedName = malloc(namelen + 1);
72105b261ecSmrg		    if (c->savedName)
72205b261ecSmrg			memmove(c->savedName, name, namelen + 1);
72305b261ecSmrg		    c->savedNameLen = namelen;
72405b261ecSmrg		    aliascount = 20;
72505b261ecSmrg		}
72605b261ecSmrg		memmove(c->current.pattern, tmp_pattern, resolvedlen);
72705b261ecSmrg		c->current.patlen = resolvedlen;
72805b261ecSmrg		c->current.max_names = c->names->nnames + 1;
72905b261ecSmrg		c->current.current_fpe = -1;
73005b261ecSmrg		c->current.private = 0;
73105b261ecSmrg		err = BadFontName;
73205b261ecSmrg	    }
73305b261ecSmrg	}
73405b261ecSmrg	/*
73505b261ecSmrg	 * At the end of this FPE, step to the next.  If we've finished
73605b261ecSmrg	 * processing an alias, pop state back. If we've collected enough
73705b261ecSmrg	 * font names, quit.
73805b261ecSmrg	 */
73905b261ecSmrg	if (err == BadFontName) {
74005b261ecSmrg	  ContBadFontName: ;
74105b261ecSmrg	    c->current.list_started = FALSE;
74205b261ecSmrg	    c->current.current_fpe++;
74305b261ecSmrg	    err = Successful;
74405b261ecSmrg	    if (c->haveSaved)
74505b261ecSmrg	    {
74605b261ecSmrg		if (c->names->nnames == c->current.max_names ||
74705b261ecSmrg			c->current.current_fpe == c->num_fpes) {
74805b261ecSmrg		    c->haveSaved = FALSE;
74905b261ecSmrg		    c->current = c->saved;
75005b261ecSmrg		    /* Give the saved namelist a chance to clean itself up */
75105b261ecSmrg		    continue;
75205b261ecSmrg		}
75305b261ecSmrg	    }
75405b261ecSmrg	    if (c->names->nnames == c->current.max_names)
75505b261ecSmrg		break;
75605b261ecSmrg	}
75705b261ecSmrg    }
75805b261ecSmrg
75905b261ecSmrg    /*
76005b261ecSmrg     * send the reply
76105b261ecSmrg     */
76205b261ecSmrg    if (err != Successful) {
76305b261ecSmrg	SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err));
76405b261ecSmrg	goto bail;
76505b261ecSmrg    }
76605b261ecSmrg
76705b261ecSmrgfinish:
76805b261ecSmrg
76905b261ecSmrg    names = c->names;
77005b261ecSmrg    nnames = names->nnames;
77105b261ecSmrg    client = c->client;
77205b261ecSmrg    stringLens = 0;
77305b261ecSmrg    for (i = 0; i < nnames; i++)
77405b261ecSmrg	stringLens += (names->length[i] <= 255) ? names->length[i] : 0;
77505b261ecSmrg
7766747b715Smrg    memset(&reply, 0, sizeof(xListFontsReply));
77705b261ecSmrg    reply.type = X_Reply;
7786747b715Smrg    reply.length = bytes_to_int32(stringLens + nnames);
77905b261ecSmrg    reply.nFonts = nnames;
78005b261ecSmrg    reply.sequenceNumber = client->sequence;
78105b261ecSmrg
7826747b715Smrg    bufptr = bufferStart = malloc(reply.length << 2);
78305b261ecSmrg
78405b261ecSmrg    if (!bufptr && reply.length) {
78505b261ecSmrg	SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc);
78605b261ecSmrg	goto bail;
78705b261ecSmrg    }
78805b261ecSmrg    /*
78905b261ecSmrg     * since WriteToClient long word aligns things, copy to temp buffer and
79005b261ecSmrg     * write all at once
79105b261ecSmrg     */
79205b261ecSmrg    for (i = 0; i < nnames; i++) {
79305b261ecSmrg	if (names->length[i] > 255)
79405b261ecSmrg	    reply.nFonts--;
79505b261ecSmrg	else
79605b261ecSmrg	{
79705b261ecSmrg	    *bufptr++ = names->length[i];
79805b261ecSmrg	    memmove( bufptr, names->names[i], names->length[i]);
79905b261ecSmrg	    bufptr += names->length[i];
80005b261ecSmrg	}
80105b261ecSmrg    }
80205b261ecSmrg    nnames = reply.nFonts;
8036747b715Smrg    reply.length = bytes_to_int32(stringLens + nnames);
80405b261ecSmrg    client->pSwapReplyFunc = ReplySwapVector[X_ListFonts];
80505b261ecSmrg    WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply);
80605b261ecSmrg    (void) WriteToClient(client, stringLens + nnames, bufferStart);
8076747b715Smrg    free(bufferStart);
80805b261ecSmrg
80905b261ecSmrgbail:
8106747b715Smrg    ClientWakeup(client);
8116747b715Smrgxinerama_sleep:
81205b261ecSmrg    for (i = 0; i < c->num_fpes; i++)
81305b261ecSmrg	FreeFPE(c->fpe_list[i]);
8146747b715Smrg    free(c->fpe_list);
8156747b715Smrg    free(c->savedName);
81605b261ecSmrg    FreeFontNames(names);
8176747b715Smrg    free(c);
8186747b715Smrg    free(resolved);
81905b261ecSmrg    return TRUE;
82005b261ecSmrg}
82105b261ecSmrg
82205b261ecSmrgint
82305b261ecSmrgListFonts(ClientPtr client, unsigned char *pattern, unsigned length,
82405b261ecSmrg          unsigned max_names)
82505b261ecSmrg{
82605b261ecSmrg    int         i;
82705b261ecSmrg    LFclosurePtr c;
82805b261ecSmrg
82905b261ecSmrg    /*
83005b261ecSmrg     * The right error to return here would be BadName, however the
83105b261ecSmrg     * specification does not allow for a Name error on this request.
83205b261ecSmrg     * Perhaps a better solution would be to return a nil list, i.e.
83305b261ecSmrg     * a list containing zero fontnames.
83405b261ecSmrg     */
83505b261ecSmrg    if (length > XLFDMAXFONTNAMELEN)
83605b261ecSmrg	return BadAlloc;
83705b261ecSmrg
8384642e01fSmrg    i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
8394642e01fSmrg    if (i != Success)
8404642e01fSmrg	return i;
8414642e01fSmrg
8426747b715Smrg    if (!(c = malloc(sizeof *c)))
84305b261ecSmrg	return BadAlloc;
8446747b715Smrg    c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes);
84505b261ecSmrg    if (!c->fpe_list) {
8466747b715Smrg	free(c);
84705b261ecSmrg	return BadAlloc;
84805b261ecSmrg    }
84905b261ecSmrg    c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100);
85005b261ecSmrg    if (!c->names)
85105b261ecSmrg    {
8526747b715Smrg	free(c->fpe_list);
8536747b715Smrg	free(c);
85405b261ecSmrg	return BadAlloc;
85505b261ecSmrg    }
85605b261ecSmrg    memmove( c->current.pattern, pattern, length);
85705b261ecSmrg    for (i = 0; i < num_fpes; i++) {
85805b261ecSmrg	c->fpe_list[i] = font_path_elements[i];
85905b261ecSmrg	UseFPE(c->fpe_list[i]);
86005b261ecSmrg    }
86105b261ecSmrg    c->client = client;
86205b261ecSmrg    c->num_fpes = num_fpes;
86305b261ecSmrg    c->current.patlen = length;
86405b261ecSmrg    c->current.current_fpe = 0;
86505b261ecSmrg    c->current.max_names = max_names;
86605b261ecSmrg    c->current.list_started = FALSE;
86705b261ecSmrg    c->current.private = 0;
86805b261ecSmrg    c->haveSaved = FALSE;
86905b261ecSmrg    c->savedName = 0;
87005b261ecSmrg    doListFontsAndAliases(client, c);
87105b261ecSmrg    return Success;
87205b261ecSmrg}
87305b261ecSmrg
87405b261ecSmrgint
87505b261ecSmrgdoListFontsWithInfo(ClientPtr client, LFWIclosurePtr c)
87605b261ecSmrg{
87705b261ecSmrg    FontPathElementPtr fpe;
87805b261ecSmrg    int         err = Successful;
87905b261ecSmrg    char       *name;
88005b261ecSmrg    int         namelen;
88105b261ecSmrg    int         numFonts;
88205b261ecSmrg    FontInfoRec fontInfo,
88305b261ecSmrg               *pFontInfo;
88405b261ecSmrg    xListFontsWithInfoReply *reply;
88505b261ecSmrg    int         length;
88605b261ecSmrg    xFontProp  *pFP;
88705b261ecSmrg    int         i;
88805b261ecSmrg    int		aliascount = 0;
88905b261ecSmrg    xListFontsWithInfoReply finalReply;
89005b261ecSmrg
89105b261ecSmrg    if (client->clientGone)
89205b261ecSmrg    {
89305b261ecSmrg	if (c->current.current_fpe < c->num_fpes)
89405b261ecSmrg 	{
89505b261ecSmrg	    fpe = c->fpe_list[c->current.current_fpe];
89605b261ecSmrg	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
89705b261ecSmrg	}
89805b261ecSmrg	err = Successful;
89905b261ecSmrg	goto bail;
90005b261ecSmrg    }
90105b261ecSmrg    client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo];
90205b261ecSmrg    if (!c->current.patlen)
90305b261ecSmrg	goto finish;
90405b261ecSmrg    while (c->current.current_fpe < c->num_fpes)
90505b261ecSmrg    {
90605b261ecSmrg	fpe = c->fpe_list[c->current.current_fpe];
90705b261ecSmrg	err = Successful;
90805b261ecSmrg	if (!c->current.list_started)
90905b261ecSmrg 	{
91005b261ecSmrg	    err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
91105b261ecSmrg		(client, fpe, c->current.pattern, c->current.patlen,
91205b261ecSmrg		 c->current.max_names, &c->current.private);
91305b261ecSmrg	    if (err == Suspended)
91405b261ecSmrg 	    {
9156747b715Smrg		if (!ClientIsAsleep(client))
9166747b715Smrg		    ClientSleep(client,
9176747b715Smrg				(ClientSleepProcPtr)doListFontsWithInfo, c);
9186747b715Smrg		else
9196747b715Smrg		    goto xinerama_sleep;
92005b261ecSmrg		return TRUE;
92105b261ecSmrg	    }
92205b261ecSmrg	    if (err == Successful)
92305b261ecSmrg		c->current.list_started = TRUE;
92405b261ecSmrg	}
92505b261ecSmrg	if (err == Successful)
92605b261ecSmrg 	{
92705b261ecSmrg	    name = 0;
92805b261ecSmrg	    pFontInfo = &fontInfo;
92905b261ecSmrg	    err = (*fpe_functions[fpe->type].list_next_font_with_info)
93005b261ecSmrg		(client, fpe, &name, &namelen, &pFontInfo,
93105b261ecSmrg		 &numFonts, c->current.private);
93205b261ecSmrg	    if (err == Suspended)
93305b261ecSmrg 	    {
9346747b715Smrg		if (!ClientIsAsleep(client))
93505b261ecSmrg		    ClientSleep(client,
9366747b715Smrg				(ClientSleepProcPtr)doListFontsWithInfo, c);
9376747b715Smrg		else
9386747b715Smrg		    goto xinerama_sleep;
93905b261ecSmrg		return TRUE;
94005b261ecSmrg	    }
94105b261ecSmrg	}
94205b261ecSmrg	/*
94305b261ecSmrg	 * When we get an alias back, save our state and reset back to the
94405b261ecSmrg	 * start of the FPE looking for the specified name.  As soon as a real
94505b261ecSmrg	 * font is found for the alias, pop back to the old state
94605b261ecSmrg	 */
94705b261ecSmrg	if (err == FontNameAlias)
94805b261ecSmrg 	{
94905b261ecSmrg	    /*
95005b261ecSmrg	     * when an alias recurses, we need to give
95105b261ecSmrg	     * the last FPE a chance to clean up; so we call
95205b261ecSmrg	     * it again, and assume that the error returned
95305b261ecSmrg	     * is BadFontName, indicating the alias resolution
95405b261ecSmrg	     * is complete.
95505b261ecSmrg	     */
95605b261ecSmrg	    if (c->haveSaved)
95705b261ecSmrg	    {
95805b261ecSmrg		char	*tmpname;
95905b261ecSmrg		int	tmpnamelen;
96005b261ecSmrg		FontInfoPtr tmpFontInfo;
96105b261ecSmrg
96205b261ecSmrg	    	tmpname = 0;
96305b261ecSmrg	    	tmpFontInfo = &fontInfo;
96405b261ecSmrg	    	(void) (*fpe_functions[fpe->type].list_next_font_with_info)
96505b261ecSmrg		    (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
96605b261ecSmrg		     &numFonts, c->current.private);
96705b261ecSmrg		if (--aliascount <= 0)
96805b261ecSmrg		{
96905b261ecSmrg		    err = BadFontName;
97005b261ecSmrg		    goto ContBadFontName;
97105b261ecSmrg		}
97205b261ecSmrg	    }
97305b261ecSmrg	    else
97405b261ecSmrg	    {
97505b261ecSmrg		c->saved = c->current;
97605b261ecSmrg		c->haveSaved = TRUE;
97705b261ecSmrg		c->savedNumFonts = numFonts;
9786747b715Smrg		free(c->savedName);
9796747b715Smrg		c->savedName = malloc(namelen + 1);
98005b261ecSmrg		if (c->savedName)
98105b261ecSmrg		  memmove(c->savedName, name, namelen + 1);
98205b261ecSmrg		aliascount = 20;
98305b261ecSmrg	    }
98405b261ecSmrg	    memmove(c->current.pattern, name, namelen);
98505b261ecSmrg	    c->current.patlen = namelen;
98605b261ecSmrg	    c->current.max_names = 1;
98705b261ecSmrg	    c->current.current_fpe = 0;
98805b261ecSmrg	    c->current.private = 0;
98905b261ecSmrg	    c->current.list_started = FALSE;
99005b261ecSmrg	}
99105b261ecSmrg	/*
99205b261ecSmrg	 * At the end of this FPE, step to the next.  If we've finished
99305b261ecSmrg	 * processing an alias, pop state back.  If we've sent enough font
99405b261ecSmrg	 * names, quit.  Always wait for BadFontName to let the FPE
99505b261ecSmrg	 * have a chance to clean up.
99605b261ecSmrg	 */
99705b261ecSmrg	else if (err == BadFontName)
99805b261ecSmrg 	{
99905b261ecSmrg	  ContBadFontName: ;
100005b261ecSmrg	    c->current.list_started = FALSE;
100105b261ecSmrg	    c->current.current_fpe++;
100205b261ecSmrg	    err = Successful;
100305b261ecSmrg	    if (c->haveSaved)
100405b261ecSmrg 	    {
100505b261ecSmrg		if (c->current.max_names == 0 ||
100605b261ecSmrg			c->current.current_fpe == c->num_fpes)
100705b261ecSmrg 		{
100805b261ecSmrg		    c->haveSaved = FALSE;
100905b261ecSmrg		    c->saved.max_names -= (1 - c->current.max_names);
101005b261ecSmrg		    c->current = c->saved;
101105b261ecSmrg		}
101205b261ecSmrg	    }
101305b261ecSmrg	    else if (c->current.max_names == 0)
101405b261ecSmrg		break;
101505b261ecSmrg	}
101605b261ecSmrg 	else if (err == Successful)
101705b261ecSmrg 	{
101805b261ecSmrg	    length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
101905b261ecSmrg	    reply = c->reply;
102005b261ecSmrg	    if (c->length < length)
102105b261ecSmrg 	    {
10226747b715Smrg		reply = (xListFontsWithInfoReply *) realloc(c->reply, length);
102305b261ecSmrg		if (!reply)
102405b261ecSmrg 		{
102505b261ecSmrg		    err = AllocError;
102605b261ecSmrg		    break;
102705b261ecSmrg		}
10286747b715Smrg		memset((char*)reply + c->length, 0, length - c->length);
102905b261ecSmrg		c->reply = reply;
103005b261ecSmrg		c->length = length;
103105b261ecSmrg	    }
103205b261ecSmrg	    if (c->haveSaved)
103305b261ecSmrg 	    {
103405b261ecSmrg		numFonts = c->savedNumFonts;
103505b261ecSmrg		name = c->savedName;
103605b261ecSmrg		namelen = strlen(name);
103705b261ecSmrg	    }
103805b261ecSmrg	    reply->type = X_Reply;
10396747b715Smrg	    reply->length = bytes_to_int32(sizeof *reply - sizeof(xGenericReply) +
104005b261ecSmrg			     pFontInfo->nprops * sizeof(xFontProp) +
10416747b715Smrg			     namelen);
104205b261ecSmrg	    reply->sequenceNumber = client->sequence;
104305b261ecSmrg	    reply->nameLength = namelen;
104405b261ecSmrg	    reply->minBounds = pFontInfo->ink_minbounds;
104505b261ecSmrg	    reply->maxBounds = pFontInfo->ink_maxbounds;
104605b261ecSmrg	    reply->minCharOrByte2 = pFontInfo->firstCol;
104705b261ecSmrg	    reply->maxCharOrByte2 = pFontInfo->lastCol;
104805b261ecSmrg	    reply->defaultChar = pFontInfo->defaultCh;
104905b261ecSmrg	    reply->nFontProps = pFontInfo->nprops;
105005b261ecSmrg	    reply->drawDirection = pFontInfo->drawDirection;
105105b261ecSmrg	    reply->minByte1 = pFontInfo->firstRow;
105205b261ecSmrg	    reply->maxByte1 = pFontInfo->lastRow;
105305b261ecSmrg	    reply->allCharsExist = pFontInfo->allExist;
105405b261ecSmrg	    reply->fontAscent = pFontInfo->fontAscent;
105505b261ecSmrg	    reply->fontDescent = pFontInfo->fontDescent;
105605b261ecSmrg	    reply->nReplies = numFonts;
105705b261ecSmrg	    pFP = (xFontProp *) (reply + 1);
105805b261ecSmrg	    for (i = 0; i < pFontInfo->nprops; i++)
105905b261ecSmrg 	    {
106005b261ecSmrg		pFP->name = pFontInfo->props[i].name;
106105b261ecSmrg		pFP->value = pFontInfo->props[i].value;
106205b261ecSmrg		pFP++;
106305b261ecSmrg	    }
106405b261ecSmrg	    WriteSwappedDataToClient(client, length, reply);
106505b261ecSmrg	    (void) WriteToClient(client, namelen, name);
106605b261ecSmrg	    if (pFontInfo == &fontInfo)
106705b261ecSmrg 	    {
10686747b715Smrg		free(fontInfo.props);
10696747b715Smrg		free(fontInfo.isStringProp);
107005b261ecSmrg	    }
107105b261ecSmrg	    --c->current.max_names;
107205b261ecSmrg	}
107305b261ecSmrg    }
107405b261ecSmrgfinish:
107505b261ecSmrg    length = sizeof(xListFontsWithInfoReply);
10766747b715Smrg    memset((char *) &finalReply, 0, sizeof(xListFontsWithInfoReply));
107705b261ecSmrg    finalReply.type = X_Reply;
107805b261ecSmrg    finalReply.sequenceNumber = client->sequence;
10796747b715Smrg    finalReply.length = bytes_to_int32(sizeof(xListFontsWithInfoReply)
10806747b715Smrg		     - sizeof(xGenericReply));
108105b261ecSmrg    WriteSwappedDataToClient(client, length, &finalReply);
108205b261ecSmrgbail:
10836747b715Smrg    ClientWakeup(client);
10846747b715Smrgxinerama_sleep:
108505b261ecSmrg    for (i = 0; i < c->num_fpes; i++)
108605b261ecSmrg	FreeFPE(c->fpe_list[i]);
10876747b715Smrg    free(c->reply);
10886747b715Smrg    free(c->fpe_list);
10896747b715Smrg    free(c->savedName);
10906747b715Smrg    free(c);
109105b261ecSmrg    return TRUE;
109205b261ecSmrg}
109305b261ecSmrg
109405b261ecSmrgint
109505b261ecSmrgStartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern,
109605b261ecSmrg                       int max_names)
109705b261ecSmrg{
109805b261ecSmrg    int		    i;
109905b261ecSmrg    LFWIclosurePtr  c;
110005b261ecSmrg
110105b261ecSmrg    /*
110205b261ecSmrg     * The right error to return here would be BadName, however the
110305b261ecSmrg     * specification does not allow for a Name error on this request.
110405b261ecSmrg     * Perhaps a better solution would be to return a nil list, i.e.
110505b261ecSmrg     * a list containing zero fontnames.
110605b261ecSmrg     */
110705b261ecSmrg    if (length > XLFDMAXFONTNAMELEN)
110805b261ecSmrg	return BadAlloc;
110905b261ecSmrg
11104642e01fSmrg    i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
11114642e01fSmrg    if (i != Success)
11124642e01fSmrg	return i;
11134642e01fSmrg
11146747b715Smrg    if (!(c = malloc(sizeof *c)))
111505b261ecSmrg	goto badAlloc;
11166747b715Smrg    c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes);
111705b261ecSmrg    if (!c->fpe_list)
111805b261ecSmrg    {
11196747b715Smrg	free(c);
112005b261ecSmrg	goto badAlloc;
112105b261ecSmrg    }
112205b261ecSmrg    memmove(c->current.pattern, pattern, length);
112305b261ecSmrg    for (i = 0; i < num_fpes; i++)
112405b261ecSmrg    {
112505b261ecSmrg	c->fpe_list[i] = font_path_elements[i];
112605b261ecSmrg	UseFPE(c->fpe_list[i]);
112705b261ecSmrg    }
112805b261ecSmrg    c->client = client;
112905b261ecSmrg    c->num_fpes = num_fpes;
113005b261ecSmrg    c->reply = 0;
113105b261ecSmrg    c->length = 0;
113205b261ecSmrg    c->current.patlen = length;
113305b261ecSmrg    c->current.current_fpe = 0;
113405b261ecSmrg    c->current.max_names = max_names;
113505b261ecSmrg    c->current.list_started = FALSE;
113605b261ecSmrg    c->current.private = 0;
113705b261ecSmrg    c->savedNumFonts = 0;
113805b261ecSmrg    c->haveSaved = FALSE;
113905b261ecSmrg    c->savedName = 0;
114005b261ecSmrg    doListFontsWithInfo(client, c);
114105b261ecSmrg    return Success;
114205b261ecSmrgbadAlloc:
114305b261ecSmrg    return BadAlloc;
114405b261ecSmrg}
114505b261ecSmrg
114605b261ecSmrg#define TextEltHeader 2
114705b261ecSmrg#define FontShiftSize 5
11486747b715Smrgstatic ChangeGCVal clearGC[] = { { .ptr = NullPixmap } };
114905b261ecSmrg#define clearGCmask (GCClipMask)
115005b261ecSmrg
115105b261ecSmrgint
115205b261ecSmrgdoPolyText(ClientPtr client, PTclosurePtr c)
115305b261ecSmrg{
115405b261ecSmrg    FontPtr pFont = c->pGC->font, oldpFont;
115505b261ecSmrg    int err = Success, lgerr;	/* err is in X error, not font error, space */
115605b261ecSmrg    enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state = NEVER_SLEPT;
115705b261ecSmrg    FontPathElementPtr fpe;
115805b261ecSmrg    GC *origGC = NULL;
11599ace9065Smrg    int itemSize = c->reqType == X_PolyText8 ? 1 : 2;
116005b261ecSmrg
116105b261ecSmrg    if (client->clientGone)
116205b261ecSmrg    {
116305b261ecSmrg	fpe = c->pGC->font->fpe;
116405b261ecSmrg	(*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
116505b261ecSmrg
11666747b715Smrg	if (ClientIsAsleep(client))
116705b261ecSmrg	{
116805b261ecSmrg	    /* Client has died, but we cannot bail out right now.  We
116905b261ecSmrg	       need to clean up after the work we did when going to
117005b261ecSmrg	       sleep.  Setting the drawable pointer to 0 makes this
117105b261ecSmrg	       happen without any attempts to render or perform other
117205b261ecSmrg	       unnecessary activities.  */
117305b261ecSmrg	    c->pDraw = (DrawablePtr)0;
117405b261ecSmrg	}
117505b261ecSmrg	else
117605b261ecSmrg	{
117705b261ecSmrg	    err = Success;
117805b261ecSmrg	    goto bail;
117905b261ecSmrg	}
118005b261ecSmrg    }
118105b261ecSmrg
118205b261ecSmrg    /* Make sure our drawable hasn't disappeared while we slept. */
11836747b715Smrg    if (ClientIsAsleep(client) && c->pDraw)
118405b261ecSmrg    {
11856747b715Smrg	DrawablePtr pDraw;
11866747b715Smrg	dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess);
11876747b715Smrg	if (c->pDraw != pDraw) {
11886747b715Smrg	    /* Our drawable has disappeared.  Treat like client died... ask
11896747b715Smrg	       the FPE code to clean up after client and avoid further
11906747b715Smrg	       rendering while we clean up after ourself.  */
11916747b715Smrg	    fpe = c->pGC->font->fpe;
11926747b715Smrg	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
11936747b715Smrg	    c->pDraw = (DrawablePtr)0;
11946747b715Smrg	}
119505b261ecSmrg    }
119605b261ecSmrg
11976747b715Smrg    client_state = ClientIsAsleep(client) ? SLEEPING : NEVER_SLEPT;
119805b261ecSmrg
119905b261ecSmrg    while (c->endReq - c->pElt > TextEltHeader)
120005b261ecSmrg    {
120105b261ecSmrg	if (*c->pElt == FontChange)
120205b261ecSmrg        {
12036747b715Smrg	    Font fid;
120405b261ecSmrg	    if (c->endReq - c->pElt < FontShiftSize)
120505b261ecSmrg	    {
120605b261ecSmrg		 err = BadLength;
120705b261ecSmrg		 goto bail;
120805b261ecSmrg	    }
120905b261ecSmrg
121005b261ecSmrg	    oldpFont = pFont;
121105b261ecSmrg
121205b261ecSmrg	    fid =  ((Font)*(c->pElt+4))		/* big-endian */
121305b261ecSmrg		 | ((Font)*(c->pElt+3)) << 8
121405b261ecSmrg		 | ((Font)*(c->pElt+2)) << 16
121505b261ecSmrg		 | ((Font)*(c->pElt+1)) << 24;
12166747b715Smrg	    err = dixLookupResourceByType((pointer *)&pFont, fid, RT_FONT,
12176747b715Smrg					  client, DixUseAccess);
12186747b715Smrg	    if (err != Success)
121905b261ecSmrg	    {
12206747b715Smrg		/* restore pFont for step 4 (described below) */
122105b261ecSmrg		pFont = oldpFont;
122205b261ecSmrg
122305b261ecSmrg		/* If we're in START_SLEEP mode, the following step
122405b261ecSmrg		   shortens the request...  in the unlikely event that
122505b261ecSmrg		   the fid somehow becomes valid before we come through
122605b261ecSmrg		   again to actually execute the polytext, which would
122705b261ecSmrg		   then mess up our refcounting scheme badly.  */
122805b261ecSmrg		c->err = err;
122905b261ecSmrg		c->endReq = c->pElt;
123005b261ecSmrg
123105b261ecSmrg		goto bail;
123205b261ecSmrg	    }
123305b261ecSmrg
123405b261ecSmrg	    /* Step 3 (described below) on our new font */
123505b261ecSmrg	    if (client_state == START_SLEEP)
123605b261ecSmrg		pFont->refcnt++;
123705b261ecSmrg	    else
123805b261ecSmrg	    {
123905b261ecSmrg		if (pFont != c->pGC->font && c->pDraw)
124005b261ecSmrg		{
12416747b715Smrg		    ChangeGCVal val;
12426747b715Smrg		    val.ptr = pFont;
12436747b715Smrg		    ChangeGC(NullClient, c->pGC, GCFont, &val);
124405b261ecSmrg		    ValidateGC(c->pDraw, c->pGC);
124505b261ecSmrg		}
124605b261ecSmrg
124705b261ecSmrg		/* Undo the refcnt++ we performed when going to sleep */
124805b261ecSmrg		if (client_state == SLEEPING)
124905b261ecSmrg		    (void)CloseFont(c->pGC->font, (Font)0);
125005b261ecSmrg	    }
125105b261ecSmrg	    c->pElt += FontShiftSize;
125205b261ecSmrg	}
125305b261ecSmrg	else	/* print a string */
125405b261ecSmrg	{
125505b261ecSmrg	    unsigned char *pNextElt;
12569ace9065Smrg	    pNextElt = c->pElt + TextEltHeader + (*c->pElt) * itemSize;
125705b261ecSmrg	    if ( pNextElt > c->endReq)
125805b261ecSmrg	    {
125905b261ecSmrg		err = BadLength;
126005b261ecSmrg		goto bail;
126105b261ecSmrg	    }
126205b261ecSmrg	    if (client_state == START_SLEEP)
126305b261ecSmrg	    {
126405b261ecSmrg		c->pElt = pNextElt;
126505b261ecSmrg		continue;
126605b261ecSmrg	    }
126705b261ecSmrg	    if (c->pDraw)
126805b261ecSmrg	    {
12699ace9065Smrg		lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, itemSize,
127005b261ecSmrg				   c->pElt + TextEltHeader);
127105b261ecSmrg	    }
127205b261ecSmrg	    else lgerr = Successful;
127305b261ecSmrg
127405b261ecSmrg	    if (lgerr == Suspended)
127505b261ecSmrg	    {
12766747b715Smrg		if (!ClientIsAsleep(client)) {
127705b261ecSmrg		    int len;
127805b261ecSmrg		    GC *pGC;
127905b261ecSmrg		    PTclosurePtr new_closure;
128005b261ecSmrg
128105b261ecSmrg    /*  We're putting the client to sleep.  We need to do a few things
128205b261ecSmrg	to ensure successful and atomic-appearing execution of the
128305b261ecSmrg	remainder of the request.  First, copy the remainder of the
128405b261ecSmrg	request into a safe malloc'd area.  Second, create a scratch GC
128505b261ecSmrg	to use for the remainder of the request.  Third, mark all fonts
128605b261ecSmrg	referenced in the remainder of the request to prevent their
128705b261ecSmrg	deallocation.  Fourth, make the original GC look like the
128805b261ecSmrg	request has completed...  set its font to the final font value
128905b261ecSmrg	from this request.  These GC manipulations are for the unlikely
129005b261ecSmrg	(but possible) event that some other client is using the GC.
129105b261ecSmrg	Steps 3 and 4 are performed by running this procedure through
129205b261ecSmrg	the remainder of the request in a special no-render mode
129305b261ecSmrg	indicated by client_state = START_SLEEP.  */
129405b261ecSmrg
129505b261ecSmrg		    /* Step 1 */
129605b261ecSmrg		    /* Allocate a malloc'd closure structure to replace
129705b261ecSmrg		       the local one we were passed */
12986747b715Smrg		    new_closure = malloc(sizeof(PTclosureRec));
129905b261ecSmrg		    if (!new_closure)
130005b261ecSmrg		    {
130105b261ecSmrg			err = BadAlloc;
130205b261ecSmrg			goto bail;
130305b261ecSmrg		    }
130405b261ecSmrg		    *new_closure = *c;
130505b261ecSmrg
1306475c125cSmrg		    len = new_closure->endReq - new_closure->pElt;
1307475c125cSmrg		    new_closure->data = malloc(len);
1308475c125cSmrg		    if (!new_closure->data)
130905b261ecSmrg		    {
1310475c125cSmrg			free(new_closure);
131105b261ecSmrg			err = BadAlloc;
131205b261ecSmrg			goto bail;
131305b261ecSmrg		    }
1314475c125cSmrg		    memmove(new_closure->data, new_closure->pElt, len);
1315475c125cSmrg		    new_closure->pElt = new_closure->data;
1316475c125cSmrg		    new_closure->endReq = new_closure->pElt + len;
131705b261ecSmrg
131805b261ecSmrg		    /* Step 2 */
131905b261ecSmrg
1320475c125cSmrg		    pGC = GetScratchGC(new_closure->pGC->depth, new_closure->pGC->pScreen);
132105b261ecSmrg		    if (!pGC)
132205b261ecSmrg		    {
1323475c125cSmrg			free(new_closure->data);
1324475c125cSmrg			free(new_closure);
132505b261ecSmrg			err = BadAlloc;
132605b261ecSmrg			goto bail;
132705b261ecSmrg		    }
1328475c125cSmrg		    if ((err = CopyGC(new_closure->pGC, pGC, GCFunction |
132905b261ecSmrg				      GCPlaneMask | GCForeground |
133005b261ecSmrg				      GCBackground | GCFillStyle |
133105b261ecSmrg				      GCTile | GCStipple |
133205b261ecSmrg				      GCTileStipXOrigin |
133305b261ecSmrg				      GCTileStipYOrigin | GCFont |
133405b261ecSmrg				      GCSubwindowMode | GCClipXOrigin |
133505b261ecSmrg				      GCClipYOrigin | GCClipMask)) !=
133605b261ecSmrg				      Success)
133705b261ecSmrg		    {
133805b261ecSmrg			FreeScratchGC(pGC);
1339475c125cSmrg			free(new_closure->data);
1340475c125cSmrg			free(new_closure);
134105b261ecSmrg			err = BadAlloc;
134205b261ecSmrg			goto bail;
134305b261ecSmrg		    }
1344475c125cSmrg		    c = new_closure;
134505b261ecSmrg		    origGC = c->pGC;
134605b261ecSmrg		    c->pGC = pGC;
134705b261ecSmrg		    ValidateGC(c->pDraw, c->pGC);
1348475c125cSmrg
13496747b715Smrg		    ClientSleep(client, (ClientSleepProcPtr)doPolyText, c);
135005b261ecSmrg
135105b261ecSmrg		    /* Set up to perform steps 3 and 4 */
135205b261ecSmrg		    client_state = START_SLEEP;
135305b261ecSmrg		    continue;	/* on to steps 3 and 4 */
135405b261ecSmrg		}
13556747b715Smrg		else
13566747b715Smrg		    goto xinerama_sleep;
135705b261ecSmrg		return TRUE;
135805b261ecSmrg	    }
135905b261ecSmrg	    else if (lgerr != Successful)
136005b261ecSmrg	    {
136105b261ecSmrg		err = FontToXError(lgerr);
136205b261ecSmrg		goto bail;
136305b261ecSmrg	    }
136405b261ecSmrg	    if (c->pDraw)
136505b261ecSmrg	    {
136605b261ecSmrg		c->xorg += *((INT8 *)(c->pElt + 1));	/* must be signed */
13679ace9065Smrg		if (c->reqType == X_PolyText8)
13689ace9065Smrg		    c->xorg = (* c->pGC->ops->PolyText8)(c->pDraw, c->pGC, c->xorg, c->yorg,
13699ace9065Smrg			*c->pElt, (char *) (c->pElt + TextEltHeader));
13709ace9065Smrg		else
13719ace9065Smrg		    c->xorg = (* c->pGC->ops->PolyText16)(c->pDraw, c->pGC, c->xorg, c->yorg,
13729ace9065Smrg			*c->pElt, (unsigned short *) (c->pElt + TextEltHeader));
137305b261ecSmrg	    }
137405b261ecSmrg	    c->pElt = pNextElt;
137505b261ecSmrg	}
137605b261ecSmrg    }
137705b261ecSmrg
137805b261ecSmrgbail:
137905b261ecSmrg
138005b261ecSmrg    if (client_state == START_SLEEP)
138105b261ecSmrg    {
138205b261ecSmrg	/* Step 4 */
138305b261ecSmrg	if (pFont != origGC->font)
138405b261ecSmrg	{
13856747b715Smrg	    ChangeGCVal val;
13866747b715Smrg	    val.ptr = pFont;
13876747b715Smrg	    ChangeGC(NullClient, origGC, GCFont, &val);
138805b261ecSmrg	    ValidateGC(c->pDraw, origGC);
138905b261ecSmrg	}
139005b261ecSmrg
139105b261ecSmrg	/* restore pElt pointer for execution of remainder of the request */
139205b261ecSmrg	c->pElt = c->data;
139305b261ecSmrg	return TRUE;
139405b261ecSmrg    }
139505b261ecSmrg
139605b261ecSmrg    if (c->err != Success) err = c->err;
139705b261ecSmrg    if (err != Success && c->client != serverClient) {
139805b261ecSmrg#ifdef PANORAMIX
139905b261ecSmrg        if (noPanoramiXExtension || !c->pGC->pScreen->myNum)
140005b261ecSmrg#endif
140105b261ecSmrg	    SendErrorToClient(c->client, c->reqType, 0, 0, err);
140205b261ecSmrg    }
14036747b715Smrg    if (ClientIsAsleep(client))
140405b261ecSmrg    {
140505b261ecSmrg	ClientWakeup(c->client);
14066747b715Smrgxinerama_sleep:
14076747b715Smrg	ChangeGC(NullClient, c->pGC, clearGCmask, clearGC);
140805b261ecSmrg
140905b261ecSmrg	/* Unreference the font from the scratch GC */
141005b261ecSmrg	CloseFont(c->pGC->font, (Font)0);
141105b261ecSmrg	c->pGC->font = NullFont;
141205b261ecSmrg
141305b261ecSmrg	FreeScratchGC(c->pGC);
14146747b715Smrg	free(c->data);
14156747b715Smrg	free(c);
141605b261ecSmrg    }
141705b261ecSmrg    return TRUE;
141805b261ecSmrg}
141905b261ecSmrg
142005b261ecSmrgint
142105b261ecSmrgPolyText(ClientPtr client, DrawablePtr pDraw, GC *pGC, unsigned char *pElt,
142205b261ecSmrg         unsigned char *endReq, int xorg, int yorg, int reqType, XID did)
142305b261ecSmrg{
142405b261ecSmrg    PTclosureRec local_closure;
142505b261ecSmrg
142605b261ecSmrg    local_closure.pElt = pElt;
142705b261ecSmrg    local_closure.endReq = endReq;
142805b261ecSmrg    local_closure.client = client;
142905b261ecSmrg    local_closure.pDraw = pDraw;
143005b261ecSmrg    local_closure.xorg = xorg;
143105b261ecSmrg    local_closure.yorg = yorg;
14329ace9065Smrg    local_closure.reqType = reqType;
143305b261ecSmrg    local_closure.pGC = pGC;
143405b261ecSmrg    local_closure.did = did;
143505b261ecSmrg    local_closure.err = Success;
143605b261ecSmrg
143705b261ecSmrg    (void) doPolyText(client, &local_closure);
143805b261ecSmrg    return Success;
143905b261ecSmrg}
144005b261ecSmrg
144105b261ecSmrg
144205b261ecSmrg#undef TextEltHeader
144305b261ecSmrg#undef FontShiftSize
144405b261ecSmrg
144505b261ecSmrgint
144605b261ecSmrgdoImageText(ClientPtr client, ITclosurePtr c)
144705b261ecSmrg{
144805b261ecSmrg    int err = Success, lgerr;	/* err is in X error, not font error, space */
144905b261ecSmrg    FontPathElementPtr fpe;
14509ace9065Smrg    int itemSize = c->reqType == X_ImageText8 ? 1 : 2;
145105b261ecSmrg
145205b261ecSmrg    if (client->clientGone)
145305b261ecSmrg    {
145405b261ecSmrg	fpe = c->pGC->font->fpe;
145505b261ecSmrg	(*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
145605b261ecSmrg	err = Success;
145705b261ecSmrg	goto bail;
145805b261ecSmrg    }
145905b261ecSmrg
146005b261ecSmrg    /* Make sure our drawable hasn't disappeared while we slept. */
14616747b715Smrg    if (ClientIsAsleep(client) && c->pDraw)
146205b261ecSmrg    {
14636747b715Smrg	DrawablePtr pDraw;
14646747b715Smrg	dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess);
14656747b715Smrg	if (c->pDraw != pDraw) {
14666747b715Smrg	    /* Our drawable has disappeared.  Treat like client died... ask
14676747b715Smrg	       the FPE code to clean up after client. */
14686747b715Smrg	    fpe = c->pGC->font->fpe;
14696747b715Smrg	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
14706747b715Smrg	    err = Success;
14716747b715Smrg	    goto bail;
14726747b715Smrg	}
147305b261ecSmrg    }
147405b261ecSmrg
14759ace9065Smrg    lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, itemSize, c->data);
147605b261ecSmrg    if (lgerr == Suspended)
147705b261ecSmrg    {
14786747b715Smrg        if (!ClientIsAsleep(client)) {
147905b261ecSmrg	    GC *pGC;
148005b261ecSmrg	    unsigned char *data;
148105b261ecSmrg	    ITclosurePtr new_closure;
14822717a907Sspz            ITclosurePtr old_closure;
148305b261ecSmrg
148405b261ecSmrg	    /* We're putting the client to sleep.  We need to
148505b261ecSmrg	       save some state.  Similar problem to that handled
148605b261ecSmrg	       in doPolyText, but much simpler because the
148705b261ecSmrg	       request structure is much simpler. */
148805b261ecSmrg
14896747b715Smrg	    new_closure = malloc(sizeof(ITclosureRec));
149005b261ecSmrg	    if (!new_closure)
149105b261ecSmrg	    {
149205b261ecSmrg		err = BadAlloc;
149305b261ecSmrg		goto bail;
149405b261ecSmrg	    }
14952717a907Sspz            old_closure = c;
149605b261ecSmrg	    *new_closure = *c;
149705b261ecSmrg	    c = new_closure;
149805b261ecSmrg
14999ace9065Smrg	    data = malloc(c->nChars * itemSize);
150005b261ecSmrg	    if (!data)
150105b261ecSmrg	    {
15026747b715Smrg		free(c);
15032717a907Sspz                c = old_closure;
150405b261ecSmrg		err = BadAlloc;
150505b261ecSmrg		goto bail;
150605b261ecSmrg	    }
15079ace9065Smrg	    memmove(data, c->data, c->nChars * itemSize);
150805b261ecSmrg	    c->data = data;
150905b261ecSmrg
151005b261ecSmrg	    pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
151105b261ecSmrg	    if (!pGC)
151205b261ecSmrg	    {
15136747b715Smrg		free(c->data);
15146747b715Smrg		free(c);
15152717a907Sspz                c = old_closure;
151605b261ecSmrg		err = BadAlloc;
151705b261ecSmrg		goto bail;
151805b261ecSmrg	    }
151905b261ecSmrg	    if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask |
152005b261ecSmrg			      GCForeground | GCBackground | GCFillStyle |
152105b261ecSmrg			      GCTile | GCStipple | GCTileStipXOrigin |
152205b261ecSmrg			      GCTileStipYOrigin | GCFont |
152305b261ecSmrg			      GCSubwindowMode | GCClipXOrigin |
152405b261ecSmrg			      GCClipYOrigin | GCClipMask)) != Success)
152505b261ecSmrg	    {
152605b261ecSmrg		FreeScratchGC(pGC);
15276747b715Smrg		free(c->data);
15286747b715Smrg		free(c);
15292717a907Sspz                c = old_closure;
153005b261ecSmrg		err = BadAlloc;
153105b261ecSmrg		goto bail;
153205b261ecSmrg	    }
153305b261ecSmrg	    c->pGC = pGC;
153405b261ecSmrg	    ValidateGC(c->pDraw, c->pGC);
153505b261ecSmrg
15366747b715Smrg            ClientSleep(client, (ClientSleepProcPtr)doImageText, c);
153705b261ecSmrg        }
15386747b715Smrg	else
15396747b715Smrg	    goto xinerama_sleep;
154005b261ecSmrg        return TRUE;
154105b261ecSmrg    }
154205b261ecSmrg    else if (lgerr != Successful)
154305b261ecSmrg    {
154405b261ecSmrg        err = FontToXError(lgerr);
154505b261ecSmrg        goto bail;
154605b261ecSmrg    }
154705b261ecSmrg    if (c->pDraw)
154805b261ecSmrg    {
15499ace9065Smrg	if (c->reqType == X_ImageText8)
15509ace9065Smrg	    (* c->pGC->ops->ImageText8)(c->pDraw, c->pGC, c->xorg, c->yorg,
15519ace9065Smrg		c->nChars, (char *) c->data);
15529ace9065Smrg	else
15539ace9065Smrg	    (* c->pGC->ops->ImageText16)(c->pDraw, c->pGC, c->xorg, c->yorg,
15549ace9065Smrg		c->nChars, (unsigned short *) c->data);
155505b261ecSmrg    }
155605b261ecSmrg
155705b261ecSmrgbail:
155805b261ecSmrg
155905b261ecSmrg    if (err != Success && c->client != serverClient) {
156005b261ecSmrg	SendErrorToClient(c->client, c->reqType, 0, 0, err);
156105b261ecSmrg    }
15626747b715Smrg    if (ClientIsAsleep(client))
156305b261ecSmrg    {
156405b261ecSmrg	ClientWakeup(c->client);
15656747b715Smrgxinerama_sleep:
15666747b715Smrg	ChangeGC(NullClient, c->pGC, clearGCmask, clearGC);
156705b261ecSmrg
156805b261ecSmrg	/* Unreference the font from the scratch GC */
156905b261ecSmrg	CloseFont(c->pGC->font, (Font)0);
157005b261ecSmrg	c->pGC->font = NullFont;
157105b261ecSmrg
157205b261ecSmrg	FreeScratchGC(c->pGC);
15736747b715Smrg	free(c->data);
15746747b715Smrg	free(c);
157505b261ecSmrg    }
157605b261ecSmrg    return TRUE;
157705b261ecSmrg}
157805b261ecSmrg
157905b261ecSmrgint
158005b261ecSmrgImageText(ClientPtr client, DrawablePtr pDraw, GC *pGC, int nChars,
158105b261ecSmrg          unsigned char *data, int xorg, int yorg, int reqType, XID did)
158205b261ecSmrg{
158305b261ecSmrg    ITclosureRec local_closure;
158405b261ecSmrg
158505b261ecSmrg    local_closure.client = client;
158605b261ecSmrg    local_closure.pDraw = pDraw;
158705b261ecSmrg    local_closure.pGC = pGC;
158805b261ecSmrg    local_closure.nChars = nChars;
158905b261ecSmrg    local_closure.data = data;
159005b261ecSmrg    local_closure.xorg = xorg;
159105b261ecSmrg    local_closure.yorg = yorg;
15929ace9065Smrg    local_closure.reqType = reqType;
159305b261ecSmrg    local_closure.did = did;
159405b261ecSmrg
159505b261ecSmrg    (void) doImageText(client, &local_closure);
159605b261ecSmrg    return Success;
159705b261ecSmrg}
159805b261ecSmrg
159905b261ecSmrg
160005b261ecSmrg/* does the necessary magic to figure out the fpe type */
160105b261ecSmrgstatic int
160205b261ecSmrgDetermineFPEType(char *pathname)
160305b261ecSmrg{
160405b261ecSmrg    int         i;
160505b261ecSmrg
160605b261ecSmrg    for (i = 0; i < num_fpe_types; i++) {
160705b261ecSmrg	if ((*fpe_functions[i].name_check) (pathname))
160805b261ecSmrg	    return i;
160905b261ecSmrg    }
161005b261ecSmrg    return -1;
161105b261ecSmrg}
161205b261ecSmrg
161305b261ecSmrg
161405b261ecSmrgstatic void
161505b261ecSmrgFreeFontPath(FontPathElementPtr *list, int n, Bool force)
161605b261ecSmrg{
161705b261ecSmrg    int         i;
161805b261ecSmrg
161905b261ecSmrg    for (i = 0; i < n; i++) {
162005b261ecSmrg	if (force) {
162105b261ecSmrg	    /* Sanity check that all refcounts will be 0 by the time
162205b261ecSmrg	       we get to the end of the list. */
162305b261ecSmrg	    int found = 1;	/* the first reference is us */
162405b261ecSmrg	    int j;
162505b261ecSmrg	    for (j = i+1; j < n; j++) {
162605b261ecSmrg		if (list[j] == list[i])
162705b261ecSmrg		    found++;
162805b261ecSmrg	    }
162905b261ecSmrg	    if (list[i]->refcount != found) {
163005b261ecSmrg		list[i]->refcount = found; /* ensure it will get freed */
163105b261ecSmrg	    }
163205b261ecSmrg	}
163305b261ecSmrg	FreeFPE(list[i]);
163405b261ecSmrg    }
16356747b715Smrg    free(list);
163605b261ecSmrg}
163705b261ecSmrg
163805b261ecSmrgstatic FontPathElementPtr
163905b261ecSmrgfind_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len)
164005b261ecSmrg{
164105b261ecSmrg    FontPathElementPtr fpe;
164205b261ecSmrg    int         i;
164305b261ecSmrg
164405b261ecSmrg    for (i = 0; i < num; i++) {
164505b261ecSmrg	fpe = list[i];
164605b261ecSmrg	if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0)
164705b261ecSmrg	    return fpe;
164805b261ecSmrg    }
164905b261ecSmrg    return (FontPathElementPtr) 0;
165005b261ecSmrg}
165105b261ecSmrg
165205b261ecSmrg
165305b261ecSmrgstatic int
165405b261ecSmrgSetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist)
165505b261ecSmrg{
165605b261ecSmrg    int         i, err = 0;
165705b261ecSmrg    int         valid_paths = 0;
165805b261ecSmrg    unsigned int len;
165905b261ecSmrg    unsigned char *cp = paths;
166005b261ecSmrg    FontPathElementPtr fpe = NULL, *fplist;
166105b261ecSmrg
16626747b715Smrg    fplist = malloc(sizeof(FontPathElementPtr) * npaths);
166305b261ecSmrg    if (!fplist) {
166405b261ecSmrg	*bad = 0;
166505b261ecSmrg	return BadAlloc;
166605b261ecSmrg    }
166705b261ecSmrg    for (i = 0; i < num_fpe_types; i++) {
166805b261ecSmrg	if (fpe_functions[i].set_path_hook)
166905b261ecSmrg	    (*fpe_functions[i].set_path_hook) ();
167005b261ecSmrg    }
167105b261ecSmrg    for (i = 0; i < npaths; i++)
167205b261ecSmrg    {
167305b261ecSmrg	len = (unsigned int) (*cp++);
167405b261ecSmrg
167505b261ecSmrg	if (len == 0)
167605b261ecSmrg	{
167705b261ecSmrg	    if (persist)
16784642e01fSmrg		ErrorF("[dix] Removing empty element from the valid list of fontpaths\n");
167905b261ecSmrg	    err = BadValue;
168005b261ecSmrg	}
168105b261ecSmrg	else
168205b261ecSmrg	{
168305b261ecSmrg	    /* if it's already in our active list, just reset it */
168405b261ecSmrg	    /*
168505b261ecSmrg	     * note that this can miss FPE's in limbo -- may be worth catching
168605b261ecSmrg	     * them, though it'd muck up refcounting
168705b261ecSmrg	     */
168805b261ecSmrg	    fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
168905b261ecSmrg	    if (fpe)
169005b261ecSmrg	    {
169105b261ecSmrg		err = (*fpe_functions[fpe->type].reset_fpe) (fpe);
169205b261ecSmrg		if (err == Successful)
169305b261ecSmrg		{
169405b261ecSmrg		    UseFPE(fpe);/* since it'll be decref'd later when freed
169505b261ecSmrg				 * from the old list */
169605b261ecSmrg		}
169705b261ecSmrg		else
169805b261ecSmrg		    fpe = 0;
169905b261ecSmrg	    }
170005b261ecSmrg	    /* if error or can't do it, act like it's a new one */
170105b261ecSmrg	    if (!fpe)
170205b261ecSmrg	    {
17036747b715Smrg		fpe = malloc(sizeof(FontPathElementRec));
170405b261ecSmrg		if (!fpe)
170505b261ecSmrg		{
170605b261ecSmrg		    err = BadAlloc;
170705b261ecSmrg		    goto bail;
170805b261ecSmrg		}
17096747b715Smrg		fpe->name = malloc(len + 1);
171005b261ecSmrg		if (!fpe->name)
171105b261ecSmrg		{
17126747b715Smrg		    free(fpe);
171305b261ecSmrg		    err = BadAlloc;
171405b261ecSmrg		    goto bail;
171505b261ecSmrg		}
171605b261ecSmrg		fpe->refcount = 1;
171705b261ecSmrg
171805b261ecSmrg		strncpy(fpe->name, (char *) cp, (int) len);
171905b261ecSmrg		fpe->name[len] = '\0';
172005b261ecSmrg		fpe->name_length = len;
172105b261ecSmrg		fpe->type = DetermineFPEType(fpe->name);
172205b261ecSmrg		if (fpe->type == -1)
172305b261ecSmrg		    err = BadValue;
172405b261ecSmrg		else
172505b261ecSmrg		    err = (*fpe_functions[fpe->type].init_fpe) (fpe);
172605b261ecSmrg		if (err != Successful)
172705b261ecSmrg		{
172805b261ecSmrg		    if (persist)
172905b261ecSmrg		    {
17304642e01fSmrg			ErrorF("[dix] Could not init font path element %s, removing from list!\n",
173105b261ecSmrg			       fpe->name);
173205b261ecSmrg		    }
17336747b715Smrg		    free(fpe->name);
17346747b715Smrg		    free(fpe);
173505b261ecSmrg		}
173605b261ecSmrg	    }
173705b261ecSmrg	}
173805b261ecSmrg	if (err != Successful)
173905b261ecSmrg	{
174005b261ecSmrg	    if (!persist)
174105b261ecSmrg		goto bail;
174205b261ecSmrg	}
174305b261ecSmrg	else
174405b261ecSmrg	{
174505b261ecSmrg	    fplist[valid_paths++] = fpe;
174605b261ecSmrg	}
174705b261ecSmrg	cp += len;
174805b261ecSmrg    }
174905b261ecSmrg
175005b261ecSmrg    FreeFontPath(font_path_elements, num_fpes, FALSE);
175105b261ecSmrg    font_path_elements = fplist;
175205b261ecSmrg    if (patternCache)
175305b261ecSmrg	EmptyFontPatternCache(patternCache);
175405b261ecSmrg    num_fpes = valid_paths;
175505b261ecSmrg
175605b261ecSmrg    return Success;
175705b261ecSmrgbail:
175805b261ecSmrg    *bad = i;
175905b261ecSmrg    while (--valid_paths >= 0)
176005b261ecSmrg	FreeFPE(fplist[valid_paths]);
17616747b715Smrg    free(fplist);
176205b261ecSmrg    return FontToXError(err);
176305b261ecSmrg}
176405b261ecSmrg
176505b261ecSmrgint
17666747b715SmrgSetFontPath(ClientPtr client, int npaths, unsigned char *paths)
176705b261ecSmrg{
17684642e01fSmrg    int err = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess);
17694642e01fSmrg    if (err != Success)
17704642e01fSmrg	return err;
177105b261ecSmrg
177205b261ecSmrg    if (npaths == 0) {
177305b261ecSmrg	if (SetDefaultFontPath(defaultFontPath) != Success)
177405b261ecSmrg	    return BadValue;
177505b261ecSmrg    } else {
17766747b715Smrg	int bad;
17776747b715Smrg	err = SetFontPathElements(npaths, paths, &bad, FALSE);
17786747b715Smrg	client->errorValue = bad;
177905b261ecSmrg    }
178005b261ecSmrg    return err;
178105b261ecSmrg}
178205b261ecSmrg
178305b261ecSmrgint
178405b261ecSmrgSetDefaultFontPath(char *path)
178505b261ecSmrg{
1786b1d344b3Smrg    char       *temp_path,
1787b1d344b3Smrg               *start,
1788b1d344b3Smrg               *end;
178905b261ecSmrg    unsigned char *cp,
179005b261ecSmrg               *pp,
179105b261ecSmrg               *nump,
179205b261ecSmrg               *newpath;
179305b261ecSmrg    int         num = 1,
179405b261ecSmrg                len,
179505b261ecSmrg                err,
179605b261ecSmrg                size = 0,
179705b261ecSmrg                bad;
179805b261ecSmrg
1799b1d344b3Smrg    /* ensure temp_path contains "built-ins" */
1800b1d344b3Smrg    start = path;
1801b1d344b3Smrg    while (1) {
1802b1d344b3Smrg	start = strstr(start, "built-ins");
1803b1d344b3Smrg	if (start == NULL)
1804b1d344b3Smrg	    break;
1805b1d344b3Smrg	end = start + strlen("built-ins");
1806b1d344b3Smrg	if ((start == path || start[-1] == ',') && (!*end || *end == ','))
1807b1d344b3Smrg	    break;
1808b1d344b3Smrg	start = end;
1809b1d344b3Smrg    }
1810b1d344b3Smrg    if (!start) {
18119ace9065Smrg	if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "")
18129ace9065Smrg	    == -1)
18139ace9065Smrg	    temp_path = NULL;
1814b1d344b3Smrg    } else {
18156747b715Smrg	temp_path = strdup(path);
1816b1d344b3Smrg    }
1817b1d344b3Smrg    if (!temp_path)
1818b1d344b3Smrg        return BadAlloc;
1819b1d344b3Smrg
182005b261ecSmrg    /* get enough for string, plus values -- use up commas */
1821b1d344b3Smrg    len = strlen(temp_path) + 1;
18226747b715Smrg    nump = cp = newpath = malloc(len);
18239ace9065Smrg    if (!newpath) {
18249ace9065Smrg	free(temp_path);
182505b261ecSmrg	return BadAlloc;
18269ace9065Smrg    }
1827b1d344b3Smrg    pp = (unsigned char *) temp_path;
182805b261ecSmrg    cp++;
182905b261ecSmrg    while (*pp) {
183005b261ecSmrg	if (*pp == ',') {
183105b261ecSmrg	    *nump = (unsigned char) size;
183205b261ecSmrg	    nump = cp++;
183305b261ecSmrg	    pp++;
183405b261ecSmrg	    num++;
183505b261ecSmrg	    size = 0;
183605b261ecSmrg	} else {
183705b261ecSmrg	    *cp++ = *pp++;
183805b261ecSmrg	    size++;
183905b261ecSmrg	}
184005b261ecSmrg    }
184105b261ecSmrg    *nump = (unsigned char) size;
184205b261ecSmrg
184305b261ecSmrg    err = SetFontPathElements(num, newpath, &bad, TRUE);
184405b261ecSmrg
18456747b715Smrg    free(newpath);
18466747b715Smrg    free(temp_path);
184705b261ecSmrg
184805b261ecSmrg    return err;
184905b261ecSmrg}
185005b261ecSmrg
18514642e01fSmrgint
18524642e01fSmrgGetFontPath(ClientPtr client, int *count, int *length, unsigned char **result)
185305b261ecSmrg{
185405b261ecSmrg    int			i;
185505b261ecSmrg    unsigned char       *c;
185605b261ecSmrg    int			len;
185705b261ecSmrg    FontPathElementPtr	fpe;
185805b261ecSmrg
18594642e01fSmrg    i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
18604642e01fSmrg    if (i != Success)
18614642e01fSmrg	return i;
18624642e01fSmrg
186305b261ecSmrg    len = 0;
186405b261ecSmrg    for (i = 0; i < num_fpes; i++) {
186505b261ecSmrg	fpe = font_path_elements[i];
186605b261ecSmrg	len += fpe->name_length + 1;
186705b261ecSmrg    }
18686747b715Smrg    font_path_string = (unsigned char *) realloc(font_path_string, len);
186905b261ecSmrg    if (!font_path_string)
18704642e01fSmrg	return BadAlloc;
187105b261ecSmrg
187205b261ecSmrg    c = font_path_string;
187305b261ecSmrg    *length = 0;
187405b261ecSmrg    for (i = 0; i < num_fpes; i++) {
187505b261ecSmrg	fpe = font_path_elements[i];
187605b261ecSmrg	*c = fpe->name_length;
187705b261ecSmrg	*length += *c++;
187805b261ecSmrg	memmove(c, fpe->name, fpe->name_length);
187905b261ecSmrg	c += fpe->name_length;
188005b261ecSmrg    }
188105b261ecSmrg    *count = num_fpes;
18824642e01fSmrg    *result = font_path_string;
18834642e01fSmrg    return Success;
188405b261ecSmrg}
188505b261ecSmrg
188605b261ecSmrgvoid
188705b261ecSmrgDeleteClientFontStuff(ClientPtr client)
188805b261ecSmrg{
188905b261ecSmrg    int			i;
189005b261ecSmrg    FontPathElementPtr	fpe;
189105b261ecSmrg
189205b261ecSmrg    for (i = 0; i < num_fpes; i++)
189305b261ecSmrg    {
189405b261ecSmrg	fpe = font_path_elements[i];
189505b261ecSmrg	if (fpe_functions[fpe->type].client_died)
189605b261ecSmrg	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
189705b261ecSmrg    }
189805b261ecSmrg}
189905b261ecSmrg
190005b261ecSmrgvoid
190105b261ecSmrgInitFonts (void)
190205b261ecSmrg{
190305b261ecSmrg    patternCache = MakeFontPatternCache();
190405b261ecSmrg
19056747b715Smrg    register_fpe_functions();
190605b261ecSmrg}
190705b261ecSmrg
190805b261ecSmrgint
19096747b715SmrgGetDefaultPointSize (void)
191005b261ecSmrg{
191105b261ecSmrg    return 120;
191205b261ecSmrg}
191305b261ecSmrg
191405b261ecSmrg
191505b261ecSmrgFontResolutionPtr
191605b261ecSmrgGetClientResolutions (int *num)
191705b261ecSmrg{
19184642e01fSmrg    static struct _FontResolution res;
19194642e01fSmrg    ScreenPtr   pScreen;
192005b261ecSmrg
19214642e01fSmrg    pScreen = screenInfo.screens[0];
19224642e01fSmrg    res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth;
19234642e01fSmrg    /*
19244642e01fSmrg     * XXX - we'll want this as long as bitmap instances are prevalent
19254642e01fSmrg     so that we can match them from scalable fonts
19264642e01fSmrg     */
19274642e01fSmrg    if (res.x_resolution < 88)
19284642e01fSmrg	res.x_resolution = 75;
19294642e01fSmrg    else
19304642e01fSmrg	res.x_resolution = 100;
19314642e01fSmrg    res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight;
19324642e01fSmrg    if (res.y_resolution < 88)
19334642e01fSmrg	res.y_resolution = 75;
19344642e01fSmrg    else
19354642e01fSmrg	res.y_resolution = 100;
19364642e01fSmrg    res.point_size = 120;
19374642e01fSmrg    *num = 1;
19384642e01fSmrg    return &res;
193905b261ecSmrg}
194005b261ecSmrg
194105b261ecSmrg/*
194205b261ecSmrg * returns the type index of the new fpe
194305b261ecSmrg *
194405b261ecSmrg * should be called (only once!) by each type of fpe when initialized
194505b261ecSmrg */
194605b261ecSmrg
194705b261ecSmrgint
194805b261ecSmrgRegisterFPEFunctions(NameCheckFunc name_func,
194905b261ecSmrg		     InitFpeFunc init_func,
195005b261ecSmrg		     FreeFpeFunc free_func,
195105b261ecSmrg		     ResetFpeFunc reset_func,
195205b261ecSmrg		     OpenFontFunc open_func,
195305b261ecSmrg		     CloseFontFunc close_func,
195405b261ecSmrg		     ListFontsFunc list_func,
195505b261ecSmrg		     StartLfwiFunc start_lfwi_func,
195605b261ecSmrg		     NextLfwiFunc next_lfwi_func,
195705b261ecSmrg		     WakeupFpeFunc wakeup_func,
195805b261ecSmrg		     ClientDiedFunc client_died,
195905b261ecSmrg		     LoadGlyphsFunc load_glyphs,
196005b261ecSmrg		     StartLaFunc start_list_alias_func,
196105b261ecSmrg		     NextLaFunc next_list_alias_func,
196205b261ecSmrg		     SetPathFunc set_path_func)
196305b261ecSmrg{
196405b261ecSmrg    FPEFunctions *new;
196505b261ecSmrg
196605b261ecSmrg    /* grow the list */
19676747b715Smrg    new = (FPEFunctions *) realloc(fpe_functions,
196805b261ecSmrg				 (num_fpe_types + 1) * sizeof(FPEFunctions));
196905b261ecSmrg    if (!new)
197005b261ecSmrg	return -1;
197105b261ecSmrg    fpe_functions = new;
197205b261ecSmrg
197305b261ecSmrg    fpe_functions[num_fpe_types].name_check = name_func;
197405b261ecSmrg    fpe_functions[num_fpe_types].open_font = open_func;
197505b261ecSmrg    fpe_functions[num_fpe_types].close_font = close_func;
197605b261ecSmrg    fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func;
197705b261ecSmrg    fpe_functions[num_fpe_types].list_fonts = list_func;
197805b261ecSmrg    fpe_functions[num_fpe_types].start_list_fonts_with_info =
197905b261ecSmrg	start_lfwi_func;
198005b261ecSmrg    fpe_functions[num_fpe_types].list_next_font_with_info =
198105b261ecSmrg	next_lfwi_func;
198205b261ecSmrg    fpe_functions[num_fpe_types].init_fpe = init_func;
198305b261ecSmrg    fpe_functions[num_fpe_types].free_fpe = free_func;
198405b261ecSmrg    fpe_functions[num_fpe_types].reset_fpe = reset_func;
198505b261ecSmrg    fpe_functions[num_fpe_types].client_died = client_died;
198605b261ecSmrg    fpe_functions[num_fpe_types].load_glyphs = load_glyphs;
198705b261ecSmrg    fpe_functions[num_fpe_types].start_list_fonts_and_aliases =
198805b261ecSmrg	start_list_alias_func;
198905b261ecSmrg    fpe_functions[num_fpe_types].list_next_font_or_alias =
199005b261ecSmrg	next_list_alias_func;
199105b261ecSmrg    fpe_functions[num_fpe_types].set_path_hook = set_path_func;
199205b261ecSmrg
199305b261ecSmrg    return num_fpe_types++;
199405b261ecSmrg}
199505b261ecSmrg
199605b261ecSmrgvoid
199705b261ecSmrgFreeFonts(void)
199805b261ecSmrg{
199905b261ecSmrg    if (patternCache) {
200005b261ecSmrg	FreeFontPatternCache(patternCache);
200105b261ecSmrg	patternCache = 0;
200205b261ecSmrg    }
200305b261ecSmrg    FreeFontPath(font_path_elements, num_fpes, TRUE);
200405b261ecSmrg    font_path_elements = 0;
200505b261ecSmrg    num_fpes = 0;
20066747b715Smrg    free(fpe_functions);
200705b261ecSmrg    num_fpe_types = 0;
200805b261ecSmrg    fpe_functions = (FPEFunctions *) 0;
200905b261ecSmrg}
201005b261ecSmrg
201105b261ecSmrg/* convenience functions for FS interface */
201205b261ecSmrg
201305b261ecSmrgFontPtr
201405b261ecSmrgfind_old_font(XID id)
201505b261ecSmrg{
20166747b715Smrg    pointer pFont;
20176747b715Smrg    dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess);
20186747b715Smrg    return (FontPtr)pFont;
201905b261ecSmrg}
202005b261ecSmrg
202105b261ecSmrgFont
20226747b715SmrgGetNewFontClientID(void)
202305b261ecSmrg{
202405b261ecSmrg    return FakeClientID(0);
202505b261ecSmrg}
202605b261ecSmrg
202705b261ecSmrgint
202805b261ecSmrgStoreFontClientFont(FontPtr pfont, Font id)
202905b261ecSmrg{
203005b261ecSmrg    return AddResource(id, RT_NONE, (pointer) pfont);
203105b261ecSmrg}
203205b261ecSmrg
203305b261ecSmrgvoid
203405b261ecSmrgDeleteFontClientID(Font id)
203505b261ecSmrg{
203605b261ecSmrg    FreeResource(id, RT_NONE);
203705b261ecSmrg}
203805b261ecSmrg
203905b261ecSmrgint
204005b261ecSmrgclient_auth_generation(ClientPtr client)
204105b261ecSmrg{
204205b261ecSmrg    return 0;
204305b261ecSmrg}
204405b261ecSmrg
204505b261ecSmrgstatic int  fs_handlers_installed = 0;
204605b261ecSmrgstatic unsigned int last_server_gen;
204705b261ecSmrg
204805b261ecSmrgint
204905b261ecSmrginit_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler)
205005b261ecSmrg{
205105b261ecSmrg    /* if server has reset, make sure the b&w handlers are reinstalled */
205205b261ecSmrg    if (last_server_gen < serverGeneration) {
205305b261ecSmrg	last_server_gen = serverGeneration;
205405b261ecSmrg	fs_handlers_installed = 0;
205505b261ecSmrg    }
205605b261ecSmrg    if (fs_handlers_installed == 0) {
205705b261ecSmrg	if (!RegisterBlockAndWakeupHandlers(block_handler,
205805b261ecSmrg					    FontWakeup, (pointer) 0))
205905b261ecSmrg	    return AllocError;
206005b261ecSmrg	fs_handlers_installed++;
206105b261ecSmrg    }
206205b261ecSmrg    QueueFontWakeup(fpe);
206305b261ecSmrg    return Successful;
206405b261ecSmrg}
206505b261ecSmrg
206605b261ecSmrgvoid
206705b261ecSmrgremove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, Bool all)
206805b261ecSmrg{
206905b261ecSmrg    if (all) {
207005b261ecSmrg	/* remove the handlers if no one else is using them */
207105b261ecSmrg	if (--fs_handlers_installed == 0) {
207205b261ecSmrg	    RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
207305b261ecSmrg					 (pointer) 0);
207405b261ecSmrg	}
207505b261ecSmrg    }
207605b261ecSmrg    RemoveFontWakeup(fpe);
207705b261ecSmrg}
2078