dixfonts.c revision 475c125c
1/************************************************************************
2Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
3
4                        All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of Digital not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22************************************************************************/
23/* The panoramix components contained the following notice */
24/*
25Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
26
27Permission is hereby granted, free of charge, to any person obtaining a copy
28of this software and associated documentation files (the "Software"), to deal
29in the Software without restriction, including without limitation the rights
30to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31copies of the Software.
32
33The above copyright notice and this permission notice shall be included in
34all copies or substantial portions of the Software.
35
36THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
39DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
40BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
41WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
42IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43
44Except as contained in this notice, the name of Digital Equipment Corporation
45shall not be used in advertising or otherwise to promote the sale, use or other
46dealings in this Software without prior written authorization from Digital
47Equipment Corporation.
48
49******************************************************************/
50
51#ifdef HAVE_DIX_CONFIG_H
52#include <dix-config.h>
53#endif
54
55#include <X11/X.h>
56#include <X11/Xmd.h>
57#include <X11/Xproto.h>
58#include "scrnintstr.h"
59#include "resource.h"
60#include "dixstruct.h"
61#include "cursorstr.h"
62#include "misc.h"
63#include "opaque.h"
64#include "dixfontstr.h"
65#include "closestr.h"
66#include "dixfont.h"
67#include "xace.h"
68
69#ifdef XF86BIGFONT
70#include "xf86bigfontsrv.h"
71#endif
72
73extern pointer fosNaturalParams;
74extern FontPtr defaultFont;
75
76static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
77static int  num_fpes = 0;
78static FPEFunctions *fpe_functions = (FPEFunctions *) 0;
79static int  num_fpe_types = 0;
80
81static unsigned char *font_path_string;
82
83static int  num_slept_fpes = 0;
84static int  size_slept_fpes = 0;
85static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
86static FontPatternCachePtr patternCache;
87
88static int
89FontToXError(int err)
90{
91    switch (err) {
92    case Successful:
93	return Success;
94    case AllocError:
95	return BadAlloc;
96    case BadFontName:
97	return BadName;
98    case BadFontPath:
99    case BadFontFormat:	/* is there something better? */
100    case BadCharRange:
101	return BadValue;
102    default:
103	return err;
104    }
105}
106
107static int
108LoadGlyphs(ClientPtr client, FontPtr pfont, unsigned nchars, int item_size,
109	   unsigned char *data)
110{
111    if (fpe_functions[pfont->fpe->type].load_glyphs)
112	return (*fpe_functions[pfont->fpe->type].load_glyphs)
113	    (client, pfont, 0, nchars, item_size, data);
114    else
115	return Successful;
116}
117
118/*
119 * adding RT_FONT prevents conflict with default cursor font
120 */
121Bool
122SetDefaultFont(char *defaultfontname)
123{
124    int         err;
125    FontPtr     pf;
126    XID         fid;
127
128    fid = FakeClientID(0);
129    err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync,
130		   (unsigned) strlen(defaultfontname), defaultfontname);
131    if (err != Success)
132	return FALSE;
133    err = dixLookupResourceByType((pointer *)&pf, fid, RT_FONT, serverClient,
134				  DixReadAccess);
135    if (err != Success)
136	return FALSE;
137    defaultFont = pf;
138    return TRUE;
139}
140
141/*
142 * note that the font wakeup queue is not refcounted.  this is because
143 * an fpe needs to be added when it's inited, and removed when it's finally
144 * freed, in order to handle any data that isn't requested, like FS events.
145 *
146 * since the only thing that should call these routines is the renderer's
147 * init_fpe() and free_fpe(), there shouldn't be any problem in using
148 * freed data.
149 */
150void
151QueueFontWakeup(FontPathElementPtr fpe)
152{
153    int         i;
154    FontPathElementPtr *new;
155
156    for (i = 0; i < num_slept_fpes; i++) {
157	if (slept_fpes[i] == fpe) {
158	    return;
159	}
160    }
161    if (num_slept_fpes == size_slept_fpes) {
162	new = (FontPathElementPtr *)
163	    realloc(slept_fpes,
164		     sizeof(FontPathElementPtr) * (size_slept_fpes + 4));
165	if (!new)
166	    return;
167	slept_fpes = new;
168	size_slept_fpes += 4;
169    }
170    slept_fpes[num_slept_fpes] = fpe;
171    num_slept_fpes++;
172}
173
174void
175RemoveFontWakeup(FontPathElementPtr fpe)
176{
177    int         i,
178                j;
179
180    for (i = 0; i < num_slept_fpes; i++) {
181	if (slept_fpes[i] == fpe) {
182	    for (j = i; j < num_slept_fpes; j++) {
183		slept_fpes[j] = slept_fpes[j + 1];
184	    }
185	    num_slept_fpes--;
186	    return;
187	}
188    }
189}
190
191void
192FontWakeup(pointer data, int count, pointer LastSelectMask)
193{
194    int         i;
195    FontPathElementPtr fpe;
196
197    if (count < 0)
198	return;
199    /* wake up any fpe's that may be waiting for information */
200    for (i = 0; i < num_slept_fpes; i++) {
201	fpe = slept_fpes[i];
202	(void) (*fpe_functions[fpe->type].wakeup_fpe) (fpe, LastSelectMask);
203    }
204}
205
206/* XXX -- these two funcs may want to be broken into macros */
207static void
208UseFPE(FontPathElementPtr fpe)
209{
210    fpe->refcount++;
211}
212
213static void
214FreeFPE (FontPathElementPtr fpe)
215{
216    fpe->refcount--;
217    if (fpe->refcount == 0) {
218	(*fpe_functions[fpe->type].free_fpe) (fpe);
219	free(fpe->name);
220	free(fpe);
221    }
222}
223
224static Bool
225doOpenFont(ClientPtr client, OFclosurePtr c)
226{
227    FontPtr     pfont = NullFont;
228    FontPathElementPtr fpe = NULL;
229    ScreenPtr   pScr;
230    int         err = Successful;
231    int         i;
232    char       *alias,
233               *newname;
234    int         newlen;
235    int		aliascount = 20;
236    /*
237     * Decide at runtime what FontFormat to use.
238     */
239    Mask FontFormat =
240
241	((screenInfo.imageByteOrder == LSBFirst) ?
242	    BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) |
243
244	((screenInfo.bitmapBitOrder == LSBFirst) ?
245	    BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) |
246
247	BitmapFormatImageRectMin |
248
249#if GLYPHPADBYTES == 1
250	BitmapFormatScanlinePad8 |
251#endif
252
253#if GLYPHPADBYTES == 2
254	BitmapFormatScanlinePad16 |
255#endif
256
257#if GLYPHPADBYTES == 4
258	BitmapFormatScanlinePad32 |
259#endif
260
261#if GLYPHPADBYTES == 8
262	BitmapFormatScanlinePad64 |
263#endif
264
265	BitmapFormatScanlineUnit8;
266
267    if (client->clientGone)
268    {
269	if (c->current_fpe < c->num_fpes)
270	{
271	    fpe = c->fpe_list[c->current_fpe];
272	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
273	}
274	err = Successful;
275	goto bail;
276    }
277    while (c->current_fpe < c->num_fpes) {
278	fpe = c->fpe_list[c->current_fpe];
279	err = (*fpe_functions[fpe->type].open_font)
280	    ((pointer) client, fpe, c->flags,
281	     c->fontname, c->fnamelen, FontFormat,
282	     BitmapFormatMaskByte |
283	     BitmapFormatMaskBit |
284	     BitmapFormatMaskImageRectangle |
285	     BitmapFormatMaskScanLinePad |
286	     BitmapFormatMaskScanLineUnit,
287	     c->fontid, &pfont, &alias,
288	     c->non_cachable_font && c->non_cachable_font->fpe == fpe ?
289		 c->non_cachable_font :
290		 (FontPtr)0);
291
292	if (err == FontNameAlias && alias) {
293	    newlen = strlen(alias);
294	    newname = (char *) realloc(c->fontname, newlen);
295	    if (!newname) {
296		err = AllocError;
297		break;
298	    }
299	    memmove(newname, alias, newlen);
300	    c->fontname = newname;
301	    c->fnamelen = newlen;
302	    c->current_fpe = 0;
303	    if (--aliascount <= 0) {
304		/* We've tried resolving this alias 20 times, we're
305 		 * probably stuck in an infinite loop of aliases pointing
306 		 * to each other - time to take emergency exit!
307 		 */
308 		err = BadImplementation;
309		break;
310	    }
311	    continue;
312	}
313	if (err == BadFontName) {
314	    c->current_fpe++;
315	    continue;
316	}
317	if (err == Suspended) {
318	    if (!ClientIsAsleep(client))
319		ClientSleep(client, (ClientSleepProcPtr)doOpenFont, c);
320	    else
321		goto xinerama_sleep;
322	    return TRUE;
323	}
324	break;
325    }
326
327    if (err != Successful)
328	goto bail;
329    if (!pfont) {
330	err = BadFontName;
331	goto bail;
332    }
333    /* check values for firstCol, lastCol, firstRow, and lastRow */
334    if (pfont->info.firstCol > pfont->info.lastCol ||
335       pfont->info.firstRow > pfont->info.lastRow ||
336       pfont->info.lastCol - pfont->info.firstCol > 255) {
337       err = AllocError;
338       goto bail;
339    }
340    if (!pfont->fpe)
341	pfont->fpe = fpe;
342    pfont->refcnt++;
343    if (pfont->refcnt == 1) {
344	UseFPE(pfont->fpe);
345	for (i = 0; i < screenInfo.numScreens; i++) {
346	    pScr = screenInfo.screens[i];
347	    if (pScr->RealizeFont)
348	    {
349		if (!(*pScr->RealizeFont) (pScr, pfont))
350		{
351		    CloseFont (pfont, (Font) 0);
352		    err = AllocError;
353		    goto bail;
354		}
355	    }
356	}
357    }
358    if (!AddResource(c->fontid, RT_FONT, (pointer) pfont)) {
359	err = AllocError;
360	goto bail;
361    }
362    if (patternCache && pfont != c->non_cachable_font)
363	CacheFontPattern(patternCache, c->origFontName, c->origFontNameLen,
364			 pfont);
365bail:
366    if (err != Successful && c->client != serverClient) {
367	SendErrorToClient(c->client, X_OpenFont, 0,
368			  c->fontid, FontToXError(err));
369    }
370    ClientWakeup(c->client);
371xinerama_sleep:
372    for (i = 0; i < c->num_fpes; i++) {
373	FreeFPE(c->fpe_list[i]);
374    }
375    free(c->fpe_list);
376    free(c->fontname);
377    free(c);
378    return TRUE;
379}
380
381int
382OpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname, char *pfontname)
383{
384    OFclosurePtr c;
385    int         i;
386    FontPtr     cached = (FontPtr)0;
387
388    if (!lenfname || lenfname > XLFDMAXFONTNAMELEN)
389	return BadName;
390    if (patternCache)
391    {
392
393    /*
394    ** Check name cache.  If we find a cached version of this font that
395    ** is cachable, immediately satisfy the request with it.  If we find
396    ** a cached version of this font that is non-cachable, we do not
397    ** satisfy the request with it.  Instead, we pass the FontPtr to the
398    ** FPE's open_font code (the fontfile FPE in turn passes the
399    ** information to the rasterizer; the fserve FPE ignores it).
400    **
401    ** Presumably, the font is marked non-cachable because the FPE has
402    ** put some licensing restrictions on it.  If the FPE, using
403    ** whatever logic it relies on, determines that it is willing to
404    ** share this existing font with the client, then it has the option
405    ** to return the FontPtr we passed it as the newly-opened font.
406    ** This allows the FPE to exercise its licensing logic without
407    ** having to create another instance of a font that already exists.
408    */
409
410	cached = FindCachedFontPattern(patternCache, pfontname, lenfname);
411	if (cached && cached->info.cachable)
412	{
413	    if (!AddResource(fid, RT_FONT, (pointer) cached))
414		return BadAlloc;
415	    cached->refcnt++;
416	    return Success;
417	}
418    }
419    c = malloc(sizeof(OFclosureRec));
420    if (!c)
421	return BadAlloc;
422    c->fontname = malloc(lenfname);
423    c->origFontName = pfontname;
424    c->origFontNameLen = lenfname;
425    if (!c->fontname) {
426	free(c);
427	return BadAlloc;
428    }
429    /*
430     * copy the current FPE list, so that if it gets changed by another client
431     * while we're blocking, the request still appears atomic
432     */
433    c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes);
434    if (!c->fpe_list) {
435	free(c->fontname);
436	free(c);
437	return BadAlloc;
438    }
439    memmove(c->fontname, pfontname, lenfname);
440    for (i = 0; i < num_fpes; i++) {
441	c->fpe_list[i] = font_path_elements[i];
442	UseFPE(c->fpe_list[i]);
443    }
444    c->client = client;
445    c->fontid = fid;
446    c->current_fpe = 0;
447    c->num_fpes = num_fpes;
448    c->fnamelen = lenfname;
449    c->flags = flags;
450    c->non_cachable_font = cached;
451
452    (void) doOpenFont(client, c);
453    return Success;
454}
455
456/**
457 * Decrement font's ref count, and free storage if ref count equals zero
458 *
459 *  \param value must conform to DeleteType
460 */
461int
462CloseFont(pointer value, XID fid)
463{
464    int         nscr;
465    ScreenPtr   pscr;
466    FontPathElementPtr fpe;
467    FontPtr     pfont = (FontPtr)value;
468
469    if (pfont == NullFont)
470	return Success;
471    if (--pfont->refcnt == 0) {
472	if (patternCache)
473	    RemoveCachedFontPattern (patternCache, pfont);
474	/*
475	 * since the last reference is gone, ask each screen to free any
476	 * storage it may have allocated locally for it.
477	 */
478	for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
479	    pscr = screenInfo.screens[nscr];
480	    if (pscr->UnrealizeFont)
481		(*pscr->UnrealizeFont) (pscr, pfont);
482	}
483	if (pfont == defaultFont)
484	    defaultFont = NULL;
485#ifdef XF86BIGFONT
486	XF86BigfontFreeFontShm(pfont);
487#endif
488	fpe = pfont->fpe;
489	(*fpe_functions[fpe->type].close_font) (fpe, pfont);
490	FreeFPE(fpe);
491    }
492    return Success;
493}
494
495
496/***====================================================================***/
497
498/**
499 * Sets up pReply as the correct QueryFontReply for pFont with the first
500 * nProtoCCIStructs char infos.
501 *
502 *  \param pReply caller must allocate this storage
503  */
504void
505QueryFont(FontPtr pFont, xQueryFontReply *pReply, int nProtoCCIStructs)
506{
507    FontPropPtr      pFP;
508    int              r,
509                     c,
510                     i;
511    xFontProp       *prFP;
512    xCharInfo       *prCI;
513    xCharInfo       *charInfos[256];
514    unsigned char    chars[512];
515    int              ninfos;
516    unsigned long    ncols;
517    unsigned long    count;
518
519    /* pr->length set in dispatch */
520    pReply->minCharOrByte2 = pFont->info.firstCol;
521    pReply->defaultChar = pFont->info.defaultCh;
522    pReply->maxCharOrByte2 = pFont->info.lastCol;
523    pReply->drawDirection = pFont->info.drawDirection;
524    pReply->allCharsExist = pFont->info.allExist;
525    pReply->minByte1 = pFont->info.firstRow;
526    pReply->maxByte1 = pFont->info.lastRow;
527    pReply->fontAscent = pFont->info.fontAscent;
528    pReply->fontDescent = pFont->info.fontDescent;
529
530    pReply->minBounds = pFont->info.ink_minbounds;
531    pReply->maxBounds = pFont->info.ink_maxbounds;
532
533    pReply->nFontProps = pFont->info.nprops;
534    pReply->nCharInfos = nProtoCCIStructs;
535
536    for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]);
537	    i < pFont->info.nprops;
538	    i++, pFP++, prFP++) {
539	prFP->name = pFP->name;
540	prFP->value = pFP->value;
541    }
542
543    ninfos = 0;
544    ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1);
545    prCI = (xCharInfo *) (prFP);
546    for (r = pFont->info.firstRow;
547	    ninfos < nProtoCCIStructs && r <= (int)pFont->info.lastRow;
548	    r++) {
549	i = 0;
550	for (c = pFont->info.firstCol; c <= (int)pFont->info.lastCol; c++) {
551	    chars[i++] = r;
552	    chars[i++] = c;
553	}
554	(*pFont->get_metrics) (pFont, ncols, chars,
555				TwoD16Bit, &count, charInfos);
556	i = 0;
557	for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) {
558	    *prCI = *charInfos[i];
559	    prCI++;
560	    ninfos++;
561	}
562    }
563    return;
564}
565
566static Bool
567doListFontsAndAliases(ClientPtr client, LFclosurePtr c)
568{
569    FontPathElementPtr fpe;
570    int         err = Successful;
571    FontNamesPtr names = NULL;
572    char       *name, *resolved=NULL;
573    int         namelen, resolvedlen;
574    int		nnames;
575    int         stringLens;
576    int         i;
577    xListFontsReply reply;
578    char	*bufptr;
579    char	*bufferStart;
580    int		aliascount = 0;
581
582    if (client->clientGone)
583    {
584	if (c->current.current_fpe < c->num_fpes)
585	{
586	    fpe = c->fpe_list[c->current.current_fpe];
587	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
588	}
589	err = Successful;
590	goto bail;
591    }
592
593    if (!c->current.patlen)
594	goto finish;
595
596    while (c->current.current_fpe < c->num_fpes) {
597	fpe = c->fpe_list[c->current.current_fpe];
598	err = Successful;
599
600	if (!fpe_functions[fpe->type].start_list_fonts_and_aliases)
601	{
602	    /* This FPE doesn't support/require list_fonts_and_aliases */
603
604	    err = (*fpe_functions[fpe->type].list_fonts)
605		((pointer) c->client, fpe, c->current.pattern,
606		 c->current.patlen, c->current.max_names - c->names->nnames,
607		 c->names);
608
609	    if (err == Suspended) {
610		if (!ClientIsAsleep(client))
611		    ClientSleep(client,
612				(ClientSleepProcPtr)doListFontsAndAliases,
613				c);
614		else
615		    goto xinerama_sleep;
616		return TRUE;
617	    }
618
619	    err = BadFontName;
620	}
621	else
622	{
623	    /* Start of list_fonts_and_aliases functionality.  Modeled
624	       after list_fonts_with_info in that it resolves aliases,
625	       except that the information collected from FPEs is just
626	       names, not font info.  Each list_next_font_or_alias()
627	       returns either a name into name/namelen or an alias into
628	       name/namelen and its target name into resolved/resolvedlen.
629	       The code at this level then resolves the alias by polling
630	       the FPEs.  */
631
632	    if (!c->current.list_started) {
633		err = (*fpe_functions[fpe->type].start_list_fonts_and_aliases)
634		    ((pointer) c->client, fpe, c->current.pattern,
635		     c->current.patlen, c->current.max_names - c->names->nnames,
636		     &c->current.private);
637		if (err == Suspended) {
638		    if (!ClientIsAsleep(client))
639			ClientSleep(client,
640				    (ClientSleepProcPtr)doListFontsAndAliases,
641				    c);
642		    else
643			goto xinerama_sleep;
644		    return TRUE;
645		}
646		if (err == Successful)
647		    c->current.list_started = TRUE;
648	    }
649	    if (err == Successful) {
650		char    *tmpname;
651		name = 0;
652		err = (*fpe_functions[fpe->type].list_next_font_or_alias)
653		    ((pointer) c->client, fpe, &name, &namelen, &tmpname,
654		     &resolvedlen, c->current.private);
655		if (err == Suspended) {
656		    if (!ClientIsAsleep(client))
657			ClientSleep(client,
658				    (ClientSleepProcPtr)doListFontsAndAliases,
659				    c);
660		    else
661			goto xinerama_sleep;
662		    return TRUE;
663		}
664		if (err == FontNameAlias) {
665		    free(resolved);
666		    resolved = malloc(resolvedlen + 1);
667		    if (resolved)
668			memmove(resolved, tmpname, resolvedlen + 1);
669		}
670	    }
671
672	    if (err == Successful)
673	    {
674		if (c->haveSaved)
675		{
676		    if (c->savedName)
677			(void)AddFontNamesName(c->names, c->savedName,
678					       c->savedNameLen);
679		}
680		else
681		    (void)AddFontNamesName(c->names, name, namelen);
682	    }
683
684	    /*
685	     * When we get an alias back, save our state and reset back to
686	     * the start of the FPE looking for the specified name.  As
687	     * soon as a real font is found for the alias, pop back to the
688	     * old state
689	     */
690	    else if (err == FontNameAlias) {
691		char	tmp_pattern[XLFDMAXFONTNAMELEN];
692		/*
693		 * when an alias recurses, we need to give
694		 * the last FPE a chance to clean up; so we call
695		 * it again, and assume that the error returned
696		 * is BadFontName, indicating the alias resolution
697		 * is complete.
698		 */
699		memmove(tmp_pattern, resolved, resolvedlen);
700		if (c->haveSaved)
701		{
702		    char    *tmpname;
703		    int     tmpnamelen;
704
705		    tmpname = 0;
706		    (void) (*fpe_functions[fpe->type].list_next_font_or_alias)
707			((pointer) c->client, fpe, &tmpname, &tmpnamelen,
708			 &tmpname, &tmpnamelen, c->current.private);
709		    if (--aliascount <= 0)
710		    {
711			err = BadFontName;
712			goto ContBadFontName;
713		    }
714		}
715		else
716		{
717		    c->saved = c->current;
718		    c->haveSaved = TRUE;
719		    free(c->savedName);
720		    c->savedName = malloc(namelen + 1);
721		    if (c->savedName)
722			memmove(c->savedName, name, namelen + 1);
723		    c->savedNameLen = namelen;
724		    aliascount = 20;
725		}
726		memmove(c->current.pattern, tmp_pattern, resolvedlen);
727		c->current.patlen = resolvedlen;
728		c->current.max_names = c->names->nnames + 1;
729		c->current.current_fpe = -1;
730		c->current.private = 0;
731		err = BadFontName;
732	    }
733	}
734	/*
735	 * At the end of this FPE, step to the next.  If we've finished
736	 * processing an alias, pop state back. If we've collected enough
737	 * font names, quit.
738	 */
739	if (err == BadFontName) {
740	  ContBadFontName: ;
741	    c->current.list_started = FALSE;
742	    c->current.current_fpe++;
743	    err = Successful;
744	    if (c->haveSaved)
745	    {
746		if (c->names->nnames == c->current.max_names ||
747			c->current.current_fpe == c->num_fpes) {
748		    c->haveSaved = FALSE;
749		    c->current = c->saved;
750		    /* Give the saved namelist a chance to clean itself up */
751		    continue;
752		}
753	    }
754	    if (c->names->nnames == c->current.max_names)
755		break;
756	}
757    }
758
759    /*
760     * send the reply
761     */
762    if (err != Successful) {
763	SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err));
764	goto bail;
765    }
766
767finish:
768
769    names = c->names;
770    nnames = names->nnames;
771    client = c->client;
772    stringLens = 0;
773    for (i = 0; i < nnames; i++)
774	stringLens += (names->length[i] <= 255) ? names->length[i] : 0;
775
776    memset(&reply, 0, sizeof(xListFontsReply));
777    reply.type = X_Reply;
778    reply.length = bytes_to_int32(stringLens + nnames);
779    reply.nFonts = nnames;
780    reply.sequenceNumber = client->sequence;
781
782    bufptr = bufferStart = malloc(reply.length << 2);
783
784    if (!bufptr && reply.length) {
785	SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc);
786	goto bail;
787    }
788    /*
789     * since WriteToClient long word aligns things, copy to temp buffer and
790     * write all at once
791     */
792    for (i = 0; i < nnames; i++) {
793	if (names->length[i] > 255)
794	    reply.nFonts--;
795	else
796	{
797	    *bufptr++ = names->length[i];
798	    memmove( bufptr, names->names[i], names->length[i]);
799	    bufptr += names->length[i];
800	}
801    }
802    nnames = reply.nFonts;
803    reply.length = bytes_to_int32(stringLens + nnames);
804    client->pSwapReplyFunc = ReplySwapVector[X_ListFonts];
805    WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply);
806    (void) WriteToClient(client, stringLens + nnames, bufferStart);
807    free(bufferStart);
808
809bail:
810    ClientWakeup(client);
811xinerama_sleep:
812    for (i = 0; i < c->num_fpes; i++)
813	FreeFPE(c->fpe_list[i]);
814    free(c->fpe_list);
815    free(c->savedName);
816    FreeFontNames(names);
817    free(c);
818    free(resolved);
819    return TRUE;
820}
821
822int
823ListFonts(ClientPtr client, unsigned char *pattern, unsigned length,
824          unsigned max_names)
825{
826    int         i;
827    LFclosurePtr c;
828
829    /*
830     * The right error to return here would be BadName, however the
831     * specification does not allow for a Name error on this request.
832     * Perhaps a better solution would be to return a nil list, i.e.
833     * a list containing zero fontnames.
834     */
835    if (length > XLFDMAXFONTNAMELEN)
836	return BadAlloc;
837
838    i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
839    if (i != Success)
840	return i;
841
842    if (!(c = malloc(sizeof *c)))
843	return BadAlloc;
844    c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes);
845    if (!c->fpe_list) {
846	free(c);
847	return BadAlloc;
848    }
849    c->names = MakeFontNamesRecord(max_names < 100 ? max_names : 100);
850    if (!c->names)
851    {
852	free(c->fpe_list);
853	free(c);
854	return BadAlloc;
855    }
856    memmove( c->current.pattern, pattern, length);
857    for (i = 0; i < num_fpes; i++) {
858	c->fpe_list[i] = font_path_elements[i];
859	UseFPE(c->fpe_list[i]);
860    }
861    c->client = client;
862    c->num_fpes = num_fpes;
863    c->current.patlen = length;
864    c->current.current_fpe = 0;
865    c->current.max_names = max_names;
866    c->current.list_started = FALSE;
867    c->current.private = 0;
868    c->haveSaved = FALSE;
869    c->savedName = 0;
870    doListFontsAndAliases(client, c);
871    return Success;
872}
873
874int
875doListFontsWithInfo(ClientPtr client, LFWIclosurePtr c)
876{
877    FontPathElementPtr fpe;
878    int         err = Successful;
879    char       *name;
880    int         namelen;
881    int         numFonts;
882    FontInfoRec fontInfo,
883               *pFontInfo;
884    xListFontsWithInfoReply *reply;
885    int         length;
886    xFontProp  *pFP;
887    int         i;
888    int		aliascount = 0;
889    xListFontsWithInfoReply finalReply;
890
891    if (client->clientGone)
892    {
893	if (c->current.current_fpe < c->num_fpes)
894 	{
895	    fpe = c->fpe_list[c->current.current_fpe];
896	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
897	}
898	err = Successful;
899	goto bail;
900    }
901    client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo];
902    if (!c->current.patlen)
903	goto finish;
904    while (c->current.current_fpe < c->num_fpes)
905    {
906	fpe = c->fpe_list[c->current.current_fpe];
907	err = Successful;
908	if (!c->current.list_started)
909 	{
910	    err = (*fpe_functions[fpe->type].start_list_fonts_with_info)
911		(client, fpe, c->current.pattern, c->current.patlen,
912		 c->current.max_names, &c->current.private);
913	    if (err == Suspended)
914 	    {
915		if (!ClientIsAsleep(client))
916		    ClientSleep(client,
917				(ClientSleepProcPtr)doListFontsWithInfo, c);
918		else
919		    goto xinerama_sleep;
920		return TRUE;
921	    }
922	    if (err == Successful)
923		c->current.list_started = TRUE;
924	}
925	if (err == Successful)
926 	{
927	    name = 0;
928	    pFontInfo = &fontInfo;
929	    err = (*fpe_functions[fpe->type].list_next_font_with_info)
930		(client, fpe, &name, &namelen, &pFontInfo,
931		 &numFonts, c->current.private);
932	    if (err == Suspended)
933 	    {
934		if (!ClientIsAsleep(client))
935		    ClientSleep(client,
936				(ClientSleepProcPtr)doListFontsWithInfo, c);
937		else
938		    goto xinerama_sleep;
939		return TRUE;
940	    }
941	}
942	/*
943	 * When we get an alias back, save our state and reset back to the
944	 * start of the FPE looking for the specified name.  As soon as a real
945	 * font is found for the alias, pop back to the old state
946	 */
947	if (err == FontNameAlias)
948 	{
949	    /*
950	     * when an alias recurses, we need to give
951	     * the last FPE a chance to clean up; so we call
952	     * it again, and assume that the error returned
953	     * is BadFontName, indicating the alias resolution
954	     * is complete.
955	     */
956	    if (c->haveSaved)
957	    {
958		char	*tmpname;
959		int	tmpnamelen;
960		FontInfoPtr tmpFontInfo;
961
962	    	tmpname = 0;
963	    	tmpFontInfo = &fontInfo;
964	    	(void) (*fpe_functions[fpe->type].list_next_font_with_info)
965		    (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
966		     &numFonts, c->current.private);
967		if (--aliascount <= 0)
968		{
969		    err = BadFontName;
970		    goto ContBadFontName;
971		}
972	    }
973	    else
974	    {
975		c->saved = c->current;
976		c->haveSaved = TRUE;
977		c->savedNumFonts = numFonts;
978		free(c->savedName);
979		c->savedName = malloc(namelen + 1);
980		if (c->savedName)
981		  memmove(c->savedName, name, namelen + 1);
982		aliascount = 20;
983	    }
984	    memmove(c->current.pattern, name, namelen);
985	    c->current.patlen = namelen;
986	    c->current.max_names = 1;
987	    c->current.current_fpe = 0;
988	    c->current.private = 0;
989	    c->current.list_started = FALSE;
990	}
991	/*
992	 * At the end of this FPE, step to the next.  If we've finished
993	 * processing an alias, pop state back.  If we've sent enough font
994	 * names, quit.  Always wait for BadFontName to let the FPE
995	 * have a chance to clean up.
996	 */
997	else if (err == BadFontName)
998 	{
999	  ContBadFontName: ;
1000	    c->current.list_started = FALSE;
1001	    c->current.current_fpe++;
1002	    err = Successful;
1003	    if (c->haveSaved)
1004 	    {
1005		if (c->current.max_names == 0 ||
1006			c->current.current_fpe == c->num_fpes)
1007 		{
1008		    c->haveSaved = FALSE;
1009		    c->saved.max_names -= (1 - c->current.max_names);
1010		    c->current = c->saved;
1011		}
1012	    }
1013	    else if (c->current.max_names == 0)
1014		break;
1015	}
1016 	else if (err == Successful)
1017 	{
1018	    length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
1019	    reply = c->reply;
1020	    if (c->length < length)
1021 	    {
1022		reply = (xListFontsWithInfoReply *) realloc(c->reply, length);
1023		if (!reply)
1024 		{
1025		    err = AllocError;
1026		    break;
1027		}
1028		memset((char*)reply + c->length, 0, length - c->length);
1029		c->reply = reply;
1030		c->length = length;
1031	    }
1032	    if (c->haveSaved)
1033 	    {
1034		numFonts = c->savedNumFonts;
1035		name = c->savedName;
1036		namelen = strlen(name);
1037	    }
1038	    reply->type = X_Reply;
1039	    reply->length = bytes_to_int32(sizeof *reply - sizeof(xGenericReply) +
1040			     pFontInfo->nprops * sizeof(xFontProp) +
1041			     namelen);
1042	    reply->sequenceNumber = client->sequence;
1043	    reply->nameLength = namelen;
1044	    reply->minBounds = pFontInfo->ink_minbounds;
1045	    reply->maxBounds = pFontInfo->ink_maxbounds;
1046	    reply->minCharOrByte2 = pFontInfo->firstCol;
1047	    reply->maxCharOrByte2 = pFontInfo->lastCol;
1048	    reply->defaultChar = pFontInfo->defaultCh;
1049	    reply->nFontProps = pFontInfo->nprops;
1050	    reply->drawDirection = pFontInfo->drawDirection;
1051	    reply->minByte1 = pFontInfo->firstRow;
1052	    reply->maxByte1 = pFontInfo->lastRow;
1053	    reply->allCharsExist = pFontInfo->allExist;
1054	    reply->fontAscent = pFontInfo->fontAscent;
1055	    reply->fontDescent = pFontInfo->fontDescent;
1056	    reply->nReplies = numFonts;
1057	    pFP = (xFontProp *) (reply + 1);
1058	    for (i = 0; i < pFontInfo->nprops; i++)
1059 	    {
1060		pFP->name = pFontInfo->props[i].name;
1061		pFP->value = pFontInfo->props[i].value;
1062		pFP++;
1063	    }
1064	    WriteSwappedDataToClient(client, length, reply);
1065	    (void) WriteToClient(client, namelen, name);
1066	    if (pFontInfo == &fontInfo)
1067 	    {
1068		free(fontInfo.props);
1069		free(fontInfo.isStringProp);
1070	    }
1071	    --c->current.max_names;
1072	}
1073    }
1074finish:
1075    length = sizeof(xListFontsWithInfoReply);
1076    memset((char *) &finalReply, 0, sizeof(xListFontsWithInfoReply));
1077    finalReply.type = X_Reply;
1078    finalReply.sequenceNumber = client->sequence;
1079    finalReply.length = bytes_to_int32(sizeof(xListFontsWithInfoReply)
1080		     - sizeof(xGenericReply));
1081    WriteSwappedDataToClient(client, length, &finalReply);
1082bail:
1083    ClientWakeup(client);
1084xinerama_sleep:
1085    for (i = 0; i < c->num_fpes; i++)
1086	FreeFPE(c->fpe_list[i]);
1087    free(c->reply);
1088    free(c->fpe_list);
1089    free(c->savedName);
1090    free(c);
1091    return TRUE;
1092}
1093
1094int
1095StartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern,
1096                       int max_names)
1097{
1098    int		    i;
1099    LFWIclosurePtr  c;
1100
1101    /*
1102     * The right error to return here would be BadName, however the
1103     * specification does not allow for a Name error on this request.
1104     * Perhaps a better solution would be to return a nil list, i.e.
1105     * a list containing zero fontnames.
1106     */
1107    if (length > XLFDMAXFONTNAMELEN)
1108	return BadAlloc;
1109
1110    i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
1111    if (i != Success)
1112	return i;
1113
1114    if (!(c = malloc(sizeof *c)))
1115	goto badAlloc;
1116    c->fpe_list = malloc(sizeof(FontPathElementPtr) * num_fpes);
1117    if (!c->fpe_list)
1118    {
1119	free(c);
1120	goto badAlloc;
1121    }
1122    memmove(c->current.pattern, pattern, length);
1123    for (i = 0; i < num_fpes; i++)
1124    {
1125	c->fpe_list[i] = font_path_elements[i];
1126	UseFPE(c->fpe_list[i]);
1127    }
1128    c->client = client;
1129    c->num_fpes = num_fpes;
1130    c->reply = 0;
1131    c->length = 0;
1132    c->current.patlen = length;
1133    c->current.current_fpe = 0;
1134    c->current.max_names = max_names;
1135    c->current.list_started = FALSE;
1136    c->current.private = 0;
1137    c->savedNumFonts = 0;
1138    c->haveSaved = FALSE;
1139    c->savedName = 0;
1140    doListFontsWithInfo(client, c);
1141    return Success;
1142badAlloc:
1143    return BadAlloc;
1144}
1145
1146#define TextEltHeader 2
1147#define FontShiftSize 5
1148static ChangeGCVal clearGC[] = { { .ptr = NullPixmap } };
1149#define clearGCmask (GCClipMask)
1150
1151int
1152doPolyText(ClientPtr client, PTclosurePtr c)
1153{
1154    FontPtr pFont = c->pGC->font, oldpFont;
1155    int err = Success, lgerr;	/* err is in X error, not font error, space */
1156    enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state = NEVER_SLEPT;
1157    FontPathElementPtr fpe;
1158    GC *origGC = NULL;
1159    int itemSize = c->reqType == X_PolyText8 ? 1 : 2;
1160
1161    if (client->clientGone)
1162    {
1163	fpe = c->pGC->font->fpe;
1164	(*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1165
1166	if (ClientIsAsleep(client))
1167	{
1168	    /* Client has died, but we cannot bail out right now.  We
1169	       need to clean up after the work we did when going to
1170	       sleep.  Setting the drawable pointer to 0 makes this
1171	       happen without any attempts to render or perform other
1172	       unnecessary activities.  */
1173	    c->pDraw = (DrawablePtr)0;
1174	}
1175	else
1176	{
1177	    err = Success;
1178	    goto bail;
1179	}
1180    }
1181
1182    /* Make sure our drawable hasn't disappeared while we slept. */
1183    if (ClientIsAsleep(client) && c->pDraw)
1184    {
1185	DrawablePtr pDraw;
1186	dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess);
1187	if (c->pDraw != pDraw) {
1188	    /* Our drawable has disappeared.  Treat like client died... ask
1189	       the FPE code to clean up after client and avoid further
1190	       rendering while we clean up after ourself.  */
1191	    fpe = c->pGC->font->fpe;
1192	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1193	    c->pDraw = (DrawablePtr)0;
1194	}
1195    }
1196
1197    client_state = ClientIsAsleep(client) ? SLEEPING : NEVER_SLEPT;
1198
1199    while (c->endReq - c->pElt > TextEltHeader)
1200    {
1201	if (*c->pElt == FontChange)
1202        {
1203	    Font fid;
1204	    if (c->endReq - c->pElt < FontShiftSize)
1205	    {
1206		 err = BadLength;
1207		 goto bail;
1208	    }
1209
1210	    oldpFont = pFont;
1211
1212	    fid =  ((Font)*(c->pElt+4))		/* big-endian */
1213		 | ((Font)*(c->pElt+3)) << 8
1214		 | ((Font)*(c->pElt+2)) << 16
1215		 | ((Font)*(c->pElt+1)) << 24;
1216	    err = dixLookupResourceByType((pointer *)&pFont, fid, RT_FONT,
1217					  client, DixUseAccess);
1218	    if (err != Success)
1219	    {
1220		/* restore pFont for step 4 (described below) */
1221		pFont = oldpFont;
1222
1223		/* If we're in START_SLEEP mode, the following step
1224		   shortens the request...  in the unlikely event that
1225		   the fid somehow becomes valid before we come through
1226		   again to actually execute the polytext, which would
1227		   then mess up our refcounting scheme badly.  */
1228		c->err = err;
1229		c->endReq = c->pElt;
1230
1231		goto bail;
1232	    }
1233
1234	    /* Step 3 (described below) on our new font */
1235	    if (client_state == START_SLEEP)
1236		pFont->refcnt++;
1237	    else
1238	    {
1239		if (pFont != c->pGC->font && c->pDraw)
1240		{
1241		    ChangeGCVal val;
1242		    val.ptr = pFont;
1243		    ChangeGC(NullClient, c->pGC, GCFont, &val);
1244		    ValidateGC(c->pDraw, c->pGC);
1245		}
1246
1247		/* Undo the refcnt++ we performed when going to sleep */
1248		if (client_state == SLEEPING)
1249		    (void)CloseFont(c->pGC->font, (Font)0);
1250	    }
1251	    c->pElt += FontShiftSize;
1252	}
1253	else	/* print a string */
1254	{
1255	    unsigned char *pNextElt;
1256	    pNextElt = c->pElt + TextEltHeader + (*c->pElt) * itemSize;
1257	    if ( pNextElt > c->endReq)
1258	    {
1259		err = BadLength;
1260		goto bail;
1261	    }
1262	    if (client_state == START_SLEEP)
1263	    {
1264		c->pElt = pNextElt;
1265		continue;
1266	    }
1267	    if (c->pDraw)
1268	    {
1269		lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, itemSize,
1270				   c->pElt + TextEltHeader);
1271	    }
1272	    else lgerr = Successful;
1273
1274	    if (lgerr == Suspended)
1275	    {
1276		if (!ClientIsAsleep(client)) {
1277		    int len;
1278		    GC *pGC;
1279		    PTclosurePtr new_closure;
1280
1281    /*  We're putting the client to sleep.  We need to do a few things
1282	to ensure successful and atomic-appearing execution of the
1283	remainder of the request.  First, copy the remainder of the
1284	request into a safe malloc'd area.  Second, create a scratch GC
1285	to use for the remainder of the request.  Third, mark all fonts
1286	referenced in the remainder of the request to prevent their
1287	deallocation.  Fourth, make the original GC look like the
1288	request has completed...  set its font to the final font value
1289	from this request.  These GC manipulations are for the unlikely
1290	(but possible) event that some other client is using the GC.
1291	Steps 3 and 4 are performed by running this procedure through
1292	the remainder of the request in a special no-render mode
1293	indicated by client_state = START_SLEEP.  */
1294
1295		    /* Step 1 */
1296		    /* Allocate a malloc'd closure structure to replace
1297		       the local one we were passed */
1298		    new_closure = malloc(sizeof(PTclosureRec));
1299		    if (!new_closure)
1300		    {
1301			err = BadAlloc;
1302			goto bail;
1303		    }
1304		    *new_closure = *c;
1305
1306		    len = new_closure->endReq - new_closure->pElt;
1307		    new_closure->data = malloc(len);
1308		    if (!new_closure->data)
1309		    {
1310			free(new_closure);
1311			err = BadAlloc;
1312			goto bail;
1313		    }
1314		    memmove(new_closure->data, new_closure->pElt, len);
1315		    new_closure->pElt = new_closure->data;
1316		    new_closure->endReq = new_closure->pElt + len;
1317
1318		    /* Step 2 */
1319
1320		    pGC = GetScratchGC(new_closure->pGC->depth, new_closure->pGC->pScreen);
1321		    if (!pGC)
1322		    {
1323			free(new_closure->data);
1324			free(new_closure);
1325			err = BadAlloc;
1326			goto bail;
1327		    }
1328		    if ((err = CopyGC(new_closure->pGC, pGC, GCFunction |
1329				      GCPlaneMask | GCForeground |
1330				      GCBackground | GCFillStyle |
1331				      GCTile | GCStipple |
1332				      GCTileStipXOrigin |
1333				      GCTileStipYOrigin | GCFont |
1334				      GCSubwindowMode | GCClipXOrigin |
1335				      GCClipYOrigin | GCClipMask)) !=
1336				      Success)
1337		    {
1338			FreeScratchGC(pGC);
1339			free(new_closure->data);
1340			free(new_closure);
1341			err = BadAlloc;
1342			goto bail;
1343		    }
1344		    c = new_closure;
1345		    origGC = c->pGC;
1346		    c->pGC = pGC;
1347		    ValidateGC(c->pDraw, c->pGC);
1348
1349		    ClientSleep(client, (ClientSleepProcPtr)doPolyText, c);
1350
1351		    /* Set up to perform steps 3 and 4 */
1352		    client_state = START_SLEEP;
1353		    continue;	/* on to steps 3 and 4 */
1354		}
1355		else
1356		    goto xinerama_sleep;
1357		return TRUE;
1358	    }
1359	    else if (lgerr != Successful)
1360	    {
1361		err = FontToXError(lgerr);
1362		goto bail;
1363	    }
1364	    if (c->pDraw)
1365	    {
1366		c->xorg += *((INT8 *)(c->pElt + 1));	/* must be signed */
1367		if (c->reqType == X_PolyText8)
1368		    c->xorg = (* c->pGC->ops->PolyText8)(c->pDraw, c->pGC, c->xorg, c->yorg,
1369			*c->pElt, (char *) (c->pElt + TextEltHeader));
1370		else
1371		    c->xorg = (* c->pGC->ops->PolyText16)(c->pDraw, c->pGC, c->xorg, c->yorg,
1372			*c->pElt, (unsigned short *) (c->pElt + TextEltHeader));
1373	    }
1374	    c->pElt = pNextElt;
1375	}
1376    }
1377
1378bail:
1379
1380    if (client_state == START_SLEEP)
1381    {
1382	/* Step 4 */
1383	if (pFont != origGC->font)
1384	{
1385	    ChangeGCVal val;
1386	    val.ptr = pFont;
1387	    ChangeGC(NullClient, origGC, GCFont, &val);
1388	    ValidateGC(c->pDraw, origGC);
1389	}
1390
1391	/* restore pElt pointer for execution of remainder of the request */
1392	c->pElt = c->data;
1393	return TRUE;
1394    }
1395
1396    if (c->err != Success) err = c->err;
1397    if (err != Success && c->client != serverClient) {
1398#ifdef PANORAMIX
1399        if (noPanoramiXExtension || !c->pGC->pScreen->myNum)
1400#endif
1401	    SendErrorToClient(c->client, c->reqType, 0, 0, err);
1402    }
1403    if (ClientIsAsleep(client))
1404    {
1405	ClientWakeup(c->client);
1406xinerama_sleep:
1407	ChangeGC(NullClient, c->pGC, clearGCmask, clearGC);
1408
1409	/* Unreference the font from the scratch GC */
1410	CloseFont(c->pGC->font, (Font)0);
1411	c->pGC->font = NullFont;
1412
1413	FreeScratchGC(c->pGC);
1414	free(c->data);
1415	free(c);
1416    }
1417    return TRUE;
1418}
1419
1420int
1421PolyText(ClientPtr client, DrawablePtr pDraw, GC *pGC, unsigned char *pElt,
1422         unsigned char *endReq, int xorg, int yorg, int reqType, XID did)
1423{
1424    PTclosureRec local_closure;
1425
1426    local_closure.pElt = pElt;
1427    local_closure.endReq = endReq;
1428    local_closure.client = client;
1429    local_closure.pDraw = pDraw;
1430    local_closure.xorg = xorg;
1431    local_closure.yorg = yorg;
1432    local_closure.reqType = reqType;
1433    local_closure.pGC = pGC;
1434    local_closure.did = did;
1435    local_closure.err = Success;
1436
1437    (void) doPolyText(client, &local_closure);
1438    return Success;
1439}
1440
1441
1442#undef TextEltHeader
1443#undef FontShiftSize
1444
1445int
1446doImageText(ClientPtr client, ITclosurePtr c)
1447{
1448    int err = Success, lgerr;	/* err is in X error, not font error, space */
1449    FontPathElementPtr fpe;
1450    int itemSize = c->reqType == X_ImageText8 ? 1 : 2;
1451
1452    if (client->clientGone)
1453    {
1454	fpe = c->pGC->font->fpe;
1455	(*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1456	err = Success;
1457	goto bail;
1458    }
1459
1460    /* Make sure our drawable hasn't disappeared while we slept. */
1461    if (ClientIsAsleep(client) && c->pDraw)
1462    {
1463	DrawablePtr pDraw;
1464	dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess);
1465	if (c->pDraw != pDraw) {
1466	    /* Our drawable has disappeared.  Treat like client died... ask
1467	       the FPE code to clean up after client. */
1468	    fpe = c->pGC->font->fpe;
1469	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1470	    err = Success;
1471	    goto bail;
1472	}
1473    }
1474
1475    lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, itemSize, c->data);
1476    if (lgerr == Suspended)
1477    {
1478        if (!ClientIsAsleep(client)) {
1479	    GC *pGC;
1480	    unsigned char *data;
1481	    ITclosurePtr new_closure;
1482
1483	    /* We're putting the client to sleep.  We need to
1484	       save some state.  Similar problem to that handled
1485	       in doPolyText, but much simpler because the
1486	       request structure is much simpler. */
1487
1488	    new_closure = malloc(sizeof(ITclosureRec));
1489	    if (!new_closure)
1490	    {
1491		err = BadAlloc;
1492		goto bail;
1493	    }
1494	    *new_closure = *c;
1495	    c = new_closure;
1496
1497	    data = malloc(c->nChars * itemSize);
1498	    if (!data)
1499	    {
1500		free(c);
1501		err = BadAlloc;
1502		goto bail;
1503	    }
1504	    memmove(data, c->data, c->nChars * itemSize);
1505	    c->data = data;
1506
1507	    pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
1508	    if (!pGC)
1509	    {
1510		free(c->data);
1511		free(c);
1512		err = BadAlloc;
1513		goto bail;
1514	    }
1515	    if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask |
1516			      GCForeground | GCBackground | GCFillStyle |
1517			      GCTile | GCStipple | GCTileStipXOrigin |
1518			      GCTileStipYOrigin | GCFont |
1519			      GCSubwindowMode | GCClipXOrigin |
1520			      GCClipYOrigin | GCClipMask)) != Success)
1521	    {
1522		FreeScratchGC(pGC);
1523		free(c->data);
1524		free(c);
1525		err = BadAlloc;
1526		goto bail;
1527	    }
1528	    c->pGC = pGC;
1529	    ValidateGC(c->pDraw, c->pGC);
1530
1531            ClientSleep(client, (ClientSleepProcPtr)doImageText, c);
1532        }
1533	else
1534	    goto xinerama_sleep;
1535        return TRUE;
1536    }
1537    else if (lgerr != Successful)
1538    {
1539        err = FontToXError(lgerr);
1540        goto bail;
1541    }
1542    if (c->pDraw)
1543    {
1544	if (c->reqType == X_ImageText8)
1545	    (* c->pGC->ops->ImageText8)(c->pDraw, c->pGC, c->xorg, c->yorg,
1546		c->nChars, (char *) c->data);
1547	else
1548	    (* c->pGC->ops->ImageText16)(c->pDraw, c->pGC, c->xorg, c->yorg,
1549		c->nChars, (unsigned short *) c->data);
1550    }
1551
1552bail:
1553
1554    if (err != Success && c->client != serverClient) {
1555	SendErrorToClient(c->client, c->reqType, 0, 0, err);
1556    }
1557    if (ClientIsAsleep(client))
1558    {
1559	ClientWakeup(c->client);
1560xinerama_sleep:
1561	ChangeGC(NullClient, c->pGC, clearGCmask, clearGC);
1562
1563	/* Unreference the font from the scratch GC */
1564	CloseFont(c->pGC->font, (Font)0);
1565	c->pGC->font = NullFont;
1566
1567	FreeScratchGC(c->pGC);
1568	free(c->data);
1569	free(c);
1570    }
1571    return TRUE;
1572}
1573
1574int
1575ImageText(ClientPtr client, DrawablePtr pDraw, GC *pGC, int nChars,
1576          unsigned char *data, int xorg, int yorg, int reqType, XID did)
1577{
1578    ITclosureRec local_closure;
1579
1580    local_closure.client = client;
1581    local_closure.pDraw = pDraw;
1582    local_closure.pGC = pGC;
1583    local_closure.nChars = nChars;
1584    local_closure.data = data;
1585    local_closure.xorg = xorg;
1586    local_closure.yorg = yorg;
1587    local_closure.reqType = reqType;
1588    local_closure.did = did;
1589
1590    (void) doImageText(client, &local_closure);
1591    return Success;
1592}
1593
1594
1595/* does the necessary magic to figure out the fpe type */
1596static int
1597DetermineFPEType(char *pathname)
1598{
1599    int         i;
1600
1601    for (i = 0; i < num_fpe_types; i++) {
1602	if ((*fpe_functions[i].name_check) (pathname))
1603	    return i;
1604    }
1605    return -1;
1606}
1607
1608
1609static void
1610FreeFontPath(FontPathElementPtr *list, int n, Bool force)
1611{
1612    int         i;
1613
1614    for (i = 0; i < n; i++) {
1615	if (force) {
1616	    /* Sanity check that all refcounts will be 0 by the time
1617	       we get to the end of the list. */
1618	    int found = 1;	/* the first reference is us */
1619	    int j;
1620	    for (j = i+1; j < n; j++) {
1621		if (list[j] == list[i])
1622		    found++;
1623	    }
1624	    if (list[i]->refcount != found) {
1625		list[i]->refcount = found; /* ensure it will get freed */
1626	    }
1627	}
1628	FreeFPE(list[i]);
1629    }
1630    free(list);
1631}
1632
1633static FontPathElementPtr
1634find_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len)
1635{
1636    FontPathElementPtr fpe;
1637    int         i;
1638
1639    for (i = 0; i < num; i++) {
1640	fpe = list[i];
1641	if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0)
1642	    return fpe;
1643    }
1644    return (FontPathElementPtr) 0;
1645}
1646
1647
1648static int
1649SetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist)
1650{
1651    int         i, err = 0;
1652    int         valid_paths = 0;
1653    unsigned int len;
1654    unsigned char *cp = paths;
1655    FontPathElementPtr fpe = NULL, *fplist;
1656
1657    fplist = malloc(sizeof(FontPathElementPtr) * npaths);
1658    if (!fplist) {
1659	*bad = 0;
1660	return BadAlloc;
1661    }
1662    for (i = 0; i < num_fpe_types; i++) {
1663	if (fpe_functions[i].set_path_hook)
1664	    (*fpe_functions[i].set_path_hook) ();
1665    }
1666    for (i = 0; i < npaths; i++)
1667    {
1668	len = (unsigned int) (*cp++);
1669
1670	if (len == 0)
1671	{
1672	    if (persist)
1673		ErrorF("[dix] Removing empty element from the valid list of fontpaths\n");
1674	    err = BadValue;
1675	}
1676	else
1677	{
1678	    /* if it's already in our active list, just reset it */
1679	    /*
1680	     * note that this can miss FPE's in limbo -- may be worth catching
1681	     * them, though it'd muck up refcounting
1682	     */
1683	    fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
1684	    if (fpe)
1685	    {
1686		err = (*fpe_functions[fpe->type].reset_fpe) (fpe);
1687		if (err == Successful)
1688		{
1689		    UseFPE(fpe);/* since it'll be decref'd later when freed
1690				 * from the old list */
1691		}
1692		else
1693		    fpe = 0;
1694	    }
1695	    /* if error or can't do it, act like it's a new one */
1696	    if (!fpe)
1697	    {
1698		fpe = malloc(sizeof(FontPathElementRec));
1699		if (!fpe)
1700		{
1701		    err = BadAlloc;
1702		    goto bail;
1703		}
1704		fpe->name = malloc(len + 1);
1705		if (!fpe->name)
1706		{
1707		    free(fpe);
1708		    err = BadAlloc;
1709		    goto bail;
1710		}
1711		fpe->refcount = 1;
1712
1713		strncpy(fpe->name, (char *) cp, (int) len);
1714		fpe->name[len] = '\0';
1715		fpe->name_length = len;
1716		fpe->type = DetermineFPEType(fpe->name);
1717		if (fpe->type == -1)
1718		    err = BadValue;
1719		else
1720		    err = (*fpe_functions[fpe->type].init_fpe) (fpe);
1721		if (err != Successful)
1722		{
1723		    if (persist)
1724		    {
1725			ErrorF("[dix] Could not init font path element %s, removing from list!\n",
1726			       fpe->name);
1727		    }
1728		    free(fpe->name);
1729		    free(fpe);
1730		}
1731	    }
1732	}
1733	if (err != Successful)
1734	{
1735	    if (!persist)
1736		goto bail;
1737	}
1738	else
1739	{
1740	    fplist[valid_paths++] = fpe;
1741	}
1742	cp += len;
1743    }
1744
1745    FreeFontPath(font_path_elements, num_fpes, FALSE);
1746    font_path_elements = fplist;
1747    if (patternCache)
1748	EmptyFontPatternCache(patternCache);
1749    num_fpes = valid_paths;
1750
1751    return Success;
1752bail:
1753    *bad = i;
1754    while (--valid_paths >= 0)
1755	FreeFPE(fplist[valid_paths]);
1756    free(fplist);
1757    return FontToXError(err);
1758}
1759
1760int
1761SetFontPath(ClientPtr client, int npaths, unsigned char *paths)
1762{
1763    int err = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess);
1764    if (err != Success)
1765	return err;
1766
1767    if (npaths == 0) {
1768	if (SetDefaultFontPath(defaultFontPath) != Success)
1769	    return BadValue;
1770    } else {
1771	int bad;
1772	err = SetFontPathElements(npaths, paths, &bad, FALSE);
1773	client->errorValue = bad;
1774    }
1775    return err;
1776}
1777
1778int
1779SetDefaultFontPath(char *path)
1780{
1781    char       *temp_path,
1782               *start,
1783               *end;
1784    unsigned char *cp,
1785               *pp,
1786               *nump,
1787               *newpath;
1788    int         num = 1,
1789                len,
1790                err,
1791                size = 0,
1792                bad;
1793
1794    /* ensure temp_path contains "built-ins" */
1795    start = path;
1796    while (1) {
1797	start = strstr(start, "built-ins");
1798	if (start == NULL)
1799	    break;
1800	end = start + strlen("built-ins");
1801	if ((start == path || start[-1] == ',') && (!*end || *end == ','))
1802	    break;
1803	start = end;
1804    }
1805    if (!start) {
1806	if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "")
1807	    == -1)
1808	    temp_path = NULL;
1809    } else {
1810	temp_path = strdup(path);
1811    }
1812    if (!temp_path)
1813        return BadAlloc;
1814
1815    /* get enough for string, plus values -- use up commas */
1816    len = strlen(temp_path) + 1;
1817    nump = cp = newpath = malloc(len);
1818    if (!newpath) {
1819	free(temp_path);
1820	return BadAlloc;
1821    }
1822    pp = (unsigned char *) temp_path;
1823    cp++;
1824    while (*pp) {
1825	if (*pp == ',') {
1826	    *nump = (unsigned char) size;
1827	    nump = cp++;
1828	    pp++;
1829	    num++;
1830	    size = 0;
1831	} else {
1832	    *cp++ = *pp++;
1833	    size++;
1834	}
1835    }
1836    *nump = (unsigned char) size;
1837
1838    err = SetFontPathElements(num, newpath, &bad, TRUE);
1839
1840    free(newpath);
1841    free(temp_path);
1842
1843    return err;
1844}
1845
1846int
1847GetFontPath(ClientPtr client, int *count, int *length, unsigned char **result)
1848{
1849    int			i;
1850    unsigned char       *c;
1851    int			len;
1852    FontPathElementPtr	fpe;
1853
1854    i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
1855    if (i != Success)
1856	return i;
1857
1858    len = 0;
1859    for (i = 0; i < num_fpes; i++) {
1860	fpe = font_path_elements[i];
1861	len += fpe->name_length + 1;
1862    }
1863    font_path_string = (unsigned char *) realloc(font_path_string, len);
1864    if (!font_path_string)
1865	return BadAlloc;
1866
1867    c = font_path_string;
1868    *length = 0;
1869    for (i = 0; i < num_fpes; i++) {
1870	fpe = font_path_elements[i];
1871	*c = fpe->name_length;
1872	*length += *c++;
1873	memmove(c, fpe->name, fpe->name_length);
1874	c += fpe->name_length;
1875    }
1876    *count = num_fpes;
1877    *result = font_path_string;
1878    return Success;
1879}
1880
1881void
1882DeleteClientFontStuff(ClientPtr client)
1883{
1884    int			i;
1885    FontPathElementPtr	fpe;
1886
1887    for (i = 0; i < num_fpes; i++)
1888    {
1889	fpe = font_path_elements[i];
1890	if (fpe_functions[fpe->type].client_died)
1891	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1892    }
1893}
1894
1895void
1896InitFonts (void)
1897{
1898    patternCache = MakeFontPatternCache();
1899
1900    register_fpe_functions();
1901}
1902
1903int
1904GetDefaultPointSize (void)
1905{
1906    return 120;
1907}
1908
1909
1910FontResolutionPtr
1911GetClientResolutions (int *num)
1912{
1913    static struct _FontResolution res;
1914    ScreenPtr   pScreen;
1915
1916    pScreen = screenInfo.screens[0];
1917    res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth;
1918    /*
1919     * XXX - we'll want this as long as bitmap instances are prevalent
1920     so that we can match them from scalable fonts
1921     */
1922    if (res.x_resolution < 88)
1923	res.x_resolution = 75;
1924    else
1925	res.x_resolution = 100;
1926    res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight;
1927    if (res.y_resolution < 88)
1928	res.y_resolution = 75;
1929    else
1930	res.y_resolution = 100;
1931    res.point_size = 120;
1932    *num = 1;
1933    return &res;
1934}
1935
1936/*
1937 * returns the type index of the new fpe
1938 *
1939 * should be called (only once!) by each type of fpe when initialized
1940 */
1941
1942int
1943RegisterFPEFunctions(NameCheckFunc name_func,
1944		     InitFpeFunc init_func,
1945		     FreeFpeFunc free_func,
1946		     ResetFpeFunc reset_func,
1947		     OpenFontFunc open_func,
1948		     CloseFontFunc close_func,
1949		     ListFontsFunc list_func,
1950		     StartLfwiFunc start_lfwi_func,
1951		     NextLfwiFunc next_lfwi_func,
1952		     WakeupFpeFunc wakeup_func,
1953		     ClientDiedFunc client_died,
1954		     LoadGlyphsFunc load_glyphs,
1955		     StartLaFunc start_list_alias_func,
1956		     NextLaFunc next_list_alias_func,
1957		     SetPathFunc set_path_func)
1958{
1959    FPEFunctions *new;
1960
1961    /* grow the list */
1962    new = (FPEFunctions *) realloc(fpe_functions,
1963				 (num_fpe_types + 1) * sizeof(FPEFunctions));
1964    if (!new)
1965	return -1;
1966    fpe_functions = new;
1967
1968    fpe_functions[num_fpe_types].name_check = name_func;
1969    fpe_functions[num_fpe_types].open_font = open_func;
1970    fpe_functions[num_fpe_types].close_font = close_func;
1971    fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func;
1972    fpe_functions[num_fpe_types].list_fonts = list_func;
1973    fpe_functions[num_fpe_types].start_list_fonts_with_info =
1974	start_lfwi_func;
1975    fpe_functions[num_fpe_types].list_next_font_with_info =
1976	next_lfwi_func;
1977    fpe_functions[num_fpe_types].init_fpe = init_func;
1978    fpe_functions[num_fpe_types].free_fpe = free_func;
1979    fpe_functions[num_fpe_types].reset_fpe = reset_func;
1980    fpe_functions[num_fpe_types].client_died = client_died;
1981    fpe_functions[num_fpe_types].load_glyphs = load_glyphs;
1982    fpe_functions[num_fpe_types].start_list_fonts_and_aliases =
1983	start_list_alias_func;
1984    fpe_functions[num_fpe_types].list_next_font_or_alias =
1985	next_list_alias_func;
1986    fpe_functions[num_fpe_types].set_path_hook = set_path_func;
1987
1988    return num_fpe_types++;
1989}
1990
1991void
1992FreeFonts(void)
1993{
1994    if (patternCache) {
1995	FreeFontPatternCache(patternCache);
1996	patternCache = 0;
1997    }
1998    FreeFontPath(font_path_elements, num_fpes, TRUE);
1999    font_path_elements = 0;
2000    num_fpes = 0;
2001    free(fpe_functions);
2002    num_fpe_types = 0;
2003    fpe_functions = (FPEFunctions *) 0;
2004}
2005
2006/* convenience functions for FS interface */
2007
2008FontPtr
2009find_old_font(XID id)
2010{
2011    pointer pFont;
2012    dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess);
2013    return (FontPtr)pFont;
2014}
2015
2016Font
2017GetNewFontClientID(void)
2018{
2019    return FakeClientID(0);
2020}
2021
2022int
2023StoreFontClientFont(FontPtr pfont, Font id)
2024{
2025    return AddResource(id, RT_NONE, (pointer) pfont);
2026}
2027
2028void
2029DeleteFontClientID(Font id)
2030{
2031    FreeResource(id, RT_NONE);
2032}
2033
2034int
2035client_auth_generation(ClientPtr client)
2036{
2037    return 0;
2038}
2039
2040static int  fs_handlers_installed = 0;
2041static unsigned int last_server_gen;
2042
2043int
2044init_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler)
2045{
2046    /* if server has reset, make sure the b&w handlers are reinstalled */
2047    if (last_server_gen < serverGeneration) {
2048	last_server_gen = serverGeneration;
2049	fs_handlers_installed = 0;
2050    }
2051    if (fs_handlers_installed == 0) {
2052	if (!RegisterBlockAndWakeupHandlers(block_handler,
2053					    FontWakeup, (pointer) 0))
2054	    return AllocError;
2055	fs_handlers_installed++;
2056    }
2057    QueueFontWakeup(fpe);
2058    return Successful;
2059}
2060
2061void
2062remove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, Bool all)
2063{
2064    if (all) {
2065	/* remove the handlers if no one else is using them */
2066	if (--fs_handlers_installed == 0) {
2067	    RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
2068					 (pointer) 0);
2069	}
2070    }
2071    RemoveFontWakeup(fpe);
2072}
2073