dixfonts.c revision 7e31ba66
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 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
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
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
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        client->errorValue = bad;
1691    }
1692    return err;
1693}
1694
1695int
1696SetDefaultFontPath(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
1757int
1758GetFontPath(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
1795void
1796DeleteClientFontStuff(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
1808static int
1809register_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
1824static unsigned long
1825get_server_generation(void)
1826{
1827    return serverGeneration;
1828}
1829
1830static void *
1831get_server_client(void)
1832{
1833    return serverClient;
1834}
1835
1836static int
1837get_default_point_size(void)
1838{
1839    return 120;
1840}
1841
1842static FontResolutionPtr
1843get_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
1868void
1869FreeFonts(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
1885static FontPtr
1886find_old_font(XID id)
1887{
1888    void *pFont;
1889
1890    dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess);
1891    return (FontPtr) pFont;
1892}
1893
1894static Font
1895get_new_font_client_id(void)
1896{
1897    return FakeClientID(0);
1898}
1899
1900static int
1901store_font_Client_font(FontPtr pfont, Font id)
1902{
1903    return AddResource(id, RT_NONE, (void *) pfont);
1904}
1905
1906static void
1907delete_font_client_id(Font id)
1908{
1909    FreeResource(id, RT_NONE);
1910}
1911
1912static int
1913_client_auth_generation(ClientPtr client)
1914{
1915    return 0;
1916}
1917
1918static int fs_handlers_installed = 0;
1919static unsigned int last_server_gen;
1920
1921static void fs_block_handler(void *blockData, void *timeout)
1922{
1923    FontBlockHandlerProcPtr block_handler = blockData;
1924
1925    (*block_handler)(timeout);
1926}
1927
1928struct fs_fd_entry {
1929    struct xorg_list            entry;
1930    int                         fd;
1931    void                        *data;
1932    FontFdHandlerProcPtr        handler;
1933};
1934
1935static void
1936fs_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
1943static struct xorg_list fs_fd_list;
1944
1945static int
1946add_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
1964static void
1965remove_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
1979static void
1980adjust_fs_wait_for_delay(void *wt, unsigned long newdelay)
1981{
1982    AdjustWaitForDelay(wt, newdelay);
1983}
1984
1985static int
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
2004static void
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
2018static uint32_t wrap_time_in_millis(void)
2019{
2020    return GetTimeInMillis();
2021}
2022
2023static 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
2049xfont2_pattern_cache_ptr fontPatternCache;
2050
2051void
2052InitFonts(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