diff options
author | marha <marha@users.sourceforge.net> | 2012-03-23 10:05:55 +0100 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2012-03-23 10:05:55 +0100 |
commit | 0f834b91a4768673833ab4917e87d86c237bb1a6 (patch) | |
tree | 363489504ed4b2d360259b8de4c9e392918e5d02 /xorg-server/render/glyph.c | |
parent | fc72edebf875378459368c5383d9023730cbca54 (diff) | |
download | vcxsrv-0f834b91a4768673833ab4917e87d86c237bb1a6.tar.gz vcxsrv-0f834b91a4768673833ab4917e87d86c237bb1a6.tar.bz2 vcxsrv-0f834b91a4768673833ab4917e87d86c237bb1a6.zip |
libX11 xserver fontconfig mesa pixman xkbcomp xkeyboard-config git update
23 Mar 2012
Diffstat (limited to 'xorg-server/render/glyph.c')
-rw-r--r-- | xorg-server/render/glyph.c | 1434 |
1 files changed, 686 insertions, 748 deletions
diff --git a/xorg-server/render/glyph.c b/xorg-server/render/glyph.c index ab20da625..a143e9eb5 100644 --- a/xorg-server/render/glyph.c +++ b/xorg-server/render/glyph.c @@ -1,748 +1,686 @@ -/*
- *
- * 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];
-
-void
-GlyphUninit (ScreenPtr pScreen)
-{
- PictureScreenPtr ps = GetPictureScreen (pScreen);
- GlyphPtr glyph;
- int fdepth, i;
- int scrno = pScreen->myNum;
-
- 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)
- {
- if (GlyphPicture(glyph)[scrno])
- {
- FreePicture ((pointer) GlyphPicture (glyph)[scrno], 0);
- GlyphPicture(glyph)[scrno] = NULL;
- }
- (*ps->UnrealizeGlyph) (pScreen, 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);
- dixFreeObjectWithPrivates(glyph, PRIVATE_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);
- dixFreeObjectWithPrivates(glyph, PRIVATE_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;
- int head_size;
-
- head_size = sizeof (GlyphRec) + screenInfo.numScreens * sizeof (PicturePtr);
- size = (head_size + dixPrivatesSize(PRIVATE_GLYPH));
- glyph = (GlyphPtr) malloc (size);
- if (!glyph)
- return 0;
- glyph->refcnt = 0;
- glyph->size = size + sizeof (xGlyphInfo);
- glyph->info = *gi;
- dixInitPrivates(glyph, (char *) glyph + head_size, PRIVATE_GLYPH);
-
- 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);
- }
-
- dixFreeObjectWithPrivates(glyph, PRIVATE_GLYPH);
- return 0;
-}
-
-Bool
-AllocateGlyphHash (GlyphHashPtr hash, GlyphHashSetPtr hashSet)
-{
- hash->table = calloc(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;
- }
- }
- free(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;
-
- if (!globalGlyphs[fdepth].hashSet)
- {
- if (!AllocateGlyphHash (&globalGlyphs[fdepth], &glyphHashSets[0]))
- return FALSE;
- }
-
- glyphSet = dixAllocateObjectWithPrivates(GlyphSetRec, PRIVATE_GLYPHSET);
- if (!glyphSet)
- return FALSE;
-
- if (!AllocateGlyphHash (&glyphSet->hash, &glyphHashSets[0]))
- {
- free(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)
- {
- free(globalGlyphs[glyphSet->fdepth].table);
- globalGlyphs[glyphSet->fdepth].table = 0;
- globalGlyphs[glyphSet->fdepth].hashSet = 0;
- }
- else
- ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], 0, TRUE);
- free(table);
- dixFreeObjectWithPrivates(glyphSet, PRIVATE_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);
- }
-}
+/* + * + * 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]; + +void +GlyphUninit(ScreenPtr pScreen) +{ + PictureScreenPtr ps = GetPictureScreen(pScreen); + GlyphPtr glyph; + int fdepth, i; + int scrno = pScreen->myNum; + + 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) { + if (GlyphPicture(glyph)[scrno]) { + FreePicture((pointer) GlyphPicture(glyph)[scrno], 0); + GlyphPicture(glyph)[scrno] = NULL; + } + (*ps->UnrealizeGlyph) (pScreen, 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); + dixFreeObjectWithPrivates(glyph, PRIVATE_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); + dixFreeObjectWithPrivates(glyph, PRIVATE_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; + int head_size; + + head_size = sizeof(GlyphRec) + screenInfo.numScreens * sizeof(PicturePtr); + size = (head_size + dixPrivatesSize(PRIVATE_GLYPH)); + glyph = (GlyphPtr) malloc(size); + if (!glyph) + return 0; + glyph->refcnt = 0; + glyph->size = size + sizeof(xGlyphInfo); + glyph->info = *gi; + dixInitPrivates(glyph, (char *) glyph + head_size, PRIVATE_GLYPH); + + 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); + } + + dixFreeObjectWithPrivates(glyph, PRIVATE_GLYPH); + return 0; +} + +Bool +AllocateGlyphHash(GlyphHashPtr hash, GlyphHashSetPtr hashSet) +{ + hash->table = calloc(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; + } + } + free(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; + + if (!globalGlyphs[fdepth].hashSet) { + if (!AllocateGlyphHash(&globalGlyphs[fdepth], &glyphHashSets[0])) + return FALSE; + } + + glyphSet = dixAllocateObjectWithPrivates(GlyphSetRec, PRIVATE_GLYPHSET); + if (!glyphSet) + return FALSE; + + if (!AllocateGlyphHash(&glyphSet->hash, &glyphHashSets[0])) { + free(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) { + free(globalGlyphs[glyphSet->fdepth].table); + globalGlyphs[glyphSet->fdepth].table = 0; + globalGlyphs[glyphSet->fdepth].hashSet = 0; + } + else + ResizeGlyphHash(&globalGlyphs[glyphSet->fdepth], 0, TRUE); + free(table); + dixFreeObjectWithPrivates(glyphSet, PRIVATE_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); + } +} |