Edit

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

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2012-06-10 13:21:05
    Hash : e60da745
    Message : Update to xserver 1.12.2. tested by naddy@, krw@, mpi@.

  • 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];
    
    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);
        }
    }