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