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#ifdef SVR4 4405b261ecSmrg#include <sys/sysmacros.h> 4505b261ecSmrg#endif 4635c4bbdfSmrg#if defined(__CYGWIN__) 4705b261ecSmrg#include <sys/param.h> 4805b261ecSmrg#include <sys/sysmacros.h> 4905b261ecSmrg#endif 5005b261ecSmrg#include <sys/ipc.h> 5105b261ecSmrg#include <sys/shm.h> 5205b261ecSmrg#include <sys/stat.h> 5305b261ecSmrg#include <stdlib.h> 5405b261ecSmrg#include <unistd.h> 5505b261ecSmrg#include <time.h> 5605b261ecSmrg#include <errno.h> 5705b261ecSmrg#endif 5805b261ecSmrg 5905b261ecSmrg#include <X11/X.h> 6005b261ecSmrg#include <X11/Xproto.h> 6105b261ecSmrg#include "misc.h" 6205b261ecSmrg#include "os.h" 6305b261ecSmrg#include "dixstruct.h" 6405b261ecSmrg#include "gcstruct.h" 6505b261ecSmrg#include "dixfontstr.h" 6605b261ecSmrg#include "extnsionst.h" 6735c4bbdfSmrg#include "extinit.h" 686747b715Smrg#include "protocol-versions.h" 6905b261ecSmrg 706747b715Smrg#include <X11/extensions/xf86bigfproto.h> 716747b715Smrg#include "xf86bigfontsrv.h" 7205b261ecSmrg 7335c4bbdfSmrgstatic void XF86BigfontResetProc(ExtensionEntry * /* extEntry */ 7405b261ecSmrg ); 7505b261ecSmrg 7605b261ecSmrg#ifdef HAS_SHM 7705b261ecSmrg 7805b261ecSmrg/* A random signature, transmitted to the clients so they can verify that the 7905b261ecSmrg shared memory segment they are attaching to was really established by the 8005b261ecSmrg X server they are talking to. */ 8105b261ecSmrgstatic CARD32 signature; 8205b261ecSmrg 8305b261ecSmrg/* Index for additional information stored in a FontRec's devPrivates array. */ 8405b261ecSmrgstatic int FontShmdescIndex; 8505b261ecSmrg 8605b261ecSmrgstatic unsigned int pagesize; 8705b261ecSmrg 8805b261ecSmrgstatic Bool badSysCall = FALSE; 8905b261ecSmrg 9005b261ecSmrg#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__) 9105b261ecSmrg 9205b261ecSmrgstatic void 9335c4bbdfSmrgSigSysHandler(int signo) 9405b261ecSmrg{ 9505b261ecSmrg badSysCall = TRUE; 9605b261ecSmrg} 9705b261ecSmrg 9805b261ecSmrgstatic Bool 9905b261ecSmrgCheckForShmSyscall(void) 10005b261ecSmrg{ 10135c4bbdfSmrg void (*oldHandler) (int); 10205b261ecSmrg int shmid = -1; 10305b261ecSmrg 10405b261ecSmrg /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */ 1051b5d61b8Smrg oldHandler = OsSignal(SIGSYS, SigSysHandler); 10605b261ecSmrg 10705b261ecSmrg badSysCall = FALSE; 10805b261ecSmrg shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT); 10935c4bbdfSmrg if (shmid != -1) { 11005b261ecSmrg /* Successful allocation - clean up */ 11135c4bbdfSmrg shmctl(shmid, IPC_RMID, NULL); 11205b261ecSmrg } 11335c4bbdfSmrg else { 11405b261ecSmrg /* Allocation failed */ 11505b261ecSmrg badSysCall = TRUE; 11605b261ecSmrg } 1171b5d61b8Smrg OsSignal(SIGSYS, oldHandler); 1186747b715Smrg return !badSysCall; 11905b261ecSmrg} 12005b261ecSmrg 12105b261ecSmrg#define MUST_CHECK_FOR_SHM_SYSCALL 12205b261ecSmrg 12305b261ecSmrg#endif 12405b261ecSmrg 12505b261ecSmrg#endif 12605b261ecSmrg 12705b261ecSmrg/* ========== Management of shared memory segments ========== */ 12805b261ecSmrg 12905b261ecSmrg#ifdef HAS_SHM 13005b261ecSmrg 13105b261ecSmrg#ifdef __linux__ 13205b261ecSmrg/* On Linux, shared memory marked as "removed" can still be attached. 13305b261ecSmrg Nice feature, because the kernel will automatically free the associated 13405b261ecSmrg storage when the server and all clients are gone. */ 13505b261ecSmrg#define EARLY_REMOVE 13605b261ecSmrg#endif 13705b261ecSmrg 13805b261ecSmrgtypedef struct _ShmDesc { 13905b261ecSmrg struct _ShmDesc *next; 14005b261ecSmrg struct _ShmDesc **prev; 14105b261ecSmrg int shmid; 14205b261ecSmrg char *attach_addr; 14305b261ecSmrg} ShmDescRec, *ShmDescPtr; 14405b261ecSmrg 14505b261ecSmrgstatic ShmDescPtr ShmList = (ShmDescPtr) NULL; 14605b261ecSmrg 14705b261ecSmrgstatic ShmDescPtr 14835c4bbdfSmrgshmalloc(unsigned int size) 14905b261ecSmrg{ 15005b261ecSmrg ShmDescPtr pDesc; 15105b261ecSmrg int shmid; 15205b261ecSmrg char *addr; 15305b261ecSmrg 15405b261ecSmrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL 15505b261ecSmrg if (pagesize == 0) 15635c4bbdfSmrg return (ShmDescPtr) NULL; 15705b261ecSmrg#endif 15805b261ecSmrg 15905b261ecSmrg /* On some older Linux systems, the number of shared memory segments 16005b261ecSmrg system-wide is 127. In Linux 2.4, it is 4095. 16105b261ecSmrg Therefore there is a tradeoff to be made between allocating a 16205b261ecSmrg shared memory segment on one hand, and allocating memory and piping 16305b261ecSmrg the glyph metrics on the other hand. If the glyph metrics size is 16405b261ecSmrg small, we prefer the traditional way. */ 16505b261ecSmrg if (size < 3500) 16635c4bbdfSmrg return (ShmDescPtr) NULL; 16705b261ecSmrg 1686747b715Smrg pDesc = malloc(sizeof(ShmDescRec)); 16905b261ecSmrg if (!pDesc) 17035c4bbdfSmrg return (ShmDescPtr) NULL; 17105b261ecSmrg 17235c4bbdfSmrg size = (size + pagesize - 1) & -pagesize; 17305b261ecSmrg shmid = shmget(IPC_PRIVATE, size, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); 17405b261ecSmrg if (shmid == -1) { 17535c4bbdfSmrg ErrorF(XF86BIGFONTNAME " extension: shmget() failed, size = %u, %s\n", 17635c4bbdfSmrg size, strerror(errno)); 17735c4bbdfSmrg free(pDesc); 17835c4bbdfSmrg return (ShmDescPtr) NULL; 17905b261ecSmrg } 18005b261ecSmrg 18135c4bbdfSmrg if ((addr = shmat(shmid, 0, 0)) == (char *) -1) { 18235c4bbdfSmrg ErrorF(XF86BIGFONTNAME " extension: shmat() failed, size = %u, %s\n", 18335c4bbdfSmrg size, strerror(errno)); 18435c4bbdfSmrg shmctl(shmid, IPC_RMID, (void *) 0); 18535c4bbdfSmrg free(pDesc); 18635c4bbdfSmrg return (ShmDescPtr) NULL; 18705b261ecSmrg } 18805b261ecSmrg 18905b261ecSmrg#ifdef EARLY_REMOVE 19005b261ecSmrg shmctl(shmid, IPC_RMID, (void *) 0); 19105b261ecSmrg#endif 19205b261ecSmrg 19305b261ecSmrg pDesc->shmid = shmid; 19405b261ecSmrg pDesc->attach_addr = addr; 19535c4bbdfSmrg if (ShmList) 19635c4bbdfSmrg ShmList->prev = &pDesc->next; 19705b261ecSmrg pDesc->next = ShmList; 19805b261ecSmrg pDesc->prev = &ShmList; 19905b261ecSmrg ShmList = pDesc; 20005b261ecSmrg 20105b261ecSmrg return pDesc; 20205b261ecSmrg} 20305b261ecSmrg 20405b261ecSmrgstatic void 20535c4bbdfSmrgshmdealloc(ShmDescPtr pDesc) 20605b261ecSmrg{ 20705b261ecSmrg#ifndef EARLY_REMOVE 20805b261ecSmrg shmctl(pDesc->shmid, IPC_RMID, (void *) 0); 20905b261ecSmrg#endif 21005b261ecSmrg shmdt(pDesc->attach_addr); 21105b261ecSmrg 21235c4bbdfSmrg if (pDesc->next) 21335c4bbdfSmrg pDesc->next->prev = pDesc->prev; 21405b261ecSmrg *pDesc->prev = pDesc->next; 2156747b715Smrg free(pDesc); 21605b261ecSmrg} 21705b261ecSmrg 21805b261ecSmrg#endif 21905b261ecSmrg 22005b261ecSmrg/* Called when a font is closed. */ 22105b261ecSmrgvoid 22235c4bbdfSmrgXF86BigfontFreeFontShm(FontPtr pFont) 22305b261ecSmrg{ 22405b261ecSmrg#ifdef HAS_SHM 22505b261ecSmrg ShmDescPtr pDesc; 22605b261ecSmrg 22705b261ecSmrg /* If during shutdown of the server, XF86BigfontCleanup() has already 22805b261ecSmrg * called shmdealloc() for all segments, we don't need to do it here. 22905b261ecSmrg */ 23005b261ecSmrg if (!ShmList) 23135c4bbdfSmrg return; 23205b261ecSmrg 23305b261ecSmrg pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex); 23405b261ecSmrg if (pDesc) 23535c4bbdfSmrg shmdealloc(pDesc); 23605b261ecSmrg#endif 23705b261ecSmrg} 23805b261ecSmrg 23905b261ecSmrg/* Called upon fatal signal. */ 24005b261ecSmrgvoid 2416747b715SmrgXF86BigfontCleanup(void) 24205b261ecSmrg{ 24305b261ecSmrg#ifdef HAS_SHM 24405b261ecSmrg while (ShmList) 24535c4bbdfSmrg shmdealloc(ShmList); 24605b261ecSmrg#endif 24705b261ecSmrg} 24805b261ecSmrg 24905b261ecSmrg/* Called when a server generation dies. */ 25005b261ecSmrgstatic void 25135c4bbdfSmrgXF86BigfontResetProc(ExtensionEntry * extEntry) 25205b261ecSmrg{ 25305b261ecSmrg /* This function is normally called from CloseDownExtensions(), called 25405b261ecSmrg * from main(). It will be followed by a call to FreeAllResources(), 25505b261ecSmrg * which will call XF86BigfontFreeFontShm() for each font. Thus it 25605b261ecSmrg * appears that we do not need to do anything in this function. -- 25705b261ecSmrg * But I prefer to write robust code, and not keep shared memory lying 25805b261ecSmrg * around when it's not needed any more. (Someone might close down the 25905b261ecSmrg * extension without calling FreeAllResources()...) 26005b261ecSmrg */ 26105b261ecSmrg XF86BigfontCleanup(); 26205b261ecSmrg} 26305b261ecSmrg 26405b261ecSmrg/* ========== Handling of extension specific requests ========== */ 26505b261ecSmrg 26605b261ecSmrgstatic int 26735c4bbdfSmrgProcXF86BigfontQueryVersion(ClientPtr client) 26805b261ecSmrg{ 26905b261ecSmrg xXF86BigfontQueryVersionReply reply; 27005b261ecSmrg 27105b261ecSmrg REQUEST_SIZE_MATCH(xXF86BigfontQueryVersionReq); 27235c4bbdfSmrg reply = (xXF86BigfontQueryVersionReply) { 27335c4bbdfSmrg .type = X_Reply, 27435c4bbdfSmrg .sequenceNumber = client->sequence, 27535c4bbdfSmrg .length = 0, 27635c4bbdfSmrg .majorVersion = SERVER_XF86BIGFONT_MAJOR_VERSION, 27735c4bbdfSmrg .minorVersion = SERVER_XF86BIGFONT_MINOR_VERSION, 27835c4bbdfSmrg .uid = geteuid(), 27935c4bbdfSmrg .gid = getegid(), 28005b261ecSmrg#ifdef HAS_SHM 28135c4bbdfSmrg .signature = signature, 28235c4bbdfSmrg .capabilities = (client->local && !client->swapped) 28335c4bbdfSmrg ? XF86Bigfont_CAP_LocalShm : 0 28405b261ecSmrg#else 28535c4bbdfSmrg .signature = 0, 28635c4bbdfSmrg .capabilities = 0 28705b261ecSmrg#endif 28835c4bbdfSmrg }; 28905b261ecSmrg if (client->swapped) { 29035c4bbdfSmrg swaps(&reply.sequenceNumber); 29135c4bbdfSmrg swapl(&reply.length); 29235c4bbdfSmrg swaps(&reply.majorVersion); 29335c4bbdfSmrg swaps(&reply.minorVersion); 29435c4bbdfSmrg swapl(&reply.uid); 29535c4bbdfSmrg swapl(&reply.gid); 29635c4bbdfSmrg swapl(&reply.signature); 29705b261ecSmrg } 29835c4bbdfSmrg WriteToClient(client, sizeof(xXF86BigfontQueryVersionReply), &reply); 2996747b715Smrg return Success; 30005b261ecSmrg} 30105b261ecSmrg 30205b261ecSmrgstatic void 30335c4bbdfSmrgswapCharInfo(xCharInfo * pCI) 30405b261ecSmrg{ 30535c4bbdfSmrg swaps(&pCI->leftSideBearing); 30635c4bbdfSmrg swaps(&pCI->rightSideBearing); 30735c4bbdfSmrg swaps(&pCI->characterWidth); 30835c4bbdfSmrg swaps(&pCI->ascent); 30935c4bbdfSmrg swaps(&pCI->descent); 31035c4bbdfSmrg swaps(&pCI->attributes); 31105b261ecSmrg} 31205b261ecSmrg 31305b261ecSmrg/* static CARD32 hashCI (xCharInfo *p); */ 31405b261ecSmrg#define hashCI(p) \ 31505b261ecSmrg (CARD32)(((p->leftSideBearing << 27) + (p->leftSideBearing >> 5) + \ 31605b261ecSmrg (p->rightSideBearing << 23) + (p->rightSideBearing >> 9) + \ 31705b261ecSmrg (p->characterWidth << 16) + \ 31805b261ecSmrg (p->ascent << 11) + (p->descent << 6)) ^ p->attributes) 31905b261ecSmrg 32005b261ecSmrgstatic int 32135c4bbdfSmrgProcXF86BigfontQueryFont(ClientPtr client) 32205b261ecSmrg{ 32305b261ecSmrg FontPtr pFont; 32435c4bbdfSmrg 32505b261ecSmrg REQUEST(xXF86BigfontQueryFontReq); 32605b261ecSmrg CARD32 stuff_flags; 32735c4bbdfSmrg xCharInfo *pmax; 32835c4bbdfSmrg xCharInfo *pmin; 32905b261ecSmrg int nCharInfos; 33005b261ecSmrg int shmid; 33135c4bbdfSmrg 33205b261ecSmrg#ifdef HAS_SHM 3336747b715Smrg ShmDescPtr pDesc = NULL; 33405b261ecSmrg#else 33505b261ecSmrg#define pDesc 0 33605b261ecSmrg#endif 33735c4bbdfSmrg xCharInfo *pCI; 33835c4bbdfSmrg CARD16 *pIndex2UniqIndex; 33935c4bbdfSmrg CARD16 *pUniqIndex2Index; 34005b261ecSmrg CARD32 nUniqCharInfos; 34105b261ecSmrg 34205b261ecSmrg#if 0 34305b261ecSmrg REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq); 34405b261ecSmrg#else 34505b261ecSmrg switch (client->req_len) { 34635c4bbdfSmrg case 2: /* client with version 1.0 libX11 */ 34735c4bbdfSmrg stuff_flags = (client->local && 34835c4bbdfSmrg !client->swapped ? XF86Bigfont_FLAGS_Shm : 0); 34935c4bbdfSmrg break; 35035c4bbdfSmrg case 3: /* client with version 1.1 libX11 */ 35135c4bbdfSmrg stuff_flags = stuff->flags; 35235c4bbdfSmrg break; 35335c4bbdfSmrg default: 35435c4bbdfSmrg return BadLength; 35505b261ecSmrg } 35605b261ecSmrg#endif 35735c4bbdfSmrg if (dixLookupFontable(&pFont, stuff->id, client, DixGetAttrAccess) != 35835c4bbdfSmrg Success) 35935c4bbdfSmrg return BadFont; /* procotol spec says only error is BadFont */ 36005b261ecSmrg 36105b261ecSmrg pmax = FONTINKMAX(pFont); 36205b261ecSmrg pmin = FONTINKMIN(pFont); 36305b261ecSmrg nCharInfos = 36435c4bbdfSmrg (pmax->rightSideBearing == pmin->rightSideBearing 36535c4bbdfSmrg && pmax->leftSideBearing == pmin->leftSideBearing 36635c4bbdfSmrg && pmax->descent == pmin->descent 36735c4bbdfSmrg && pmax->ascent == pmin->ascent 36835c4bbdfSmrg && pmax->characterWidth == pmin->characterWidth) 36935c4bbdfSmrg ? 0 : N2dChars(pFont); 37005b261ecSmrg shmid = -1; 37105b261ecSmrg pCI = NULL; 37205b261ecSmrg pIndex2UniqIndex = NULL; 37305b261ecSmrg pUniqIndex2Index = NULL; 37405b261ecSmrg nUniqCharInfos = 0; 37505b261ecSmrg 37605b261ecSmrg if (nCharInfos > 0) { 37705b261ecSmrg#ifdef HAS_SHM 37835c4bbdfSmrg if (!badSysCall) 37935c4bbdfSmrg pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex); 380d5c798e1Smrg if (pDesc && pDesc->attach_addr) { 38135c4bbdfSmrg pCI = (xCharInfo *) pDesc->attach_addr; 38235c4bbdfSmrg if (stuff_flags & XF86Bigfont_FLAGS_Shm) 38335c4bbdfSmrg shmid = pDesc->shmid; 38435c4bbdfSmrg } 38535c4bbdfSmrg else { 38635c4bbdfSmrg if (stuff_flags & XF86Bigfont_FLAGS_Shm && !badSysCall) 38735c4bbdfSmrg pDesc = shmalloc(nCharInfos * sizeof(xCharInfo) 38835c4bbdfSmrg + sizeof(CARD32)); 38935c4bbdfSmrg if (pDesc) { 39035c4bbdfSmrg pCI = (xCharInfo *) pDesc->attach_addr; 39135c4bbdfSmrg shmid = pDesc->shmid; 39235c4bbdfSmrg } 39335c4bbdfSmrg else { 39405b261ecSmrg#endif 39535c4bbdfSmrg pCI = xallocarray(nCharInfos, sizeof(xCharInfo)); 39635c4bbdfSmrg if (!pCI) 39735c4bbdfSmrg return BadAlloc; 39805b261ecSmrg#ifdef HAS_SHM 39935c4bbdfSmrg } 40005b261ecSmrg#endif 40135c4bbdfSmrg /* Fill nCharInfos starting at pCI. */ 40235c4bbdfSmrg { 40335c4bbdfSmrg xCharInfo *prCI = pCI; 40435c4bbdfSmrg int ninfos = 0; 40535c4bbdfSmrg int ncols = pFont->info.lastCol - pFont->info.firstCol + 1; 40635c4bbdfSmrg int row; 40735c4bbdfSmrg 40835c4bbdfSmrg for (row = pFont->info.firstRow; 40935c4bbdfSmrg row <= pFont->info.lastRow && ninfos < nCharInfos; row++) { 41035c4bbdfSmrg unsigned char chars[512]; 41135c4bbdfSmrg xCharInfo *tmpCharInfos[256]; 41235c4bbdfSmrg unsigned long count; 41335c4bbdfSmrg int col; 41435c4bbdfSmrg unsigned long i; 41535c4bbdfSmrg 41635c4bbdfSmrg i = 0; 41735c4bbdfSmrg for (col = pFont->info.firstCol; 41835c4bbdfSmrg col <= pFont->info.lastCol; col++) { 41935c4bbdfSmrg chars[i++] = row; 42035c4bbdfSmrg chars[i++] = col; 42135c4bbdfSmrg } 42235c4bbdfSmrg (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit, 42335c4bbdfSmrg &count, tmpCharInfos); 42435c4bbdfSmrg for (i = 0; i < count && ninfos < nCharInfos; i++) { 42535c4bbdfSmrg *prCI++ = *tmpCharInfos[i]; 42635c4bbdfSmrg ninfos++; 42735c4bbdfSmrg } 42835c4bbdfSmrg } 42935c4bbdfSmrg } 43005b261ecSmrg#ifdef HAS_SHM 43135c4bbdfSmrg if (pDesc && !badSysCall) { 43235c4bbdfSmrg *(CARD32 *) (pCI + nCharInfos) = signature; 4331b5d61b8Smrg if (!xfont2_font_set_private(pFont, FontShmdescIndex, pDesc)) { 43435c4bbdfSmrg shmdealloc(pDesc); 43535c4bbdfSmrg return BadAlloc; 43635c4bbdfSmrg } 43735c4bbdfSmrg } 43835c4bbdfSmrg } 43905b261ecSmrg#endif 44035c4bbdfSmrg if (shmid == -1) { 44135c4bbdfSmrg /* Cannot use shared memory, so remove-duplicates the xCharInfos 44235c4bbdfSmrg using a temporary hash table. */ 44335c4bbdfSmrg /* Note that CARD16 is suitable as index type, because 44435c4bbdfSmrg nCharInfos <= 0x10000. */ 44535c4bbdfSmrg CARD32 hashModulus; 44635c4bbdfSmrg CARD16 *pHash2UniqIndex; 44735c4bbdfSmrg CARD16 *pUniqIndex2NextUniqIndex; 44835c4bbdfSmrg CARD32 NextIndex; 44935c4bbdfSmrg CARD32 NextUniqIndex; 45035c4bbdfSmrg CARD16 *tmp; 45135c4bbdfSmrg CARD32 i, j; 45235c4bbdfSmrg 45335c4bbdfSmrg hashModulus = 67; 45435c4bbdfSmrg if (hashModulus > nCharInfos + 1) 45535c4bbdfSmrg hashModulus = nCharInfos + 1; 45635c4bbdfSmrg 45735c4bbdfSmrg tmp = xallocarray(4 * nCharInfos + 1, sizeof(CARD16)); 45835c4bbdfSmrg if (!tmp) { 45935c4bbdfSmrg if (!pDesc) 46035c4bbdfSmrg free(pCI); 46135c4bbdfSmrg return BadAlloc; 46235c4bbdfSmrg } 46335c4bbdfSmrg pIndex2UniqIndex = tmp; 46435c4bbdfSmrg /* nCharInfos elements */ 46535c4bbdfSmrg pUniqIndex2Index = tmp + nCharInfos; 46635c4bbdfSmrg /* max. nCharInfos elements */ 46735c4bbdfSmrg pUniqIndex2NextUniqIndex = tmp + 2 * nCharInfos; 46835c4bbdfSmrg /* max. nCharInfos elements */ 46935c4bbdfSmrg pHash2UniqIndex = tmp + 3 * nCharInfos; 47035c4bbdfSmrg /* hashModulus (<= nCharInfos+1) elements */ 47135c4bbdfSmrg 47235c4bbdfSmrg /* Note that we can use 0xffff as end-of-list indicator, because 47335c4bbdfSmrg even if nCharInfos = 0x10000, 0xffff can not occur as valid 47435c4bbdfSmrg entry before the last element has been inserted. And once the 47535c4bbdfSmrg last element has been inserted, we don't need the hash table 47635c4bbdfSmrg any more. */ 47735c4bbdfSmrg for (j = 0; j < hashModulus; j++) 47835c4bbdfSmrg pHash2UniqIndex[j] = (CARD16) (-1); 47935c4bbdfSmrg 48035c4bbdfSmrg NextUniqIndex = 0; 48135c4bbdfSmrg for (NextIndex = 0; NextIndex < nCharInfos; NextIndex++) { 48235c4bbdfSmrg xCharInfo *p = &pCI[NextIndex]; 48335c4bbdfSmrg CARD32 hashCode = hashCI(p) % hashModulus; 48435c4bbdfSmrg 48535c4bbdfSmrg for (i = pHash2UniqIndex[hashCode]; 48635c4bbdfSmrg i != (CARD16) (-1); i = pUniqIndex2NextUniqIndex[i]) { 48735c4bbdfSmrg j = pUniqIndex2Index[i]; 48835c4bbdfSmrg if (pCI[j].leftSideBearing == p->leftSideBearing 48935c4bbdfSmrg && pCI[j].rightSideBearing == p->rightSideBearing 49035c4bbdfSmrg && pCI[j].characterWidth == p->characterWidth 49135c4bbdfSmrg && pCI[j].ascent == p->ascent 49235c4bbdfSmrg && pCI[j].descent == p->descent 49335c4bbdfSmrg && pCI[j].attributes == p->attributes) 49435c4bbdfSmrg break; 49535c4bbdfSmrg } 49635c4bbdfSmrg if (i != (CARD16) (-1)) { 49735c4bbdfSmrg /* Found *p at Index j, UniqIndex i */ 49835c4bbdfSmrg pIndex2UniqIndex[NextIndex] = i; 49935c4bbdfSmrg } 50035c4bbdfSmrg else { 50135c4bbdfSmrg /* Allocate a new entry in the Uniq table */ 50235c4bbdfSmrg if (hashModulus <= 2 * NextUniqIndex 50335c4bbdfSmrg && hashModulus < nCharInfos + 1) { 50435c4bbdfSmrg /* Time to increate hash table size */ 50535c4bbdfSmrg hashModulus = 2 * hashModulus + 1; 50635c4bbdfSmrg if (hashModulus > nCharInfos + 1) 50735c4bbdfSmrg hashModulus = nCharInfos + 1; 50835c4bbdfSmrg for (j = 0; j < hashModulus; j++) 50935c4bbdfSmrg pHash2UniqIndex[j] = (CARD16) (-1); 51035c4bbdfSmrg for (i = 0; i < NextUniqIndex; i++) 51135c4bbdfSmrg pUniqIndex2NextUniqIndex[i] = (CARD16) (-1); 51235c4bbdfSmrg for (i = 0; i < NextUniqIndex; i++) { 51335c4bbdfSmrg j = pUniqIndex2Index[i]; 51435c4bbdfSmrg p = &pCI[j]; 51535c4bbdfSmrg hashCode = hashCI(p) % hashModulus; 51635c4bbdfSmrg pUniqIndex2NextUniqIndex[i] = 51735c4bbdfSmrg pHash2UniqIndex[hashCode]; 51835c4bbdfSmrg pHash2UniqIndex[hashCode] = i; 51935c4bbdfSmrg } 52035c4bbdfSmrg p = &pCI[NextIndex]; 52135c4bbdfSmrg hashCode = hashCI(p) % hashModulus; 52235c4bbdfSmrg } 52335c4bbdfSmrg i = NextUniqIndex++; 52435c4bbdfSmrg pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode]; 52535c4bbdfSmrg pHash2UniqIndex[hashCode] = i; 52635c4bbdfSmrg pUniqIndex2Index[i] = NextIndex; 52735c4bbdfSmrg pIndex2UniqIndex[NextIndex] = i; 52835c4bbdfSmrg } 52935c4bbdfSmrg } 53035c4bbdfSmrg nUniqCharInfos = NextUniqIndex; 53135c4bbdfSmrg /* fprintf(stderr, "font metrics: nCharInfos = %d, nUniqCharInfos = %d, hashModulus = %d\n", nCharInfos, nUniqCharInfos, hashModulus); */ 53235c4bbdfSmrg } 53305b261ecSmrg } 53405b261ecSmrg 53505b261ecSmrg { 53635c4bbdfSmrg int nfontprops = pFont->info.nprops; 53735c4bbdfSmrg int rlength = sizeof(xXF86BigfontQueryFontReply) 53835c4bbdfSmrg + nfontprops * sizeof(xFontProp) 53935c4bbdfSmrg + (nCharInfos > 0 && shmid == -1 54035c4bbdfSmrg ? nUniqCharInfos * sizeof(xCharInfo) 54135c4bbdfSmrg + (nCharInfos + 1) / 2 * 2 * sizeof(CARD16) 54235c4bbdfSmrg : 0); 54335c4bbdfSmrg xXF86BigfontQueryFontReply *reply = calloc(1, rlength); 54435c4bbdfSmrg char *p; 54535c4bbdfSmrg 54635c4bbdfSmrg if (!reply) { 54735c4bbdfSmrg if (nCharInfos > 0) { 54835c4bbdfSmrg if (shmid == -1) 54935c4bbdfSmrg free(pIndex2UniqIndex); 55035c4bbdfSmrg if (!pDesc) 55135c4bbdfSmrg free(pCI); 55235c4bbdfSmrg } 55335c4bbdfSmrg return BadAlloc; 55435c4bbdfSmrg } 55535c4bbdfSmrg reply->type = X_Reply; 55635c4bbdfSmrg reply->length = bytes_to_int32(rlength - sizeof(xGenericReply)); 55735c4bbdfSmrg reply->sequenceNumber = client->sequence; 55835c4bbdfSmrg reply->minBounds = pFont->info.ink_minbounds; 55935c4bbdfSmrg reply->maxBounds = pFont->info.ink_maxbounds; 56035c4bbdfSmrg reply->minCharOrByte2 = pFont->info.firstCol; 56135c4bbdfSmrg reply->maxCharOrByte2 = pFont->info.lastCol; 56235c4bbdfSmrg reply->defaultChar = pFont->info.defaultCh; 56335c4bbdfSmrg reply->nFontProps = pFont->info.nprops; 56435c4bbdfSmrg reply->drawDirection = pFont->info.drawDirection; 56535c4bbdfSmrg reply->minByte1 = pFont->info.firstRow; 56635c4bbdfSmrg reply->maxByte1 = pFont->info.lastRow; 56735c4bbdfSmrg reply->allCharsExist = pFont->info.allExist; 56835c4bbdfSmrg reply->fontAscent = pFont->info.fontAscent; 56935c4bbdfSmrg reply->fontDescent = pFont->info.fontDescent; 57035c4bbdfSmrg reply->nCharInfos = nCharInfos; 57105b261ecSmrg reply->nUniqCharInfos = nUniqCharInfos; 57235c4bbdfSmrg reply->shmid = shmid; 57335c4bbdfSmrg reply->shmsegoffset = 0; 57435c4bbdfSmrg if (client->swapped) { 57535c4bbdfSmrg swaps(&reply->sequenceNumber); 57635c4bbdfSmrg swapl(&reply->length); 57735c4bbdfSmrg swapCharInfo(&reply->minBounds); 57835c4bbdfSmrg swapCharInfo(&reply->maxBounds); 57935c4bbdfSmrg swaps(&reply->minCharOrByte2); 58035c4bbdfSmrg swaps(&reply->maxCharOrByte2); 58135c4bbdfSmrg swaps(&reply->defaultChar); 58235c4bbdfSmrg swaps(&reply->nFontProps); 58335c4bbdfSmrg swaps(&reply->fontAscent); 58435c4bbdfSmrg swaps(&reply->fontDescent); 58535c4bbdfSmrg swapl(&reply->nCharInfos); 58635c4bbdfSmrg swapl(&reply->nUniqCharInfos); 58735c4bbdfSmrg swapl(&reply->shmid); 58835c4bbdfSmrg swapl(&reply->shmsegoffset); 58935c4bbdfSmrg } 59035c4bbdfSmrg p = (char *) &reply[1]; 59135c4bbdfSmrg { 59235c4bbdfSmrg FontPropPtr pFP; 59335c4bbdfSmrg xFontProp *prFP; 59435c4bbdfSmrg int i; 59535c4bbdfSmrg 59635c4bbdfSmrg for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) p; 59735c4bbdfSmrg i < nfontprops; i++, pFP++, prFP++) { 59835c4bbdfSmrg prFP->name = pFP->name; 59935c4bbdfSmrg prFP->value = pFP->value; 60035c4bbdfSmrg if (client->swapped) { 60135c4bbdfSmrg swapl(&prFP->name); 60235c4bbdfSmrg swapl(&prFP->value); 60335c4bbdfSmrg } 60435c4bbdfSmrg } 60535c4bbdfSmrg p = (char *) prFP; 60635c4bbdfSmrg } 60735c4bbdfSmrg if (nCharInfos > 0 && shmid == -1) { 60835c4bbdfSmrg xCharInfo *pci; 60935c4bbdfSmrg CARD16 *ps; 61035c4bbdfSmrg int i, j; 61135c4bbdfSmrg 61235c4bbdfSmrg pci = (xCharInfo *) p; 61335c4bbdfSmrg for (i = 0; i < nUniqCharInfos; i++, pci++) { 61435c4bbdfSmrg *pci = pCI[pUniqIndex2Index[i]]; 61535c4bbdfSmrg if (client->swapped) 61635c4bbdfSmrg swapCharInfo(pci); 61735c4bbdfSmrg } 61835c4bbdfSmrg ps = (CARD16 *) pci; 61935c4bbdfSmrg for (j = 0; j < nCharInfos; j++, ps++) { 62035c4bbdfSmrg *ps = pIndex2UniqIndex[j]; 62135c4bbdfSmrg if (client->swapped) { 62235c4bbdfSmrg swaps(ps); 62335c4bbdfSmrg } 62435c4bbdfSmrg } 62535c4bbdfSmrg } 62635c4bbdfSmrg WriteToClient(client, rlength, reply); 62735c4bbdfSmrg free(reply); 62835c4bbdfSmrg if (nCharInfos > 0) { 62935c4bbdfSmrg if (shmid == -1) 63035c4bbdfSmrg free(pIndex2UniqIndex); 63135c4bbdfSmrg if (!pDesc) 63235c4bbdfSmrg free(pCI); 63335c4bbdfSmrg } 63435c4bbdfSmrg return Success; 63505b261ecSmrg } 63605b261ecSmrg} 63705b261ecSmrg 63805b261ecSmrgstatic int 63935c4bbdfSmrgProcXF86BigfontDispatch(ClientPtr client) 64005b261ecSmrg{ 64105b261ecSmrg REQUEST(xReq); 64205b261ecSmrg 64305b261ecSmrg switch (stuff->data) { 64435c4bbdfSmrg case X_XF86BigfontQueryVersion: 64535c4bbdfSmrg return ProcXF86BigfontQueryVersion(client); 64635c4bbdfSmrg case X_XF86BigfontQueryFont: 64735c4bbdfSmrg return ProcXF86BigfontQueryFont(client); 64835c4bbdfSmrg default: 64935c4bbdfSmrg return BadRequest; 65005b261ecSmrg } 65105b261ecSmrg} 65205b261ecSmrg 6531b5d61b8Smrgstatic int _X_COLD 65435c4bbdfSmrgSProcXF86BigfontQueryVersion(ClientPtr client) 65505b261ecSmrg{ 65605b261ecSmrg REQUEST(xXF86BigfontQueryVersionReq); 65705b261ecSmrg 65835c4bbdfSmrg swaps(&stuff->length); 65905b261ecSmrg return ProcXF86BigfontQueryVersion(client); 66005b261ecSmrg} 66105b261ecSmrg 6621b5d61b8Smrgstatic int _X_COLD 66335c4bbdfSmrgSProcXF86BigfontQueryFont(ClientPtr client) 66405b261ecSmrg{ 66505b261ecSmrg REQUEST(xXF86BigfontQueryFontReq); 66605b261ecSmrg 66735c4bbdfSmrg swaps(&stuff->length); 66805b261ecSmrg REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq); 66935c4bbdfSmrg swapl(&stuff->id); 67005b261ecSmrg return ProcXF86BigfontQueryFont(client); 67105b261ecSmrg} 67205b261ecSmrg 6731b5d61b8Smrgstatic int _X_COLD 67435c4bbdfSmrgSProcXF86BigfontDispatch(ClientPtr client) 67505b261ecSmrg{ 67605b261ecSmrg REQUEST(xReq); 67705b261ecSmrg 67805b261ecSmrg switch (stuff->data) { 67935c4bbdfSmrg case X_XF86BigfontQueryVersion: 68035c4bbdfSmrg return SProcXF86BigfontQueryVersion(client); 68135c4bbdfSmrg case X_XF86BigfontQueryFont: 68235c4bbdfSmrg return SProcXF86BigfontQueryFont(client); 68335c4bbdfSmrg default: 68435c4bbdfSmrg return BadRequest; 68505b261ecSmrg } 68605b261ecSmrg} 6879ace9065Smrg 6889ace9065Smrgvoid 6899ace9065SmrgXFree86BigfontExtensionInit(void) 6909ace9065Smrg{ 6919ace9065Smrg if (AddExtension(XF86BIGFONTNAME, 69235c4bbdfSmrg XF86BigfontNumberEvents, 69335c4bbdfSmrg XF86BigfontNumberErrors, 69435c4bbdfSmrg ProcXF86BigfontDispatch, 69535c4bbdfSmrg SProcXF86BigfontDispatch, 69635c4bbdfSmrg XF86BigfontResetProc, StandardMinorOpcode)) { 6979ace9065Smrg#ifdef HAS_SHM 6989ace9065Smrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL 69935c4bbdfSmrg /* 70035c4bbdfSmrg * Note: Local-clients will not be optimized without shared memory 70135c4bbdfSmrg * support. Remote-client optimization does not depend on shared 70235c4bbdfSmrg * memory support. Thus, the extension is still registered even 70335c4bbdfSmrg * when shared memory support is not functional. 70435c4bbdfSmrg */ 70535c4bbdfSmrg if (!CheckForShmSyscall()) { 70635c4bbdfSmrg ErrorF(XF86BIGFONTNAME 70735c4bbdfSmrg " extension local-client optimization disabled due to lack of shared memory support in the kernel\n"); 70835c4bbdfSmrg return; 70935c4bbdfSmrg } 7109ace9065Smrg#endif 7119ace9065Smrg 71235c4bbdfSmrg srand((unsigned int) time(NULL)); 71335c4bbdfSmrg signature = ((unsigned int) (65536.0 / (RAND_MAX + 1.0) * rand()) << 16) 71435c4bbdfSmrg + (unsigned int) (65536.0 / (RAND_MAX + 1.0) * rand()); 71535c4bbdfSmrg /* fprintf(stderr, "signature = 0x%08X\n", signature); */ 7169ace9065Smrg 7171b5d61b8Smrg FontShmdescIndex = xfont2_allocate_font_private_index(); 7189ace9065Smrg 7199ace9065Smrg#if !defined(CSRG_BASED) && !defined(__CYGWIN__) 72035c4bbdfSmrg pagesize = SHMLBA; 7219ace9065Smrg#else 72235c4bbdfSmrg#ifdef _SC_PAGESIZE 72335c4bbdfSmrg pagesize = sysconf(_SC_PAGESIZE); 72435c4bbdfSmrg#else 72535c4bbdfSmrg pagesize = getpagesize(); 72635c4bbdfSmrg#endif 7279ace9065Smrg#endif 7289ace9065Smrg#endif 7299ace9065Smrg } 7309ace9065Smrg} 731