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