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            ITclosurePtr old_closure;
1483
1484	    /* We're putting the client to sleep.  We need to
1485	       save some state.  Similar problem to that handled
1486	       in doPolyText, but much simpler because the
1487	       request structure is much simpler. */
1488
1489	    new_closure = malloc(sizeof(ITclosureRec));
1490	    if (!new_closure)
1491	    {
1492		err = BadAlloc;
1493		goto bail;
1494	    }
1495            old_closure = c;
1496	    *new_closure = *c;
1497	    c = new_closure;
1498
1499	    data = malloc(c->nChars * itemSize);
1500	    if (!data)
1501	    {
1502		free(c);
1503                c = old_closure;
1504		err = BadAlloc;
1505		goto bail;
1506	    }
1507	    memmove(data, c->data, c->nChars * itemSize);
1508	    c->data = data;
1509
1510	    pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
1511	    if (!pGC)
1512	    {
1513		free(c->data);
1514		free(c);
1515                c = old_closure;
1516		err = BadAlloc;
1517		goto bail;
1518	    }
1519	    if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask |
1520			      GCForeground | GCBackground | GCFillStyle |
1521			      GCTile | GCStipple | GCTileStipXOrigin |
1522			      GCTileStipYOrigin | GCFont |
1523			      GCSubwindowMode | GCClipXOrigin |
1524			      GCClipYOrigin | GCClipMask)) != Success)
1525	    {
1526		FreeScratchGC(pGC);
1527		free(c->data);
1528		free(c);
1529                c = old_closure;
1530		err = BadAlloc;
1531		goto bail;
1532	    }
1533	    c->pGC = pGC;
1534	    ValidateGC(c->pDraw, c->pGC);
1535
1536            ClientSleep(client, (ClientSleepProcPtr)doImageText, c);
1537        }
1538	else
1539	    goto xinerama_sleep;
1540        return TRUE;
1541    }
1542    else if (lgerr != Successful)
1543    {
1544        err = FontToXError(lgerr);
1545        goto bail;
1546    }
1547    if (c->pDraw)
1548    {
1549	if (c->reqType == X_ImageText8)
1550	    (* c->pGC->ops->ImageText8)(c->pDraw, c->pGC, c->xorg, c->yorg,
1551		c->nChars, (char *) c->data);
1552	else
1553	    (* c->pGC->ops->ImageText16)(c->pDraw, c->pGC, c->xorg, c->yorg,
1554		c->nChars, (unsigned short *) c->data);
1555    }
1556
1557bail:
1558
1559    if (err != Success && c->client != serverClient) {
1560	SendErrorToClient(c->client, c->reqType, 0, 0, err);
1561    }
1562    if (ClientIsAsleep(client))
1563    {
1564	ClientWakeup(c->client);
1565xinerama_sleep:
1566	ChangeGC(NullClient, c->pGC, clearGCmask, clearGC);
1567
1568	/* Unreference the font from the scratch GC */
1569	CloseFont(c->pGC->font, (Font)0);
1570	c->pGC->font = NullFont;
1571
1572	FreeScratchGC(c->pGC);
1573	free(c->data);
1574	free(c);
1575    }
1576    return TRUE;
1577}
1578
1579int
1580ImageText(ClientPtr client, DrawablePtr pDraw, GC *pGC, int nChars,
1581          unsigned char *data, int xorg, int yorg, int reqType, XID did)
1582{
1583    ITclosureRec local_closure;
1584
1585    local_closure.client = client;
1586    local_closure.pDraw = pDraw;
1587    local_closure.pGC = pGC;
1588    local_closure.nChars = nChars;
1589    local_closure.data = data;
1590    local_closure.xorg = xorg;
1591    local_closure.yorg = yorg;
1592    local_closure.reqType = reqType;
1593    local_closure.did = did;
1594
1595    (void) doImageText(client, &local_closure);
1596    return Success;
1597}
1598
1599
1600/* does the necessary magic to figure out the fpe type */
1601static int
1602DetermineFPEType(char *pathname)
1603{
1604    int         i;
1605
1606    for (i = 0; i < num_fpe_types; i++) {
1607	if ((*fpe_functions[i].name_check) (pathname))
1608	    return i;
1609    }
1610    return -1;
1611}
1612
1613
1614static void
1615FreeFontPath(FontPathElementPtr *list, int n, Bool force)
1616{
1617    int         i;
1618
1619    for (i = 0; i < n; i++) {
1620	if (force) {
1621	    /* Sanity check that all refcounts will be 0 by the time
1622	       we get to the end of the list. */
1623	    int found = 1;	/* the first reference is us */
1624	    int j;
1625	    for (j = i+1; j < n; j++) {
1626		if (list[j] == list[i])
1627		    found++;
1628	    }
1629	    if (list[i]->refcount != found) {
1630		list[i]->refcount = found; /* ensure it will get freed */
1631	    }
1632	}
1633	FreeFPE(list[i]);
1634    }
1635    free(list);
1636}
1637
1638static FontPathElementPtr
1639find_existing_fpe(FontPathElementPtr *list, int num, unsigned char *name, int len)
1640{
1641    FontPathElementPtr fpe;
1642    int         i;
1643
1644    for (i = 0; i < num; i++) {
1645	fpe = list[i];
1646	if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0)
1647	    return fpe;
1648    }
1649    return (FontPathElementPtr) 0;
1650}
1651
1652
1653static int
1654SetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist)
1655{
1656    int         i, err = 0;
1657    int         valid_paths = 0;
1658    unsigned int len;
1659    unsigned char *cp = paths;
1660    FontPathElementPtr fpe = NULL, *fplist;
1661
1662    fplist = malloc(sizeof(FontPathElementPtr) * npaths);
1663    if (!fplist) {
1664	*bad = 0;
1665	return BadAlloc;
1666    }
1667    for (i = 0; i < num_fpe_types; i++) {
1668	if (fpe_functions[i].set_path_hook)
1669	    (*fpe_functions[i].set_path_hook) ();
1670    }
1671    for (i = 0; i < npaths; i++)
1672    {
1673	len = (unsigned int) (*cp++);
1674
1675	if (len == 0)
1676	{
1677	    if (persist)
1678		ErrorF("[dix] Removing empty element from the valid list of fontpaths\n");
1679	    err = BadValue;
1680	}
1681	else
1682	{
1683	    /* if it's already in our active list, just reset it */
1684	    /*
1685	     * note that this can miss FPE's in limbo -- may be worth catching
1686	     * them, though it'd muck up refcounting
1687	     */
1688	    fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
1689	    if (fpe)
1690	    {
1691		err = (*fpe_functions[fpe->type].reset_fpe) (fpe);
1692		if (err == Successful)
1693		{
1694		    UseFPE(fpe);/* since it'll be decref'd later when freed
1695				 * from the old list */
1696		}
1697		else
1698		    fpe = 0;
1699	    }
1700	    /* if error or can't do it, act like it's a new one */
1701	    if (!fpe)
1702	    {
1703		fpe = malloc(sizeof(FontPathElementRec));
1704		if (!fpe)
1705		{
1706		    err = BadAlloc;
1707		    goto bail;
1708		}
1709		fpe->name = malloc(len + 1);
1710		if (!fpe->name)
1711		{
1712		    free(fpe);
1713		    err = BadAlloc;
1714		    goto bail;
1715		}
1716		fpe->refcount = 1;
1717
1718		strncpy(fpe->name, (char *) cp, (int) len);
1719		fpe->name[len] = '\0';
1720		fpe->name_length = len;
1721		fpe->type = DetermineFPEType(fpe->name);
1722		if (fpe->type == -1)
1723		    err = BadValue;
1724		else
1725		    err = (*fpe_functions[fpe->type].init_fpe) (fpe);
1726		if (err != Successful)
1727		{
1728		    if (persist)
1729		    {
1730			ErrorF("[dix] Could not init font path element %s, removing from list!\n",
1731			       fpe->name);
1732		    }
1733		    free(fpe->name);
1734		    free(fpe);
1735		}
1736	    }
1737	}
1738	if (err != Successful)
1739	{
1740	    if (!persist)
1741		goto bail;
1742	}
1743	else
1744	{
1745	    fplist[valid_paths++] = fpe;
1746	}
1747	cp += len;
1748    }
1749
1750    FreeFontPath(font_path_elements, num_fpes, FALSE);
1751    font_path_elements = fplist;
1752    if (patternCache)
1753	EmptyFontPatternCache(patternCache);
1754    num_fpes = valid_paths;
1755
1756    return Success;
1757bail:
1758    *bad = i;
1759    while (--valid_paths >= 0)
1760	FreeFPE(fplist[valid_paths]);
1761    free(fplist);
1762    return FontToXError(err);
1763}
1764
1765int
1766SetFontPath(ClientPtr client, int npaths, unsigned char *paths)
1767{
1768    int err = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess);
1769    if (err != Success)
1770	return err;
1771
1772    if (npaths == 0) {
1773	if (SetDefaultFontPath(defaultFontPath) != Success)
1774	    return BadValue;
1775    } else {
1776	int bad;
1777	err = SetFontPathElements(npaths, paths, &bad, FALSE);
1778	client->errorValue = bad;
1779    }
1780    return err;
1781}
1782
1783int
1784SetDefaultFontPath(char *path)
1785{
1786    char       *temp_path,
1787               *start,
1788               *end;
1789    unsigned char *cp,
1790               *pp,
1791               *nump,
1792               *newpath;
1793    int         num = 1,
1794                len,
1795                err,
1796                size = 0,
1797                bad;
1798
1799    /* ensure temp_path contains "built-ins" */
1800    start = path;
1801    while (1) {
1802	start = strstr(start, "built-ins");
1803	if (start == NULL)
1804	    break;
1805	end = start + strlen("built-ins");
1806	if ((start == path || start[-1] == ',') && (!*end || *end == ','))
1807	    break;
1808	start = end;
1809    }
1810    if (!start) {
1811	if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "")
1812	    == -1)
1813	    temp_path = NULL;
1814    } else {
1815	temp_path = strdup(path);
1816    }
1817    if (!temp_path)
1818        return BadAlloc;
1819
1820    /* get enough for string, plus values -- use up commas */
1821    len = strlen(temp_path) + 1;
1822    nump = cp = newpath = malloc(len);
1823    if (!newpath) {
1824	free(temp_path);
1825	return BadAlloc;
1826    }
1827    pp = (unsigned char *) temp_path;
1828    cp++;
1829    while (*pp) {
1830	if (*pp == ',') {
1831	    *nump = (unsigned char) size;
1832	    nump = cp++;
1833	    pp++;
1834	    num++;
1835	    size = 0;
1836	} else {
1837	    *cp++ = *pp++;
1838	    size++;
1839	}
1840    }
1841    *nump = (unsigned char) size;
1842
1843    err = SetFontPathElements(num, newpath, &bad, TRUE);
1844
1845    free(newpath);
1846    free(temp_path);
1847
1848    return err;
1849}
1850
1851int
1852GetFontPath(ClientPtr client, int *count, int *length, unsigned char **result)
1853{
1854    int			i;
1855    unsigned char       *c;
1856    int			len;
1857    FontPathElementPtr	fpe;
1858
1859    i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
1860    if (i != Success)
1861	return i;
1862
1863    len = 0;
1864    for (i = 0; i < num_fpes; i++) {
1865	fpe = font_path_elements[i];
1866	len += fpe->name_length + 1;
1867    }
1868    font_path_string = (unsigned char *) realloc(font_path_string, len);
1869    if (!font_path_string)
1870	return BadAlloc;
1871
1872    c = font_path_string;
1873    *length = 0;
1874    for (i = 0; i < num_fpes; i++) {
1875	fpe = font_path_elements[i];
1876	*c = fpe->name_length;
1877	*length += *c++;
1878	memmove(c, fpe->name, fpe->name_length);
1879	c += fpe->name_length;
1880    }
1881    *count = num_fpes;
1882    *result = font_path_string;
1883    return Success;
1884}
1885
1886void
1887DeleteClientFontStuff(ClientPtr client)
1888{
1889    int			i;
1890    FontPathElementPtr	fpe;
1891
1892    for (i = 0; i < num_fpes; i++)
1893    {
1894	fpe = font_path_elements[i];
1895	if (fpe_functions[fpe->type].client_died)
1896	    (*fpe_functions[fpe->type].client_died) ((pointer) client, fpe);
1897    }
1898}
1899
1900void
1901InitFonts (void)
1902{
1903    patternCache = MakeFontPatternCache();
1904
1905    register_fpe_functions();
1906}
1907
1908int
1909GetDefaultPointSize (void)
1910{
1911    return 120;
1912}
1913
1914
1915FontResolutionPtr
1916GetClientResolutions (int *num)
1917{
1918    static struct _FontResolution res;
1919    ScreenPtr   pScreen;
1920
1921    pScreen = screenInfo.screens[0];
1922    res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth;
1923    /*
1924     * XXX - we'll want this as long as bitmap instances are prevalent
1925     so that we can match them from scalable fonts
1926     */
1927    if (res.x_resolution < 88)
1928	res.x_resolution = 75;
1929    else
1930	res.x_resolution = 100;
1931    res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight;
1932    if (res.y_resolution < 88)
1933	res.y_resolution = 75;
1934    else
1935	res.y_resolution = 100;
1936    res.point_size = 120;
1937    *num = 1;
1938    return &res;
1939}
1940
1941/*
1942 * returns the type index of the new fpe
1943 *
1944 * should be called (only once!) by each type of fpe when initialized
1945 */
1946
1947int
1948RegisterFPEFunctions(NameCheckFunc name_func,
1949		     InitFpeFunc init_func,
1950		     FreeFpeFunc free_func,
1951		     ResetFpeFunc reset_func,
1952		     OpenFontFunc open_func,
1953		     CloseFontFunc close_func,
1954		     ListFontsFunc list_func,
1955		     StartLfwiFunc start_lfwi_func,
1956		     NextLfwiFunc next_lfwi_func,
1957		     WakeupFpeFunc wakeup_func,
1958		     ClientDiedFunc client_died,
1959		     LoadGlyphsFunc load_glyphs,
1960		     StartLaFunc start_list_alias_func,
1961		     NextLaFunc next_list_alias_func,
1962		     SetPathFunc set_path_func)
1963{
1964    FPEFunctions *new;
1965
1966    /* grow the list */
1967    new = (FPEFunctions *) realloc(fpe_functions,
1968				 (num_fpe_types + 1) * sizeof(FPEFunctions));
1969    if (!new)
1970	return -1;
1971    fpe_functions = new;
1972
1973    fpe_functions[num_fpe_types].name_check = name_func;
1974    fpe_functions[num_fpe_types].open_font = open_func;
1975    fpe_functions[num_fpe_types].close_font = close_func;
1976    fpe_functions[num_fpe_types].wakeup_fpe = wakeup_func;
1977    fpe_functions[num_fpe_types].list_fonts = list_func;
1978    fpe_functions[num_fpe_types].start_list_fonts_with_info =
1979	start_lfwi_func;
1980    fpe_functions[num_fpe_types].list_next_font_with_info =
1981	next_lfwi_func;
1982    fpe_functions[num_fpe_types].init_fpe = init_func;
1983    fpe_functions[num_fpe_types].free_fpe = free_func;
1984    fpe_functions[num_fpe_types].reset_fpe = reset_func;
1985    fpe_functions[num_fpe_types].client_died = client_died;
1986    fpe_functions[num_fpe_types].load_glyphs = load_glyphs;
1987    fpe_functions[num_fpe_types].start_list_fonts_and_aliases =
1988	start_list_alias_func;
1989    fpe_functions[num_fpe_types].list_next_font_or_alias =
1990	next_list_alias_func;
1991    fpe_functions[num_fpe_types].set_path_hook = set_path_func;
1992
1993    return num_fpe_types++;
1994}
1995
1996void
1997FreeFonts(void)
1998{
1999    if (patternCache) {
2000	FreeFontPatternCache(patternCache);
2001	patternCache = 0;
2002    }
2003    FreeFontPath(font_path_elements, num_fpes, TRUE);
2004    font_path_elements = 0;
2005    num_fpes = 0;
2006    free(fpe_functions);
2007    num_fpe_types = 0;
2008    fpe_functions = (FPEFunctions *) 0;
2009}
2010
2011/* convenience functions for FS interface */
2012
2013FontPtr
2014find_old_font(XID id)
2015{
2016    pointer pFont;
2017    dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess);
2018    return (FontPtr)pFont;
2019}
2020
2021Font
2022GetNewFontClientID(void)
2023{
2024    return FakeClientID(0);
2025}
2026
2027int
2028StoreFontClientFont(FontPtr pfont, Font id)
2029{
2030    return AddResource(id, RT_NONE, (pointer) pfont);
2031}
2032
2033void
2034DeleteFontClientID(Font id)
2035{
2036    FreeResource(id, RT_NONE);
2037}
2038
2039int
2040client_auth_generation(ClientPtr client)
2041{
2042    return 0;
2043}
2044
2045static int  fs_handlers_installed = 0;
2046static unsigned int last_server_gen;
2047
2048int
2049init_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler)
2050{
2051    /* if server has reset, make sure the b&w handlers are reinstalled */
2052    if (last_server_gen < serverGeneration) {
2053	last_server_gen = serverGeneration;
2054	fs_handlers_installed = 0;
2055    }
2056    if (fs_handlers_installed == 0) {
2057	if (!RegisterBlockAndWakeupHandlers(block_handler,
2058					    FontWakeup, (pointer) 0))
2059	    return AllocError;
2060	fs_handlers_installed++;
2061    }
2062    QueueFontWakeup(fpe);
2063    return Successful;
2064}
2065
2066void
2067remove_fs_handlers(FontPathElementPtr fpe, BlockHandlerProcPtr block_handler, Bool all)
2068{
2069    if (all) {
2070	/* remove the handlers if no one else is using them */
2071	if (--fs_handlers_installed == 0) {
2072	    RemoveBlockAndWakeupHandlers(block_handler, FontWakeup,
2073					 (pointer) 0);
2074	}
2075    }
2076    RemoveFontWakeup(fpe);
2077}
2078