1/************************************************************************
2Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
3
4                        All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of Digital not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22************************************************************************/
23/* The panoramix components contained the following notice */
24/*
25Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
26
27Permission is hereby granted, free of charge, to any person obtaining a copy
28of this software and associated documentation files (the "Software"), to deal
29in the Software without restriction, including without limitation the rights
30to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31copies of the Software.
32
33The above copyright notice and this permission notice shall be included in
34all copies or substantial portions of the Software.
35
36THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
39DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
40BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
41WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
42IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43
44Except as contained in this notice, the name of Digital Equipment Corporation
45shall not be used in advertising or otherwise to promote the sale, use or other
46dealings in this Software without prior written authorization from Digital
47Equipment Corporation.
48
49******************************************************************/
50
51#ifdef HAVE_DIX_CONFIG_H
52#include <dix-config.h>
53#endif
54
55#include <X11/X.h>
56#include <X11/Xmd.h>
57#include <X11/Xproto.h>
58#include "scrnintstr.h"
59#include "resource.h"
60#include "dixstruct.h"
61#include "cursorstr.h"
62#include "misc.h"
63#include "opaque.h"
64#include "dixfontstr.h"
65#include "closestr.h"
66#include "dixfont.h"
67#include "xace.h"
68#include <X11/fonts/libxfont2.h>
69
70#ifdef XF86BIGFONT
71#include "xf86bigfontsrv.h"
72#endif
73
74extern void *fosNaturalParams;
75extern FontPtr defaultFont;
76
77static FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
78static int num_fpes = 0;
79static xfont2_fpe_funcs_rec const **fpe_functions;
80static int num_fpe_types = 0;
81
82static unsigned char *font_path_string;
83
84static int num_slept_fpes = 0;
85static int size_slept_fpes = 0;
86static FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
87static xfont2_pattern_cache_ptr patternCache;
88
89static int
90FontToXError(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
108static int
109LoadGlyphs(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
119void
120GetGlyphs(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 */
131Bool
132SetDefaultFont(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 */
160static void
161QueueFontWakeup(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
183static void
184RemoveFontWakeup(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
199static void
200FontWakeup(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 */
215static void
216UseFPE(FontPathElementPtr fpe)
217{
218    fpe->refcount++;
219}
220
221static void
222FreeFPE(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
232static Bool
233doOpenFont(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
373int
374OpenFont(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 */
452int
453CloseFont(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  */
494void
495QueryFont(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
552static Bool
553doListFontsAndAliases(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
792int
793ListFonts(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
843static int
844doListFontsWithInfo(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
1038int
1039StartListFontsWithInfo(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
1090static ChangeGCVal clearGC[] = { {.ptr = NullPixmap} };
1091
1092#define clearGCmask (GCClipMask)
1093
1094static int
1095doPolyText(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 pointer 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
1351int
1352PolyText(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        .client = client,
1357        .pDraw = pDraw,
1358        .pGC = pGC,
1359        .pElt = pElt,
1360        .endReq = endReq,
1361        .xorg = xorg,
1362        .yorg = yorg,
1363        .reqType = reqType,
1364        .did = did,
1365        .err = Success
1366    };
1367
1368    (void) doPolyText(client, &local_closure);
1369    return Success;
1370}
1371
1372#undef TextEltHeader
1373#undef FontShiftSize
1374
1375static int
1376doImageText(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
1497int
1498ImageText(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 */
1518static int
1519DetermineFPEType(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
1530static void
1531FreeFontPath(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
1555static FontPathElementPtr
1556find_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
1570static int
1571SetFontPathElements(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
1674int
1675SetFontPath(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        if (err != Success)
1691            client->errorValue = bad;
1692    }
1693    return err;
1694}
1695
1696int
1697SetDefaultFontPath(const char *path)
1698{
1699    const char *start, *end;
1700    char *temp_path;
1701    unsigned char *cp, *pp, *nump, *newpath;
1702    int num = 1, len, err, size = 0, bad;
1703
1704    /* ensure temp_path contains "built-ins" */
1705    start = path;
1706    while (1) {
1707        start = strstr(start, "built-ins");
1708        if (start == NULL)
1709            break;
1710        end = start + strlen("built-ins");
1711        if ((start == path || start[-1] == ',') && (!*end || *end == ','))
1712            break;
1713        start = end;
1714    }
1715    if (!start) {
1716        if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "")
1717            == -1)
1718            temp_path = NULL;
1719    }
1720    else {
1721        temp_path = strdup(path);
1722    }
1723    if (!temp_path)
1724        return BadAlloc;
1725
1726    /* get enough for string, plus values -- use up commas */
1727    len = strlen(temp_path) + 1;
1728    nump = cp = newpath = malloc(len);
1729    if (!newpath) {
1730        free(temp_path);
1731        return BadAlloc;
1732    }
1733    pp = (unsigned char *) temp_path;
1734    cp++;
1735    while (*pp) {
1736        if (*pp == ',') {
1737            *nump = (unsigned char) size;
1738            nump = cp++;
1739            pp++;
1740            num++;
1741            size = 0;
1742        }
1743        else {
1744            *cp++ = *pp++;
1745            size++;
1746        }
1747    }
1748    *nump = (unsigned char) size;
1749
1750    err = SetFontPathElements(num, newpath, &bad, TRUE);
1751
1752    free(newpath);
1753    free(temp_path);
1754
1755    return err;
1756}
1757
1758int
1759GetFontPath(ClientPtr client, int *count, int *length, unsigned char **result)
1760{
1761    int i;
1762    unsigned char *c;
1763    int len;
1764    FontPathElementPtr fpe;
1765
1766    i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
1767    if (i != Success)
1768        return i;
1769
1770    len = 0;
1771    for (i = 0; i < num_fpes; i++) {
1772        fpe = font_path_elements[i];
1773        len += fpe->name_length + 1;
1774    }
1775    c = realloc(font_path_string, len);
1776    if (c == NULL) {
1777        free(font_path_string);
1778        font_path_string = NULL;
1779        return BadAlloc;
1780    }
1781
1782    font_path_string = c;
1783    *length = 0;
1784    for (i = 0; i < num_fpes; i++) {
1785        fpe = font_path_elements[i];
1786        *c = fpe->name_length;
1787        *length += *c++;
1788        memmove(c, fpe->name, fpe->name_length);
1789        c += fpe->name_length;
1790    }
1791    *count = num_fpes;
1792    *result = font_path_string;
1793    return Success;
1794}
1795
1796void
1797DeleteClientFontStuff(ClientPtr client)
1798{
1799    int i;
1800    FontPathElementPtr fpe;
1801
1802    for (i = 0; i < num_fpes; i++) {
1803        fpe = font_path_elements[i];
1804        if (fpe_functions[fpe->type]->client_died)
1805            (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
1806    }
1807}
1808
1809static int
1810register_fpe_funcs(const xfont2_fpe_funcs_rec *funcs)
1811{
1812    xfont2_fpe_funcs_rec const **new;
1813
1814    /* grow the list */
1815    new = reallocarray(fpe_functions, num_fpe_types + 1, sizeof(xfont2_fpe_funcs_ptr));
1816    if (!new)
1817        return -1;
1818    fpe_functions = new;
1819
1820    fpe_functions[num_fpe_types] = funcs;
1821
1822    return num_fpe_types++;
1823}
1824
1825static unsigned long
1826get_server_generation(void)
1827{
1828    return serverGeneration;
1829}
1830
1831static void *
1832get_server_client(void)
1833{
1834    return serverClient;
1835}
1836
1837static int
1838get_default_point_size(void)
1839{
1840    return 120;
1841}
1842
1843static FontResolutionPtr
1844get_client_resolutions(int *num)
1845{
1846    static struct _FontResolution res;
1847    ScreenPtr pScreen;
1848
1849    pScreen = screenInfo.screens[0];
1850    res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth;
1851    /*
1852     * XXX - we'll want this as long as bitmap instances are prevalent
1853     so that we can match them from scalable fonts
1854     */
1855    if (res.x_resolution < 88)
1856        res.x_resolution = 75;
1857    else
1858        res.x_resolution = 100;
1859    res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight;
1860    if (res.y_resolution < 88)
1861        res.y_resolution = 75;
1862    else
1863        res.y_resolution = 100;
1864    res.point_size = 120;
1865    *num = 1;
1866    return &res;
1867}
1868
1869void
1870FreeFonts(void)
1871{
1872    if (patternCache) {
1873        xfont2_free_font_pattern_cache(patternCache);
1874        patternCache = 0;
1875    }
1876    FreeFontPath(font_path_elements, num_fpes, TRUE);
1877    font_path_elements = 0;
1878    num_fpes = 0;
1879    free(fpe_functions);
1880    num_fpe_types = 0;
1881    fpe_functions = NULL;
1882}
1883
1884/* convenience functions for FS interface */
1885
1886static FontPtr
1887find_old_font(XID id)
1888{
1889    void *pFont;
1890
1891    dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess);
1892    return (FontPtr) pFont;
1893}
1894
1895static Font
1896get_new_font_client_id(void)
1897{
1898    return FakeClientID(0);
1899}
1900
1901static int
1902store_font_Client_font(FontPtr pfont, Font id)
1903{
1904    return AddResource(id, RT_NONE, (void *) pfont);
1905}
1906
1907static void
1908delete_font_client_id(Font id)
1909{
1910    FreeResource(id, RT_NONE);
1911}
1912
1913static int
1914_client_auth_generation(ClientPtr client)
1915{
1916    return 0;
1917}
1918
1919static int fs_handlers_installed = 0;
1920static unsigned int last_server_gen;
1921
1922static void fs_block_handler(void *blockData, void *timeout)
1923{
1924    FontBlockHandlerProcPtr block_handler = blockData;
1925
1926    (*block_handler)(timeout);
1927}
1928
1929struct fs_fd_entry {
1930    struct xorg_list            entry;
1931    int                         fd;
1932    void                        *data;
1933    FontFdHandlerProcPtr        handler;
1934};
1935
1936static void
1937fs_fd_handler(int fd, int ready, void *data)
1938{
1939    struct fs_fd_entry    *entry = data;
1940
1941    entry->handler(fd, entry->data);
1942}
1943
1944static struct xorg_list fs_fd_list;
1945
1946static int
1947add_fs_fd(int fd, FontFdHandlerProcPtr handler, void *data)
1948{
1949    struct fs_fd_entry  *entry = calloc(1, sizeof (struct fs_fd_entry));
1950
1951    if (!entry)
1952        return FALSE;
1953
1954    entry->fd = fd;
1955    entry->data = data;
1956    entry->handler = handler;
1957    if (!SetNotifyFd(fd, fs_fd_handler, X_NOTIFY_READ, entry)) {
1958        free(entry);
1959        return FALSE;
1960    }
1961    xorg_list_add(&entry->entry, &fs_fd_list);
1962    return TRUE;
1963}
1964
1965static void
1966remove_fs_fd(int fd)
1967{
1968    struct fs_fd_entry  *entry, *temp;
1969
1970    xorg_list_for_each_entry_safe(entry, temp, &fs_fd_list, entry) {
1971        if (entry->fd == fd) {
1972            xorg_list_del(&entry->entry);
1973            free(entry);
1974            break;
1975        }
1976    }
1977    RemoveNotifyFd(fd);
1978}
1979
1980static void
1981adjust_fs_wait_for_delay(void *wt, unsigned long newdelay)
1982{
1983    AdjustWaitForDelay(wt, newdelay);
1984}
1985
1986static int
1987_init_fs_handlers(FontPathElementPtr fpe, FontBlockHandlerProcPtr block_handler)
1988{
1989    /* if server has reset, make sure the b&w handlers are reinstalled */
1990    if (last_server_gen < serverGeneration) {
1991        last_server_gen = serverGeneration;
1992        fs_handlers_installed = 0;
1993    }
1994    if (fs_handlers_installed == 0) {
1995        if (!RegisterBlockAndWakeupHandlers(fs_block_handler,
1996                                            FontWakeup, (void *) block_handler))
1997            return AllocError;
1998        xorg_list_init(&fs_fd_list);
1999        fs_handlers_installed++;
2000    }
2001    QueueFontWakeup(fpe);
2002    return Successful;
2003}
2004
2005static void
2006_remove_fs_handlers(FontPathElementPtr fpe, FontBlockHandlerProcPtr block_handler,
2007                    Bool all)
2008{
2009    if (all) {
2010        /* remove the handlers if no one else is using them */
2011        if (--fs_handlers_installed == 0) {
2012            RemoveBlockAndWakeupHandlers(fs_block_handler, FontWakeup,
2013                                         (void *) block_handler);
2014        }
2015    }
2016    RemoveFontWakeup(fpe);
2017}
2018
2019static uint32_t wrap_time_in_millis(void)
2020{
2021    return GetTimeInMillis();
2022}
2023
2024static const xfont2_client_funcs_rec xfont2_client_funcs = {
2025    .version = XFONT2_CLIENT_FUNCS_VERSION,
2026    .client_auth_generation = _client_auth_generation,
2027    .client_signal = ClientSignal,
2028    .delete_font_client_id = delete_font_client_id,
2029    .verrorf = VErrorF,
2030    .find_old_font = find_old_font,
2031    .get_client_resolutions = get_client_resolutions,
2032    .get_default_point_size = get_default_point_size,
2033    .get_new_font_client_id = get_new_font_client_id,
2034    .get_time_in_millis = wrap_time_in_millis,
2035    .init_fs_handlers = _init_fs_handlers,
2036    .register_fpe_funcs = register_fpe_funcs,
2037    .remove_fs_handlers = _remove_fs_handlers,
2038    .get_server_client = get_server_client,
2039    .set_font_authorizations = set_font_authorizations,
2040    .store_font_client_font = store_font_Client_font,
2041    .make_atom = MakeAtom,
2042    .valid_atom = ValidAtom,
2043    .name_for_atom = NameForAtom,
2044    .get_server_generation = get_server_generation,
2045    .add_fs_fd = add_fs_fd,
2046    .remove_fs_fd = remove_fs_fd,
2047    .adjust_fs_wait_for_delay = adjust_fs_wait_for_delay,
2048};
2049
2050xfont2_pattern_cache_ptr fontPatternCache;
2051
2052void
2053InitFonts(void)
2054{
2055    if (fontPatternCache)
2056	xfont2_free_font_pattern_cache(fontPatternCache);
2057    fontPatternCache = xfont2_make_font_pattern_cache();
2058    xfont2_init(&xfont2_client_funcs);
2059}
2060