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