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