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