751 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			751 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * 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 <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#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 <asm/page.h>. */
 | 
						|
#include <asm/page.h>
 | 
						|
#endif
 | 
						|
#ifdef SVR4
 | 
						|
#include <sys/sysmacros.h>
 | 
						|
#endif
 | 
						|
#if defined(__CYGWIN__) 
 | 
						|
#include <sys/param.h>
 | 
						|
#include <sys/sysmacros.h>
 | 
						|
#endif
 | 
						|
#include <sys/ipc.h>
 | 
						|
#include <sys/shm.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <time.h>
 | 
						|
#include <errno.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <X11/X.h>
 | 
						|
#include <X11/Xproto.h>
 | 
						|
#include "misc.h"
 | 
						|
#include "os.h"
 | 
						|
#include "dixstruct.h"
 | 
						|
#include "gcstruct.h"
 | 
						|
#include "dixfontstr.h"
 | 
						|
#include "extnsionst.h"
 | 
						|
#include "protocol-versions.h"
 | 
						|
 | 
						|
#include <X11/extensions/xf86bigfproto.h>
 | 
						|
#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 <sys/signal.h>
 | 
						|
 | 
						|
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
 | 
						|
 | 
						|
/* ========== 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;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
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
 | 
						|
    }
 | 
						|
}
 |