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