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