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