105b261ecSmrg/************************************************************************
205b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
305b261ecSmrg
405b261ecSmrg                        All Rights Reserved
505b261ecSmrg
605b261ecSmrgPermission to use, copy, modify, and distribute this software and its
705b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
805b261ecSmrgprovided that the above copyright notice appear in all copies and that
905b261ecSmrgboth that copyright notice and this permission notice appear in
1005b261ecSmrgsupporting documentation, and that the name of Digital not be
1105b261ecSmrgused in advertising or publicity pertaining to distribution of the
1205b261ecSmrgsoftware without specific, written prior permission.
1305b261ecSmrg
1405b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1505b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1605b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1705b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1805b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1905b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2005b261ecSmrgSOFTWARE.
2105b261ecSmrg
2205b261ecSmrg************************************************************************/
2305b261ecSmrg/* The panoramix components contained the following notice */
2405b261ecSmrg/*
2505b261ecSmrgCopyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
2605b261ecSmrg
2705b261ecSmrgPermission is hereby granted, free of charge, to any person obtaining a copy
2805b261ecSmrgof this software and associated documentation files (the "Software"), to deal
2905b261ecSmrgin the Software without restriction, including without limitation the rights
3005b261ecSmrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3105b261ecSmrgcopies of the Software.
3205b261ecSmrg
3305b261ecSmrgThe above copyright notice and this permission notice shall be included in
3405b261ecSmrgall copies or substantial portions of the Software.
3505b261ecSmrg
3605b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3705b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3805b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
3905b261ecSmrgDIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
4005b261ecSmrgBUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
4205b261ecSmrgIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4305b261ecSmrg
4405b261ecSmrgExcept as contained in this notice, the name of Digital Equipment Corporation
4505b261ecSmrgshall not be used in advertising or otherwise to promote the sale, use or other
4605b261ecSmrgdealings in this Software without prior written authorization from Digital
4705b261ecSmrgEquipment Corporation.
4805b261ecSmrg
4905b261ecSmrg******************************************************************/
5005b261ecSmrg
5105b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5205b261ecSmrg#include <dix-config.h>
5305b261ecSmrg#endif
5405b261ecSmrg
5505b261ecSmrg#include <X11/X.h>
5605b261ecSmrg#include <X11/Xmd.h>
5705b261ecSmrg#include <X11/Xproto.h>
5805b261ecSmrg#include "scrnintstr.h"
5905b261ecSmrg#include "resource.h"
6005b261ecSmrg#include "dixstruct.h"
6105b261ecSmrg#include "cursorstr.h"
6205b261ecSmrg#include "misc.h"
6305b261ecSmrg#include "opaque.h"
6405b261ecSmrg#include "dixfontstr.h"
6505b261ecSmrg#include "closestr.h"
6605b261ecSmrg#include "dixfont.h"
674642e01fSmrg#include "xace.h"
687e31ba66Smrg#include <X11/fonts/libxfont2.h>
6905b261ecSmrg
7005b261ecSmrg#ifdef XF86BIGFONT
716747b715Smrg#include "xf86bigfontsrv.h"
7205b261ecSmrg#endif
7305b261ecSmrg
74f7df2e56Smrgextern void *fosNaturalParams;
7505b261ecSmrgextern FontPtr defaultFont;
7605b261ecSmrg
7705b261ecSmrgstatic FontPathElementPtr *font_path_elements = (FontPathElementPtr *) 0;
78f7df2e56Smrgstatic int num_fpes = 0;
797e31ba66Smrgstatic xfont2_fpe_funcs_rec const **fpe_functions;
80f7df2e56Smrgstatic int num_fpe_types = 0;
8105b261ecSmrg
8205b261ecSmrgstatic unsigned char *font_path_string;
8305b261ecSmrg
84f7df2e56Smrgstatic int num_slept_fpes = 0;
85f7df2e56Smrgstatic int size_slept_fpes = 0;
8605b261ecSmrgstatic FontPathElementPtr *slept_fpes = (FontPathElementPtr *) 0;
877e31ba66Smrgstatic xfont2_pattern_cache_ptr patternCache;
8805b261ecSmrg
894642e01fSmrgstatic int
904642e01fSmrgFontToXError(int err)
9105b261ecSmrg{
9205b261ecSmrg    switch (err) {
9305b261ecSmrg    case Successful:
94f7df2e56Smrg        return Success;
9505b261ecSmrg    case AllocError:
96f7df2e56Smrg        return BadAlloc;
9705b261ecSmrg    case BadFontName:
98f7df2e56Smrg        return BadName;
9905b261ecSmrg    case BadFontPath:
100f7df2e56Smrg    case BadFontFormat:        /* is there something better? */
10105b261ecSmrg    case BadCharRange:
102f7df2e56Smrg        return BadValue;
10305b261ecSmrg    default:
104f7df2e56Smrg        return err;
10505b261ecSmrg    }
10605b261ecSmrg}
10705b261ecSmrg
1084642e01fSmrgstatic int
1094642e01fSmrgLoadGlyphs(ClientPtr client, FontPtr pfont, unsigned nchars, int item_size,
110f7df2e56Smrg           unsigned char *data)
1114642e01fSmrg{
1127e31ba66Smrg    if (fpe_functions[pfont->fpe->type]->load_glyphs)
1137e31ba66Smrg        return (*fpe_functions[pfont->fpe->type]->load_glyphs)
114f7df2e56Smrg            (client, pfont, 0, nchars, item_size, data);
1154642e01fSmrg    else
116f7df2e56Smrg        return Successful;
117f7df2e56Smrg}
118f7df2e56Smrg
119f7df2e56Smrgvoid
1207e31ba66SmrgGetGlyphs(FontPtr font, unsigned long count, unsigned char *chars,
1217e31ba66Smrg          FontEncoding fontEncoding,
1227e31ba66Smrg          unsigned long *glyphcount,    /* RETURN */
1237e31ba66Smrg          CharInfoPtr *glyphs)          /* RETURN */
124f7df2e56Smrg{
125f7df2e56Smrg    (*font->get_glyphs) (font, count, chars, fontEncoding, glyphcount, glyphs);
1264642e01fSmrg}
12705b261ecSmrg
12805b261ecSmrg/*
12905b261ecSmrg * adding RT_FONT prevents conflict with default cursor font
13005b261ecSmrg */
13105b261ecSmrgBool
132f7df2e56SmrgSetDefaultFont(const char *defaultfontname)
13305b261ecSmrg{
134f7df2e56Smrg    int err;
135f7df2e56Smrg    FontPtr pf;
136f7df2e56Smrg    XID fid;
13705b261ecSmrg
13805b261ecSmrg    fid = FakeClientID(0);
13905b261ecSmrg    err = OpenFont(serverClient, fid, FontLoadAll | FontOpenSync,
140f7df2e56Smrg                   (unsigned) strlen(defaultfontname), defaultfontname);
14105b261ecSmrg    if (err != Success)
142f7df2e56Smrg        return FALSE;
143f7df2e56Smrg    err = dixLookupResourceByType((void **) &pf, fid, RT_FONT, serverClient,
144f7df2e56Smrg                                  DixReadAccess);
1456747b715Smrg    if (err != Success)
146f7df2e56Smrg        return FALSE;
14705b261ecSmrg    defaultFont = pf;
14805b261ecSmrg    return TRUE;
14905b261ecSmrg}
15005b261ecSmrg
15105b261ecSmrg/*
15205b261ecSmrg * note that the font wakeup queue is not refcounted.  this is because
15305b261ecSmrg * an fpe needs to be added when it's inited, and removed when it's finally
15405b261ecSmrg * freed, in order to handle any data that isn't requested, like FS events.
15505b261ecSmrg *
15605b261ecSmrg * since the only thing that should call these routines is the renderer's
15705b261ecSmrg * init_fpe() and free_fpe(), there shouldn't be any problem in using
15805b261ecSmrg * freed data.
15905b261ecSmrg */
160f7df2e56Smrgstatic void
16105b261ecSmrgQueueFontWakeup(FontPathElementPtr fpe)
16205b261ecSmrg{
163f7df2e56Smrg    int i;
16405b261ecSmrg    FontPathElementPtr *new;
16505b261ecSmrg
16605b261ecSmrg    for (i = 0; i < num_slept_fpes; i++) {
167f7df2e56Smrg        if (slept_fpes[i] == fpe) {
168f7df2e56Smrg            return;
169f7df2e56Smrg        }
17005b261ecSmrg    }
17105b261ecSmrg    if (num_slept_fpes == size_slept_fpes) {
172f7df2e56Smrg        new = reallocarray(slept_fpes, size_slept_fpes + 4,
173f7df2e56Smrg                           sizeof(FontPathElementPtr));
174f7df2e56Smrg        if (!new)
175f7df2e56Smrg            return;
176f7df2e56Smrg        slept_fpes = new;
177f7df2e56Smrg        size_slept_fpes += 4;
17805b261ecSmrg    }
17905b261ecSmrg    slept_fpes[num_slept_fpes] = fpe;
18005b261ecSmrg    num_slept_fpes++;
18105b261ecSmrg}
18205b261ecSmrg
183f7df2e56Smrgstatic void
18405b261ecSmrgRemoveFontWakeup(FontPathElementPtr fpe)
18505b261ecSmrg{
186f7df2e56Smrg    int i, j;
18705b261ecSmrg
18805b261ecSmrg    for (i = 0; i < num_slept_fpes; i++) {
189f7df2e56Smrg        if (slept_fpes[i] == fpe) {
190f7df2e56Smrg            for (j = i; j < num_slept_fpes; j++) {
191f7df2e56Smrg                slept_fpes[j] = slept_fpes[j + 1];
192f7df2e56Smrg            }
193f7df2e56Smrg            num_slept_fpes--;
194f7df2e56Smrg            return;
195f7df2e56Smrg        }
19605b261ecSmrg    }
19705b261ecSmrg}
19805b261ecSmrg
199f7df2e56Smrgstatic void
2007e31ba66SmrgFontWakeup(void *data, int count)
20105b261ecSmrg{
202f7df2e56Smrg    int i;
20305b261ecSmrg    FontPathElementPtr fpe;
20405b261ecSmrg
20505b261ecSmrg    if (count < 0)
206f7df2e56Smrg        return;
20705b261ecSmrg    /* wake up any fpe's that may be waiting for information */
20805b261ecSmrg    for (i = 0; i < num_slept_fpes; i++) {
209f7df2e56Smrg        fpe = slept_fpes[i];
2107e31ba66Smrg        (void) (*fpe_functions[fpe->type]->wakeup_fpe) (fpe);
21105b261ecSmrg    }
21205b261ecSmrg}
21305b261ecSmrg
21405b261ecSmrg/* XXX -- these two funcs may want to be broken into macros */
21505b261ecSmrgstatic void
21605b261ecSmrgUseFPE(FontPathElementPtr fpe)
21705b261ecSmrg{
21805b261ecSmrg    fpe->refcount++;
21905b261ecSmrg}
22005b261ecSmrg
22105b261ecSmrgstatic void
222f7df2e56SmrgFreeFPE(FontPathElementPtr fpe)
22305b261ecSmrg{
22405b261ecSmrg    fpe->refcount--;
22505b261ecSmrg    if (fpe->refcount == 0) {
2267e31ba66Smrg        (*fpe_functions[fpe->type]->free_fpe) (fpe);
227f7df2e56Smrg        free((void *) fpe->name);
228f7df2e56Smrg        free(fpe);
22905b261ecSmrg    }
23005b261ecSmrg}
23105b261ecSmrg
23205b261ecSmrgstatic Bool
23305b261ecSmrgdoOpenFont(ClientPtr client, OFclosurePtr c)
23405b261ecSmrg{
235f7df2e56Smrg    FontPtr pfont = NullFont;
23605b261ecSmrg    FontPathElementPtr fpe = NULL;
237f7df2e56Smrg    ScreenPtr pScr;
238f7df2e56Smrg    int err = Successful;
239f7df2e56Smrg    int i;
240f7df2e56Smrg    char *alias, *newname;
241f7df2e56Smrg    int newlen;
242f7df2e56Smrg    int aliascount = 20;
243f7df2e56Smrg
24405b261ecSmrg    /*
24505b261ecSmrg     * Decide at runtime what FontFormat to use.
24605b261ecSmrg     */
247f7df2e56Smrg    Mask FontFormat =
248f7df2e56Smrg        ((screenInfo.imageByteOrder == LSBFirst) ?
249f7df2e56Smrg         BitmapFormatByteOrderLSB : BitmapFormatByteOrderMSB) |
250f7df2e56Smrg        ((screenInfo.bitmapBitOrder == LSBFirst) ?
251f7df2e56Smrg         BitmapFormatBitOrderLSB : BitmapFormatBitOrderMSB) |
252f7df2e56Smrg        BitmapFormatImageRectMin |
25305b261ecSmrg#if GLYPHPADBYTES == 1
254f7df2e56Smrg        BitmapFormatScanlinePad8 |
25505b261ecSmrg#endif
25605b261ecSmrg#if GLYPHPADBYTES == 2
257f7df2e56Smrg        BitmapFormatScanlinePad16 |
25805b261ecSmrg#endif
25905b261ecSmrg#if GLYPHPADBYTES == 4
260f7df2e56Smrg        BitmapFormatScanlinePad32 |
26105b261ecSmrg#endif
26205b261ecSmrg#if GLYPHPADBYTES == 8
263f7df2e56Smrg        BitmapFormatScanlinePad64 |
26405b261ecSmrg#endif
265f7df2e56Smrg        BitmapFormatScanlineUnit8;
26605b261ecSmrg
267f7df2e56Smrg    if (client->clientGone) {
268f7df2e56Smrg        if (c->current_fpe < c->num_fpes) {
269f7df2e56Smrg            fpe = c->fpe_list[c->current_fpe];
2707e31ba66Smrg            (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
271f7df2e56Smrg        }
272f7df2e56Smrg        err = Successful;
273f7df2e56Smrg        goto bail;
27405b261ecSmrg    }
27505b261ecSmrg    while (c->current_fpe < c->num_fpes) {
276f7df2e56Smrg        fpe = c->fpe_list[c->current_fpe];
2777e31ba66Smrg        err = (*fpe_functions[fpe->type]->open_font)
278f7df2e56Smrg            ((void *) client, fpe, c->flags,
279f7df2e56Smrg             c->fontname, c->fnamelen, FontFormat,
280f7df2e56Smrg             BitmapFormatMaskByte |
281f7df2e56Smrg             BitmapFormatMaskBit |
282f7df2e56Smrg             BitmapFormatMaskImageRectangle |
283f7df2e56Smrg             BitmapFormatMaskScanLinePad |
284f7df2e56Smrg             BitmapFormatMaskScanLineUnit,
285f7df2e56Smrg             c->fontid, &pfont, &alias,
286f7df2e56Smrg             c->non_cachable_font && c->non_cachable_font->fpe == fpe ?
287f7df2e56Smrg             c->non_cachable_font : (FontPtr) 0);
288f7df2e56Smrg
289f7df2e56Smrg        if (err == FontNameAlias && alias) {
290f7df2e56Smrg            newlen = strlen(alias);
291f7df2e56Smrg            newname = (char *) realloc((char *) c->fontname, newlen);
292f7df2e56Smrg            if (!newname) {
293f7df2e56Smrg                err = AllocError;
294f7df2e56Smrg                break;
295f7df2e56Smrg            }
296f7df2e56Smrg            memmove(newname, alias, newlen);
297f7df2e56Smrg            c->fontname = newname;
298f7df2e56Smrg            c->fnamelen = newlen;
299f7df2e56Smrg            c->current_fpe = 0;
300f7df2e56Smrg            if (--aliascount <= 0) {
301f7df2e56Smrg                /* We've tried resolving this alias 20 times, we're
302f7df2e56Smrg                 * probably stuck in an infinite loop of aliases pointing
303f7df2e56Smrg                 * to each other - time to take emergency exit!
304f7df2e56Smrg                 */
305f7df2e56Smrg                err = BadImplementation;
306f7df2e56Smrg                break;
307f7df2e56Smrg            }
308f7df2e56Smrg            continue;
309f7df2e56Smrg        }
310f7df2e56Smrg        if (err == BadFontName) {
311f7df2e56Smrg            c->current_fpe++;
312f7df2e56Smrg            continue;
313f7df2e56Smrg        }
314f7df2e56Smrg        if (err == Suspended) {
315f7df2e56Smrg            if (!ClientIsAsleep(client))
316f7df2e56Smrg                ClientSleep(client, (ClientSleepProcPtr) doOpenFont, c);
317f7df2e56Smrg            return TRUE;
318f7df2e56Smrg        }
319f7df2e56Smrg        break;
32005b261ecSmrg    }
32105b261ecSmrg
32205b261ecSmrg    if (err != Successful)
323f7df2e56Smrg        goto bail;
32405b261ecSmrg    if (!pfont) {
325f7df2e56Smrg        err = BadFontName;
326f7df2e56Smrg        goto bail;
32705b261ecSmrg    }
32805b261ecSmrg    /* check values for firstCol, lastCol, firstRow, and lastRow */
32905b261ecSmrg    if (pfont->info.firstCol > pfont->info.lastCol ||
330f7df2e56Smrg        pfont->info.firstRow > pfont->info.lastRow ||
331f7df2e56Smrg        pfont->info.lastCol - pfont->info.firstCol > 255) {
332f7df2e56Smrg        err = AllocError;
333f7df2e56Smrg        goto bail;
33405b261ecSmrg    }
33505b261ecSmrg    if (!pfont->fpe)
336f7df2e56Smrg        pfont->fpe = fpe;
33705b261ecSmrg    pfont->refcnt++;
33805b261ecSmrg    if (pfont->refcnt == 1) {
339f7df2e56Smrg        UseFPE(pfont->fpe);
340f7df2e56Smrg        for (i = 0; i < screenInfo.numScreens; i++) {
341f7df2e56Smrg            pScr = screenInfo.screens[i];
342f7df2e56Smrg            if (pScr->RealizeFont) {
343f7df2e56Smrg                if (!(*pScr->RealizeFont) (pScr, pfont)) {
344f7df2e56Smrg                    CloseFont(pfont, (Font) 0);
345f7df2e56Smrg                    err = AllocError;
346f7df2e56Smrg                    goto bail;
347f7df2e56Smrg                }
348f7df2e56Smrg            }
349f7df2e56Smrg        }
350f7df2e56Smrg    }
351f7df2e56Smrg    if (!AddResource(c->fontid, RT_FONT, (void *) pfont)) {
352f7df2e56Smrg        err = AllocError;
353f7df2e56Smrg        goto bail;
35405b261ecSmrg    }
35505b261ecSmrg    if (patternCache && pfont != c->non_cachable_font)
3567e31ba66Smrg        xfont2_cache_font_pattern(patternCache, c->origFontName, c->origFontNameLen,
3577e31ba66Smrg                                  pfont);
358f7df2e56Smrg bail:
35905b261ecSmrg    if (err != Successful && c->client != serverClient) {
360f7df2e56Smrg        SendErrorToClient(c->client, X_OpenFont, 0,
361f7df2e56Smrg                          c->fontid, FontToXError(err));
36205b261ecSmrg    }
3636747b715Smrg    ClientWakeup(c->client);
36405b261ecSmrg    for (i = 0; i < c->num_fpes; i++) {
365f7df2e56Smrg        FreeFPE(c->fpe_list[i]);
36605b261ecSmrg    }
3676747b715Smrg    free(c->fpe_list);
368f7df2e56Smrg    free((void *) c->fontname);
3696747b715Smrg    free(c);
37005b261ecSmrg    return TRUE;
37105b261ecSmrg}
37205b261ecSmrg
37305b261ecSmrgint
374f7df2e56SmrgOpenFont(ClientPtr client, XID fid, Mask flags, unsigned lenfname,
375f7df2e56Smrg         const char *pfontname)
37605b261ecSmrg{
37705b261ecSmrg    OFclosurePtr c;
378f7df2e56Smrg    int i;
379f7df2e56Smrg    FontPtr cached = (FontPtr) 0;
38005b261ecSmrg
38105b261ecSmrg    if (!lenfname || lenfname > XLFDMAXFONTNAMELEN)
382f7df2e56Smrg        return BadName;
383f7df2e56Smrg    if (patternCache) {
38405b261ecSmrg
385f7df2e56Smrg        /*
386f7df2e56Smrg         ** Check name cache.  If we find a cached version of this font that
387f7df2e56Smrg         ** is cachable, immediately satisfy the request with it.  If we find
388f7df2e56Smrg         ** a cached version of this font that is non-cachable, we do not
389f7df2e56Smrg         ** satisfy the request with it.  Instead, we pass the FontPtr to the
390f7df2e56Smrg         ** FPE's open_font code (the fontfile FPE in turn passes the
391f7df2e56Smrg         ** information to the rasterizer; the fserve FPE ignores it).
392f7df2e56Smrg         **
393f7df2e56Smrg         ** Presumably, the font is marked non-cachable because the FPE has
394f7df2e56Smrg         ** put some licensing restrictions on it.  If the FPE, using
395f7df2e56Smrg         ** whatever logic it relies on, determines that it is willing to
396f7df2e56Smrg         ** share this existing font with the client, then it has the option
397f7df2e56Smrg         ** to return the FontPtr we passed it as the newly-opened font.
398f7df2e56Smrg         ** This allows the FPE to exercise its licensing logic without
399f7df2e56Smrg         ** having to create another instance of a font that already exists.
400f7df2e56Smrg         */
401f7df2e56Smrg
4027e31ba66Smrg        cached = xfont2_find_cached_font_pattern(patternCache, pfontname, lenfname);
403f7df2e56Smrg        if (cached && cached->info.cachable) {
404f7df2e56Smrg            if (!AddResource(fid, RT_FONT, (void *) cached))
405f7df2e56Smrg                return BadAlloc;
406f7df2e56Smrg            cached->refcnt++;
407f7df2e56Smrg            return Success;
408f7df2e56Smrg        }
40905b261ecSmrg    }
4106747b715Smrg    c = malloc(sizeof(OFclosureRec));
41105b261ecSmrg    if (!c)
412f7df2e56Smrg        return BadAlloc;
4136747b715Smrg    c->fontname = malloc(lenfname);
41405b261ecSmrg    c->origFontName = pfontname;
41505b261ecSmrg    c->origFontNameLen = lenfname;
41605b261ecSmrg    if (!c->fontname) {
417f7df2e56Smrg        free(c);
418f7df2e56Smrg        return BadAlloc;
41905b261ecSmrg    }
42005b261ecSmrg    /*
42105b261ecSmrg     * copy the current FPE list, so that if it gets changed by another client
42205b261ecSmrg     * while we're blocking, the request still appears atomic
42305b261ecSmrg     */
424f7df2e56Smrg    c->fpe_list = xallocarray(num_fpes, sizeof(FontPathElementPtr));
42505b261ecSmrg    if (!c->fpe_list) {
426f7df2e56Smrg        free((void *) c->fontname);
427f7df2e56Smrg        free(c);
428f7df2e56Smrg        return BadAlloc;
42905b261ecSmrg    }
43005b261ecSmrg    memmove(c->fontname, pfontname, lenfname);
43105b261ecSmrg    for (i = 0; i < num_fpes; i++) {
432f7df2e56Smrg        c->fpe_list[i] = font_path_elements[i];
433f7df2e56Smrg        UseFPE(c->fpe_list[i]);
43405b261ecSmrg    }
43505b261ecSmrg    c->client = client;
43605b261ecSmrg    c->fontid = fid;
43705b261ecSmrg    c->current_fpe = 0;
43805b261ecSmrg    c->num_fpes = num_fpes;
43905b261ecSmrg    c->fnamelen = lenfname;
44005b261ecSmrg    c->flags = flags;
44105b261ecSmrg    c->non_cachable_font = cached;
44205b261ecSmrg
44305b261ecSmrg    (void) doOpenFont(client, c);
44405b261ecSmrg    return Success;
44505b261ecSmrg}
44605b261ecSmrg
44705b261ecSmrg/**
44805b261ecSmrg * Decrement font's ref count, and free storage if ref count equals zero
44905b261ecSmrg *
45005b261ecSmrg *  \param value must conform to DeleteType
45105b261ecSmrg */
4524642e01fSmrgint
453f7df2e56SmrgCloseFont(void *value, XID fid)
45405b261ecSmrg{
455f7df2e56Smrg    int nscr;
456f7df2e56Smrg    ScreenPtr pscr;
45705b261ecSmrg    FontPathElementPtr fpe;
458f7df2e56Smrg    FontPtr pfont = (FontPtr) value;
45905b261ecSmrg
46005b261ecSmrg    if (pfont == NullFont)
461f7df2e56Smrg        return Success;
46205b261ecSmrg    if (--pfont->refcnt == 0) {
463f7df2e56Smrg        if (patternCache)
4647e31ba66Smrg            xfont2_remove_cached_font_pattern(patternCache, pfont);
465f7df2e56Smrg        /*
466f7df2e56Smrg         * since the last reference is gone, ask each screen to free any
467f7df2e56Smrg         * storage it may have allocated locally for it.
468f7df2e56Smrg         */
469f7df2e56Smrg        for (nscr = 0; nscr < screenInfo.numScreens; nscr++) {
470f7df2e56Smrg            pscr = screenInfo.screens[nscr];
471f7df2e56Smrg            if (pscr->UnrealizeFont)
472f7df2e56Smrg                (*pscr->UnrealizeFont) (pscr, pfont);
473f7df2e56Smrg        }
474f7df2e56Smrg        if (pfont == defaultFont)
475f7df2e56Smrg            defaultFont = NULL;
47605b261ecSmrg#ifdef XF86BIGFONT
477f7df2e56Smrg        XF86BigfontFreeFontShm(pfont);
47805b261ecSmrg#endif
479f7df2e56Smrg        fpe = pfont->fpe;
4807e31ba66Smrg        (*fpe_functions[fpe->type]->close_font) (fpe, pfont);
481f7df2e56Smrg        FreeFPE(fpe);
48205b261ecSmrg    }
4836747b715Smrg    return Success;
48405b261ecSmrg}
48505b261ecSmrg
48605b261ecSmrg/***====================================================================***/
48705b261ecSmrg
48805b261ecSmrg/**
48905b261ecSmrg * Sets up pReply as the correct QueryFontReply for pFont with the first
49005b261ecSmrg * nProtoCCIStructs char infos.
49105b261ecSmrg *
49205b261ecSmrg *  \param pReply caller must allocate this storage
49305b261ecSmrg  */
49405b261ecSmrgvoid
495f7df2e56SmrgQueryFont(FontPtr pFont, xQueryFontReply * pReply, int nProtoCCIStructs)
49605b261ecSmrg{
497f7df2e56Smrg    FontPropPtr pFP;
498f7df2e56Smrg    int r, c, i;
499f7df2e56Smrg    xFontProp *prFP;
500f7df2e56Smrg    xCharInfo *prCI;
501f7df2e56Smrg    xCharInfo *charInfos[256];
502f7df2e56Smrg    unsigned char chars[512];
503f7df2e56Smrg    int ninfos;
504f7df2e56Smrg    unsigned long ncols;
505f7df2e56Smrg    unsigned long count;
50605b261ecSmrg
50705b261ecSmrg    /* pr->length set in dispatch */
50805b261ecSmrg    pReply->minCharOrByte2 = pFont->info.firstCol;
50905b261ecSmrg    pReply->defaultChar = pFont->info.defaultCh;
51005b261ecSmrg    pReply->maxCharOrByte2 = pFont->info.lastCol;
51105b261ecSmrg    pReply->drawDirection = pFont->info.drawDirection;
51205b261ecSmrg    pReply->allCharsExist = pFont->info.allExist;
51305b261ecSmrg    pReply->minByte1 = pFont->info.firstRow;
51405b261ecSmrg    pReply->maxByte1 = pFont->info.lastRow;
51505b261ecSmrg    pReply->fontAscent = pFont->info.fontAscent;
51605b261ecSmrg    pReply->fontDescent = pFont->info.fontDescent;
51705b261ecSmrg
51805b261ecSmrg    pReply->minBounds = pFont->info.ink_minbounds;
51905b261ecSmrg    pReply->maxBounds = pFont->info.ink_maxbounds;
52005b261ecSmrg
52105b261ecSmrg    pReply->nFontProps = pFont->info.nprops;
52205b261ecSmrg    pReply->nCharInfos = nProtoCCIStructs;
52305b261ecSmrg
52405b261ecSmrg    for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) (&pReply[1]);
525f7df2e56Smrg         i < pFont->info.nprops; i++, pFP++, prFP++) {
526f7df2e56Smrg        prFP->name = pFP->name;
527f7df2e56Smrg        prFP->value = pFP->value;
52805b261ecSmrg    }
52905b261ecSmrg
53005b261ecSmrg    ninfos = 0;
53105b261ecSmrg    ncols = (unsigned long) (pFont->info.lastCol - pFont->info.firstCol + 1);
53205b261ecSmrg    prCI = (xCharInfo *) (prFP);
53305b261ecSmrg    for (r = pFont->info.firstRow;
534f7df2e56Smrg         ninfos < nProtoCCIStructs && r <= (int) pFont->info.lastRow; r++) {
535f7df2e56Smrg        i = 0;
536f7df2e56Smrg        for (c = pFont->info.firstCol; c <= (int) pFont->info.lastCol; c++) {
537f7df2e56Smrg            chars[i++] = r;
538f7df2e56Smrg            chars[i++] = c;
539f7df2e56Smrg        }
540f7df2e56Smrg        (*pFont->get_metrics) (pFont, ncols, chars,
541f7df2e56Smrg                               TwoD16Bit, &count, charInfos);
542f7df2e56Smrg        i = 0;
543f7df2e56Smrg        for (i = 0; i < (int) count && ninfos < nProtoCCIStructs; i++) {
544f7df2e56Smrg            *prCI = *charInfos[i];
545f7df2e56Smrg            prCI++;
546f7df2e56Smrg            ninfos++;
547f7df2e56Smrg        }
54805b261ecSmrg    }
54905b261ecSmrg    return;
55005b261ecSmrg}
55105b261ecSmrg
55205b261ecSmrgstatic Bool
55305b261ecSmrgdoListFontsAndAliases(ClientPtr client, LFclosurePtr c)
55405b261ecSmrg{
55505b261ecSmrg    FontPathElementPtr fpe;
556f7df2e56Smrg    int err = Successful;
55705b261ecSmrg    FontNamesPtr names = NULL;
558f7df2e56Smrg    char *name, *resolved = NULL;
559f7df2e56Smrg    int namelen, resolvedlen;
560f7df2e56Smrg    int nnames;
561f7df2e56Smrg    int stringLens;
562f7df2e56Smrg    int i;
56305b261ecSmrg    xListFontsReply reply;
564f7df2e56Smrg    char *bufptr;
565f7df2e56Smrg    char *bufferStart;
566f7df2e56Smrg    int aliascount = 0;
567f7df2e56Smrg
568f7df2e56Smrg    if (client->clientGone) {
569f7df2e56Smrg        if (c->current.current_fpe < c->num_fpes) {
570f7df2e56Smrg            fpe = c->fpe_list[c->current.current_fpe];
5717e31ba66Smrg            (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
572f7df2e56Smrg        }
573f7df2e56Smrg        err = Successful;
574f7df2e56Smrg        goto bail;
57505b261ecSmrg    }
57605b261ecSmrg
57705b261ecSmrg    if (!c->current.patlen)
578f7df2e56Smrg        goto finish;
57905b261ecSmrg
58005b261ecSmrg    while (c->current.current_fpe < c->num_fpes) {
581f7df2e56Smrg        fpe = c->fpe_list[c->current.current_fpe];
582f7df2e56Smrg        err = Successful;
583f7df2e56Smrg
5847e31ba66Smrg        if (!fpe_functions[fpe->type]->start_list_fonts_and_aliases) {
585f7df2e56Smrg            /* This FPE doesn't support/require list_fonts_and_aliases */
586f7df2e56Smrg
5877e31ba66Smrg            err = (*fpe_functions[fpe->type]->list_fonts)
588f7df2e56Smrg                ((void *) c->client, fpe, c->current.pattern,
589f7df2e56Smrg                 c->current.patlen, c->current.max_names - c->names->nnames,
590f7df2e56Smrg                 c->names);
591f7df2e56Smrg
592f7df2e56Smrg            if (err == Suspended) {
593f7df2e56Smrg                if (!ClientIsAsleep(client))
594f7df2e56Smrg                    ClientSleep(client,
595f7df2e56Smrg                                (ClientSleepProcPtr) doListFontsAndAliases, c);
596f7df2e56Smrg                return TRUE;
597f7df2e56Smrg            }
598f7df2e56Smrg
599f7df2e56Smrg            err = BadFontName;
600f7df2e56Smrg        }
601f7df2e56Smrg        else {
602f7df2e56Smrg            /* Start of list_fonts_and_aliases functionality.  Modeled
603f7df2e56Smrg               after list_fonts_with_info in that it resolves aliases,
604f7df2e56Smrg               except that the information collected from FPEs is just
605f7df2e56Smrg               names, not font info.  Each list_next_font_or_alias()
606f7df2e56Smrg               returns either a name into name/namelen or an alias into
607f7df2e56Smrg               name/namelen and its target name into resolved/resolvedlen.
608f7df2e56Smrg               The code at this level then resolves the alias by polling
609f7df2e56Smrg               the FPEs.  */
610f7df2e56Smrg
611f7df2e56Smrg            if (!c->current.list_started) {
6127e31ba66Smrg                err = (*fpe_functions[fpe->type]->start_list_fonts_and_aliases)
613f7df2e56Smrg                    ((void *) c->client, fpe, c->current.pattern,
614f7df2e56Smrg                     c->current.patlen, c->current.max_names - c->names->nnames,
615f7df2e56Smrg                     &c->current.private);
616f7df2e56Smrg                if (err == Suspended) {
617f7df2e56Smrg                    if (!ClientIsAsleep(client))
618f7df2e56Smrg                        ClientSleep(client,
619f7df2e56Smrg                                    (ClientSleepProcPtr) doListFontsAndAliases,
620f7df2e56Smrg                                    c);
621f7df2e56Smrg                    return TRUE;
622f7df2e56Smrg                }
623f7df2e56Smrg                if (err == Successful)
624f7df2e56Smrg                    c->current.list_started = TRUE;
625f7df2e56Smrg            }
626f7df2e56Smrg            if (err == Successful) {
627f7df2e56Smrg                char *tmpname;
628f7df2e56Smrg
629f7df2e56Smrg                name = 0;
6307e31ba66Smrg                err = (*fpe_functions[fpe->type]->list_next_font_or_alias)
631f7df2e56Smrg                    ((void *) c->client, fpe, &name, &namelen, &tmpname,
632f7df2e56Smrg                     &resolvedlen, c->current.private);
633f7df2e56Smrg                if (err == Suspended) {
634f7df2e56Smrg                    if (!ClientIsAsleep(client))
635f7df2e56Smrg                        ClientSleep(client,
636f7df2e56Smrg                                    (ClientSleepProcPtr) doListFontsAndAliases,
637f7df2e56Smrg                                    c);
638f7df2e56Smrg                    return TRUE;
639f7df2e56Smrg                }
640f7df2e56Smrg                if (err == FontNameAlias) {
641f7df2e56Smrg                    free(resolved);
642f7df2e56Smrg                    resolved = malloc(resolvedlen + 1);
643f7df2e56Smrg                    if (resolved)
644f7df2e56Smrg                        memmove(resolved, tmpname, resolvedlen + 1);
645f7df2e56Smrg                }
646f7df2e56Smrg            }
647f7df2e56Smrg
648f7df2e56Smrg            if (err == Successful) {
649f7df2e56Smrg                if (c->haveSaved) {
650f7df2e56Smrg                    if (c->savedName)
6517e31ba66Smrg                        (void) xfont2_add_font_names_name(c->names, c->savedName,
652f7df2e56Smrg                                                c->savedNameLen);
653f7df2e56Smrg                }
654f7df2e56Smrg                else
6557e31ba66Smrg                    (void) xfont2_add_font_names_name(c->names, name, namelen);
656f7df2e56Smrg            }
657f7df2e56Smrg
658f7df2e56Smrg            /*
659f7df2e56Smrg             * When we get an alias back, save our state and reset back to
660f7df2e56Smrg             * the start of the FPE looking for the specified name.  As
661f7df2e56Smrg             * soon as a real font is found for the alias, pop back to the
662f7df2e56Smrg             * old state
663f7df2e56Smrg             */
664f7df2e56Smrg            else if (err == FontNameAlias) {
665f7df2e56Smrg                char tmp_pattern[XLFDMAXFONTNAMELEN];
666f7df2e56Smrg
667f7df2e56Smrg                /*
668f7df2e56Smrg                 * when an alias recurses, we need to give
669f7df2e56Smrg                 * the last FPE a chance to clean up; so we call
670f7df2e56Smrg                 * it again, and assume that the error returned
671f7df2e56Smrg                 * is BadFontName, indicating the alias resolution
672f7df2e56Smrg                 * is complete.
673f7df2e56Smrg                 */
674f7df2e56Smrg                memmove(tmp_pattern, resolved, resolvedlen);
675f7df2e56Smrg                if (c->haveSaved) {
676f7df2e56Smrg                    char *tmpname;
677f7df2e56Smrg                    int tmpnamelen;
678f7df2e56Smrg
679f7df2e56Smrg                    tmpname = 0;
6807e31ba66Smrg                    (void) (*fpe_functions[fpe->type]->list_next_font_or_alias)
681f7df2e56Smrg                        ((void *) c->client, fpe, &tmpname, &tmpnamelen,
682f7df2e56Smrg                         &tmpname, &tmpnamelen, c->current.private);
683f7df2e56Smrg                    if (--aliascount <= 0) {
684f7df2e56Smrg                        err = BadFontName;
685f7df2e56Smrg                        goto ContBadFontName;
686f7df2e56Smrg                    }
687f7df2e56Smrg                }
688f7df2e56Smrg                else {
689f7df2e56Smrg                    c->saved = c->current;
690f7df2e56Smrg                    c->haveSaved = TRUE;
691f7df2e56Smrg                    free(c->savedName);
692f7df2e56Smrg                    c->savedName = malloc(namelen + 1);
693f7df2e56Smrg                    if (c->savedName)
694f7df2e56Smrg                        memmove(c->savedName, name, namelen + 1);
695f7df2e56Smrg                    c->savedNameLen = namelen;
696f7df2e56Smrg                    aliascount = 20;
697f7df2e56Smrg                }
698f7df2e56Smrg                memmove(c->current.pattern, tmp_pattern, resolvedlen);
699f7df2e56Smrg                c->current.patlen = resolvedlen;
700f7df2e56Smrg                c->current.max_names = c->names->nnames + 1;
701f7df2e56Smrg                c->current.current_fpe = -1;
702f7df2e56Smrg                c->current.private = 0;
703f7df2e56Smrg                err = BadFontName;
704f7df2e56Smrg            }
705f7df2e56Smrg        }
706f7df2e56Smrg        /*
707f7df2e56Smrg         * At the end of this FPE, step to the next.  If we've finished
708f7df2e56Smrg         * processing an alias, pop state back. If we've collected enough
709f7df2e56Smrg         * font names, quit.
710f7df2e56Smrg         */
711f7df2e56Smrg        if (err == BadFontName) {
712f7df2e56Smrg ContBadFontName:;
713f7df2e56Smrg            c->current.list_started = FALSE;
714f7df2e56Smrg            c->current.current_fpe++;
715f7df2e56Smrg            err = Successful;
716f7df2e56Smrg            if (c->haveSaved) {
717f7df2e56Smrg                if (c->names->nnames == c->current.max_names ||
718f7df2e56Smrg                    c->current.current_fpe == c->num_fpes) {
719f7df2e56Smrg                    c->haveSaved = FALSE;
720f7df2e56Smrg                    c->current = c->saved;
721f7df2e56Smrg                    /* Give the saved namelist a chance to clean itself up */
722f7df2e56Smrg                    continue;
723f7df2e56Smrg                }
724f7df2e56Smrg            }
725f7df2e56Smrg            if (c->names->nnames == c->current.max_names)
726f7df2e56Smrg                break;
727f7df2e56Smrg        }
72805b261ecSmrg    }
72905b261ecSmrg
73005b261ecSmrg    /*
73105b261ecSmrg     * send the reply
73205b261ecSmrg     */
73305b261ecSmrg    if (err != Successful) {
734f7df2e56Smrg        SendErrorToClient(client, X_ListFonts, 0, 0, FontToXError(err));
735f7df2e56Smrg        goto bail;
73605b261ecSmrg    }
73705b261ecSmrg
738f7df2e56Smrg finish:
73905b261ecSmrg
74005b261ecSmrg    names = c->names;
74105b261ecSmrg    nnames = names->nnames;
74205b261ecSmrg    client = c->client;
74305b261ecSmrg    stringLens = 0;
74405b261ecSmrg    for (i = 0; i < nnames; i++)
745f7df2e56Smrg        stringLens += (names->length[i] <= 255) ? names->length[i] : 0;
74605b261ecSmrg
747f7df2e56Smrg    reply = (xListFontsReply) {
748f7df2e56Smrg        .type = X_Reply,
749f7df2e56Smrg        .length = bytes_to_int32(stringLens + nnames),
750f7df2e56Smrg        .nFonts = nnames,
751f7df2e56Smrg        .sequenceNumber = client->sequence
752f7df2e56Smrg    };
75305b261ecSmrg
7546747b715Smrg    bufptr = bufferStart = malloc(reply.length << 2);
75505b261ecSmrg
75605b261ecSmrg    if (!bufptr && reply.length) {
757f7df2e56Smrg        SendErrorToClient(client, X_ListFonts, 0, 0, BadAlloc);
758f7df2e56Smrg        goto bail;
75905b261ecSmrg    }
76005b261ecSmrg    /*
76105b261ecSmrg     * since WriteToClient long word aligns things, copy to temp buffer and
76205b261ecSmrg     * write all at once
76305b261ecSmrg     */
76405b261ecSmrg    for (i = 0; i < nnames; i++) {
765f7df2e56Smrg        if (names->length[i] > 255)
766f7df2e56Smrg            reply.nFonts--;
767f7df2e56Smrg        else {
768f7df2e56Smrg            *bufptr++ = names->length[i];
769f7df2e56Smrg            memmove(bufptr, names->names[i], names->length[i]);
770f7df2e56Smrg            bufptr += names->length[i];
771f7df2e56Smrg        }
77205b261ecSmrg    }
77305b261ecSmrg    nnames = reply.nFonts;
7746747b715Smrg    reply.length = bytes_to_int32(stringLens + nnames);
77505b261ecSmrg    client->pSwapReplyFunc = ReplySwapVector[X_ListFonts];
77605b261ecSmrg    WriteSwappedDataToClient(client, sizeof(xListFontsReply), &reply);
777f7df2e56Smrg    WriteToClient(client, stringLens + nnames, bufferStart);
7786747b715Smrg    free(bufferStart);
77905b261ecSmrg
780f7df2e56Smrg bail:
7816747b715Smrg    ClientWakeup(client);
78205b261ecSmrg    for (i = 0; i < c->num_fpes; i++)
783f7df2e56Smrg        FreeFPE(c->fpe_list[i]);
7846747b715Smrg    free(c->fpe_list);
7856747b715Smrg    free(c->savedName);
7867e31ba66Smrg    xfont2_free_font_names(names);
7876747b715Smrg    free(c);
7886747b715Smrg    free(resolved);
78905b261ecSmrg    return TRUE;
79005b261ecSmrg}
79105b261ecSmrg
79205b261ecSmrgint
793f7df2e56SmrgListFonts(ClientPtr client, unsigned char *pattern, unsigned length,
79405b261ecSmrg          unsigned max_names)
79505b261ecSmrg{
796f7df2e56Smrg    int i;
79705b261ecSmrg    LFclosurePtr c;
79805b261ecSmrg
799f7df2e56Smrg    /*
80005b261ecSmrg     * The right error to return here would be BadName, however the
80105b261ecSmrg     * specification does not allow for a Name error on this request.
80205b261ecSmrg     * Perhaps a better solution would be to return a nil list, i.e.
80305b261ecSmrg     * a list containing zero fontnames.
80405b261ecSmrg     */
80505b261ecSmrg    if (length > XLFDMAXFONTNAMELEN)
806f7df2e56Smrg        return BadAlloc;
80705b261ecSmrg
8084642e01fSmrg    i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
8094642e01fSmrg    if (i != Success)
810f7df2e56Smrg        return i;
8114642e01fSmrg
8126747b715Smrg    if (!(c = malloc(sizeof *c)))
813f7df2e56Smrg        return BadAlloc;
814f7df2e56Smrg    c->fpe_list = xallocarray(num_fpes, sizeof(FontPathElementPtr));
81505b261ecSmrg    if (!c->fpe_list) {
816f7df2e56Smrg        free(c);
817f7df2e56Smrg        return BadAlloc;
81805b261ecSmrg    }
8197e31ba66Smrg    c->names = xfont2_make_font_names_record(max_names < 100 ? max_names : 100);
820f7df2e56Smrg    if (!c->names) {
821f7df2e56Smrg        free(c->fpe_list);
822f7df2e56Smrg        free(c);
823f7df2e56Smrg        return BadAlloc;
82405b261ecSmrg    }
825f7df2e56Smrg    memmove(c->current.pattern, pattern, length);
82605b261ecSmrg    for (i = 0; i < num_fpes; i++) {
827f7df2e56Smrg        c->fpe_list[i] = font_path_elements[i];
828f7df2e56Smrg        UseFPE(c->fpe_list[i]);
82905b261ecSmrg    }
83005b261ecSmrg    c->client = client;
83105b261ecSmrg    c->num_fpes = num_fpes;
83205b261ecSmrg    c->current.patlen = length;
83305b261ecSmrg    c->current.current_fpe = 0;
83405b261ecSmrg    c->current.max_names = max_names;
83505b261ecSmrg    c->current.list_started = FALSE;
83605b261ecSmrg    c->current.private = 0;
83705b261ecSmrg    c->haveSaved = FALSE;
83805b261ecSmrg    c->savedName = 0;
83905b261ecSmrg    doListFontsAndAliases(client, c);
84005b261ecSmrg    return Success;
84105b261ecSmrg}
84205b261ecSmrg
843f7df2e56Smrgstatic int
84405b261ecSmrgdoListFontsWithInfo(ClientPtr client, LFWIclosurePtr c)
84505b261ecSmrg{
84605b261ecSmrg    FontPathElementPtr fpe;
847f7df2e56Smrg    int err = Successful;
848f7df2e56Smrg    char *name;
849f7df2e56Smrg    int namelen;
850f7df2e56Smrg    int numFonts;
851f7df2e56Smrg    FontInfoRec fontInfo, *pFontInfo;
85205b261ecSmrg    xListFontsWithInfoReply *reply;
853f7df2e56Smrg    int length;
854f7df2e56Smrg    xFontProp *pFP;
855f7df2e56Smrg    int i;
856f7df2e56Smrg    int aliascount = 0;
85705b261ecSmrg    xListFontsWithInfoReply finalReply;
85805b261ecSmrg
859f7df2e56Smrg    if (client->clientGone) {
860f7df2e56Smrg        if (c->current.current_fpe < c->num_fpes) {
861f7df2e56Smrg            fpe = c->fpe_list[c->current.current_fpe];
8627e31ba66Smrg            (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
863f7df2e56Smrg        }
864f7df2e56Smrg        err = Successful;
865f7df2e56Smrg        goto bail;
86605b261ecSmrg    }
86705b261ecSmrg    client->pSwapReplyFunc = ReplySwapVector[X_ListFontsWithInfo];
86805b261ecSmrg    if (!c->current.patlen)
869f7df2e56Smrg        goto finish;
870f7df2e56Smrg    while (c->current.current_fpe < c->num_fpes) {
871f7df2e56Smrg        fpe = c->fpe_list[c->current.current_fpe];
872f7df2e56Smrg        err = Successful;
873f7df2e56Smrg        if (!c->current.list_started) {
8747e31ba66Smrg            err = (*fpe_functions[fpe->type]->start_list_fonts_with_info)
875f7df2e56Smrg                (client, fpe, c->current.pattern, c->current.patlen,
876f7df2e56Smrg                 c->current.max_names, &c->current.private);
877f7df2e56Smrg            if (err == Suspended) {
878f7df2e56Smrg                if (!ClientIsAsleep(client))
879f7df2e56Smrg                    ClientSleep(client,
880f7df2e56Smrg                                (ClientSleepProcPtr) doListFontsWithInfo, c);
881f7df2e56Smrg                return TRUE;
882f7df2e56Smrg            }
883f7df2e56Smrg            if (err == Successful)
884f7df2e56Smrg                c->current.list_started = TRUE;
885f7df2e56Smrg        }
886f7df2e56Smrg        if (err == Successful) {
887f7df2e56Smrg            name = 0;
888f7df2e56Smrg            pFontInfo = &fontInfo;
8897e31ba66Smrg            err = (*fpe_functions[fpe->type]->list_next_font_with_info)
890f7df2e56Smrg                (client, fpe, &name, &namelen, &pFontInfo,
891f7df2e56Smrg                 &numFonts, c->current.private);
892f7df2e56Smrg            if (err == Suspended) {
893f7df2e56Smrg                if (!ClientIsAsleep(client))
894f7df2e56Smrg                    ClientSleep(client,
895f7df2e56Smrg                                (ClientSleepProcPtr) doListFontsWithInfo, c);
896f7df2e56Smrg                return TRUE;
897f7df2e56Smrg            }
898f7df2e56Smrg        }
899f7df2e56Smrg        /*
900f7df2e56Smrg         * When we get an alias back, save our state and reset back to the
901f7df2e56Smrg         * start of the FPE looking for the specified name.  As soon as a real
902f7df2e56Smrg         * font is found for the alias, pop back to the old state
903f7df2e56Smrg         */
904f7df2e56Smrg        if (err == FontNameAlias) {
905f7df2e56Smrg            /*
906f7df2e56Smrg             * when an alias recurses, we need to give
907f7df2e56Smrg             * the last FPE a chance to clean up; so we call
908f7df2e56Smrg             * it again, and assume that the error returned
909f7df2e56Smrg             * is BadFontName, indicating the alias resolution
910f7df2e56Smrg             * is complete.
911f7df2e56Smrg             */
912f7df2e56Smrg            if (c->haveSaved) {
913f7df2e56Smrg                char *tmpname;
914f7df2e56Smrg                int tmpnamelen;
915f7df2e56Smrg                FontInfoPtr tmpFontInfo;
916f7df2e56Smrg
917f7df2e56Smrg                tmpname = 0;
918f7df2e56Smrg                tmpFontInfo = &fontInfo;
9197e31ba66Smrg                (void) (*fpe_functions[fpe->type]->list_next_font_with_info)
920f7df2e56Smrg                    (client, fpe, &tmpname, &tmpnamelen, &tmpFontInfo,
921f7df2e56Smrg                     &numFonts, c->current.private);
922f7df2e56Smrg                if (--aliascount <= 0) {
923f7df2e56Smrg                    err = BadFontName;
924f7df2e56Smrg                    goto ContBadFontName;
925f7df2e56Smrg                }
926f7df2e56Smrg            }
927f7df2e56Smrg            else {
928f7df2e56Smrg                c->saved = c->current;
929f7df2e56Smrg                c->haveSaved = TRUE;
930f7df2e56Smrg                c->savedNumFonts = numFonts;
931f7df2e56Smrg                free(c->savedName);
932f7df2e56Smrg                c->savedName = malloc(namelen + 1);
933f7df2e56Smrg                if (c->savedName)
934f7df2e56Smrg                    memmove(c->savedName, name, namelen + 1);
935f7df2e56Smrg                aliascount = 20;
936f7df2e56Smrg            }
937f7df2e56Smrg            memmove(c->current.pattern, name, namelen);
938f7df2e56Smrg            c->current.patlen = namelen;
939f7df2e56Smrg            c->current.max_names = 1;
940f7df2e56Smrg            c->current.current_fpe = 0;
941f7df2e56Smrg            c->current.private = 0;
942f7df2e56Smrg            c->current.list_started = FALSE;
943f7df2e56Smrg        }
944f7df2e56Smrg        /*
945f7df2e56Smrg         * At the end of this FPE, step to the next.  If we've finished
946f7df2e56Smrg         * processing an alias, pop state back.  If we've sent enough font
947f7df2e56Smrg         * names, quit.  Always wait for BadFontName to let the FPE
948f7df2e56Smrg         * have a chance to clean up.
949f7df2e56Smrg         */
950f7df2e56Smrg        else if (err == BadFontName) {
951f7df2e56Smrg ContBadFontName:;
952f7df2e56Smrg            c->current.list_started = FALSE;
953f7df2e56Smrg            c->current.current_fpe++;
954f7df2e56Smrg            err = Successful;
955f7df2e56Smrg            if (c->haveSaved) {
956f7df2e56Smrg                if (c->current.max_names == 0 ||
957f7df2e56Smrg                    c->current.current_fpe == c->num_fpes) {
958f7df2e56Smrg                    c->haveSaved = FALSE;
959f7df2e56Smrg                    c->saved.max_names -= (1 - c->current.max_names);
960f7df2e56Smrg                    c->current = c->saved;
961f7df2e56Smrg                }
962f7df2e56Smrg            }
963f7df2e56Smrg            else if (c->current.max_names == 0)
964f7df2e56Smrg                break;
965f7df2e56Smrg        }
966f7df2e56Smrg        else if (err == Successful) {
967f7df2e56Smrg            length = sizeof(*reply) + pFontInfo->nprops * sizeof(xFontProp);
968f7df2e56Smrg            reply = c->reply;
969f7df2e56Smrg            if (c->length < length) {
970f7df2e56Smrg                reply = (xListFontsWithInfoReply *) realloc(c->reply, length);
971f7df2e56Smrg                if (!reply) {
972f7df2e56Smrg                    err = AllocError;
973f7df2e56Smrg                    break;
974f7df2e56Smrg                }
975f7df2e56Smrg                memset((char *) reply + c->length, 0, length - c->length);
976f7df2e56Smrg                c->reply = reply;
977f7df2e56Smrg                c->length = length;
978f7df2e56Smrg            }
979f7df2e56Smrg            if (c->haveSaved) {
980f7df2e56Smrg                numFonts = c->savedNumFonts;
981f7df2e56Smrg                name = c->savedName;
982f7df2e56Smrg                namelen = strlen(name);
983f7df2e56Smrg            }
984f7df2e56Smrg            reply->type = X_Reply;
985f7df2e56Smrg            reply->length =
986f7df2e56Smrg                bytes_to_int32(sizeof *reply - sizeof(xGenericReply) +
987f7df2e56Smrg                               pFontInfo->nprops * sizeof(xFontProp) + namelen);
988f7df2e56Smrg            reply->sequenceNumber = client->sequence;
989f7df2e56Smrg            reply->nameLength = namelen;
990f7df2e56Smrg            reply->minBounds = pFontInfo->ink_minbounds;
991f7df2e56Smrg            reply->maxBounds = pFontInfo->ink_maxbounds;
992f7df2e56Smrg            reply->minCharOrByte2 = pFontInfo->firstCol;
993f7df2e56Smrg            reply->maxCharOrByte2 = pFontInfo->lastCol;
994f7df2e56Smrg            reply->defaultChar = pFontInfo->defaultCh;
995f7df2e56Smrg            reply->nFontProps = pFontInfo->nprops;
996f7df2e56Smrg            reply->drawDirection = pFontInfo->drawDirection;
997f7df2e56Smrg            reply->minByte1 = pFontInfo->firstRow;
998f7df2e56Smrg            reply->maxByte1 = pFontInfo->lastRow;
999f7df2e56Smrg            reply->allCharsExist = pFontInfo->allExist;
1000f7df2e56Smrg            reply->fontAscent = pFontInfo->fontAscent;
1001f7df2e56Smrg            reply->fontDescent = pFontInfo->fontDescent;
1002f7df2e56Smrg            reply->nReplies = numFonts;
1003f7df2e56Smrg            pFP = (xFontProp *) (reply + 1);
1004f7df2e56Smrg            for (i = 0; i < pFontInfo->nprops; i++) {
1005f7df2e56Smrg                pFP->name = pFontInfo->props[i].name;
1006f7df2e56Smrg                pFP->value = pFontInfo->props[i].value;
1007f7df2e56Smrg                pFP++;
1008f7df2e56Smrg            }
1009f7df2e56Smrg            WriteSwappedDataToClient(client, length, reply);
1010f7df2e56Smrg            WriteToClient(client, namelen, name);
1011f7df2e56Smrg            if (pFontInfo == &fontInfo) {
1012f7df2e56Smrg                free(fontInfo.props);
1013f7df2e56Smrg                free(fontInfo.isStringProp);
1014f7df2e56Smrg            }
1015f7df2e56Smrg            --c->current.max_names;
1016f7df2e56Smrg        }
1017f7df2e56Smrg    }
1018f7df2e56Smrg finish:
101905b261ecSmrg    length = sizeof(xListFontsWithInfoReply);
1020f7df2e56Smrg    finalReply = (xListFontsWithInfoReply) {
1021f7df2e56Smrg        .type = X_Reply,
1022f7df2e56Smrg        .sequenceNumber = client->sequence,
1023f7df2e56Smrg        .length = bytes_to_int32(sizeof(xListFontsWithInfoReply)
1024f7df2e56Smrg                                 - sizeof(xGenericReply))
1025f7df2e56Smrg    };
102605b261ecSmrg    WriteSwappedDataToClient(client, length, &finalReply);
1027f7df2e56Smrg bail:
10286747b715Smrg    ClientWakeup(client);
102905b261ecSmrg    for (i = 0; i < c->num_fpes; i++)
1030f7df2e56Smrg        FreeFPE(c->fpe_list[i]);
10316747b715Smrg    free(c->reply);
10326747b715Smrg    free(c->fpe_list);
10336747b715Smrg    free(c->savedName);
10346747b715Smrg    free(c);
103505b261ecSmrg    return TRUE;
103605b261ecSmrg}
103705b261ecSmrg
103805b261ecSmrgint
1039f7df2e56SmrgStartListFontsWithInfo(ClientPtr client, int length, unsigned char *pattern,
104005b261ecSmrg                       int max_names)
104105b261ecSmrg{
1042f7df2e56Smrg    int i;
1043f7df2e56Smrg    LFWIclosurePtr c;
104405b261ecSmrg
1045f7df2e56Smrg    /*
104605b261ecSmrg     * The right error to return here would be BadName, however the
104705b261ecSmrg     * specification does not allow for a Name error on this request.
104805b261ecSmrg     * Perhaps a better solution would be to return a nil list, i.e.
104905b261ecSmrg     * a list containing zero fontnames.
105005b261ecSmrg     */
105105b261ecSmrg    if (length > XLFDMAXFONTNAMELEN)
1052f7df2e56Smrg        return BadAlloc;
105305b261ecSmrg
10544642e01fSmrg    i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
10554642e01fSmrg    if (i != Success)
1056f7df2e56Smrg        return i;
10574642e01fSmrg
10586747b715Smrg    if (!(c = malloc(sizeof *c)))
1059f7df2e56Smrg        goto badAlloc;
1060f7df2e56Smrg    c->fpe_list = xallocarray(num_fpes, sizeof(FontPathElementPtr));
1061f7df2e56Smrg    if (!c->fpe_list) {
1062f7df2e56Smrg        free(c);
1063f7df2e56Smrg        goto badAlloc;
106405b261ecSmrg    }
106505b261ecSmrg    memmove(c->current.pattern, pattern, length);
1066f7df2e56Smrg    for (i = 0; i < num_fpes; i++) {
1067f7df2e56Smrg        c->fpe_list[i] = font_path_elements[i];
1068f7df2e56Smrg        UseFPE(c->fpe_list[i]);
106905b261ecSmrg    }
107005b261ecSmrg    c->client = client;
107105b261ecSmrg    c->num_fpes = num_fpes;
107205b261ecSmrg    c->reply = 0;
107305b261ecSmrg    c->length = 0;
107405b261ecSmrg    c->current.patlen = length;
107505b261ecSmrg    c->current.current_fpe = 0;
107605b261ecSmrg    c->current.max_names = max_names;
107705b261ecSmrg    c->current.list_started = FALSE;
107805b261ecSmrg    c->current.private = 0;
107905b261ecSmrg    c->savedNumFonts = 0;
108005b261ecSmrg    c->haveSaved = FALSE;
108105b261ecSmrg    c->savedName = 0;
108205b261ecSmrg    doListFontsWithInfo(client, c);
108305b261ecSmrg    return Success;
1084f7df2e56Smrg badAlloc:
108505b261ecSmrg    return BadAlloc;
108605b261ecSmrg}
108705b261ecSmrg
108805b261ecSmrg#define TextEltHeader 2
108905b261ecSmrg#define FontShiftSize 5
1090f7df2e56Smrgstatic ChangeGCVal clearGC[] = { {.ptr = NullPixmap} };
1091f7df2e56Smrg
109205b261ecSmrg#define clearGCmask (GCClipMask)
109305b261ecSmrg
1094f7df2e56Smrgstatic int
109505b261ecSmrgdoPolyText(ClientPtr client, PTclosurePtr c)
109605b261ecSmrg{
109705b261ecSmrg    FontPtr pFont = c->pGC->font, oldpFont;
1098f7df2e56Smrg    int err = Success, lgerr;   /* err is in X error, not font error, space */
109905b261ecSmrg    enum { NEVER_SLEPT, START_SLEEP, SLEEPING } client_state = NEVER_SLEPT;
110005b261ecSmrg    FontPathElementPtr fpe;
110105b261ecSmrg    GC *origGC = NULL;
11029ace9065Smrg    int itemSize = c->reqType == X_PolyText8 ? 1 : 2;
110305b261ecSmrg
1104f7df2e56Smrg    if (client->clientGone) {
1105f7df2e56Smrg        fpe = c->pGC->font->fpe;
11067e31ba66Smrg        (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
1107f7df2e56Smrg
1108f7df2e56Smrg        if (ClientIsAsleep(client)) {
1109f7df2e56Smrg            /* Client has died, but we cannot bail out right now.  We
1110f7df2e56Smrg               need to clean up after the work we did when going to
11115a112b11Smrg               sleep.  Setting the drawable pointer to 0 makes this
1112f7df2e56Smrg               happen without any attempts to render or perform other
1113f7df2e56Smrg               unnecessary activities.  */
1114f7df2e56Smrg            c->pDraw = (DrawablePtr) 0;
1115f7df2e56Smrg        }
1116f7df2e56Smrg        else {
1117f7df2e56Smrg            err = Success;
1118f7df2e56Smrg            goto bail;
1119f7df2e56Smrg        }
112005b261ecSmrg    }
112105b261ecSmrg
112205b261ecSmrg    /* Make sure our drawable hasn't disappeared while we slept. */
1123f7df2e56Smrg    if (ClientIsAsleep(client) && c->pDraw) {
1124f7df2e56Smrg        DrawablePtr pDraw;
1125f7df2e56Smrg
1126f7df2e56Smrg        dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess);
1127f7df2e56Smrg        if (c->pDraw != pDraw) {
1128f7df2e56Smrg            /* Our drawable has disappeared.  Treat like client died... ask
1129f7df2e56Smrg               the FPE code to clean up after client and avoid further
1130f7df2e56Smrg               rendering while we clean up after ourself.  */
1131f7df2e56Smrg            fpe = c->pGC->font->fpe;
11327e31ba66Smrg            (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
1133f7df2e56Smrg            c->pDraw = (DrawablePtr) 0;
1134f7df2e56Smrg        }
113505b261ecSmrg    }
113605b261ecSmrg
11376747b715Smrg    client_state = ClientIsAsleep(client) ? SLEEPING : NEVER_SLEPT;
113805b261ecSmrg
1139f7df2e56Smrg    while (c->endReq - c->pElt > TextEltHeader) {
1140f7df2e56Smrg        if (*c->pElt == FontChange) {
1141f7df2e56Smrg            Font fid;
1142f7df2e56Smrg
1143f7df2e56Smrg            if (c->endReq - c->pElt < FontShiftSize) {
1144f7df2e56Smrg                err = BadLength;
1145f7df2e56Smrg                goto bail;
1146f7df2e56Smrg            }
1147f7df2e56Smrg
1148f7df2e56Smrg            oldpFont = pFont;
1149f7df2e56Smrg
1150f7df2e56Smrg            fid = ((Font) *(c->pElt + 4))       /* big-endian */
1151f7df2e56Smrg                |((Font) *(c->pElt + 3)) << 8
1152f7df2e56Smrg                | ((Font) *(c->pElt + 2)) << 16 | ((Font) *(c->pElt + 1)) << 24;
1153f7df2e56Smrg            err = dixLookupResourceByType((void **) &pFont, fid, RT_FONT,
1154f7df2e56Smrg                                          client, DixUseAccess);
1155f7df2e56Smrg            if (err != Success) {
1156f7df2e56Smrg                /* restore pFont for step 4 (described below) */
1157f7df2e56Smrg                pFont = oldpFont;
1158f7df2e56Smrg
1159f7df2e56Smrg                /* If we're in START_SLEEP mode, the following step
1160f7df2e56Smrg                   shortens the request...  in the unlikely event that
1161f7df2e56Smrg                   the fid somehow becomes valid before we come through
1162f7df2e56Smrg                   again to actually execute the polytext, which would
1163f7df2e56Smrg                   then mess up our refcounting scheme badly.  */
1164f7df2e56Smrg                c->err = err;
1165f7df2e56Smrg                c->endReq = c->pElt;
1166f7df2e56Smrg
1167f7df2e56Smrg                goto bail;
1168f7df2e56Smrg            }
1169f7df2e56Smrg
1170f7df2e56Smrg            /* Step 3 (described below) on our new font */
1171f7df2e56Smrg            if (client_state == START_SLEEP)
1172f7df2e56Smrg                pFont->refcnt++;
1173f7df2e56Smrg            else {
1174f7df2e56Smrg                if (pFont != c->pGC->font && c->pDraw) {
1175f7df2e56Smrg                    ChangeGCVal val;
1176f7df2e56Smrg
1177f7df2e56Smrg                    val.ptr = pFont;
1178f7df2e56Smrg                    ChangeGC(NullClient, c->pGC, GCFont, &val);
1179f7df2e56Smrg                    ValidateGC(c->pDraw, c->pGC);
1180f7df2e56Smrg                }
1181f7df2e56Smrg
1182f7df2e56Smrg                /* Undo the refcnt++ we performed when going to sleep */
1183f7df2e56Smrg                if (client_state == SLEEPING)
1184f7df2e56Smrg                    (void) CloseFont(c->pGC->font, (Font) 0);
1185f7df2e56Smrg            }
1186f7df2e56Smrg            c->pElt += FontShiftSize;
1187f7df2e56Smrg        }
1188f7df2e56Smrg        else {                  /* print a string */
1189f7df2e56Smrg
1190f7df2e56Smrg            unsigned char *pNextElt;
1191f7df2e56Smrg
1192f7df2e56Smrg            pNextElt = c->pElt + TextEltHeader + (*c->pElt) * itemSize;
1193f7df2e56Smrg            if (pNextElt > c->endReq) {
1194f7df2e56Smrg                err = BadLength;
1195f7df2e56Smrg                goto bail;
1196f7df2e56Smrg            }
1197f7df2e56Smrg            if (client_state == START_SLEEP) {
1198f7df2e56Smrg                c->pElt = pNextElt;
1199f7df2e56Smrg                continue;
1200f7df2e56Smrg            }
1201f7df2e56Smrg            if (c->pDraw) {
1202f7df2e56Smrg                lgerr = LoadGlyphs(client, c->pGC->font, *c->pElt, itemSize,
1203f7df2e56Smrg                                   c->pElt + TextEltHeader);
1204f7df2e56Smrg            }
1205f7df2e56Smrg            else
1206f7df2e56Smrg                lgerr = Successful;
1207f7df2e56Smrg
1208f7df2e56Smrg            if (lgerr == Suspended) {
1209f7df2e56Smrg                if (!ClientIsAsleep(client)) {
1210f7df2e56Smrg                    int len;
1211f7df2e56Smrg                    GC *pGC;
1212f7df2e56Smrg                    PTclosurePtr new_closure;
1213f7df2e56Smrg
1214f7df2e56Smrg                    /*  We're putting the client to sleep.  We need to do a few things
1215f7df2e56Smrg                       to ensure successful and atomic-appearing execution of the
1216f7df2e56Smrg                       remainder of the request.  First, copy the remainder of the
1217f7df2e56Smrg                       request into a safe malloc'd area.  Second, create a scratch GC
1218f7df2e56Smrg                       to use for the remainder of the request.  Third, mark all fonts
1219f7df2e56Smrg                       referenced in the remainder of the request to prevent their
1220f7df2e56Smrg                       deallocation.  Fourth, make the original GC look like the
1221f7df2e56Smrg                       request has completed...  set its font to the final font value
1222f7df2e56Smrg                       from this request.  These GC manipulations are for the unlikely
1223f7df2e56Smrg                       (but possible) event that some other client is using the GC.
1224f7df2e56Smrg                       Steps 3 and 4 are performed by running this procedure through
1225f7df2e56Smrg                       the remainder of the request in a special no-render mode
1226f7df2e56Smrg                       indicated by client_state = START_SLEEP.  */
1227f7df2e56Smrg
1228f7df2e56Smrg                    /* Step 1 */
1229f7df2e56Smrg                    /* Allocate a malloc'd closure structure to replace
1230f7df2e56Smrg                       the local one we were passed */
1231f7df2e56Smrg                    new_closure = malloc(sizeof(PTclosureRec));
1232f7df2e56Smrg                    if (!new_closure) {
1233f7df2e56Smrg                        err = BadAlloc;
1234f7df2e56Smrg                        goto bail;
1235f7df2e56Smrg                    }
1236f7df2e56Smrg                    *new_closure = *c;
1237f7df2e56Smrg
1238f7df2e56Smrg                    len = new_closure->endReq - new_closure->pElt;
1239f7df2e56Smrg                    new_closure->data = malloc(len);
1240f7df2e56Smrg                    if (!new_closure->data) {
1241f7df2e56Smrg                        free(new_closure);
1242f7df2e56Smrg                        err = BadAlloc;
1243f7df2e56Smrg                        goto bail;
1244f7df2e56Smrg                    }
1245f7df2e56Smrg                    memmove(new_closure->data, new_closure->pElt, len);
1246f7df2e56Smrg                    new_closure->pElt = new_closure->data;
1247f7df2e56Smrg                    new_closure->endReq = new_closure->pElt + len;
1248f7df2e56Smrg
1249f7df2e56Smrg                    /* Step 2 */
1250f7df2e56Smrg
1251f7df2e56Smrg                    pGC =
1252f7df2e56Smrg                        GetScratchGC(new_closure->pGC->depth,
1253f7df2e56Smrg                                     new_closure->pGC->pScreen);
1254f7df2e56Smrg                    if (!pGC) {
1255f7df2e56Smrg                        free(new_closure->data);
1256f7df2e56Smrg                        free(new_closure);
1257f7df2e56Smrg                        err = BadAlloc;
1258f7df2e56Smrg                        goto bail;
1259f7df2e56Smrg                    }
1260f7df2e56Smrg                    if ((err = CopyGC(new_closure->pGC, pGC, GCFunction |
1261f7df2e56Smrg                                      GCPlaneMask | GCForeground |
1262f7df2e56Smrg                                      GCBackground | GCFillStyle |
1263f7df2e56Smrg                                      GCTile | GCStipple |
1264f7df2e56Smrg                                      GCTileStipXOrigin |
1265f7df2e56Smrg                                      GCTileStipYOrigin | GCFont |
1266f7df2e56Smrg                                      GCSubwindowMode | GCClipXOrigin |
1267f7df2e56Smrg                                      GCClipYOrigin | GCClipMask)) != Success) {
1268f7df2e56Smrg                        FreeScratchGC(pGC);
1269f7df2e56Smrg                        free(new_closure->data);
1270f7df2e56Smrg                        free(new_closure);
1271f7df2e56Smrg                        err = BadAlloc;
1272f7df2e56Smrg                        goto bail;
1273f7df2e56Smrg                    }
1274f7df2e56Smrg                    c = new_closure;
1275f7df2e56Smrg                    origGC = c->pGC;
1276f7df2e56Smrg                    c->pGC = pGC;
1277f7df2e56Smrg                    ValidateGC(c->pDraw, c->pGC);
1278f7df2e56Smrg
1279f7df2e56Smrg                    ClientSleep(client, (ClientSleepProcPtr) doPolyText, c);
1280f7df2e56Smrg
1281f7df2e56Smrg                    /* Set up to perform steps 3 and 4 */
1282f7df2e56Smrg                    client_state = START_SLEEP;
1283f7df2e56Smrg                    continue;   /* on to steps 3 and 4 */
1284f7df2e56Smrg                }
1285f7df2e56Smrg                return TRUE;
1286f7df2e56Smrg            }
1287f7df2e56Smrg            else if (lgerr != Successful) {
1288f7df2e56Smrg                err = FontToXError(lgerr);
1289f7df2e56Smrg                goto bail;
1290f7df2e56Smrg            }
1291f7df2e56Smrg            if (c->pDraw) {
1292f7df2e56Smrg                c->xorg += *((INT8 *) (c->pElt + 1));   /* must be signed */
1293f7df2e56Smrg                if (c->reqType == X_PolyText8)
1294f7df2e56Smrg                    c->xorg =
1295f7df2e56Smrg                        (*c->pGC->ops->PolyText8) (c->pDraw, c->pGC, c->xorg,
1296f7df2e56Smrg                                                   c->yorg, *c->pElt,
1297f7df2e56Smrg                                                   (char *) (c->pElt +
1298f7df2e56Smrg                                                             TextEltHeader));
1299f7df2e56Smrg                else
1300f7df2e56Smrg                    c->xorg =
1301f7df2e56Smrg                        (*c->pGC->ops->PolyText16) (c->pDraw, c->pGC, c->xorg,
1302f7df2e56Smrg                                                    c->yorg, *c->pElt,
1303f7df2e56Smrg                                                    (unsigned short *) (c->
1304f7df2e56Smrg                                                                        pElt +
1305f7df2e56Smrg                                                                        TextEltHeader));
1306f7df2e56Smrg            }
1307f7df2e56Smrg            c->pElt = pNextElt;
1308f7df2e56Smrg        }
1309f7df2e56Smrg    }
1310f7df2e56Smrg
1311f7df2e56Smrg bail:
1312f7df2e56Smrg
1313f7df2e56Smrg    if (client_state == START_SLEEP) {
1314f7df2e56Smrg        /* Step 4 */
1315f7df2e56Smrg        if (pFont != origGC->font) {
1316f7df2e56Smrg            ChangeGCVal val;
1317f7df2e56Smrg
1318f7df2e56Smrg            val.ptr = pFont;
1319f7df2e56Smrg            ChangeGC(NullClient, origGC, GCFont, &val);
1320f7df2e56Smrg            ValidateGC(c->pDraw, origGC);
1321f7df2e56Smrg        }
1322f7df2e56Smrg
1323f7df2e56Smrg        /* restore pElt pointer for execution of remainder of the request */
1324f7df2e56Smrg        c->pElt = c->data;
1325f7df2e56Smrg        return TRUE;
1326f7df2e56Smrg    }
1327f7df2e56Smrg
1328f7df2e56Smrg    if (c->err != Success)
1329f7df2e56Smrg        err = c->err;
133005b261ecSmrg    if (err != Success && c->client != serverClient) {
133105b261ecSmrg#ifdef PANORAMIX
133205b261ecSmrg        if (noPanoramiXExtension || !c->pGC->pScreen->myNum)
133305b261ecSmrg#endif
1334f7df2e56Smrg            SendErrorToClient(c->client, c->reqType, 0, 0, err);
133505b261ecSmrg    }
1336f7df2e56Smrg    if (ClientIsAsleep(client)) {
1337f7df2e56Smrg        ClientWakeup(c->client);
1338f7df2e56Smrg        ChangeGC(NullClient, c->pGC, clearGCmask, clearGC);
133905b261ecSmrg
1340f7df2e56Smrg        /* Unreference the font from the scratch GC */
1341f7df2e56Smrg        CloseFont(c->pGC->font, (Font) 0);
1342f7df2e56Smrg        c->pGC->font = NullFont;
134305b261ecSmrg
1344f7df2e56Smrg        FreeScratchGC(c->pGC);
1345f7df2e56Smrg        free(c->data);
1346f7df2e56Smrg        free(c);
134705b261ecSmrg    }
134805b261ecSmrg    return TRUE;
134905b261ecSmrg}
135005b261ecSmrg
135105b261ecSmrgint
1352f7df2e56SmrgPolyText(ClientPtr client, DrawablePtr pDraw, GC * pGC, unsigned char *pElt,
135305b261ecSmrg         unsigned char *endReq, int xorg, int yorg, int reqType, XID did)
135405b261ecSmrg{
135559ca590cSmrg    PTclosureRec local_closure = {
135659ca590cSmrg        .client = client,
135759ca590cSmrg        .pDraw = pDraw,
135859ca590cSmrg        .pGC = pGC,
135959ca590cSmrg        .pElt = pElt,
136059ca590cSmrg        .endReq = endReq,
136159ca590cSmrg        .xorg = xorg,
136259ca590cSmrg        .yorg = yorg,
136359ca590cSmrg        .reqType = reqType,
136459ca590cSmrg        .did = did,
136559ca590cSmrg        .err = Success
136659ca590cSmrg    };
136705b261ecSmrg
136805b261ecSmrg    (void) doPolyText(client, &local_closure);
136905b261ecSmrg    return Success;
137005b261ecSmrg}
137105b261ecSmrg
137205b261ecSmrg#undef TextEltHeader
137305b261ecSmrg#undef FontShiftSize
137405b261ecSmrg
1375f7df2e56Smrgstatic int
137605b261ecSmrgdoImageText(ClientPtr client, ITclosurePtr c)
137705b261ecSmrg{
1378f7df2e56Smrg    int err = Success, lgerr;   /* err is in X error, not font error, space */
137905b261ecSmrg    FontPathElementPtr fpe;
13809ace9065Smrg    int itemSize = c->reqType == X_ImageText8 ? 1 : 2;
138105b261ecSmrg
1382f7df2e56Smrg    if (client->clientGone) {
1383f7df2e56Smrg        fpe = c->pGC->font->fpe;
13847e31ba66Smrg        (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
1385f7df2e56Smrg        err = Success;
1386f7df2e56Smrg        goto bail;
138705b261ecSmrg    }
138805b261ecSmrg
138905b261ecSmrg    /* Make sure our drawable hasn't disappeared while we slept. */
1390f7df2e56Smrg    if (ClientIsAsleep(client) && c->pDraw) {
1391f7df2e56Smrg        DrawablePtr pDraw;
1392f7df2e56Smrg
1393f7df2e56Smrg        dixLookupDrawable(&pDraw, c->did, client, 0, DixWriteAccess);
1394f7df2e56Smrg        if (c->pDraw != pDraw) {
1395f7df2e56Smrg            /* Our drawable has disappeared.  Treat like client died... ask
1396f7df2e56Smrg               the FPE code to clean up after client. */
1397f7df2e56Smrg            fpe = c->pGC->font->fpe;
13987e31ba66Smrg            (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
1399f7df2e56Smrg            err = Success;
1400f7df2e56Smrg            goto bail;
1401f7df2e56Smrg        }
140205b261ecSmrg    }
140305b261ecSmrg
14049ace9065Smrg    lgerr = LoadGlyphs(client, c->pGC->font, c->nChars, itemSize, c->data);
1405f7df2e56Smrg    if (lgerr == Suspended) {
14066747b715Smrg        if (!ClientIsAsleep(client)) {
1407f7df2e56Smrg            GC *pGC;
1408f7df2e56Smrg            unsigned char *data;
1409f7df2e56Smrg            ITclosurePtr new_closure;
14102717a907Sspz            ITclosurePtr old_closure;
141105b261ecSmrg
1412f7df2e56Smrg            /* We're putting the client to sleep.  We need to
1413f7df2e56Smrg               save some state.  Similar problem to that handled
1414f7df2e56Smrg               in doPolyText, but much simpler because the
1415f7df2e56Smrg               request structure is much simpler. */
1416f7df2e56Smrg
1417f7df2e56Smrg            new_closure = malloc(sizeof(ITclosureRec));
1418f7df2e56Smrg            if (!new_closure) {
1419f7df2e56Smrg                err = BadAlloc;
1420f7df2e56Smrg                goto bail;
1421f7df2e56Smrg            }
14222717a907Sspz            old_closure = c;
1423f7df2e56Smrg            *new_closure = *c;
1424f7df2e56Smrg            c = new_closure;
142505b261ecSmrg
1426f7df2e56Smrg            data = xallocarray(c->nChars, itemSize);
1427f7df2e56Smrg            if (!data) {
1428f7df2e56Smrg                free(c);
14292717a907Sspz                c = old_closure;
1430f7df2e56Smrg                err = BadAlloc;
1431f7df2e56Smrg                goto bail;
1432f7df2e56Smrg            }
1433f7df2e56Smrg            memmove(data, c->data, c->nChars * itemSize);
1434f7df2e56Smrg            c->data = data;
1435f7df2e56Smrg
1436f7df2e56Smrg            pGC = GetScratchGC(c->pGC->depth, c->pGC->pScreen);
1437f7df2e56Smrg            if (!pGC) {
1438f7df2e56Smrg                free(c->data);
1439f7df2e56Smrg                free(c);
14402717a907Sspz                c = old_closure;
1441f7df2e56Smrg                err = BadAlloc;
1442f7df2e56Smrg                goto bail;
1443f7df2e56Smrg            }
1444f7df2e56Smrg            if ((err = CopyGC(c->pGC, pGC, GCFunction | GCPlaneMask |
1445f7df2e56Smrg                              GCForeground | GCBackground | GCFillStyle |
1446f7df2e56Smrg                              GCTile | GCStipple | GCTileStipXOrigin |
1447f7df2e56Smrg                              GCTileStipYOrigin | GCFont |
1448f7df2e56Smrg                              GCSubwindowMode | GCClipXOrigin |
1449f7df2e56Smrg                              GCClipYOrigin | GCClipMask)) != Success) {
1450f7df2e56Smrg                FreeScratchGC(pGC);
1451f7df2e56Smrg                free(c->data);
1452f7df2e56Smrg                free(c);
14532717a907Sspz                c = old_closure;
1454f7df2e56Smrg                err = BadAlloc;
1455f7df2e56Smrg                goto bail;
1456f7df2e56Smrg            }
1457f7df2e56Smrg            c->pGC = pGC;
1458f7df2e56Smrg            ValidateGC(c->pDraw, c->pGC);
145905b261ecSmrg
1460f7df2e56Smrg            ClientSleep(client, (ClientSleepProcPtr) doImageText, c);
146105b261ecSmrg        }
146205b261ecSmrg        return TRUE;
146305b261ecSmrg    }
1464f7df2e56Smrg    else if (lgerr != Successful) {
146505b261ecSmrg        err = FontToXError(lgerr);
146605b261ecSmrg        goto bail;
146705b261ecSmrg    }
1468f7df2e56Smrg    if (c->pDraw) {
1469f7df2e56Smrg        if (c->reqType == X_ImageText8)
1470f7df2e56Smrg            (*c->pGC->ops->ImageText8) (c->pDraw, c->pGC, c->xorg, c->yorg,
1471f7df2e56Smrg                                        c->nChars, (char *) c->data);
1472f7df2e56Smrg        else
1473f7df2e56Smrg            (*c->pGC->ops->ImageText16) (c->pDraw, c->pGC, c->xorg, c->yorg,
1474f7df2e56Smrg                                         c->nChars, (unsigned short *) c->data);
147505b261ecSmrg    }
147605b261ecSmrg
1477f7df2e56Smrg bail:
147805b261ecSmrg
147905b261ecSmrg    if (err != Success && c->client != serverClient) {
1480f7df2e56Smrg        SendErrorToClient(c->client, c->reqType, 0, 0, err);
148105b261ecSmrg    }
1482f7df2e56Smrg    if (ClientIsAsleep(client)) {
1483f7df2e56Smrg        ClientWakeup(c->client);
1484f7df2e56Smrg        ChangeGC(NullClient, c->pGC, clearGCmask, clearGC);
148505b261ecSmrg
1486f7df2e56Smrg        /* Unreference the font from the scratch GC */
1487f7df2e56Smrg        CloseFont(c->pGC->font, (Font) 0);
1488f7df2e56Smrg        c->pGC->font = NullFont;
148905b261ecSmrg
1490f7df2e56Smrg        FreeScratchGC(c->pGC);
1491f7df2e56Smrg        free(c->data);
1492f7df2e56Smrg        free(c);
149305b261ecSmrg    }
149405b261ecSmrg    return TRUE;
149505b261ecSmrg}
149605b261ecSmrg
149705b261ecSmrgint
1498f7df2e56SmrgImageText(ClientPtr client, DrawablePtr pDraw, GC * pGC, int nChars,
149905b261ecSmrg          unsigned char *data, int xorg, int yorg, int reqType, XID did)
150005b261ecSmrg{
150105b261ecSmrg    ITclosureRec local_closure;
150205b261ecSmrg
150305b261ecSmrg    local_closure.client = client;
150405b261ecSmrg    local_closure.pDraw = pDraw;
150505b261ecSmrg    local_closure.pGC = pGC;
150605b261ecSmrg    local_closure.nChars = nChars;
150705b261ecSmrg    local_closure.data = data;
150805b261ecSmrg    local_closure.xorg = xorg;
150905b261ecSmrg    local_closure.yorg = yorg;
15109ace9065Smrg    local_closure.reqType = reqType;
151105b261ecSmrg    local_closure.did = did;
151205b261ecSmrg
151305b261ecSmrg    (void) doImageText(client, &local_closure);
151405b261ecSmrg    return Success;
151505b261ecSmrg}
151605b261ecSmrg
151705b261ecSmrg/* does the necessary magic to figure out the fpe type */
151805b261ecSmrgstatic int
1519f7df2e56SmrgDetermineFPEType(const char *pathname)
152005b261ecSmrg{
1521f7df2e56Smrg    int i;
152205b261ecSmrg
152305b261ecSmrg    for (i = 0; i < num_fpe_types; i++) {
15247e31ba66Smrg        if ((*fpe_functions[i]->name_check) (pathname))
1525f7df2e56Smrg            return i;
152605b261ecSmrg    }
152705b261ecSmrg    return -1;
152805b261ecSmrg}
152905b261ecSmrg
153005b261ecSmrgstatic void
1531f7df2e56SmrgFreeFontPath(FontPathElementPtr * list, int n, Bool force)
153205b261ecSmrg{
1533f7df2e56Smrg    int i;
153405b261ecSmrg
153505b261ecSmrg    for (i = 0; i < n; i++) {
1536f7df2e56Smrg        if (force) {
1537f7df2e56Smrg            /* Sanity check that all refcounts will be 0 by the time
1538f7df2e56Smrg               we get to the end of the list. */
1539f7df2e56Smrg            int found = 1;      /* the first reference is us */
1540f7df2e56Smrg            int j;
1541f7df2e56Smrg
1542f7df2e56Smrg            for (j = i + 1; j < n; j++) {
1543f7df2e56Smrg                if (list[j] == list[i])
1544f7df2e56Smrg                    found++;
1545f7df2e56Smrg            }
1546f7df2e56Smrg            if (list[i]->refcount != found) {
1547f7df2e56Smrg                list[i]->refcount = found;      /* ensure it will get freed */
1548f7df2e56Smrg            }
1549f7df2e56Smrg        }
1550f7df2e56Smrg        FreeFPE(list[i]);
155105b261ecSmrg    }
15526747b715Smrg    free(list);
155305b261ecSmrg}
155405b261ecSmrg
155505b261ecSmrgstatic FontPathElementPtr
1556f7df2e56Smrgfind_existing_fpe(FontPathElementPtr * list, int num, unsigned char *name,
1557f7df2e56Smrg                  int len)
155805b261ecSmrg{
155905b261ecSmrg    FontPathElementPtr fpe;
1560f7df2e56Smrg    int i;
156105b261ecSmrg
156205b261ecSmrg    for (i = 0; i < num; i++) {
1563f7df2e56Smrg        fpe = list[i];
1564f7df2e56Smrg        if (fpe->name_length == len && memcmp(name, fpe->name, len) == 0)
1565f7df2e56Smrg            return fpe;
156605b261ecSmrg    }
156705b261ecSmrg    return (FontPathElementPtr) 0;
156805b261ecSmrg}
156905b261ecSmrg
157005b261ecSmrgstatic int
157105b261ecSmrgSetFontPathElements(int npaths, unsigned char *paths, int *bad, Bool persist)
157205b261ecSmrg{
1573f7df2e56Smrg    int i, err = 0;
1574f7df2e56Smrg    int valid_paths = 0;
157505b261ecSmrg    unsigned int len;
157605b261ecSmrg    unsigned char *cp = paths;
157705b261ecSmrg    FontPathElementPtr fpe = NULL, *fplist;
157805b261ecSmrg
1579f7df2e56Smrg    fplist = xallocarray(npaths, sizeof(FontPathElementPtr));
158005b261ecSmrg    if (!fplist) {
1581f7df2e56Smrg        *bad = 0;
1582f7df2e56Smrg        return BadAlloc;
158305b261ecSmrg    }
158405b261ecSmrg    for (i = 0; i < num_fpe_types; i++) {
15857e31ba66Smrg        if (fpe_functions[i]->set_path_hook)
15867e31ba66Smrg            (*fpe_functions[i]->set_path_hook) ();
1587f7df2e56Smrg    }
1588f7df2e56Smrg    for (i = 0; i < npaths; i++) {
1589f7df2e56Smrg        len = (unsigned int) (*cp++);
1590f7df2e56Smrg
1591f7df2e56Smrg        if (len == 0) {
1592f7df2e56Smrg            if (persist)
1593f7df2e56Smrg                ErrorF
1594f7df2e56Smrg                    ("[dix] Removing empty element from the valid list of fontpaths\n");
1595f7df2e56Smrg            err = BadValue;
1596f7df2e56Smrg        }
1597f7df2e56Smrg        else {
1598f7df2e56Smrg            /* if it's already in our active list, just reset it */
1599f7df2e56Smrg            /*
1600f7df2e56Smrg             * note that this can miss FPE's in limbo -- may be worth catching
1601f7df2e56Smrg             * them, though it'd muck up refcounting
1602f7df2e56Smrg             */
1603f7df2e56Smrg            fpe = find_existing_fpe(font_path_elements, num_fpes, cp, len);
1604f7df2e56Smrg            if (fpe) {
16057e31ba66Smrg                err = (*fpe_functions[fpe->type]->reset_fpe) (fpe);
1606f7df2e56Smrg                if (err == Successful) {
1607f7df2e56Smrg                    UseFPE(fpe);        /* since it'll be decref'd later when freed
1608f7df2e56Smrg                                         * from the old list */
1609f7df2e56Smrg                }
1610f7df2e56Smrg                else
1611f7df2e56Smrg                    fpe = 0;
1612f7df2e56Smrg            }
1613f7df2e56Smrg            /* if error or can't do it, act like it's a new one */
1614f7df2e56Smrg            if (!fpe) {
1615f7df2e56Smrg                char *name;
1616f7df2e56Smrg                fpe = malloc(sizeof(FontPathElementRec));
1617f7df2e56Smrg                if (!fpe) {
1618f7df2e56Smrg                    err = BadAlloc;
1619f7df2e56Smrg                    goto bail;
1620f7df2e56Smrg                }
1621f7df2e56Smrg                name = malloc(len + 1);
1622f7df2e56Smrg                if (!name) {
1623f7df2e56Smrg                    free(fpe);
1624f7df2e56Smrg                    err = BadAlloc;
1625f7df2e56Smrg                    goto bail;
1626f7df2e56Smrg                }
1627f7df2e56Smrg                fpe->refcount = 1;
1628f7df2e56Smrg
1629f7df2e56Smrg                strncpy(name, (char *) cp, (int) len);
1630f7df2e56Smrg                name[len] = '\0';
1631f7df2e56Smrg                fpe->name = name;
1632f7df2e56Smrg                fpe->name_length = len;
1633f7df2e56Smrg                fpe->type = DetermineFPEType(fpe->name);
1634f7df2e56Smrg                if (fpe->type == -1)
1635f7df2e56Smrg                    err = BadValue;
1636f7df2e56Smrg                else
16377e31ba66Smrg                    err = (*fpe_functions[fpe->type]->init_fpe) (fpe);
1638f7df2e56Smrg                if (err != Successful) {
1639f7df2e56Smrg                    if (persist) {
1640f7df2e56Smrg                        DebugF
1641f7df2e56Smrg                            ("[dix] Could not init font path element %s, removing from list!\n",
1642f7df2e56Smrg                             fpe->name);
1643f7df2e56Smrg                    }
1644f7df2e56Smrg                    free((void *) fpe->name);
1645f7df2e56Smrg                    free(fpe);
1646f7df2e56Smrg                }
1647f7df2e56Smrg            }
1648f7df2e56Smrg        }
1649f7df2e56Smrg        if (err != Successful) {
1650f7df2e56Smrg            if (!persist)
1651f7df2e56Smrg                goto bail;
1652f7df2e56Smrg        }
1653f7df2e56Smrg        else {
1654f7df2e56Smrg            fplist[valid_paths++] = fpe;
1655f7df2e56Smrg        }
1656f7df2e56Smrg        cp += len;
165705b261ecSmrg    }
165805b261ecSmrg
165905b261ecSmrg    FreeFontPath(font_path_elements, num_fpes, FALSE);
166005b261ecSmrg    font_path_elements = fplist;
166105b261ecSmrg    if (patternCache)
16627e31ba66Smrg        xfont2_empty_font_pattern_cache(patternCache);
166305b261ecSmrg    num_fpes = valid_paths;
166405b261ecSmrg
166505b261ecSmrg    return Success;
1666f7df2e56Smrg bail:
166705b261ecSmrg    *bad = i;
166805b261ecSmrg    while (--valid_paths >= 0)
1669f7df2e56Smrg        FreeFPE(fplist[valid_paths]);
16706747b715Smrg    free(fplist);
167105b261ecSmrg    return FontToXError(err);
167205b261ecSmrg}
167305b261ecSmrg
167405b261ecSmrgint
16756747b715SmrgSetFontPath(ClientPtr client, int npaths, unsigned char *paths)
167605b261ecSmrg{
16774642e01fSmrg    int err = XaceHook(XACE_SERVER_ACCESS, client, DixManageAccess);
1678f7df2e56Smrg
16794642e01fSmrg    if (err != Success)
1680f7df2e56Smrg        return err;
168105b261ecSmrg
168205b261ecSmrg    if (npaths == 0) {
1683f7df2e56Smrg        if (SetDefaultFontPath(defaultFontPath) != Success)
1684f7df2e56Smrg            return BadValue;
1685f7df2e56Smrg    }
1686f7df2e56Smrg    else {
1687f7df2e56Smrg        int bad;
1688f7df2e56Smrg
1689f7df2e56Smrg        err = SetFontPathElements(npaths, paths, &bad, FALSE);
169059ca590cSmrg        if (err != Success)
169159ca590cSmrg            client->errorValue = bad;
169205b261ecSmrg    }
169305b261ecSmrg    return err;
169405b261ecSmrg}
169505b261ecSmrg
169605b261ecSmrgint
1697f7df2e56SmrgSetDefaultFontPath(const char *path)
169805b261ecSmrg{
1699f7df2e56Smrg    const char *start, *end;
1700f7df2e56Smrg    char *temp_path;
1701f7df2e56Smrg    unsigned char *cp, *pp, *nump, *newpath;
1702f7df2e56Smrg    int num = 1, len, err, size = 0, bad;
170305b261ecSmrg
1704b1d344b3Smrg    /* ensure temp_path contains "built-ins" */
1705b1d344b3Smrg    start = path;
1706b1d344b3Smrg    while (1) {
1707f7df2e56Smrg        start = strstr(start, "built-ins");
1708f7df2e56Smrg        if (start == NULL)
1709f7df2e56Smrg            break;
1710f7df2e56Smrg        end = start + strlen("built-ins");
1711f7df2e56Smrg        if ((start == path || start[-1] == ',') && (!*end || *end == ','))
1712f7df2e56Smrg            break;
1713f7df2e56Smrg        start = end;
1714b1d344b3Smrg    }
1715b1d344b3Smrg    if (!start) {
1716f7df2e56Smrg        if (asprintf(&temp_path, "%s%sbuilt-ins", path, *path ? "," : "")
1717f7df2e56Smrg            == -1)
1718f7df2e56Smrg            temp_path = NULL;
1719f7df2e56Smrg    }
1720f7df2e56Smrg    else {
1721f7df2e56Smrg        temp_path = strdup(path);
1722b1d344b3Smrg    }
1723b1d344b3Smrg    if (!temp_path)
1724b1d344b3Smrg        return BadAlloc;
1725b1d344b3Smrg
172605b261ecSmrg    /* get enough for string, plus values -- use up commas */
1727b1d344b3Smrg    len = strlen(temp_path) + 1;
17286747b715Smrg    nump = cp = newpath = malloc(len);
17299ace9065Smrg    if (!newpath) {
1730f7df2e56Smrg        free(temp_path);
1731f7df2e56Smrg        return BadAlloc;
17329ace9065Smrg    }
1733b1d344b3Smrg    pp = (unsigned char *) temp_path;
173405b261ecSmrg    cp++;
173505b261ecSmrg    while (*pp) {
1736f7df2e56Smrg        if (*pp == ',') {
1737f7df2e56Smrg            *nump = (unsigned char) size;
1738f7df2e56Smrg            nump = cp++;
1739f7df2e56Smrg            pp++;
1740f7df2e56Smrg            num++;
1741f7df2e56Smrg            size = 0;
1742f7df2e56Smrg        }
1743f7df2e56Smrg        else {
1744f7df2e56Smrg            *cp++ = *pp++;
1745f7df2e56Smrg            size++;
1746f7df2e56Smrg        }
174705b261ecSmrg    }
174805b261ecSmrg    *nump = (unsigned char) size;
174905b261ecSmrg
175005b261ecSmrg    err = SetFontPathElements(num, newpath, &bad, TRUE);
175105b261ecSmrg
17526747b715Smrg    free(newpath);
17536747b715Smrg    free(temp_path);
175405b261ecSmrg
175505b261ecSmrg    return err;
175605b261ecSmrg}
175705b261ecSmrg
17584642e01fSmrgint
17594642e01fSmrgGetFontPath(ClientPtr client, int *count, int *length, unsigned char **result)
176005b261ecSmrg{
1761f7df2e56Smrg    int i;
1762f7df2e56Smrg    unsigned char *c;
1763f7df2e56Smrg    int len;
1764f7df2e56Smrg    FontPathElementPtr fpe;
176505b261ecSmrg
17664642e01fSmrg    i = XaceHook(XACE_SERVER_ACCESS, client, DixGetAttrAccess);
17674642e01fSmrg    if (i != Success)
1768f7df2e56Smrg        return i;
17694642e01fSmrg
177005b261ecSmrg    len = 0;
177105b261ecSmrg    for (i = 0; i < num_fpes; i++) {
1772f7df2e56Smrg        fpe = font_path_elements[i];
1773f7df2e56Smrg        len += fpe->name_length + 1;
1774f7df2e56Smrg    }
1775f7df2e56Smrg    c = realloc(font_path_string, len);
1776f7df2e56Smrg    if (c == NULL) {
1777f7df2e56Smrg        free(font_path_string);
1778f7df2e56Smrg        font_path_string = NULL;
1779f7df2e56Smrg        return BadAlloc;
178005b261ecSmrg    }
178105b261ecSmrg
1782f7df2e56Smrg    font_path_string = c;
178305b261ecSmrg    *length = 0;
178405b261ecSmrg    for (i = 0; i < num_fpes; i++) {
1785f7df2e56Smrg        fpe = font_path_elements[i];
1786f7df2e56Smrg        *c = fpe->name_length;
1787f7df2e56Smrg        *length += *c++;
1788f7df2e56Smrg        memmove(c, fpe->name, fpe->name_length);
1789f7df2e56Smrg        c += fpe->name_length;
179005b261ecSmrg    }
179105b261ecSmrg    *count = num_fpes;
17924642e01fSmrg    *result = font_path_string;
17934642e01fSmrg    return Success;
179405b261ecSmrg}
179505b261ecSmrg
179605b261ecSmrgvoid
179705b261ecSmrgDeleteClientFontStuff(ClientPtr client)
179805b261ecSmrg{
1799f7df2e56Smrg    int i;
1800f7df2e56Smrg    FontPathElementPtr fpe;
180105b261ecSmrg
1802f7df2e56Smrg    for (i = 0; i < num_fpes; i++) {
1803f7df2e56Smrg        fpe = font_path_elements[i];
18047e31ba66Smrg        if (fpe_functions[fpe->type]->client_died)
18057e31ba66Smrg            (*fpe_functions[fpe->type]->client_died) ((void *) client, fpe);
180605b261ecSmrg    }
180705b261ecSmrg}
180805b261ecSmrg
18097e31ba66Smrgstatic int
18107e31ba66Smrgregister_fpe_funcs(const xfont2_fpe_funcs_rec *funcs)
181105b261ecSmrg{
18127e31ba66Smrg    xfont2_fpe_funcs_rec const **new;
181305b261ecSmrg
18147e31ba66Smrg    /* grow the list */
18157e31ba66Smrg    new = reallocarray(fpe_functions, num_fpe_types + 1, sizeof(xfont2_fpe_funcs_ptr));
18167e31ba66Smrg    if (!new)
18177e31ba66Smrg        return -1;
18187e31ba66Smrg    fpe_functions = new;
18197e31ba66Smrg
18207e31ba66Smrg    fpe_functions[num_fpe_types] = funcs;
18217e31ba66Smrg
18227e31ba66Smrg    return num_fpe_types++;
182305b261ecSmrg}
182405b261ecSmrg
18257e31ba66Smrgstatic unsigned long
18267e31ba66Smrgget_server_generation(void)
18277e31ba66Smrg{
18287e31ba66Smrg    return serverGeneration;
18297e31ba66Smrg}
18307e31ba66Smrg
18317e31ba66Smrgstatic void *
18327e31ba66Smrgget_server_client(void)
18337e31ba66Smrg{
18347e31ba66Smrg    return serverClient;
18357e31ba66Smrg}
18367e31ba66Smrg
18377e31ba66Smrgstatic int
18387e31ba66Smrgget_default_point_size(void)
183905b261ecSmrg{
184005b261ecSmrg    return 120;
184105b261ecSmrg}
184205b261ecSmrg
18437e31ba66Smrgstatic FontResolutionPtr
18447e31ba66Smrgget_client_resolutions(int *num)
184505b261ecSmrg{
18464642e01fSmrg    static struct _FontResolution res;
1847f7df2e56Smrg    ScreenPtr pScreen;
184805b261ecSmrg
18494642e01fSmrg    pScreen = screenInfo.screens[0];
18504642e01fSmrg    res.x_resolution = (pScreen->width * 25.4) / pScreen->mmWidth;
18514642e01fSmrg    /*
1852f7df2e56Smrg     * XXX - we'll want this as long as bitmap instances are prevalent
18534642e01fSmrg     so that we can match them from scalable fonts
18544642e01fSmrg     */
18554642e01fSmrg    if (res.x_resolution < 88)
1856f7df2e56Smrg        res.x_resolution = 75;
18574642e01fSmrg    else
1858f7df2e56Smrg        res.x_resolution = 100;
18594642e01fSmrg    res.y_resolution = (pScreen->height * 25.4) / pScreen->mmHeight;
18604642e01fSmrg    if (res.y_resolution < 88)
1861f7df2e56Smrg        res.y_resolution = 75;
18624642e01fSmrg    else
1863f7df2e56Smrg        res.y_resolution = 100;
18644642e01fSmrg    res.point_size = 120;
18654642e01fSmrg    *num = 1;
18664642e01fSmrg    return &res;
186705b261ecSmrg}
186805b261ecSmrg
186905b261ecSmrgvoid
187005b261ecSmrgFreeFonts(void)
187105b261ecSmrg{
187205b261ecSmrg    if (patternCache) {
18737e31ba66Smrg        xfont2_free_font_pattern_cache(patternCache);
1874f7df2e56Smrg        patternCache = 0;
187505b261ecSmrg    }
187605b261ecSmrg    FreeFontPath(font_path_elements, num_fpes, TRUE);
187705b261ecSmrg    font_path_elements = 0;
187805b261ecSmrg    num_fpes = 0;
18796747b715Smrg    free(fpe_functions);
188005b261ecSmrg    num_fpe_types = 0;
18817e31ba66Smrg    fpe_functions = NULL;
188205b261ecSmrg}
188305b261ecSmrg
188405b261ecSmrg/* convenience functions for FS interface */
188505b261ecSmrg
18867e31ba66Smrgstatic FontPtr
188705b261ecSmrgfind_old_font(XID id)
188805b261ecSmrg{
1889f7df2e56Smrg    void *pFont;
1890f7df2e56Smrg
18916747b715Smrg    dixLookupResourceByType(&pFont, id, RT_NONE, serverClient, DixReadAccess);
1892f7df2e56Smrg    return (FontPtr) pFont;
189305b261ecSmrg}
189405b261ecSmrg
18957e31ba66Smrgstatic Font
18967e31ba66Smrgget_new_font_client_id(void)
189705b261ecSmrg{
189805b261ecSmrg    return FakeClientID(0);
189905b261ecSmrg}
190005b261ecSmrg
19017e31ba66Smrgstatic int
19027e31ba66Smrgstore_font_Client_font(FontPtr pfont, Font id)
190305b261ecSmrg{
1904f7df2e56Smrg    return AddResource(id, RT_NONE, (void *) pfont);
190505b261ecSmrg}
190605b261ecSmrg
19077e31ba66Smrgstatic void
19087e31ba66Smrgdelete_font_client_id(Font id)
190905b261ecSmrg{
191005b261ecSmrg    FreeResource(id, RT_NONE);
191105b261ecSmrg}
191205b261ecSmrg
19137e31ba66Smrgstatic int
19147e31ba66Smrg_client_auth_generation(ClientPtr client)
191505b261ecSmrg{
191605b261ecSmrg    return 0;
191705b261ecSmrg}
191805b261ecSmrg
1919f7df2e56Smrgstatic int fs_handlers_installed = 0;
192005b261ecSmrgstatic unsigned int last_server_gen;
192105b261ecSmrg
19227e31ba66Smrgstatic void fs_block_handler(void *blockData, void *timeout)
19237e31ba66Smrg{
19247e31ba66Smrg    FontBlockHandlerProcPtr block_handler = blockData;
19257e31ba66Smrg
19267e31ba66Smrg    (*block_handler)(timeout);
19277e31ba66Smrg}
19287e31ba66Smrg
19297e31ba66Smrgstruct fs_fd_entry {
19307e31ba66Smrg    struct xorg_list            entry;
19317e31ba66Smrg    int                         fd;
19327e31ba66Smrg    void                        *data;
19337e31ba66Smrg    FontFdHandlerProcPtr        handler;
19347e31ba66Smrg};
19357e31ba66Smrg
19367e31ba66Smrgstatic void
19377e31ba66Smrgfs_fd_handler(int fd, int ready, void *data)
19387e31ba66Smrg{
19397e31ba66Smrg    struct fs_fd_entry    *entry = data;
19407e31ba66Smrg
19417e31ba66Smrg    entry->handler(fd, entry->data);
19427e31ba66Smrg}
19437e31ba66Smrg
19447e31ba66Smrgstatic struct xorg_list fs_fd_list;
19457e31ba66Smrg
19467e31ba66Smrgstatic int
19477e31ba66Smrgadd_fs_fd(int fd, FontFdHandlerProcPtr handler, void *data)
19487e31ba66Smrg{
19497e31ba66Smrg    struct fs_fd_entry  *entry = calloc(1, sizeof (struct fs_fd_entry));
19507e31ba66Smrg
19517e31ba66Smrg    if (!entry)
19527e31ba66Smrg        return FALSE;
19537e31ba66Smrg
19547e31ba66Smrg    entry->fd = fd;
19557e31ba66Smrg    entry->data = data;
19567e31ba66Smrg    entry->handler = handler;
19577e31ba66Smrg    if (!SetNotifyFd(fd, fs_fd_handler, X_NOTIFY_READ, entry)) {
19587e31ba66Smrg        free(entry);
19597e31ba66Smrg        return FALSE;
19607e31ba66Smrg    }
19617e31ba66Smrg    xorg_list_add(&entry->entry, &fs_fd_list);
19627e31ba66Smrg    return TRUE;
19637e31ba66Smrg}
19647e31ba66Smrg
19657e31ba66Smrgstatic void
19667e31ba66Smrgremove_fs_fd(int fd)
19677e31ba66Smrg{
19687e31ba66Smrg    struct fs_fd_entry  *entry, *temp;
19697e31ba66Smrg
19707e31ba66Smrg    xorg_list_for_each_entry_safe(entry, temp, &fs_fd_list, entry) {
19717e31ba66Smrg        if (entry->fd == fd) {
19727e31ba66Smrg            xorg_list_del(&entry->entry);
19737e31ba66Smrg            free(entry);
19747e31ba66Smrg            break;
19757e31ba66Smrg        }
19767e31ba66Smrg    }
19777e31ba66Smrg    RemoveNotifyFd(fd);
19787e31ba66Smrg}
19797e31ba66Smrg
19807e31ba66Smrgstatic void
19817e31ba66Smrgadjust_fs_wait_for_delay(void *wt, unsigned long newdelay)
19827e31ba66Smrg{
19837e31ba66Smrg    AdjustWaitForDelay(wt, newdelay);
19847e31ba66Smrg}
19857e31ba66Smrg
19867e31ba66Smrgstatic int
19877e31ba66Smrg_init_fs_handlers(FontPathElementPtr fpe, FontBlockHandlerProcPtr block_handler)
198805b261ecSmrg{
198905b261ecSmrg    /* if server has reset, make sure the b&w handlers are reinstalled */
199005b261ecSmrg    if (last_server_gen < serverGeneration) {
1991f7df2e56Smrg        last_server_gen = serverGeneration;
1992f7df2e56Smrg        fs_handlers_installed = 0;
199305b261ecSmrg    }
199405b261ecSmrg    if (fs_handlers_installed == 0) {
19957e31ba66Smrg        if (!RegisterBlockAndWakeupHandlers(fs_block_handler,
19967e31ba66Smrg                                            FontWakeup, (void *) block_handler))
1997f7df2e56Smrg            return AllocError;
19987e31ba66Smrg        xorg_list_init(&fs_fd_list);
1999f7df2e56Smrg        fs_handlers_installed++;
200005b261ecSmrg    }
200105b261ecSmrg    QueueFontWakeup(fpe);
200205b261ecSmrg    return Successful;
200305b261ecSmrg}
200405b261ecSmrg
20057e31ba66Smrgstatic void
20067e31ba66Smrg_remove_fs_handlers(FontPathElementPtr fpe, FontBlockHandlerProcPtr block_handler,
20077e31ba66Smrg                    Bool all)
200805b261ecSmrg{
200905b261ecSmrg    if (all) {
2010f7df2e56Smrg        /* remove the handlers if no one else is using them */
2011f7df2e56Smrg        if (--fs_handlers_installed == 0) {
20127e31ba66Smrg            RemoveBlockAndWakeupHandlers(fs_block_handler, FontWakeup,
20137e31ba66Smrg                                         (void *) block_handler);
2014f7df2e56Smrg        }
201505b261ecSmrg    }
201605b261ecSmrg    RemoveFontWakeup(fpe);
201705b261ecSmrg}
20187e31ba66Smrg
20197e31ba66Smrgstatic uint32_t wrap_time_in_millis(void)
20207e31ba66Smrg{
20217e31ba66Smrg    return GetTimeInMillis();
20227e31ba66Smrg}
20237e31ba66Smrg
20247e31ba66Smrgstatic const xfont2_client_funcs_rec xfont2_client_funcs = {
20257e31ba66Smrg    .version = XFONT2_CLIENT_FUNCS_VERSION,
20267e31ba66Smrg    .client_auth_generation = _client_auth_generation,
20277e31ba66Smrg    .client_signal = ClientSignal,
20287e31ba66Smrg    .delete_font_client_id = delete_font_client_id,
20297e31ba66Smrg    .verrorf = VErrorF,
20307e31ba66Smrg    .find_old_font = find_old_font,
20317e31ba66Smrg    .get_client_resolutions = get_client_resolutions,
20327e31ba66Smrg    .get_default_point_size = get_default_point_size,
20337e31ba66Smrg    .get_new_font_client_id = get_new_font_client_id,
20347e31ba66Smrg    .get_time_in_millis = wrap_time_in_millis,
20357e31ba66Smrg    .init_fs_handlers = _init_fs_handlers,
20367e31ba66Smrg    .register_fpe_funcs = register_fpe_funcs,
20377e31ba66Smrg    .remove_fs_handlers = _remove_fs_handlers,
20387e31ba66Smrg    .get_server_client = get_server_client,
20397e31ba66Smrg    .set_font_authorizations = set_font_authorizations,
20407e31ba66Smrg    .store_font_client_font = store_font_Client_font,
20417e31ba66Smrg    .make_atom = MakeAtom,
20427e31ba66Smrg    .valid_atom = ValidAtom,
20437e31ba66Smrg    .name_for_atom = NameForAtom,
20447e31ba66Smrg    .get_server_generation = get_server_generation,
20457e31ba66Smrg    .add_fs_fd = add_fs_fd,
20467e31ba66Smrg    .remove_fs_fd = remove_fs_fd,
20477e31ba66Smrg    .adjust_fs_wait_for_delay = adjust_fs_wait_for_delay,
20487e31ba66Smrg};
20497e31ba66Smrg
20507e31ba66Smrgxfont2_pattern_cache_ptr fontPatternCache;
20517e31ba66Smrg
20527e31ba66Smrgvoid
20537e31ba66SmrgInitFonts(void)
20547e31ba66Smrg{
20557e31ba66Smrg    if (fontPatternCache)
20567e31ba66Smrg	xfont2_free_font_pattern_cache(fontPatternCache);
20577e31ba66Smrg    fontPatternCache = xfont2_make_font_pattern_cache();
20587e31ba66Smrg    xfont2_init(&xfont2_client_funcs);
20597e31ba66Smrg}
2060