xf86bigfont.c revision 9ace9065
1/*
2 * BIGFONT extension for sharing font metrics between clients (if possible)
3 * and for transmitting font metrics to clients in a compressed form.
4 *
5 * Copyright (c) 1999-2000  Bruno Haible
6 * Copyright (c) 1999-2000  The XFree86 Project, Inc.
7 */
8
9/* THIS IS NOT AN X CONSORTIUM STANDARD */
10
11/*
12 * Big fonts suffer from the following: All clients that have opened a
13 * font can access the complete glyph metrics array (the XFontStruct member
14 * `per_char') directly, without going through a macro. Moreover these
15 * glyph metrics are ink metrics, i.e. are not redundant even for a
16 * fixed-width font. For a Unicode font, the size of this array is 768 KB.
17 *
18 * Problems: 1. It eats a lot of memory in each client. 2. All this glyph
19 * metrics data is piped through the socket when the font is opened.
20 *
21 * This extension addresses these two problems for local clients, by using
22 * shared memory. It also addresses the second problem for non-local clients,
23 * by compressing the data before transmit by a factor of nearly 6.
24 *
25 * If you use this extension, your OS ought to nicely support shared memory.
26 * This means: Shared memory should be swappable to the swap, and the limits
27 * should be high enough (SHMMNI at least 64, SHMMAX at least 768 KB,
28 * SHMALL at least 48 MB). It is a plus if your OS allows shmat() calls
29 * on segments that have already been marked "removed", because it permits
30 * these segments to be cleaned up by the OS if the X server is killed with
31 * signal SIGKILL.
32 *
33 * This extension is transparently exploited by Xlib (functions XQueryFont,
34 * XLoadQueryFont).
35 */
36
37#ifdef HAVE_DIX_CONFIG_H
38#include <dix-config.h>
39#endif
40
41#include <sys/types.h>
42#ifdef HAS_SHM
43#if defined(linux) && (!defined(__GNU_LIBRARY__) || __GNU_LIBRARY__ < 2)
44/* libc4 does not define __GNU_LIBRARY__, libc5 defines __GNU_LIBRARY__ as 1 */
45/* Linux libc4 and libc5 only (because glibc doesn't include kernel headers):
46   Linux 2.0.x and 2.2.x define SHMLBA as PAGE_SIZE, but forget to define
47   PAGE_SIZE. It is defined in <asm/page.h>. */
48#include <asm/page.h>
49#endif
50#ifdef SVR4
51#include <sys/sysmacros.h>
52#endif
53#if defined(__CYGWIN__)
54#include <sys/param.h>
55#include <sys/sysmacros.h>
56#endif
57#include <sys/ipc.h>
58#include <sys/shm.h>
59#include <sys/stat.h>
60#include <stdlib.h>
61#include <unistd.h>
62#include <time.h>
63#include <errno.h>
64#endif
65
66#include <X11/X.h>
67#include <X11/Xproto.h>
68#include "misc.h"
69#include "os.h"
70#include "dixstruct.h"
71#include "gcstruct.h"
72#include "dixfontstr.h"
73#include "extnsionst.h"
74#include "protocol-versions.h"
75
76#include <X11/extensions/xf86bigfproto.h>
77#include "xf86bigfontsrv.h"
78
79static void XF86BigfontResetProc(
80    ExtensionEntry *	/* extEntry */
81    );
82
83
84#ifdef HAS_SHM
85
86/* A random signature, transmitted to the clients so they can verify that the
87   shared memory segment they are attaching to was really established by the
88   X server they are talking to. */
89static CARD32 signature;
90
91/* Index for additional information stored in a FontRec's devPrivates array. */
92static int FontShmdescIndex;
93
94static unsigned int pagesize;
95
96static Bool badSysCall = FALSE;
97
98#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
99
100#include <sys/signal.h>
101
102static void
103SigSysHandler(
104     int signo)
105{
106    badSysCall = TRUE;
107}
108
109static Bool
110CheckForShmSyscall(void)
111{
112    void (*oldHandler)(int);
113    int shmid = -1;
114
115    /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
116    oldHandler = signal(SIGSYS, SigSysHandler);
117
118    badSysCall = FALSE;
119    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
120    if (shmid != -1)
121    {
122        /* Successful allocation - clean up */
123	shmctl(shmid, IPC_RMID, NULL);
124    }
125    else
126    {
127        /* Allocation failed */
128        badSysCall = TRUE;
129    }
130    signal(SIGSYS, oldHandler);
131    return !badSysCall;
132}
133
134#define MUST_CHECK_FOR_SHM_SYSCALL
135
136#endif
137
138#endif
139
140/* ========== Management of shared memory segments ========== */
141
142#ifdef HAS_SHM
143
144#ifdef __linux__
145/* On Linux, shared memory marked as "removed" can still be attached.
146   Nice feature, because the kernel will automatically free the associated
147   storage when the server and all clients are gone. */
148#define EARLY_REMOVE
149#endif
150
151typedef struct _ShmDesc {
152    struct _ShmDesc *next;
153    struct _ShmDesc **prev;
154    int shmid;
155    char *attach_addr;
156} ShmDescRec, *ShmDescPtr;
157
158static ShmDescPtr ShmList = (ShmDescPtr) NULL;
159
160static ShmDescPtr
161shmalloc(
162    unsigned int size)
163{
164    ShmDescPtr pDesc;
165    int shmid;
166    char *addr;
167
168#ifdef MUST_CHECK_FOR_SHM_SYSCALL
169    if (pagesize == 0)
170	return (ShmDescPtr) NULL;
171#endif
172
173    /* On some older Linux systems, the number of shared memory segments
174       system-wide is 127. In Linux 2.4, it is 4095.
175       Therefore there is a tradeoff to be made between allocating a
176       shared memory segment on one hand, and allocating memory and piping
177       the glyph metrics on the other hand. If the glyph metrics size is
178       small, we prefer the traditional way. */
179    if (size < 3500)
180	return (ShmDescPtr) NULL;
181
182    pDesc = malloc(sizeof(ShmDescRec));
183    if (!pDesc)
184	return (ShmDescPtr) NULL;
185
186    size = (size + pagesize-1) & -pagesize;
187    shmid = shmget(IPC_PRIVATE, size, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
188    if (shmid == -1) {
189	ErrorF(XF86BIGFONTNAME " extension: shmget() failed, size = %u, %s\n",
190	       size, strerror(errno));
191	free(pDesc);
192	return (ShmDescPtr) NULL;
193    }
194
195    if ((addr = shmat(shmid, 0, 0)) == (char *)-1) {
196	ErrorF(XF86BIGFONTNAME " extension: shmat() failed, size = %u, %s\n",
197	       size, strerror(errno));
198	shmctl(shmid, IPC_RMID, (void *) 0);
199	free(pDesc);
200	return (ShmDescPtr) NULL;
201    }
202
203#ifdef EARLY_REMOVE
204    shmctl(shmid, IPC_RMID, (void *) 0);
205#endif
206
207    pDesc->shmid = shmid;
208    pDesc->attach_addr = addr;
209    if (ShmList) ShmList->prev = &pDesc->next;
210    pDesc->next = ShmList;
211    pDesc->prev = &ShmList;
212    ShmList = pDesc;
213
214    return pDesc;
215}
216
217static void
218shmdealloc(
219    ShmDescPtr pDesc)
220{
221#ifndef EARLY_REMOVE
222    shmctl(pDesc->shmid, IPC_RMID, (void *) 0);
223#endif
224    shmdt(pDesc->attach_addr);
225
226    if (pDesc->next) pDesc->next->prev = pDesc->prev;
227    *pDesc->prev = pDesc->next;
228    free(pDesc);
229}
230
231#endif
232
233/* Called when a font is closed. */
234void
235XF86BigfontFreeFontShm(
236    FontPtr pFont)
237{
238#ifdef HAS_SHM
239    ShmDescPtr pDesc;
240
241    /* If during shutdown of the server, XF86BigfontCleanup() has already
242     * called shmdealloc() for all segments, we don't need to do it here.
243     */
244    if (!ShmList)
245	return;
246
247    pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex);
248    if (pDesc)
249	shmdealloc(pDesc);
250#endif
251}
252
253/* Called upon fatal signal. */
254void
255XF86BigfontCleanup(void)
256{
257#ifdef HAS_SHM
258    while (ShmList)
259	shmdealloc(ShmList);
260#endif
261}
262
263/* Called when a server generation dies. */
264static void
265XF86BigfontResetProc(
266    ExtensionEntry* extEntry)
267{
268    /* This function is normally called from CloseDownExtensions(), called
269     * from main(). It will be followed by a call to FreeAllResources(),
270     * which will call XF86BigfontFreeFontShm() for each font. Thus it
271     * appears that we do not need to do anything in this function. --
272     * But I prefer to write robust code, and not keep shared memory lying
273     * around when it's not needed any more. (Someone might close down the
274     * extension without calling FreeAllResources()...)
275     */
276    XF86BigfontCleanup();
277}
278
279
280/* ========== Handling of extension specific requests ========== */
281
282static int
283ProcXF86BigfontQueryVersion(
284    ClientPtr client)
285{
286    xXF86BigfontQueryVersionReply reply;
287
288    REQUEST_SIZE_MATCH(xXF86BigfontQueryVersionReq);
289    reply.type = X_Reply;
290    reply.length = 0;
291    reply.sequenceNumber = client->sequence;
292    reply.majorVersion = SERVER_XF86BIGFONT_MAJOR_VERSION;
293    reply.minorVersion = SERVER_XF86BIGFONT_MINOR_VERSION;
294    reply.uid = geteuid();
295    reply.gid = getegid();
296#ifdef HAS_SHM
297    reply.signature = signature;
298#else
299    reply.signature = 0; /* This is redundant. Avoids uninitialized memory. */
300#endif
301    reply.capabilities =
302#ifdef HAS_SHM
303	(LocalClient(client) && !client->swapped ? XF86Bigfont_CAP_LocalShm : 0)
304#else
305	0
306#endif
307	; /* may add more bits here in future versions */
308    if (client->swapped) {
309	char tmp;
310	swaps(&reply.sequenceNumber, tmp);
311	swapl(&reply.length, tmp);
312	swaps(&reply.majorVersion, tmp);
313	swaps(&reply.minorVersion, tmp);
314	swapl(&reply.uid, tmp);
315	swapl(&reply.gid, tmp);
316	swapl(&reply.signature, tmp);
317    }
318    WriteToClient(client,
319		  sizeof(xXF86BigfontQueryVersionReply), (char *)&reply);
320    return Success;
321}
322
323static void
324swapCharInfo(
325    xCharInfo *pCI)
326{
327    char tmp;
328
329    swaps(&pCI->leftSideBearing, tmp);
330    swaps(&pCI->rightSideBearing, tmp);
331    swaps(&pCI->characterWidth, tmp);
332    swaps(&pCI->ascent, tmp);
333    swaps(&pCI->descent, tmp);
334    swaps(&pCI->attributes, tmp);
335}
336
337/* static CARD32 hashCI (xCharInfo *p); */
338#define hashCI(p) \
339	(CARD32)(((p->leftSideBearing << 27) + (p->leftSideBearing >> 5) + \
340	          (p->rightSideBearing << 23) + (p->rightSideBearing >> 9) + \
341	          (p->characterWidth << 16) + \
342	          (p->ascent << 11) + (p->descent << 6)) ^ p->attributes)
343
344static int
345ProcXF86BigfontQueryFont(
346    ClientPtr client)
347{
348    FontPtr pFont;
349    REQUEST(xXF86BigfontQueryFontReq);
350    CARD32 stuff_flags;
351    xCharInfo* pmax;
352    xCharInfo* pmin;
353    int nCharInfos;
354    int shmid;
355#ifdef HAS_SHM
356    ShmDescPtr pDesc = NULL;
357#else
358#define pDesc 0
359#endif
360    xCharInfo* pCI;
361    CARD16* pIndex2UniqIndex;
362    CARD16* pUniqIndex2Index;
363    CARD32 nUniqCharInfos;
364
365#if 0
366    REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq);
367#else
368    switch (client->req_len) {
369	case 2: /* client with version 1.0 libX11 */
370	    stuff_flags = (LocalClient(client) && !client->swapped ? XF86Bigfont_FLAGS_Shm : 0);
371	    break;
372	case 3: /* client with version 1.1 libX11 */
373	    stuff_flags = stuff->flags;
374	    break;
375	default:
376	    return BadLength;
377    }
378#endif
379    if (dixLookupFontable(&pFont, stuff->id, client, DixGetAttrAccess) != Success)
380	return BadFont;    /* procotol spec says only error is BadFont */
381
382    pmax = FONTINKMAX(pFont);
383    pmin = FONTINKMIN(pFont);
384    nCharInfos =
385       (pmax->rightSideBearing == pmin->rightSideBearing
386        && pmax->leftSideBearing == pmin->leftSideBearing
387        && pmax->descent == pmin->descent
388        && pmax->ascent == pmin->ascent
389        && pmax->characterWidth == pmin->characterWidth)
390       ? 0 : N2dChars(pFont);
391    shmid = -1;
392    pCI = NULL;
393    pIndex2UniqIndex = NULL;
394    pUniqIndex2Index = NULL;
395    nUniqCharInfos = 0;
396
397    if (nCharInfos > 0) {
398#ifdef HAS_SHM
399	if (!badSysCall)
400	    pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex);
401	if (pDesc) {
402	    pCI = (xCharInfo *) pDesc->attach_addr;
403	    if (stuff_flags & XF86Bigfont_FLAGS_Shm)
404		shmid = pDesc->shmid;
405	} else {
406	    if (stuff_flags & XF86Bigfont_FLAGS_Shm && !badSysCall)
407		pDesc = shmalloc(nCharInfos * sizeof(xCharInfo)
408				 + sizeof(CARD32));
409	    if (pDesc) {
410		pCI = (xCharInfo *) pDesc->attach_addr;
411		shmid = pDesc->shmid;
412	    } else {
413#endif
414		pCI = malloc(nCharInfos * sizeof(xCharInfo));
415		if (!pCI)
416		    return BadAlloc;
417#ifdef HAS_SHM
418	    }
419#endif
420	    /* Fill nCharInfos starting at pCI. */
421	    {
422		xCharInfo* prCI = pCI;
423		int ninfos = 0;
424		int ncols = pFont->info.lastCol - pFont->info.firstCol + 1;
425		int row;
426		for (row = pFont->info.firstRow;
427		     row <= pFont->info.lastRow && ninfos < nCharInfos;
428		     row++) {
429		    unsigned char chars[512];
430		    xCharInfo* tmpCharInfos[256];
431		    unsigned long count;
432		    int col;
433		    unsigned long i;
434		    i = 0;
435		    for (col = pFont->info.firstCol;
436			 col <= pFont->info.lastCol;
437			 col++) {
438			chars[i++] = row;
439			chars[i++] = col;
440		    }
441		    (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit,
442					   &count, tmpCharInfos);
443		    for (i = 0; i < count && ninfos < nCharInfos; i++) {
444			*prCI++ = *tmpCharInfos[i];
445			ninfos++;
446		    }
447		}
448	    }
449#ifdef HAS_SHM
450	    if (pDesc && !badSysCall) {
451		*(CARD32 *)(pCI + nCharInfos) = signature;
452		if (!FontSetPrivate(pFont, FontShmdescIndex, pDesc)) {
453		    shmdealloc(pDesc);
454		    return BadAlloc;
455		}
456	    }
457	}
458#endif
459	if (shmid == -1) {
460	    /* Cannot use shared memory, so remove-duplicates the xCharInfos
461	       using a temporary hash table. */
462	    /* Note that CARD16 is suitable as index type, because
463	       nCharInfos <= 0x10000. */
464	    CARD32 hashModulus;
465	    CARD16* pHash2UniqIndex;
466	    CARD16* pUniqIndex2NextUniqIndex;
467	    CARD32 NextIndex;
468	    CARD32 NextUniqIndex;
469	    CARD16* tmp;
470	    CARD32 i, j;
471
472	    hashModulus = 67;
473	    if (hashModulus > nCharInfos+1)
474		hashModulus = nCharInfos+1;
475
476	    tmp = malloc((4*nCharInfos+1) * sizeof(CARD16));
477	    if (!tmp) {
478		if (!pDesc) free(pCI);
479		return BadAlloc;
480	    }
481	    pIndex2UniqIndex = tmp;
482		/* nCharInfos elements */
483	    pUniqIndex2Index = tmp + nCharInfos;
484		/* max. nCharInfos elements */
485	    pUniqIndex2NextUniqIndex = tmp + 2*nCharInfos;
486		/* max. nCharInfos elements */
487	    pHash2UniqIndex = tmp + 3*nCharInfos;
488		/* hashModulus (<= nCharInfos+1) elements */
489
490	    /* Note that we can use 0xffff as end-of-list indicator, because
491	       even if nCharInfos = 0x10000, 0xffff can not occur as valid
492	       entry before the last element has been inserted. And once the
493	       last element has been inserted, we don't need the hash table
494	       any more. */
495	    for (j = 0; j < hashModulus; j++)
496		pHash2UniqIndex[j] = (CARD16)(-1);
497
498	    NextUniqIndex = 0;
499	    for (NextIndex = 0; NextIndex < nCharInfos; NextIndex++) {
500		xCharInfo* p = &pCI[NextIndex];
501		CARD32 hashCode = hashCI(p) % hashModulus;
502		for (i = pHash2UniqIndex[hashCode];
503		     i != (CARD16)(-1);
504		     i = pUniqIndex2NextUniqIndex[i]) {
505		    j = pUniqIndex2Index[i];
506		    if (pCI[j].leftSideBearing == p->leftSideBearing
507			&& pCI[j].rightSideBearing == p->rightSideBearing
508			&& pCI[j].characterWidth == p->characterWidth
509			&& pCI[j].ascent == p->ascent
510			&& pCI[j].descent == p->descent
511			&& pCI[j].attributes == p->attributes)
512			break;
513		}
514		if (i != (CARD16)(-1)) {
515		    /* Found *p at Index j, UniqIndex i */
516		    pIndex2UniqIndex[NextIndex] = i;
517		} else {
518		    /* Allocate a new entry in the Uniq table */
519		    if (hashModulus <= 2*NextUniqIndex
520			&& hashModulus < nCharInfos+1) {
521			/* Time to increate hash table size */
522			hashModulus = 2*hashModulus+1;
523			if (hashModulus > nCharInfos+1)
524			    hashModulus = nCharInfos+1;
525			for (j = 0; j < hashModulus; j++)
526			    pHash2UniqIndex[j] = (CARD16)(-1);
527			for (i = 0; i < NextUniqIndex; i++)
528			    pUniqIndex2NextUniqIndex[i] = (CARD16)(-1);
529			for (i = 0; i < NextUniqIndex; i++) {
530			    j = pUniqIndex2Index[i];
531			    p = &pCI[j];
532			    hashCode = hashCI(p) % hashModulus;
533			    pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode];
534			    pHash2UniqIndex[hashCode] = i;
535			}
536			p = &pCI[NextIndex];
537			hashCode = hashCI(p) % hashModulus;
538		    }
539		    i = NextUniqIndex++;
540		    pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode];
541		    pHash2UniqIndex[hashCode] = i;
542		    pUniqIndex2Index[i] = NextIndex;
543		    pIndex2UniqIndex[NextIndex] = i;
544		}
545	    }
546	    nUniqCharInfos = NextUniqIndex;
547	    /* fprintf(stderr, "font metrics: nCharInfos = %d, nUniqCharInfos = %d, hashModulus = %d\n", nCharInfos, nUniqCharInfos, hashModulus); */
548	}
549    }
550
551    {
552	int nfontprops = pFont->info.nprops;
553	int rlength =
554	   sizeof(xXF86BigfontQueryFontReply)
555	   + nfontprops * sizeof(xFontProp)
556	   + (nCharInfos > 0 && shmid == -1
557	      ? nUniqCharInfos * sizeof(xCharInfo)
558	        + (nCharInfos+1)/2 * 2 * sizeof(CARD16)
559	      : 0);
560	xXF86BigfontQueryFontReply* reply = malloc(rlength);
561	char* p;
562	if (!reply) {
563	    if (nCharInfos > 0) {
564		if (shmid == -1) free(pIndex2UniqIndex);
565		if (!pDesc) free(pCI);
566	    }
567	    return BadAlloc;
568	}
569	reply->type = X_Reply;
570	reply->length = bytes_to_int32(rlength - sizeof(xGenericReply));
571	reply->sequenceNumber = client->sequence;
572	reply->minBounds = pFont->info.ink_minbounds;
573	reply->maxBounds = pFont->info.ink_maxbounds;
574	reply->minCharOrByte2 = pFont->info.firstCol;
575	reply->maxCharOrByte2 = pFont->info.lastCol;
576	reply->defaultChar = pFont->info.defaultCh;
577	reply->nFontProps = pFont->info.nprops;
578	reply->drawDirection = pFont->info.drawDirection;
579	reply->minByte1 = pFont->info.firstRow;
580	reply->maxByte1 = pFont->info.lastRow;
581	reply->allCharsExist = pFont->info.allExist;
582	reply->fontAscent = pFont->info.fontAscent;
583	reply->fontDescent = pFont->info.fontDescent;
584	reply->nCharInfos = nCharInfos;
585        reply->nUniqCharInfos = nUniqCharInfos;
586	reply->shmid = shmid;
587	reply->shmsegoffset = 0;
588	if (client->swapped) {
589	    char tmp;
590	    swaps(&reply->sequenceNumber, tmp);
591	    swapl(&reply->length, tmp);
592	    swapCharInfo(&reply->minBounds);
593	    swapCharInfo(&reply->maxBounds);
594	    swaps(&reply->minCharOrByte2, tmp);
595	    swaps(&reply->maxCharOrByte2, tmp);
596	    swaps(&reply->defaultChar, tmp);
597	    swaps(&reply->nFontProps, tmp);
598	    swaps(&reply->fontAscent, tmp);
599	    swaps(&reply->fontDescent, tmp);
600	    swapl(&reply->nCharInfos, tmp);
601	    swapl(&reply->nUniqCharInfos, tmp);
602	    swapl(&reply->shmid, tmp);
603	    swapl(&reply->shmsegoffset, tmp);
604	}
605	p = (char*) &reply[1];
606	{
607	    FontPropPtr pFP;
608	    xFontProp* prFP;
609	    int i;
610	    for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) p;
611		 i < nfontprops;
612		 i++, pFP++, prFP++) {
613		prFP->name = pFP->name;
614		prFP->value = pFP->value;
615		if (client->swapped) {
616		    char tmp;
617		    swapl(&prFP->name, tmp);
618		    swapl(&prFP->value, tmp);
619		}
620	    }
621	    p = (char*) prFP;
622	}
623	if (nCharInfos > 0 && shmid == -1) {
624	    xCharInfo* pci;
625	    CARD16* ps;
626	    int i, j;
627	    pci = (xCharInfo*) p;
628	    for (i = 0; i < nUniqCharInfos; i++, pci++) {
629		*pci = pCI[pUniqIndex2Index[i]];
630		if (client->swapped)
631		    swapCharInfo(pci);
632	    }
633	    ps = (CARD16*) pci;
634	    for (j = 0; j < nCharInfos; j++, ps++) {
635		*ps = pIndex2UniqIndex[j];
636		if (client->swapped) {
637		    char tmp;
638		    swaps(ps, tmp);
639		}
640	    }
641	}
642	WriteToClient(client, rlength, (char *)reply);
643	free(reply);
644	if (nCharInfos > 0) {
645	    if (shmid == -1) free(pIndex2UniqIndex);
646	    if (!pDesc) free(pCI);
647	}
648	return Success;
649    }
650}
651
652static int
653ProcXF86BigfontDispatch(
654    ClientPtr client)
655{
656    REQUEST(xReq);
657
658    switch (stuff->data) {
659	case X_XF86BigfontQueryVersion:
660	    return ProcXF86BigfontQueryVersion(client);
661	case X_XF86BigfontQueryFont:
662	    return ProcXF86BigfontQueryFont(client);
663	default:
664	    return BadRequest;
665    }
666}
667
668static int
669SProcXF86BigfontQueryVersion(
670    ClientPtr client)
671{
672    REQUEST(xXF86BigfontQueryVersionReq);
673    char tmp;
674
675    swaps(&stuff->length, tmp);
676    return ProcXF86BigfontQueryVersion(client);
677}
678
679static int
680SProcXF86BigfontQueryFont(
681    ClientPtr client)
682{
683    REQUEST(xXF86BigfontQueryFontReq);
684    char tmp;
685
686    swaps(&stuff->length, tmp);
687    REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq);
688    swapl(&stuff->id, tmp);
689    return ProcXF86BigfontQueryFont(client);
690}
691
692static int
693SProcXF86BigfontDispatch(
694    ClientPtr client)
695{
696    REQUEST(xReq);
697
698    switch (stuff->data) {
699	case X_XF86BigfontQueryVersion:
700	    return SProcXF86BigfontQueryVersion(client);
701	case X_XF86BigfontQueryFont:
702	    return SProcXF86BigfontQueryFont(client);
703	default:
704	    return BadRequest;
705    }
706}
707
708void
709XFree86BigfontExtensionInit(void)
710{
711    if (AddExtension(XF86BIGFONTNAME,
712		     XF86BigfontNumberEvents,
713		     XF86BigfontNumberErrors,
714		     ProcXF86BigfontDispatch,
715		     SProcXF86BigfontDispatch,
716		     XF86BigfontResetProc,
717		     StandardMinorOpcode)) {
718#ifdef HAS_SHM
719#ifdef MUST_CHECK_FOR_SHM_SYSCALL
720	/*
721	 * Note: Local-clients will not be optimized without shared memory
722	 * support. Remote-client optimization does not depend on shared
723	 * memory support.  Thus, the extension is still registered even
724	 * when shared memory support is not functional.
725	 */
726	if (!CheckForShmSyscall()) {
727	    ErrorF(XF86BIGFONTNAME " extension local-client optimization disabled due to lack of shared memory support in the kernel\n");
728	    return;
729	}
730#endif
731
732	srand((unsigned int) time(NULL));
733	signature = ((unsigned int) (65536.0/(RAND_MAX+1.0) * rand()) << 16)
734	           + (unsigned int) (65536.0/(RAND_MAX+1.0) * rand());
735	/* fprintf(stderr, "signature = 0x%08X\n", signature); */
736
737	FontShmdescIndex = AllocateFontPrivateIndex();
738
739#if !defined(CSRG_BASED) && !defined(__CYGWIN__)
740	pagesize = SHMLBA;
741#else
742# ifdef _SC_PAGESIZE
743	pagesize = sysconf(_SC_PAGESIZE);
744# else
745	pagesize = getpagesize();
746# endif
747#endif
748#endif
749    }
750}
751