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