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