glyph.c revision 05b261ec
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 "misc.h"
30#include "scrnintstr.h"
31#include "os.h"
32#include "regionstr.h"
33#include "validate.h"
34#include "windowstr.h"
35#include "input.h"
36#include "resource.h"
37#include "colormapst.h"
38#include "cursorstr.h"
39#include "dixstruct.h"
40#include "gcstruct.h"
41#include "servermd.h"
42#include "picturestr.h"
43#include "glyphstr.h"
44
45#if HAVE_STDINT_H
46#include <stdint.h>
47#elif !defined(UINT32_MAX)
48#define UINT32_MAX 0xffffffffU
49#endif
50
51/*
52 * From Knuth -- a good choice for hash/rehash values is p, p-2 where
53 * p and p-2 are both prime.  These tables are sized to have an extra 10%
54 * free to avoid exponential performance degradation as the hash table fills
55 */
56static GlyphHashSetRec glyphHashSets[] = {
57    { 32,		43,		41        },
58    { 64,		73,		71        },
59    { 128,		151,		149       },
60    { 256,		283,		281       },
61    { 512,		571,		569       },
62    { 1024,		1153,		1151      },
63    { 2048,		2269,		2267      },
64    { 4096,		4519,		4517      },
65    { 8192,		9013,		9011      },
66    { 16384,		18043,		18041     },
67    { 32768,		36109,		36107     },
68    { 65536,		72091,		72089     },
69    { 131072,		144409,		144407    },
70    { 262144,		288361,		288359    },
71    { 524288,		576883,		576881    },
72    { 1048576,		1153459,	1153457   },
73    { 2097152,		2307163,	2307161   },
74    { 4194304,		4613893,	4613891   },
75    { 8388608,		9227641,	9227639   },
76    { 16777216,		18455029,	18455027  },
77    { 33554432,		36911011,	36911009  },
78    { 67108864,		73819861,	73819859  },
79    { 134217728,	147639589,	147639587 },
80    { 268435456,	295279081,	295279079 },
81    { 536870912,	590559793,	590559791 }
82};
83
84#define NGLYPHHASHSETS	(sizeof(glyphHashSets)/sizeof(glyphHashSets[0]))
85
86static const CARD8	glyphDepths[GlyphFormatNum] = { 1, 4, 8, 16, 32 };
87
88static GlyphHashRec	globalGlyphs[GlyphFormatNum];
89
90static int	globalTotalGlyphPrivateSize = 0;
91
92static int	glyphPrivateCount = 0;
93
94void
95ResetGlyphPrivates (void)
96{
97    glyphPrivateCount = 0;
98}
99
100int
101AllocateGlyphPrivateIndex (void)
102{
103    return glyphPrivateCount++;
104}
105
106Bool
107AllocateGlyphPrivate (ScreenPtr pScreen,
108		      int	index2,
109		      unsigned	amount)
110{
111    PictureScreenPtr ps;
112    unsigned	     oldamount;
113
114    ps = GetPictureScreenIfSet (pScreen);
115    if (!ps)
116	return FALSE;
117
118    /* Round up sizes for proper alignment */
119    amount = ((amount + (sizeof (DevUnion) - 1)) / sizeof (DevUnion)) *
120	sizeof (DevUnion);
121
122    if (index2 >= ps->glyphPrivateLen)
123    {
124	unsigned *nsizes;
125	nsizes = (unsigned *) xrealloc (ps->glyphPrivateSizes,
126					(index2 + 1) * sizeof (unsigned));
127	if (!nsizes)
128	    return FALSE;
129
130	while (ps->glyphPrivateLen <= index2)
131	{
132	    nsizes[ps->glyphPrivateLen++] = 0;
133	    ps->totalGlyphPrivateSize += sizeof (DevUnion);
134	}
135	ps->glyphPrivateSizes = nsizes;
136    }
137    oldamount = ps->glyphPrivateSizes[index2];
138    if (amount > oldamount)
139    {
140	ps->glyphPrivateSizes[index2] = amount;
141	ps->totalGlyphPrivateSize += (amount - oldamount);
142    }
143    ps->totalGlyphPrivateSize = BitmapBytePad (ps->totalGlyphPrivateSize * 8);
144
145    return TRUE;
146}
147
148static void
149SetGlyphScreenPrivateOffsets (void)
150{
151    PictureScreenPtr ps;
152    int		     offset = 0;
153    int		     i;
154
155    for (i = 0; i < screenInfo.numScreens; i++)
156    {
157	ps = GetPictureScreenIfSet (screenInfo.screens[i]);
158	if (ps && ps->totalGlyphPrivateSize)
159	{
160	    ps->glyphPrivateOffset = offset;
161	    offset += ps->totalGlyphPrivateSize / sizeof (DevUnion);
162	}
163    }
164}
165
166static void
167SetGlyphPrivatePointers (GlyphPtr glyph)
168{
169    PictureScreenPtr ps;
170    int		     i;
171    char	     *ptr;
172    DevUnion         *ppriv;
173    unsigned         *sizes;
174    unsigned         size;
175    int		     len;
176
177    for (i = 0; i < screenInfo.numScreens; i++)
178    {
179	ps = GetPictureScreenIfSet (screenInfo.screens[i]);
180	if (ps && ps->totalGlyphPrivateSize)
181	{
182	    ppriv = glyph->devPrivates + ps->glyphPrivateOffset;
183	    sizes = ps->glyphPrivateSizes;
184	    ptr = (char *) (ppriv + ps->glyphPrivateLen);
185	    for (len = ps->glyphPrivateLen; --len >= 0; ppriv++, sizes++)
186	    {
187		if ((size = *sizes) != 0)
188		{
189		    ppriv->ptr = (pointer) ptr;
190		    ptr += size;
191		}
192		else
193		    ppriv->ptr = (pointer) 0;
194	    }
195	}
196    }
197}
198
199static Bool
200ReallocGlobalGlyphPrivate (GlyphPtr glyph)
201{
202    PictureScreenPtr ps;
203    DevUnion         *devPrivates;
204    char	     *ptr;
205    int		     i;
206
207    devPrivates = xalloc (globalTotalGlyphPrivateSize);
208    if (!devPrivates)
209	return FALSE;
210
211    ptr = (char *) devPrivates;
212    for (i = 0; i < screenInfo.numScreens; i++)
213    {
214	ps = GetPictureScreenIfSet (screenInfo.screens[i]);
215	if (ps && ps->totalGlyphPrivateSize)
216	{
217	    if (ps->glyphPrivateOffset != -1)
218	    {
219		memcpy (ptr, glyph->devPrivates + ps->glyphPrivateOffset,
220			ps->totalGlyphPrivateSize);
221	    }
222	    else if (ps->totalGlyphPrivateSize)
223	    {
224		memset (ptr, 0, ps->totalGlyphPrivateSize);
225	    }
226
227	    ptr += ps->totalGlyphPrivateSize;
228	}
229    }
230
231    if (glyph->devPrivates)
232	xfree (glyph->devPrivates);
233
234    glyph->devPrivates = devPrivates;
235
236    return TRUE;
237}
238
239Bool
240GlyphInit (ScreenPtr pScreen)
241{
242    PictureScreenPtr ps = GetPictureScreen (pScreen);
243
244    ps->totalGlyphPrivateSize = 0;
245    ps->glyphPrivateSizes = 0;
246    ps->glyphPrivateLen = 0;
247    ps->glyphPrivateOffset = -1;
248
249    return TRUE;
250}
251
252Bool
253GlyphFinishInit (ScreenPtr pScreen)
254{
255    PictureScreenPtr ps = GetPictureScreen (pScreen);
256
257    if (ps->totalGlyphPrivateSize)
258    {
259	GlyphPtr glyph;
260	int	 fdepth, i;
261
262	globalTotalGlyphPrivateSize += ps->totalGlyphPrivateSize;
263
264	for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++)
265	{
266	    if (!globalGlyphs[fdepth].hashSet)
267		continue;
268
269	    for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++)
270	    {
271		glyph = globalGlyphs[fdepth].table[i].glyph;
272		if (glyph && glyph != DeletedGlyph)
273		{
274		    if (!ReallocGlobalGlyphPrivate (glyph))
275			return FALSE;
276		}
277	    }
278	}
279
280	SetGlyphScreenPrivateOffsets ();
281
282	for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++)
283	{
284	    if (!globalGlyphs[fdepth].hashSet)
285		continue;
286
287	    for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++)
288	    {
289		glyph = globalGlyphs[fdepth].table[i].glyph;
290		if (glyph && glyph != DeletedGlyph)
291		{
292		    SetGlyphPrivatePointers (glyph);
293
294		    if (!(*ps->RealizeGlyph) (pScreen, glyph))
295			return FALSE;
296		}
297	    }
298	}
299    }
300    else
301	ps->glyphPrivateOffset = 0;
302
303    return TRUE;
304}
305
306void
307GlyphUninit (ScreenPtr pScreen)
308{
309    PictureScreenPtr ps = GetPictureScreen (pScreen);
310    GlyphPtr	     glyph;
311    int		     fdepth, i;
312
313    globalTotalGlyphPrivateSize -= ps->totalGlyphPrivateSize;
314
315    for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++)
316    {
317	if (!globalGlyphs[fdepth].hashSet)
318	    continue;
319
320	for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++)
321	{
322	    glyph = globalGlyphs[fdepth].table[i].glyph;
323	    if (glyph && glyph != DeletedGlyph)
324	    {
325		(*ps->UnrealizeGlyph) (pScreen, glyph);
326
327		if (globalTotalGlyphPrivateSize)
328		{
329		    if (!ReallocGlobalGlyphPrivate (glyph))
330			return;
331		}
332		else
333		{
334		    if (glyph->devPrivates)
335			xfree (glyph->devPrivates);
336		    glyph->devPrivates = NULL;
337		}
338	    }
339	}
340    }
341
342    if (globalTotalGlyphPrivateSize)
343	SetGlyphScreenPrivateOffsets ();
344
345    for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++)
346    {
347	if (!globalGlyphs[fdepth].hashSet)
348	    continue;
349
350	for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++)
351	{
352	    glyph = globalGlyphs[fdepth].table[i].glyph;
353	    if (glyph && glyph != DeletedGlyph)
354	    {
355		if (globalTotalGlyphPrivateSize)
356		    SetGlyphPrivatePointers (glyph);
357	    }
358	}
359    }
360
361    if (ps->glyphPrivateSizes)
362	xfree (ps->glyphPrivateSizes);
363}
364
365GlyphHashSetPtr
366FindGlyphHashSet (CARD32 filled)
367{
368    int	i;
369
370    for (i = 0; i < NGLYPHHASHSETS; i++)
371	if (glyphHashSets[i].entries >= filled)
372	    return &glyphHashSets[i];
373    return 0;
374}
375
376static int _GlyphSetPrivateAllocateIndex = 0;
377
378int
379AllocateGlyphSetPrivateIndex (void)
380{
381    return _GlyphSetPrivateAllocateIndex++;
382}
383
384void
385ResetGlyphSetPrivateIndex (void)
386{
387    _GlyphSetPrivateAllocateIndex = 0;
388}
389
390Bool
391_GlyphSetSetNewPrivate (GlyphSetPtr glyphSet, int n, pointer ptr)
392{
393    pointer *new;
394
395    if (n > glyphSet->maxPrivate) {
396	if (glyphSet->devPrivates &&
397	    glyphSet->devPrivates != (pointer)(&glyphSet[1])) {
398	    new = (pointer *) xrealloc (glyphSet->devPrivates,
399					(n + 1) * sizeof (pointer));
400	    if (!new)
401		return FALSE;
402	} else {
403	    new = (pointer *) xalloc ((n + 1) * sizeof (pointer));
404	    if (!new)
405		return FALSE;
406	    if (glyphSet->devPrivates)
407		memcpy (new,
408			glyphSet->devPrivates,
409			(glyphSet->maxPrivate + 1) * sizeof (pointer));
410	}
411	glyphSet->devPrivates = new;
412	/* Zero out new, uninitialize privates */
413	while (++glyphSet->maxPrivate < n)
414	    glyphSet->devPrivates[glyphSet->maxPrivate] = (pointer)0;
415    }
416    glyphSet->devPrivates[n] = ptr;
417    return TRUE;
418}
419
420GlyphRefPtr
421FindGlyphRef (GlyphHashPtr hash, CARD32 signature, Bool match, GlyphPtr compare)
422{
423    CARD32	elt, step, s;
424    GlyphPtr	glyph;
425    GlyphRefPtr	table, gr, del;
426    CARD32	tableSize = hash->hashSet->size;
427
428    table = hash->table;
429    elt = signature % tableSize;
430    step = 0;
431    del = 0;
432    for (;;)
433    {
434	gr = &table[elt];
435	s = gr->signature;
436	glyph = gr->glyph;
437	if (!glyph)
438	{
439	    if (del)
440		gr = del;
441	    break;
442	}
443	if (glyph == DeletedGlyph)
444	{
445	    if (!del)
446		del = gr;
447	    else if (gr == del)
448		break;
449	}
450	else if (s == signature &&
451		 (!match ||
452		  memcmp (&compare->info, &glyph->info, compare->size) == 0))
453	{
454	    break;
455	}
456	if (!step)
457	{
458	    step = signature % hash->hashSet->rehash;
459	    if (!step)
460		step = 1;
461	}
462	elt += step;
463	if (elt >= tableSize)
464	    elt -= tableSize;
465    }
466    return gr;
467}
468
469CARD32
470HashGlyph (GlyphPtr glyph)
471{
472    CARD32  *bits = (CARD32 *) &(glyph->info);
473    CARD32  hash;
474    int	    n = glyph->size / sizeof (CARD32);
475
476    hash = 0;
477    while (n--)
478	hash ^= *bits++;
479    return hash;
480}
481
482#ifdef CHECK_DUPLICATES
483void
484DuplicateRef (GlyphPtr glyph, char *where)
485{
486    ErrorF ("Duplicate Glyph 0x%x from %s\n", glyph, where);
487}
488
489void
490CheckDuplicates (GlyphHashPtr hash, char *where)
491{
492    GlyphPtr	g;
493    int		i, j;
494
495    for (i = 0; i < hash->hashSet->size; i++)
496    {
497	g = hash->table[i].glyph;
498	if (!g || g == DeletedGlyph)
499	    continue;
500	for (j = i + 1; j < hash->hashSet->size; j++)
501	    if (hash->table[j].glyph == g)
502		DuplicateRef (g, where);
503    }
504}
505#else
506#define CheckDuplicates(a,b)
507#define DuplicateRef(a,b)
508#endif
509
510void
511FreeGlyph (GlyphPtr glyph, int format)
512{
513    CheckDuplicates (&globalGlyphs[format], "FreeGlyph");
514    if (--glyph->refcnt == 0)
515    {
516	PictureScreenPtr ps;
517	GlyphRefPtr      gr;
518	int	         i;
519	int	         first;
520
521	first = -1;
522	for (i = 0; i < globalGlyphs[format].hashSet->size; i++)
523	    if (globalGlyphs[format].table[i].glyph == glyph)
524	    {
525		if (first != -1)
526		    DuplicateRef (glyph, "FreeGlyph check");
527		first = i;
528	    }
529
530	gr = FindGlyphRef (&globalGlyphs[format],
531			   HashGlyph (glyph), TRUE, glyph);
532	if (gr - globalGlyphs[format].table != first)
533	    DuplicateRef (glyph, "Found wrong one");
534	if (gr->glyph && gr->glyph != DeletedGlyph)
535	{
536	    gr->glyph = DeletedGlyph;
537	    gr->signature = 0;
538	    globalGlyphs[format].tableEntries--;
539	}
540
541	for (i = 0; i < screenInfo.numScreens; i++)
542	{
543	    ps = GetPictureScreenIfSet (screenInfo.screens[i]);
544	    if (ps)
545		(*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph);
546	}
547
548	if (glyph->devPrivates)
549	    xfree (glyph->devPrivates);
550	xfree (glyph);
551    }
552}
553
554void
555AddGlyph (GlyphSetPtr glyphSet, GlyphPtr glyph, Glyph id)
556{
557    GlyphRefPtr	    gr;
558    CARD32	    hash;
559
560    CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph top global");
561    /* Locate existing matching glyph */
562    hash = HashGlyph (glyph);
563    gr = FindGlyphRef (&globalGlyphs[glyphSet->fdepth], hash, TRUE, glyph);
564    if (gr->glyph && gr->glyph != DeletedGlyph)
565    {
566	PictureScreenPtr ps;
567	int              i;
568
569	for (i = 0; i < screenInfo.numScreens; i++)
570	{
571	    ps = GetPictureScreenIfSet (screenInfo.screens[i]);
572	    if (ps)
573		(*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph);
574	}
575	if (glyph->devPrivates)
576	    xfree (glyph->devPrivates);
577	xfree (glyph);
578	glyph = gr->glyph;
579    }
580    else
581    {
582	gr->glyph = glyph;
583	gr->signature = hash;
584	globalGlyphs[glyphSet->fdepth].tableEntries++;
585    }
586
587    /* Insert/replace glyphset value */
588    gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0);
589    ++glyph->refcnt;
590    if (gr->glyph && gr->glyph != DeletedGlyph)
591	FreeGlyph (gr->glyph, glyphSet->fdepth);
592    else
593	glyphSet->hash.tableEntries++;
594    gr->glyph = glyph;
595    gr->signature = id;
596    CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph bottom");
597}
598
599Bool
600DeleteGlyph (GlyphSetPtr glyphSet, Glyph id)
601{
602    GlyphRefPtr     gr;
603    GlyphPtr	    glyph;
604
605    gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0);
606    glyph = gr->glyph;
607    if (glyph && glyph != DeletedGlyph)
608    {
609	gr->glyph = DeletedGlyph;
610	glyphSet->hash.tableEntries--;
611	FreeGlyph (glyph, glyphSet->fdepth);
612	return TRUE;
613    }
614    return FALSE;
615}
616
617GlyphPtr
618FindGlyph (GlyphSetPtr glyphSet, Glyph id)
619{
620    GlyphPtr        glyph;
621
622    glyph = FindGlyphRef (&glyphSet->hash, id, FALSE, 0)->glyph;
623    if (glyph == DeletedGlyph)
624	glyph = 0;
625    return glyph;
626}
627
628GlyphPtr
629AllocateGlyph (xGlyphInfo *gi, int fdepth)
630{
631    PictureScreenPtr ps;
632    int		     size;
633    GlyphPtr	     glyph;
634    int		     i;
635    size_t	     padded_width;
636
637    padded_width = PixmapBytePad (gi->width, glyphDepths[fdepth]);
638    if (gi->height && padded_width > (UINT32_MAX - sizeof(GlyphRec))/gi->height)
639	return 0;
640    size = gi->height * padded_width;
641    glyph = (GlyphPtr) xalloc (size + sizeof (GlyphRec));
642    if (!glyph)
643	return 0;
644    glyph->refcnt = 0;
645    glyph->size = size + sizeof (xGlyphInfo);
646    glyph->info = *gi;
647
648    if (globalTotalGlyphPrivateSize)
649    {
650	glyph->devPrivates = xalloc (globalTotalGlyphPrivateSize);
651	if (!glyph->devPrivates)
652	    return 0;
653
654	SetGlyphPrivatePointers (glyph);
655    } else
656	glyph->devPrivates = NULL;
657
658    for (i = 0; i < screenInfo.numScreens; i++)
659    {
660	ps = GetPictureScreenIfSet (screenInfo.screens[i]);
661	if (ps)
662	{
663	    if (!(*ps->RealizeGlyph) (screenInfo.screens[i], glyph))
664	    {
665		while (i--)
666		{
667		    ps = GetPictureScreenIfSet (screenInfo.screens[i]);
668		    if (ps)
669			(*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph);
670		}
671
672		if (glyph->devPrivates)
673		    xfree (glyph->devPrivates);
674		xfree (glyph);
675		return 0;
676	    }
677	}
678    }
679
680    return glyph;
681}
682
683Bool
684AllocateGlyphHash (GlyphHashPtr hash, GlyphHashSetPtr hashSet)
685{
686    hash->table = (GlyphRefPtr) xalloc (hashSet->size * sizeof (GlyphRefRec));
687    if (!hash->table)
688	return FALSE;
689    memset (hash->table, 0, hashSet->size * sizeof (GlyphRefRec));
690    hash->hashSet = hashSet;
691    hash->tableEntries = 0;
692    return TRUE;
693}
694
695Bool
696ResizeGlyphHash (GlyphHashPtr hash, CARD32 change, Bool global)
697{
698    CARD32	    tableEntries;
699    GlyphHashSetPtr hashSet;
700    GlyphHashRec    newHash;
701    GlyphRefPtr	    gr;
702    GlyphPtr	    glyph;
703    int		    i;
704    int		    oldSize;
705    CARD32	    s;
706
707    tableEntries = hash->tableEntries + change;
708    hashSet = FindGlyphHashSet (tableEntries);
709    if (hashSet == hash->hashSet)
710	return TRUE;
711    if (global)
712	CheckDuplicates (hash, "ResizeGlyphHash top");
713    if (!AllocateGlyphHash (&newHash, hashSet))
714	return FALSE;
715    if (hash->table)
716    {
717	oldSize = hash->hashSet->size;
718	for (i = 0; i < oldSize; i++)
719	{
720	    glyph = hash->table[i].glyph;
721	    if (glyph && glyph != DeletedGlyph)
722	    {
723		s = hash->table[i].signature;
724		gr = FindGlyphRef (&newHash, s, global, glyph);
725		gr->signature = s;
726		gr->glyph = glyph;
727		++newHash.tableEntries;
728	    }
729	}
730	xfree (hash->table);
731    }
732    *hash = newHash;
733    if (global)
734	CheckDuplicates (hash, "ResizeGlyphHash bottom");
735    return TRUE;
736}
737
738Bool
739ResizeGlyphSet (GlyphSetPtr glyphSet, CARD32 change)
740{
741    return (ResizeGlyphHash (&glyphSet->hash, change, FALSE) &&
742	    ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], change, TRUE));
743}
744
745GlyphSetPtr
746AllocateGlyphSet (int fdepth, PictFormatPtr format)
747{
748    GlyphSetPtr	glyphSet;
749    int size;
750
751    if (!globalGlyphs[fdepth].hashSet)
752    {
753	if (!AllocateGlyphHash (&globalGlyphs[fdepth], &glyphHashSets[0]))
754	    return FALSE;
755    }
756
757    size = (sizeof (GlyphSetRec) +
758	    (sizeof (pointer) * _GlyphSetPrivateAllocateIndex));
759    glyphSet = xalloc (size);
760    if (!glyphSet)
761	return FALSE;
762    bzero((char *)glyphSet, size);
763    glyphSet->maxPrivate = _GlyphSetPrivateAllocateIndex - 1;
764    if (_GlyphSetPrivateAllocateIndex)
765	glyphSet->devPrivates = (pointer)(&glyphSet[1]);
766
767    if (!AllocateGlyphHash (&glyphSet->hash, &glyphHashSets[0]))
768    {
769	xfree (glyphSet);
770	return FALSE;
771    }
772    glyphSet->refcnt = 1;
773    glyphSet->fdepth = fdepth;
774    glyphSet->format = format;
775    return glyphSet;
776}
777
778int
779FreeGlyphSet (pointer	value,
780	      XID       gid)
781{
782    GlyphSetPtr	glyphSet = (GlyphSetPtr) value;
783
784    if (--glyphSet->refcnt == 0)
785    {
786	CARD32	    i, tableSize = glyphSet->hash.hashSet->size;
787	GlyphRefPtr table = glyphSet->hash.table;
788	GlyphPtr    glyph;
789
790	for (i = 0; i < tableSize; i++)
791	{
792	    glyph = table[i].glyph;
793	    if (glyph && glyph != DeletedGlyph)
794		FreeGlyph (glyph, glyphSet->fdepth);
795	}
796	if (!globalGlyphs[glyphSet->fdepth].tableEntries)
797	{
798	    xfree (globalGlyphs[glyphSet->fdepth].table);
799	    globalGlyphs[glyphSet->fdepth].table = 0;
800	    globalGlyphs[glyphSet->fdepth].hashSet = 0;
801	}
802	else
803	    ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], 0, TRUE);
804	xfree (table);
805
806	if (glyphSet->devPrivates &&
807	    glyphSet->devPrivates != (pointer)(&glyphSet[1]))
808	    xfree(glyphSet->devPrivates);
809
810	xfree (glyphSet);
811    }
812    return Success;
813}
814