xf86bigfont.c revision 4642e01f
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 534642e01fSmrg#if defined(__CYGWIN__) || defined(__SCO__) 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" 7405b261ecSmrg 7505b261ecSmrg#define _XF86BIGFONT_SERVER_ 7605b261ecSmrg#include <X11/extensions/xf86bigfstr.h> 7705b261ecSmrg 7805b261ecSmrgstatic void XF86BigfontResetProc( 7905b261ecSmrg ExtensionEntry * /* extEntry */ 8005b261ecSmrg ); 8105b261ecSmrg 8205b261ecSmrgstatic DISPATCH_PROC(ProcXF86BigfontDispatch); 8305b261ecSmrgstatic DISPATCH_PROC(ProcXF86BigfontQueryVersion); 8405b261ecSmrgstatic DISPATCH_PROC(ProcXF86BigfontQueryFont); 8505b261ecSmrgstatic DISPATCH_PROC(SProcXF86BigfontDispatch); 8605b261ecSmrgstatic DISPATCH_PROC(SProcXF86BigfontQueryVersion); 8705b261ecSmrgstatic DISPATCH_PROC(SProcXF86BigfontQueryFont); 8805b261ecSmrg 8905b261ecSmrg#ifdef HAS_SHM 9005b261ecSmrg 9105b261ecSmrg/* A random signature, transmitted to the clients so they can verify that the 9205b261ecSmrg shared memory segment they are attaching to was really established by the 9305b261ecSmrg X server they are talking to. */ 9405b261ecSmrgstatic CARD32 signature; 9505b261ecSmrg 9605b261ecSmrg/* Index for additional information stored in a FontRec's devPrivates array. */ 9705b261ecSmrgstatic int FontShmdescIndex; 9805b261ecSmrg 9905b261ecSmrgstatic unsigned int pagesize; 10005b261ecSmrg 10105b261ecSmrgstatic Bool badSysCall = FALSE; 10205b261ecSmrg 10305b261ecSmrg#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__) 10405b261ecSmrg 10505b261ecSmrg#include <sys/signal.h> 10605b261ecSmrg 10705b261ecSmrgstatic void 10805b261ecSmrgSigSysHandler( 10905b261ecSmrg int signo) 11005b261ecSmrg{ 11105b261ecSmrg badSysCall = TRUE; 11205b261ecSmrg} 11305b261ecSmrg 11405b261ecSmrgstatic Bool 11505b261ecSmrgCheckForShmSyscall(void) 11605b261ecSmrg{ 11705b261ecSmrg void (*oldHandler)(int); 11805b261ecSmrg int shmid = -1; 11905b261ecSmrg 12005b261ecSmrg /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */ 12105b261ecSmrg oldHandler = signal(SIGSYS, SigSysHandler); 12205b261ecSmrg 12305b261ecSmrg badSysCall = FALSE; 12405b261ecSmrg shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT); 12505b261ecSmrg if (shmid != -1) 12605b261ecSmrg { 12705b261ecSmrg /* Successful allocation - clean up */ 12805b261ecSmrg shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL); 12905b261ecSmrg } 13005b261ecSmrg else 13105b261ecSmrg { 13205b261ecSmrg /* Allocation failed */ 13305b261ecSmrg badSysCall = TRUE; 13405b261ecSmrg } 13505b261ecSmrg signal(SIGSYS, oldHandler); 13605b261ecSmrg return (!badSysCall); 13705b261ecSmrg} 13805b261ecSmrg 13905b261ecSmrg#define MUST_CHECK_FOR_SHM_SYSCALL 14005b261ecSmrg 14105b261ecSmrg#endif 14205b261ecSmrg 14305b261ecSmrg#endif 14405b261ecSmrg 14505b261ecSmrgvoid 14605b261ecSmrgXFree86BigfontExtensionInit() 14705b261ecSmrg{ 14805b261ecSmrg if (AddExtension(XF86BIGFONTNAME, 14905b261ecSmrg XF86BigfontNumberEvents, 15005b261ecSmrg XF86BigfontNumberErrors, 15105b261ecSmrg ProcXF86BigfontDispatch, 15205b261ecSmrg SProcXF86BigfontDispatch, 15305b261ecSmrg XF86BigfontResetProc, 15405b261ecSmrg StandardMinorOpcode)) { 15505b261ecSmrg#ifdef HAS_SHM 15605b261ecSmrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL 15705b261ecSmrg /* 15805b261ecSmrg * Note: Local-clients will not be optimized without shared memory 15905b261ecSmrg * support. Remote-client optimization does not depend on shared 16005b261ecSmrg * memory support. Thus, the extension is still registered even 16105b261ecSmrg * when shared memory support is not functional. 16205b261ecSmrg */ 16305b261ecSmrg if (!CheckForShmSyscall()) { 16405b261ecSmrg ErrorF(XF86BIGFONTNAME " extension local-client optimization disabled due to lack of shared memory support in the kernel\n"); 16505b261ecSmrg return; 16605b261ecSmrg } 16705b261ecSmrg#endif 16805b261ecSmrg 16905b261ecSmrg srand((unsigned int) time(NULL)); 17005b261ecSmrg signature = ((unsigned int) (65536.0/(RAND_MAX+1.0) * rand()) << 16) 17105b261ecSmrg + (unsigned int) (65536.0/(RAND_MAX+1.0) * rand()); 17205b261ecSmrg /* fprintf(stderr, "signature = 0x%08X\n", signature); */ 17305b261ecSmrg 17405b261ecSmrg FontShmdescIndex = AllocateFontPrivateIndex(); 17505b261ecSmrg 17605b261ecSmrg#if !defined(CSRG_BASED) && !defined(__CYGWIN__) 17705b261ecSmrg pagesize = SHMLBA; 17805b261ecSmrg#else 17905b261ecSmrg# ifdef _SC_PAGESIZE 18005b261ecSmrg pagesize = sysconf(_SC_PAGESIZE); 18105b261ecSmrg# else 18205b261ecSmrg pagesize = getpagesize(); 18305b261ecSmrg# endif 18405b261ecSmrg#endif 18505b261ecSmrg#endif 18605b261ecSmrg } 18705b261ecSmrg} 18805b261ecSmrg 18905b261ecSmrg 19005b261ecSmrg/* ========== Management of shared memory segments ========== */ 19105b261ecSmrg 19205b261ecSmrg#ifdef HAS_SHM 19305b261ecSmrg 19405b261ecSmrg#ifdef __linux__ 19505b261ecSmrg/* On Linux, shared memory marked as "removed" can still be attached. 19605b261ecSmrg Nice feature, because the kernel will automatically free the associated 19705b261ecSmrg storage when the server and all clients are gone. */ 19805b261ecSmrg#define EARLY_REMOVE 19905b261ecSmrg#endif 20005b261ecSmrg 20105b261ecSmrgtypedef struct _ShmDesc { 20205b261ecSmrg struct _ShmDesc *next; 20305b261ecSmrg struct _ShmDesc **prev; 20405b261ecSmrg int shmid; 20505b261ecSmrg char *attach_addr; 20605b261ecSmrg} ShmDescRec, *ShmDescPtr; 20705b261ecSmrg 20805b261ecSmrgstatic ShmDescPtr ShmList = (ShmDescPtr) NULL; 20905b261ecSmrg 21005b261ecSmrgstatic ShmDescPtr 21105b261ecSmrgshmalloc( 21205b261ecSmrg unsigned int size) 21305b261ecSmrg{ 21405b261ecSmrg ShmDescPtr pDesc; 21505b261ecSmrg int shmid; 21605b261ecSmrg char *addr; 21705b261ecSmrg 21805b261ecSmrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL 21905b261ecSmrg if (pagesize == 0) 22005b261ecSmrg return (ShmDescPtr) NULL; 22105b261ecSmrg#endif 22205b261ecSmrg 22305b261ecSmrg /* On some older Linux systems, the number of shared memory segments 22405b261ecSmrg system-wide is 127. In Linux 2.4, it is 4095. 22505b261ecSmrg Therefore there is a tradeoff to be made between allocating a 22605b261ecSmrg shared memory segment on one hand, and allocating memory and piping 22705b261ecSmrg the glyph metrics on the other hand. If the glyph metrics size is 22805b261ecSmrg small, we prefer the traditional way. */ 22905b261ecSmrg if (size < 3500) 23005b261ecSmrg return (ShmDescPtr) NULL; 23105b261ecSmrg 23205b261ecSmrg pDesc = (ShmDescRec *) xalloc(sizeof(ShmDescRec)); 23305b261ecSmrg if (!pDesc) 23405b261ecSmrg return (ShmDescPtr) NULL; 23505b261ecSmrg 23605b261ecSmrg size = (size + pagesize-1) & -pagesize; 23705b261ecSmrg shmid = shmget(IPC_PRIVATE, size, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); 23805b261ecSmrg if (shmid == -1) { 2394642e01fSmrg ErrorF(XF86BIGFONTNAME " extension: shmget() failed, size = %u, %s\n", 2404642e01fSmrg size, strerror(errno)); 24105b261ecSmrg xfree(pDesc); 24205b261ecSmrg return (ShmDescPtr) NULL; 24305b261ecSmrg } 24405b261ecSmrg 24505b261ecSmrg if ((addr = shmat(shmid, 0, 0)) == (char *)-1) { 2464642e01fSmrg ErrorF(XF86BIGFONTNAME " extension: shmat() failed, size = %u, %s\n", 2474642e01fSmrg size, strerror(errno)); 24805b261ecSmrg shmctl(shmid, IPC_RMID, (void *) 0); 24905b261ecSmrg xfree(pDesc); 25005b261ecSmrg return (ShmDescPtr) NULL; 25105b261ecSmrg } 25205b261ecSmrg 25305b261ecSmrg#ifdef EARLY_REMOVE 25405b261ecSmrg shmctl(shmid, IPC_RMID, (void *) 0); 25505b261ecSmrg#endif 25605b261ecSmrg 25705b261ecSmrg pDesc->shmid = shmid; 25805b261ecSmrg pDesc->attach_addr = addr; 25905b261ecSmrg if (ShmList) ShmList->prev = &pDesc->next; 26005b261ecSmrg pDesc->next = ShmList; 26105b261ecSmrg pDesc->prev = &ShmList; 26205b261ecSmrg ShmList = pDesc; 26305b261ecSmrg 26405b261ecSmrg return pDesc; 26505b261ecSmrg} 26605b261ecSmrg 26705b261ecSmrgstatic void 26805b261ecSmrgshmdealloc( 26905b261ecSmrg ShmDescPtr pDesc) 27005b261ecSmrg{ 27105b261ecSmrg#ifndef EARLY_REMOVE 27205b261ecSmrg shmctl(pDesc->shmid, IPC_RMID, (void *) 0); 27305b261ecSmrg#endif 27405b261ecSmrg shmdt(pDesc->attach_addr); 27505b261ecSmrg 27605b261ecSmrg if (pDesc->next) pDesc->next->prev = pDesc->prev; 27705b261ecSmrg *pDesc->prev = pDesc->next; 27805b261ecSmrg xfree(pDesc); 27905b261ecSmrg} 28005b261ecSmrg 28105b261ecSmrg#endif 28205b261ecSmrg 28305b261ecSmrg/* Called when a font is closed. */ 28405b261ecSmrgvoid 28505b261ecSmrgXF86BigfontFreeFontShm( 28605b261ecSmrg FontPtr pFont) 28705b261ecSmrg{ 28805b261ecSmrg#ifdef HAS_SHM 28905b261ecSmrg ShmDescPtr pDesc; 29005b261ecSmrg 29105b261ecSmrg /* If during shutdown of the server, XF86BigfontCleanup() has already 29205b261ecSmrg * called shmdealloc() for all segments, we don't need to do it here. 29305b261ecSmrg */ 29405b261ecSmrg if (!ShmList) 29505b261ecSmrg return; 29605b261ecSmrg 29705b261ecSmrg pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex); 29805b261ecSmrg if (pDesc) 29905b261ecSmrg shmdealloc(pDesc); 30005b261ecSmrg#endif 30105b261ecSmrg} 30205b261ecSmrg 30305b261ecSmrg/* Called upon fatal signal. */ 30405b261ecSmrgvoid 30505b261ecSmrgXF86BigfontCleanup() 30605b261ecSmrg{ 30705b261ecSmrg#ifdef HAS_SHM 30805b261ecSmrg while (ShmList) 30905b261ecSmrg shmdealloc(ShmList); 31005b261ecSmrg#endif 31105b261ecSmrg} 31205b261ecSmrg 31305b261ecSmrg/* Called when a server generation dies. */ 31405b261ecSmrgstatic void 31505b261ecSmrgXF86BigfontResetProc( 31605b261ecSmrg ExtensionEntry* extEntry) 31705b261ecSmrg{ 31805b261ecSmrg /* This function is normally called from CloseDownExtensions(), called 31905b261ecSmrg * from main(). It will be followed by a call to FreeAllResources(), 32005b261ecSmrg * which will call XF86BigfontFreeFontShm() for each font. Thus it 32105b261ecSmrg * appears that we do not need to do anything in this function. -- 32205b261ecSmrg * But I prefer to write robust code, and not keep shared memory lying 32305b261ecSmrg * around when it's not needed any more. (Someone might close down the 32405b261ecSmrg * extension without calling FreeAllResources()...) 32505b261ecSmrg */ 32605b261ecSmrg XF86BigfontCleanup(); 32705b261ecSmrg} 32805b261ecSmrg 32905b261ecSmrg 33005b261ecSmrg/* ========== Handling of extension specific requests ========== */ 33105b261ecSmrg 33205b261ecSmrgstatic int 33305b261ecSmrgProcXF86BigfontQueryVersion( 33405b261ecSmrg ClientPtr client) 33505b261ecSmrg{ 33605b261ecSmrg xXF86BigfontQueryVersionReply reply; 33705b261ecSmrg 33805b261ecSmrg REQUEST_SIZE_MATCH(xXF86BigfontQueryVersionReq); 33905b261ecSmrg reply.type = X_Reply; 34005b261ecSmrg reply.length = 0; 34105b261ecSmrg reply.sequenceNumber = client->sequence; 34205b261ecSmrg reply.majorVersion = XF86BIGFONT_MAJOR_VERSION; 34305b261ecSmrg reply.minorVersion = XF86BIGFONT_MINOR_VERSION; 34405b261ecSmrg reply.uid = geteuid(); 34505b261ecSmrg reply.gid = getegid(); 34605b261ecSmrg#ifdef HAS_SHM 34705b261ecSmrg reply.signature = signature; 34805b261ecSmrg#else 34905b261ecSmrg reply.signature = 0; /* This is redundant. Avoids uninitialized memory. */ 35005b261ecSmrg#endif 35105b261ecSmrg reply.capabilities = 35205b261ecSmrg#ifdef HAS_SHM 35305b261ecSmrg (LocalClient(client) && !client->swapped ? XF86Bigfont_CAP_LocalShm : 0) 35405b261ecSmrg#else 35505b261ecSmrg 0 35605b261ecSmrg#endif 35705b261ecSmrg ; /* may add more bits here in future versions */ 35805b261ecSmrg if (client->swapped) { 35905b261ecSmrg char tmp; 36005b261ecSmrg swaps(&reply.sequenceNumber, tmp); 36105b261ecSmrg swapl(&reply.length, tmp); 36205b261ecSmrg swaps(&reply.majorVersion, tmp); 36305b261ecSmrg swaps(&reply.minorVersion, tmp); 36405b261ecSmrg swapl(&reply.uid, tmp); 36505b261ecSmrg swapl(&reply.gid, tmp); 36605b261ecSmrg swapl(&reply.signature, tmp); 36705b261ecSmrg } 36805b261ecSmrg WriteToClient(client, 36905b261ecSmrg sizeof(xXF86BigfontQueryVersionReply), (char *)&reply); 37005b261ecSmrg return client->noClientException; 37105b261ecSmrg} 37205b261ecSmrg 37305b261ecSmrgstatic void 37405b261ecSmrgswapCharInfo( 37505b261ecSmrg xCharInfo *pCI) 37605b261ecSmrg{ 37705b261ecSmrg char tmp; 37805b261ecSmrg 37905b261ecSmrg swaps(&pCI->leftSideBearing, tmp); 38005b261ecSmrg swaps(&pCI->rightSideBearing, tmp); 38105b261ecSmrg swaps(&pCI->characterWidth, tmp); 38205b261ecSmrg swaps(&pCI->ascent, tmp); 38305b261ecSmrg swaps(&pCI->descent, tmp); 38405b261ecSmrg swaps(&pCI->attributes, tmp); 38505b261ecSmrg} 38605b261ecSmrg 38705b261ecSmrg/* static CARD32 hashCI (xCharInfo *p); */ 38805b261ecSmrg#define hashCI(p) \ 38905b261ecSmrg (CARD32)(((p->leftSideBearing << 27) + (p->leftSideBearing >> 5) + \ 39005b261ecSmrg (p->rightSideBearing << 23) + (p->rightSideBearing >> 9) + \ 39105b261ecSmrg (p->characterWidth << 16) + \ 39205b261ecSmrg (p->ascent << 11) + (p->descent << 6)) ^ p->attributes) 39305b261ecSmrg 39405b261ecSmrgstatic int 39505b261ecSmrgProcXF86BigfontQueryFont( 39605b261ecSmrg ClientPtr client) 39705b261ecSmrg{ 39805b261ecSmrg FontPtr pFont; 39905b261ecSmrg REQUEST(xXF86BigfontQueryFontReq); 40005b261ecSmrg CARD32 stuff_flags; 40105b261ecSmrg xCharInfo* pmax; 40205b261ecSmrg xCharInfo* pmin; 40305b261ecSmrg int nCharInfos; 40405b261ecSmrg int shmid; 40505b261ecSmrg#ifdef HAS_SHM 40605b261ecSmrg ShmDescPtr pDesc; 40705b261ecSmrg#else 40805b261ecSmrg#define pDesc 0 40905b261ecSmrg#endif 41005b261ecSmrg xCharInfo* pCI; 41105b261ecSmrg CARD16* pIndex2UniqIndex; 41205b261ecSmrg CARD16* pUniqIndex2Index; 41305b261ecSmrg CARD32 nUniqCharInfos; 41405b261ecSmrg 41505b261ecSmrg#if 0 41605b261ecSmrg REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq); 41705b261ecSmrg#else 41805b261ecSmrg switch (client->req_len) { 41905b261ecSmrg case 2: /* client with version 1.0 libX11 */ 42005b261ecSmrg stuff_flags = (LocalClient(client) && !client->swapped ? XF86Bigfont_FLAGS_Shm : 0); 42105b261ecSmrg break; 42205b261ecSmrg case 3: /* client with version 1.1 libX11 */ 42305b261ecSmrg stuff_flags = stuff->flags; 42405b261ecSmrg break; 42505b261ecSmrg default: 42605b261ecSmrg return BadLength; 42705b261ecSmrg } 42805b261ecSmrg#endif 42905b261ecSmrg client->errorValue = stuff->id; /* EITHER font or gc */ 43005b261ecSmrg pFont = (FontPtr)SecurityLookupIDByType(client, stuff->id, RT_FONT, 4314642e01fSmrg DixGetAttrAccess); 43205b261ecSmrg if (!pFont) { 43305b261ecSmrg GC *pGC = (GC *) SecurityLookupIDByType(client, stuff->id, RT_GC, 4344642e01fSmrg DixGetAttrAccess); 43505b261ecSmrg if (!pGC) { 43605b261ecSmrg client->errorValue = stuff->id; 43705b261ecSmrg return BadFont; /* procotol spec says only error is BadFont */ 43805b261ecSmrg } 43905b261ecSmrg pFont = pGC->font; 44005b261ecSmrg } 44105b261ecSmrg 44205b261ecSmrg pmax = FONTINKMAX(pFont); 44305b261ecSmrg pmin = FONTINKMIN(pFont); 44405b261ecSmrg nCharInfos = 44505b261ecSmrg (pmax->rightSideBearing == pmin->rightSideBearing 44605b261ecSmrg && pmax->leftSideBearing == pmin->leftSideBearing 44705b261ecSmrg && pmax->descent == pmin->descent 44805b261ecSmrg && pmax->ascent == pmin->ascent 44905b261ecSmrg && pmax->characterWidth == pmin->characterWidth) 45005b261ecSmrg ? 0 : N2dChars(pFont); 45105b261ecSmrg shmid = -1; 45205b261ecSmrg pCI = NULL; 45305b261ecSmrg pIndex2UniqIndex = NULL; 45405b261ecSmrg pUniqIndex2Index = NULL; 45505b261ecSmrg nUniqCharInfos = 0; 45605b261ecSmrg 45705b261ecSmrg if (nCharInfos > 0) { 45805b261ecSmrg#ifdef HAS_SHM 45905b261ecSmrg if (!badSysCall) 46005b261ecSmrg pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex); 46105b261ecSmrg else 46205b261ecSmrg pDesc = NULL; 46305b261ecSmrg if (pDesc) { 46405b261ecSmrg pCI = (xCharInfo *) pDesc->attach_addr; 46505b261ecSmrg if (stuff_flags & XF86Bigfont_FLAGS_Shm) 46605b261ecSmrg shmid = pDesc->shmid; 46705b261ecSmrg } else { 46805b261ecSmrg if (stuff_flags & XF86Bigfont_FLAGS_Shm && !badSysCall) 46905b261ecSmrg pDesc = shmalloc(nCharInfos * sizeof(xCharInfo) 47005b261ecSmrg + sizeof(CARD32)); 47105b261ecSmrg if (pDesc) { 47205b261ecSmrg pCI = (xCharInfo *) pDesc->attach_addr; 47305b261ecSmrg shmid = pDesc->shmid; 47405b261ecSmrg } else { 47505b261ecSmrg#endif 47605b261ecSmrg pCI = (xCharInfo *) 4774642e01fSmrg xalloc(nCharInfos * sizeof(xCharInfo)); 47805b261ecSmrg if (!pCI) 47905b261ecSmrg return BadAlloc; 48005b261ecSmrg#ifdef HAS_SHM 48105b261ecSmrg } 48205b261ecSmrg#endif 48305b261ecSmrg /* Fill nCharInfos starting at pCI. */ 48405b261ecSmrg { 48505b261ecSmrg xCharInfo* prCI = pCI; 48605b261ecSmrg int ninfos = 0; 48705b261ecSmrg int ncols = pFont->info.lastCol - pFont->info.firstCol + 1; 48805b261ecSmrg int row; 48905b261ecSmrg for (row = pFont->info.firstRow; 49005b261ecSmrg row <= pFont->info.lastRow && ninfos < nCharInfos; 49105b261ecSmrg row++) { 49205b261ecSmrg unsigned char chars[512]; 49305b261ecSmrg xCharInfo* tmpCharInfos[256]; 49405b261ecSmrg unsigned long count; 49505b261ecSmrg int col; 49605b261ecSmrg unsigned long i; 49705b261ecSmrg i = 0; 49805b261ecSmrg for (col = pFont->info.firstCol; 49905b261ecSmrg col <= pFont->info.lastCol; 50005b261ecSmrg col++) { 50105b261ecSmrg chars[i++] = row; 50205b261ecSmrg chars[i++] = col; 50305b261ecSmrg } 50405b261ecSmrg (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit, 50505b261ecSmrg &count, tmpCharInfos); 50605b261ecSmrg for (i = 0; i < count && ninfos < nCharInfos; i++) { 50705b261ecSmrg *prCI++ = *tmpCharInfos[i]; 50805b261ecSmrg ninfos++; 50905b261ecSmrg } 51005b261ecSmrg } 51105b261ecSmrg } 51205b261ecSmrg#ifdef HAS_SHM 51305b261ecSmrg if (pDesc && !badSysCall) { 51405b261ecSmrg *(CARD32 *)(pCI + nCharInfos) = signature; 51505b261ecSmrg if (!FontSetPrivate(pFont, FontShmdescIndex, pDesc)) { 51605b261ecSmrg shmdealloc(pDesc); 51705b261ecSmrg return BadAlloc; 51805b261ecSmrg } 51905b261ecSmrg } 52005b261ecSmrg } 52105b261ecSmrg#endif 52205b261ecSmrg if (shmid == -1) { 52305b261ecSmrg /* Cannot use shared memory, so remove-duplicates the xCharInfos 52405b261ecSmrg using a temporary hash table. */ 52505b261ecSmrg /* Note that CARD16 is suitable as index type, because 52605b261ecSmrg nCharInfos <= 0x10000. */ 52705b261ecSmrg CARD32 hashModulus; 52805b261ecSmrg CARD16* pHash2UniqIndex; 52905b261ecSmrg CARD16* pUniqIndex2NextUniqIndex; 53005b261ecSmrg CARD32 NextIndex; 53105b261ecSmrg CARD32 NextUniqIndex; 53205b261ecSmrg CARD16* tmp; 53305b261ecSmrg CARD32 i, j; 53405b261ecSmrg 53505b261ecSmrg hashModulus = 67; 53605b261ecSmrg if (hashModulus > nCharInfos+1) 53705b261ecSmrg hashModulus = nCharInfos+1; 53805b261ecSmrg 53905b261ecSmrg tmp = (CARD16*) 5404642e01fSmrg xalloc((4*nCharInfos+1) * sizeof(CARD16)); 54105b261ecSmrg if (!tmp) { 5424642e01fSmrg if (!pDesc) xfree(pCI); 54305b261ecSmrg return BadAlloc; 54405b261ecSmrg } 54505b261ecSmrg pIndex2UniqIndex = tmp; 54605b261ecSmrg /* nCharInfos elements */ 54705b261ecSmrg pUniqIndex2Index = tmp + nCharInfos; 54805b261ecSmrg /* max. nCharInfos elements */ 54905b261ecSmrg pUniqIndex2NextUniqIndex = tmp + 2*nCharInfos; 55005b261ecSmrg /* max. nCharInfos elements */ 55105b261ecSmrg pHash2UniqIndex = tmp + 3*nCharInfos; 55205b261ecSmrg /* hashModulus (<= nCharInfos+1) elements */ 55305b261ecSmrg 55405b261ecSmrg /* Note that we can use 0xffff as end-of-list indicator, because 55505b261ecSmrg even if nCharInfos = 0x10000, 0xffff can not occur as valid 55605b261ecSmrg entry before the last element has been inserted. And once the 55705b261ecSmrg last element has been inserted, we don't need the hash table 55805b261ecSmrg any more. */ 55905b261ecSmrg for (j = 0; j < hashModulus; j++) 56005b261ecSmrg pHash2UniqIndex[j] = (CARD16)(-1); 56105b261ecSmrg 56205b261ecSmrg NextUniqIndex = 0; 56305b261ecSmrg for (NextIndex = 0; NextIndex < nCharInfos; NextIndex++) { 56405b261ecSmrg xCharInfo* p = &pCI[NextIndex]; 56505b261ecSmrg CARD32 hashCode = hashCI(p) % hashModulus; 56605b261ecSmrg for (i = pHash2UniqIndex[hashCode]; 56705b261ecSmrg i != (CARD16)(-1); 56805b261ecSmrg i = pUniqIndex2NextUniqIndex[i]) { 56905b261ecSmrg j = pUniqIndex2Index[i]; 57005b261ecSmrg if (pCI[j].leftSideBearing == p->leftSideBearing 57105b261ecSmrg && pCI[j].rightSideBearing == p->rightSideBearing 57205b261ecSmrg && pCI[j].characterWidth == p->characterWidth 57305b261ecSmrg && pCI[j].ascent == p->ascent 57405b261ecSmrg && pCI[j].descent == p->descent 57505b261ecSmrg && pCI[j].attributes == p->attributes) 57605b261ecSmrg break; 57705b261ecSmrg } 57805b261ecSmrg if (i != (CARD16)(-1)) { 57905b261ecSmrg /* Found *p at Index j, UniqIndex i */ 58005b261ecSmrg pIndex2UniqIndex[NextIndex] = i; 58105b261ecSmrg } else { 58205b261ecSmrg /* Allocate a new entry in the Uniq table */ 58305b261ecSmrg if (hashModulus <= 2*NextUniqIndex 58405b261ecSmrg && hashModulus < nCharInfos+1) { 58505b261ecSmrg /* Time to increate hash table size */ 58605b261ecSmrg hashModulus = 2*hashModulus+1; 58705b261ecSmrg if (hashModulus > nCharInfos+1) 58805b261ecSmrg hashModulus = nCharInfos+1; 58905b261ecSmrg for (j = 0; j < hashModulus; j++) 59005b261ecSmrg pHash2UniqIndex[j] = (CARD16)(-1); 59105b261ecSmrg for (i = 0; i < NextUniqIndex; i++) 59205b261ecSmrg pUniqIndex2NextUniqIndex[i] = (CARD16)(-1); 59305b261ecSmrg for (i = 0; i < NextUniqIndex; i++) { 59405b261ecSmrg j = pUniqIndex2Index[i]; 59505b261ecSmrg p = &pCI[j]; 59605b261ecSmrg hashCode = hashCI(p) % hashModulus; 59705b261ecSmrg pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode]; 59805b261ecSmrg pHash2UniqIndex[hashCode] = i; 59905b261ecSmrg } 60005b261ecSmrg p = &pCI[NextIndex]; 60105b261ecSmrg hashCode = hashCI(p) % hashModulus; 60205b261ecSmrg } 60305b261ecSmrg i = NextUniqIndex++; 60405b261ecSmrg pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode]; 60505b261ecSmrg pHash2UniqIndex[hashCode] = i; 60605b261ecSmrg pUniqIndex2Index[i] = NextIndex; 60705b261ecSmrg pIndex2UniqIndex[NextIndex] = i; 60805b261ecSmrg } 60905b261ecSmrg } 61005b261ecSmrg nUniqCharInfos = NextUniqIndex; 61105b261ecSmrg /* fprintf(stderr, "font metrics: nCharInfos = %d, nUniqCharInfos = %d, hashModulus = %d\n", nCharInfos, nUniqCharInfos, hashModulus); */ 61205b261ecSmrg } 61305b261ecSmrg } 61405b261ecSmrg 61505b261ecSmrg { 61605b261ecSmrg int nfontprops = pFont->info.nprops; 61705b261ecSmrg int rlength = 61805b261ecSmrg sizeof(xXF86BigfontQueryFontReply) 61905b261ecSmrg + nfontprops * sizeof(xFontProp) 62005b261ecSmrg + (nCharInfos > 0 && shmid == -1 62105b261ecSmrg ? nUniqCharInfos * sizeof(xCharInfo) 62205b261ecSmrg + (nCharInfos+1)/2 * 2 * sizeof(CARD16) 62305b261ecSmrg : 0); 62405b261ecSmrg xXF86BigfontQueryFontReply* reply = 6254642e01fSmrg (xXF86BigfontQueryFontReply *) xalloc(rlength); 62605b261ecSmrg char* p; 62705b261ecSmrg if (!reply) { 62805b261ecSmrg if (nCharInfos > 0) { 6294642e01fSmrg if (shmid == -1) xfree(pIndex2UniqIndex); 6304642e01fSmrg if (!pDesc) xfree(pCI); 63105b261ecSmrg } 63205b261ecSmrg return BadAlloc; 63305b261ecSmrg } 63405b261ecSmrg reply->type = X_Reply; 63505b261ecSmrg reply->length = (rlength - sizeof(xGenericReply)) >> 2; 63605b261ecSmrg reply->sequenceNumber = client->sequence; 63705b261ecSmrg reply->minBounds = pFont->info.ink_minbounds; 63805b261ecSmrg reply->maxBounds = pFont->info.ink_maxbounds; 63905b261ecSmrg reply->minCharOrByte2 = pFont->info.firstCol; 64005b261ecSmrg reply->maxCharOrByte2 = pFont->info.lastCol; 64105b261ecSmrg reply->defaultChar = pFont->info.defaultCh; 64205b261ecSmrg reply->nFontProps = pFont->info.nprops; 64305b261ecSmrg reply->drawDirection = pFont->info.drawDirection; 64405b261ecSmrg reply->minByte1 = pFont->info.firstRow; 64505b261ecSmrg reply->maxByte1 = pFont->info.lastRow; 64605b261ecSmrg reply->allCharsExist = pFont->info.allExist; 64705b261ecSmrg reply->fontAscent = pFont->info.fontAscent; 64805b261ecSmrg reply->fontDescent = pFont->info.fontDescent; 64905b261ecSmrg reply->nCharInfos = nCharInfos; 65005b261ecSmrg reply->nUniqCharInfos = nUniqCharInfos; 65105b261ecSmrg reply->shmid = shmid; 65205b261ecSmrg reply->shmsegoffset = 0; 65305b261ecSmrg if (client->swapped) { 65405b261ecSmrg char tmp; 65505b261ecSmrg swaps(&reply->sequenceNumber, tmp); 65605b261ecSmrg swapl(&reply->length, tmp); 65705b261ecSmrg swapCharInfo(&reply->minBounds); 65805b261ecSmrg swapCharInfo(&reply->maxBounds); 65905b261ecSmrg swaps(&reply->minCharOrByte2, tmp); 66005b261ecSmrg swaps(&reply->maxCharOrByte2, tmp); 66105b261ecSmrg swaps(&reply->defaultChar, tmp); 66205b261ecSmrg swaps(&reply->nFontProps, tmp); 66305b261ecSmrg swaps(&reply->fontAscent, tmp); 66405b261ecSmrg swaps(&reply->fontDescent, tmp); 66505b261ecSmrg swapl(&reply->nCharInfos, tmp); 66605b261ecSmrg swapl(&reply->nUniqCharInfos, tmp); 66705b261ecSmrg swapl(&reply->shmid, tmp); 66805b261ecSmrg swapl(&reply->shmsegoffset, tmp); 66905b261ecSmrg } 67005b261ecSmrg p = (char*) &reply[1]; 67105b261ecSmrg { 67205b261ecSmrg FontPropPtr pFP; 67305b261ecSmrg xFontProp* prFP; 67405b261ecSmrg int i; 67505b261ecSmrg for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) p; 67605b261ecSmrg i < nfontprops; 67705b261ecSmrg i++, pFP++, prFP++) { 67805b261ecSmrg prFP->name = pFP->name; 67905b261ecSmrg prFP->value = pFP->value; 68005b261ecSmrg if (client->swapped) { 68105b261ecSmrg char tmp; 68205b261ecSmrg swapl(&prFP->name, tmp); 68305b261ecSmrg swapl(&prFP->value, tmp); 68405b261ecSmrg } 68505b261ecSmrg } 68605b261ecSmrg p = (char*) prFP; 68705b261ecSmrg } 68805b261ecSmrg if (nCharInfos > 0 && shmid == -1) { 68905b261ecSmrg xCharInfo* pci; 69005b261ecSmrg CARD16* ps; 69105b261ecSmrg int i, j; 69205b261ecSmrg pci = (xCharInfo*) p; 69305b261ecSmrg for (i = 0; i < nUniqCharInfos; i++, pci++) { 69405b261ecSmrg *pci = pCI[pUniqIndex2Index[i]]; 69505b261ecSmrg if (client->swapped) 69605b261ecSmrg swapCharInfo(pci); 69705b261ecSmrg } 69805b261ecSmrg ps = (CARD16*) pci; 69905b261ecSmrg for (j = 0; j < nCharInfos; j++, ps++) { 70005b261ecSmrg *ps = pIndex2UniqIndex[j]; 70105b261ecSmrg if (client->swapped) { 70205b261ecSmrg char tmp; 70305b261ecSmrg swaps(ps, tmp); 70405b261ecSmrg } 70505b261ecSmrg } 70605b261ecSmrg } 70705b261ecSmrg WriteToClient(client, rlength, (char *)reply); 7084642e01fSmrg xfree(reply); 70905b261ecSmrg if (nCharInfos > 0) { 7104642e01fSmrg if (shmid == -1) xfree(pIndex2UniqIndex); 7114642e01fSmrg if (!pDesc) xfree(pCI); 71205b261ecSmrg } 71305b261ecSmrg return (client->noClientException); 71405b261ecSmrg } 71505b261ecSmrg} 71605b261ecSmrg 71705b261ecSmrgstatic int 71805b261ecSmrgProcXF86BigfontDispatch( 71905b261ecSmrg ClientPtr client) 72005b261ecSmrg{ 72105b261ecSmrg REQUEST(xReq); 72205b261ecSmrg 72305b261ecSmrg switch (stuff->data) { 72405b261ecSmrg case X_XF86BigfontQueryVersion: 72505b261ecSmrg return ProcXF86BigfontQueryVersion(client); 72605b261ecSmrg case X_XF86BigfontQueryFont: 72705b261ecSmrg return ProcXF86BigfontQueryFont(client); 72805b261ecSmrg default: 72905b261ecSmrg return BadRequest; 73005b261ecSmrg } 73105b261ecSmrg} 73205b261ecSmrg 73305b261ecSmrgstatic int 73405b261ecSmrgSProcXF86BigfontQueryVersion( 73505b261ecSmrg ClientPtr client) 73605b261ecSmrg{ 73705b261ecSmrg REQUEST(xXF86BigfontQueryVersionReq); 73805b261ecSmrg char tmp; 73905b261ecSmrg 74005b261ecSmrg swaps(&stuff->length, tmp); 74105b261ecSmrg return ProcXF86BigfontQueryVersion(client); 74205b261ecSmrg} 74305b261ecSmrg 74405b261ecSmrgstatic int 74505b261ecSmrgSProcXF86BigfontQueryFont( 74605b261ecSmrg ClientPtr client) 74705b261ecSmrg{ 74805b261ecSmrg REQUEST(xXF86BigfontQueryFontReq); 74905b261ecSmrg char tmp; 75005b261ecSmrg 75105b261ecSmrg swaps(&stuff->length, tmp); 75205b261ecSmrg REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq); 75305b261ecSmrg swapl(&stuff->id, tmp); 75405b261ecSmrg return ProcXF86BigfontQueryFont(client); 75505b261ecSmrg} 75605b261ecSmrg 75705b261ecSmrgstatic int 75805b261ecSmrgSProcXF86BigfontDispatch( 75905b261ecSmrg ClientPtr client) 76005b261ecSmrg{ 76105b261ecSmrg REQUEST(xReq); 76205b261ecSmrg 76305b261ecSmrg switch (stuff->data) { 76405b261ecSmrg case X_XF86BigfontQueryVersion: 76505b261ecSmrg return SProcXF86BigfontQueryVersion(client); 76605b261ecSmrg case X_XF86BigfontQueryFont: 76705b261ecSmrg return SProcXF86BigfontQueryFont(client); 76805b261ecSmrg default: 76905b261ecSmrg return BadRequest; 77005b261ecSmrg } 77105b261ecSmrg} 772