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