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