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