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