glyph.c revision 875c6e4f
1/*
2 *
3 * Copyright © 2000 SuSE, Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of SuSE not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission.  SuSE makes no representations about the
12 * suitability of this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 *
15 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
17 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
19 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 *
22 * Author:  Keith Packard, SuSE, Inc.
23 */
24
25#ifdef HAVE_DIX_CONFIG_H
26#include <dix-config.h>
27#endif
28
29#include "xsha1.h"
30
31#include "misc.h"
32#include "scrnintstr.h"
33#include "os.h"
34#include "regionstr.h"
35#include "validate.h"
36#include "windowstr.h"
37#include "input.h"
38#include "resource.h"
39#include "colormapst.h"
40#include "cursorstr.h"
41#include "dixstruct.h"
42#include "gcstruct.h"
43#include "servermd.h"
44#include "picturestr.h"
45#include "glyphstr.h"
46#include "mipict.h"
47
48/*
49 * From Knuth -- a good choice for hash/rehash values is p, p-2 where
50 * p and p-2 are both prime.  These tables are sized to have an extra 10%
51 * free to avoid exponential performance degradation as the hash table fills
52 */
53static GlyphHashSetRec glyphHashSets[] = {
54    {32, 43, 41},
55    {64, 73, 71},
56    {128, 151, 149},
57    {256, 283, 281},
58    {512, 571, 569},
59    {1024, 1153, 1151},
60    {2048, 2269, 2267},
61    {4096, 4519, 4517},
62    {8192, 9013, 9011},
63    {16384, 18043, 18041},
64    {32768, 36109, 36107},
65    {65536, 72091, 72089},
66    {131072, 144409, 144407},
67    {262144, 288361, 288359},
68    {524288, 576883, 576881},
69    {1048576, 1153459, 1153457},
70    {2097152, 2307163, 2307161},
71    {4194304, 4613893, 4613891},
72    {8388608, 9227641, 9227639},
73    {16777216, 18455029, 18455027},
74    {33554432, 36911011, 36911009},
75    {67108864, 73819861, 73819859},
76    {134217728, 147639589, 147639587},
77    {268435456, 295279081, 295279079},
78    {536870912, 590559793, 590559791}
79};
80
81#define NGLYPHHASHSETS	ARRAY_SIZE(glyphHashSets)
82
83static GlyphHashRec globalGlyphs[GlyphFormatNum];
84
85void
86GlyphUninit(ScreenPtr pScreen)
87{
88    PictureScreenPtr ps = GetPictureScreen(pScreen);
89    GlyphPtr glyph;
90    int fdepth, i;
91
92    for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++) {
93        if (!globalGlyphs[fdepth].hashSet)
94            continue;
95
96        for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++) {
97            glyph = globalGlyphs[fdepth].table[i].glyph;
98            if (glyph && glyph != DeletedGlyph) {
99                if (GetGlyphPicture(glyph, pScreen)) {
100                    FreePicture((void *) GetGlyphPicture(glyph, pScreen), 0);
101                    SetGlyphPicture(glyph, pScreen, NULL);
102                }
103                (*ps->UnrealizeGlyph) (pScreen, glyph);
104            }
105        }
106    }
107}
108
109static GlyphHashSetPtr
110FindGlyphHashSet(CARD32 filled)
111{
112    int i;
113
114    for (i = 0; i < NGLYPHHASHSETS; i++)
115        if (glyphHashSets[i].entries >= filled)
116            return &glyphHashSets[i];
117    return 0;
118}
119
120static GlyphRefPtr
121FindGlyphRef(GlyphHashPtr hash,
122             CARD32 signature, Bool match, unsigned char sha1[20])
123{
124    CARD32 elt, step, s;
125    GlyphPtr glyph;
126    GlyphRefPtr table, gr, del;
127    CARD32 tableSize = hash->hashSet->size;
128
129    table = hash->table;
130    elt = signature % tableSize;
131    step = 0;
132    del = 0;
133    for (;;) {
134        gr = &table[elt];
135        s = gr->signature;
136        glyph = gr->glyph;
137        if (!glyph) {
138            if (del)
139                gr = del;
140            break;
141        }
142        if (glyph == DeletedGlyph) {
143            if (!del)
144                del = gr;
145            else if (gr == del)
146                break;
147        }
148        else if (s == signature &&
149                 (!match || memcmp(glyph->sha1, sha1, 20) == 0)) {
150            break;
151        }
152        if (!step) {
153            step = signature % hash->hashSet->rehash;
154            if (!step)
155                step = 1;
156        }
157        elt += step;
158        if (elt >= tableSize)
159            elt -= tableSize;
160    }
161    return gr;
162}
163
164int
165HashGlyph(xGlyphInfo * gi,
166          CARD8 *bits, unsigned long size, unsigned char sha1[20])
167{
168    void *ctx = x_sha1_init();
169    int success;
170
171    if (!ctx)
172        return BadAlloc;
173
174    success = x_sha1_update(ctx, gi, sizeof(xGlyphInfo));
175    if (!success)
176        return BadAlloc;
177    success = x_sha1_update(ctx, bits, size);
178    if (!success)
179        return BadAlloc;
180    success = x_sha1_final(ctx, sha1);
181    if (!success)
182        return BadAlloc;
183    return Success;
184}
185
186GlyphPtr
187FindGlyphByHash(unsigned char sha1[20], int format)
188{
189    GlyphRefPtr gr;
190    CARD32 signature = *(CARD32 *) sha1;
191
192    if (!globalGlyphs[format].hashSet)
193        return NULL;
194
195    gr = FindGlyphRef(&globalGlyphs[format], signature, TRUE, sha1);
196
197    if (gr->glyph && gr->glyph != DeletedGlyph)
198        return gr->glyph;
199    else
200        return NULL;
201}
202
203#ifdef CHECK_DUPLICATES
204void
205DuplicateRef(GlyphPtr glyph, char *where)
206{
207    ErrorF("Duplicate Glyph 0x%x from %s\n", glyph, where);
208}
209
210void
211CheckDuplicates(GlyphHashPtr hash, char *where)
212{
213    GlyphPtr g;
214    int i, j;
215
216    for (i = 0; i < hash->hashSet->size; i++) {
217        g = hash->table[i].glyph;
218        if (!g || g == DeletedGlyph)
219            continue;
220        for (j = i + 1; j < hash->hashSet->size; j++)
221            if (hash->table[j].glyph == g)
222                DuplicateRef(g, where);
223    }
224}
225#else
226#define CheckDuplicates(a,b)
227#define DuplicateRef(a,b)
228#endif
229
230static void
231FreeGlyphPicture(GlyphPtr glyph)
232{
233    PictureScreenPtr ps;
234    int i;
235
236    for (i = 0; i < screenInfo.numScreens; i++) {
237        ScreenPtr pScreen = screenInfo.screens[i];
238
239        if (GetGlyphPicture(glyph, pScreen))
240            FreePicture((void *) GetGlyphPicture(glyph, pScreen), 0);
241
242        ps = GetPictureScreenIfSet(pScreen);
243        if (ps)
244            (*ps->UnrealizeGlyph) (pScreen, glyph);
245    }
246}
247
248void
249FreeGlyph(GlyphPtr glyph, int format)
250{
251    CheckDuplicates(&globalGlyphs[format], "FreeGlyph");
252    BUG_RETURN(glyph->refcnt == 0);
253    if (--glyph->refcnt == 0) {
254        GlyphRefPtr gr;
255        int i;
256        int first;
257        CARD32 signature;
258
259        first = -1;
260        for (i = 0; i < globalGlyphs[format].hashSet->size; i++)
261            if (globalGlyphs[format].table[i].glyph == glyph) {
262                if (first != -1)
263                    DuplicateRef(glyph, "FreeGlyph check");
264                first = i;
265            }
266
267        signature = *(CARD32 *) glyph->sha1;
268        gr = FindGlyphRef(&globalGlyphs[format], signature, TRUE, glyph->sha1);
269        if (gr - globalGlyphs[format].table != first)
270            DuplicateRef(glyph, "Found wrong one");
271        if (gr->glyph && gr->glyph != DeletedGlyph) {
272            gr->glyph = DeletedGlyph;
273            gr->signature = 0;
274            globalGlyphs[format].tableEntries--;
275        }
276
277        FreeGlyphPicture(glyph);
278        dixFreeObjectWithPrivates(glyph, PRIVATE_GLYPH);
279    }
280}
281
282void
283AddGlyph(GlyphSetPtr glyphSet, GlyphPtr glyph, Glyph id)
284{
285    GlyphRefPtr gr;
286    CARD32 signature;
287
288    CheckDuplicates(&globalGlyphs[glyphSet->fdepth], "AddGlyph top global");
289    /* Locate existing matching glyph */
290    signature = *(CARD32 *) glyph->sha1;
291    gr = FindGlyphRef(&globalGlyphs[glyphSet->fdepth], signature,
292                      TRUE, glyph->sha1);
293    if (gr->glyph && gr->glyph != DeletedGlyph && gr->glyph != glyph) {
294        glyph = gr->glyph;
295    }
296    else if (gr->glyph != glyph) {
297        gr->glyph = glyph;
298        gr->signature = signature;
299        globalGlyphs[glyphSet->fdepth].tableEntries++;
300    }
301
302    /* Insert/replace glyphset value */
303    gr = FindGlyphRef(&glyphSet->hash, id, FALSE, 0);
304    ++glyph->refcnt;
305    if (gr->glyph && gr->glyph != DeletedGlyph)
306        FreeGlyph(gr->glyph, glyphSet->fdepth);
307    else
308        glyphSet->hash.tableEntries++;
309    gr->glyph = glyph;
310    gr->signature = id;
311    CheckDuplicates(&globalGlyphs[glyphSet->fdepth], "AddGlyph bottom");
312}
313
314Bool
315DeleteGlyph(GlyphSetPtr glyphSet, Glyph id)
316{
317    GlyphRefPtr gr;
318    GlyphPtr glyph;
319
320    gr = FindGlyphRef(&glyphSet->hash, id, FALSE, 0);
321    glyph = gr->glyph;
322    if (glyph && glyph != DeletedGlyph) {
323        gr->glyph = DeletedGlyph;
324        glyphSet->hash.tableEntries--;
325        FreeGlyph(glyph, glyphSet->fdepth);
326        return TRUE;
327    }
328    return FALSE;
329}
330
331GlyphPtr
332FindGlyph(GlyphSetPtr glyphSet, Glyph id)
333{
334    GlyphPtr glyph;
335
336    glyph = FindGlyphRef(&glyphSet->hash, id, FALSE, 0)->glyph;
337    if (glyph == DeletedGlyph)
338        glyph = 0;
339    return glyph;
340}
341
342GlyphPtr
343AllocateGlyph(xGlyphInfo * gi, int fdepth)
344{
345    PictureScreenPtr ps;
346    int size;
347    GlyphPtr glyph;
348    int i;
349    int head_size;
350
351    head_size = sizeof(GlyphRec) + screenInfo.numScreens * sizeof(PicturePtr);
352    size = (head_size + dixPrivatesSize(PRIVATE_GLYPH));
353    glyph = (GlyphPtr) malloc(size);
354    if (!glyph)
355        return 0;
356    glyph->refcnt = 1;
357    glyph->size = size + sizeof(xGlyphInfo);
358    glyph->info = *gi;
359    dixInitPrivates(glyph, (char *) glyph + head_size, PRIVATE_GLYPH);
360
361    for (i = 0; i < screenInfo.numScreens; i++) {
362        ScreenPtr pScreen = screenInfo.screens[i];
363        SetGlyphPicture(glyph, pScreen, NULL);
364        ps = GetPictureScreenIfSet(pScreen);
365
366        if (ps) {
367            if (!(*ps->RealizeGlyph) (pScreen, glyph))
368                goto bail;
369        }
370    }
371
372    return glyph;
373
374 bail:
375    while (i--) {
376        ps = GetPictureScreenIfSet(screenInfo.screens[i]);
377        if (ps)
378            (*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph);
379    }
380
381    dixFreeObjectWithPrivates(glyph, PRIVATE_GLYPH);
382    return 0;
383}
384
385static Bool
386AllocateGlyphHash(GlyphHashPtr hash, GlyphHashSetPtr hashSet)
387{
388    hash->table = calloc(hashSet->size, sizeof(GlyphRefRec));
389    if (!hash->table)
390        return FALSE;
391    hash->hashSet = hashSet;
392    hash->tableEntries = 0;
393    return TRUE;
394}
395
396static Bool
397ResizeGlyphHash(GlyphHashPtr hash, CARD32 change, Bool global)
398{
399    CARD32 tableEntries;
400    GlyphHashSetPtr hashSet;
401    GlyphHashRec newHash;
402    GlyphRefPtr gr;
403    GlyphPtr glyph;
404    int i;
405    int oldSize;
406    CARD32 s;
407
408    tableEntries = hash->tableEntries + change;
409    hashSet = FindGlyphHashSet(tableEntries);
410    if (hashSet == hash->hashSet)
411        return TRUE;
412    if (global)
413        CheckDuplicates(hash, "ResizeGlyphHash top");
414    if (!AllocateGlyphHash(&newHash, hashSet))
415        return FALSE;
416    if (hash->table) {
417        oldSize = hash->hashSet->size;
418        for (i = 0; i < oldSize; i++) {
419            glyph = hash->table[i].glyph;
420            if (glyph && glyph != DeletedGlyph) {
421                s = hash->table[i].signature;
422                gr = FindGlyphRef(&newHash, s, global, glyph->sha1);
423
424                gr->signature = s;
425                gr->glyph = glyph;
426                ++newHash.tableEntries;
427            }
428        }
429        free(hash->table);
430    }
431    *hash = newHash;
432    if (global)
433        CheckDuplicates(hash, "ResizeGlyphHash bottom");
434    return TRUE;
435}
436
437Bool
438ResizeGlyphSet(GlyphSetPtr glyphSet, CARD32 change)
439{
440    return (ResizeGlyphHash(&glyphSet->hash, change, FALSE) &&
441            ResizeGlyphHash(&globalGlyphs[glyphSet->fdepth], change, TRUE));
442}
443
444GlyphSetPtr
445AllocateGlyphSet(int fdepth, PictFormatPtr format)
446{
447    GlyphSetPtr glyphSet;
448
449    if (!globalGlyphs[fdepth].hashSet) {
450        if (!AllocateGlyphHash(&globalGlyphs[fdepth], &glyphHashSets[0]))
451            return FALSE;
452    }
453
454    glyphSet = dixAllocateObjectWithPrivates(GlyphSetRec, PRIVATE_GLYPHSET);
455    if (!glyphSet)
456        return FALSE;
457
458    if (!AllocateGlyphHash(&glyphSet->hash, &glyphHashSets[0])) {
459        free(glyphSet);
460        return FALSE;
461    }
462    glyphSet->refcnt = 1;
463    glyphSet->fdepth = fdepth;
464    glyphSet->format = format;
465    return glyphSet;
466}
467
468int
469FreeGlyphSet(void *value, XID gid)
470{
471    GlyphSetPtr glyphSet = (GlyphSetPtr) value;
472
473    if (--glyphSet->refcnt == 0) {
474        CARD32 i, tableSize = glyphSet->hash.hashSet->size;
475        GlyphRefPtr table = glyphSet->hash.table;
476        GlyphPtr glyph;
477
478        for (i = 0; i < tableSize; i++) {
479            glyph = table[i].glyph;
480            if (glyph && glyph != DeletedGlyph)
481                FreeGlyph(glyph, glyphSet->fdepth);
482        }
483        if (!globalGlyphs[glyphSet->fdepth].tableEntries) {
484            free(globalGlyphs[glyphSet->fdepth].table);
485            globalGlyphs[glyphSet->fdepth].table = 0;
486            globalGlyphs[glyphSet->fdepth].hashSet = 0;
487        }
488        else
489            ResizeGlyphHash(&globalGlyphs[glyphSet->fdepth], 0, TRUE);
490        free(table);
491        dixFreeObjectWithPrivates(glyphSet, PRIVATE_GLYPHSET);
492    }
493    return Success;
494}
495
496static void
497GlyphExtents(int nlist, GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
498{
499    int x1, x2, y1, y2;
500    int n;
501    GlyphPtr glyph;
502    int x, y;
503
504    x = 0;
505    y = 0;
506    extents->x1 = MAXSHORT;
507    extents->x2 = MINSHORT;
508    extents->y1 = MAXSHORT;
509    extents->y2 = MINSHORT;
510    while (nlist--) {
511        x += list->xOff;
512        y += list->yOff;
513        n = list->len;
514        list++;
515        while (n--) {
516            glyph = *glyphs++;
517            x1 = x - glyph->info.x;
518            if (x1 < MINSHORT)
519                x1 = MINSHORT;
520            y1 = y - glyph->info.y;
521            if (y1 < MINSHORT)
522                y1 = MINSHORT;
523            x2 = x1 + glyph->info.width;
524            if (x2 > MAXSHORT)
525                x2 = MAXSHORT;
526            y2 = y1 + glyph->info.height;
527            if (y2 > MAXSHORT)
528                y2 = MAXSHORT;
529            if (x1 < extents->x1)
530                extents->x1 = x1;
531            if (x2 > extents->x2)
532                extents->x2 = x2;
533            if (y1 < extents->y1)
534                extents->y1 = y1;
535            if (y2 > extents->y2)
536                extents->y2 = y2;
537            x += glyph->info.xOff;
538            y += glyph->info.yOff;
539        }
540    }
541}
542
543#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
544
545void
546CompositeGlyphs(CARD8 op,
547                PicturePtr pSrc,
548                PicturePtr pDst,
549                PictFormatPtr maskFormat,
550                INT16 xSrc,
551                INT16 ySrc, int nlist, GlyphListPtr lists, GlyphPtr * glyphs)
552{
553    PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen);
554
555    ValidatePicture(pSrc);
556    ValidatePicture(pDst);
557    (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, lists,
558                   glyphs);
559}
560
561Bool
562miRealizeGlyph(ScreenPtr pScreen, GlyphPtr glyph)
563{
564    return TRUE;
565}
566
567void
568miUnrealizeGlyph(ScreenPtr pScreen, GlyphPtr glyph)
569{
570}
571
572void
573miGlyphs(CARD8 op,
574         PicturePtr pSrc,
575         PicturePtr pDst,
576         PictFormatPtr maskFormat,
577         INT16 xSrc,
578         INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
579{
580    PicturePtr pPicture;
581    PixmapPtr pMaskPixmap = 0;
582    PicturePtr pMask;
583    ScreenPtr pScreen = pDst->pDrawable->pScreen;
584    int width = 0, height = 0;
585    int x, y;
586    int xDst = list->xOff, yDst = list->yOff;
587    int n;
588    GlyphPtr glyph;
589    int error;
590    BoxRec extents = { 0, 0, 0, 0 };
591    CARD32 component_alpha;
592
593    if (maskFormat) {
594        GCPtr pGC;
595        xRectangle rect;
596
597        GlyphExtents(nlist, list, glyphs, &extents);
598
599        if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
600            return;
601        width = extents.x2 - extents.x1;
602        height = extents.y2 - extents.y1;
603        pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
604                                                maskFormat->depth,
605                                                CREATE_PIXMAP_USAGE_SCRATCH);
606        if (!pMaskPixmap)
607            return;
608        component_alpha = NeedsComponent(maskFormat->format);
609        pMask = CreatePicture(0, &pMaskPixmap->drawable,
610                              maskFormat, CPComponentAlpha, &component_alpha,
611                              serverClient, &error);
612        if (!pMask) {
613            (*pScreen->DestroyPixmap) (pMaskPixmap);
614            return;
615        }
616        pGC = GetScratchGC(pMaskPixmap->drawable.depth, pScreen);
617        ValidateGC(&pMaskPixmap->drawable, pGC);
618        rect.x = 0;
619        rect.y = 0;
620        rect.width = width;
621        rect.height = height;
622        (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
623        FreeScratchGC(pGC);
624        x = -extents.x1;
625        y = -extents.y1;
626    }
627    else {
628        pMask = pDst;
629        x = 0;
630        y = 0;
631    }
632    while (nlist--) {
633        x += list->xOff;
634        y += list->yOff;
635        n = list->len;
636        while (n--) {
637            glyph = *glyphs++;
638            pPicture = GetGlyphPicture(glyph, pScreen);
639
640            if (pPicture) {
641                if (maskFormat) {
642                    CompositePicture(PictOpAdd,
643                                     pPicture,
644                                     None,
645                                     pMask,
646                                     0, 0,
647                                     0, 0,
648                                     x - glyph->info.x,
649                                     y - glyph->info.y,
650                                     glyph->info.width, glyph->info.height);
651                }
652                else {
653                    CompositePicture(op,
654                                     pSrc,
655                                     pPicture,
656                                     pDst,
657                                     xSrc + (x - glyph->info.x) - xDst,
658                                     ySrc + (y - glyph->info.y) - yDst,
659                                     0, 0,
660                                     x - glyph->info.x,
661                                     y - glyph->info.y,
662                                     glyph->info.width, glyph->info.height);
663                }
664            }
665
666            x += glyph->info.xOff;
667            y += glyph->info.yOff;
668        }
669        list++;
670    }
671    if (maskFormat) {
672        x = extents.x1;
673        y = extents.y1;
674        CompositePicture(op,
675                         pSrc,
676                         pMask,
677                         pDst,
678                         xSrc + x - xDst,
679                         ySrc + y - yDst, 0, 0, x, y, width, height);
680        FreePicture((void *) pMask, (XID) 0);
681        (*pScreen->DestroyPixmap) (pMaskPixmap);
682    }
683}
684
685PicturePtr GetGlyphPicture(GlyphPtr glyph, ScreenPtr pScreen)
686{
687    if (pScreen->isGPU)
688        return NULL;
689    return GlyphPicture(glyph)[pScreen->myNum];
690}
691
692void SetGlyphPicture(GlyphPtr glyph, ScreenPtr pScreen, PicturePtr picture)
693{
694    GlyphPicture(glyph)[pScreen->myNum] = picture;
695}
696