105b261ecSmrg/*
205b261ecSmrg * BIGFONT extension for sharing font metrics between clients (if possible)
305b261ecSmrg * and for transmitting font metrics to clients in a compressed form.
405b261ecSmrg *
505b261ecSmrg * Copyright (c) 1999-2000  Bruno Haible
605b261ecSmrg * Copyright (c) 1999-2000  The XFree86 Project, Inc.
705b261ecSmrg */
805b261ecSmrg
905b261ecSmrg/* THIS IS NOT AN X CONSORTIUM STANDARD */
1005b261ecSmrg
1105b261ecSmrg/*
1205b261ecSmrg * Big fonts suffer from the following: All clients that have opened a
1305b261ecSmrg * font can access the complete glyph metrics array (the XFontStruct member
1405b261ecSmrg * `per_char') directly, without going through a macro. Moreover these
1505b261ecSmrg * glyph metrics are ink metrics, i.e. are not redundant even for a
1605b261ecSmrg * fixed-width font. For a Unicode font, the size of this array is 768 KB.
1705b261ecSmrg *
1805b261ecSmrg * Problems: 1. It eats a lot of memory in each client. 2. All this glyph
1905b261ecSmrg * metrics data is piped through the socket when the font is opened.
2005b261ecSmrg *
2105b261ecSmrg * This extension addresses these two problems for local clients, by using
2205b261ecSmrg * shared memory. It also addresses the second problem for non-local clients,
2305b261ecSmrg * by compressing the data before transmit by a factor of nearly 6.
2405b261ecSmrg *
2505b261ecSmrg * If you use this extension, your OS ought to nicely support shared memory.
2605b261ecSmrg * This means: Shared memory should be swappable to the swap, and the limits
2705b261ecSmrg * should be high enough (SHMMNI at least 64, SHMMAX at least 768 KB,
2805b261ecSmrg * SHMALL at least 48 MB). It is a plus if your OS allows shmat() calls
2905b261ecSmrg * on segments that have already been marked "removed", because it permits
3005b261ecSmrg * these segments to be cleaned up by the OS if the X server is killed with
3105b261ecSmrg * signal SIGKILL.
3205b261ecSmrg *
3305b261ecSmrg * This extension is transparently exploited by Xlib (functions XQueryFont,
3405b261ecSmrg * XLoadQueryFont).
3505b261ecSmrg */
3605b261ecSmrg
3705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
3805b261ecSmrg#include <dix-config.h>
3905b261ecSmrg#endif
4005b261ecSmrg
4105b261ecSmrg#include <sys/types.h>
4205b261ecSmrg#ifdef HAS_SHM
4305b261ecSmrg#ifdef SVR4
4405b261ecSmrg#include <sys/sysmacros.h>
4505b261ecSmrg#endif
4635c4bbdfSmrg#if defined(__CYGWIN__)
4705b261ecSmrg#include <sys/param.h>
4805b261ecSmrg#include <sys/sysmacros.h>
4905b261ecSmrg#endif
5005b261ecSmrg#include <sys/ipc.h>
5105b261ecSmrg#include <sys/shm.h>
5205b261ecSmrg#include <sys/stat.h>
5305b261ecSmrg#include <stdlib.h>
5405b261ecSmrg#include <unistd.h>
5505b261ecSmrg#include <time.h>
5605b261ecSmrg#include <errno.h>
5705b261ecSmrg#endif
5805b261ecSmrg
5905b261ecSmrg#include <X11/X.h>
6005b261ecSmrg#include <X11/Xproto.h>
6105b261ecSmrg#include "misc.h"
6205b261ecSmrg#include "os.h"
6305b261ecSmrg#include "dixstruct.h"
6405b261ecSmrg#include "gcstruct.h"
6505b261ecSmrg#include "dixfontstr.h"
6605b261ecSmrg#include "extnsionst.h"
6735c4bbdfSmrg#include "extinit.h"
686747b715Smrg#include "protocol-versions.h"
6905b261ecSmrg
706747b715Smrg#include <X11/extensions/xf86bigfproto.h>
716747b715Smrg#include "xf86bigfontsrv.h"
7205b261ecSmrg
7335c4bbdfSmrgstatic void XF86BigfontResetProc(ExtensionEntry *       /* extEntry */
7405b261ecSmrg    );
7505b261ecSmrg
7605b261ecSmrg#ifdef HAS_SHM
7705b261ecSmrg
7805b261ecSmrg/* A random signature, transmitted to the clients so they can verify that the
7905b261ecSmrg   shared memory segment they are attaching to was really established by the
8005b261ecSmrg   X server they are talking to. */
8105b261ecSmrgstatic CARD32 signature;
8205b261ecSmrg
8305b261ecSmrg/* Index for additional information stored in a FontRec's devPrivates array. */
8405b261ecSmrgstatic int FontShmdescIndex;
8505b261ecSmrg
8605b261ecSmrgstatic unsigned int pagesize;
8705b261ecSmrg
8805b261ecSmrgstatic Bool badSysCall = FALSE;
8905b261ecSmrg
9005b261ecSmrg#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
9105b261ecSmrg
9205b261ecSmrgstatic void
9335c4bbdfSmrgSigSysHandler(int signo)
9405b261ecSmrg{
9505b261ecSmrg    badSysCall = TRUE;
9605b261ecSmrg}
9705b261ecSmrg
9805b261ecSmrgstatic Bool
9905b261ecSmrgCheckForShmSyscall(void)
10005b261ecSmrg{
10135c4bbdfSmrg    void (*oldHandler) (int);
10205b261ecSmrg    int shmid = -1;
10305b261ecSmrg
10405b261ecSmrg    /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
1051b5d61b8Smrg    oldHandler = OsSignal(SIGSYS, SigSysHandler);
10605b261ecSmrg
10705b261ecSmrg    badSysCall = FALSE;
10805b261ecSmrg    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
10935c4bbdfSmrg    if (shmid != -1) {
11005b261ecSmrg        /* Successful allocation - clean up */
11135c4bbdfSmrg        shmctl(shmid, IPC_RMID, NULL);
11205b261ecSmrg    }
11335c4bbdfSmrg    else {
11405b261ecSmrg        /* Allocation failed */
11505b261ecSmrg        badSysCall = TRUE;
11605b261ecSmrg    }
1171b5d61b8Smrg    OsSignal(SIGSYS, oldHandler);
1186747b715Smrg    return !badSysCall;
11905b261ecSmrg}
12005b261ecSmrg
12105b261ecSmrg#define MUST_CHECK_FOR_SHM_SYSCALL
12205b261ecSmrg
12305b261ecSmrg#endif
12405b261ecSmrg
12505b261ecSmrg#endif
12605b261ecSmrg
12705b261ecSmrg/* ========== Management of shared memory segments ========== */
12805b261ecSmrg
12905b261ecSmrg#ifdef HAS_SHM
13005b261ecSmrg
13105b261ecSmrg#ifdef __linux__
13205b261ecSmrg/* On Linux, shared memory marked as "removed" can still be attached.
13305b261ecSmrg   Nice feature, because the kernel will automatically free the associated
13405b261ecSmrg   storage when the server and all clients are gone. */
13505b261ecSmrg#define EARLY_REMOVE
13605b261ecSmrg#endif
13705b261ecSmrg
13805b261ecSmrgtypedef struct _ShmDesc {
13905b261ecSmrg    struct _ShmDesc *next;
14005b261ecSmrg    struct _ShmDesc **prev;
14105b261ecSmrg    int shmid;
14205b261ecSmrg    char *attach_addr;
14305b261ecSmrg} ShmDescRec, *ShmDescPtr;
14405b261ecSmrg
14505b261ecSmrgstatic ShmDescPtr ShmList = (ShmDescPtr) NULL;
14605b261ecSmrg
14705b261ecSmrgstatic ShmDescPtr
14835c4bbdfSmrgshmalloc(unsigned int size)
14905b261ecSmrg{
15005b261ecSmrg    ShmDescPtr pDesc;
15105b261ecSmrg    int shmid;
15205b261ecSmrg    char *addr;
15305b261ecSmrg
15405b261ecSmrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL
15505b261ecSmrg    if (pagesize == 0)
15635c4bbdfSmrg        return (ShmDescPtr) NULL;
15705b261ecSmrg#endif
15805b261ecSmrg
15905b261ecSmrg    /* On some older Linux systems, the number of shared memory segments
16005b261ecSmrg       system-wide is 127. In Linux 2.4, it is 4095.
16105b261ecSmrg       Therefore there is a tradeoff to be made between allocating a
16205b261ecSmrg       shared memory segment on one hand, and allocating memory and piping
16305b261ecSmrg       the glyph metrics on the other hand. If the glyph metrics size is
16405b261ecSmrg       small, we prefer the traditional way. */
16505b261ecSmrg    if (size < 3500)
16635c4bbdfSmrg        return (ShmDescPtr) NULL;
16705b261ecSmrg
1686747b715Smrg    pDesc = malloc(sizeof(ShmDescRec));
16905b261ecSmrg    if (!pDesc)
17035c4bbdfSmrg        return (ShmDescPtr) NULL;
17105b261ecSmrg
17235c4bbdfSmrg    size = (size + pagesize - 1) & -pagesize;
17305b261ecSmrg    shmid = shmget(IPC_PRIVATE, size, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
17405b261ecSmrg    if (shmid == -1) {
17535c4bbdfSmrg        ErrorF(XF86BIGFONTNAME " extension: shmget() failed, size = %u, %s\n",
17635c4bbdfSmrg               size, strerror(errno));
17735c4bbdfSmrg        free(pDesc);
17835c4bbdfSmrg        return (ShmDescPtr) NULL;
17905b261ecSmrg    }
18005b261ecSmrg
18135c4bbdfSmrg    if ((addr = shmat(shmid, 0, 0)) == (char *) -1) {
18235c4bbdfSmrg        ErrorF(XF86BIGFONTNAME " extension: shmat() failed, size = %u, %s\n",
18335c4bbdfSmrg               size, strerror(errno));
18435c4bbdfSmrg        shmctl(shmid, IPC_RMID, (void *) 0);
18535c4bbdfSmrg        free(pDesc);
18635c4bbdfSmrg        return (ShmDescPtr) NULL;
18705b261ecSmrg    }
18805b261ecSmrg
18905b261ecSmrg#ifdef EARLY_REMOVE
19005b261ecSmrg    shmctl(shmid, IPC_RMID, (void *) 0);
19105b261ecSmrg#endif
19205b261ecSmrg
19305b261ecSmrg    pDesc->shmid = shmid;
19405b261ecSmrg    pDesc->attach_addr = addr;
19535c4bbdfSmrg    if (ShmList)
19635c4bbdfSmrg        ShmList->prev = &pDesc->next;
19705b261ecSmrg    pDesc->next = ShmList;
19805b261ecSmrg    pDesc->prev = &ShmList;
19905b261ecSmrg    ShmList = pDesc;
20005b261ecSmrg
20105b261ecSmrg    return pDesc;
20205b261ecSmrg}
20305b261ecSmrg
20405b261ecSmrgstatic void
20535c4bbdfSmrgshmdealloc(ShmDescPtr pDesc)
20605b261ecSmrg{
20705b261ecSmrg#ifndef EARLY_REMOVE
20805b261ecSmrg    shmctl(pDesc->shmid, IPC_RMID, (void *) 0);
20905b261ecSmrg#endif
21005b261ecSmrg    shmdt(pDesc->attach_addr);
21105b261ecSmrg
21235c4bbdfSmrg    if (pDesc->next)
21335c4bbdfSmrg        pDesc->next->prev = pDesc->prev;
21405b261ecSmrg    *pDesc->prev = pDesc->next;
2156747b715Smrg    free(pDesc);
21605b261ecSmrg}
21705b261ecSmrg
21805b261ecSmrg#endif
21905b261ecSmrg
22005b261ecSmrg/* Called when a font is closed. */
22105b261ecSmrgvoid
22235c4bbdfSmrgXF86BigfontFreeFontShm(FontPtr pFont)
22305b261ecSmrg{
22405b261ecSmrg#ifdef HAS_SHM
22505b261ecSmrg    ShmDescPtr pDesc;
22605b261ecSmrg
22705b261ecSmrg    /* If during shutdown of the server, XF86BigfontCleanup() has already
22805b261ecSmrg     * called shmdealloc() for all segments, we don't need to do it here.
22905b261ecSmrg     */
23005b261ecSmrg    if (!ShmList)
23135c4bbdfSmrg        return;
23205b261ecSmrg
23305b261ecSmrg    pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex);
23405b261ecSmrg    if (pDesc)
23535c4bbdfSmrg        shmdealloc(pDesc);
23605b261ecSmrg#endif
23705b261ecSmrg}
23805b261ecSmrg
23905b261ecSmrg/* Called upon fatal signal. */
24005b261ecSmrgvoid
2416747b715SmrgXF86BigfontCleanup(void)
24205b261ecSmrg{
24305b261ecSmrg#ifdef HAS_SHM
24405b261ecSmrg    while (ShmList)
24535c4bbdfSmrg        shmdealloc(ShmList);
24605b261ecSmrg#endif
24705b261ecSmrg}
24805b261ecSmrg
24905b261ecSmrg/* Called when a server generation dies. */
25005b261ecSmrgstatic void
25135c4bbdfSmrgXF86BigfontResetProc(ExtensionEntry * extEntry)
25205b261ecSmrg{
25305b261ecSmrg    /* This function is normally called from CloseDownExtensions(), called
25405b261ecSmrg     * from main(). It will be followed by a call to FreeAllResources(),
25505b261ecSmrg     * which will call XF86BigfontFreeFontShm() for each font. Thus it
25605b261ecSmrg     * appears that we do not need to do anything in this function. --
25705b261ecSmrg     * But I prefer to write robust code, and not keep shared memory lying
25805b261ecSmrg     * around when it's not needed any more. (Someone might close down the
25905b261ecSmrg     * extension without calling FreeAllResources()...)
26005b261ecSmrg     */
26105b261ecSmrg    XF86BigfontCleanup();
26205b261ecSmrg}
26305b261ecSmrg
26405b261ecSmrg/* ========== Handling of extension specific requests ========== */
26505b261ecSmrg
26605b261ecSmrgstatic int
26735c4bbdfSmrgProcXF86BigfontQueryVersion(ClientPtr client)
26805b261ecSmrg{
26905b261ecSmrg    xXF86BigfontQueryVersionReply reply;
27005b261ecSmrg
27105b261ecSmrg    REQUEST_SIZE_MATCH(xXF86BigfontQueryVersionReq);
27235c4bbdfSmrg    reply = (xXF86BigfontQueryVersionReply) {
27335c4bbdfSmrg        .type = X_Reply,
27435c4bbdfSmrg        .sequenceNumber = client->sequence,
27535c4bbdfSmrg        .length = 0,
27635c4bbdfSmrg        .majorVersion = SERVER_XF86BIGFONT_MAJOR_VERSION,
27735c4bbdfSmrg        .minorVersion = SERVER_XF86BIGFONT_MINOR_VERSION,
27835c4bbdfSmrg        .uid = geteuid(),
27935c4bbdfSmrg        .gid = getegid(),
28005b261ecSmrg#ifdef HAS_SHM
28135c4bbdfSmrg        .signature = signature,
28235c4bbdfSmrg        .capabilities = (client->local && !client->swapped)
28335c4bbdfSmrg                         ? XF86Bigfont_CAP_LocalShm : 0
28405b261ecSmrg#else
28535c4bbdfSmrg        .signature = 0,
28635c4bbdfSmrg        .capabilities = 0
28705b261ecSmrg#endif
28835c4bbdfSmrg    };
28905b261ecSmrg    if (client->swapped) {
29035c4bbdfSmrg        swaps(&reply.sequenceNumber);
29135c4bbdfSmrg        swapl(&reply.length);
29235c4bbdfSmrg        swaps(&reply.majorVersion);
29335c4bbdfSmrg        swaps(&reply.minorVersion);
29435c4bbdfSmrg        swapl(&reply.uid);
29535c4bbdfSmrg        swapl(&reply.gid);
29635c4bbdfSmrg        swapl(&reply.signature);
29705b261ecSmrg    }
29835c4bbdfSmrg    WriteToClient(client, sizeof(xXF86BigfontQueryVersionReply), &reply);
2996747b715Smrg    return Success;
30005b261ecSmrg}
30105b261ecSmrg
30205b261ecSmrgstatic void
30335c4bbdfSmrgswapCharInfo(xCharInfo * pCI)
30405b261ecSmrg{
30535c4bbdfSmrg    swaps(&pCI->leftSideBearing);
30635c4bbdfSmrg    swaps(&pCI->rightSideBearing);
30735c4bbdfSmrg    swaps(&pCI->characterWidth);
30835c4bbdfSmrg    swaps(&pCI->ascent);
30935c4bbdfSmrg    swaps(&pCI->descent);
31035c4bbdfSmrg    swaps(&pCI->attributes);
31105b261ecSmrg}
31205b261ecSmrg
31305b261ecSmrg/* static CARD32 hashCI (xCharInfo *p); */
31405b261ecSmrg#define hashCI(p) \
31505b261ecSmrg	(CARD32)(((p->leftSideBearing << 27) + (p->leftSideBearing >> 5) + \
31605b261ecSmrg	          (p->rightSideBearing << 23) + (p->rightSideBearing >> 9) + \
31705b261ecSmrg	          (p->characterWidth << 16) + \
31805b261ecSmrg	          (p->ascent << 11) + (p->descent << 6)) ^ p->attributes)
31905b261ecSmrg
32005b261ecSmrgstatic int
32135c4bbdfSmrgProcXF86BigfontQueryFont(ClientPtr client)
32205b261ecSmrg{
32305b261ecSmrg    FontPtr pFont;
32435c4bbdfSmrg
32505b261ecSmrg    REQUEST(xXF86BigfontQueryFontReq);
32605b261ecSmrg    CARD32 stuff_flags;
32735c4bbdfSmrg    xCharInfo *pmax;
32835c4bbdfSmrg    xCharInfo *pmin;
32905b261ecSmrg    int nCharInfos;
33005b261ecSmrg    int shmid;
33135c4bbdfSmrg
33205b261ecSmrg#ifdef HAS_SHM
3336747b715Smrg    ShmDescPtr pDesc = NULL;
33405b261ecSmrg#else
33505b261ecSmrg#define pDesc 0
33605b261ecSmrg#endif
33735c4bbdfSmrg    xCharInfo *pCI;
33835c4bbdfSmrg    CARD16 *pIndex2UniqIndex;
33935c4bbdfSmrg    CARD16 *pUniqIndex2Index;
34005b261ecSmrg    CARD32 nUniqCharInfos;
34105b261ecSmrg
34205b261ecSmrg#if 0
34305b261ecSmrg    REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq);
34405b261ecSmrg#else
34505b261ecSmrg    switch (client->req_len) {
34635c4bbdfSmrg    case 2:                    /* client with version 1.0 libX11 */
34735c4bbdfSmrg        stuff_flags = (client->local &&
34835c4bbdfSmrg                       !client->swapped ? XF86Bigfont_FLAGS_Shm : 0);
34935c4bbdfSmrg        break;
35035c4bbdfSmrg    case 3:                    /* client with version 1.1 libX11 */
35135c4bbdfSmrg        stuff_flags = stuff->flags;
35235c4bbdfSmrg        break;
35335c4bbdfSmrg    default:
35435c4bbdfSmrg        return BadLength;
35505b261ecSmrg    }
35605b261ecSmrg#endif
35735c4bbdfSmrg    if (dixLookupFontable(&pFont, stuff->id, client, DixGetAttrAccess) !=
35835c4bbdfSmrg        Success)
35935c4bbdfSmrg        return BadFont;         /* procotol spec says only error is BadFont */
36005b261ecSmrg
36105b261ecSmrg    pmax = FONTINKMAX(pFont);
36205b261ecSmrg    pmin = FONTINKMIN(pFont);
36305b261ecSmrg    nCharInfos =
36435c4bbdfSmrg        (pmax->rightSideBearing == pmin->rightSideBearing
36535c4bbdfSmrg         && pmax->leftSideBearing == pmin->leftSideBearing
36635c4bbdfSmrg         && pmax->descent == pmin->descent
36735c4bbdfSmrg         && pmax->ascent == pmin->ascent
36835c4bbdfSmrg         && pmax->characterWidth == pmin->characterWidth)
36935c4bbdfSmrg        ? 0 : N2dChars(pFont);
37005b261ecSmrg    shmid = -1;
37105b261ecSmrg    pCI = NULL;
37205b261ecSmrg    pIndex2UniqIndex = NULL;
37305b261ecSmrg    pUniqIndex2Index = NULL;
37405b261ecSmrg    nUniqCharInfos = 0;
37505b261ecSmrg
37605b261ecSmrg    if (nCharInfos > 0) {
37705b261ecSmrg#ifdef HAS_SHM
37835c4bbdfSmrg        if (!badSysCall)
37935c4bbdfSmrg            pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex);
380d5c798e1Smrg        if (pDesc && pDesc->attach_addr) {
38135c4bbdfSmrg            pCI = (xCharInfo *) pDesc->attach_addr;
38235c4bbdfSmrg            if (stuff_flags & XF86Bigfont_FLAGS_Shm)
38335c4bbdfSmrg                shmid = pDesc->shmid;
38435c4bbdfSmrg        }
38535c4bbdfSmrg        else {
38635c4bbdfSmrg            if (stuff_flags & XF86Bigfont_FLAGS_Shm && !badSysCall)
38735c4bbdfSmrg                pDesc = shmalloc(nCharInfos * sizeof(xCharInfo)
38835c4bbdfSmrg                                 + sizeof(CARD32));
38935c4bbdfSmrg            if (pDesc) {
39035c4bbdfSmrg                pCI = (xCharInfo *) pDesc->attach_addr;
39135c4bbdfSmrg                shmid = pDesc->shmid;
39235c4bbdfSmrg            }
39335c4bbdfSmrg            else {
39405b261ecSmrg#endif
39535c4bbdfSmrg                pCI = xallocarray(nCharInfos, sizeof(xCharInfo));
39635c4bbdfSmrg                if (!pCI)
39735c4bbdfSmrg                    return BadAlloc;
39805b261ecSmrg#ifdef HAS_SHM
39935c4bbdfSmrg            }
40005b261ecSmrg#endif
40135c4bbdfSmrg            /* Fill nCharInfos starting at pCI. */
40235c4bbdfSmrg            {
40335c4bbdfSmrg                xCharInfo *prCI = pCI;
40435c4bbdfSmrg                int ninfos = 0;
40535c4bbdfSmrg                int ncols = pFont->info.lastCol - pFont->info.firstCol + 1;
40635c4bbdfSmrg                int row;
40735c4bbdfSmrg
40835c4bbdfSmrg                for (row = pFont->info.firstRow;
40935c4bbdfSmrg                     row <= pFont->info.lastRow && ninfos < nCharInfos; row++) {
41035c4bbdfSmrg                    unsigned char chars[512];
41135c4bbdfSmrg                    xCharInfo *tmpCharInfos[256];
41235c4bbdfSmrg                    unsigned long count;
41335c4bbdfSmrg                    int col;
41435c4bbdfSmrg                    unsigned long i;
41535c4bbdfSmrg
41635c4bbdfSmrg                    i = 0;
41735c4bbdfSmrg                    for (col = pFont->info.firstCol;
41835c4bbdfSmrg                         col <= pFont->info.lastCol; col++) {
41935c4bbdfSmrg                        chars[i++] = row;
42035c4bbdfSmrg                        chars[i++] = col;
42135c4bbdfSmrg                    }
42235c4bbdfSmrg                    (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit,
42335c4bbdfSmrg                                           &count, tmpCharInfos);
42435c4bbdfSmrg                    for (i = 0; i < count && ninfos < nCharInfos; i++) {
42535c4bbdfSmrg                        *prCI++ = *tmpCharInfos[i];
42635c4bbdfSmrg                        ninfos++;
42735c4bbdfSmrg                    }
42835c4bbdfSmrg                }
42935c4bbdfSmrg            }
43005b261ecSmrg#ifdef HAS_SHM
43135c4bbdfSmrg            if (pDesc && !badSysCall) {
43235c4bbdfSmrg                *(CARD32 *) (pCI + nCharInfos) = signature;
4331b5d61b8Smrg                if (!xfont2_font_set_private(pFont, FontShmdescIndex, pDesc)) {
43435c4bbdfSmrg                    shmdealloc(pDesc);
43535c4bbdfSmrg                    return BadAlloc;
43635c4bbdfSmrg                }
43735c4bbdfSmrg            }
43835c4bbdfSmrg        }
43905b261ecSmrg#endif
44035c4bbdfSmrg        if (shmid == -1) {
44135c4bbdfSmrg            /* Cannot use shared memory, so remove-duplicates the xCharInfos
44235c4bbdfSmrg               using a temporary hash table. */
44335c4bbdfSmrg            /* Note that CARD16 is suitable as index type, because
44435c4bbdfSmrg               nCharInfos <= 0x10000. */
44535c4bbdfSmrg            CARD32 hashModulus;
44635c4bbdfSmrg            CARD16 *pHash2UniqIndex;
44735c4bbdfSmrg            CARD16 *pUniqIndex2NextUniqIndex;
44835c4bbdfSmrg            CARD32 NextIndex;
44935c4bbdfSmrg            CARD32 NextUniqIndex;
45035c4bbdfSmrg            CARD16 *tmp;
45135c4bbdfSmrg            CARD32 i, j;
45235c4bbdfSmrg
45335c4bbdfSmrg            hashModulus = 67;
45435c4bbdfSmrg            if (hashModulus > nCharInfos + 1)
45535c4bbdfSmrg                hashModulus = nCharInfos + 1;
45635c4bbdfSmrg
45735c4bbdfSmrg            tmp = xallocarray(4 * nCharInfos + 1, sizeof(CARD16));
45835c4bbdfSmrg            if (!tmp) {
45935c4bbdfSmrg                if (!pDesc)
46035c4bbdfSmrg                    free(pCI);
46135c4bbdfSmrg                return BadAlloc;
46235c4bbdfSmrg            }
46335c4bbdfSmrg            pIndex2UniqIndex = tmp;
46435c4bbdfSmrg            /* nCharInfos elements */
46535c4bbdfSmrg            pUniqIndex2Index = tmp + nCharInfos;
46635c4bbdfSmrg            /* max. nCharInfos elements */
46735c4bbdfSmrg            pUniqIndex2NextUniqIndex = tmp + 2 * nCharInfos;
46835c4bbdfSmrg            /* max. nCharInfos elements */
46935c4bbdfSmrg            pHash2UniqIndex = tmp + 3 * nCharInfos;
47035c4bbdfSmrg            /* hashModulus (<= nCharInfos+1) elements */
47135c4bbdfSmrg
47235c4bbdfSmrg            /* Note that we can use 0xffff as end-of-list indicator, because
47335c4bbdfSmrg               even if nCharInfos = 0x10000, 0xffff can not occur as valid
47435c4bbdfSmrg               entry before the last element has been inserted. And once the
47535c4bbdfSmrg               last element has been inserted, we don't need the hash table
47635c4bbdfSmrg               any more. */
47735c4bbdfSmrg            for (j = 0; j < hashModulus; j++)
47835c4bbdfSmrg                pHash2UniqIndex[j] = (CARD16) (-1);
47935c4bbdfSmrg
48035c4bbdfSmrg            NextUniqIndex = 0;
48135c4bbdfSmrg            for (NextIndex = 0; NextIndex < nCharInfos; NextIndex++) {
48235c4bbdfSmrg                xCharInfo *p = &pCI[NextIndex];
48335c4bbdfSmrg                CARD32 hashCode = hashCI(p) % hashModulus;
48435c4bbdfSmrg
48535c4bbdfSmrg                for (i = pHash2UniqIndex[hashCode];
48635c4bbdfSmrg                     i != (CARD16) (-1); i = pUniqIndex2NextUniqIndex[i]) {
48735c4bbdfSmrg                    j = pUniqIndex2Index[i];
48835c4bbdfSmrg                    if (pCI[j].leftSideBearing == p->leftSideBearing
48935c4bbdfSmrg                        && pCI[j].rightSideBearing == p->rightSideBearing
49035c4bbdfSmrg                        && pCI[j].characterWidth == p->characterWidth
49135c4bbdfSmrg                        && pCI[j].ascent == p->ascent
49235c4bbdfSmrg                        && pCI[j].descent == p->descent
49335c4bbdfSmrg                        && pCI[j].attributes == p->attributes)
49435c4bbdfSmrg                        break;
49535c4bbdfSmrg                }
49635c4bbdfSmrg                if (i != (CARD16) (-1)) {
49735c4bbdfSmrg                    /* Found *p at Index j, UniqIndex i */
49835c4bbdfSmrg                    pIndex2UniqIndex[NextIndex] = i;
49935c4bbdfSmrg                }
50035c4bbdfSmrg                else {
50135c4bbdfSmrg                    /* Allocate a new entry in the Uniq table */
50235c4bbdfSmrg                    if (hashModulus <= 2 * NextUniqIndex
50335c4bbdfSmrg                        && hashModulus < nCharInfos + 1) {
50435c4bbdfSmrg                        /* Time to increate hash table size */
50535c4bbdfSmrg                        hashModulus = 2 * hashModulus + 1;
50635c4bbdfSmrg                        if (hashModulus > nCharInfos + 1)
50735c4bbdfSmrg                            hashModulus = nCharInfos + 1;
50835c4bbdfSmrg                        for (j = 0; j < hashModulus; j++)
50935c4bbdfSmrg                            pHash2UniqIndex[j] = (CARD16) (-1);
51035c4bbdfSmrg                        for (i = 0; i < NextUniqIndex; i++)
51135c4bbdfSmrg                            pUniqIndex2NextUniqIndex[i] = (CARD16) (-1);
51235c4bbdfSmrg                        for (i = 0; i < NextUniqIndex; i++) {
51335c4bbdfSmrg                            j = pUniqIndex2Index[i];
51435c4bbdfSmrg                            p = &pCI[j];
51535c4bbdfSmrg                            hashCode = hashCI(p) % hashModulus;
51635c4bbdfSmrg                            pUniqIndex2NextUniqIndex[i] =
51735c4bbdfSmrg                                pHash2UniqIndex[hashCode];
51835c4bbdfSmrg                            pHash2UniqIndex[hashCode] = i;
51935c4bbdfSmrg                        }
52035c4bbdfSmrg                        p = &pCI[NextIndex];
52135c4bbdfSmrg                        hashCode = hashCI(p) % hashModulus;
52235c4bbdfSmrg                    }
52335c4bbdfSmrg                    i = NextUniqIndex++;
52435c4bbdfSmrg                    pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode];
52535c4bbdfSmrg                    pHash2UniqIndex[hashCode] = i;
52635c4bbdfSmrg                    pUniqIndex2Index[i] = NextIndex;
52735c4bbdfSmrg                    pIndex2UniqIndex[NextIndex] = i;
52835c4bbdfSmrg                }
52935c4bbdfSmrg            }
53035c4bbdfSmrg            nUniqCharInfos = NextUniqIndex;
53135c4bbdfSmrg            /* fprintf(stderr, "font metrics: nCharInfos = %d, nUniqCharInfos = %d, hashModulus = %d\n", nCharInfos, nUniqCharInfos, hashModulus); */
53235c4bbdfSmrg        }
53305b261ecSmrg    }
53405b261ecSmrg
53505b261ecSmrg    {
53635c4bbdfSmrg        int nfontprops = pFont->info.nprops;
53735c4bbdfSmrg        int rlength = sizeof(xXF86BigfontQueryFontReply)
53835c4bbdfSmrg            + nfontprops * sizeof(xFontProp)
53935c4bbdfSmrg            + (nCharInfos > 0 && shmid == -1
54035c4bbdfSmrg               ? nUniqCharInfos * sizeof(xCharInfo)
54135c4bbdfSmrg               + (nCharInfos + 1) / 2 * 2 * sizeof(CARD16)
54235c4bbdfSmrg               : 0);
54335c4bbdfSmrg        xXF86BigfontQueryFontReply *reply = calloc(1, rlength);
54435c4bbdfSmrg        char *p;
54535c4bbdfSmrg
54635c4bbdfSmrg        if (!reply) {
54735c4bbdfSmrg            if (nCharInfos > 0) {
54835c4bbdfSmrg                if (shmid == -1)
54935c4bbdfSmrg                    free(pIndex2UniqIndex);
55035c4bbdfSmrg                if (!pDesc)
55135c4bbdfSmrg                    free(pCI);
55235c4bbdfSmrg            }
55335c4bbdfSmrg            return BadAlloc;
55435c4bbdfSmrg        }
55535c4bbdfSmrg        reply->type = X_Reply;
55635c4bbdfSmrg        reply->length = bytes_to_int32(rlength - sizeof(xGenericReply));
55735c4bbdfSmrg        reply->sequenceNumber = client->sequence;
55835c4bbdfSmrg        reply->minBounds = pFont->info.ink_minbounds;
55935c4bbdfSmrg        reply->maxBounds = pFont->info.ink_maxbounds;
56035c4bbdfSmrg        reply->minCharOrByte2 = pFont->info.firstCol;
56135c4bbdfSmrg        reply->maxCharOrByte2 = pFont->info.lastCol;
56235c4bbdfSmrg        reply->defaultChar = pFont->info.defaultCh;
56335c4bbdfSmrg        reply->nFontProps = pFont->info.nprops;
56435c4bbdfSmrg        reply->drawDirection = pFont->info.drawDirection;
56535c4bbdfSmrg        reply->minByte1 = pFont->info.firstRow;
56635c4bbdfSmrg        reply->maxByte1 = pFont->info.lastRow;
56735c4bbdfSmrg        reply->allCharsExist = pFont->info.allExist;
56835c4bbdfSmrg        reply->fontAscent = pFont->info.fontAscent;
56935c4bbdfSmrg        reply->fontDescent = pFont->info.fontDescent;
57035c4bbdfSmrg        reply->nCharInfos = nCharInfos;
57105b261ecSmrg        reply->nUniqCharInfos = nUniqCharInfos;
57235c4bbdfSmrg        reply->shmid = shmid;
57335c4bbdfSmrg        reply->shmsegoffset = 0;
57435c4bbdfSmrg        if (client->swapped) {
57535c4bbdfSmrg            swaps(&reply->sequenceNumber);
57635c4bbdfSmrg            swapl(&reply->length);
57735c4bbdfSmrg            swapCharInfo(&reply->minBounds);
57835c4bbdfSmrg            swapCharInfo(&reply->maxBounds);
57935c4bbdfSmrg            swaps(&reply->minCharOrByte2);
58035c4bbdfSmrg            swaps(&reply->maxCharOrByte2);
58135c4bbdfSmrg            swaps(&reply->defaultChar);
58235c4bbdfSmrg            swaps(&reply->nFontProps);
58335c4bbdfSmrg            swaps(&reply->fontAscent);
58435c4bbdfSmrg            swaps(&reply->fontDescent);
58535c4bbdfSmrg            swapl(&reply->nCharInfos);
58635c4bbdfSmrg            swapl(&reply->nUniqCharInfos);
58735c4bbdfSmrg            swapl(&reply->shmid);
58835c4bbdfSmrg            swapl(&reply->shmsegoffset);
58935c4bbdfSmrg        }
59035c4bbdfSmrg        p = (char *) &reply[1];
59135c4bbdfSmrg        {
59235c4bbdfSmrg            FontPropPtr pFP;
59335c4bbdfSmrg            xFontProp *prFP;
59435c4bbdfSmrg            int i;
59535c4bbdfSmrg
59635c4bbdfSmrg            for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) p;
59735c4bbdfSmrg                 i < nfontprops; i++, pFP++, prFP++) {
59835c4bbdfSmrg                prFP->name = pFP->name;
59935c4bbdfSmrg                prFP->value = pFP->value;
60035c4bbdfSmrg                if (client->swapped) {
60135c4bbdfSmrg                    swapl(&prFP->name);
60235c4bbdfSmrg                    swapl(&prFP->value);
60335c4bbdfSmrg                }
60435c4bbdfSmrg            }
60535c4bbdfSmrg            p = (char *) prFP;
60635c4bbdfSmrg        }
60735c4bbdfSmrg        if (nCharInfos > 0 && shmid == -1) {
60835c4bbdfSmrg            xCharInfo *pci;
60935c4bbdfSmrg            CARD16 *ps;
61035c4bbdfSmrg            int i, j;
61135c4bbdfSmrg
61235c4bbdfSmrg            pci = (xCharInfo *) p;
61335c4bbdfSmrg            for (i = 0; i < nUniqCharInfos; i++, pci++) {
61435c4bbdfSmrg                *pci = pCI[pUniqIndex2Index[i]];
61535c4bbdfSmrg                if (client->swapped)
61635c4bbdfSmrg                    swapCharInfo(pci);
61735c4bbdfSmrg            }
61835c4bbdfSmrg            ps = (CARD16 *) pci;
61935c4bbdfSmrg            for (j = 0; j < nCharInfos; j++, ps++) {
62035c4bbdfSmrg                *ps = pIndex2UniqIndex[j];
62135c4bbdfSmrg                if (client->swapped) {
62235c4bbdfSmrg                    swaps(ps);
62335c4bbdfSmrg                }
62435c4bbdfSmrg            }
62535c4bbdfSmrg        }
62635c4bbdfSmrg        WriteToClient(client, rlength, reply);
62735c4bbdfSmrg        free(reply);
62835c4bbdfSmrg        if (nCharInfos > 0) {
62935c4bbdfSmrg            if (shmid == -1)
63035c4bbdfSmrg                free(pIndex2UniqIndex);
63135c4bbdfSmrg            if (!pDesc)
63235c4bbdfSmrg                free(pCI);
63335c4bbdfSmrg        }
63435c4bbdfSmrg        return Success;
63505b261ecSmrg    }
63605b261ecSmrg}
63705b261ecSmrg
63805b261ecSmrgstatic int
63935c4bbdfSmrgProcXF86BigfontDispatch(ClientPtr client)
64005b261ecSmrg{
64105b261ecSmrg    REQUEST(xReq);
64205b261ecSmrg
64305b261ecSmrg    switch (stuff->data) {
64435c4bbdfSmrg    case X_XF86BigfontQueryVersion:
64535c4bbdfSmrg        return ProcXF86BigfontQueryVersion(client);
64635c4bbdfSmrg    case X_XF86BigfontQueryFont:
64735c4bbdfSmrg        return ProcXF86BigfontQueryFont(client);
64835c4bbdfSmrg    default:
64935c4bbdfSmrg        return BadRequest;
65005b261ecSmrg    }
65105b261ecSmrg}
65205b261ecSmrg
6531b5d61b8Smrgstatic int _X_COLD
65435c4bbdfSmrgSProcXF86BigfontQueryVersion(ClientPtr client)
65505b261ecSmrg{
65605b261ecSmrg    REQUEST(xXF86BigfontQueryVersionReq);
65705b261ecSmrg
65835c4bbdfSmrg    swaps(&stuff->length);
65905b261ecSmrg    return ProcXF86BigfontQueryVersion(client);
66005b261ecSmrg}
66105b261ecSmrg
6621b5d61b8Smrgstatic int _X_COLD
66335c4bbdfSmrgSProcXF86BigfontQueryFont(ClientPtr client)
66405b261ecSmrg{
66505b261ecSmrg    REQUEST(xXF86BigfontQueryFontReq);
66605b261ecSmrg
66735c4bbdfSmrg    swaps(&stuff->length);
66805b261ecSmrg    REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq);
66935c4bbdfSmrg    swapl(&stuff->id);
67005b261ecSmrg    return ProcXF86BigfontQueryFont(client);
67105b261ecSmrg}
67205b261ecSmrg
6731b5d61b8Smrgstatic int _X_COLD
67435c4bbdfSmrgSProcXF86BigfontDispatch(ClientPtr client)
67505b261ecSmrg{
67605b261ecSmrg    REQUEST(xReq);
67705b261ecSmrg
67805b261ecSmrg    switch (stuff->data) {
67935c4bbdfSmrg    case X_XF86BigfontQueryVersion:
68035c4bbdfSmrg        return SProcXF86BigfontQueryVersion(client);
68135c4bbdfSmrg    case X_XF86BigfontQueryFont:
68235c4bbdfSmrg        return SProcXF86BigfontQueryFont(client);
68335c4bbdfSmrg    default:
68435c4bbdfSmrg        return BadRequest;
68505b261ecSmrg    }
68605b261ecSmrg}
6879ace9065Smrg
6889ace9065Smrgvoid
6899ace9065SmrgXFree86BigfontExtensionInit(void)
6909ace9065Smrg{
6919ace9065Smrg    if (AddExtension(XF86BIGFONTNAME,
69235c4bbdfSmrg                     XF86BigfontNumberEvents,
69335c4bbdfSmrg                     XF86BigfontNumberErrors,
69435c4bbdfSmrg                     ProcXF86BigfontDispatch,
69535c4bbdfSmrg                     SProcXF86BigfontDispatch,
69635c4bbdfSmrg                     XF86BigfontResetProc, StandardMinorOpcode)) {
6979ace9065Smrg#ifdef HAS_SHM
6989ace9065Smrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL
69935c4bbdfSmrg        /*
70035c4bbdfSmrg         * Note: Local-clients will not be optimized without shared memory
70135c4bbdfSmrg         * support. Remote-client optimization does not depend on shared
70235c4bbdfSmrg         * memory support.  Thus, the extension is still registered even
70335c4bbdfSmrg         * when shared memory support is not functional.
70435c4bbdfSmrg         */
70535c4bbdfSmrg        if (!CheckForShmSyscall()) {
70635c4bbdfSmrg            ErrorF(XF86BIGFONTNAME
70735c4bbdfSmrg                   " extension local-client optimization disabled due to lack of shared memory support in the kernel\n");
70835c4bbdfSmrg            return;
70935c4bbdfSmrg        }
7109ace9065Smrg#endif
7119ace9065Smrg
71235c4bbdfSmrg        srand((unsigned int) time(NULL));
71335c4bbdfSmrg        signature = ((unsigned int) (65536.0 / (RAND_MAX + 1.0) * rand()) << 16)
71435c4bbdfSmrg            + (unsigned int) (65536.0 / (RAND_MAX + 1.0) * rand());
71535c4bbdfSmrg        /* fprintf(stderr, "signature = 0x%08X\n", signature); */
7169ace9065Smrg
7171b5d61b8Smrg        FontShmdescIndex = xfont2_allocate_font_private_index();
7189ace9065Smrg
7199ace9065Smrg#if !defined(CSRG_BASED) && !defined(__CYGWIN__)
72035c4bbdfSmrg        pagesize = SHMLBA;
7219ace9065Smrg#else
72235c4bbdfSmrg#ifdef _SC_PAGESIZE
72335c4bbdfSmrg        pagesize = sysconf(_SC_PAGESIZE);
72435c4bbdfSmrg#else
72535c4bbdfSmrg        pagesize = getpagesize();
72635c4bbdfSmrg#endif
7279ace9065Smrg#endif
7289ace9065Smrg#endif
7299ace9065Smrg    }
7309ace9065Smrg}
731