Imported Upstream version 1.11.4
[ubuntu-omap:xserver.git] / exa / exa_glyphs.c
1 /*
2  * Copyright © 2008 Red Hat, Inc.
3  * Partly based on code 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 Red Hat not be used in advertising or
10  * publicity pertaining to distribution of the software without specific,
11  * written prior permission.  Red Hat 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  * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
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  * Permission to use, copy, modify, distribute, and sell this software and its
23  * documentation for any purpose is hereby granted without fee, provided that
24  * the above copyright notice appear in all copies and that both that
25  * copyright notice and this permission notice appear in supporting
26  * documentation, and that the name of SuSE not be used in advertising or
27  * publicity pertaining to distribution of the software without specific,
28  * written prior permission.  SuSE makes no representations about the
29  * suitability of this software for any purpose.  It is provided "as is"
30  * without express or implied warranty.
31  *
32  * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
33  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
34  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
35  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
36  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
37  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
38  *
39  * Author: Owen Taylor <otaylor@fishsoup.net>
40  * Based on code by: Keith Packard
41  */
42
43 #ifdef HAVE_DIX_CONFIG_H
44 #include <dix-config.h>
45 #endif
46
47 #include <stdlib.h>
48
49 #include "exa_priv.h"
50
51 #include "mipict.h"
52
53 #if DEBUG_GLYPH_CACHE
54 #define DBG_GLYPH_CACHE(a) ErrorF a
55 #else
56 #define DBG_GLYPH_CACHE(a)
57 #endif
58
59 /* Width of the pixmaps we use for the caches; this should be less than
60  * max texture size of the driver; this may need to actually come from
61  * the driver.
62  */
63 #define CACHE_PICTURE_WIDTH 1024
64
65 /* Maximum number of glyphs we buffer on the stack before flushing
66  * rendering to the mask or destination surface.
67  */
68 #define GLYPH_BUFFER_SIZE 256
69
70 typedef struct {
71     PicturePtr mask;
72     ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE];
73     int count;
74 } ExaGlyphBuffer, *ExaGlyphBufferPtr;
75
76 typedef enum {
77     ExaGlyphSuccess,    /* Glyph added to render buffer */
78     ExaGlyphFail,       /* out of memory, etc */
79     ExaGlyphNeedFlush,  /* would evict a glyph already in the buffer */
80 } ExaGlyphCacheResult;
81
82 void
83 exaGlyphsInit(ScreenPtr pScreen)
84 {
85     ExaScreenPriv(pScreen);
86     int i = 0;
87
88     memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches));
89
90     pExaScr->glyphCaches[i].format = PICT_a8;
91     pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16;
92     i++;
93     pExaScr->glyphCaches[i].format = PICT_a8;
94     pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32;
95     i++;
96     pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
97     pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16;
98     i++;
99     pExaScr->glyphCaches[i].format = PICT_a8r8g8b8;
100     pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32;
101     i++;
102
103     assert(i == EXA_NUM_GLYPH_CACHES);
104     
105     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
106         pExaScr->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth;
107         pExaScr->glyphCaches[i].size = 256;
108         pExaScr->glyphCaches[i].hashSize = 557;
109     }
110 }
111
112 static void
113 exaUnrealizeGlyphCaches(ScreenPtr    pScreen,
114                         unsigned int format)
115 {
116     ExaScreenPriv(pScreen);
117     int i;
118
119     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
120         ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
121         
122         if (cache->format != format)
123             continue;
124
125         if (cache->picture) {
126             FreePicture ((pointer) cache->picture, (XID) 0);
127             cache->picture = NULL;
128         }
129
130         free(cache->hashEntries);
131         cache->hashEntries = NULL;
132         
133         free(cache->glyphs);
134         cache->glyphs = NULL;
135         cache->glyphCount = 0;
136     }
137 }
138
139 #define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
140
141 /* All caches for a single format share a single pixmap for glyph storage,
142  * allowing mixing glyphs of different sizes without paying a penalty
143  * for switching between mask pixmaps. (Note that for a size of font
144  * right at the border between two sizes, we might be switching for almost
145  * every glyph.)
146  *
147  * This function allocates the storage pixmap, and then fills in the
148  * rest of the allocated structures for all caches with the given format.
149  */
150 static Bool
151 exaRealizeGlyphCaches(ScreenPtr    pScreen,
152                       unsigned int format)
153 {
154     ExaScreenPriv(pScreen);
155
156     int depth = PIXMAN_FORMAT_DEPTH(format);
157     PictFormatPtr pPictFormat;
158     PixmapPtr pPixmap;
159     PicturePtr pPicture;
160     CARD32 component_alpha;
161     int height;
162     int i;
163     int error;
164
165     pPictFormat = PictureMatchFormat(pScreen, depth, format);
166     if (!pPictFormat)
167         return FALSE;
168     
169     /* Compute the total vertical size needed for the format */
170
171     height = 0;
172     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
173         ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
174         int rows;
175
176         if (cache->format != format)
177             continue;
178
179         cache->yOffset = height;
180
181         rows = (cache->size + cache->columns - 1) / cache->columns;
182         height += rows * cache->glyphHeight;
183     }
184
185     /* Now allocate the pixmap and picture */
186     pPixmap = (*pScreen->CreatePixmap) (pScreen,
187                                         CACHE_PICTURE_WIDTH,
188                                         height, depth, 0);
189     if (!pPixmap)
190         return FALSE;
191
192     component_alpha = NeedsComponent(pPictFormat->format);
193     pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat,
194                              CPComponentAlpha, &component_alpha, serverClient,
195                              &error);
196
197     (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */
198
199     if (!pPicture)
200         return FALSE;
201
202     /* And store the picture in all the caches for the format */
203     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
204         ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
205         int j;
206
207         if (cache->format != format)
208             continue;
209
210         cache->picture = pPicture;
211         cache->picture->refcnt++;
212         cache->hashEntries = malloc(sizeof(int) * cache->hashSize);
213         cache->glyphs = malloc(sizeof(ExaCachedGlyphRec) * cache->size);
214         cache->glyphCount = 0;
215
216         if (!cache->hashEntries || !cache->glyphs)
217             goto bail;
218
219         for (j = 0; j < cache->hashSize; j++)
220             cache->hashEntries[j] = -1;
221         
222         cache->evictionPosition = rand() % cache->size;
223     }
224
225     /* Each cache references the picture individually */
226     FreePicture ((pointer) pPicture, (XID) 0);
227     return TRUE;
228
229 bail:
230     exaUnrealizeGlyphCaches(pScreen, format);
231     return FALSE;
232 }
233
234 void
235 exaGlyphsFini (ScreenPtr pScreen)
236 {
237     ExaScreenPriv(pScreen);
238     int i;
239
240     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
241         ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
242
243         if (cache->picture)
244             exaUnrealizeGlyphCaches(pScreen, cache->format);
245     }
246 }
247
248 static int
249 exaGlyphCacheHashLookup(ExaGlyphCachePtr cache,
250                         GlyphPtr         pGlyph)
251 {
252     int slot;
253
254     slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
255     
256     while (TRUE) { /* hash table can never be full */
257         int entryPos = cache->hashEntries[slot];
258         if (entryPos == -1)
259             return -1;
260
261         if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){
262             return entryPos;
263         }
264             
265         slot--;
266         if (slot < 0)
267             slot = cache->hashSize - 1;
268     }
269 }
270
271 static void
272 exaGlyphCacheHashInsert(ExaGlyphCachePtr cache,
273                         GlyphPtr         pGlyph,
274                         int              pos)
275 {
276     int slot;
277
278     memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1));
279     
280     slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize;
281     
282     while (TRUE) { /* hash table can never be full */
283         if (cache->hashEntries[slot] == -1) {
284             cache->hashEntries[slot] = pos;
285             return;
286         }
287             
288         slot--;
289         if (slot < 0)
290             slot = cache->hashSize - 1;
291     }
292 }
293
294 static void
295 exaGlyphCacheHashRemove(ExaGlyphCachePtr cache,
296                         int              pos)
297 {
298     int slot;
299     int emptiedSlot = -1;
300
301     slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize;
302
303     while (TRUE) { /* hash table can never be full */
304         int entryPos = cache->hashEntries[slot];
305         
306         if (entryPos == -1)
307             return;
308
309         if (entryPos == pos) {
310             cache->hashEntries[slot] = -1;
311             emptiedSlot = slot;
312         } else if (emptiedSlot != -1) {
313             /* See if we can move this entry into the emptied slot, we can't
314              * do that if if entry would have hashed between the current position
315              * and the emptied slot. (taking wrapping into account). Bad positions
316              * are:
317              *
318              * |   XXXXXXXXXX             |
319              *     i         j            
320              *                            
321              * |XXX                   XXXX|
322              *     j                  i
323              *
324              * i - slot, j - emptiedSlot
325              *
326              * (Knuth 6.4R)
327              */
328             
329             int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize;
330
331             if (!((entrySlot >= slot && entrySlot < emptiedSlot) ||
332                   (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot)))) 
333             {
334                 cache->hashEntries[emptiedSlot] = entryPos;
335                 cache->hashEntries[slot] = -1;
336                 emptiedSlot = slot;
337             }
338         }
339         
340         slot--;
341         if (slot < 0)
342             slot = cache->hashSize - 1;
343     }
344 }
345
346 #define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth)
347 #define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight)
348
349 /* The most efficient thing to way to upload the glyph to the screen
350  * is to use the UploadToScreen() driver hook; this allows us to
351  * pipeline glyph uploads and to avoid creating gpu backed pixmaps for
352  * glyphs that we'll never use again.
353  *
354  * If we can't do it with UploadToScreen (because the glyph has a gpu copy,
355  * etc), we fall back to CompositePicture.
356  *
357  * We need to damage the cache pixmap manually in either case because the damage
358  * layer unwrapped the picture screen before calling exaGlyphs.
359  */
360 static void
361 exaGlyphCacheUploadGlyph(ScreenPtr         pScreen,
362                          ExaGlyphCachePtr  cache,
363                          int               x,
364                          int               y,
365                          GlyphPtr          pGlyph)
366 {
367     ExaScreenPriv(pScreen);
368     PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum];
369     PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable;
370     ExaPixmapPriv(pGlyphPixmap);
371     PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable;
372
373     if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut || pExaPixmap->accel_blocked)
374         goto composite;
375
376     /* If the glyph pixmap is already uploaded, no point in doing
377      * things this way */
378     if (exaPixmapHasGpuCopy(pGlyphPixmap))
379         goto composite;
380
381     /* UploadToScreen only works if bpp match */
382     if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel)
383         goto composite;
384
385     if (pExaScr->do_migration) {
386         ExaMigrationRec pixmaps[1];
387
388         /* cache pixmap must have a gpu copy. */
389         pixmaps[0].as_dst = TRUE;
390         pixmaps[0].as_src = FALSE;
391         pixmaps[0].pPix = pCachePixmap;
392         pixmaps[0].pReg = NULL;
393         exaDoMigration (pixmaps, 1, TRUE);
394     }
395
396     if (!exaPixmapHasGpuCopy(pCachePixmap))
397         goto composite;
398
399     /* x,y are in pixmap coordinates, no need for cache{X,Y}off */
400     if (pExaScr->info->UploadToScreen(pCachePixmap,
401                                       x,
402                                       y,
403                                       pGlyph->info.width,
404                                       pGlyph->info.height,
405                                       (char *)pExaPixmap->sys_ptr,
406                                       pExaPixmap->sys_pitch))
407         goto damage;
408
409 composite:
410     CompositePicture (PictOpSrc,
411                       pGlyphPicture,
412                       None,
413                       cache->picture,
414                       0, 0,
415                       0, 0,
416                       x,
417                       y,
418                       pGlyph->info.width,
419                       pGlyph->info.height);
420
421 damage:
422     /* The cache pixmap isn't a window, so no need to offset coordinates. */
423     exaPixmapDirty (pCachePixmap,
424                     x,
425                     y,
426                     x + cache->glyphWidth,
427                     y + cache->glyphHeight);
428 }
429
430 static ExaGlyphCacheResult
431 exaGlyphCacheBufferGlyph(ScreenPtr         pScreen,
432                          ExaGlyphCachePtr  cache,
433                          ExaGlyphBufferPtr buffer,
434                          GlyphPtr          pGlyph,
435                          PicturePtr        pSrc,
436                          PicturePtr        pDst,
437                          INT16             xSrc,
438                          INT16             ySrc,
439                          INT16             xMask,
440                          INT16             yMask,
441                          INT16             xDst,
442                          INT16             yDst)
443 {
444     ExaCompositeRectPtr rect;
445     int pos;
446     int x, y;
447     
448     if (buffer->mask && buffer->mask != cache->picture)
449         return ExaGlyphNeedFlush;
450
451     if (!cache->picture) {
452         if (!exaRealizeGlyphCaches(pScreen, cache->format))
453             return ExaGlyphFail;
454     }
455
456     DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n",
457                      cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB",
458                      (long)*(CARD32 *) pGlyph->sha1));
459    
460     pos = exaGlyphCacheHashLookup(cache, pGlyph);
461     if (pos != -1) {
462         DBG_GLYPH_CACHE(("  found existing glyph at %d\n", pos));
463         x = CACHE_X(pos);
464         y = CACHE_Y(pos);
465     } else {
466         if (cache->glyphCount < cache->size) {
467             /* Space remaining; we fill from the start */
468             pos = cache->glyphCount;
469             x = CACHE_X(pos);
470             y = CACHE_Y(pos);
471             cache->glyphCount++;
472             DBG_GLYPH_CACHE(("  storing glyph in free space at %d\n", pos));
473
474             exaGlyphCacheHashInsert(cache, pGlyph, pos);
475
476         } else {
477             /* Need to evict an entry. We have to see if any glyphs
478              * already in the output buffer were at this position in
479              * the cache
480              */
481             pos = cache->evictionPosition;
482             x = CACHE_X(pos);
483             y = CACHE_Y(pos);
484             DBG_GLYPH_CACHE(("  evicting glyph at %d\n", pos));
485             if (buffer->count) {
486                 int i;
487
488                 for (i = 0; i < buffer->count; i++) {
489                     if (pSrc ?
490                         (buffer->rects[i].xMask == x && buffer->rects[i].yMask == y) :
491                         (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y)) {
492                         DBG_GLYPH_CACHE(("  must flush buffer\n"));
493                         return ExaGlyphNeedFlush;
494                     }
495                 }
496             }
497
498             /* OK, we're all set, swap in the new glyph */
499             exaGlyphCacheHashRemove(cache, pos);
500             exaGlyphCacheHashInsert(cache, pGlyph, pos);
501
502             /* And pick a new eviction position */
503             cache->evictionPosition = rand() % cache->size;
504         }
505
506         exaGlyphCacheUploadGlyph(pScreen, cache, x, y, pGlyph);
507     }
508
509     buffer->mask = cache->picture;
510             
511     rect = &buffer->rects[buffer->count];
512
513     if (pSrc)
514     {
515         rect->xSrc = xSrc;
516         rect->ySrc = ySrc;
517         rect->xMask = x;
518         rect->yMask = y;
519     }
520     else
521     {
522         rect->xSrc = x;
523         rect->ySrc = y;
524         rect->xMask = 0;
525         rect->yMask = 0;
526     }
527
528     rect->pDst = pDst;
529     rect->xDst = xDst;
530     rect->yDst = yDst;
531     rect->width = pGlyph->info.width;
532     rect->height = pGlyph->info.height;
533
534     buffer->count++;
535
536     return ExaGlyphSuccess;
537 }
538
539 #undef CACHE_X
540 #undef CACHE_Y
541
542 static ExaGlyphCacheResult
543 exaBufferGlyph(ScreenPtr         pScreen,
544                ExaGlyphBufferPtr buffer,
545                GlyphPtr          pGlyph,
546                PicturePtr        pSrc,
547                PicturePtr        pDst,
548                INT16             xSrc,
549                INT16             ySrc,
550                INT16             xMask,
551                INT16             yMask,
552                INT16             xDst,
553                INT16             yDst)
554 {
555     ExaScreenPriv(pScreen);
556     unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format;
557     int width = pGlyph->info.width;
558     int height = pGlyph->info.height;
559     ExaCompositeRectPtr rect;
560     PicturePtr mask;
561     int i;
562
563     if (buffer->count == GLYPH_BUFFER_SIZE)
564         return ExaGlyphNeedFlush;
565
566     if (PICT_FORMAT_BPP(format) == 1)
567         format = PICT_a8;
568     
569     for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) {
570         ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i];
571
572         if (format == cache->format &&
573             width <= cache->glyphWidth &&
574             height <= cache->glyphHeight) {
575             ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen,
576                                                                   &pExaScr->glyphCaches[i],
577                                                                   buffer,
578                                                                   pGlyph,
579                                                                   pSrc,
580                                                                   pDst,
581                                                                   xSrc, ySrc,
582                                                                   xMask, yMask,
583                                                                   xDst, yDst);
584             switch (result) {
585             case ExaGlyphFail:
586                 break;
587             case ExaGlyphSuccess:
588             case ExaGlyphNeedFlush:
589                 return result;
590             }
591         }
592     }
593
594     /* Couldn't find the glyph in the cache, use the glyph picture directly */
595
596     mask = GlyphPicture(pGlyph)[pScreen->myNum];
597     if (buffer->mask && buffer->mask != mask)
598         return ExaGlyphNeedFlush;
599
600     buffer->mask = mask;
601
602     rect = &buffer->rects[buffer->count];
603     rect->xSrc = xSrc;
604     rect->ySrc = ySrc;
605     rect->xMask = xMask;
606     rect->yMask = yMask;
607     rect->xDst = xDst;
608     rect->yDst = yDst;
609     rect->width = width;
610     rect->height = height;
611
612     buffer->count++;
613
614     return ExaGlyphSuccess;
615 }
616
617 static void
618 exaGlyphsToMask(PicturePtr        pMask,
619                 ExaGlyphBufferPtr buffer)
620 {
621     exaCompositeRects(PictOpAdd, buffer->mask, NULL, pMask,
622                       buffer->count, buffer->rects);
623     
624     buffer->count = 0;
625     buffer->mask = NULL;
626 }
627
628 static void
629 exaGlyphsToDst(PicturePtr        pSrc,
630                PicturePtr        pDst,
631                ExaGlyphBufferPtr buffer)
632 {
633     exaCompositeRects(PictOpOver, pSrc, buffer->mask, pDst, buffer->count,
634                       buffer->rects);
635     
636     buffer->count = 0;
637     buffer->mask = NULL;
638 }
639
640 /* Cut and paste from render/glyph.c - probably should export it instead */
641 static void
642 GlyphExtents (int               nlist,
643               GlyphListPtr      list,
644               GlyphPtr         *glyphs,
645               BoxPtr            extents)
646 {
647     int         x1, x2, y1, y2;
648     int         n;
649     GlyphPtr    glyph;
650     int         x, y;
651     
652     x = 0;
653     y = 0;
654     extents->x1 = MAXSHORT;
655     extents->x2 = MINSHORT;
656     extents->y1 = MAXSHORT;
657     extents->y2 = MINSHORT;
658     while (nlist--)
659     {
660         x += list->xOff;
661         y += list->yOff;
662         n = list->len;
663         list++;
664         while (n--)
665         {
666             glyph = *glyphs++;
667             x1 = x - glyph->info.x;
668             if (x1 < MINSHORT)
669                 x1 = MINSHORT;
670             y1 = y - glyph->info.y;
671             if (y1 < MINSHORT)
672                 y1 = MINSHORT;
673             x2 = x1 + glyph->info.width;
674             if (x2 > MAXSHORT)
675                 x2 = MAXSHORT;
676             y2 = y1 + glyph->info.height;
677             if (y2 > MAXSHORT)
678                 y2 = MAXSHORT;
679             if (x1 < extents->x1)
680                 extents->x1 = x1;
681             if (x2 > extents->x2)
682                 extents->x2 = x2;
683             if (y1 < extents->y1)
684                 extents->y1 = y1;
685             if (y2 > extents->y2)
686                 extents->y2 = y2;
687             x += glyph->info.xOff;
688             y += glyph->info.yOff;
689         }
690     }
691 }
692
693 void
694 exaGlyphs (CARD8         op,
695            PicturePtr    pSrc,
696            PicturePtr    pDst,
697            PictFormatPtr maskFormat,
698            INT16         xSrc,
699            INT16         ySrc,
700            int           nlist,
701            GlyphListPtr  list,
702            GlyphPtr     *glyphs)
703 {
704     PixmapPtr   pMaskPixmap = 0;
705     PicturePtr  pMask = NULL;
706     ScreenPtr   pScreen = pDst->pDrawable->pScreen;
707     int         width = 0, height = 0;
708     int         x, y;
709     int         first_xOff = list->xOff, first_yOff = list->yOff;
710     int         n;
711     GlyphPtr    glyph;
712     int         error;
713     BoxRec      extents = {0, 0, 0, 0};
714     CARD32      component_alpha;
715     ExaGlyphBuffer buffer;
716
717     if (maskFormat)
718     {
719         ExaScreenPriv(pScreen);
720         GCPtr       pGC;
721         xRectangle  rect;
722
723         GlyphExtents (nlist, list, glyphs, &extents);
724
725         if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
726             return;
727         width = extents.x2 - extents.x1;
728         height = extents.y2 - extents.y1;
729
730         if (maskFormat->depth == 1) {
731             PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8);
732
733             if (a8Format)
734                 maskFormat = a8Format;
735         }
736
737         pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
738                                                 maskFormat->depth,
739                                                 CREATE_PIXMAP_USAGE_SCRATCH);
740         if (!pMaskPixmap)
741             return;
742         component_alpha = NeedsComponent(maskFormat->format);
743         pMask = CreatePicture (0, &pMaskPixmap->drawable,
744                                maskFormat, CPComponentAlpha, &component_alpha,
745                                serverClient, &error);
746         if (!pMask ||
747             (!component_alpha && pExaScr->info->CheckComposite &&
748              !(*pExaScr->info->CheckComposite) (PictOpAdd, pSrc, NULL, pMask)))
749         {
750             PictFormatPtr argbFormat;
751
752             (*pScreen->DestroyPixmap) (pMaskPixmap);
753
754             if (!pMask)
755                 return;
756
757             /* The driver can't seem to composite to a8, let's try argb (but
758              * without component-alpha) */
759             FreePicture ((pointer) pMask, (XID) 0);
760
761             argbFormat = PictureMatchFormat (pScreen, 32, PICT_a8r8g8b8);
762
763             if (argbFormat)
764                 maskFormat = argbFormat;
765             
766             pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
767                                                     maskFormat->depth,
768                                                     CREATE_PIXMAP_USAGE_SCRATCH);
769             if (!pMaskPixmap)
770                 return;
771
772             pMask = CreatePicture (0, &pMaskPixmap->drawable, maskFormat, 0, 0,
773                                    serverClient, &error);
774             if (!pMask) {
775                 (*pScreen->DestroyPixmap) (pMaskPixmap);
776                 return;
777             }
778         }
779         pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
780         ValidateGC (&pMaskPixmap->drawable, pGC);
781         rect.x = 0;
782         rect.y = 0;
783         rect.width = width;
784         rect.height = height;
785         (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
786         FreeScratchGC (pGC);
787         x = -extents.x1;
788         y = -extents.y1;
789     }
790     else
791     {
792         x = 0;
793         y = 0;
794     }
795     buffer.count = 0;
796     buffer.mask = NULL;
797     while (nlist--)
798     {
799         x += list->xOff;
800         y += list->yOff;
801         n = list->len;
802         while (n--)
803         {
804             glyph = *glyphs++;
805
806             if (glyph->info.width > 0 && glyph->info.height > 0)
807             {
808                 /* pGlyph->info.{x,y} compensate for empty space in the glyph. */
809                 if (maskFormat)
810                 {
811                     if (exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
812                                        0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y) == ExaGlyphNeedFlush)
813                     {
814                         exaGlyphsToMask(pMask, &buffer);
815                         exaBufferGlyph(pScreen, &buffer, glyph, NULL, pMask,
816                                        0, 0, 0, 0, x - glyph->info.x, y - glyph->info.y);
817                     }
818                 }
819                 else
820                 {
821                     if (exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
822                                        xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff,
823                                        0, 0, x - glyph->info.x, y - glyph->info.y)
824                         == ExaGlyphNeedFlush)
825                     {
826                         exaGlyphsToDst(pSrc, pDst, &buffer);
827                         exaBufferGlyph(pScreen, &buffer, glyph, pSrc, pDst,
828                                        xSrc + (x - glyph->info.x) - first_xOff, ySrc + (y - glyph->info.y) - first_yOff,
829                                        0, 0, x - glyph->info.x, y - glyph->info.y);
830                     }
831                 }
832             }
833
834             x += glyph->info.xOff;
835             y += glyph->info.yOff;
836         }
837         list++;
838     }
839     
840     if (buffer.count) {
841         if (maskFormat)
842             exaGlyphsToMask(pMask, &buffer);
843         else
844             exaGlyphsToDst(pSrc, pDst, &buffer);
845     }
846
847     if (maskFormat)
848     {
849         x = extents.x1;
850         y = extents.y1;
851         CompositePicture (op,
852                           pSrc,
853                           pMask,
854                           pDst,
855                           xSrc + x - first_xOff,
856                           ySrc + y - first_yOff,
857                           0, 0,
858                           x, y,
859                           width, height);
860         FreePicture ((pointer) pMask, (XID) 0);
861         (*pScreen->DestroyPixmap) (pMaskPixmap);
862     }
863 }