From 8fd06c45853cb2300105db84e4b722f0e2dad8d2 Mon Sep 17 00:00:00 2001 From: marha Date: Wed, 22 Dec 2010 13:20:05 +0000 Subject: xserver libX11 libXdmcp pixman git update 22-12-2010 --- xorg-server/Xext/xf86bigfont.c | 1502 ++++++++++++++++++++-------------------- 1 file changed, 751 insertions(+), 751 deletions(-) (limited to 'xorg-server/Xext') diff --git a/xorg-server/Xext/xf86bigfont.c b/xorg-server/Xext/xf86bigfont.c index 356a6152b..da3528783 100644 --- a/xorg-server/Xext/xf86bigfont.c +++ b/xorg-server/Xext/xf86bigfont.c @@ -1,751 +1,751 @@ -/* - * BIGFONT extension for sharing font metrics between clients (if possible) - * and for transmitting font metrics to clients in a compressed form. - * - * Copyright (c) 1999-2000 Bruno Haible - * Copyright (c) 1999-2000 The XFree86 Project, Inc. - */ - -/* THIS IS NOT AN X CONSORTIUM STANDARD */ - -/* - * Big fonts suffer from the following: All clients that have opened a - * font can access the complete glyph metrics array (the XFontStruct member - * `per_char') directly, without going through a macro. Moreover these - * glyph metrics are ink metrics, i.e. are not redundant even for a - * fixed-width font. For a Unicode font, the size of this array is 768 KB. - * - * Problems: 1. It eats a lot of memory in each client. 2. All this glyph - * metrics data is piped through the socket when the font is opened. - * - * This extension addresses these two problems for local clients, by using - * shared memory. It also addresses the second problem for non-local clients, - * by compressing the data before transmit by a factor of nearly 6. - * - * If you use this extension, your OS ought to nicely support shared memory. - * This means: Shared memory should be swappable to the swap, and the limits - * should be high enough (SHMMNI at least 64, SHMMAX at least 768 KB, - * SHMALL at least 48 MB). It is a plus if your OS allows shmat() calls - * on segments that have already been marked "removed", because it permits - * these segments to be cleaned up by the OS if the X server is killed with - * signal SIGKILL. - * - * This extension is transparently exploited by Xlib (functions XQueryFont, - * XLoadQueryFont). - */ - -#ifdef HAVE_DIX_CONFIG_H -#include -#endif - -#include -#ifdef HAS_SHM -#if defined(linux) && (!defined(__GNU_LIBRARY__) || __GNU_LIBRARY__ < 2) -/* libc4 does not define __GNU_LIBRARY__, libc5 defines __GNU_LIBRARY__ as 1 */ -/* Linux libc4 and libc5 only (because glibc doesn't include kernel headers): - Linux 2.0.x and 2.2.x define SHMLBA as PAGE_SIZE, but forget to define - PAGE_SIZE. It is defined in . */ -#include -#endif -#ifdef SVR4 -#include -#endif -#if defined(__CYGWIN__) || defined(__SCO__) -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#endif - -#include -#include -#include "misc.h" -#include "os.h" -#include "dixstruct.h" -#include "gcstruct.h" -#include "dixfontstr.h" -#include "extnsionst.h" -#include "protocol-versions.h" - -#include -#include "xf86bigfontsrv.h" - -static void XF86BigfontResetProc( - ExtensionEntry * /* extEntry */ - ); - - -#ifdef HAS_SHM - -/* A random signature, transmitted to the clients so they can verify that the - shared memory segment they are attaching to was really established by the - X server they are talking to. */ -static CARD32 signature; - -/* Index for additional information stored in a FontRec's devPrivates array. */ -static int FontShmdescIndex; - -static unsigned int pagesize; - -static Bool badSysCall = FALSE; - -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__) - -#include - -static void -SigSysHandler( - int signo) -{ - badSysCall = TRUE; -} - -static Bool -CheckForShmSyscall(void) -{ - void (*oldHandler)(int); - int shmid = -1; - - /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */ - oldHandler = signal(SIGSYS, SigSysHandler); - - badSysCall = FALSE; - shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT); - if (shmid != -1) - { - /* Successful allocation - clean up */ - shmctl(shmid, IPC_RMID, NULL); - } - else - { - /* Allocation failed */ - badSysCall = TRUE; - } - signal(SIGSYS, oldHandler); - return !badSysCall; -} - -#define MUST_CHECK_FOR_SHM_SYSCALL - -#endif - -#endif - -void -XFree86BigfontExtensionInit(void) -{ - if (AddExtension(XF86BIGFONTNAME, - XF86BigfontNumberEvents, - XF86BigfontNumberErrors, - ProcXF86BigfontDispatch, - SProcXF86BigfontDispatch, - XF86BigfontResetProc, - StandardMinorOpcode)) { -#ifdef HAS_SHM -#ifdef MUST_CHECK_FOR_SHM_SYSCALL - /* - * Note: Local-clients will not be optimized without shared memory - * support. Remote-client optimization does not depend on shared - * memory support. Thus, the extension is still registered even - * when shared memory support is not functional. - */ - if (!CheckForShmSyscall()) { - ErrorF(XF86BIGFONTNAME " extension local-client optimization disabled due to lack of shared memory support in the kernel\n"); - return; - } -#endif - - srand((unsigned int) time(NULL)); - signature = ((unsigned int) (65536.0/(RAND_MAX+1.0) * rand()) << 16) - + (unsigned int) (65536.0/(RAND_MAX+1.0) * rand()); - /* fprintf(stderr, "signature = 0x%08X\n", signature); */ - - FontShmdescIndex = AllocateFontPrivateIndex(); - -#if !defined(CSRG_BASED) && !defined(__CYGWIN__) - pagesize = SHMLBA; -#else -# ifdef _SC_PAGESIZE - pagesize = sysconf(_SC_PAGESIZE); -# else - pagesize = getpagesize(); -# endif -#endif -#endif - } -} - - -/* ========== Management of shared memory segments ========== */ - -#ifdef HAS_SHM - -#ifdef __linux__ -/* On Linux, shared memory marked as "removed" can still be attached. - Nice feature, because the kernel will automatically free the associated - storage when the server and all clients are gone. */ -#define EARLY_REMOVE -#endif - -typedef struct _ShmDesc { - struct _ShmDesc *next; - struct _ShmDesc **prev; - int shmid; - char *attach_addr; -} ShmDescRec, *ShmDescPtr; - -static ShmDescPtr ShmList = (ShmDescPtr) NULL; - -static ShmDescPtr -shmalloc( - unsigned int size) -{ - ShmDescPtr pDesc; - int shmid; - char *addr; - -#ifdef MUST_CHECK_FOR_SHM_SYSCALL - if (pagesize == 0) - return (ShmDescPtr) NULL; -#endif - - /* On some older Linux systems, the number of shared memory segments - system-wide is 127. In Linux 2.4, it is 4095. - Therefore there is a tradeoff to be made between allocating a - shared memory segment on one hand, and allocating memory and piping - the glyph metrics on the other hand. If the glyph metrics size is - small, we prefer the traditional way. */ - if (size < 3500) - return (ShmDescPtr) NULL; - - pDesc = malloc(sizeof(ShmDescRec)); - if (!pDesc) - return (ShmDescPtr) NULL; - - size = (size + pagesize-1) & -pagesize; - shmid = shmget(IPC_PRIVATE, size, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); - if (shmid == -1) { - ErrorF(XF86BIGFONTNAME " extension: shmget() failed, size = %u, %s\n", - size, strerror(errno)); - free(pDesc); - return (ShmDescPtr) NULL; - } - - if ((addr = shmat(shmid, 0, 0)) == (char *)-1) { - ErrorF(XF86BIGFONTNAME " extension: shmat() failed, size = %u, %s\n", - size, strerror(errno)); - shmctl(shmid, IPC_RMID, (void *) 0); - free(pDesc); - return (ShmDescPtr) NULL; - } - -#ifdef EARLY_REMOVE - shmctl(shmid, IPC_RMID, (void *) 0); -#endif - - pDesc->shmid = shmid; - pDesc->attach_addr = addr; - if (ShmList) ShmList->prev = &pDesc->next; - pDesc->next = ShmList; - pDesc->prev = &ShmList; - ShmList = pDesc; - - return pDesc; -} - -static void -shmdealloc( - ShmDescPtr pDesc) -{ -#ifndef EARLY_REMOVE - shmctl(pDesc->shmid, IPC_RMID, (void *) 0); -#endif - shmdt(pDesc->attach_addr); - - if (pDesc->next) pDesc->next->prev = pDesc->prev; - *pDesc->prev = pDesc->next; - free(pDesc); -} - -#endif - -/* Called when a font is closed. */ -void -XF86BigfontFreeFontShm( - FontPtr pFont) -{ -#ifdef HAS_SHM - ShmDescPtr pDesc; - - /* If during shutdown of the server, XF86BigfontCleanup() has already - * called shmdealloc() for all segments, we don't need to do it here. - */ - if (!ShmList) - return; - - pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex); - if (pDesc) - shmdealloc(pDesc); -#endif -} - -/* Called upon fatal signal. */ -void -XF86BigfontCleanup(void) -{ -#ifdef HAS_SHM - while (ShmList) - shmdealloc(ShmList); -#endif -} - -/* Called when a server generation dies. */ -static void -XF86BigfontResetProc( - ExtensionEntry* extEntry) -{ - /* This function is normally called from CloseDownExtensions(), called - * from main(). It will be followed by a call to FreeAllResources(), - * which will call XF86BigfontFreeFontShm() for each font. Thus it - * appears that we do not need to do anything in this function. -- - * But I prefer to write robust code, and not keep shared memory lying - * around when it's not needed any more. (Someone might close down the - * extension without calling FreeAllResources()...) - */ - XF86BigfontCleanup(); -} - - -/* ========== Handling of extension specific requests ========== */ - -static int -ProcXF86BigfontQueryVersion( - ClientPtr client) -{ - xXF86BigfontQueryVersionReply reply; - - REQUEST_SIZE_MATCH(xXF86BigfontQueryVersionReq); - reply.type = X_Reply; - reply.length = 0; - reply.sequenceNumber = client->sequence; - reply.majorVersion = SERVER_XF86BIGFONT_MAJOR_VERSION; - reply.minorVersion = SERVER_XF86BIGFONT_MINOR_VERSION; - reply.uid = geteuid(); - reply.gid = getegid(); -#ifdef HAS_SHM - reply.signature = signature; -#else - reply.signature = 0; /* This is redundant. Avoids uninitialized memory. */ -#endif - reply.capabilities = -#ifdef HAS_SHM - (LocalClient(client) && !client->swapped ? XF86Bigfont_CAP_LocalShm : 0) -#else - 0 -#endif - ; /* may add more bits here in future versions */ - if (client->swapped) { - char tmp; - swaps(&reply.sequenceNumber, tmp); - swapl(&reply.length, tmp); - swaps(&reply.majorVersion, tmp); - swaps(&reply.minorVersion, tmp); - swapl(&reply.uid, tmp); - swapl(&reply.gid, tmp); - swapl(&reply.signature, tmp); - } - WriteToClient(client, - sizeof(xXF86BigfontQueryVersionReply), (char *)&reply); - return Success; -} - -static void -swapCharInfo( - xCharInfo *pCI) -{ - char tmp; - - swaps(&pCI->leftSideBearing, tmp); - swaps(&pCI->rightSideBearing, tmp); - swaps(&pCI->characterWidth, tmp); - swaps(&pCI->ascent, tmp); - swaps(&pCI->descent, tmp); - swaps(&pCI->attributes, tmp); -} - -/* static CARD32 hashCI (xCharInfo *p); */ -#define hashCI(p) \ - (CARD32)(((p->leftSideBearing << 27) + (p->leftSideBearing >> 5) + \ - (p->rightSideBearing << 23) + (p->rightSideBearing >> 9) + \ - (p->characterWidth << 16) + \ - (p->ascent << 11) + (p->descent << 6)) ^ p->attributes) - -static int -ProcXF86BigfontQueryFont( - ClientPtr client) -{ - FontPtr pFont; - REQUEST(xXF86BigfontQueryFontReq); - CARD32 stuff_flags; - xCharInfo* pmax; - xCharInfo* pmin; - int nCharInfos; - int shmid; -#ifdef HAS_SHM - ShmDescPtr pDesc = NULL; -#else -#define pDesc 0 -#endif - xCharInfo* pCI; - CARD16* pIndex2UniqIndex; - CARD16* pUniqIndex2Index; - CARD32 nUniqCharInfos; - -#if 0 - REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq); -#else - switch (client->req_len) { - case 2: /* client with version 1.0 libX11 */ - stuff_flags = (LocalClient(client) && !client->swapped ? XF86Bigfont_FLAGS_Shm : 0); - break; - case 3: /* client with version 1.1 libX11 */ - stuff_flags = stuff->flags; - break; - default: - return BadLength; - } -#endif - if (dixLookupFontable(&pFont, stuff->id, client, DixGetAttrAccess) != Success) - return BadFont; /* procotol spec says only error is BadFont */ - - pmax = FONTINKMAX(pFont); - pmin = FONTINKMIN(pFont); - nCharInfos = - (pmax->rightSideBearing == pmin->rightSideBearing - && pmax->leftSideBearing == pmin->leftSideBearing - && pmax->descent == pmin->descent - && pmax->ascent == pmin->ascent - && pmax->characterWidth == pmin->characterWidth) - ? 0 : N2dChars(pFont); - shmid = -1; - pCI = NULL; - pIndex2UniqIndex = NULL; - pUniqIndex2Index = NULL; - nUniqCharInfos = 0; - - if (nCharInfos > 0) { -#ifdef HAS_SHM - if (!badSysCall) - pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex); - if (pDesc) { - pCI = (xCharInfo *) pDesc->attach_addr; - if (stuff_flags & XF86Bigfont_FLAGS_Shm) - shmid = pDesc->shmid; - } else { - if (stuff_flags & XF86Bigfont_FLAGS_Shm && !badSysCall) - pDesc = shmalloc(nCharInfos * sizeof(xCharInfo) - + sizeof(CARD32)); - if (pDesc) { - pCI = (xCharInfo *) pDesc->attach_addr; - shmid = pDesc->shmid; - } else { -#endif - pCI = malloc(nCharInfos * sizeof(xCharInfo)); - if (!pCI) - return BadAlloc; -#ifdef HAS_SHM - } -#endif - /* Fill nCharInfos starting at pCI. */ - { - xCharInfo* prCI = pCI; - int ninfos = 0; - int ncols = pFont->info.lastCol - pFont->info.firstCol + 1; - int row; - for (row = pFont->info.firstRow; - row <= pFont->info.lastRow && ninfos < nCharInfos; - row++) { - unsigned char chars[512]; - xCharInfo* tmpCharInfos[256]; - unsigned long count; - int col; - unsigned long i; - i = 0; - for (col = pFont->info.firstCol; - col <= pFont->info.lastCol; - col++) { - chars[i++] = row; - chars[i++] = col; - } - (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit, - &count, tmpCharInfos); - for (i = 0; i < count && ninfos < nCharInfos; i++) { - *prCI++ = *tmpCharInfos[i]; - ninfos++; - } - } - } -#ifdef HAS_SHM - if (pDesc && !badSysCall) { - *(CARD32 *)(pCI + nCharInfos) = signature; - if (!FontSetPrivate(pFont, FontShmdescIndex, pDesc)) { - shmdealloc(pDesc); - return BadAlloc; - } - } - } -#endif - if (shmid == -1) { - /* Cannot use shared memory, so remove-duplicates the xCharInfos - using a temporary hash table. */ - /* Note that CARD16 is suitable as index type, because - nCharInfos <= 0x10000. */ - CARD32 hashModulus; - CARD16* pHash2UniqIndex; - CARD16* pUniqIndex2NextUniqIndex; - CARD32 NextIndex; - CARD32 NextUniqIndex; - CARD16* tmp; - CARD32 i, j; - - hashModulus = 67; - if (hashModulus > nCharInfos+1) - hashModulus = nCharInfos+1; - - tmp = malloc((4*nCharInfos+1) * sizeof(CARD16)); - if (!tmp) { - if (!pDesc) free(pCI); - return BadAlloc; - } - pIndex2UniqIndex = tmp; - /* nCharInfos elements */ - pUniqIndex2Index = tmp + nCharInfos; - /* max. nCharInfos elements */ - pUniqIndex2NextUniqIndex = tmp + 2*nCharInfos; - /* max. nCharInfos elements */ - pHash2UniqIndex = tmp + 3*nCharInfos; - /* hashModulus (<= nCharInfos+1) elements */ - - /* Note that we can use 0xffff as end-of-list indicator, because - even if nCharInfos = 0x10000, 0xffff can not occur as valid - entry before the last element has been inserted. And once the - last element has been inserted, we don't need the hash table - any more. */ - for (j = 0; j < hashModulus; j++) - pHash2UniqIndex[j] = (CARD16)(-1); - - NextUniqIndex = 0; - for (NextIndex = 0; NextIndex < nCharInfos; NextIndex++) { - xCharInfo* p = &pCI[NextIndex]; - CARD32 hashCode = hashCI(p) % hashModulus; - for (i = pHash2UniqIndex[hashCode]; - i != (CARD16)(-1); - i = pUniqIndex2NextUniqIndex[i]) { - j = pUniqIndex2Index[i]; - if (pCI[j].leftSideBearing == p->leftSideBearing - && pCI[j].rightSideBearing == p->rightSideBearing - && pCI[j].characterWidth == p->characterWidth - && pCI[j].ascent == p->ascent - && pCI[j].descent == p->descent - && pCI[j].attributes == p->attributes) - break; - } - if (i != (CARD16)(-1)) { - /* Found *p at Index j, UniqIndex i */ - pIndex2UniqIndex[NextIndex] = i; - } else { - /* Allocate a new entry in the Uniq table */ - if (hashModulus <= 2*NextUniqIndex - && hashModulus < nCharInfos+1) { - /* Time to increate hash table size */ - hashModulus = 2*hashModulus+1; - if (hashModulus > nCharInfos+1) - hashModulus = nCharInfos+1; - for (j = 0; j < hashModulus; j++) - pHash2UniqIndex[j] = (CARD16)(-1); - for (i = 0; i < NextUniqIndex; i++) - pUniqIndex2NextUniqIndex[i] = (CARD16)(-1); - for (i = 0; i < NextUniqIndex; i++) { - j = pUniqIndex2Index[i]; - p = &pCI[j]; - hashCode = hashCI(p) % hashModulus; - pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode]; - pHash2UniqIndex[hashCode] = i; - } - p = &pCI[NextIndex]; - hashCode = hashCI(p) % hashModulus; - } - i = NextUniqIndex++; - pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode]; - pHash2UniqIndex[hashCode] = i; - pUniqIndex2Index[i] = NextIndex; - pIndex2UniqIndex[NextIndex] = i; - } - } - nUniqCharInfos = NextUniqIndex; - /* fprintf(stderr, "font metrics: nCharInfos = %d, nUniqCharInfos = %d, hashModulus = %d\n", nCharInfos, nUniqCharInfos, hashModulus); */ - } - } - - { - int nfontprops = pFont->info.nprops; - int rlength = - sizeof(xXF86BigfontQueryFontReply) - + nfontprops * sizeof(xFontProp) - + (nCharInfos > 0 && shmid == -1 - ? nUniqCharInfos * sizeof(xCharInfo) - + (nCharInfos+1)/2 * 2 * sizeof(CARD16) - : 0); - xXF86BigfontQueryFontReply* reply = malloc(rlength); - char* p; - if (!reply) { - if (nCharInfos > 0) { - if (shmid == -1) free(pIndex2UniqIndex); - if (!pDesc) free(pCI); - } - return BadAlloc; - } - reply->type = X_Reply; - reply->length = bytes_to_int32(rlength - sizeof(xGenericReply)); - reply->sequenceNumber = client->sequence; - reply->minBounds = pFont->info.ink_minbounds; - reply->maxBounds = pFont->info.ink_maxbounds; - reply->minCharOrByte2 = pFont->info.firstCol; - reply->maxCharOrByte2 = pFont->info.lastCol; - reply->defaultChar = pFont->info.defaultCh; - reply->nFontProps = pFont->info.nprops; - reply->drawDirection = pFont->info.drawDirection; - reply->minByte1 = pFont->info.firstRow; - reply->maxByte1 = pFont->info.lastRow; - reply->allCharsExist = pFont->info.allExist; - reply->fontAscent = pFont->info.fontAscent; - reply->fontDescent = pFont->info.fontDescent; - reply->nCharInfos = nCharInfos; - reply->nUniqCharInfos = nUniqCharInfos; - reply->shmid = shmid; - reply->shmsegoffset = 0; - if (client->swapped) { - char tmp; - swaps(&reply->sequenceNumber, tmp); - swapl(&reply->length, tmp); - swapCharInfo(&reply->minBounds); - swapCharInfo(&reply->maxBounds); - swaps(&reply->minCharOrByte2, tmp); - swaps(&reply->maxCharOrByte2, tmp); - swaps(&reply->defaultChar, tmp); - swaps(&reply->nFontProps, tmp); - swaps(&reply->fontAscent, tmp); - swaps(&reply->fontDescent, tmp); - swapl(&reply->nCharInfos, tmp); - swapl(&reply->nUniqCharInfos, tmp); - swapl(&reply->shmid, tmp); - swapl(&reply->shmsegoffset, tmp); - } - p = (char*) &reply[1]; - { - FontPropPtr pFP; - xFontProp* prFP; - int i; - for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) p; - i < nfontprops; - i++, pFP++, prFP++) { - prFP->name = pFP->name; - prFP->value = pFP->value; - if (client->swapped) { - char tmp; - swapl(&prFP->name, tmp); - swapl(&prFP->value, tmp); - } - } - p = (char*) prFP; - } - if (nCharInfos > 0 && shmid == -1) { - xCharInfo* pci; - CARD16* ps; - int i, j; - pci = (xCharInfo*) p; - for (i = 0; i < nUniqCharInfos; i++, pci++) { - *pci = pCI[pUniqIndex2Index[i]]; - if (client->swapped) - swapCharInfo(pci); - } - ps = (CARD16*) pci; - for (j = 0; j < nCharInfos; j++, ps++) { - *ps = pIndex2UniqIndex[j]; - if (client->swapped) { - char tmp; - swaps(ps, tmp); - } - } - } - WriteToClient(client, rlength, (char *)reply); - free(reply); - if (nCharInfos > 0) { - if (shmid == -1) free(pIndex2UniqIndex); - if (!pDesc) free(pCI); - } - return Success; - } -} - -static int -ProcXF86BigfontDispatch( - ClientPtr client) -{ - REQUEST(xReq); - - switch (stuff->data) { - case X_XF86BigfontQueryVersion: - return ProcXF86BigfontQueryVersion(client); - case X_XF86BigfontQueryFont: - return ProcXF86BigfontQueryFont(client); - default: - return BadRequest; - } -} - -static int -SProcXF86BigfontQueryVersion( - ClientPtr client) -{ - REQUEST(xXF86BigfontQueryVersionReq); - char tmp; - - swaps(&stuff->length, tmp); - return ProcXF86BigfontQueryVersion(client); -} - -static int -SProcXF86BigfontQueryFont( - ClientPtr client) -{ - REQUEST(xXF86BigfontQueryFontReq); - char tmp; - - swaps(&stuff->length, tmp); - REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq); - swapl(&stuff->id, tmp); - return ProcXF86BigfontQueryFont(client); -} - -static int -SProcXF86BigfontDispatch( - ClientPtr client) -{ - REQUEST(xReq); - - switch (stuff->data) { - case X_XF86BigfontQueryVersion: - return SProcXF86BigfontQueryVersion(client); - case X_XF86BigfontQueryFont: - return SProcXF86BigfontQueryFont(client); - default: - return BadRequest; - } -} +/* + * BIGFONT extension for sharing font metrics between clients (if possible) + * and for transmitting font metrics to clients in a compressed form. + * + * Copyright (c) 1999-2000 Bruno Haible + * Copyright (c) 1999-2000 The XFree86 Project, Inc. + */ + +/* THIS IS NOT AN X CONSORTIUM STANDARD */ + +/* + * Big fonts suffer from the following: All clients that have opened a + * font can access the complete glyph metrics array (the XFontStruct member + * `per_char') directly, without going through a macro. Moreover these + * glyph metrics are ink metrics, i.e. are not redundant even for a + * fixed-width font. For a Unicode font, the size of this array is 768 KB. + * + * Problems: 1. It eats a lot of memory in each client. 2. All this glyph + * metrics data is piped through the socket when the font is opened. + * + * This extension addresses these two problems for local clients, by using + * shared memory. It also addresses the second problem for non-local clients, + * by compressing the data before transmit by a factor of nearly 6. + * + * If you use this extension, your OS ought to nicely support shared memory. + * This means: Shared memory should be swappable to the swap, and the limits + * should be high enough (SHMMNI at least 64, SHMMAX at least 768 KB, + * SHMALL at least 48 MB). It is a plus if your OS allows shmat() calls + * on segments that have already been marked "removed", because it permits + * these segments to be cleaned up by the OS if the X server is killed with + * signal SIGKILL. + * + * This extension is transparently exploited by Xlib (functions XQueryFont, + * XLoadQueryFont). + */ + +#ifdef HAVE_DIX_CONFIG_H +#include +#endif + +#include +#ifdef HAS_SHM +#if defined(linux) && (!defined(__GNU_LIBRARY__) || __GNU_LIBRARY__ < 2) +/* libc4 does not define __GNU_LIBRARY__, libc5 defines __GNU_LIBRARY__ as 1 */ +/* Linux libc4 and libc5 only (because glibc doesn't include kernel headers): + Linux 2.0.x and 2.2.x define SHMLBA as PAGE_SIZE, but forget to define + PAGE_SIZE. It is defined in . */ +#include +#endif +#ifdef SVR4 +#include +#endif +#if defined(__CYGWIN__) +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "gcstruct.h" +#include "dixfontstr.h" +#include "extnsionst.h" +#include "protocol-versions.h" + +#include +#include "xf86bigfontsrv.h" + +static void XF86BigfontResetProc( + ExtensionEntry * /* extEntry */ + ); + + +#ifdef HAS_SHM + +/* A random signature, transmitted to the clients so they can verify that the + shared memory segment they are attaching to was really established by the + X server they are talking to. */ +static CARD32 signature; + +/* Index for additional information stored in a FontRec's devPrivates array. */ +static int FontShmdescIndex; + +static unsigned int pagesize; + +static Bool badSysCall = FALSE; + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__) + +#include + +static void +SigSysHandler( + int signo) +{ + badSysCall = TRUE; +} + +static Bool +CheckForShmSyscall(void) +{ + void (*oldHandler)(int); + int shmid = -1; + + /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */ + oldHandler = signal(SIGSYS, SigSysHandler); + + badSysCall = FALSE; + shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT); + if (shmid != -1) + { + /* Successful allocation - clean up */ + shmctl(shmid, IPC_RMID, NULL); + } + else + { + /* Allocation failed */ + badSysCall = TRUE; + } + signal(SIGSYS, oldHandler); + return !badSysCall; +} + +#define MUST_CHECK_FOR_SHM_SYSCALL + +#endif + +#endif + +void +XFree86BigfontExtensionInit(void) +{ + if (AddExtension(XF86BIGFONTNAME, + XF86BigfontNumberEvents, + XF86BigfontNumberErrors, + ProcXF86BigfontDispatch, + SProcXF86BigfontDispatch, + XF86BigfontResetProc, + StandardMinorOpcode)) { +#ifdef HAS_SHM +#ifdef MUST_CHECK_FOR_SHM_SYSCALL + /* + * Note: Local-clients will not be optimized without shared memory + * support. Remote-client optimization does not depend on shared + * memory support. Thus, the extension is still registered even + * when shared memory support is not functional. + */ + if (!CheckForShmSyscall()) { + ErrorF(XF86BIGFONTNAME " extension local-client optimization disabled due to lack of shared memory support in the kernel\n"); + return; + } +#endif + + srand((unsigned int) time(NULL)); + signature = ((unsigned int) (65536.0/(RAND_MAX+1.0) * rand()) << 16) + + (unsigned int) (65536.0/(RAND_MAX+1.0) * rand()); + /* fprintf(stderr, "signature = 0x%08X\n", signature); */ + + FontShmdescIndex = AllocateFontPrivateIndex(); + +#if !defined(CSRG_BASED) && !defined(__CYGWIN__) + pagesize = SHMLBA; +#else +# ifdef _SC_PAGESIZE + pagesize = sysconf(_SC_PAGESIZE); +# else + pagesize = getpagesize(); +# endif +#endif +#endif + } +} + + +/* ========== Management of shared memory segments ========== */ + +#ifdef HAS_SHM + +#ifdef __linux__ +/* On Linux, shared memory marked as "removed" can still be attached. + Nice feature, because the kernel will automatically free the associated + storage when the server and all clients are gone. */ +#define EARLY_REMOVE +#endif + +typedef struct _ShmDesc { + struct _ShmDesc *next; + struct _ShmDesc **prev; + int shmid; + char *attach_addr; +} ShmDescRec, *ShmDescPtr; + +static ShmDescPtr ShmList = (ShmDescPtr) NULL; + +static ShmDescPtr +shmalloc( + unsigned int size) +{ + ShmDescPtr pDesc; + int shmid; + char *addr; + +#ifdef MUST_CHECK_FOR_SHM_SYSCALL + if (pagesize == 0) + return (ShmDescPtr) NULL; +#endif + + /* On some older Linux systems, the number of shared memory segments + system-wide is 127. In Linux 2.4, it is 4095. + Therefore there is a tradeoff to be made between allocating a + shared memory segment on one hand, and allocating memory and piping + the glyph metrics on the other hand. If the glyph metrics size is + small, we prefer the traditional way. */ + if (size < 3500) + return (ShmDescPtr) NULL; + + pDesc = malloc(sizeof(ShmDescRec)); + if (!pDesc) + return (ShmDescPtr) NULL; + + size = (size + pagesize-1) & -pagesize; + shmid = shmget(IPC_PRIVATE, size, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); + if (shmid == -1) { + ErrorF(XF86BIGFONTNAME " extension: shmget() failed, size = %u, %s\n", + size, strerror(errno)); + free(pDesc); + return (ShmDescPtr) NULL; + } + + if ((addr = shmat(shmid, 0, 0)) == (char *)-1) { + ErrorF(XF86BIGFONTNAME " extension: shmat() failed, size = %u, %s\n", + size, strerror(errno)); + shmctl(shmid, IPC_RMID, (void *) 0); + free(pDesc); + return (ShmDescPtr) NULL; + } + +#ifdef EARLY_REMOVE + shmctl(shmid, IPC_RMID, (void *) 0); +#endif + + pDesc->shmid = shmid; + pDesc->attach_addr = addr; + if (ShmList) ShmList->prev = &pDesc->next; + pDesc->next = ShmList; + pDesc->prev = &ShmList; + ShmList = pDesc; + + return pDesc; +} + +static void +shmdealloc( + ShmDescPtr pDesc) +{ +#ifndef EARLY_REMOVE + shmctl(pDesc->shmid, IPC_RMID, (void *) 0); +#endif + shmdt(pDesc->attach_addr); + + if (pDesc->next) pDesc->next->prev = pDesc->prev; + *pDesc->prev = pDesc->next; + free(pDesc); +} + +#endif + +/* Called when a font is closed. */ +void +XF86BigfontFreeFontShm( + FontPtr pFont) +{ +#ifdef HAS_SHM + ShmDescPtr pDesc; + + /* If during shutdown of the server, XF86BigfontCleanup() has already + * called shmdealloc() for all segments, we don't need to do it here. + */ + if (!ShmList) + return; + + pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex); + if (pDesc) + shmdealloc(pDesc); +#endif +} + +/* Called upon fatal signal. */ +void +XF86BigfontCleanup(void) +{ +#ifdef HAS_SHM + while (ShmList) + shmdealloc(ShmList); +#endif +} + +/* Called when a server generation dies. */ +static void +XF86BigfontResetProc( + ExtensionEntry* extEntry) +{ + /* This function is normally called from CloseDownExtensions(), called + * from main(). It will be followed by a call to FreeAllResources(), + * which will call XF86BigfontFreeFontShm() for each font. Thus it + * appears that we do not need to do anything in this function. -- + * But I prefer to write robust code, and not keep shared memory lying + * around when it's not needed any more. (Someone might close down the + * extension without calling FreeAllResources()...) + */ + XF86BigfontCleanup(); +} + + +/* ========== Handling of extension specific requests ========== */ + +static int +ProcXF86BigfontQueryVersion( + ClientPtr client) +{ + xXF86BigfontQueryVersionReply reply; + + REQUEST_SIZE_MATCH(xXF86BigfontQueryVersionReq); + reply.type = X_Reply; + reply.length = 0; + reply.sequenceNumber = client->sequence; + reply.majorVersion = SERVER_XF86BIGFONT_MAJOR_VERSION; + reply.minorVersion = SERVER_XF86BIGFONT_MINOR_VERSION; + reply.uid = geteuid(); + reply.gid = getegid(); +#ifdef HAS_SHM + reply.signature = signature; +#else + reply.signature = 0; /* This is redundant. Avoids uninitialized memory. */ +#endif + reply.capabilities = +#ifdef HAS_SHM + (LocalClient(client) && !client->swapped ? XF86Bigfont_CAP_LocalShm : 0) +#else + 0 +#endif + ; /* may add more bits here in future versions */ + if (client->swapped) { + char tmp; + swaps(&reply.sequenceNumber, tmp); + swapl(&reply.length, tmp); + swaps(&reply.majorVersion, tmp); + swaps(&reply.minorVersion, tmp); + swapl(&reply.uid, tmp); + swapl(&reply.gid, tmp); + swapl(&reply.signature, tmp); + } + WriteToClient(client, + sizeof(xXF86BigfontQueryVersionReply), (char *)&reply); + return Success; +} + +static void +swapCharInfo( + xCharInfo *pCI) +{ + char tmp; + + swaps(&pCI->leftSideBearing, tmp); + swaps(&pCI->rightSideBearing, tmp); + swaps(&pCI->characterWidth, tmp); + swaps(&pCI->ascent, tmp); + swaps(&pCI->descent, tmp); + swaps(&pCI->attributes, tmp); +} + +/* static CARD32 hashCI (xCharInfo *p); */ +#define hashCI(p) \ + (CARD32)(((p->leftSideBearing << 27) + (p->leftSideBearing >> 5) + \ + (p->rightSideBearing << 23) + (p->rightSideBearing >> 9) + \ + (p->characterWidth << 16) + \ + (p->ascent << 11) + (p->descent << 6)) ^ p->attributes) + +static int +ProcXF86BigfontQueryFont( + ClientPtr client) +{ + FontPtr pFont; + REQUEST(xXF86BigfontQueryFontReq); + CARD32 stuff_flags; + xCharInfo* pmax; + xCharInfo* pmin; + int nCharInfos; + int shmid; +#ifdef HAS_SHM + ShmDescPtr pDesc = NULL; +#else +#define pDesc 0 +#endif + xCharInfo* pCI; + CARD16* pIndex2UniqIndex; + CARD16* pUniqIndex2Index; + CARD32 nUniqCharInfos; + +#if 0 + REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq); +#else + switch (client->req_len) { + case 2: /* client with version 1.0 libX11 */ + stuff_flags = (LocalClient(client) && !client->swapped ? XF86Bigfont_FLAGS_Shm : 0); + break; + case 3: /* client with version 1.1 libX11 */ + stuff_flags = stuff->flags; + break; + default: + return BadLength; + } +#endif + if (dixLookupFontable(&pFont, stuff->id, client, DixGetAttrAccess) != Success) + return BadFont; /* procotol spec says only error is BadFont */ + + pmax = FONTINKMAX(pFont); + pmin = FONTINKMIN(pFont); + nCharInfos = + (pmax->rightSideBearing == pmin->rightSideBearing + && pmax->leftSideBearing == pmin->leftSideBearing + && pmax->descent == pmin->descent + && pmax->ascent == pmin->ascent + && pmax->characterWidth == pmin->characterWidth) + ? 0 : N2dChars(pFont); + shmid = -1; + pCI = NULL; + pIndex2UniqIndex = NULL; + pUniqIndex2Index = NULL; + nUniqCharInfos = 0; + + if (nCharInfos > 0) { +#ifdef HAS_SHM + if (!badSysCall) + pDesc = (ShmDescPtr) FontGetPrivate(pFont, FontShmdescIndex); + if (pDesc) { + pCI = (xCharInfo *) pDesc->attach_addr; + if (stuff_flags & XF86Bigfont_FLAGS_Shm) + shmid = pDesc->shmid; + } else { + if (stuff_flags & XF86Bigfont_FLAGS_Shm && !badSysCall) + pDesc = shmalloc(nCharInfos * sizeof(xCharInfo) + + sizeof(CARD32)); + if (pDesc) { + pCI = (xCharInfo *) pDesc->attach_addr; + shmid = pDesc->shmid; + } else { +#endif + pCI = malloc(nCharInfos * sizeof(xCharInfo)); + if (!pCI) + return BadAlloc; +#ifdef HAS_SHM + } +#endif + /* Fill nCharInfos starting at pCI. */ + { + xCharInfo* prCI = pCI; + int ninfos = 0; + int ncols = pFont->info.lastCol - pFont->info.firstCol + 1; + int row; + for (row = pFont->info.firstRow; + row <= pFont->info.lastRow && ninfos < nCharInfos; + row++) { + unsigned char chars[512]; + xCharInfo* tmpCharInfos[256]; + unsigned long count; + int col; + unsigned long i; + i = 0; + for (col = pFont->info.firstCol; + col <= pFont->info.lastCol; + col++) { + chars[i++] = row; + chars[i++] = col; + } + (*pFont->get_metrics) (pFont, ncols, chars, TwoD16Bit, + &count, tmpCharInfos); + for (i = 0; i < count && ninfos < nCharInfos; i++) { + *prCI++ = *tmpCharInfos[i]; + ninfos++; + } + } + } +#ifdef HAS_SHM + if (pDesc && !badSysCall) { + *(CARD32 *)(pCI + nCharInfos) = signature; + if (!FontSetPrivate(pFont, FontShmdescIndex, pDesc)) { + shmdealloc(pDesc); + return BadAlloc; + } + } + } +#endif + if (shmid == -1) { + /* Cannot use shared memory, so remove-duplicates the xCharInfos + using a temporary hash table. */ + /* Note that CARD16 is suitable as index type, because + nCharInfos <= 0x10000. */ + CARD32 hashModulus; + CARD16* pHash2UniqIndex; + CARD16* pUniqIndex2NextUniqIndex; + CARD32 NextIndex; + CARD32 NextUniqIndex; + CARD16* tmp; + CARD32 i, j; + + hashModulus = 67; + if (hashModulus > nCharInfos+1) + hashModulus = nCharInfos+1; + + tmp = malloc((4*nCharInfos+1) * sizeof(CARD16)); + if (!tmp) { + if (!pDesc) free(pCI); + return BadAlloc; + } + pIndex2UniqIndex = tmp; + /* nCharInfos elements */ + pUniqIndex2Index = tmp + nCharInfos; + /* max. nCharInfos elements */ + pUniqIndex2NextUniqIndex = tmp + 2*nCharInfos; + /* max. nCharInfos elements */ + pHash2UniqIndex = tmp + 3*nCharInfos; + /* hashModulus (<= nCharInfos+1) elements */ + + /* Note that we can use 0xffff as end-of-list indicator, because + even if nCharInfos = 0x10000, 0xffff can not occur as valid + entry before the last element has been inserted. And once the + last element has been inserted, we don't need the hash table + any more. */ + for (j = 0; j < hashModulus; j++) + pHash2UniqIndex[j] = (CARD16)(-1); + + NextUniqIndex = 0; + for (NextIndex = 0; NextIndex < nCharInfos; NextIndex++) { + xCharInfo* p = &pCI[NextIndex]; + CARD32 hashCode = hashCI(p) % hashModulus; + for (i = pHash2UniqIndex[hashCode]; + i != (CARD16)(-1); + i = pUniqIndex2NextUniqIndex[i]) { + j = pUniqIndex2Index[i]; + if (pCI[j].leftSideBearing == p->leftSideBearing + && pCI[j].rightSideBearing == p->rightSideBearing + && pCI[j].characterWidth == p->characterWidth + && pCI[j].ascent == p->ascent + && pCI[j].descent == p->descent + && pCI[j].attributes == p->attributes) + break; + } + if (i != (CARD16)(-1)) { + /* Found *p at Index j, UniqIndex i */ + pIndex2UniqIndex[NextIndex] = i; + } else { + /* Allocate a new entry in the Uniq table */ + if (hashModulus <= 2*NextUniqIndex + && hashModulus < nCharInfos+1) { + /* Time to increate hash table size */ + hashModulus = 2*hashModulus+1; + if (hashModulus > nCharInfos+1) + hashModulus = nCharInfos+1; + for (j = 0; j < hashModulus; j++) + pHash2UniqIndex[j] = (CARD16)(-1); + for (i = 0; i < NextUniqIndex; i++) + pUniqIndex2NextUniqIndex[i] = (CARD16)(-1); + for (i = 0; i < NextUniqIndex; i++) { + j = pUniqIndex2Index[i]; + p = &pCI[j]; + hashCode = hashCI(p) % hashModulus; + pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode]; + pHash2UniqIndex[hashCode] = i; + } + p = &pCI[NextIndex]; + hashCode = hashCI(p) % hashModulus; + } + i = NextUniqIndex++; + pUniqIndex2NextUniqIndex[i] = pHash2UniqIndex[hashCode]; + pHash2UniqIndex[hashCode] = i; + pUniqIndex2Index[i] = NextIndex; + pIndex2UniqIndex[NextIndex] = i; + } + } + nUniqCharInfos = NextUniqIndex; + /* fprintf(stderr, "font metrics: nCharInfos = %d, nUniqCharInfos = %d, hashModulus = %d\n", nCharInfos, nUniqCharInfos, hashModulus); */ + } + } + + { + int nfontprops = pFont->info.nprops; + int rlength = + sizeof(xXF86BigfontQueryFontReply) + + nfontprops * sizeof(xFontProp) + + (nCharInfos > 0 && shmid == -1 + ? nUniqCharInfos * sizeof(xCharInfo) + + (nCharInfos+1)/2 * 2 * sizeof(CARD16) + : 0); + xXF86BigfontQueryFontReply* reply = malloc(rlength); + char* p; + if (!reply) { + if (nCharInfos > 0) { + if (shmid == -1) free(pIndex2UniqIndex); + if (!pDesc) free(pCI); + } + return BadAlloc; + } + reply->type = X_Reply; + reply->length = bytes_to_int32(rlength - sizeof(xGenericReply)); + reply->sequenceNumber = client->sequence; + reply->minBounds = pFont->info.ink_minbounds; + reply->maxBounds = pFont->info.ink_maxbounds; + reply->minCharOrByte2 = pFont->info.firstCol; + reply->maxCharOrByte2 = pFont->info.lastCol; + reply->defaultChar = pFont->info.defaultCh; + reply->nFontProps = pFont->info.nprops; + reply->drawDirection = pFont->info.drawDirection; + reply->minByte1 = pFont->info.firstRow; + reply->maxByte1 = pFont->info.lastRow; + reply->allCharsExist = pFont->info.allExist; + reply->fontAscent = pFont->info.fontAscent; + reply->fontDescent = pFont->info.fontDescent; + reply->nCharInfos = nCharInfos; + reply->nUniqCharInfos = nUniqCharInfos; + reply->shmid = shmid; + reply->shmsegoffset = 0; + if (client->swapped) { + char tmp; + swaps(&reply->sequenceNumber, tmp); + swapl(&reply->length, tmp); + swapCharInfo(&reply->minBounds); + swapCharInfo(&reply->maxBounds); + swaps(&reply->minCharOrByte2, tmp); + swaps(&reply->maxCharOrByte2, tmp); + swaps(&reply->defaultChar, tmp); + swaps(&reply->nFontProps, tmp); + swaps(&reply->fontAscent, tmp); + swaps(&reply->fontDescent, tmp); + swapl(&reply->nCharInfos, tmp); + swapl(&reply->nUniqCharInfos, tmp); + swapl(&reply->shmid, tmp); + swapl(&reply->shmsegoffset, tmp); + } + p = (char*) &reply[1]; + { + FontPropPtr pFP; + xFontProp* prFP; + int i; + for (i = 0, pFP = pFont->info.props, prFP = (xFontProp *) p; + i < nfontprops; + i++, pFP++, prFP++) { + prFP->name = pFP->name; + prFP->value = pFP->value; + if (client->swapped) { + char tmp; + swapl(&prFP->name, tmp); + swapl(&prFP->value, tmp); + } + } + p = (char*) prFP; + } + if (nCharInfos > 0 && shmid == -1) { + xCharInfo* pci; + CARD16* ps; + int i, j; + pci = (xCharInfo*) p; + for (i = 0; i < nUniqCharInfos; i++, pci++) { + *pci = pCI[pUniqIndex2Index[i]]; + if (client->swapped) + swapCharInfo(pci); + } + ps = (CARD16*) pci; + for (j = 0; j < nCharInfos; j++, ps++) { + *ps = pIndex2UniqIndex[j]; + if (client->swapped) { + char tmp; + swaps(ps, tmp); + } + } + } + WriteToClient(client, rlength, (char *)reply); + free(reply); + if (nCharInfos > 0) { + if (shmid == -1) free(pIndex2UniqIndex); + if (!pDesc) free(pCI); + } + return Success; + } +} + +static int +ProcXF86BigfontDispatch( + ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_XF86BigfontQueryVersion: + return ProcXF86BigfontQueryVersion(client); + case X_XF86BigfontQueryFont: + return ProcXF86BigfontQueryFont(client); + default: + return BadRequest; + } +} + +static int +SProcXF86BigfontQueryVersion( + ClientPtr client) +{ + REQUEST(xXF86BigfontQueryVersionReq); + char tmp; + + swaps(&stuff->length, tmp); + return ProcXF86BigfontQueryVersion(client); +} + +static int +SProcXF86BigfontQueryFont( + ClientPtr client) +{ + REQUEST(xXF86BigfontQueryFontReq); + char tmp; + + swaps(&stuff->length, tmp); + REQUEST_SIZE_MATCH(xXF86BigfontQueryFontReq); + swapl(&stuff->id, tmp); + return ProcXF86BigfontQueryFont(client); +} + +static int +SProcXF86BigfontDispatch( + ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_XF86BigfontQueryVersion: + return SProcXF86BigfontQueryVersion(client); + case X_XF86BigfontQueryFont: + return SProcXF86BigfontQueryFont(client); + default: + return BadRequest; + } +} -- cgit v1.2.3