1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 2010 Intel Corporation
3428d7b3dSmrg * Partly based on code Copyright © 2008 Red Hat, Inc.
4428d7b3dSmrg * Partly based on code Copyright © 2000 SuSE, Inc.
5428d7b3dSmrg *
6428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
7428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that
8428d7b3dSmrg * the above copyright notice appear in all copies and that both that
9428d7b3dSmrg * copyright notice and this permission notice appear in supporting
10428d7b3dSmrg * documentation, and that the name of Intel not be used in advertising or
11428d7b3dSmrg * publicity pertaining to distribution of the software without specific,
12428d7b3dSmrg * written prior permission.  Intel makes no representations about the
13428d7b3dSmrg * suitability of this software for any purpose.  It is provided "as is"
14428d7b3dSmrg * without express or implied warranty.
15428d7b3dSmrg *
16428d7b3dSmrg * INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17428d7b3dSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL
18428d7b3dSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19428d7b3dSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20428d7b3dSmrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21428d7b3dSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22428d7b3dSmrg *
23428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
24428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that
25428d7b3dSmrg * the above copyright notice appear in all copies and that both that
26428d7b3dSmrg * copyright notice and this permission notice appear in supporting
27428d7b3dSmrg * documentation, and that the name of Red Hat not be used in advertising or
28428d7b3dSmrg * publicity pertaining to distribution of the software without specific,
29428d7b3dSmrg * written prior permission.  Red Hat makes no representations about the
30428d7b3dSmrg * suitability of this software for any purpose.  It is provided "as is"
31428d7b3dSmrg * without express or implied warranty.
32428d7b3dSmrg *
33428d7b3dSmrg * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
34428d7b3dSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
35428d7b3dSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
36428d7b3dSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
37428d7b3dSmrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
38428d7b3dSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
39428d7b3dSmrg *
40428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
41428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that
42428d7b3dSmrg * the above copyright notice appear in all copies and that both that
43428d7b3dSmrg * copyright notice and this permission notice appear in supporting
44428d7b3dSmrg * documentation, and that the name of SuSE not be used in advertising or
45428d7b3dSmrg * publicity pertaining to distribution of the software without specific,
46428d7b3dSmrg * written prior permission.  SuSE makes no representations about the
47428d7b3dSmrg * suitability of this software for any purpose.  It is provided "as is"
48428d7b3dSmrg * without express or implied warranty.
49428d7b3dSmrg *
50428d7b3dSmrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
51428d7b3dSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
52428d7b3dSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
53428d7b3dSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
54428d7b3dSmrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
55428d7b3dSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56428d7b3dSmrg *
57428d7b3dSmrg * Author: Chris Wilson <chris@chris-wilson.co.uk>
58428d7b3dSmrg * Based on code by: Keith Packard <keithp@keithp.com> and Owen Taylor <otaylor@fishsoup.net>
59428d7b3dSmrg */
60428d7b3dSmrg
61428d7b3dSmrg#ifdef HAVE_DIX_CONFIG_H
62428d7b3dSmrg#include <dix-config.h>
63428d7b3dSmrg#endif
64428d7b3dSmrg
65428d7b3dSmrg#include <stdlib.h>
66428d7b3dSmrg
67428d7b3dSmrg#include "uxa-priv.h"
68428d7b3dSmrg#include "common.h"
69428d7b3dSmrg
70428d7b3dSmrg/* Width of the pixmaps we use for the caches; this should be less than
71428d7b3dSmrg * max texture size of the driver; this may need to actually come from
72428d7b3dSmrg * the driver.
73428d7b3dSmrg */
74428d7b3dSmrg#define CACHE_PICTURE_SIZE 1024
75428d7b3dSmrg#define GLYPH_MIN_SIZE 8
76428d7b3dSmrg#define GLYPH_MAX_SIZE 64
77428d7b3dSmrg#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE))
78428d7b3dSmrg
79428d7b3dSmrgstruct uxa_glyph {
80428d7b3dSmrg	uxa_glyph_cache_t *cache;
81428d7b3dSmrg	uint16_t x, y;
82428d7b3dSmrg	uint16_t size, pos;
83428d7b3dSmrg};
84428d7b3dSmrg
85428d7b3dSmrg#if HAS_DEVPRIVATEKEYREC
86428d7b3dSmrgstatic DevPrivateKeyRec uxa_glyph_key;
87428d7b3dSmrg#else
88428d7b3dSmrgstatic int uxa_glyph_key;
89428d7b3dSmrg#endif
90428d7b3dSmrg
91428d7b3dSmrgstatic inline struct uxa_glyph *uxa_glyph_get_private(GlyphPtr glyph)
92428d7b3dSmrg{
93428d7b3dSmrg#if HAS_DEVPRIVATEKEYREC
94428d7b3dSmrg	return dixGetPrivate(&glyph->devPrivates, &uxa_glyph_key);
95428d7b3dSmrg#else
96428d7b3dSmrg	return dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_key);
97428d7b3dSmrg#endif
98428d7b3dSmrg}
99428d7b3dSmrg
100428d7b3dSmrgstatic inline void uxa_glyph_set_private(GlyphPtr glyph, struct uxa_glyph *priv)
101428d7b3dSmrg{
102428d7b3dSmrg	dixSetPrivate(&glyph->devPrivates, &uxa_glyph_key, priv);
103428d7b3dSmrg}
104428d7b3dSmrg
105428d7b3dSmrg#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
106428d7b3dSmrg
107428d7b3dSmrgstatic void uxa_unrealize_glyph_caches(ScreenPtr pScreen)
108428d7b3dSmrg{
109428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
110428d7b3dSmrg	int i;
111428d7b3dSmrg
112428d7b3dSmrg	if (!uxa_screen->glyph_cache_initialized)
113428d7b3dSmrg		return;
114428d7b3dSmrg
115428d7b3dSmrg	for (i = 0; i < UXA_NUM_GLYPH_CACHE_FORMATS; i++) {
116428d7b3dSmrg		uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
117428d7b3dSmrg
118428d7b3dSmrg		if (cache->picture)
119428d7b3dSmrg			FreePicture(cache->picture, 0);
120428d7b3dSmrg
121428d7b3dSmrg		if (cache->glyphs)
122428d7b3dSmrg			free(cache->glyphs);
123428d7b3dSmrg	}
124428d7b3dSmrg	uxa_screen->glyph_cache_initialized = FALSE;
125428d7b3dSmrg}
126428d7b3dSmrg
127428d7b3dSmrgvoid uxa_glyphs_fini(ScreenPtr pScreen)
128428d7b3dSmrg{
129428d7b3dSmrg	uxa_unrealize_glyph_caches(pScreen);
130428d7b3dSmrg}
131428d7b3dSmrg
132428d7b3dSmrg/* All caches for a single format share a single pixmap for glyph storage,
133428d7b3dSmrg * allowing mixing glyphs of different sizes without paying a penalty
134428d7b3dSmrg * for switching between source pixmaps. (Note that for a size of font
135428d7b3dSmrg * right at the border between two sizes, we might be switching for almost
136428d7b3dSmrg * every glyph.)
137428d7b3dSmrg *
138428d7b3dSmrg * This function allocates the storage pixmap, and then fills in the
139428d7b3dSmrg * rest of the allocated structures for all caches with the given format.
140428d7b3dSmrg */
141428d7b3dSmrgstatic Bool uxa_realize_glyph_caches(ScreenPtr pScreen)
142428d7b3dSmrg{
143428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
144428d7b3dSmrg	unsigned int formats[] = {
145428d7b3dSmrg		PIXMAN_a8,
146428d7b3dSmrg		PIXMAN_a8r8g8b8,
147428d7b3dSmrg	};
148428d7b3dSmrg	unsigned i;
149428d7b3dSmrg
150428d7b3dSmrg	if (uxa_screen->glyph_cache_initialized)
151428d7b3dSmrg		return TRUE;
152428d7b3dSmrg
153428d7b3dSmrg	uxa_screen->glyph_cache_initialized = TRUE;
154428d7b3dSmrg	memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches));
155428d7b3dSmrg
156428d7b3dSmrg	for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
157428d7b3dSmrg		uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
158428d7b3dSmrg		PixmapPtr pixmap;
159428d7b3dSmrg		PicturePtr picture;
160428d7b3dSmrg		CARD32 component_alpha;
161428d7b3dSmrg		int depth = PIXMAN_FORMAT_DEPTH(formats[i]);
162428d7b3dSmrg		int error;
163428d7b3dSmrg		PictFormatPtr pPictFormat = PictureMatchFormat(pScreen, depth, formats[i]);
164428d7b3dSmrg		if (!pPictFormat)
165428d7b3dSmrg			goto bail;
166428d7b3dSmrg
167428d7b3dSmrg		/* Now allocate the pixmap and picture */
168428d7b3dSmrg		pixmap = pScreen->CreatePixmap(pScreen,
169428d7b3dSmrg					       CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE, depth,
170428d7b3dSmrg					       INTEL_CREATE_PIXMAP_TILING_X);
171428d7b3dSmrg		if (!pixmap)
172428d7b3dSmrg			goto bail;
173428d7b3dSmrg		if (!uxa_pixmap_is_offscreen(pixmap)) {
174428d7b3dSmrg			/* Presume shadow is in-effect */
175428d7b3dSmrg			pScreen->DestroyPixmap(pixmap);
176428d7b3dSmrg			uxa_unrealize_glyph_caches(pScreen);
177428d7b3dSmrg			return TRUE;
178428d7b3dSmrg		}
179428d7b3dSmrg
180428d7b3dSmrg		component_alpha = NeedsComponent(pPictFormat->format);
181428d7b3dSmrg		picture = CreatePicture(0, &pixmap->drawable, pPictFormat,
182428d7b3dSmrg					CPComponentAlpha, &component_alpha,
183428d7b3dSmrg					serverClient, &error);
184428d7b3dSmrg
185428d7b3dSmrg		pScreen->DestroyPixmap(pixmap);
186428d7b3dSmrg
187428d7b3dSmrg		if (!picture)
188428d7b3dSmrg			goto bail;
189428d7b3dSmrg
190428d7b3dSmrg		ValidatePicture(picture);
191428d7b3dSmrg
192428d7b3dSmrg		cache->picture = picture;
193428d7b3dSmrg		cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE);
194428d7b3dSmrg		if (!cache->glyphs)
195428d7b3dSmrg			goto bail;
196428d7b3dSmrg
197428d7b3dSmrg		cache->evict = rand() % GLYPH_CACHE_SIZE;
198428d7b3dSmrg	}
199428d7b3dSmrg	assert(i == UXA_NUM_GLYPH_CACHE_FORMATS);
200428d7b3dSmrg
201428d7b3dSmrg	return TRUE;
202428d7b3dSmrg
203428d7b3dSmrgbail:
204428d7b3dSmrg	uxa_unrealize_glyph_caches(pScreen);
205428d7b3dSmrg	return FALSE;
206428d7b3dSmrg}
207428d7b3dSmrg
208428d7b3dSmrg
209428d7b3dSmrgBool uxa_glyphs_init(ScreenPtr pScreen)
210428d7b3dSmrg{
211428d7b3dSmrg
212428d7b3dSmrg#if HAS_DIXREGISTERPRIVATEKEY
213428d7b3dSmrg	if (!dixRegisterPrivateKey(&uxa_glyph_key, PRIVATE_GLYPH, 0))
214428d7b3dSmrg		return FALSE;
215428d7b3dSmrg#else
216428d7b3dSmrg	if (!dixRequestPrivate(&uxa_glyph_key, 0))
217428d7b3dSmrg		return FALSE;
218428d7b3dSmrg#endif
219428d7b3dSmrg
220428d7b3dSmrg	/* Skip pixmap creation if we don't intend to use it. */
221428d7b3dSmrg	if (uxa_get_screen(pScreen)->force_fallback)
222428d7b3dSmrg		return TRUE;
223428d7b3dSmrg
224428d7b3dSmrg	return uxa_realize_glyph_caches(pScreen);
225428d7b3dSmrg}
226428d7b3dSmrg
227428d7b3dSmrg/* The most efficient thing to way to upload the glyph to the screen
228428d7b3dSmrg * is to use CopyArea; uxa pixmaps are always offscreen.
229428d7b3dSmrg */
230428d7b3dSmrgstatic void
231428d7b3dSmrguxa_glyph_cache_upload_glyph(ScreenPtr screen,
232428d7b3dSmrg			     uxa_glyph_cache_t * cache,
233428d7b3dSmrg			     GlyphPtr glyph,
234428d7b3dSmrg			     int x, int y)
235428d7b3dSmrg{
236428d7b3dSmrg	PicturePtr pGlyphPicture = GetGlyphPicture(glyph, screen);
237428d7b3dSmrg	PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
238428d7b3dSmrg	PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
239428d7b3dSmrg	PixmapPtr scratch;
240428d7b3dSmrg	GCPtr gc;
241428d7b3dSmrg
242428d7b3dSmrg	gc = GetScratchGC(pCachePixmap->drawable.depth, screen);
243428d7b3dSmrg	if (!gc)
244428d7b3dSmrg		return;
245428d7b3dSmrg
246428d7b3dSmrg	ValidateGC(&pCachePixmap->drawable, gc);
247428d7b3dSmrg
248428d7b3dSmrg	scratch = pGlyphPixmap;
249428d7b3dSmrg	/* Create a temporary bo to stream the updates to the cache */
250428d7b3dSmrg	if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth ||
251428d7b3dSmrg	    !uxa_pixmap_is_offscreen(scratch)) {
252428d7b3dSmrg		scratch = screen->CreatePixmap(screen,
253428d7b3dSmrg					       glyph->info.width,
254428d7b3dSmrg					       glyph->info.height,
255428d7b3dSmrg					       pCachePixmap->drawable.depth,
256428d7b3dSmrg					       UXA_CREATE_PIXMAP_FOR_MAP);
257428d7b3dSmrg		if (scratch) {
258428d7b3dSmrg			if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) {
259428d7b3dSmrg				PicturePtr picture;
260428d7b3dSmrg				int error;
261428d7b3dSmrg
262428d7b3dSmrg				picture = CreatePicture(0, &scratch->drawable,
263428d7b3dSmrg							PictureMatchFormat(screen,
264428d7b3dSmrg									   pCachePixmap->drawable.depth,
265428d7b3dSmrg									   cache->picture->format),
266428d7b3dSmrg							0, NULL,
267428d7b3dSmrg							serverClient, &error);
268428d7b3dSmrg				if (picture) {
269428d7b3dSmrg					ValidatePicture(picture);
270428d7b3dSmrg					uxa_composite(PictOpSrc, pGlyphPicture, NULL, picture,
271428d7b3dSmrg						      0, 0,
272428d7b3dSmrg						      0, 0,
273428d7b3dSmrg						      0, 0,
274428d7b3dSmrg						      glyph->info.width, glyph->info.height);
275428d7b3dSmrg					FreePicture(picture, 0);
276428d7b3dSmrg				}
277428d7b3dSmrg			} else {
278428d7b3dSmrg				uxa_copy_area(&pGlyphPixmap->drawable,
279428d7b3dSmrg					      &scratch->drawable,
280428d7b3dSmrg					      gc,
281428d7b3dSmrg					      0, 0,
282428d7b3dSmrg					      glyph->info.width, glyph->info.height,
283428d7b3dSmrg					      0, 0);
284428d7b3dSmrg			}
285428d7b3dSmrg		} else {
286428d7b3dSmrg			scratch = pGlyphPixmap;
287428d7b3dSmrg		}
288428d7b3dSmrg	}
289428d7b3dSmrg
290428d7b3dSmrg	uxa_copy_area(&scratch->drawable, &pCachePixmap->drawable, gc,
291428d7b3dSmrg		      0, 0,
292428d7b3dSmrg		      glyph->info.width, glyph->info.height,
293428d7b3dSmrg		      x, y);
294428d7b3dSmrg
295428d7b3dSmrg	if (scratch != pGlyphPixmap)
296428d7b3dSmrg		screen->DestroyPixmap(scratch);
297428d7b3dSmrg
298428d7b3dSmrg	FreeScratchGC(gc);
299428d7b3dSmrg}
300428d7b3dSmrg
301428d7b3dSmrgvoid
302428d7b3dSmrguxa_glyph_unrealize(ScreenPtr screen,
303428d7b3dSmrg		    GlyphPtr glyph)
304428d7b3dSmrg{
305428d7b3dSmrg	struct uxa_glyph *priv;
306428d7b3dSmrg
307428d7b3dSmrg	/* Use Lookup in case we have not attached to this glyph. */
308428d7b3dSmrg	priv = dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_key);
309428d7b3dSmrg	if (priv == NULL)
310428d7b3dSmrg		return;
311428d7b3dSmrg
312428d7b3dSmrg	priv->cache->glyphs[priv->pos] = NULL;
313428d7b3dSmrg
314428d7b3dSmrg	uxa_glyph_set_private(glyph, NULL);
315428d7b3dSmrg	free(priv);
316428d7b3dSmrg}
317428d7b3dSmrg
318428d7b3dSmrg/* Cut and paste from render/glyph.c - probably should export it instead */
319428d7b3dSmrgstatic void
320428d7b3dSmrguxa_glyph_extents(int nlist,
321428d7b3dSmrg		  GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
322428d7b3dSmrg{
323428d7b3dSmrg	int x1, x2, y1, y2;
324428d7b3dSmrg	int x, y, n;
325428d7b3dSmrg
326428d7b3dSmrg	x1 = y1 = MAXSHORT;
327428d7b3dSmrg	x2 = y2 = MINSHORT;
328428d7b3dSmrg	x = y = 0;
329428d7b3dSmrg	while (nlist--) {
330428d7b3dSmrg		x += list->xOff;
331428d7b3dSmrg		y += list->yOff;
332428d7b3dSmrg		n = list->len;
333428d7b3dSmrg		list++;
334428d7b3dSmrg		while (n--) {
335428d7b3dSmrg			GlyphPtr glyph = *glyphs++;
336428d7b3dSmrg			int v;
337428d7b3dSmrg
338428d7b3dSmrg			v = x - glyph->info.x;
339428d7b3dSmrg			if (v < x1)
340428d7b3dSmrg			    x1 = v;
341428d7b3dSmrg			v += glyph->info.width;
342428d7b3dSmrg			if (v > x2)
343428d7b3dSmrg			    x2 = v;
344428d7b3dSmrg
345428d7b3dSmrg			v = y - glyph->info.y;
346428d7b3dSmrg			if (v < y1)
347428d7b3dSmrg			    y1 = v;
348428d7b3dSmrg			v += glyph->info.height;
349428d7b3dSmrg			if (v > y2)
350428d7b3dSmrg			    y2 = v;
351428d7b3dSmrg
352428d7b3dSmrg			x += glyph->info.xOff;
353428d7b3dSmrg			y += glyph->info.yOff;
354428d7b3dSmrg		}
355428d7b3dSmrg	}
356428d7b3dSmrg
357428d7b3dSmrg	extents->x1 = x1 < MINSHORT ? MINSHORT : x1;
358428d7b3dSmrg	extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2;
359428d7b3dSmrg	extents->y1 = y1 < MINSHORT ? MINSHORT : y1;
360428d7b3dSmrg	extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2;
361428d7b3dSmrg}
362428d7b3dSmrg
363428d7b3dSmrg/**
364428d7b3dSmrg * Returns TRUE if the glyphs in the lists intersect.  Only checks based on
365428d7b3dSmrg * bounding box, which appears to be good enough to catch most cases at least.
366428d7b3dSmrg */
367428d7b3dSmrgstatic Bool
368428d7b3dSmrguxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs)
369428d7b3dSmrg{
370428d7b3dSmrg	int x1, x2, y1, y2;
371428d7b3dSmrg	int n;
372428d7b3dSmrg	int x, y;
373428d7b3dSmrg	BoxRec extents;
374428d7b3dSmrg	Bool first = TRUE;
375428d7b3dSmrg
376428d7b3dSmrg	x = 0;
377428d7b3dSmrg	y = 0;
378428d7b3dSmrg	extents.x1 = 0;
379428d7b3dSmrg	extents.y1 = 0;
380428d7b3dSmrg	extents.x2 = 0;
381428d7b3dSmrg	extents.y2 = 0;
382428d7b3dSmrg	while (nlist--) {
383428d7b3dSmrg		x += list->xOff;
384428d7b3dSmrg		y += list->yOff;
385428d7b3dSmrg		n = list->len;
386428d7b3dSmrg		list++;
387428d7b3dSmrg		while (n--) {
388428d7b3dSmrg			GlyphPtr glyph = *glyphs++;
389428d7b3dSmrg
390428d7b3dSmrg			if (glyph->info.width == 0 || glyph->info.height == 0) {
391428d7b3dSmrg				x += glyph->info.xOff;
392428d7b3dSmrg				y += glyph->info.yOff;
393428d7b3dSmrg				continue;
394428d7b3dSmrg			}
395428d7b3dSmrg
396428d7b3dSmrg			x1 = x - glyph->info.x;
397428d7b3dSmrg			if (x1 < MINSHORT)
398428d7b3dSmrg				x1 = MINSHORT;
399428d7b3dSmrg			y1 = y - glyph->info.y;
400428d7b3dSmrg			if (y1 < MINSHORT)
401428d7b3dSmrg				y1 = MINSHORT;
402428d7b3dSmrg			x2 = x1 + glyph->info.width;
403428d7b3dSmrg			if (x2 > MAXSHORT)
404428d7b3dSmrg				x2 = MAXSHORT;
405428d7b3dSmrg			y2 = y1 + glyph->info.height;
406428d7b3dSmrg			if (y2 > MAXSHORT)
407428d7b3dSmrg				y2 = MAXSHORT;
408428d7b3dSmrg
409428d7b3dSmrg			if (first) {
410428d7b3dSmrg				extents.x1 = x1;
411428d7b3dSmrg				extents.y1 = y1;
412428d7b3dSmrg				extents.x2 = x2;
413428d7b3dSmrg				extents.y2 = y2;
414428d7b3dSmrg				first = FALSE;
415428d7b3dSmrg			} else {
416428d7b3dSmrg				if (x1 < extents.x2 && x2 > extents.x1 &&
417428d7b3dSmrg				    y1 < extents.y2 && y2 > extents.y1) {
418428d7b3dSmrg					return TRUE;
419428d7b3dSmrg				}
420428d7b3dSmrg
421428d7b3dSmrg				if (x1 < extents.x1)
422428d7b3dSmrg					extents.x1 = x1;
423428d7b3dSmrg				if (x2 > extents.x2)
424428d7b3dSmrg					extents.x2 = x2;
425428d7b3dSmrg				if (y1 < extents.y1)
426428d7b3dSmrg					extents.y1 = y1;
427428d7b3dSmrg				if (y2 > extents.y2)
428428d7b3dSmrg					extents.y2 = y2;
429428d7b3dSmrg			}
430428d7b3dSmrg			x += glyph->info.xOff;
431428d7b3dSmrg			y += glyph->info.yOff;
432428d7b3dSmrg		}
433428d7b3dSmrg	}
434428d7b3dSmrg
435428d7b3dSmrg	return FALSE;
436428d7b3dSmrg}
437428d7b3dSmrg
438428d7b3dSmrgstatic void
439428d7b3dSmrguxa_check_glyphs(CARD8 op,
440428d7b3dSmrg		 PicturePtr src,
441428d7b3dSmrg		 PicturePtr dst,
442428d7b3dSmrg		 PictFormatPtr maskFormat,
443428d7b3dSmrg		 INT16 xSrc,
444428d7b3dSmrg		 INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
445428d7b3dSmrg{
446428d7b3dSmrg	pixman_image_t *image;
447428d7b3dSmrg	PixmapPtr scratch;
448428d7b3dSmrg	PicturePtr mask, mask_src = NULL, mask_dst = NULL, white = NULL;
449428d7b3dSmrg	int width = 0, height = 0;
450428d7b3dSmrg	int x, y, n;
451428d7b3dSmrg	int xDst = list->xOff, yDst = list->yOff;
452428d7b3dSmrg	BoxRec extents = { 0, 0, 0, 0 };
453428d7b3dSmrg	CARD8 mask_op = 0;
454428d7b3dSmrg
455428d7b3dSmrg	if (maskFormat) {
456428d7b3dSmrg		pixman_format_code_t format;
457428d7b3dSmrg		CARD32 component_alpha;
458428d7b3dSmrg		xRenderColor color;
459428d7b3dSmrg		int error;
460428d7b3dSmrg
461428d7b3dSmrg		uxa_glyph_extents(nlist, list, glyphs, &extents);
462428d7b3dSmrg		if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
463428d7b3dSmrg			return;
464428d7b3dSmrg
465428d7b3dSmrg		width = extents.x2 - extents.x1;
466428d7b3dSmrg		height = extents.y2 - extents.y1;
467428d7b3dSmrg
468428d7b3dSmrg		format = maskFormat->format |
469428d7b3dSmrg			(BitsPerPixel(maskFormat->depth) << 24);
470428d7b3dSmrg		image =
471428d7b3dSmrg			pixman_image_create_bits(format, width, height, NULL, 0);
472428d7b3dSmrg		if (!image)
473428d7b3dSmrg			return;
474428d7b3dSmrg
475428d7b3dSmrg		scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height,
476428d7b3dSmrg						 PIXMAN_FORMAT_DEPTH(format),
477428d7b3dSmrg						 PIXMAN_FORMAT_BPP(format),
478428d7b3dSmrg						 pixman_image_get_stride(image),
479428d7b3dSmrg						 pixman_image_get_data(image));
480428d7b3dSmrg
481428d7b3dSmrg		if (!scratch) {
482428d7b3dSmrg			pixman_image_unref(image);
483428d7b3dSmrg			return;
484428d7b3dSmrg		}
485428d7b3dSmrg
486428d7b3dSmrg		component_alpha = NeedsComponent(maskFormat->format);
487428d7b3dSmrg		mask = CreatePicture(0, &scratch->drawable,
488428d7b3dSmrg				     maskFormat, CPComponentAlpha,
489428d7b3dSmrg				     &component_alpha, serverClient, &error);
490428d7b3dSmrg		if (!mask) {
491428d7b3dSmrg			FreeScratchPixmapHeader(scratch);
492428d7b3dSmrg			pixman_image_unref(image);
493428d7b3dSmrg			return;
494428d7b3dSmrg		}
495428d7b3dSmrg		ValidatePicture(mask);
496428d7b3dSmrg
497428d7b3dSmrg		x = -extents.x1;
498428d7b3dSmrg		y = -extents.y1;
499428d7b3dSmrg
500428d7b3dSmrg		color.red = color.green = color.blue = color.alpha = 0xffff;
501428d7b3dSmrg		white = CreateSolidPicture(0, &color, &error);
502428d7b3dSmrg
503428d7b3dSmrg		mask_op = op;
504428d7b3dSmrg		op = PictOpAdd;
505428d7b3dSmrg
506428d7b3dSmrg		mask_src = src;
507428d7b3dSmrg		src = white;
508428d7b3dSmrg
509428d7b3dSmrg		mask_dst = dst;
510428d7b3dSmrg		dst = mask;
511428d7b3dSmrg	} else {
512428d7b3dSmrg		mask = dst;
513428d7b3dSmrg		x = 0;
514428d7b3dSmrg		y = 0;
515428d7b3dSmrg	}
516428d7b3dSmrg
517428d7b3dSmrg	while (nlist--) {
518428d7b3dSmrg		x += list->xOff;
519428d7b3dSmrg		y += list->yOff;
520428d7b3dSmrg		n = list->len;
521428d7b3dSmrg		while (n--) {
522428d7b3dSmrg			GlyphPtr glyph = *glyphs++;
523428d7b3dSmrg			PicturePtr g = GetGlyphPicture(glyph, dst->pDrawable->pScreen);
524428d7b3dSmrg			if (g) {
525428d7b3dSmrg				CompositePicture(op, src, g, dst,
526428d7b3dSmrg						 xSrc + (x - glyph->info.x) - xDst,
527428d7b3dSmrg						 ySrc + (y - glyph->info.y) - yDst,
528428d7b3dSmrg						 0, 0,
529428d7b3dSmrg						 x - glyph->info.x,
530428d7b3dSmrg						 y - glyph->info.y,
531428d7b3dSmrg						 glyph->info.width,
532428d7b3dSmrg						 glyph->info.height);
533428d7b3dSmrg			}
534428d7b3dSmrg
535428d7b3dSmrg			x += glyph->info.xOff;
536428d7b3dSmrg			y += glyph->info.yOff;
537428d7b3dSmrg		}
538428d7b3dSmrg		list++;
539428d7b3dSmrg	}
540428d7b3dSmrg
541428d7b3dSmrg	if (white)
542428d7b3dSmrg		FreePicture(white, 0);
543428d7b3dSmrg
544428d7b3dSmrg	if (maskFormat) {
545428d7b3dSmrg		x = extents.x1;
546428d7b3dSmrg		y = extents.y1;
547428d7b3dSmrg		CompositePicture(mask_op, mask_src, mask, mask_dst,
548428d7b3dSmrg				 xSrc + x - xDst,
549428d7b3dSmrg				 ySrc + y - yDst,
550428d7b3dSmrg				 0, 0,
551428d7b3dSmrg				 x, y,
552428d7b3dSmrg				 width, height);
553428d7b3dSmrg		FreePicture(mask, 0);
554428d7b3dSmrg		FreeScratchPixmapHeader(scratch);
555428d7b3dSmrg		pixman_image_unref(image);
556428d7b3dSmrg	}
557428d7b3dSmrg}
558428d7b3dSmrg
559428d7b3dSmrgstatic inline unsigned int
560428d7b3dSmrguxa_glyph_size_to_count(int size)
561428d7b3dSmrg{
562428d7b3dSmrg	size /= GLYPH_MIN_SIZE;
563428d7b3dSmrg	return size * size;
564428d7b3dSmrg}
565428d7b3dSmrg
566428d7b3dSmrgstatic inline unsigned int
567428d7b3dSmrguxa_glyph_count_to_mask(int count)
568428d7b3dSmrg{
569428d7b3dSmrg	return ~(count - 1);
570428d7b3dSmrg}
571428d7b3dSmrg
572428d7b3dSmrgstatic inline unsigned int
573428d7b3dSmrguxa_glyph_size_to_mask(int size)
574428d7b3dSmrg{
575428d7b3dSmrg	return uxa_glyph_count_to_mask(uxa_glyph_size_to_count(size));
576428d7b3dSmrg}
577428d7b3dSmrg
578428d7b3dSmrgstatic PicturePtr
579428d7b3dSmrguxa_glyph_cache(ScreenPtr screen, GlyphPtr glyph, int *out_x, int *out_y)
580428d7b3dSmrg{
581428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
582428d7b3dSmrg	PicturePtr glyph_picture = GetGlyphPicture(glyph, screen);
583428d7b3dSmrg	uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0];
584428d7b3dSmrg	struct uxa_glyph *priv = NULL;
585428d7b3dSmrg	int size, mask, pos, s;
586428d7b3dSmrg
587428d7b3dSmrg	if (glyph->info.width > GLYPH_MAX_SIZE || glyph->info.height > GLYPH_MAX_SIZE)
588428d7b3dSmrg		return NULL;
589428d7b3dSmrg
590428d7b3dSmrg	for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
591428d7b3dSmrg		if (glyph->info.width <= size && glyph->info.height <= size)
592428d7b3dSmrg			break;
593428d7b3dSmrg
594428d7b3dSmrg	s = uxa_glyph_size_to_count(size);
595428d7b3dSmrg	mask = uxa_glyph_count_to_mask(s);
596428d7b3dSmrg	pos = (cache->count + s - 1) & mask;
597428d7b3dSmrg	if (pos < GLYPH_CACHE_SIZE) {
598428d7b3dSmrg		cache->count = pos + s;
599428d7b3dSmrg	} else {
600428d7b3dSmrg		for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) {
601428d7b3dSmrg			int i = cache->evict & uxa_glyph_size_to_mask(s);
602428d7b3dSmrg			GlyphPtr evicted = cache->glyphs[i];
603428d7b3dSmrg			if (evicted == NULL)
604428d7b3dSmrg				continue;
605428d7b3dSmrg
606428d7b3dSmrg			priv = uxa_glyph_get_private(evicted);
607428d7b3dSmrg			if (priv->size >= s) {
608428d7b3dSmrg				cache->glyphs[i] = NULL;
609428d7b3dSmrg				uxa_glyph_set_private(evicted, NULL);
610428d7b3dSmrg				pos = cache->evict & uxa_glyph_size_to_mask(size);
611428d7b3dSmrg			} else
612428d7b3dSmrg				priv = NULL;
613428d7b3dSmrg			break;
614428d7b3dSmrg		}
615428d7b3dSmrg		if (priv == NULL) {
616428d7b3dSmrg			int count = uxa_glyph_size_to_count(size);
617428d7b3dSmrg			mask = uxa_glyph_count_to_mask(count);
618428d7b3dSmrg			pos = cache->evict & mask;
619428d7b3dSmrg			for (s = 0; s < count; s++) {
620428d7b3dSmrg				GlyphPtr evicted = cache->glyphs[pos + s];
621428d7b3dSmrg				if (evicted != NULL) {
622428d7b3dSmrg					if (priv != NULL)
623428d7b3dSmrg						free(priv);
624428d7b3dSmrg
625428d7b3dSmrg					priv = uxa_glyph_get_private(evicted);
626428d7b3dSmrg					uxa_glyph_set_private(evicted, NULL);
627428d7b3dSmrg					cache->glyphs[pos + s] = NULL;
628428d7b3dSmrg				}
629428d7b3dSmrg			}
630428d7b3dSmrg		}
631428d7b3dSmrg
632428d7b3dSmrg		/* And pick a new eviction position */
633428d7b3dSmrg		cache->evict = rand() % GLYPH_CACHE_SIZE;
634428d7b3dSmrg	}
635428d7b3dSmrg
636428d7b3dSmrg	if (priv == NULL) {
637428d7b3dSmrg		priv = malloc(sizeof(struct uxa_glyph));
638428d7b3dSmrg		if (priv == NULL)
639428d7b3dSmrg			return NULL;
640428d7b3dSmrg	}
641428d7b3dSmrg
642428d7b3dSmrg	uxa_glyph_set_private(glyph, priv);
643428d7b3dSmrg	cache->glyphs[pos] = glyph;
644428d7b3dSmrg
645428d7b3dSmrg	priv->cache = cache;
646428d7b3dSmrg	priv->size = size;
647428d7b3dSmrg	priv->pos = pos;
648428d7b3dSmrg	s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE));
649428d7b3dSmrg	priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE;
650428d7b3dSmrg	priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE;
651428d7b3dSmrg	for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) {
652428d7b3dSmrg		if (pos & 1)
653428d7b3dSmrg			priv->x += s;
654428d7b3dSmrg		if (pos & 2)
655428d7b3dSmrg			priv->y += s;
656428d7b3dSmrg		pos >>= 2;
657428d7b3dSmrg	}
658428d7b3dSmrg
659428d7b3dSmrg	uxa_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y);
660428d7b3dSmrg
661428d7b3dSmrg	*out_x = priv->x;
662428d7b3dSmrg	*out_y = priv->y;
663428d7b3dSmrg	return cache->picture;
664428d7b3dSmrg}
665428d7b3dSmrg
666428d7b3dSmrgstatic void
667428d7b3dSmrguxa_clear_pixmap(ScreenPtr screen,
668428d7b3dSmrg		 uxa_screen_t *uxa_screen,
669428d7b3dSmrg		 PixmapPtr pixmap)
670428d7b3dSmrg{
671428d7b3dSmrg	if (uxa_screen->info->check_solid &&
672428d7b3dSmrg	    !uxa_screen->info->check_solid(&pixmap->drawable, GXcopy, FB_ALLONES))
673428d7b3dSmrg		goto fallback;
674428d7b3dSmrg
675428d7b3dSmrg	if (!uxa_screen->info->prepare_solid(pixmap, GXcopy, FB_ALLONES, 0))
676428d7b3dSmrg		goto fallback;
677428d7b3dSmrg
678428d7b3dSmrg	uxa_screen->info->solid(pixmap,
679428d7b3dSmrg				0, 0,
680428d7b3dSmrg				pixmap->drawable.width,
681428d7b3dSmrg				pixmap->drawable.height);
682428d7b3dSmrg
683428d7b3dSmrg	uxa_screen->info->done_solid(pixmap);
684428d7b3dSmrg	return;
685428d7b3dSmrg
686428d7b3dSmrgfallback:
687428d7b3dSmrg	{
688428d7b3dSmrg		GCPtr gc;
689428d7b3dSmrg
690428d7b3dSmrg		gc = GetScratchGC(pixmap->drawable.depth, screen);
691428d7b3dSmrg		if (gc) {
692428d7b3dSmrg			xRectangle rect;
693428d7b3dSmrg
694428d7b3dSmrg			ValidateGC(&pixmap->drawable, gc);
695428d7b3dSmrg
696428d7b3dSmrg			rect.x = 0;
697428d7b3dSmrg			rect.y = 0;
698428d7b3dSmrg			rect.width  = pixmap->drawable.width;
699428d7b3dSmrg			rect.height = pixmap->drawable.height;
700428d7b3dSmrg			gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect);
701428d7b3dSmrg
702428d7b3dSmrg			FreeScratchGC(gc);
703428d7b3dSmrg		}
704428d7b3dSmrg	}
705428d7b3dSmrg}
706428d7b3dSmrg
707428d7b3dSmrgstatic PicturePtr
708428d7b3dSmrgcreate_white_solid(ScreenPtr screen)
709428d7b3dSmrg{
710428d7b3dSmrg	PicturePtr white, ret = NULL;
711428d7b3dSmrg	xRenderColor color;
712428d7b3dSmrg	int error;
713428d7b3dSmrg
714428d7b3dSmrg	color.red = color.green = color.blue = color.alpha = 0xffff;
715428d7b3dSmrg	white = CreateSolidPicture(0, &color, &error);
716428d7b3dSmrg	if (white) {
717428d7b3dSmrg		ret = uxa_acquire_solid(screen, white->pSourcePict);
718428d7b3dSmrg		FreePicture(white, 0);
719428d7b3dSmrg	}
720428d7b3dSmrg
721428d7b3dSmrg	return ret;
722428d7b3dSmrg}
723428d7b3dSmrg
724428d7b3dSmrgstatic int
725428d7b3dSmrguxa_glyphs_via_mask(CARD8 op,
726428d7b3dSmrg		    PicturePtr pSrc,
727428d7b3dSmrg		    PicturePtr pDst,
728428d7b3dSmrg		    PictFormatPtr maskFormat,
729428d7b3dSmrg		    INT16 xSrc, INT16 ySrc,
730428d7b3dSmrg		    int nlist, GlyphListPtr list, GlyphPtr * glyphs)
731428d7b3dSmrg{
732428d7b3dSmrg	ScreenPtr screen = pDst->pDrawable->pScreen;
733428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
734428d7b3dSmrg	CARD32 component_alpha;
735428d7b3dSmrg	PixmapPtr pixmap, white_pixmap;
736428d7b3dSmrg	PicturePtr glyph_atlas, mask, white;
737428d7b3dSmrg	int xDst = list->xOff, yDst = list->yOff;
738428d7b3dSmrg	int x, y, width, height;
739428d7b3dSmrg	int dst_off_x, dst_off_y;
740428d7b3dSmrg	int n, error;
741428d7b3dSmrg	BoxRec box;
742428d7b3dSmrg
743428d7b3dSmrg	uxa_glyph_extents(nlist, list, glyphs, &box);
744428d7b3dSmrg	if (box.x2 <= box.x1 || box.y2 <= box.y1)
745428d7b3dSmrg		return 0;
746428d7b3dSmrg
747428d7b3dSmrg	dst_off_x = box.x1;
748428d7b3dSmrg	dst_off_y = box.y1;
749428d7b3dSmrg
750428d7b3dSmrg	width  = box.x2 - box.x1;
751428d7b3dSmrg	height = box.y2 - box.y1;
752428d7b3dSmrg	x = -box.x1;
753428d7b3dSmrg	y = -box.y1;
754428d7b3dSmrg
755428d7b3dSmrg	if (maskFormat->depth == 1) {
756428d7b3dSmrg		PictFormatPtr a8Format =
757428d7b3dSmrg			PictureMatchFormat(screen, 8, PICT_a8);
758428d7b3dSmrg
759428d7b3dSmrg		if (!a8Format)
760428d7b3dSmrg			return -1;
761428d7b3dSmrg
762428d7b3dSmrg		maskFormat = a8Format;
763428d7b3dSmrg	}
764428d7b3dSmrg
765428d7b3dSmrg	pixmap = screen->CreatePixmap(screen, width, height,
766428d7b3dSmrg				      maskFormat->depth,
767428d7b3dSmrg				      CREATE_PIXMAP_USAGE_SCRATCH);
768428d7b3dSmrg	if (!pixmap)
769428d7b3dSmrg		return 1;
770428d7b3dSmrg
771428d7b3dSmrg	if (!uxa_pixmap_is_offscreen(pixmap)) {
772428d7b3dSmrg		screen->DestroyPixmap(pixmap);
773428d7b3dSmrg		return -1;
774428d7b3dSmrg	}
775428d7b3dSmrg
776428d7b3dSmrg	white_pixmap = NULL;
777428d7b3dSmrg	white = create_white_solid(screen);
778428d7b3dSmrg	if (white)
779428d7b3dSmrg		white_pixmap = uxa_get_drawable_pixmap(white->pDrawable);
780428d7b3dSmrg	if (!white_pixmap) {
781428d7b3dSmrg		if (white)
782428d7b3dSmrg			FreePicture(white, 0);
783428d7b3dSmrg		screen->DestroyPixmap(pixmap);
784428d7b3dSmrg		return -1;
785428d7b3dSmrg	}
786428d7b3dSmrg
787428d7b3dSmrg	uxa_clear_pixmap(screen, uxa_screen, pixmap);
788428d7b3dSmrg
789428d7b3dSmrg	component_alpha = NeedsComponent(maskFormat->format);
790428d7b3dSmrg	mask = CreatePicture(0, &pixmap->drawable,
791428d7b3dSmrg			      maskFormat, CPComponentAlpha,
792428d7b3dSmrg			      &component_alpha, serverClient, &error);
793428d7b3dSmrg	screen->DestroyPixmap(pixmap);
794428d7b3dSmrg
795428d7b3dSmrg	if (!mask) {
796428d7b3dSmrg		FreePicture(white, 0);
797428d7b3dSmrg		return 1;
798428d7b3dSmrg	}
799428d7b3dSmrg
800428d7b3dSmrg	ValidatePicture(mask);
801428d7b3dSmrg
802428d7b3dSmrg	glyph_atlas = NULL;
803428d7b3dSmrg	while (nlist--) {
804428d7b3dSmrg		x += list->xOff;
805428d7b3dSmrg		y += list->yOff;
806428d7b3dSmrg		n = list->len;
807428d7b3dSmrg		while (n--) {
808428d7b3dSmrg			GlyphPtr glyph = *glyphs++;
809428d7b3dSmrg			PicturePtr this_atlas;
810428d7b3dSmrg			int glyph_x, glyph_y;
811428d7b3dSmrg			struct uxa_glyph *priv;
812428d7b3dSmrg
813428d7b3dSmrg			if (glyph->info.width == 0 || glyph->info.height == 0)
814428d7b3dSmrg				goto next_glyph;
815428d7b3dSmrg
816428d7b3dSmrg			priv = uxa_glyph_get_private(glyph);
817428d7b3dSmrg			if (priv != NULL) {
818428d7b3dSmrg				glyph_x = priv->x;
819428d7b3dSmrg				glyph_y = priv->y;
820428d7b3dSmrg				this_atlas = priv->cache->picture;
821428d7b3dSmrg			} else {
822428d7b3dSmrg				if (glyph_atlas) {
823428d7b3dSmrg					uxa_screen->info->done_composite(pixmap);
824428d7b3dSmrg					glyph_atlas = NULL;
825428d7b3dSmrg				}
826428d7b3dSmrg				this_atlas = uxa_glyph_cache(screen, glyph, &glyph_x, &glyph_y);
827428d7b3dSmrg				if (this_atlas == NULL) {
828428d7b3dSmrg					/* no cache for this glyph */
829428d7b3dSmrg					this_atlas = GetGlyphPicture(glyph, screen);
830428d7b3dSmrg					glyph_x = glyph_y = 0;
831428d7b3dSmrg				}
832428d7b3dSmrg			}
833428d7b3dSmrg
834428d7b3dSmrg			if (this_atlas != glyph_atlas) {
835428d7b3dSmrg				PixmapPtr glyph_pixmap;
836428d7b3dSmrg
837428d7b3dSmrg				if (glyph_atlas)
838428d7b3dSmrg					uxa_screen->info->done_composite(pixmap);
839428d7b3dSmrg
840428d7b3dSmrg				glyph_pixmap =
841428d7b3dSmrg					uxa_get_drawable_pixmap(this_atlas->pDrawable);
842428d7b3dSmrg				if (!uxa_pixmap_is_offscreen(glyph_pixmap) ||
843428d7b3dSmrg				    !uxa_screen->info->prepare_composite(PictOpAdd,
844428d7b3dSmrg									 white, this_atlas, mask,
845428d7b3dSmrg									 white_pixmap, glyph_pixmap, pixmap)) {
846428d7b3dSmrg					FreePicture(white, 0);
847428d7b3dSmrg					FreePicture(mask, 0);
848428d7b3dSmrg					return -1;
849428d7b3dSmrg				}
850428d7b3dSmrg
851428d7b3dSmrg				glyph_atlas = this_atlas;
852428d7b3dSmrg			}
853428d7b3dSmrg
854428d7b3dSmrg			uxa_screen->info->composite(pixmap,
855428d7b3dSmrg						    0, 0,
856428d7b3dSmrg						    glyph_x, glyph_y,
857428d7b3dSmrg						    x - glyph->info.x,
858428d7b3dSmrg						    y - glyph->info.y,
859428d7b3dSmrg						    glyph->info.width,
860428d7b3dSmrg						    glyph->info.height);
861428d7b3dSmrg
862428d7b3dSmrgnext_glyph:
863428d7b3dSmrg			x += glyph->info.xOff;
864428d7b3dSmrg			y += glyph->info.yOff;
865428d7b3dSmrg		}
866428d7b3dSmrg		list++;
867428d7b3dSmrg	}
868428d7b3dSmrg	if (glyph_atlas)
869428d7b3dSmrg		uxa_screen->info->done_composite(pixmap);
870428d7b3dSmrg
871428d7b3dSmrg	uxa_composite(op,
872428d7b3dSmrg		      pSrc, mask, pDst,
873428d7b3dSmrg		      dst_off_x + xSrc - xDst,
874428d7b3dSmrg		      dst_off_y + ySrc - yDst,
875428d7b3dSmrg		      0, 0,
876428d7b3dSmrg		      dst_off_x, dst_off_y,
877428d7b3dSmrg		      width, height);
878428d7b3dSmrg
879428d7b3dSmrg	FreePicture(white, 0);
880428d7b3dSmrg	FreePicture(mask, 0);
881428d7b3dSmrg	return 0;
882428d7b3dSmrg}
883428d7b3dSmrg
884428d7b3dSmrgstatic int
885428d7b3dSmrguxa_glyphs_to_dst(CARD8 op,
886428d7b3dSmrg		  PicturePtr pSrc,
887428d7b3dSmrg		  PicturePtr pDst,
888428d7b3dSmrg		  INT16 xSrc, INT16 ySrc,
889428d7b3dSmrg		  int nlist, GlyphListPtr list, GlyphPtr * glyphs)
890428d7b3dSmrg{
891428d7b3dSmrg	ScreenPtr screen = pDst->pDrawable->pScreen;
892428d7b3dSmrg	int x, y, n;
893428d7b3dSmrg
894428d7b3dSmrg	xSrc -= list->xOff;
895428d7b3dSmrg	ySrc -= list->yOff;
896428d7b3dSmrg	x = y = 0;
897428d7b3dSmrg	while (nlist--) {
898428d7b3dSmrg		x += list->xOff;
899428d7b3dSmrg		y += list->yOff;
900428d7b3dSmrg		n = list->len;
901428d7b3dSmrg		while (n--) {
902428d7b3dSmrg			GlyphPtr glyph = *glyphs++;
903428d7b3dSmrg			PicturePtr glyph_atlas;
904428d7b3dSmrg			int glyph_x, glyph_y;
905428d7b3dSmrg			struct uxa_glyph *priv;
906428d7b3dSmrg
907428d7b3dSmrg			if (glyph->info.width == 0 || glyph->info.height == 0)
908428d7b3dSmrg				goto next_glyph;
909428d7b3dSmrg
910428d7b3dSmrg			priv = uxa_glyph_get_private(glyph);
911428d7b3dSmrg			if (priv != NULL) {
912428d7b3dSmrg				glyph_x = priv->x;
913428d7b3dSmrg				glyph_y = priv->y;
914428d7b3dSmrg				glyph_atlas = priv->cache->picture;
915428d7b3dSmrg			} else {
916428d7b3dSmrg				glyph_atlas = uxa_glyph_cache(screen, glyph, &glyph_x, &glyph_y);
917428d7b3dSmrg				if (glyph_atlas == NULL) {
918428d7b3dSmrg					/* no cache for this glyph */
919428d7b3dSmrg					glyph_atlas = GetGlyphPicture(glyph, screen);
920428d7b3dSmrg					glyph_x = glyph_y = 0;
921428d7b3dSmrg				}
922428d7b3dSmrg			}
923428d7b3dSmrg
924428d7b3dSmrg			uxa_composite(op,
925428d7b3dSmrg				      pSrc, glyph_atlas, pDst,
926428d7b3dSmrg				      xSrc + x - glyph->info.x,
927428d7b3dSmrg				      ySrc + y - glyph->info.y,
928428d7b3dSmrg				      glyph_x, glyph_y,
929428d7b3dSmrg				      x - glyph->info.x,
930428d7b3dSmrg				      y - glyph->info.y,
931428d7b3dSmrg				      glyph->info.width, glyph->info.height);
932428d7b3dSmrg
933428d7b3dSmrgnext_glyph:
934428d7b3dSmrg			x += glyph->info.xOff;
935428d7b3dSmrg			y += glyph->info.yOff;
936428d7b3dSmrg		}
937428d7b3dSmrg		list++;
938428d7b3dSmrg	}
939428d7b3dSmrg
940428d7b3dSmrg	return 0;
941428d7b3dSmrg}
942428d7b3dSmrg
943428d7b3dSmrgstatic Bool
944428d7b3dSmrgis_solid(PicturePtr picture)
945428d7b3dSmrg{
946428d7b3dSmrg	if (picture->pSourcePict) {
947428d7b3dSmrg		SourcePict *source = picture->pSourcePict;
948428d7b3dSmrg		return source->type == SourcePictTypeSolidFill;
949428d7b3dSmrg	} else {
950428d7b3dSmrg		return (picture->repeat &&
951428d7b3dSmrg			picture->pDrawable->width  == 1 &&
952428d7b3dSmrg			picture->pDrawable->height == 1);
953428d7b3dSmrg	}
954428d7b3dSmrg}
955428d7b3dSmrg
956428d7b3dSmrgvoid
957428d7b3dSmrguxa_glyphs(CARD8 op,
958428d7b3dSmrg	   PicturePtr pSrc,
959428d7b3dSmrg	   PicturePtr pDst,
960428d7b3dSmrg	   PictFormatPtr maskFormat,
961428d7b3dSmrg	   INT16 xSrc, INT16 ySrc,
962428d7b3dSmrg	   int nlist, GlyphListPtr list, GlyphPtr * glyphs)
963428d7b3dSmrg{
964428d7b3dSmrg	ScreenPtr screen = pDst->pDrawable->pScreen;
965428d7b3dSmrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
966428d7b3dSmrg
967428d7b3dSmrg	if (!uxa_screen->info->prepare_composite ||
968428d7b3dSmrg	    uxa_screen->force_fallback ||
969428d7b3dSmrg	    !uxa_drawable_is_offscreen(pDst->pDrawable) ||
970428d7b3dSmrg	    pDst->alphaMap || pSrc->alphaMap ||
971428d7b3dSmrg	    /* XXX we fail to handle (rare) non-solid sources correctly. */
972428d7b3dSmrg	    !is_solid(pSrc)) {
973428d7b3dSmrgfallback:
974428d7b3dSmrg	    uxa_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
975428d7b3dSmrg	    return;
976428d7b3dSmrg	}
977428d7b3dSmrg
978428d7b3dSmrg	/* basic sanity check */
979428d7b3dSmrg	if (uxa_screen->info->check_composite &&
980428d7b3dSmrg	    !uxa_screen->info->check_composite(op, pSrc, NULL, pDst, 0, 0)) {
981428d7b3dSmrg		goto fallback;
982428d7b3dSmrg	}
983428d7b3dSmrg
984428d7b3dSmrg	ValidatePicture(pSrc);
985428d7b3dSmrg	ValidatePicture(pDst);
986428d7b3dSmrg
987428d7b3dSmrg	if (!maskFormat) {
988428d7b3dSmrg		/* If we don't have a mask format but all the glyphs have the same format,
989428d7b3dSmrg		 * require ComponentAlpha and don't intersect, use the glyph format as mask
990428d7b3dSmrg		 * format for the full benefits of the glyph cache.
991428d7b3dSmrg		 */
992428d7b3dSmrg		if (NeedsComponent(list[0].format->format)) {
993428d7b3dSmrg			Bool sameFormat = TRUE;
994428d7b3dSmrg			int i;
995428d7b3dSmrg
996428d7b3dSmrg			maskFormat = list[0].format;
997428d7b3dSmrg
998428d7b3dSmrg			for (i = 0; i < nlist; i++) {
999428d7b3dSmrg				if (maskFormat->format != list[i].format->format) {
1000428d7b3dSmrg					sameFormat = FALSE;
1001428d7b3dSmrg					break;
1002428d7b3dSmrg				}
1003428d7b3dSmrg			}
1004428d7b3dSmrg
1005428d7b3dSmrg			if (!sameFormat ||
1006428d7b3dSmrg			    uxa_glyphs_intersect(nlist, list, glyphs))
1007428d7b3dSmrg				maskFormat = NULL;
1008428d7b3dSmrg		}
1009428d7b3dSmrg	}
1010428d7b3dSmrg
1011428d7b3dSmrg	if (!maskFormat) {
1012428d7b3dSmrg		if (uxa_glyphs_to_dst(op, pSrc, pDst,
1013428d7b3dSmrg				      xSrc, ySrc,
1014428d7b3dSmrg				      nlist, list, glyphs))
1015428d7b3dSmrg			goto fallback;
1016428d7b3dSmrg	} else {
1017428d7b3dSmrg		if (uxa_glyphs_via_mask(op,
1018428d7b3dSmrg					pSrc, pDst, maskFormat,
1019428d7b3dSmrg					xSrc, ySrc,
1020428d7b3dSmrg					nlist, list, glyphs))
1021428d7b3dSmrg			goto fallback;
1022428d7b3dSmrg	}
1023428d7b3dSmrg}
1024