Imported Upstream version 1.11.4
[ubuntu-omap:xserver.git] / render / glyph.c
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  */
53 static 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  (sizeof(glyphHashSets)/sizeof(glyphHashSets[0]))
82
83 static const CARD8      glyphDepths[GlyphFormatNum] = { 1, 4, 8, 16, 32 };
84
85 static GlyphHashRec     globalGlyphs[GlyphFormatNum];
86
87 void
88 GlyphUninit (ScreenPtr pScreen)
89 {
90     PictureScreenPtr ps = GetPictureScreen (pScreen);
91     GlyphPtr         glyph;
92     int              fdepth, i;
93     int              scrno = pScreen->myNum;
94
95     for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++)
96     {
97         if (!globalGlyphs[fdepth].hashSet)
98             continue;
99         
100         for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++)
101         {
102             glyph = globalGlyphs[fdepth].table[i].glyph;
103             if (glyph && glyph != DeletedGlyph)
104             {
105                 if (GlyphPicture(glyph)[scrno])
106                 {
107                     FreePicture ((pointer) GlyphPicture (glyph)[scrno], 0);
108                     GlyphPicture(glyph)[scrno] = NULL;
109                 }
110                 (*ps->UnrealizeGlyph) (pScreen, glyph);
111             }
112         }
113     }
114 }
115
116 GlyphHashSetPtr
117 FindGlyphHashSet (CARD32 filled)
118 {
119     int i;
120
121     for (i = 0; i < NGLYPHHASHSETS; i++)
122         if (glyphHashSets[i].entries >= filled)
123             return &glyphHashSets[i];
124     return 0;
125 }
126
127 GlyphRefPtr
128 FindGlyphRef (GlyphHashPtr      hash,
129               CARD32            signature,
130               Bool              match,
131               unsigned char     sha1[20])
132 {
133     CARD32      elt, step, s;
134     GlyphPtr    glyph;
135     GlyphRefPtr table, gr, del;
136     CARD32      tableSize = hash->hashSet->size;
137
138     table = hash->table;
139     elt = signature % tableSize;
140     step = 0;
141     del = 0;
142     for (;;)
143     {
144         gr = &table[elt];
145         s = gr->signature;
146         glyph = gr->glyph;
147         if (!glyph)
148         {
149             if (del)
150                 gr = del;
151             break;
152         }
153         if (glyph == DeletedGlyph)
154         {
155             if (!del)
156                 del = gr;
157             else if (gr == del)
158                 break;
159         }
160         else if (s == signature &&
161                  (!match || 
162                   memcmp (glyph->sha1, sha1, 20) == 0))
163         {
164             break;
165         }
166         if (!step)
167         {
168             step = signature % hash->hashSet->rehash;
169             if (!step)
170                 step = 1;
171         }
172         elt += step;
173         if (elt >= tableSize)
174             elt -= tableSize;
175     }
176     return gr;
177 }
178
179 int
180 HashGlyph (xGlyphInfo    *gi,
181            CARD8         *bits,
182            unsigned long size,
183            unsigned char sha1[20])
184 {
185     void *ctx = x_sha1_init();
186     int success;
187
188     if (!ctx)
189         return BadAlloc;
190
191     success = x_sha1_update(ctx, gi, sizeof(xGlyphInfo));
192     if (!success)
193         return BadAlloc;
194     success = x_sha1_update(ctx, bits, size);
195     if (!success)
196         return BadAlloc;
197     success = x_sha1_final(ctx, sha1);
198     if (!success)
199         return BadAlloc;
200     return Success;
201 }
202
203 GlyphPtr
204 FindGlyphByHash (unsigned char sha1[20], int format)
205 {
206     GlyphRefPtr gr;
207     CARD32 signature = *(CARD32 *) sha1;
208
209     if (!globalGlyphs[format].hashSet)
210         return NULL;
211
212     gr = FindGlyphRef (&globalGlyphs[format],
213                        signature, TRUE, sha1);
214
215     if (gr->glyph && gr->glyph != DeletedGlyph)
216         return gr->glyph;
217     else
218         return NULL;
219 }
220
221 #ifdef CHECK_DUPLICATES
222 void
223 DuplicateRef (GlyphPtr glyph, char *where)
224 {
225     ErrorF ("Duplicate Glyph 0x%x from %s\n", glyph, where);
226 }
227
228 void
229 CheckDuplicates (GlyphHashPtr hash, char *where)
230 {
231     GlyphPtr    g;
232     int         i, j;
233
234     for (i = 0; i < hash->hashSet->size; i++)
235     {
236         g = hash->table[i].glyph;
237         if (!g || g == DeletedGlyph)
238             continue;
239         for (j = i + 1; j < hash->hashSet->size; j++)
240             if (hash->table[j].glyph == g)
241                 DuplicateRef (g, where);
242     }
243 }
244 #else
245 #define CheckDuplicates(a,b)
246 #define DuplicateRef(a,b)
247 #endif
248
249 static void
250 FreeGlyphPicture(GlyphPtr glyph)
251 {
252     PictureScreenPtr ps;
253     int i;
254
255     for (i = 0; i < screenInfo.numScreens; i++)
256     {
257         ScreenPtr pScreen = screenInfo.screens[i];
258
259         if (GlyphPicture(glyph)[i])
260             FreePicture ((pointer) GlyphPicture (glyph)[i], 0);
261
262         ps = GetPictureScreenIfSet (pScreen);
263         if (ps)
264             (*ps->UnrealizeGlyph) (pScreen, glyph);
265     }
266 }
267
268
269 void
270 FreeGlyph (GlyphPtr glyph, int format)
271 {
272     CheckDuplicates (&globalGlyphs[format], "FreeGlyph");
273     if (--glyph->refcnt == 0)
274     {
275         GlyphRefPtr      gr;
276         int              i;
277         int              first;
278         CARD32           signature;
279
280         first = -1;
281         for (i = 0; i < globalGlyphs[format].hashSet->size; i++)
282             if (globalGlyphs[format].table[i].glyph == glyph)
283             {
284                 if (first != -1)
285                     DuplicateRef (glyph, "FreeGlyph check");
286                 first = i;
287             }
288
289         signature = *(CARD32 *) glyph->sha1;
290         gr = FindGlyphRef (&globalGlyphs[format], signature,
291                            TRUE, glyph->sha1);
292         if (gr - globalGlyphs[format].table != first)
293             DuplicateRef (glyph, "Found wrong one");
294         if (gr->glyph && gr->glyph != DeletedGlyph)
295         {
296             gr->glyph = DeletedGlyph;
297             gr->signature = 0;
298             globalGlyphs[format].tableEntries--;
299         }
300
301         FreeGlyphPicture(glyph);
302         dixFreeObjectWithPrivates(glyph, PRIVATE_GLYPH);
303     }
304 }
305
306 void
307 AddGlyph (GlyphSetPtr glyphSet, GlyphPtr glyph, Glyph id)
308 {
309     GlyphRefPtr     gr;
310     CARD32          signature;
311
312     CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph top global");
313     /* Locate existing matching glyph */
314     signature = *(CARD32 *) glyph->sha1;
315     gr = FindGlyphRef (&globalGlyphs[glyphSet->fdepth], signature,
316                        TRUE, glyph->sha1);
317     if (gr->glyph && gr->glyph != DeletedGlyph && gr->glyph != glyph)
318     {
319         FreeGlyphPicture(glyph);
320         dixFreeObjectWithPrivates(glyph, PRIVATE_GLYPH);
321         glyph = gr->glyph;
322     }
323     else if (gr->glyph != glyph)
324     {
325         gr->glyph = glyph;
326         gr->signature = signature;
327         globalGlyphs[glyphSet->fdepth].tableEntries++;
328     }
329     
330     /* Insert/replace glyphset value */
331     gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0);
332     ++glyph->refcnt;
333     if (gr->glyph && gr->glyph != DeletedGlyph)
334         FreeGlyph (gr->glyph, glyphSet->fdepth);
335     else
336         glyphSet->hash.tableEntries++;
337     gr->glyph = glyph;
338     gr->signature = id;
339     CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph bottom");
340 }
341
342 Bool
343 DeleteGlyph (GlyphSetPtr glyphSet, Glyph id)
344 {
345     GlyphRefPtr     gr;
346     GlyphPtr        glyph;
347
348     gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0);
349     glyph = gr->glyph;
350     if (glyph && glyph != DeletedGlyph)
351     {
352         gr->glyph = DeletedGlyph;
353         glyphSet->hash.tableEntries--;
354         FreeGlyph (glyph, glyphSet->fdepth);
355         return TRUE;
356     }
357     return FALSE;
358 }
359
360 GlyphPtr
361 FindGlyph (GlyphSetPtr glyphSet, Glyph id)
362 {
363     GlyphPtr        glyph;
364
365     glyph = FindGlyphRef (&glyphSet->hash, id, FALSE, 0)->glyph;
366     if (glyph == DeletedGlyph)
367         glyph = 0;
368     return glyph;
369 }
370
371 GlyphPtr
372 AllocateGlyph (xGlyphInfo *gi, int fdepth)
373 {
374     PictureScreenPtr ps;
375     int              size;
376     GlyphPtr         glyph;
377     int              i;
378     int              head_size;
379
380     head_size = sizeof (GlyphRec) + screenInfo.numScreens * sizeof (PicturePtr);
381     size = (head_size + dixPrivatesSize(PRIVATE_GLYPH));
382     glyph = (GlyphPtr) malloc (size);
383     if (!glyph)
384         return 0;
385     glyph->refcnt = 0;
386     glyph->size = size + sizeof (xGlyphInfo);
387     glyph->info = *gi;
388     dixInitPrivates(glyph, (char *) glyph + head_size, PRIVATE_GLYPH);
389
390     for (i = 0; i < screenInfo.numScreens; i++)
391     {
392         GlyphPicture(glyph)[i] = NULL;
393         ps = GetPictureScreenIfSet (screenInfo.screens[i]);
394
395         if (ps)
396         {
397             if (!(*ps->RealizeGlyph) (screenInfo.screens[i], glyph))
398                 goto bail;
399         }
400     }
401     
402     return glyph;
403
404 bail:
405     while (i--)
406     {
407         ps = GetPictureScreenIfSet (screenInfo.screens[i]);
408         if (ps)
409             (*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph);
410     }
411
412     dixFreeObjectWithPrivates(glyph, PRIVATE_GLYPH);
413     return 0;
414 }
415     
416 Bool
417 AllocateGlyphHash (GlyphHashPtr hash, GlyphHashSetPtr hashSet)
418 {
419     hash->table = calloc(hashSet->size, sizeof (GlyphRefRec));
420     if (!hash->table)
421         return FALSE;
422     hash->hashSet = hashSet;
423     hash->tableEntries = 0;
424     return TRUE;
425 }
426
427 Bool
428 ResizeGlyphHash (GlyphHashPtr hash, CARD32 change, Bool global)
429 {
430     CARD32          tableEntries;
431     GlyphHashSetPtr hashSet;
432     GlyphHashRec    newHash;
433     GlyphRefPtr     gr;
434     GlyphPtr        glyph;
435     int             i;
436     int             oldSize;
437     CARD32          s;
438
439     tableEntries = hash->tableEntries + change;
440     hashSet = FindGlyphHashSet (tableEntries);
441     if (hashSet == hash->hashSet)
442         return TRUE;
443     if (global)
444         CheckDuplicates (hash, "ResizeGlyphHash top");
445     if (!AllocateGlyphHash (&newHash, hashSet))
446         return FALSE;
447     if (hash->table)
448     {
449         oldSize = hash->hashSet->size;
450         for (i = 0; i < oldSize; i++)
451         {
452             glyph = hash->table[i].glyph;
453             if (glyph && glyph != DeletedGlyph)
454             {
455                 s = hash->table[i].signature;
456                 gr = FindGlyphRef (&newHash, s, global, glyph->sha1);
457                 gr->signature = s;
458                 gr->glyph = glyph;
459                 ++newHash.tableEntries;
460             }
461         }
462         free(hash->table);
463     }
464     *hash = newHash;
465     if (global)
466         CheckDuplicates (hash, "ResizeGlyphHash bottom");
467     return TRUE;
468 }
469
470 Bool
471 ResizeGlyphSet (GlyphSetPtr glyphSet, CARD32 change)
472 {
473     return (ResizeGlyphHash (&glyphSet->hash, change, FALSE) &&
474             ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], change, TRUE));
475 }
476                             
477 GlyphSetPtr
478 AllocateGlyphSet (int fdepth, PictFormatPtr format)
479 {
480     GlyphSetPtr glyphSet;
481     
482     if (!globalGlyphs[fdepth].hashSet)
483     {
484         if (!AllocateGlyphHash (&globalGlyphs[fdepth], &glyphHashSets[0]))
485             return FALSE;
486     }
487
488     glyphSet = dixAllocateObjectWithPrivates(GlyphSetRec, PRIVATE_GLYPHSET);
489     if (!glyphSet)
490         return FALSE;
491
492     if (!AllocateGlyphHash (&glyphSet->hash, &glyphHashSets[0]))
493     {
494         free(glyphSet);
495         return FALSE;
496     }
497     glyphSet->refcnt = 1;
498     glyphSet->fdepth = fdepth;
499     glyphSet->format = format;
500     return glyphSet;    
501 }
502
503 int
504 FreeGlyphSet (pointer   value,
505               XID       gid)
506 {
507     GlyphSetPtr glyphSet = (GlyphSetPtr) value;
508     
509     if (--glyphSet->refcnt == 0)
510     {
511         CARD32      i, tableSize = glyphSet->hash.hashSet->size;
512         GlyphRefPtr table = glyphSet->hash.table;
513         GlyphPtr    glyph;
514     
515         for (i = 0; i < tableSize; i++)
516         {
517             glyph = table[i].glyph;
518             if (glyph && glyph != DeletedGlyph)
519                 FreeGlyph (glyph, glyphSet->fdepth);
520         }
521         if (!globalGlyphs[glyphSet->fdepth].tableEntries)
522         {
523             free(globalGlyphs[glyphSet->fdepth].table);
524             globalGlyphs[glyphSet->fdepth].table = 0;
525             globalGlyphs[glyphSet->fdepth].hashSet = 0;
526         }
527         else
528             ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], 0, TRUE);
529         free(table);
530         dixFreeObjectWithPrivates(glyphSet, PRIVATE_GLYPHSET);
531     }
532     return Success;
533 }
534
535 static void
536 GlyphExtents (int               nlist,
537                 GlyphListPtr    list,
538                 GlyphPtr        *glyphs,
539                 BoxPtr          extents)
540 {
541     int         x1, x2, y1, y2;
542     int         n;
543     GlyphPtr    glyph;
544     int         x, y;
545     
546     x = 0;
547     y = 0;
548     extents->x1 = MAXSHORT;
549     extents->x2 = MINSHORT;
550     extents->y1 = MAXSHORT;
551     extents->y2 = MINSHORT;
552     while (nlist--)
553     {
554         x += list->xOff;
555         y += list->yOff;
556         n = list->len;
557         list++;
558         while (n--)
559         {
560             glyph = *glyphs++;
561             x1 = x - glyph->info.x;
562             if (x1 < MINSHORT)
563                 x1 = MINSHORT;
564             y1 = y - glyph->info.y;
565             if (y1 < MINSHORT)
566                 y1 = MINSHORT;
567             x2 = x1 + glyph->info.width;
568             if (x2 > MAXSHORT)
569                 x2 = MAXSHORT;
570             y2 = y1 + glyph->info.height;
571             if (y2 > MAXSHORT)
572                 y2 = MAXSHORT;
573             if (x1 < extents->x1)
574                 extents->x1 = x1;
575             if (x2 > extents->x2)
576                 extents->x2 = x2;
577             if (y1 < extents->y1)
578                 extents->y1 = y1;
579             if (y2 > extents->y2)
580                 extents->y2 = y2;
581             x += glyph->info.xOff;
582             y += glyph->info.yOff;
583         }
584     }
585 }
586
587 #define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
588
589 void
590 CompositeGlyphs (CARD8          op,
591                  PicturePtr     pSrc,
592                  PicturePtr     pDst,
593                  PictFormatPtr  maskFormat,
594                  INT16          xSrc,
595                  INT16          ySrc,
596                  int            nlist,
597                  GlyphListPtr   lists,
598                  GlyphPtr       *glyphs)
599 {
600     PictureScreenPtr    ps = GetPictureScreen(pDst->pDrawable->pScreen);
601
602     ValidatePicture (pSrc);
603     ValidatePicture (pDst);
604     (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, lists, glyphs);
605 }
606
607 Bool
608 miRealizeGlyph (ScreenPtr pScreen,
609                 GlyphPtr  glyph)
610 {
611     return TRUE;
612 }
613
614 void
615 miUnrealizeGlyph (ScreenPtr pScreen,
616                   GlyphPtr  glyph)
617 {
618 }
619
620 void
621 miGlyphs (CARD8         op,
622           PicturePtr    pSrc,
623           PicturePtr    pDst,
624           PictFormatPtr maskFormat,
625           INT16         xSrc,
626           INT16         ySrc,
627           int           nlist,
628           GlyphListPtr  list,
629           GlyphPtr      *glyphs)
630 {
631     PicturePtr  pPicture;
632     PixmapPtr   pMaskPixmap = 0;
633     PicturePtr  pMask;
634     ScreenPtr   pScreen = pDst->pDrawable->pScreen;
635     int         width = 0, height = 0;
636     int         x, y;
637     int         xDst = list->xOff, yDst = list->yOff;
638     int         n;
639     GlyphPtr    glyph;
640     int         error;
641     BoxRec      extents = {0, 0, 0, 0};
642     CARD32      component_alpha;
643
644     if (maskFormat)
645     {
646         GCPtr       pGC;
647         xRectangle  rect;
648
649         GlyphExtents (nlist, list, glyphs, &extents);
650
651         if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
652             return;
653         width = extents.x2 - extents.x1;
654         height = extents.y2 - extents.y1;
655         pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
656                                                 maskFormat->depth,
657                                                 CREATE_PIXMAP_USAGE_SCRATCH);
658         if (!pMaskPixmap)
659             return;
660         component_alpha = NeedsComponent(maskFormat->format);
661         pMask = CreatePicture (0, &pMaskPixmap->drawable,
662                                maskFormat, CPComponentAlpha, &component_alpha,
663                                serverClient, &error);
664         if (!pMask)
665         {
666             (*pScreen->DestroyPixmap) (pMaskPixmap);
667             return;
668         }
669         pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
670         ValidateGC (&pMaskPixmap->drawable, pGC);
671         rect.x = 0;
672         rect.y = 0;
673         rect.width = width;
674         rect.height = height;
675         (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
676         FreeScratchGC (pGC);
677         x = -extents.x1;
678         y = -extents.y1;
679     }
680     else
681     {
682         pMask = pDst;
683         x = 0;
684         y = 0;
685     }
686     while (nlist--)
687     {
688         x += list->xOff;
689         y += list->yOff;
690         n = list->len;
691         while (n--)
692         {
693             glyph = *glyphs++;
694             pPicture = GlyphPicture (glyph)[pScreen->myNum];
695
696             if (pPicture)
697             {
698                 if (maskFormat)
699                 {
700                         CompositePicture (PictOpAdd,
701                                           pPicture,
702                                           None,
703                                           pMask,
704                                           0, 0,
705                                           0, 0,
706                                           x - glyph->info.x,
707                                           y - glyph->info.y,
708                                           glyph->info.width,
709                                           glyph->info.height);
710                 }
711                 else
712                 {
713                     CompositePicture (op,
714                                       pSrc,
715                                       pPicture,
716                                       pDst,
717                                       xSrc + (x - glyph->info.x) - xDst,
718                                       ySrc + (y - glyph->info.y) - yDst,
719                                       0, 0,
720                                       x - glyph->info.x,
721                                       y - glyph->info.y,
722                                       glyph->info.width,
723                                       glyph->info.height);
724                 }
725             }
726
727             x += glyph->info.xOff;
728             y += glyph->info.yOff;
729         }
730         list++;
731     }
732     if (maskFormat)
733     {
734         x = extents.x1;
735         y = extents.y1;
736         CompositePicture (op,
737                           pSrc,
738                           pMask,
739                           pDst,
740                           xSrc + x - xDst,
741                           ySrc + y - yDst,
742                           0, 0,
743                           x, y,
744                           width, height);
745         FreePicture ((pointer) pMask, (XID) 0);
746         (*pScreen->DestroyPixmap) (pMaskPixmap);
747     }
748 }