Edit

IABSD.fr/xenocara/xserver/render/glyph.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2010-07-27 19:02:24
    Hash : 95d684a0
    Message : Update to xserver 1.8. Tested by many. Ok oga@, todd@.

  • xserver/render/glyph.c
  • /*
     *
     * Copyright © 2000 SuSE, Inc.
     *
     * Permission to use, copy, modify, distribute, and sell this software and its
     * documentation for any purpose is hereby granted without fee, provided that
     * the above copyright notice appear in all copies and that both that
     * copyright notice and this permission notice appear in supporting
     * documentation, and that the name of SuSE not be used in advertising or
     * publicity pertaining to distribution of the software without specific,
     * written prior permission.  SuSE makes no representations about the
     * suitability of this software for any purpose.  It is provided "as is"
     * without express or implied warranty.
     *
     * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
     * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
     * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     *
     * Author:  Keith Packard, SuSE, Inc.
     */
    
    #ifdef HAVE_DIX_CONFIG_H
    #include <dix-config.h>
    #endif
    
    #include "xsha1.h"
    
    #include "misc.h"
    #include "scrnintstr.h"
    #include "os.h"
    #include "regionstr.h"
    #include "validate.h"
    #include "windowstr.h"
    #include "input.h"
    #include "resource.h"
    #include "colormapst.h"
    #include "cursorstr.h"
    #include "dixstruct.h"
    #include "gcstruct.h"
    #include "servermd.h"
    #include "picturestr.h"
    #include "glyphstr.h"
    #include "mipict.h"
    
    /*
     * From Knuth -- a good choice for hash/rehash values is p, p-2 where
     * p and p-2 are both prime.  These tables are sized to have an extra 10%
     * free to avoid exponential performance degradation as the hash table fills
     */
    static GlyphHashSetRec glyphHashSets[] = {
        { 32,		43,		41        },
        { 64,		73,		71        },
        { 128,		151,		149       },
        { 256,		283,		281       },
        { 512,		571,		569       },
        { 1024,		1153,		1151      },
        { 2048,		2269,		2267      },
        { 4096,		4519,		4517      },
        { 8192,		9013,		9011      },
        { 16384,		18043,		18041     },
        { 32768,		36109,		36107     },
        { 65536,		72091,		72089     },
        { 131072,		144409,		144407    },
        { 262144,		288361,		288359    },
        { 524288,		576883,		576881    },
        { 1048576,		1153459,	1153457   },
        { 2097152,		2307163,	2307161   },
        { 4194304,		4613893,	4613891   },
        { 8388608,		9227641,	9227639   },
        { 16777216,		18455029,	18455027  },
        { 33554432,		36911011,	36911009  },
        { 67108864,		73819861,	73819859  },
        { 134217728,	147639589,	147639587 },
        { 268435456,	295279081,	295279079 },
        { 536870912,	590559793,	590559791 }
    };
    
    #define NGLYPHHASHSETS	(sizeof(glyphHashSets)/sizeof(glyphHashSets[0]))
    
    static const CARD8	glyphDepths[GlyphFormatNum] = { 1, 4, 8, 16, 32 };
    
    static GlyphHashRec	globalGlyphs[GlyphFormatNum];
    
    static void
    FreeGlyphPrivates (GlyphPtr glyph)
    {
        dixFreePrivates(glyph->devPrivates);
        glyph->devPrivates = NULL;
    }
    
    void
    GlyphUninit (ScreenPtr pScreen)
    {
        PictureScreenPtr ps = GetPictureScreen (pScreen);
        GlyphPtr	     glyph;
        int		     fdepth, i;
    
        for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++)
        {
    	if (!globalGlyphs[fdepth].hashSet)
    	    continue;
    	
    	for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++)
    	{
    	    glyph = globalGlyphs[fdepth].table[i].glyph;
    	    if (glyph && glyph != DeletedGlyph)
    	    {
    		(*ps->UnrealizeGlyph) (pScreen, glyph);
    		FreeGlyphPrivates(glyph);
    	    }
    	}
        }
    
        for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++)
        {
    	if (!globalGlyphs[fdepth].hashSet)
    	    continue;
    	
    	for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++)
    	    glyph = globalGlyphs[fdepth].table[i].glyph;    
        }
    }
    
    GlyphHashSetPtr
    FindGlyphHashSet (CARD32 filled)
    {
        int	i;
    
        for (i = 0; i < NGLYPHHASHSETS; i++)
    	if (glyphHashSets[i].entries >= filled)
    	    return &glyphHashSets[i];
        return 0;
    }
    
    GlyphRefPtr
    FindGlyphRef (GlyphHashPtr	hash,
    	      CARD32		signature,
    	      Bool		match,
    	      unsigned char	sha1[20])
    {
        CARD32	elt, step, s;
        GlyphPtr	glyph;
        GlyphRefPtr	table, gr, del;
        CARD32	tableSize = hash->hashSet->size;
    
        table = hash->table;
        elt = signature % tableSize;
        step = 0;
        del = 0;
        for (;;)
        {
    	gr = &table[elt];
    	s = gr->signature;
    	glyph = gr->glyph;
    	if (!glyph)
    	{
    	    if (del)
    		gr = del;
    	    break;
    	}
    	if (glyph == DeletedGlyph)
    	{
    	    if (!del)
    		del = gr;
    	    else if (gr == del)
    		break;
    	}
    	else if (s == signature &&
    		 (!match || 
    		  memcmp (glyph->sha1, sha1, 20) == 0))
    	{
    	    break;
    	}
    	if (!step)
    	{
    	    step = signature % hash->hashSet->rehash;
    	    if (!step)
    		step = 1;
    	}
    	elt += step;
    	if (elt >= tableSize)
    	    elt -= tableSize;
        }
        return gr;
    }
    
    int
    HashGlyph (xGlyphInfo    *gi,
    	   CARD8	 *bits,
    	   unsigned long size,
    	   unsigned char sha1[20])
    {
        void *ctx = x_sha1_init();
        int success;
    
        if (!ctx)
    	return BadAlloc;
    
        success = x_sha1_update(ctx, gi, sizeof(xGlyphInfo));
        if (!success)
    	return BadAlloc;
        success = x_sha1_update(ctx, bits, size);
        if (!success)
    	return BadAlloc;
        success = x_sha1_final(ctx, sha1);
        if (!success)
    	return BadAlloc;
        return Success;
    }
    
    GlyphPtr
    FindGlyphByHash (unsigned char sha1[20], int format)
    {
        GlyphRefPtr gr;
        CARD32 signature = *(CARD32 *) sha1;
    
        if (!globalGlyphs[format].hashSet)
    	return NULL;
    
        gr = FindGlyphRef (&globalGlyphs[format],
    		       signature, TRUE, sha1);
    
        if (gr->glyph && gr->glyph != DeletedGlyph)
    	return gr->glyph;
        else
    	return NULL;
    }
    
    #ifdef CHECK_DUPLICATES
    void
    DuplicateRef (GlyphPtr glyph, char *where)
    {
        ErrorF ("Duplicate Glyph 0x%x from %s\n", glyph, where);
    }
    
    void
    CheckDuplicates (GlyphHashPtr hash, char *where)
    {
        GlyphPtr	g;
        int		i, j;
    
        for (i = 0; i < hash->hashSet->size; i++)
        {
    	g = hash->table[i].glyph;
    	if (!g || g == DeletedGlyph)
    	    continue;
    	for (j = i + 1; j < hash->hashSet->size; j++)
    	    if (hash->table[j].glyph == g)
    		DuplicateRef (g, where);
        }
    }
    #else
    #define CheckDuplicates(a,b)
    #define DuplicateRef(a,b)
    #endif
    
    static void
    FreeGlyphPicture(GlyphPtr glyph)
    {
        PictureScreenPtr ps;
        int i;
    
        for (i = 0; i < screenInfo.numScreens; i++)
        {
            ScreenPtr pScreen = screenInfo.screens[i];
    
            if (GlyphPicture(glyph)[i])
                FreePicture ((pointer) GlyphPicture (glyph)[i], 0);
    
            ps = GetPictureScreenIfSet (pScreen);
            if (ps)
                (*ps->UnrealizeGlyph) (pScreen, glyph);
        }
    }
    
    
    void
    FreeGlyph (GlyphPtr glyph, int format)
    {
        CheckDuplicates (&globalGlyphs[format], "FreeGlyph");
        if (--glyph->refcnt == 0)
        {
    	GlyphRefPtr      gr;
    	int	         i;
    	int	         first;
    	CARD32		 signature;
    
    	first = -1;
    	for (i = 0; i < globalGlyphs[format].hashSet->size; i++)
    	    if (globalGlyphs[format].table[i].glyph == glyph)
    	    {
    		if (first != -1)
    		    DuplicateRef (glyph, "FreeGlyph check");
    		first = i;
    	    }
    
    	signature = *(CARD32 *) glyph->sha1;
    	gr = FindGlyphRef (&globalGlyphs[format], signature,
    			   TRUE, glyph->sha1);
    	if (gr - globalGlyphs[format].table != first)
    	    DuplicateRef (glyph, "Found wrong one");
    	if (gr->glyph && gr->glyph != DeletedGlyph)
    	{
    	    gr->glyph = DeletedGlyph;
    	    gr->signature = 0;
    	    globalGlyphs[format].tableEntries--;
    	}
    
    	FreeGlyphPicture(glyph);
    	FreeGlyphPrivates(glyph);
    	xfree (glyph);
        }
    }
    
    void
    AddGlyph (GlyphSetPtr glyphSet, GlyphPtr glyph, Glyph id)
    {
        GlyphRefPtr	    gr;
        CARD32	    signature;
    
        CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph top global");
        /* Locate existing matching glyph */
        signature = *(CARD32 *) glyph->sha1;
        gr = FindGlyphRef (&globalGlyphs[glyphSet->fdepth], signature,
    		       TRUE, glyph->sha1);
        if (gr->glyph && gr->glyph != DeletedGlyph && gr->glyph != glyph)
        {
    	FreeGlyphPicture(glyph);
    	FreeGlyphPrivates(glyph);
    	xfree (glyph);
    	glyph = gr->glyph;
        }
        else if (gr->glyph != glyph)
        {
    	gr->glyph = glyph;
    	gr->signature = signature;
    	globalGlyphs[glyphSet->fdepth].tableEntries++;
        }
        
        /* Insert/replace glyphset value */
        gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0);
        ++glyph->refcnt;
        if (gr->glyph && gr->glyph != DeletedGlyph)
    	FreeGlyph (gr->glyph, glyphSet->fdepth);
        else
    	glyphSet->hash.tableEntries++;
        gr->glyph = glyph;
        gr->signature = id;
        CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph bottom");
    }
    
    Bool
    DeleteGlyph (GlyphSetPtr glyphSet, Glyph id)
    {
        GlyphRefPtr     gr;
        GlyphPtr	    glyph;
    
        gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0);
        glyph = gr->glyph;
        if (glyph && glyph != DeletedGlyph)
        {
    	gr->glyph = DeletedGlyph;
    	glyphSet->hash.tableEntries--;
    	FreeGlyph (glyph, glyphSet->fdepth);
    	return TRUE;
        }
        return FALSE;
    }
    
    GlyphPtr
    FindGlyph (GlyphSetPtr glyphSet, Glyph id)
    {
        GlyphPtr        glyph;
    
        glyph = FindGlyphRef (&glyphSet->hash, id, FALSE, 0)->glyph;
        if (glyph == DeletedGlyph)
    	glyph = 0;
        return glyph;
    }
    
    GlyphPtr
    AllocateGlyph (xGlyphInfo *gi, int fdepth)
    {
        PictureScreenPtr ps;
        int		     size;
        GlyphPtr	     glyph;
        int		     i;
    
        size = screenInfo.numScreens * sizeof (PicturePtr);
        glyph = (GlyphPtr) xalloc (size + sizeof (GlyphRec));
        if (!glyph)
    	return 0;
        glyph->refcnt = 0;
        glyph->size = size + sizeof (xGlyphInfo);
        glyph->info = *gi;
        glyph->devPrivates = NULL;
    
        for (i = 0; i < screenInfo.numScreens; i++)
        {
    	GlyphPicture(glyph)[i] = NULL;
    	ps = GetPictureScreenIfSet (screenInfo.screens[i]);
    
    	if (ps)
    	{
    	    if (!(*ps->RealizeGlyph) (screenInfo.screens[i], glyph))
    		goto bail;
    	}
        }
        
        return glyph;
    
    bail:
        while (i--)
        {
    	ps = GetPictureScreenIfSet (screenInfo.screens[i]);
    	if (ps)
    	    (*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph);
        }
    
        FreeGlyphPrivates(glyph);
        xfree (glyph);
        return 0;
    }
        
    Bool
    AllocateGlyphHash (GlyphHashPtr hash, GlyphHashSetPtr hashSet)
    {
        hash->table = xcalloc (hashSet->size, sizeof (GlyphRefRec));
        if (!hash->table)
    	return FALSE;
        hash->hashSet = hashSet;
        hash->tableEntries = 0;
        return TRUE;
    }
    
    Bool
    ResizeGlyphHash (GlyphHashPtr hash, CARD32 change, Bool global)
    {
        CARD32	    tableEntries;
        GlyphHashSetPtr hashSet;
        GlyphHashRec    newHash;
        GlyphRefPtr	    gr;
        GlyphPtr	    glyph;
        int		    i;
        int		    oldSize;
        CARD32	    s;
    
        tableEntries = hash->tableEntries + change;
        hashSet = FindGlyphHashSet (tableEntries);
        if (hashSet == hash->hashSet)
    	return TRUE;
        if (global)
    	CheckDuplicates (hash, "ResizeGlyphHash top");
        if (!AllocateGlyphHash (&newHash, hashSet))
    	return FALSE;
        if (hash->table)
        {
    	oldSize = hash->hashSet->size;
    	for (i = 0; i < oldSize; i++)
    	{
    	    glyph = hash->table[i].glyph;
    	    if (glyph && glyph != DeletedGlyph)
    	    {
    		s = hash->table[i].signature;
    		gr = FindGlyphRef (&newHash, s, global, glyph->sha1);
    		gr->signature = s;
    		gr->glyph = glyph;
    		++newHash.tableEntries;
    	    }
    	}
    	xfree (hash->table);
        }
        *hash = newHash;
        if (global)
    	CheckDuplicates (hash, "ResizeGlyphHash bottom");
        return TRUE;
    }
    
    Bool
    ResizeGlyphSet (GlyphSetPtr glyphSet, CARD32 change)
    {
        return (ResizeGlyphHash (&glyphSet->hash, change, FALSE) &&
    	    ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], change, TRUE));
    }
    			    
    GlyphSetPtr
    AllocateGlyphSet (int fdepth, PictFormatPtr format)
    {
        GlyphSetPtr	glyphSet;
        int size;
        
        if (!globalGlyphs[fdepth].hashSet)
        {
    	if (!AllocateGlyphHash (&globalGlyphs[fdepth], &glyphHashSets[0]))
    	    return FALSE;
        }
    
        size = sizeof (GlyphSetRec);
        glyphSet = xcalloc (1, size);
        if (!glyphSet)
    	return FALSE;
    
        if (!AllocateGlyphHash (&glyphSet->hash, &glyphHashSets[0]))
        {
    	xfree (glyphSet);
    	return FALSE;
        }
        glyphSet->refcnt = 1;
        glyphSet->fdepth = fdepth;
        glyphSet->format = format;
        return glyphSet;	
    }
    
    int
    FreeGlyphSet (pointer	value,
    	      XID       gid)
    {
        GlyphSetPtr	glyphSet = (GlyphSetPtr) value;
        
        if (--glyphSet->refcnt == 0)
        {
    	CARD32	    i, tableSize = glyphSet->hash.hashSet->size;
    	GlyphRefPtr table = glyphSet->hash.table;
    	GlyphPtr    glyph;
        
    	for (i = 0; i < tableSize; i++)
    	{
    	    glyph = table[i].glyph;
    	    if (glyph && glyph != DeletedGlyph)
    		FreeGlyph (glyph, glyphSet->fdepth);
    	}
    	if (!globalGlyphs[glyphSet->fdepth].tableEntries)
    	{
    	    xfree (globalGlyphs[glyphSet->fdepth].table);
    	    globalGlyphs[glyphSet->fdepth].table = 0;
    	    globalGlyphs[glyphSet->fdepth].hashSet = 0;
    	}
    	else
    	    ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], 0, TRUE);
    	xfree (table);
    	dixFreePrivates(glyphSet->devPrivates);
    	xfree (glyphSet);
        }
        return Success;
    }
    
    static void
    GlyphExtents (int		nlist,
    		GlyphListPtr	list,
    		GlyphPtr	*glyphs,
    		BoxPtr		extents)
    {
        int		x1, x2, y1, y2;
        int		n;
        GlyphPtr	glyph;
        int		x, y;
        
        x = 0;
        y = 0;
        extents->x1 = MAXSHORT;
        extents->x2 = MINSHORT;
        extents->y1 = MAXSHORT;
        extents->y2 = MINSHORT;
        while (nlist--)
        {
    	x += list->xOff;
    	y += list->yOff;
    	n = list->len;
    	list++;
    	while (n--)
    	{
    	    glyph = *glyphs++;
    	    x1 = x - glyph->info.x;
    	    if (x1 < MINSHORT)
    		x1 = MINSHORT;
    	    y1 = y - glyph->info.y;
    	    if (y1 < MINSHORT)
    		y1 = MINSHORT;
    	    x2 = x1 + glyph->info.width;
    	    if (x2 > MAXSHORT)
    		x2 = MAXSHORT;
    	    y2 = y1 + glyph->info.height;
    	    if (y2 > MAXSHORT)
    		y2 = MAXSHORT;
    	    if (x1 < extents->x1)
    		extents->x1 = x1;
    	    if (x2 > extents->x2)
    		extents->x2 = x2;
    	    if (y1 < extents->y1)
    		extents->y1 = y1;
    	    if (y2 > extents->y2)
    		extents->y2 = y2;
    	    x += glyph->info.xOff;
    	    y += glyph->info.yOff;
    	}
        }
    }
    
    #define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
    
    void
    CompositeGlyphs (CARD8		op,
    		 PicturePtr	pSrc,
    		 PicturePtr	pDst,
    		 PictFormatPtr	maskFormat,
    		 INT16		xSrc,
    		 INT16		ySrc,
    		 int		nlist,
    		 GlyphListPtr	lists,
    		 GlyphPtr	*glyphs)
    {
        PictureScreenPtr	ps = GetPictureScreen(pDst->pDrawable->pScreen);
    
        ValidatePicture (pSrc);
        ValidatePicture (pDst);
        (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, lists, glyphs);
    }
    
    Bool
    miRealizeGlyph (ScreenPtr pScreen,
    		GlyphPtr  glyph)
    {
        return TRUE;
    }
    
    void
    miUnrealizeGlyph (ScreenPtr pScreen,
    		  GlyphPtr  glyph)
    {
    }
    
    void
    miGlyphs (CARD8		op,
    	  PicturePtr	pSrc,
    	  PicturePtr	pDst,
    	  PictFormatPtr	maskFormat,
    	  INT16		xSrc,
    	  INT16		ySrc,
    	  int		nlist,
    	  GlyphListPtr	list,
    	  GlyphPtr	*glyphs)
    {
        PicturePtr	pPicture;
        PixmapPtr   pMaskPixmap = 0;
        PicturePtr  pMask;
        ScreenPtr   pScreen = pDst->pDrawable->pScreen;
        int		width = 0, height = 0;
        int		x, y;
        int		xDst = list->xOff, yDst = list->yOff;
        int		n;
        GlyphPtr	glyph;
        int		error;
        BoxRec	extents = {0, 0, 0, 0};
        CARD32	component_alpha;
    
        if (maskFormat)
        {
    	GCPtr	    pGC;
    	xRectangle  rect;
    
    	GlyphExtents (nlist, list, glyphs, &extents);
    
    	if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
    	    return;
    	width = extents.x2 - extents.x1;
    	height = extents.y2 - extents.y1;
    	pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
    						maskFormat->depth,
    						CREATE_PIXMAP_USAGE_SCRATCH);
    	if (!pMaskPixmap)
    	    return;
    	component_alpha = NeedsComponent(maskFormat->format);
    	pMask = CreatePicture (0, &pMaskPixmap->drawable,
    			       maskFormat, CPComponentAlpha, &component_alpha,
    			       serverClient, &error);
    	if (!pMask)
    	{
    	    (*pScreen->DestroyPixmap) (pMaskPixmap);
    	    return;
    	}
    	pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
    	ValidateGC (&pMaskPixmap->drawable, pGC);
    	rect.x = 0;
    	rect.y = 0;
    	rect.width = width;
    	rect.height = height;
    	(*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
    	FreeScratchGC (pGC);
    	x = -extents.x1;
    	y = -extents.y1;
        }
        else
        {
    	pMask = pDst;
    	x = 0;
    	y = 0;
        }
        while (nlist--)
        {
    	x += list->xOff;
    	y += list->yOff;
    	n = list->len;
    	while (n--)
    	{
    	    glyph = *glyphs++;
    	    pPicture = GlyphPicture (glyph)[pScreen->myNum];
    
    	    if (pPicture)
    	    {
    		if (maskFormat)
    		{
    			CompositePicture (PictOpAdd,
    					  pPicture,
    					  None,
    					  pMask,
    					  0, 0,
    					  0, 0,
    					  x - glyph->info.x,
    					  y - glyph->info.y,
    					  glyph->info.width,
    					  glyph->info.height);
    		}
    		else
    		{
    		    CompositePicture (op,
    				      pSrc,
    				      pPicture,
    				      pDst,
    				      xSrc + (x - glyph->info.x) - xDst,
    				      ySrc + (y - glyph->info.y) - yDst,
    				      0, 0,
    				      x - glyph->info.x,
    				      y - glyph->info.y,
    				      glyph->info.width,
    				      glyph->info.height);
    		}
    	    }
    
    	    x += glyph->info.xOff;
    	    y += glyph->info.yOff;
    	}
    	list++;
        }
        if (maskFormat)
        {
    	x = extents.x1;
    	y = extents.y1;
    	CompositePicture (op,
    			  pSrc,
    			  pMask,
    			  pDst,
    			  xSrc + x - xDst,
    			  ySrc + y - yDst,
    			  0, 0,
    			  x, y,
    			  width, height);
    	FreePicture ((pointer) pMask, (XID) 0);
    	(*pScreen->DestroyPixmap) (pMaskPixmap);
        }
    }