xf86bigfont.c revision 4642e01f
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#if defined(linux) && (!defined(__GNU_LIBRARY__) || __GNU_LIBRARY__ < 2)
4405b261ecSmrg/* libc4 does not define __GNU_LIBRARY__, libc5 defines __GNU_LIBRARY__ as 1 */
4505b261ecSmrg/* Linux libc4 and libc5 only (because glibc doesn't include kernel headers):
4605b261ecSmrg   Linux 2.0.x and 2.2.x define SHMLBA as PAGE_SIZE, but forget to define
4705b261ecSmrg   PAGE_SIZE. It is defined in <asm/page.h>. */
4805b261ecSmrg#include <asm/page.h>
4905b261ecSmrg#endif
5005b261ecSmrg#ifdef SVR4
5105b261ecSmrg#include <sys/sysmacros.h>
5205b261ecSmrg#endif
534642e01fSmrg#if defined(__CYGWIN__) || defined(__SCO__)
5405b261ecSmrg#include <sys/param.h>
5505b261ecSmrg#include <sys/sysmacros.h>
5605b261ecSmrg#endif
5705b261ecSmrg#include <sys/ipc.h>
5805b261ecSmrg#include <sys/shm.h>
5905b261ecSmrg#include <sys/stat.h>
6005b261ecSmrg#include <stdlib.h>
6105b261ecSmrg#include <unistd.h>
6205b261ecSmrg#include <time.h>
6305b261ecSmrg#include <errno.h>
6405b261ecSmrg#endif
6505b261ecSmrg
6605b261ecSmrg#include <X11/X.h>
6705b261ecSmrg#include <X11/Xproto.h>
6805b261ecSmrg#include "misc.h"
6905b261ecSmrg#include "os.h"
7005b261ecSmrg#include "dixstruct.h"
7105b261ecSmrg#include "gcstruct.h"
7205b261ecSmrg#include "dixfontstr.h"
7305b261ecSmrg#include "extnsionst.h"
7405b261ecSmrg
7505b261ecSmrg#define _XF86BIGFONT_SERVER_
7605b261ecSmrg#include <X11/extensions/xf86bigfstr.h>
7705b261ecSmrg
7805b261ecSmrgstatic void XF86BigfontResetProc(
7905b261ecSmrg    ExtensionEntry *	/* extEntry */
8005b261ecSmrg    );
8105b261ecSmrg
8205b261ecSmrgstatic DISPATCH_PROC(ProcXF86BigfontDispatch);
8305b261ecSmrgstatic DISPATCH_PROC(ProcXF86BigfontQueryVersion);
8405b261ecSmrgstatic DISPATCH_PROC(ProcXF86BigfontQueryFont);
8505b261ecSmrgstatic DISPATCH_PROC(SProcXF86BigfontDispatch);
8605b261ecSmrgstatic DISPATCH_PROC(SProcXF86BigfontQueryVersion);
8705b261ecSmrgstatic DISPATCH_PROC(SProcXF86BigfontQueryFont);
8805b261ecSmrg
8905b261ecSmrg#ifdef HAS_SHM
9005b261ecSmrg
9105b261ecSmrg/* A random signature, transmitted to the clients so they can verify that the
9205b261ecSmrg   shared memory segment they are attaching to was really established by the
9305b261ecSmrg   X server they are talking to. */
9405b261ecSmrgstatic CARD32 signature;
9505b261ecSmrg
9605b261ecSmrg/* Index for additional information stored in a FontRec's devPrivates array. */
9705b261ecSmrgstatic int FontShmdescIndex;
9805b261ecSmrg
9905b261ecSmrgstatic unsigned int pagesize;
10005b261ecSmrg
10105b261ecSmrgstatic Bool badSysCall = FALSE;
10205b261ecSmrg
10305b261ecSmrg#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
10405b261ecSmrg
10505b261ecSmrg#include <sys/signal.h>
10605b261ecSmrg
10705b261ecSmrgstatic void
10805b261ecSmrgSigSysHandler(
10905b261ecSmrg     int signo)
11005b261ecSmrg{
11105b261ecSmrg    badSysCall = TRUE;
11205b261ecSmrg}
11305b261ecSmrg
11405b261ecSmrgstatic Bool
11505b261ecSmrgCheckForShmSyscall(void)
11605b261ecSmrg{
11705b261ecSmrg    void (*oldHandler)(int);
11805b261ecSmrg    int shmid = -1;
11905b261ecSmrg
12005b261ecSmrg    /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
12105b261ecSmrg    oldHandler = signal(SIGSYS, SigSysHandler);
12205b261ecSmrg
12305b261ecSmrg    badSysCall = FALSE;
12405b261ecSmrg    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
12505b261ecSmrg    if (shmid != -1)
12605b261ecSmrg    {
12705b261ecSmrg        /* Successful allocation - clean up */
12805b261ecSmrg	shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL);
12905b261ecSmrg    }
13005b261ecSmrg    else
13105b261ecSmrg    {
13205b261ecSmrg        /* Allocation failed */
13305b261ecSmrg        badSysCall = TRUE;
13405b261ecSmrg    }
13505b261ecSmrg    signal(SIGSYS, oldHandler);
13605b261ecSmrg    return (!badSysCall);
13705b261ecSmrg}
13805b261ecSmrg
13905b261ecSmrg#define MUST_CHECK_FOR_SHM_SYSCALL
14005b261ecSmrg
14105b261ecSmrg#endif
14205b261ecSmrg
14305b261ecSmrg#endif
14405b261ecSmrg
14505b261ecSmrgvoid
14605b261ecSmrgXFree86BigfontExtensionInit()
14705b261ecSmrg{
14805b261ecSmrg    if (AddExtension(XF86BIGFONTNAME,
14905b261ecSmrg		     XF86BigfontNumberEvents,
15005b261ecSmrg		     XF86BigfontNumberErrors,
15105b261ecSmrg		     ProcXF86BigfontDispatch,
15205b261ecSmrg		     SProcXF86BigfontDispatch,
15305b261ecSmrg		     XF86BigfontResetProc,
15405b261ecSmrg		     StandardMinorOpcode)) {
15505b261ecSmrg#ifdef HAS_SHM
15605b261ecSmrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL
15705b261ecSmrg	/*
15805b261ecSmrg	 * Note: Local-clients will not be optimized without shared memory
15905b261ecSmrg	 * support. Remote-client optimization does not depend on shared
16005b261ecSmrg	 * memory support.  Thus, the extension is still registered even
16105b261ecSmrg	 * when shared memory support is not functional.
16205b261ecSmrg	 */
16305b261ecSmrg	if (!CheckForShmSyscall()) {
16405b261ecSmrg	    ErrorF(XF86BIGFONTNAME " extension local-client optimization disabled due to lack of shared memory support in the kernel\n");
16505b261ecSmrg	    return;
16605b261ecSmrg	}
16705b261ecSmrg#endif
16805b261ecSmrg
16905b261ecSmrg	srand((unsigned int) time(NULL));
17005b261ecSmrg	signature = ((unsigned int) (65536.0/(RAND_MAX+1.0) * rand()) << 16)
17105b261ecSmrg	           + (unsigned int) (65536.0/(RAND_MAX+1.0) * rand());
17205b261ecSmrg	/* fprintf(stderr, "signature = 0x%08X\n", signature); */
17305b261ecSmrg
17405b261ecSmrg	FontShmdescIndex = AllocateFontPrivateIndex();
17505b261ecSmrg
17605b261ecSmrg#if !defined(CSRG_BASED) && !defined(__CYGWIN__)
17705b261ecSmrg	pagesize = SHMLBA;
17805b261ecSmrg#else
17905b261ecSmrg# ifdef _SC_PAGESIZE
18005b261ecSmrg	pagesize = sysconf(_SC_PAGESIZE);
18105b261ecSmrg# else
18205b261ecSmrg	pagesize = getpagesize();
18305b261ecSmrg# endif
18405b261ecSmrg#endif
18505b261ecSmrg#endif
18605b261ecSmrg    }
18705b261ecSmrg}
18805b261ecSmrg
18905b261ecSmrg
19005b261ecSmrg/* ========== Management of shared memory segments ========== */
19105b261ecSmrg
19205b261ecSmrg#ifdef HAS_SHM
19305b261ecSmrg
19405b261ecSmrg#ifdef __linux__
19505b261ecSmrg/* On Linux, shared memory marked as "removed" can still be attached.
19605b261ecSmrg   Nice feature, because the kernel will automatically free the associated
19705b261ecSmrg   storage when the server and all clients are gone. */
19805b261ecSmrg#define EARLY_REMOVE
19905b261ecSmrg#endif
20005b261ecSmrg
20105b261ecSmrgtypedef struct _ShmDesc {
20205b261ecSmrg    struct _ShmDesc *next;
20305b261ecSmrg    struct _ShmDesc **prev;
20405b261ecSmrg    int shmid;
20505b261ecSmrg    char *attach_addr;
20605b261ecSmrg} ShmDescRec, *ShmDescPtr;
20705b261ecSmrg
20805b261ecSmrgstatic ShmDescPtr ShmList = (ShmDescPtr) NULL;
20905b261ecSmrg
21005b261ecSmrgstatic ShmDescPtr
21105b261ecSmrgshmalloc(
21205b261ecSmrg    unsigned int size)
21305b261ecSmrg{
21405b261ecSmrg    ShmDescPtr pDesc;
21505b261ecSmrg    int shmid;
21605b261ecSmrg    char *addr;
21705b261ecSmrg
21805b261ecSmrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL
21905b261ecSmrg    if (pagesize == 0)
22005b261ecSmrg	return (ShmDescPtr) NULL;
22105b261ecSmrg#endif
22205b261ecSmrg
22305b261ecSmrg    /* On some older Linux systems, the number of shared memory segments
22405b261ecSmrg       system-wide is 127. In Linux 2.4, it is 4095.
22505b261ecSmrg       Therefore there is a tradeoff to be made between allocating a
22605b261ecSmrg       shared memory segment on one hand, and allocating memory and piping
22705b261ecSmrg       the glyph metrics on the other hand. If the glyph metrics size is
22805b261ecSmrg       small, we prefer the traditional way. */
22905b261ecSmrg    if (size < 3500)
23005b261ecSmrg	return (ShmDescPtr) NULL;
23105b261ecSmrg
23205b261ecSmrg    pDesc = (ShmDescRec *) xalloc(sizeof(ShmDescRec));
23305b261ecSmrg    if (!pDesc)
23405b261ecSmrg	return (ShmDescPtr) NULL;
23505b261ecSmrg
23605b261ecSmrg    size = (size + pagesize-1) & -pagesize;
23705b261ecSmrg    shmid = shmget(IPC_PRIVATE, size, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
23805b261ecSmrg    if (shmid == -1) {
2394642e01fSmrg	ErrorF(XF86BIGFONTNAME " extension: shmget() failed, size = %u, %s\n",
2404642e01fSmrg	       size, strerror(errno));
24105b261ecSmrg	xfree(pDesc);
24205b261ecSmrg	return (ShmDescPtr) NULL;
24305b261ecSmrg    }
24405b261ecSmrg
24505b261ecSmrg    if ((addr = shmat(shmid, 0, 0)) == (char *)-1) {
2464642e01fSmrg	ErrorF(XF86BIGFONTNAME " extension: shmat() failed, size = %u, %s\n",
2474642e01fSmrg	       size, strerror(errno));
24805b261ecSmrg	shmctl(shmid, IPC_RMID, (void *) 0);
24905b261ecSmrg	xfree(pDesc);
25005b261ecSmrg	return (ShmDescPtr) NULL;
25105b261ecSmrg    }
25205b261ecSmrg
25305b261ecSmrg#ifdef EARLY_REMOVE
25405b261ecSmrg    shmctl(shmid, IPC_RMID, (void *) 0);
25505b261ecSmrg#endif
25605b261ecSmrg
25705b261ecSmrg    pDesc->shmid = shmid;
25805b261ecSmrg    pDesc->attach_addr = addr;
25905b261ecSmrg    if (ShmList) ShmList->prev = &pDesc->next;
26005b261ecSmrg    pDesc->next = ShmList;
26105b261ecSmrg    pDesc->prev = &ShmList;
26205b261ecSmrg    ShmList = pDesc;
26305b261ecSmrg
26405b261ecSmrg    return pDesc;
26505b261ecSmrg}
26605b261ecSmrg
26705b261ecSmrgstatic void
26805b261ecSmrgshmdealloc(
26905b261ecSmrg    ShmDescPtr pDesc)
27005b261ecSmrg{
27105b261ecSmrg#ifndef EARLY_REMOVE
27205b261ecSmrg    shmctl(pDesc->shmid, IPC_RMID, (void *) 0);
27305b261ecSmrg#endif
27405b261ecSmrg    shmdt(pDesc->attach_addr);
27505b261ecSmrg
27605b261ecSmrg    if (pDesc->next) pDesc->next->prev = pDesc->prev;
27705b261ecSmrg    *pDesc->prev = pDesc->next;
27805b261ecSmrg    xfree(pDesc);
27905b261ecSmrg}
28005b261ecSmrg
28105b261ecSmrg#endif
28205b261ecSmrg
28305b261ecSmrg/* Called when a font is closed. */
28405b261ecSmrgvoid
28505b261ecSmrgXF86BigfontFreeFontShm(
28605b261ecSmrg    FontPtr pFont)
28705b261ecSmrg{
28805b261ecSmrg#ifdef HAS_SHM
28905b261ecSmrg    ShmDescPtr pDesc;
29005b261ecSmrg
29105b261ecSmrg    /* If during shutdown of the server, XF86BigfontCleanup() has already
29205b261ecSmrg     * called shmdealloc() for all segments, we don't need to do it here.
29305b261ecSmrg     */
29405b261ecSmrg    if (!ShmList)
29505b261ecSmrg	return;
29605b261ecSmrg
29705b261ecSmrg    pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex);
29805b261ecSmrg    if (pDesc)
29905b261ecSmrg	shmdealloc(pDesc);
30005b261ecSmrg#endif
30105b261ecSmrg}
30205b261ecSmrg
30305b261ecSmrg/* Called upon fatal signal. */
30405b261ecSmrgvoid
30505b261ecSmrgXF86BigfontCleanup()
30605b261ecSmrg{
30705b261ecSmrg#ifdef HAS_SHM
30805b261ecSmrg    while (ShmList)
30905b261ecSmrg	shmdealloc(ShmList);
31005b261ecSmrg#endif
31105b261ecSmrg}
31205b261ecSmrg
31305b261ecSmrg/* Called when a server generation dies. */
31405b261ecSmrgstatic void
31505b261ecSmrgXF86BigfontResetProc(
31605b261ecSmrg    ExtensionEntry* extEntry)
31705b261ecSmrg{
31805b261ecSmrg    /* This function is normally called from CloseDownExtensions(), called
31905b261ecSmrg     * from main(). It will be followed by a call to FreeAllResources(),
32005b261ecSmrg     * which will call XF86BigfontFreeFontShm() for each font. Thus it
32105b261ecSmrg     * appears that we do not need to do anything in this function. --
32205b261ecSmrg     * But I prefer to write robust code, and not keep shared memory lying
32305b261ecSmrg     * around when it's not needed any more. (Someone might close down the
32405b261ecSmrg     * extension without calling FreeAllResources()...)
32505b261ecSmrg     */
32605b261ecSmrg    XF86BigfontCleanup();
32705b261ecSmrg}
32805b261ecSmrg
32905b261ecSmrg
33005b261ecSmrg/* ========== Handling of extension specific requests ========== */
33105b261ecSmrg
33205b261ecSmrgstatic int
33305b261ecSmrgProcXF86BigfontQueryVersion(
33405b261ecSmrg    ClientPtr client)
33505b261ecSmrg{
33605b261ecSmrg    xXF86BigfontQueryVersionReply reply;
33705b261ecSmrg
33805b261ecSmrg    REQUEST_SIZE_MATCH(xXF86BigfontQueryVersionReq);
33905b261ecSmrg    reply.type = X_Reply;
34005b261ecSmrg    reply.length = 0;
34105b261ecSmrg    reply.sequenceNumber = client->sequence;
34205b261ecSmrg    reply.majorVersion = XF86BIGFONT_MAJOR_VERSION;
34305b261ecSmrg    reply.minorVersion = XF86BIGFONT_MINOR_VERSION;
34405b261ecSmrg    reply.uid = geteuid();
34505b261ecSmrg    reply.gid = getegid();
34605b261ecSmrg#ifdef HAS_SHM
34705b261ecSmrg    reply.signature = signature;
34805b261ecSmrg#else
34905b261ecSmrg    reply.signature = 0; /* This is redundant. Avoids uninitialized memory. */
35005b261ecSmrg#endif
35105b261ecSmrg    reply.capabilities =
35205b261ecSmrg#ifdef HAS_SHM
35305b261ecSmrg	(LocalClient(client) && !client->swapped ? XF86Bigfont_CAP_LocalShm : 0)
35405b261ecSmrg#else
35505b261ecSmrg	0
35605b261ecSmrg#endif
35705b261ecSmrg	; /* may add more bits here in future versions */
35805b261ecSmrg    if (client->swapped) {
35905b261ecSmrg	char tmp;
36005b261ecSmrg	swaps(&reply.sequenceNumber, tmp);
36105b261ecSmrg	swapl(&reply.length, tmp);
36205b261ecSmrg	swaps(&reply.majorVersion, tmp);
36305b261ecSmrg	swaps(&reply.minorVersion, tmp);
36405b261ecSmrg	swapl(&reply.uid, tmp);
36505b261ecSmrg	swapl(&reply.gid, tmp);
36605b261ecSmrg	swapl(&reply.signature, tmp);
36705b261ecSmrg    }
36805b261ecSmrg    WriteToClient(client,
36905b261ecSmrg		  sizeof(xXF86BigfontQueryVersionReply), (char *)&reply);
37005b261ecSmrg    return client->noClientException;
37105b261ecSmrg}
37205b261ecSmrg
37305b261ecSmrgstatic void
37405b261ecSmrgswapCharInfo(
37505b261ecSmrg    xCharInfo *pCI)
37605b261ecSmrg{
37705b261ecSmrg    char tmp;
37805b261ecSmrg
37905b261ecSmrg    swaps(&pCI->leftSideBearing, tmp);
38005b261ecSmrg    swaps(&pCI->rightSideBearing, tmp);
38105b261ecSmrg    swaps(&pCI->characterWidth, tmp);
38205b261ecSmrg    swaps(&pCI->ascent, tmp);
38305b261ecSmrg    swaps(&pCI->descent, tmp);
38405b261ecSmrg    swaps(&pCI->attributes, tmp);
38505b261ecSmrg}
38605b261ecSmrg
38705b261ecSmrg/* static CARD32 hashCI (xCharInfo *p); */
38805b261ecSmrg#define hashCI(p) \
38905b261ecSmrg	(CARD32)(((p->leftSideBearing << 27) + (p->leftSideBearing >> 5) + \
39005b261ecSmrg	          (p->rightSideBearing << 23) + (p->rightSideBearing >> 9) + \
39105b261ecSmrg	          (p->characterWidth << 16) + \
39205b261ecSmrg	          (p->ascent << 11) + (p->descent << 6)) ^ p->attributes)
39305b261ecSmrg
39405b261ecSmrgstatic int
39505b261ecSmrgProcXF86BigfontQueryFont(
39605b261ecSmrg    ClientPtr client)
39705b261ecSmrg{
39805b261ecSmrg    FontPtr pFont;
39905b261ecSmrg    REQUEST(xXF86BigfontQueryFontReq);
40005b261ecSmrg    CARD32 stuff_flags;
40105b261ecSmrg    xCharInfo* pmax;
40205b261ecSmrg    xCharInfo* pmin;
40305b261ecSmrg    int nCharInfos;
40405b261ecSmrg    int shmid;
40505b261ecSmrg#ifdef HAS_SHM
40605b261ecSmrg    ShmDescPtr pDesc;
40705b261ecSmrg#else
40805b261ecSmrg#define pDesc 0
40905b261ecSmrg#endif
41005b261ecSmrg    xCharInfo* pCI;
41105b261ecSmrg    CARD16* pIndex2UniqIndex;
41205b261ecSmrg    CARD16* pUniqIndex2Index;
41305b261ecSmrg    CARD32 nUniqCharInfos;
41405b261ecSmrg
41505b261ecSmrg#if 0
41605b261ecSmrg    REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq);
41705b261ecSmrg#else
41805b261ecSmrg    switch (client->req_len) {
41905b261ecSmrg	case 2: /* client with version 1.0 libX11 */
42005b261ecSmrg	    stuff_flags = (LocalClient(client) && !client->swapped ? XF86Bigfont_FLAGS_Shm : 0);
42105b261ecSmrg	    break;
42205b261ecSmrg	case 3: /* client with version 1.1 libX11 */
42305b261ecSmrg	    stuff_flags = stuff->flags;
42405b261ecSmrg	    break;
42505b261ecSmrg	default:
42605b261ecSmrg	    return BadLength;
42705b261ecSmrg    }
42805b261ecSmrg#endif
42905b261ecSmrg    client->errorValue = stuff->id;		/* EITHER font or gc */
43005b261ecSmrg    pFont = (FontPtr)SecurityLookupIDByType(client, stuff->id, RT_FONT,
4314642e01fSmrg					    DixGetAttrAccess);
43205b261ecSmrg    if (!pFont) {
43305b261ecSmrg	GC *pGC = (GC *) SecurityLookupIDByType(client, stuff->id, RT_GC,
4344642e01fSmrg						DixGetAttrAccess);
43505b261ecSmrg        if (!pGC) {
43605b261ecSmrg	    client->errorValue = stuff->id;
43705b261ecSmrg            return BadFont;    /* procotol spec says only error is BadFont */
43805b261ecSmrg	}
43905b261ecSmrg	pFont = pGC->font;
44005b261ecSmrg    }
44105b261ecSmrg
44205b261ecSmrg    pmax = FONTINKMAX(pFont);
44305b261ecSmrg    pmin = FONTINKMIN(pFont);
44405b261ecSmrg    nCharInfos =
44505b261ecSmrg       (pmax->rightSideBearing == pmin->rightSideBearing
44605b261ecSmrg        && pmax->leftSideBearing == pmin->leftSideBearing
44705b261ecSmrg        && pmax->descent == pmin->descent
44805b261ecSmrg        && pmax->ascent == pmin->ascent
44905b261ecSmrg        && pmax->characterWidth == pmin->characterWidth)
45005b261ecSmrg       ? 0 : N2dChars(pFont);
45105b261ecSmrg    shmid = -1;
45205b261ecSmrg    pCI = NULL;
45305b261ecSmrg    pIndex2UniqIndex = NULL;
45405b261ecSmrg    pUniqIndex2Index = NULL;
45505b261ecSmrg    nUniqCharInfos = 0;
45605b261ecSmrg
45705b261ecSmrg    if (nCharInfos > 0) {
45805b261ecSmrg#ifdef HAS_SHM
45905b261ecSmrg	if (!badSysCall)
46005b261ecSmrg	    pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex);
46105b261ecSmrg	else
46205b261ecSmrg	    pDesc = NULL;
46305b261ecSmrg	if (pDesc) {
46405b261ecSmrg	    pCI = (xCharInfo *) pDesc->attach_addr;
46505b261ecSmrg	    if (stuff_flags & XF86Bigfont_FLAGS_Shm)
46605b261ecSmrg		shmid = pDesc->shmid;
46705b261ecSmrg	} else {
46805b261ecSmrg	    if (stuff_flags & XF86Bigfont_FLAGS_Shm && !badSysCall)
46905b261ecSmrg		pDesc = shmalloc(nCharInfos * sizeof(xCharInfo)
47005b261ecSmrg				 + sizeof(CARD32));
47105b261ecSmrg	    if (pDesc) {
47205b261ecSmrg		pCI = (xCharInfo *) pDesc->attach_addr;
47305b261ecSmrg		shmid = pDesc->shmid;
47405b261ecSmrg	    } else {
47505b261ecSmrg#endif
47605b261ecSmrg		pCI = (xCharInfo *)
4774642e01fSmrg		      xalloc(nCharInfos * sizeof(xCharInfo));
47805b261ecSmrg		if (!pCI)
47905b261ecSmrg		    return BadAlloc;
48005b261ecSmrg#ifdef HAS_SHM
48105b261ecSmrg	    }
48205b261ecSmrg#endif
48305b261ecSmrg	    /* Fill nCharInfos starting at pCI. */
48405b261ecSmrg	    {
48505b261ecSmrg		xCharInfo* prCI = pCI;
48605b261ecSmrg		int ninfos = 0;
48705b261ecSmrg		int ncols = pFont->info.lastCol - pFont->info.firstCol + 1;
48805b261ecSmrg		int row;
48905b261ecSmrg		for (row = pFont->info.firstRow;
49005b261ecSmrg		     row <= pFont->info.lastRow && ninfos < nCharInfos;
49105b261ecSmrg		     row++) {
49205b261ecSmrg		    unsigned char chars[512];
49305b261ecSmrg		    xCharInfo* tmpCharInfos[256];
49405b261ecSmrg		    unsigned long count;
49505b261ecSmrg		    int col;
49605b261ecSmrg		    unsigned long i;
49705b261ecSmrg		    i = 0;
49805b261ecSmrg		    for (col = pFont->info.firstCol;
49905b261ecSmrg			 col <= pFont->info.lastCol;
50005b261ecSmrg			 col++) {
50105b261ecSmrg			chars[i++] = row;
50205b261ecSmrg			chars[i++] = col;
50305b261ecSmrg		    }
50405b261ecSmrg		    (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit,
50505b261ecSmrg					   &count, tmpCharInfos);
50605b261ecSmrg		    for (i = 0; i < count && ninfos < nCharInfos; i++) {
50705b261ecSmrg			*prCI++ = *tmpCharInfos[i];
50805b261ecSmrg			ninfos++;
50905b261ecSmrg		    }
51005b261ecSmrg		}
51105b261ecSmrg	    }
51205b261ecSmrg#ifdef HAS_SHM
51305b261ecSmrg	    if (pDesc && !badSysCall) {
51405b261ecSmrg		*(CARD32 *)(pCI + nCharInfos) = signature;
51505b261ecSmrg		if (!FontSetPrivate(pFont, FontShmdescIndex, pDesc)) {
51605b261ecSmrg		    shmdealloc(pDesc);
51705b261ecSmrg		    return BadAlloc;
51805b261ecSmrg		}
51905b261ecSmrg	    }
52005b261ecSmrg	}
52105b261ecSmrg#endif
52205b261ecSmrg	if (shmid == -1) {
52305b261ecSmrg	    /* Cannot use shared memory, so remove-duplicates the xCharInfos
52405b261ecSmrg	       using a temporary hash table. */
52505b261ecSmrg	    /* Note that CARD16 is suitable as index type, because
52605b261ecSmrg	       nCharInfos <= 0x10000. */
52705b261ecSmrg	    CARD32 hashModulus;
52805b261ecSmrg	    CARD16* pHash2UniqIndex;
52905b261ecSmrg	    CARD16* pUniqIndex2NextUniqIndex;
53005b261ecSmrg	    CARD32 NextIndex;
53105b261ecSmrg	    CARD32 NextUniqIndex;
53205b261ecSmrg	    CARD16* tmp;
53305b261ecSmrg	    CARD32 i, j;
53405b261ecSmrg
53505b261ecSmrg	    hashModulus = 67;
53605b261ecSmrg	    if (hashModulus > nCharInfos+1)
53705b261ecSmrg		hashModulus = nCharInfos+1;
53805b261ecSmrg
53905b261ecSmrg	    tmp = (CARD16*)
5404642e01fSmrg		  xalloc((4*nCharInfos+1) * sizeof(CARD16));
54105b261ecSmrg	    if (!tmp) {
5424642e01fSmrg		if (!pDesc) xfree(pCI);
54305b261ecSmrg		return BadAlloc;
54405b261ecSmrg	    }
54505b261ecSmrg	    pIndex2UniqIndex = tmp;
54605b261ecSmrg		/* nCharInfos elements */
54705b261ecSmrg	    pUniqIndex2Index = tmp + nCharInfos;
54805b261ecSmrg		/* max. nCharInfos elements */
54905b261ecSmrg	    pUniqIndex2NextUniqIndex = tmp + 2*nCharInfos;
55005b261ecSmrg		/* max. nCharInfos elements */
55105b261ecSmrg	    pHash2UniqIndex = tmp + 3*nCharInfos;
55205b261ecSmrg		/* hashModulus (<= nCharInfos+1) elements */
55305b261ecSmrg
55405b261ecSmrg	    /* Note that we can use 0xffff as end-of-list indicator, because
55505b261ecSmrg	       even if nCharInfos = 0x10000, 0xffff can not occur as valid
55605b261ecSmrg	       entry before the last element has been inserted. And once the
55705b261ecSmrg	       last element has been inserted, we don't need the hash table
55805b261ecSmrg	       any more. */
55905b261ecSmrg	    for (j = 0; j < hashModulus; j++)
56005b261ecSmrg		pHash2UniqIndex[j] = (CARD16)(-1);
56105b261ecSmrg
56205b261ecSmrg	    NextUniqIndex = 0;
56305b261ecSmrg	    for (NextIndex = 0; NextIndex < nCharInfos; NextIndex++) {
56405b261ecSmrg		xCharInfo* p = &pCI[NextIndex];
56505b261ecSmrg		CARD32 hashCode = hashCI(p) % hashModulus;
56605b261ecSmrg		for (i = pHash2UniqIndex[hashCode];
56705b261ecSmrg		     i != (CARD16)(-1);
56805b261ecSmrg		     i = pUniqIndex2NextUniqIndex[i]) {
56905b261ecSmrg		    j = pUniqIndex2Index[i];
57005b261ecSmrg		    if (pCI[j].leftSideBearing == p->leftSideBearing
57105b261ecSmrg			&& pCI[j].rightSideBearing == p->rightSideBearing
57205b261ecSmrg			&& pCI[j].characterWidth == p->characterWidth
57305b261ecSmrg			&& pCI[j].ascent == p->ascent
57405b261ecSmrg			&& pCI[j].descent == p->descent
57505b261ecSmrg			&& pCI[j].attributes == p->attributes)
57605b261ecSmrg			break;
57705b261ecSmrg		}
57805b261ecSmrg		if (i != (CARD16)(-1)) {
57905b261ecSmrg		    /* Found *p at Index j, UniqIndex i */
58005b261ecSmrg		    pIndex2UniqIndex[NextIndex] = i;
58105b261ecSmrg		} else {
58205b261ecSmrg		    /* Allocate a new entry in the Uniq table */
58305b261ecSmrg		    if (hashModulus <= 2*NextUniqIndex
58405b261ecSmrg			&& hashModulus < nCharInfos+1) {
58505b261ecSmrg			/* Time to increate hash table size */
58605b261ecSmrg			hashModulus = 2*hashModulus+1;
58705b261ecSmrg			if (hashModulus > nCharInfos+1)
58805b261ecSmrg			    hashModulus = nCharInfos+1;
58905b261ecSmrg			for (j = 0; j < hashModulus; j++)
59005b261ecSmrg			    pHash2UniqIndex[j] = (CARD16)(-1);
59105b261ecSmrg			for (i = 0; i < NextUniqIndex; i++)
59205b261ecSmrg			    pUniqIndex2NextUniqIndex[i] = (CARD16)(-1);
59305b261ecSmrg			for (i = 0; i < NextUniqIndex; i++) {
59405b261ecSmrg			    j = pUniqIndex2Index[i];
59505b261ecSmrg			    p = &pCI[j];
59605b261ecSmrg			    hashCode = hashCI(p) % hashModulus;
59705b261ecSmrg			    pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode];
59805b261ecSmrg			    pHash2UniqIndex[hashCode] = i;
59905b261ecSmrg			}
60005b261ecSmrg			p = &pCI[NextIndex];
60105b261ecSmrg			hashCode = hashCI(p) % hashModulus;
60205b261ecSmrg		    }
60305b261ecSmrg		    i = NextUniqIndex++;
60405b261ecSmrg		    pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode];
60505b261ecSmrg		    pHash2UniqIndex[hashCode] = i;
60605b261ecSmrg		    pUniqIndex2Index[i] = NextIndex;
60705b261ecSmrg		    pIndex2UniqIndex[NextIndex] = i;
60805b261ecSmrg		}
60905b261ecSmrg	    }
61005b261ecSmrg	    nUniqCharInfos = NextUniqIndex;
61105b261ecSmrg	    /* fprintf(stderr, "font metrics: nCharInfos = %d, nUniqCharInfos = %d, hashModulus = %d\n", nCharInfos, nUniqCharInfos, hashModulus); */
61205b261ecSmrg	}
61305b261ecSmrg    }
61405b261ecSmrg
61505b261ecSmrg    {
61605b261ecSmrg	int nfontprops = pFont->info.nprops;
61705b261ecSmrg	int rlength =
61805b261ecSmrg	   sizeof(xXF86BigfontQueryFontReply)
61905b261ecSmrg	   + nfontprops * sizeof(xFontProp)
62005b261ecSmrg	   + (nCharInfos > 0 && shmid == -1
62105b261ecSmrg	      ? nUniqCharInfos * sizeof(xCharInfo)
62205b261ecSmrg	        + (nCharInfos+1)/2 * 2 * sizeof(CARD16)
62305b261ecSmrg	      : 0);
62405b261ecSmrg	xXF86BigfontQueryFontReply* reply =
6254642e01fSmrg	   (xXF86BigfontQueryFontReply *) xalloc(rlength);
62605b261ecSmrg	char* p;
62705b261ecSmrg	if (!reply) {
62805b261ecSmrg	    if (nCharInfos > 0) {
6294642e01fSmrg		if (shmid == -1) xfree(pIndex2UniqIndex);
6304642e01fSmrg		if (!pDesc) xfree(pCI);
63105b261ecSmrg	    }
63205b261ecSmrg	    return BadAlloc;
63305b261ecSmrg	}
63405b261ecSmrg	reply->type = X_Reply;
63505b261ecSmrg	reply->length = (rlength - sizeof(xGenericReply)) >> 2;
63605b261ecSmrg	reply->sequenceNumber = client->sequence;
63705b261ecSmrg	reply->minBounds = pFont->info.ink_minbounds;
63805b261ecSmrg	reply->maxBounds = pFont->info.ink_maxbounds;
63905b261ecSmrg	reply->minCharOrByte2 = pFont->info.firstCol;
64005b261ecSmrg	reply->maxCharOrByte2 = pFont->info.lastCol;
64105b261ecSmrg	reply->defaultChar = pFont->info.defaultCh;
64205b261ecSmrg	reply->nFontProps = pFont->info.nprops;
64305b261ecSmrg	reply->drawDirection = pFont->info.drawDirection;
64405b261ecSmrg	reply->minByte1 = pFont->info.firstRow;
64505b261ecSmrg	reply->maxByte1 = pFont->info.lastRow;
64605b261ecSmrg	reply->allCharsExist = pFont->info.allExist;
64705b261ecSmrg	reply->fontAscent = pFont->info.fontAscent;
64805b261ecSmrg	reply->fontDescent = pFont->info.fontDescent;
64905b261ecSmrg	reply->nCharInfos = nCharInfos;
65005b261ecSmrg        reply->nUniqCharInfos = nUniqCharInfos;
65105b261ecSmrg	reply->shmid = shmid;
65205b261ecSmrg	reply->shmsegoffset = 0;
65305b261ecSmrg	if (client->swapped) {
65405b261ecSmrg	    char tmp;
65505b261ecSmrg	    swaps(&reply->sequenceNumber, tmp);
65605b261ecSmrg	    swapl(&reply->length, tmp);
65705b261ecSmrg	    swapCharInfo(&reply->minBounds);
65805b261ecSmrg	    swapCharInfo(&reply->maxBounds);
65905b261ecSmrg	    swaps(&reply->minCharOrByte2, tmp);
66005b261ecSmrg	    swaps(&reply->maxCharOrByte2, tmp);
66105b261ecSmrg	    swaps(&reply->defaultChar, tmp);
66205b261ecSmrg	    swaps(&reply->nFontProps, tmp);
66305b261ecSmrg	    swaps(&reply->fontAscent, tmp);
66405b261ecSmrg	    swaps(&reply->fontDescent, tmp);
66505b261ecSmrg	    swapl(&reply->nCharInfos, tmp);
66605b261ecSmrg	    swapl(&reply->nUniqCharInfos, tmp);
66705b261ecSmrg	    swapl(&reply->shmid, tmp);
66805b261ecSmrg	    swapl(&reply->shmsegoffset, tmp);
66905b261ecSmrg	}
67005b261ecSmrg	p = (char*) &reply[1];
67105b261ecSmrg	{
67205b261ecSmrg	    FontPropPtr pFP;
67305b261ecSmrg	    xFontProp* prFP;
67405b261ecSmrg	    int i;
67505b261ecSmrg	    for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) p;
67605b261ecSmrg		 i < nfontprops;
67705b261ecSmrg		 i++, pFP++, prFP++) {
67805b261ecSmrg		prFP->name = pFP->name;
67905b261ecSmrg		prFP->value = pFP->value;
68005b261ecSmrg		if (client->swapped) {
68105b261ecSmrg		    char tmp;
68205b261ecSmrg		    swapl(&prFP->name, tmp);
68305b261ecSmrg		    swapl(&prFP->value, tmp);
68405b261ecSmrg		}
68505b261ecSmrg	    }
68605b261ecSmrg	    p = (char*) prFP;
68705b261ecSmrg	}
68805b261ecSmrg	if (nCharInfos > 0 && shmid == -1) {
68905b261ecSmrg	    xCharInfo* pci;
69005b261ecSmrg	    CARD16* ps;
69105b261ecSmrg	    int i, j;
69205b261ecSmrg	    pci = (xCharInfo*) p;
69305b261ecSmrg	    for (i = 0; i < nUniqCharInfos; i++, pci++) {
69405b261ecSmrg		*pci = pCI[pUniqIndex2Index[i]];
69505b261ecSmrg		if (client->swapped)
69605b261ecSmrg		    swapCharInfo(pci);
69705b261ecSmrg	    }
69805b261ecSmrg	    ps = (CARD16*) pci;
69905b261ecSmrg	    for (j = 0; j < nCharInfos; j++, ps++) {
70005b261ecSmrg		*ps = pIndex2UniqIndex[j];
70105b261ecSmrg		if (client->swapped) {
70205b261ecSmrg		    char tmp;
70305b261ecSmrg		    swaps(ps, tmp);
70405b261ecSmrg		}
70505b261ecSmrg	    }
70605b261ecSmrg	}
70705b261ecSmrg	WriteToClient(client, rlength, (char *)reply);
7084642e01fSmrg	xfree(reply);
70905b261ecSmrg	if (nCharInfos > 0) {
7104642e01fSmrg	    if (shmid == -1) xfree(pIndex2UniqIndex);
7114642e01fSmrg	    if (!pDesc) xfree(pCI);
71205b261ecSmrg	}
71305b261ecSmrg	return (client->noClientException);
71405b261ecSmrg    }
71505b261ecSmrg}
71605b261ecSmrg
71705b261ecSmrgstatic int
71805b261ecSmrgProcXF86BigfontDispatch(
71905b261ecSmrg    ClientPtr client)
72005b261ecSmrg{
72105b261ecSmrg    REQUEST(xReq);
72205b261ecSmrg
72305b261ecSmrg    switch (stuff->data) {
72405b261ecSmrg	case X_XF86BigfontQueryVersion:
72505b261ecSmrg	    return ProcXF86BigfontQueryVersion(client);
72605b261ecSmrg	case X_XF86BigfontQueryFont:
72705b261ecSmrg	    return ProcXF86BigfontQueryFont(client);
72805b261ecSmrg	default:
72905b261ecSmrg	    return BadRequest;
73005b261ecSmrg    }
73105b261ecSmrg}
73205b261ecSmrg
73305b261ecSmrgstatic int
73405b261ecSmrgSProcXF86BigfontQueryVersion(
73505b261ecSmrg    ClientPtr client)
73605b261ecSmrg{
73705b261ecSmrg    REQUEST(xXF86BigfontQueryVersionReq);
73805b261ecSmrg    char tmp;
73905b261ecSmrg
74005b261ecSmrg    swaps(&stuff->length, tmp);
74105b261ecSmrg    return ProcXF86BigfontQueryVersion(client);
74205b261ecSmrg}
74305b261ecSmrg
74405b261ecSmrgstatic int
74505b261ecSmrgSProcXF86BigfontQueryFont(
74605b261ecSmrg    ClientPtr client)
74705b261ecSmrg{
74805b261ecSmrg    REQUEST(xXF86BigfontQueryFontReq);
74905b261ecSmrg    char tmp;
75005b261ecSmrg
75105b261ecSmrg    swaps(&stuff->length, tmp);
75205b261ecSmrg    REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq);
75305b261ecSmrg    swapl(&stuff->id, tmp);
75405b261ecSmrg    return ProcXF86BigfontQueryFont(client);
75505b261ecSmrg}
75605b261ecSmrg
75705b261ecSmrgstatic int
75805b261ecSmrgSProcXF86BigfontDispatch(
75905b261ecSmrg    ClientPtr client)
76005b261ecSmrg{
76105b261ecSmrg    REQUEST(xReq);
76205b261ecSmrg
76305b261ecSmrg    switch (stuff->data) {
76405b261ecSmrg	case X_XF86BigfontQueryVersion:
76505b261ecSmrg	    return SProcXF86BigfontQueryVersion(client);
76605b261ecSmrg	case X_XF86BigfontQueryFont:
76705b261ecSmrg	    return SProcXF86BigfontQueryFont(client);
76805b261ecSmrg	default:
76905b261ecSmrg	    return BadRequest;
77005b261ecSmrg    }
77105b261ecSmrg}
772