1d514b0f3Smrg/*
2d514b0f3Smrg * Copyright © 2010 Intel Corporation
3d514b0f3Smrg * Partly based on code Copyright © 2008 Red Hat, Inc.
4d514b0f3Smrg * Partly based on code Copyright © 2000 SuSE, Inc.
5d514b0f3Smrg *
6d514b0f3Smrg * Permission to use, copy, modify, distribute, and sell this software and its
7d514b0f3Smrg * documentation for any purpose is hereby granted without fee, provided that
8d514b0f3Smrg * the above copyright notice appear in all copies and that both that
9d514b0f3Smrg * copyright notice and this permission notice appear in supporting
10d514b0f3Smrg * documentation, and that the name of Intel not be used in advertising or
11d514b0f3Smrg * publicity pertaining to distribution of the software without specific,
12d514b0f3Smrg * written prior permission.  Intel makes no representations about the
13d514b0f3Smrg * suitability of this software for any purpose.  It is provided "as is"
14d514b0f3Smrg * without express or implied warranty.
15d514b0f3Smrg *
16d514b0f3Smrg * INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17d514b0f3Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL
18d514b0f3Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19d514b0f3Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20d514b0f3Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21d514b0f3Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22d514b0f3Smrg *
23d514b0f3Smrg * Permission to use, copy, modify, distribute, and sell this software and its
24d514b0f3Smrg * documentation for any purpose is hereby granted without fee, provided that
25d514b0f3Smrg * the above copyright notice appear in all copies and that both that
26d514b0f3Smrg * copyright notice and this permission notice appear in supporting
27d514b0f3Smrg * documentation, and that the name of Red Hat not be used in advertising or
28d514b0f3Smrg * publicity pertaining to distribution of the software without specific,
29d514b0f3Smrg * written prior permission.  Red Hat makes no representations about the
30d514b0f3Smrg * suitability of this software for any purpose.  It is provided "as is"
31d514b0f3Smrg * without express or implied warranty.
32d514b0f3Smrg *
33d514b0f3Smrg * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
34d514b0f3Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat
35d514b0f3Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
36d514b0f3Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
37d514b0f3Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
38d514b0f3Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
39d514b0f3Smrg *
40d514b0f3Smrg * Permission to use, copy, modify, distribute, and sell this software and its
41d514b0f3Smrg * documentation for any purpose is hereby granted without fee, provided that
42d514b0f3Smrg * the above copyright notice appear in all copies and that both that
43d514b0f3Smrg * copyright notice and this permission notice appear in supporting
44d514b0f3Smrg * documentation, and that the name of SuSE not be used in advertising or
45d514b0f3Smrg * publicity pertaining to distribution of the software without specific,
46d514b0f3Smrg * written prior permission.  SuSE makes no representations about the
47d514b0f3Smrg * suitability of this software for any purpose.  It is provided "as is"
48d514b0f3Smrg * without express or implied warranty.
49d514b0f3Smrg *
50d514b0f3Smrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
51d514b0f3Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
52d514b0f3Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
53d514b0f3Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
54d514b0f3Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
55d514b0f3Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56d514b0f3Smrg *
57d514b0f3Smrg * Author: Chris Wilson <chris@chris-wilson.co.uk>
58d514b0f3Smrg * Based on code by: Keith Packard <keithp@keithp.com> and Owen Taylor <otaylor@fishsoup.net>
59d514b0f3Smrg */
60d514b0f3Smrg
61d514b0f3Smrg#ifdef HAVE_DIX_CONFIG_H
62d514b0f3Smrg#include <dix-config.h>
63d514b0f3Smrg#endif
64d514b0f3Smrg
65d514b0f3Smrg#include <stdlib.h>
66d514b0f3Smrg
67d514b0f3Smrg#include "uxa-priv.h"
68d514b0f3Smrg
69d514b0f3Smrg#include "mipict.h"
70d514b0f3Smrg
71d514b0f3Smrg/* Width of the pixmaps we use for the caches; this should be less than
72d514b0f3Smrg * max texture size of the driver; this may need to actually come from
73d514b0f3Smrg * the driver.
74d514b0f3Smrg */
75d514b0f3Smrg#define CACHE_PICTURE_SIZE 1024
76d514b0f3Smrg#define GLYPH_MIN_SIZE 8
77d514b0f3Smrg#define GLYPH_MAX_SIZE 64
78d514b0f3Smrg#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE))
79d514b0f3Smrg
80d514b0f3Smrgstruct uxa_glyph {
81d514b0f3Smrg	uxa_glyph_cache_t *cache;
82d514b0f3Smrg	uint16_t x, y;
83d514b0f3Smrg	uint16_t size, pos;
84d514b0f3Smrg};
85d514b0f3Smrg
86d514b0f3Smrg#if HAS_DEVPRIVATEKEYREC
87d514b0f3Smrgstatic DevPrivateKeyRec uxa_glyph_key;
88d514b0f3Smrg#else
89d514b0f3Smrgstatic int uxa_glyph_key;
90d514b0f3Smrg#endif
91d514b0f3Smrg
92d514b0f3Smrgstatic inline struct uxa_glyph *uxa_glyph_get_private(GlyphPtr glyph)
93d514b0f3Smrg{
94d514b0f3Smrg#if HAS_DEVPRIVATEKEYREC
95d514b0f3Smrg	return dixGetPrivate(&glyph->devPrivates, &uxa_glyph_key);
96d514b0f3Smrg#else
97d514b0f3Smrg	return dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_key);
98d514b0f3Smrg#endif
99d514b0f3Smrg}
100d514b0f3Smrg
101d514b0f3Smrgstatic inline void uxa_glyph_set_private(GlyphPtr glyph, struct uxa_glyph *priv)
102d514b0f3Smrg{
103d514b0f3Smrg	dixSetPrivate(&glyph->devPrivates, &uxa_glyph_key, priv);
104d514b0f3Smrg}
105d514b0f3Smrg
106d514b0f3Smrg#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
107d514b0f3Smrg
108d514b0f3Smrgstatic void uxa_unrealize_glyph_caches(ScreenPtr pScreen)
109d514b0f3Smrg{
110d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
111d514b0f3Smrg	int i;
112d514b0f3Smrg
113d514b0f3Smrg	for (i = 0; i < UXA_NUM_GLYPH_CACHE_FORMATS; i++) {
114d514b0f3Smrg		uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
115d514b0f3Smrg
116d514b0f3Smrg		if (cache->picture)
117d514b0f3Smrg			FreePicture(cache->picture, 0);
118d514b0f3Smrg
119d514b0f3Smrg		if (cache->glyphs)
120d514b0f3Smrg			free(cache->glyphs);
121d514b0f3Smrg	}
122d514b0f3Smrg}
123d514b0f3Smrg
124d514b0f3Smrgvoid uxa_glyphs_fini(ScreenPtr pScreen)
125d514b0f3Smrg{
126d514b0f3Smrg	uxa_unrealize_glyph_caches(pScreen);
127d514b0f3Smrg}
128d514b0f3Smrg
129d514b0f3Smrg/* All caches for a single format share a single pixmap for glyph storage,
130d514b0f3Smrg * allowing mixing glyphs of different sizes without paying a penalty
131d514b0f3Smrg * for switching between source pixmaps. (Note that for a size of font
132d514b0f3Smrg * right at the border between two sizes, we might be switching for almost
133d514b0f3Smrg * every glyph.)
134d514b0f3Smrg *
135d514b0f3Smrg * This function allocates the storage pixmap, and then fills in the
136d514b0f3Smrg * rest of the allocated structures for all caches with the given format.
137d514b0f3Smrg */
138d514b0f3Smrgstatic Bool uxa_realize_glyph_caches(ScreenPtr pScreen)
139d514b0f3Smrg{
140d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
141d514b0f3Smrg	unsigned int formats[] = {
142d514b0f3Smrg		PIXMAN_a8,
143d514b0f3Smrg		PIXMAN_a8r8g8b8,
144d514b0f3Smrg	};
145d514b0f3Smrg	int i;
146d514b0f3Smrg
147d514b0f3Smrg	memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches));
148d514b0f3Smrg
149d514b0f3Smrg	for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
150d514b0f3Smrg		uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
151d514b0f3Smrg		PixmapPtr pixmap;
152d514b0f3Smrg		PicturePtr picture;
153d514b0f3Smrg		CARD32 component_alpha;
154d514b0f3Smrg		int depth = PIXMAN_FORMAT_DEPTH(formats[i]);
155d514b0f3Smrg		int error;
156d514b0f3Smrg		PictFormatPtr pPictFormat = PictureMatchFormat(pScreen, depth, formats[i]);
157d514b0f3Smrg		if (!pPictFormat)
158d514b0f3Smrg			goto bail;
159d514b0f3Smrg
160d514b0f3Smrg		/* Now allocate the pixmap and picture */
161d514b0f3Smrg		pixmap = pScreen->CreatePixmap(pScreen,
162d514b0f3Smrg					       CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE, depth,
163d514b0f3Smrg					       0 /* INTEL_CREATE_PIXMAP_TILING_X -- FIXME */);
164d514b0f3Smrg		if (!pixmap)
165d514b0f3Smrg			goto bail;
166d514b0f3Smrg#if 0
167d514b0f3Smrg		assert (uxa_pixmap_is_offscreen(pixmap));
168d514b0f3Smrg#endif
169d514b0f3Smrg
170d514b0f3Smrg		component_alpha = NeedsComponent(pPictFormat->format);
171d514b0f3Smrg		picture = CreatePicture(0, &pixmap->drawable, pPictFormat,
172d514b0f3Smrg					CPComponentAlpha, &component_alpha,
173d514b0f3Smrg					serverClient, &error);
174d514b0f3Smrg
175d514b0f3Smrg		pScreen->DestroyPixmap(pixmap);
176d514b0f3Smrg
177d514b0f3Smrg		if (!picture)
178d514b0f3Smrg			goto bail;
179d514b0f3Smrg
180d514b0f3Smrg		ValidatePicture(picture);
181d514b0f3Smrg
182d514b0f3Smrg		cache->picture = picture;
183d514b0f3Smrg		cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE);
184d514b0f3Smrg		if (!cache->glyphs)
185d514b0f3Smrg			goto bail;
186d514b0f3Smrg
187d514b0f3Smrg		cache->evict = rand() % GLYPH_CACHE_SIZE;
188d514b0f3Smrg	}
189d514b0f3Smrg	assert(i == UXA_NUM_GLYPH_CACHE_FORMATS);
190d514b0f3Smrg
191d514b0f3Smrg	return TRUE;
192d514b0f3Smrg
193d514b0f3Smrgbail:
194d514b0f3Smrg	uxa_unrealize_glyph_caches(pScreen);
195d514b0f3Smrg	return FALSE;
196d514b0f3Smrg}
197d514b0f3Smrg
198d514b0f3Smrg
199d514b0f3SmrgBool uxa_glyphs_init(ScreenPtr pScreen)
200d514b0f3Smrg{
201d514b0f3Smrg#if HAS_DIXREGISTERPRIVATEKEY
202d514b0f3Smrg	if (!dixRegisterPrivateKey(&uxa_glyph_key, PRIVATE_GLYPH, 0))
203d514b0f3Smrg		return FALSE;
204d514b0f3Smrg#else
205d514b0f3Smrg	if (!dixRequestPrivate(&uxa_glyph_key, 0))
206d514b0f3Smrg		return FALSE;
207d514b0f3Smrg#endif
208d514b0f3Smrg
209d514b0f3Smrg	if (!uxa_realize_glyph_caches(pScreen))
210d514b0f3Smrg		return FALSE;
211d514b0f3Smrg
212d514b0f3Smrg	return TRUE;
213d514b0f3Smrg}
214d514b0f3Smrg
215d514b0f3Smrg/* The most efficient thing to way to upload the glyph to the screen
216d514b0f3Smrg * is to use CopyArea; uxa pixmaps are always offscreen.
217d514b0f3Smrg */
218d514b0f3Smrgstatic void
219d514b0f3Smrguxa_glyph_cache_upload_glyph(ScreenPtr screen,
220d514b0f3Smrg			     uxa_glyph_cache_t * cache,
221d514b0f3Smrg			     GlyphPtr glyph,
222d514b0f3Smrg			     int x, int y)
223d514b0f3Smrg{
224d514b0f3Smrg	PicturePtr pGlyphPicture = GetGlyphPicture(glyph, screen);
225d514b0f3Smrg	PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
226d514b0f3Smrg	PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
227d514b0f3Smrg	PixmapPtr scratch;
228d514b0f3Smrg	GCPtr gc;
229d514b0f3Smrg
230d514b0f3Smrg	gc = GetScratchGC(pCachePixmap->drawable.depth, screen);
231d514b0f3Smrg	if (!gc)
232d514b0f3Smrg		return;
233d514b0f3Smrg
234d514b0f3Smrg	ValidateGC(&pCachePixmap->drawable, gc);
235d514b0f3Smrg
236d514b0f3Smrg	scratch = pGlyphPixmap;
237d514b0f3Smrg	/* Create a temporary bo to stream the updates to the cache */
238d514b0f3Smrg	if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth ||
239d514b0f3Smrg	    !uxa_pixmap_is_offscreen(scratch)) {
240d514b0f3Smrg		scratch = screen->CreatePixmap(screen,
241d514b0f3Smrg					       glyph->info.width,
242d514b0f3Smrg					       glyph->info.height,
243d514b0f3Smrg					       pCachePixmap->drawable.depth,
244d514b0f3Smrg					       UXA_CREATE_PIXMAP_FOR_MAP);
245d514b0f3Smrg		if (scratch) {
246d514b0f3Smrg			if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) {
247d514b0f3Smrg				PicturePtr picture;
248d514b0f3Smrg				int error;
249d514b0f3Smrg
250d514b0f3Smrg				picture = CreatePicture(0, &scratch->drawable,
251d514b0f3Smrg							PictureMatchFormat(screen,
252d514b0f3Smrg									   pCachePixmap->drawable.depth,
253d514b0f3Smrg									   cache->picture->format),
254d514b0f3Smrg							0, NULL,
255d514b0f3Smrg							serverClient, &error);
256d514b0f3Smrg				if (picture) {
257d514b0f3Smrg					ValidatePicture(picture);
258d514b0f3Smrg					uxa_composite(PictOpSrc, pGlyphPicture, NULL, picture,
259d514b0f3Smrg						      0, 0,
260d514b0f3Smrg						      0, 0,
261d514b0f3Smrg						      0, 0,
262d514b0f3Smrg						      glyph->info.width, glyph->info.height);
263d514b0f3Smrg					FreePicture(picture, 0);
264d514b0f3Smrg				}
265d514b0f3Smrg			} else {
266d514b0f3Smrg				uxa_copy_area(&pGlyphPixmap->drawable,
267d514b0f3Smrg					      &scratch->drawable,
268d514b0f3Smrg					      gc,
269d514b0f3Smrg					      0, 0,
270d514b0f3Smrg					      glyph->info.width, glyph->info.height,
271d514b0f3Smrg					      0, 0);
272d514b0f3Smrg			}
273d514b0f3Smrg		} else {
274d514b0f3Smrg			scratch = pGlyphPixmap;
275d514b0f3Smrg		}
276d514b0f3Smrg	}
277d514b0f3Smrg
278d514b0f3Smrg	uxa_copy_area(&scratch->drawable, &pCachePixmap->drawable, gc,
279d514b0f3Smrg		      0, 0,
280d514b0f3Smrg		      glyph->info.width, glyph->info.height,
281d514b0f3Smrg		      x, y);
282d514b0f3Smrg
283d514b0f3Smrg	if (scratch != pGlyphPixmap)
284d514b0f3Smrg		screen->DestroyPixmap(scratch);
285d514b0f3Smrg
286d514b0f3Smrg	FreeScratchGC(gc);
287d514b0f3Smrg}
288d514b0f3Smrg
289d514b0f3Smrgvoid
290d514b0f3Smrguxa_glyph_unrealize(ScreenPtr pScreen,
291d514b0f3Smrg		    GlyphPtr pGlyph)
292d514b0f3Smrg{
293d514b0f3Smrg	struct uxa_glyph *priv;
294d514b0f3Smrg
295d514b0f3Smrg	priv = uxa_glyph_get_private(pGlyph);
296d514b0f3Smrg	if (priv == NULL)
297d514b0f3Smrg		return;
298d514b0f3Smrg
299d514b0f3Smrg	priv->cache->glyphs[priv->pos] = NULL;
300d514b0f3Smrg
301d514b0f3Smrg	uxa_glyph_set_private(pGlyph, NULL);
302d514b0f3Smrg	free(priv);
303d514b0f3Smrg}
304d514b0f3Smrg
305d514b0f3Smrg/* Cut and paste from render/glyph.c - probably should export it instead */
306d514b0f3Smrgstatic void
307d514b0f3Smrguxa_glyph_extents(int nlist,
308d514b0f3Smrg		  GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
309d514b0f3Smrg{
310d514b0f3Smrg	int x1, x2, y1, y2;
311d514b0f3Smrg	int x, y, n;
312d514b0f3Smrg
313d514b0f3Smrg	x1 = y1 = MAXSHORT;
314d514b0f3Smrg	x2 = y2 = MINSHORT;
315d514b0f3Smrg	x = y = 0;
316d514b0f3Smrg	while (nlist--) {
317d514b0f3Smrg		x += list->xOff;
318d514b0f3Smrg		y += list->yOff;
319d514b0f3Smrg		n = list->len;
320d514b0f3Smrg		list++;
321d514b0f3Smrg		while (n--) {
322d514b0f3Smrg			GlyphPtr glyph = *glyphs++;
323d514b0f3Smrg			int v;
324d514b0f3Smrg
325d514b0f3Smrg			v = x - glyph->info.x;
326d514b0f3Smrg			if (v < x1)
327d514b0f3Smrg			    x1 = v;
328d514b0f3Smrg			v += glyph->info.width;
329d514b0f3Smrg			if (v > x2)
330d514b0f3Smrg			    x2 = v;
331d514b0f3Smrg
332d514b0f3Smrg			v = y - glyph->info.y;
333d514b0f3Smrg			if (v < y1)
334d514b0f3Smrg			    y1 = v;
335d514b0f3Smrg			v += glyph->info.height;
336d514b0f3Smrg			if (v > y2)
337d514b0f3Smrg			    y2 = v;
338d514b0f3Smrg
339d514b0f3Smrg			x += glyph->info.xOff;
340d514b0f3Smrg			y += glyph->info.yOff;
341d514b0f3Smrg		}
342d514b0f3Smrg	}
343d514b0f3Smrg
344d514b0f3Smrg	extents->x1 = x1 < MINSHORT ? MINSHORT : x1;
345d514b0f3Smrg	extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2;
346d514b0f3Smrg	extents->y1 = y1 < MINSHORT ? MINSHORT : y1;
347d514b0f3Smrg	extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2;
348d514b0f3Smrg}
349d514b0f3Smrg
350d514b0f3Smrg/**
351d514b0f3Smrg * Returns TRUE if the glyphs in the lists intersect.  Only checks based on
352d514b0f3Smrg * bounding box, which appears to be good enough to catch most cases at least.
353d514b0f3Smrg */
354d514b0f3Smrgstatic Bool
355d514b0f3Smrguxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs)
356d514b0f3Smrg{
357d514b0f3Smrg	int x1, x2, y1, y2;
358d514b0f3Smrg	int n;
359d514b0f3Smrg	int x, y;
360d514b0f3Smrg	BoxRec extents;
361d514b0f3Smrg	Bool first = TRUE;
362d514b0f3Smrg
363d514b0f3Smrg	x = 0;
364d514b0f3Smrg	y = 0;
365d514b0f3Smrg	extents.x1 = 0;
366d514b0f3Smrg	extents.y1 = 0;
367d514b0f3Smrg	extents.x2 = 0;
368d514b0f3Smrg	extents.y2 = 0;
369d514b0f3Smrg	while (nlist--) {
370d514b0f3Smrg		x += list->xOff;
371d514b0f3Smrg		y += list->yOff;
372d514b0f3Smrg		n = list->len;
373d514b0f3Smrg		list++;
374d514b0f3Smrg		while (n--) {
375d514b0f3Smrg			GlyphPtr glyph = *glyphs++;
376d514b0f3Smrg
377d514b0f3Smrg			if (glyph->info.width == 0 || glyph->info.height == 0) {
378d514b0f3Smrg				x += glyph->info.xOff;
379d514b0f3Smrg				y += glyph->info.yOff;
380d514b0f3Smrg				continue;
381d514b0f3Smrg			}
382d514b0f3Smrg
383d514b0f3Smrg			x1 = x - glyph->info.x;
384d514b0f3Smrg			if (x1 < MINSHORT)
385d514b0f3Smrg				x1 = MINSHORT;
386d514b0f3Smrg			y1 = y - glyph->info.y;
387d514b0f3Smrg			if (y1 < MINSHORT)
388d514b0f3Smrg				y1 = MINSHORT;
389d514b0f3Smrg			x2 = x1 + glyph->info.width;
390d514b0f3Smrg			if (x2 > MAXSHORT)
391d514b0f3Smrg				x2 = MAXSHORT;
392d514b0f3Smrg			y2 = y1 + glyph->info.height;
393d514b0f3Smrg			if (y2 > MAXSHORT)
394d514b0f3Smrg				y2 = MAXSHORT;
395d514b0f3Smrg
396d514b0f3Smrg			if (first) {
397d514b0f3Smrg				extents.x1 = x1;
398d514b0f3Smrg				extents.y1 = y1;
399d514b0f3Smrg				extents.x2 = x2;
400d514b0f3Smrg				extents.y2 = y2;
401d514b0f3Smrg				first = FALSE;
402d514b0f3Smrg			} else {
403d514b0f3Smrg				if (x1 < extents.x2 && x2 > extents.x1 &&
404d514b0f3Smrg				    y1 < extents.y2 && y2 > extents.y1) {
405d514b0f3Smrg					return TRUE;
406d514b0f3Smrg				}
407d514b0f3Smrg
408d514b0f3Smrg				if (x1 < extents.x1)
409d514b0f3Smrg					extents.x1 = x1;
410d514b0f3Smrg				if (x2 > extents.x2)
411d514b0f3Smrg					extents.x2 = x2;
412d514b0f3Smrg				if (y1 < extents.y1)
413d514b0f3Smrg					extents.y1 = y1;
414d514b0f3Smrg				if (y2 > extents.y2)
415d514b0f3Smrg					extents.y2 = y2;
416d514b0f3Smrg			}
417d514b0f3Smrg			x += glyph->info.xOff;
418d514b0f3Smrg			y += glyph->info.yOff;
419d514b0f3Smrg		}
420d514b0f3Smrg	}
421d514b0f3Smrg
422d514b0f3Smrg	return FALSE;
423d514b0f3Smrg}
424d514b0f3Smrg
425d514b0f3Smrgstatic void
426d514b0f3Smrguxa_check_glyphs(CARD8 op,
427d514b0f3Smrg		 PicturePtr src,
428d514b0f3Smrg		 PicturePtr dst,
429d514b0f3Smrg		 PictFormatPtr maskFormat,
430d514b0f3Smrg		 INT16 xSrc,
431d514b0f3Smrg		 INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
432d514b0f3Smrg{
433d514b0f3Smrg	ScreenPtr pScreen = dst->pDrawable->pScreen;
434d514b0f3Smrg	pixman_image_t *image;
435d514b0f3Smrg	PixmapPtr scratch;
436d514b0f3Smrg	PicturePtr mask;
437d514b0f3Smrg	int width = 0, height = 0;
438d514b0f3Smrg	int x, y, n;
439d514b0f3Smrg	int xDst = list->xOff, yDst = list->yOff;
440d514b0f3Smrg	BoxRec extents = { 0, 0, 0, 0 };
441d514b0f3Smrg
442d514b0f3Smrg	if (maskFormat) {
443d514b0f3Smrg		pixman_format_code_t format;
444d514b0f3Smrg		CARD32 component_alpha;
445d514b0f3Smrg		int error;
446d514b0f3Smrg
447d514b0f3Smrg		uxa_glyph_extents(nlist, list, glyphs, &extents);
448d514b0f3Smrg		if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
449d514b0f3Smrg			return;
450d514b0f3Smrg
451d514b0f3Smrg		width = extents.x2 - extents.x1;
452d514b0f3Smrg		height = extents.y2 - extents.y1;
453d514b0f3Smrg
454d514b0f3Smrg		format = maskFormat->format |
455d514b0f3Smrg			(BitsPerPixel(maskFormat->depth) << 24);
456d514b0f3Smrg		image =
457d514b0f3Smrg			pixman_image_create_bits(format, width, height, NULL, 0);
458d514b0f3Smrg		if (!image)
459d514b0f3Smrg			return;
460d514b0f3Smrg
461d514b0f3Smrg		scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height,
462d514b0f3Smrg						 PIXMAN_FORMAT_DEPTH(format),
463d514b0f3Smrg						 PIXMAN_FORMAT_BPP(format),
464d514b0f3Smrg						 pixman_image_get_stride(image),
465d514b0f3Smrg						 pixman_image_get_data(image));
466d514b0f3Smrg
467d514b0f3Smrg		if (!scratch) {
468d514b0f3Smrg			pixman_image_unref(image);
469d514b0f3Smrg			return;
470d514b0f3Smrg		}
471d514b0f3Smrg
472d514b0f3Smrg		component_alpha = NeedsComponent(maskFormat->format);
473d514b0f3Smrg		mask = CreatePicture(0, &scratch->drawable,
474d514b0f3Smrg				     maskFormat, CPComponentAlpha,
475d514b0f3Smrg				     &component_alpha, serverClient, &error);
476d514b0f3Smrg		if (!mask) {
477d514b0f3Smrg			FreeScratchPixmapHeader(scratch);
478d514b0f3Smrg			pixman_image_unref(image);
479d514b0f3Smrg			return;
480d514b0f3Smrg		}
481d514b0f3Smrg		ValidatePicture(mask);
482d514b0f3Smrg
483d514b0f3Smrg		x = -extents.x1;
484d514b0f3Smrg		y = -extents.y1;
485d514b0f3Smrg	} else {
486d514b0f3Smrg		mask = dst;
487d514b0f3Smrg		x = 0;
488d514b0f3Smrg		y = 0;
489d514b0f3Smrg	}
490d514b0f3Smrg
491d514b0f3Smrg	while (nlist--) {
492d514b0f3Smrg		x += list->xOff;
493d514b0f3Smrg		y += list->yOff;
494d514b0f3Smrg		n = list->len;
495d514b0f3Smrg		while (n--) {
496d514b0f3Smrg			GlyphPtr glyph = *glyphs++;
497d514b0f3Smrg			PicturePtr g = GetGlyphPicture(glyph, pScreen);
498d514b0f3Smrg			if (g) {
499d514b0f3Smrg				if (maskFormat) {
500d514b0f3Smrg					CompositePicture(PictOpAdd, g, NULL, mask,
501d514b0f3Smrg							 0, 0,
502d514b0f3Smrg							 0, 0,
503d514b0f3Smrg							 x - glyph->info.x,
504d514b0f3Smrg							 y - glyph->info.y,
505d514b0f3Smrg							 glyph->info.width,
506d514b0f3Smrg							 glyph->info.height);
507d514b0f3Smrg				} else {
508d514b0f3Smrg					CompositePicture(op, src, g, dst,
509d514b0f3Smrg							 xSrc + (x - glyph->info.x) - xDst,
510d514b0f3Smrg							 ySrc + (y - glyph->info.y) - yDst,
511d514b0f3Smrg							 0, 0,
512d514b0f3Smrg							 x - glyph->info.x,
513d514b0f3Smrg							 y - glyph->info.y,
514d514b0f3Smrg							 glyph->info.width,
515d514b0f3Smrg							 glyph->info.height);
516d514b0f3Smrg				}
517d514b0f3Smrg			}
518d514b0f3Smrg
519d514b0f3Smrg			x += glyph->info.xOff;
520d514b0f3Smrg			y += glyph->info.yOff;
521d514b0f3Smrg		}
522d514b0f3Smrg		list++;
523d514b0f3Smrg	}
524d514b0f3Smrg
525d514b0f3Smrg	if (maskFormat) {
526d514b0f3Smrg		x = extents.x1;
527d514b0f3Smrg		y = extents.y1;
528d514b0f3Smrg		CompositePicture(op, src, mask, dst,
529d514b0f3Smrg				 xSrc + x - xDst,
530d514b0f3Smrg				 ySrc + y - yDst,
531d514b0f3Smrg				 0, 0,
532d514b0f3Smrg				 x, y,
533d514b0f3Smrg				 width, height);
534d514b0f3Smrg		FreePicture(mask, 0);
535d514b0f3Smrg		FreeScratchPixmapHeader(scratch);
536d514b0f3Smrg		pixman_image_unref(image);
537d514b0f3Smrg	}
538d514b0f3Smrg}
539d514b0f3Smrg
540d514b0f3Smrgstatic inline unsigned int
541d514b0f3Smrguxa_glyph_size_to_count(int size)
542d514b0f3Smrg{
543d514b0f3Smrg	size /= GLYPH_MIN_SIZE;
544d514b0f3Smrg	return size * size;
545d514b0f3Smrg}
546d514b0f3Smrg
547d514b0f3Smrgstatic inline unsigned int
548d514b0f3Smrguxa_glyph_count_to_mask(int count)
549d514b0f3Smrg{
550d514b0f3Smrg	return ~(count - 1);
551d514b0f3Smrg}
552d514b0f3Smrg
553d514b0f3Smrgstatic inline unsigned int
554d514b0f3Smrguxa_glyph_size_to_mask(int size)
555d514b0f3Smrg{
556d514b0f3Smrg	return uxa_glyph_count_to_mask(uxa_glyph_size_to_count(size));
557d514b0f3Smrg}
558d514b0f3Smrg
559d514b0f3Smrgstatic PicturePtr
560d514b0f3Smrguxa_glyph_cache(ScreenPtr screen, GlyphPtr glyph, int *out_x, int *out_y)
561d514b0f3Smrg{
562d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
563d514b0f3Smrg	PicturePtr glyph_picture = GetGlyphPicture(glyph, screen);
564d514b0f3Smrg	uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0];
565d514b0f3Smrg	struct uxa_glyph *priv = NULL;
566d514b0f3Smrg	int size, mask, pos, s;
567d514b0f3Smrg
568d514b0f3Smrg	if (glyph->info.width > GLYPH_MAX_SIZE || glyph->info.height > GLYPH_MAX_SIZE)
569d514b0f3Smrg		return NULL;
570d514b0f3Smrg
571d514b0f3Smrg	for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
572d514b0f3Smrg		if (glyph->info.width <= size && glyph->info.height <= size)
573d514b0f3Smrg			break;
574d514b0f3Smrg
575d514b0f3Smrg	s = uxa_glyph_size_to_count(size);
576d514b0f3Smrg	mask = uxa_glyph_count_to_mask(s);
577d514b0f3Smrg	pos = (cache->count + s - 1) & mask;
578d514b0f3Smrg	if (pos < GLYPH_CACHE_SIZE) {
579d514b0f3Smrg		cache->count = pos + s;
580d514b0f3Smrg	} else {
581d514b0f3Smrg		for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) {
582d514b0f3Smrg			int i = cache->evict & uxa_glyph_size_to_mask(s);
583d514b0f3Smrg			GlyphPtr evicted = cache->glyphs[i];
584d514b0f3Smrg			if (evicted == NULL)
585d514b0f3Smrg				continue;
586d514b0f3Smrg
587d514b0f3Smrg			priv = uxa_glyph_get_private(evicted);
588d514b0f3Smrg			if (priv->size >= s) {
589d514b0f3Smrg				cache->glyphs[i] = NULL;
590d514b0f3Smrg				uxa_glyph_set_private(evicted, NULL);
591d514b0f3Smrg				pos = cache->evict & uxa_glyph_size_to_mask(size);
592d514b0f3Smrg			} else
593d514b0f3Smrg				priv = NULL;
594d514b0f3Smrg			break;
595d514b0f3Smrg		}
596d514b0f3Smrg		if (priv == NULL) {
597d514b0f3Smrg			int count = uxa_glyph_size_to_count(size);
598d514b0f3Smrg			mask = uxa_glyph_count_to_mask(count);
599d514b0f3Smrg			pos = cache->evict & mask;
600d514b0f3Smrg			for (s = 0; s < count; s++) {
601d514b0f3Smrg				GlyphPtr evicted = cache->glyphs[pos + s];
602d514b0f3Smrg				if (evicted != NULL) {
603d514b0f3Smrg					if (priv != NULL)
604d514b0f3Smrg						free(priv);
605d514b0f3Smrg
606d514b0f3Smrg					priv = uxa_glyph_get_private(evicted);
607d514b0f3Smrg					uxa_glyph_set_private(evicted, NULL);
608d514b0f3Smrg					cache->glyphs[pos + s] = NULL;
609d514b0f3Smrg				}
610d514b0f3Smrg			}
611d514b0f3Smrg		}
612d514b0f3Smrg
613d514b0f3Smrg		/* And pick a new eviction position */
614d514b0f3Smrg		cache->evict = rand() % GLYPH_CACHE_SIZE;
615d514b0f3Smrg	}
616d514b0f3Smrg
617d514b0f3Smrg	if (priv == NULL) {
618d514b0f3Smrg		priv = malloc(sizeof(struct uxa_glyph));
619d514b0f3Smrg		if (priv == NULL)
620d514b0f3Smrg			return NULL;
621d514b0f3Smrg	}
622d514b0f3Smrg
623d514b0f3Smrg	uxa_glyph_set_private(glyph, priv);
624d514b0f3Smrg	cache->glyphs[pos] = glyph;
625d514b0f3Smrg
626d514b0f3Smrg	priv->cache = cache;
627d514b0f3Smrg	priv->size = size;
628d514b0f3Smrg	priv->pos = pos;
629d514b0f3Smrg	s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE));
630d514b0f3Smrg	priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE;
631d514b0f3Smrg	priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE;
632d514b0f3Smrg	for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) {
633d514b0f3Smrg		if (pos & 1)
634d514b0f3Smrg			priv->x += s;
635d514b0f3Smrg		if (pos & 2)
636d514b0f3Smrg			priv->y += s;
637d514b0f3Smrg		pos >>= 2;
638d514b0f3Smrg	}
639d514b0f3Smrg
640d514b0f3Smrg	uxa_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y);
641d514b0f3Smrg
642d514b0f3Smrg	*out_x = priv->x;
643d514b0f3Smrg	*out_y = priv->y;
644d514b0f3Smrg	return cache->picture;
645d514b0f3Smrg}
646d514b0f3Smrg
647d514b0f3Smrgstatic int
648d514b0f3Smrguxa_glyphs_to_dst(CARD8 op,
649d514b0f3Smrg		  PicturePtr pSrc,
650d514b0f3Smrg		  PicturePtr pDst,
651d514b0f3Smrg		  INT16 src_x, INT16 src_y,
652d514b0f3Smrg		  INT16 xDst, INT16 yDst,
653d514b0f3Smrg		  int nlist, GlyphListPtr list, GlyphPtr * glyphs,
654d514b0f3Smrg		  BoxPtr extents)
655d514b0f3Smrg{
656d514b0f3Smrg	ScreenPtr screen = pDst->pDrawable->pScreen;
657d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
658d514b0f3Smrg	PixmapPtr src_pixmap, dst_pixmap;
659d514b0f3Smrg	PicturePtr localSrc, glyph_atlas;
660d514b0f3Smrg	int x, y, n, nrect;
661d514b0f3Smrg	BoxRec box;
662d514b0f3Smrg
663d514b0f3Smrg	if (uxa_screen->info->check_composite_texture &&
664d514b0f3Smrg	    uxa_screen->info->check_composite_texture(screen, pSrc)) {
665d514b0f3Smrg		if (pSrc->pDrawable) {
666d514b0f3Smrg			int src_off_x, src_off_y;
667d514b0f3Smrg
668d514b0f3Smrg			src_pixmap = uxa_get_offscreen_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y);
669d514b0f3Smrg			if (src_pixmap == NULL)
670d514b0f3Smrg				return -1;
671d514b0f3Smrg
672d514b0f3Smrg			src_x += pSrc->pDrawable->x + src_off_x;
673d514b0f3Smrg			src_y += pSrc->pDrawable->y + src_off_y;
674d514b0f3Smrg		} else {
675d514b0f3Smrg			src_pixmap = NULL;
676d514b0f3Smrg		}
677d514b0f3Smrg		localSrc = pSrc;
678d514b0f3Smrg	} else {
679d514b0f3Smrg		int width, height;
680d514b0f3Smrg
681d514b0f3Smrg		if (extents == NULL) {
682d514b0f3Smrg			uxa_glyph_extents(nlist, list, glyphs, &box);
683d514b0f3Smrg			extents = &box;
684d514b0f3Smrg		}
685d514b0f3Smrg
686d514b0f3Smrg		width  = extents->x2 - extents->x1;
687d514b0f3Smrg		height = extents->y2 - extents->y1;
688d514b0f3Smrg		if (width == 0 || height == 0)
689d514b0f3Smrg			return 0;
690d514b0f3Smrg
691d514b0f3Smrg		if (pSrc->pDrawable) {
692d514b0f3Smrg			int src_off_x, src_off_y;
693d514b0f3Smrg
694d514b0f3Smrg			src_off_x = extents->x1 - xDst;
695d514b0f3Smrg			src_off_y = extents->y1 - yDst;
696d514b0f3Smrg			localSrc = uxa_acquire_drawable(screen, pSrc,
697d514b0f3Smrg							src_x + src_off_x, src_y + src_off_y,
698d514b0f3Smrg							width, height,
699d514b0f3Smrg							&src_x, &src_y);
700d514b0f3Smrg			if (uxa_screen->info->check_composite_texture &&
701d514b0f3Smrg			    !uxa_screen->info->check_composite_texture(screen, localSrc)) {
702d514b0f3Smrg				if (localSrc != pSrc)
703d514b0f3Smrg					FreePicture(localSrc, 0);
704d514b0f3Smrg				return -1;
705d514b0f3Smrg			}
706d514b0f3Smrg
707d514b0f3Smrg			src_pixmap = uxa_get_offscreen_pixmap(localSrc->pDrawable, &src_off_x, &src_off_y);
708d514b0f3Smrg			if (src_pixmap == NULL) {
709d514b0f3Smrg				if (localSrc != pSrc)
710d514b0f3Smrg					FreePicture(localSrc, 0);
711d514b0f3Smrg				return -1;
712d514b0f3Smrg			}
713d514b0f3Smrg
714d514b0f3Smrg			src_x += localSrc->pDrawable->x + src_off_x;
715d514b0f3Smrg			src_y += localSrc->pDrawable->y + src_off_y;
716d514b0f3Smrg		} else {
717d514b0f3Smrg			localSrc = uxa_acquire_pattern(screen, pSrc,
718d514b0f3Smrg						       PIXMAN_a8r8g8b8, 0, 0, width, height);
719d514b0f3Smrg			if (!localSrc)
720d514b0f3Smrg				return 1;
721d514b0f3Smrg
722d514b0f3Smrg			src_pixmap = uxa_get_drawable_pixmap(localSrc->pDrawable);
723d514b0f3Smrg			if (src_pixmap == NULL) {
724d514b0f3Smrg				FreePicture(localSrc, 0);
725d514b0f3Smrg				return -1;
726d514b0f3Smrg			}
727d514b0f3Smrg
728d514b0f3Smrg			src_x = src_y = 0;
729d514b0f3Smrg		}
730d514b0f3Smrg	}
731d514b0f3Smrg
732d514b0f3Smrg	dst_pixmap = uxa_get_offscreen_pixmap(pDst->pDrawable, &x, &y);
733d514b0f3Smrg	x += xDst + pDst->pDrawable->x - list->xOff;
734d514b0f3Smrg	y += yDst + pDst->pDrawable->y - list->yOff;
735d514b0f3Smrg
736d514b0f3Smrg	glyph_atlas = NULL;
737d514b0f3Smrg	while (nlist--) {
738d514b0f3Smrg		x += list->xOff;
739d514b0f3Smrg		y += list->yOff;
740d514b0f3Smrg		n = list->len;
741d514b0f3Smrg		while (n--) {
742d514b0f3Smrg			GlyphPtr glyph = *glyphs++;
743d514b0f3Smrg			PicturePtr this_atlas;
744d514b0f3Smrg			int mask_x, mask_y;
745d514b0f3Smrg			struct uxa_glyph *priv;
746d514b0f3Smrg
747d514b0f3Smrg			if (glyph->info.width == 0 || glyph->info.height == 0)
748d514b0f3Smrg				goto next_glyph;
749d514b0f3Smrg
750d514b0f3Smrg			priv = uxa_glyph_get_private(glyph);
751d514b0f3Smrg			if (priv != NULL) {
752d514b0f3Smrg				mask_x = priv->x;
753d514b0f3Smrg				mask_y = priv->y;
754d514b0f3Smrg				this_atlas = priv->cache->picture;
755d514b0f3Smrg			} else {
756d514b0f3Smrg				if (glyph_atlas) {
757d514b0f3Smrg					uxa_screen->info->done_composite(dst_pixmap);
758d514b0f3Smrg					glyph_atlas = NULL;
759d514b0f3Smrg				}
760d514b0f3Smrg				this_atlas = uxa_glyph_cache(screen, glyph, &mask_x, &mask_y);
761d514b0f3Smrg				if (this_atlas == NULL) {
762d514b0f3Smrg					/* no cache for this glyph */
763d514b0f3Smrg					this_atlas = GetGlyphPicture(glyph, screen);
764d514b0f3Smrg					mask_x = mask_y = 0;
765d514b0f3Smrg				}
766d514b0f3Smrg			}
767d514b0f3Smrg
768d514b0f3Smrg			if (this_atlas != glyph_atlas) {
769d514b0f3Smrg				PixmapPtr mask_pixmap;
770d514b0f3Smrg
771d514b0f3Smrg				if (glyph_atlas)
772d514b0f3Smrg					uxa_screen->info->done_composite(dst_pixmap);
773d514b0f3Smrg
774d514b0f3Smrg				mask_pixmap =
775d514b0f3Smrg					uxa_get_drawable_pixmap(this_atlas->pDrawable);
776d514b0f3Smrg				assert (uxa_pixmap_is_offscreen(mask_pixmap));
777d514b0f3Smrg
778d514b0f3Smrg				if (!uxa_screen->info->prepare_composite(op,
779d514b0f3Smrg									 localSrc, this_atlas, pDst,
780d514b0f3Smrg									 src_pixmap, mask_pixmap, dst_pixmap))
781d514b0f3Smrg					return -1;
782d514b0f3Smrg
783d514b0f3Smrg				glyph_atlas = this_atlas;
784d514b0f3Smrg			}
785d514b0f3Smrg
786d514b0f3Smrg			nrect = REGION_NUM_RECTS(pDst->pCompositeClip);
787d514b0f3Smrg			if (nrect == 1) {
788d514b0f3Smrg				uxa_screen->info->composite(dst_pixmap,
789d514b0f3Smrg							    x + src_x, y + src_y,
790d514b0f3Smrg							    mask_x, mask_y,
791d514b0f3Smrg							    x - glyph->info.x,
792d514b0f3Smrg							    y - glyph->info.y,
793d514b0f3Smrg							    glyph->info.width,
794d514b0f3Smrg							    glyph->info.height);
795d514b0f3Smrg			} else {
796d514b0f3Smrg				BoxPtr rects = REGION_RECTS(pDst->pCompositeClip);
797d514b0f3Smrg				do {
798d514b0f3Smrg					int x1 = x - glyph->info.x, dx = 0;
799d514b0f3Smrg					int y1 = y - glyph->info.y, dy = 0;
800d514b0f3Smrg					int x2 = x1 + glyph->info.width;
801d514b0f3Smrg					int y2 = y1 + glyph->info.height;
802d514b0f3Smrg
803d514b0f3Smrg					if (x1 < rects->x1)
804d514b0f3Smrg						dx = rects->x1 - x1, x1 = rects->x1;
805d514b0f3Smrg					if (x2 > rects->x2)
806d514b0f3Smrg						x2 = rects->x2;
807d514b0f3Smrg					if (y1 < rects->y1)
808d514b0f3Smrg						dy = rects->y1 - y1, y1 = rects->y1;
809d514b0f3Smrg					if (y2 > rects->y2)
810d514b0f3Smrg						y2 = rects->y2;
811d514b0f3Smrg
812d514b0f3Smrg					if (x1 < x2 && y1 < y2) {
813d514b0f3Smrg						uxa_screen->info->composite(dst_pixmap,
814d514b0f3Smrg									    x1 + src_x, y1 + src_y,
815d514b0f3Smrg									    dx + mask_x, dy + mask_y,
816d514b0f3Smrg									    x1, y1,
817d514b0f3Smrg									    x2 - x1, y2 - y1);
818d514b0f3Smrg					}
819d514b0f3Smrg					rects++;
820d514b0f3Smrg				} while (--nrect);
821d514b0f3Smrg			}
822d514b0f3Smrg
823d514b0f3Smrgnext_glyph:
824d514b0f3Smrg			x += glyph->info.xOff;
825d514b0f3Smrg			y += glyph->info.yOff;
826d514b0f3Smrg		}
827d514b0f3Smrg		list++;
828d514b0f3Smrg	}
829d514b0f3Smrg	if (glyph_atlas)
830d514b0f3Smrg		uxa_screen->info->done_composite(dst_pixmap);
831d514b0f3Smrg
832d514b0f3Smrg	if (localSrc != pSrc)
833d514b0f3Smrg		FreePicture(localSrc, 0);
834d514b0f3Smrg
835d514b0f3Smrg	return 0;
836d514b0f3Smrg}
837d514b0f3Smrg
838d514b0f3Smrgstatic void
839d514b0f3Smrguxa_clear_pixmap(ScreenPtr screen,
840d514b0f3Smrg		 uxa_screen_t *uxa_screen,
841d514b0f3Smrg		 PixmapPtr pixmap)
842d514b0f3Smrg{
843d514b0f3Smrg	if (uxa_screen->info->check_solid &&
844d514b0f3Smrg	    !uxa_screen->info->check_solid(&pixmap->drawable, GXcopy, FB_ALLONES))
845d514b0f3Smrg		goto fallback;
846d514b0f3Smrg
847d514b0f3Smrg	if (!uxa_screen->info->prepare_solid(pixmap, GXcopy, FB_ALLONES, 0))
848d514b0f3Smrg		goto fallback;
849d514b0f3Smrg
850d514b0f3Smrg	uxa_screen->info->solid(pixmap,
851d514b0f3Smrg				0, 0,
852d514b0f3Smrg				pixmap->drawable.width,
853d514b0f3Smrg				pixmap->drawable.height);
854d514b0f3Smrg
855d514b0f3Smrg	uxa_screen->info->done_solid(pixmap);
856d514b0f3Smrg	return;
857d514b0f3Smrg
858d514b0f3Smrgfallback:
859d514b0f3Smrg	{
860d514b0f3Smrg		GCPtr gc;
861d514b0f3Smrg
862d514b0f3Smrg		gc = GetScratchGC(pixmap->drawable.depth, screen);
863d514b0f3Smrg		if (gc) {
864d514b0f3Smrg			xRectangle rect;
865d514b0f3Smrg
866d514b0f3Smrg			ValidateGC(&pixmap->drawable, gc);
867d514b0f3Smrg
868d514b0f3Smrg			rect.x = 0;
869d514b0f3Smrg			rect.y = 0;
870d514b0f3Smrg			rect.width  = pixmap->drawable.width;
871d514b0f3Smrg			rect.height = pixmap->drawable.height;
872d514b0f3Smrg			gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect);
873d514b0f3Smrg
874d514b0f3Smrg			FreeScratchGC(gc);
875d514b0f3Smrg		}
876d514b0f3Smrg	}
877d514b0f3Smrg}
878d514b0f3Smrg
879d514b0f3Smrgstatic int
880d514b0f3Smrguxa_glyphs_via_mask(CARD8 op,
881d514b0f3Smrg		    PicturePtr pSrc,
882d514b0f3Smrg		    PicturePtr pDst,
883d514b0f3Smrg		    PictFormatPtr maskFormat,
884d514b0f3Smrg		    INT16 xSrc, INT16 ySrc,
885d514b0f3Smrg		    INT16 xDst, INT16 yDst,
886d514b0f3Smrg		    int nlist, GlyphListPtr list, GlyphPtr * glyphs,
887d514b0f3Smrg		    BoxPtr extents)
888d514b0f3Smrg{
889d514b0f3Smrg	ScreenPtr screen = pDst->pDrawable->pScreen;
890d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
891d514b0f3Smrg	CARD32 component_alpha;
892d514b0f3Smrg	PixmapPtr pixmap;
893d514b0f3Smrg	PicturePtr glyph_atlas, mask;
894d514b0f3Smrg	int x, y, width, height;
895d514b0f3Smrg	int dst_off_x, dst_off_y;
896d514b0f3Smrg	int n, error;
897d514b0f3Smrg	BoxRec box;
898d514b0f3Smrg
899d514b0f3Smrg	if (!extents) {
900d514b0f3Smrg		uxa_glyph_extents(nlist, list, glyphs, &box);
901d514b0f3Smrg
902d514b0f3Smrg		if (box.x2 <= box.x1 || box.y2 <= box.y1)
903d514b0f3Smrg			return 0;
904d514b0f3Smrg
905d514b0f3Smrg		extents = &box;
906d514b0f3Smrg		dst_off_x = box.x1;
907d514b0f3Smrg		dst_off_y = box.y1;
908d514b0f3Smrg	} else {
909d514b0f3Smrg		dst_off_x = dst_off_y = 0;
910d514b0f3Smrg	}
911d514b0f3Smrg
912d514b0f3Smrg	width  = extents->x2 - extents->x1;
913d514b0f3Smrg	height = extents->y2 - extents->y1;
914d514b0f3Smrg	x = -extents->x1;
915d514b0f3Smrg	y = -extents->y1;
916d514b0f3Smrg
917d514b0f3Smrg	if (maskFormat->depth == 1) {
918d514b0f3Smrg		PictFormatPtr a8Format =
919d514b0f3Smrg			PictureMatchFormat(screen, 8, PICT_a8);
920d514b0f3Smrg
921d514b0f3Smrg		if (!a8Format)
922d514b0f3Smrg			return -1;
923d514b0f3Smrg
924d514b0f3Smrg		maskFormat = a8Format;
925d514b0f3Smrg	}
926d514b0f3Smrg
927d514b0f3Smrg	pixmap = screen->CreatePixmap(screen, width, height,
928d514b0f3Smrg				      maskFormat->depth,
929d514b0f3Smrg				      CREATE_PIXMAP_USAGE_SCRATCH);
930d514b0f3Smrg	if (!pixmap)
931d514b0f3Smrg		return 1;
932d514b0f3Smrg
933d514b0f3Smrg	uxa_clear_pixmap(screen, uxa_screen, pixmap);
934d514b0f3Smrg
935d514b0f3Smrg	if (!uxa_pixmap_is_offscreen(pixmap)) {
936d514b0f3Smrg		screen->DestroyPixmap(pixmap);
937d514b0f3Smrg		return 1;
938d514b0f3Smrg	}
939d514b0f3Smrg
940d514b0f3Smrg	component_alpha = NeedsComponent(maskFormat->format);
941d514b0f3Smrg	mask = CreatePicture(0, &pixmap->drawable,
942d514b0f3Smrg			      maskFormat, CPComponentAlpha,
943d514b0f3Smrg			      &component_alpha, serverClient, &error);
944d514b0f3Smrg	screen->DestroyPixmap(pixmap);
945d514b0f3Smrg
946d514b0f3Smrg	if (!mask)
947d514b0f3Smrg		return 1;
948d514b0f3Smrg
949d514b0f3Smrg	ValidatePicture(mask);
950d514b0f3Smrg
951d514b0f3Smrg	glyph_atlas = NULL;
952d514b0f3Smrg	while (nlist--) {
953d514b0f3Smrg		x += list->xOff;
954d514b0f3Smrg		y += list->yOff;
955d514b0f3Smrg		n = list->len;
956d514b0f3Smrg		while (n--) {
957d514b0f3Smrg			GlyphPtr glyph = *glyphs++;
958d514b0f3Smrg			PicturePtr this_atlas;
959d514b0f3Smrg			int src_x, src_y;
960d514b0f3Smrg			struct uxa_glyph *priv;
961d514b0f3Smrg
962d514b0f3Smrg			if (glyph->info.width == 0 || glyph->info.height == 0)
963d514b0f3Smrg				goto next_glyph;
964d514b0f3Smrg
965d514b0f3Smrg			priv = uxa_glyph_get_private(glyph);
966d514b0f3Smrg			if (priv != NULL) {
967d514b0f3Smrg				src_x = priv->x;
968d514b0f3Smrg				src_y = priv->y;
969d514b0f3Smrg				this_atlas = priv->cache->picture;
970d514b0f3Smrg			} else {
971d514b0f3Smrg				if (glyph_atlas) {
972d514b0f3Smrg					uxa_screen->info->done_composite(pixmap);
973d514b0f3Smrg					glyph_atlas = NULL;
974d514b0f3Smrg				}
975d514b0f3Smrg				this_atlas = uxa_glyph_cache(screen, glyph, &src_x, &src_y);
976d514b0f3Smrg				if (this_atlas == NULL) {
977d514b0f3Smrg					/* no cache for this glyph */
978d514b0f3Smrg					this_atlas = GetGlyphPicture(glyph, screen);
979d514b0f3Smrg					src_x = src_y = 0;
980d514b0f3Smrg				}
981d514b0f3Smrg			}
982d514b0f3Smrg
983d514b0f3Smrg			if (this_atlas != glyph_atlas) {
984d514b0f3Smrg				PixmapPtr src_pixmap;
985d514b0f3Smrg
986d514b0f3Smrg				if (glyph_atlas)
987d514b0f3Smrg					uxa_screen->info->done_composite(pixmap);
988d514b0f3Smrg
989d514b0f3Smrg				src_pixmap =
990d514b0f3Smrg					uxa_get_drawable_pixmap(this_atlas->pDrawable);
991d514b0f3Smrg				assert (uxa_pixmap_is_offscreen(src_pixmap));
992d514b0f3Smrg
993d514b0f3Smrg				if (!uxa_screen->info->prepare_composite(PictOpAdd,
994d514b0f3Smrg									 this_atlas, NULL, mask,
995d514b0f3Smrg									 src_pixmap, NULL, pixmap)) {
996d514b0f3Smrg				        FreePicture(mask, 0);
997d514b0f3Smrg					return -1;
998d514b0f3Smrg				}
999d514b0f3Smrg
1000d514b0f3Smrg				glyph_atlas = this_atlas;
1001d514b0f3Smrg			}
1002d514b0f3Smrg
1003d514b0f3Smrg			uxa_screen->info->composite(pixmap,
1004d514b0f3Smrg						    src_x, src_y,
1005d514b0f3Smrg						    0, 0,
1006d514b0f3Smrg						    x - glyph->info.x,
1007d514b0f3Smrg						    y - glyph->info.y,
1008d514b0f3Smrg						    glyph->info.width,
1009d514b0f3Smrg						    glyph->info.height);
1010d514b0f3Smrg
1011d514b0f3Smrgnext_glyph:
1012d514b0f3Smrg			x += glyph->info.xOff;
1013d514b0f3Smrg			y += glyph->info.yOff;
1014d514b0f3Smrg		}
1015d514b0f3Smrg		list++;
1016d514b0f3Smrg	}
1017d514b0f3Smrg	if (glyph_atlas)
1018d514b0f3Smrg		uxa_screen->info->done_composite(pixmap);
1019d514b0f3Smrg
1020d514b0f3Smrg	uxa_composite(op,
1021d514b0f3Smrg		      pSrc, mask, pDst,
1022d514b0f3Smrg		      dst_off_x + xSrc - xDst,
1023d514b0f3Smrg		      dst_off_y + ySrc - yDst,
1024d514b0f3Smrg		      0, 0,
1025d514b0f3Smrg		      dst_off_x, dst_off_y,
1026d514b0f3Smrg		      width, height);
1027d514b0f3Smrg
1028d514b0f3Smrg	FreePicture(mask, 0);
1029d514b0f3Smrg	return 0;
1030d514b0f3Smrg}
1031d514b0f3Smrg
1032d514b0f3Smrgvoid
1033d514b0f3Smrguxa_glyphs(CARD8 op,
1034d514b0f3Smrg	   PicturePtr pSrc,
1035d514b0f3Smrg	   PicturePtr pDst,
1036d514b0f3Smrg	   PictFormatPtr maskFormat,
1037d514b0f3Smrg	   INT16 xSrc, INT16 ySrc,
1038d514b0f3Smrg	   int nlist, GlyphListPtr list, GlyphPtr * glyphs)
1039d514b0f3Smrg{
1040d514b0f3Smrg	ScreenPtr screen = pDst->pDrawable->pScreen;
1041d514b0f3Smrg	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
1042d514b0f3Smrg	int xDst = list->xOff, yDst = list->yOff;
1043d514b0f3Smrg	BoxRec extents = { 0, 0, 0, 0 };
1044d514b0f3Smrg	Bool have_extents = FALSE;
1045d514b0f3Smrg	int width = 0, height = 0, ret;
1046d514b0f3Smrg	PicturePtr localDst = pDst;
1047d514b0f3Smrg
1048d514b0f3Smrg	if (!uxa_screen->info->prepare_composite ||
1049d514b0f3Smrg	    uxa_screen->swappedOut ||
1050d514b0f3Smrg	    uxa_screen->force_fallback ||
1051d514b0f3Smrg	    !uxa_drawable_is_offscreen(pDst->pDrawable) ||
1052d514b0f3Smrg	    pDst->alphaMap || pSrc->alphaMap) {
1053d514b0f3Smrgfallback:
1054d514b0f3Smrg	    uxa_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
1055d514b0f3Smrg	    return;
1056d514b0f3Smrg	}
1057d514b0f3Smrg
1058d514b0f3Smrg	/* basic sanity check */
1059d514b0f3Smrg	if (uxa_screen->info->check_composite &&
1060d514b0f3Smrg	    !uxa_screen->info->check_composite(op, pSrc, NULL, pDst, 0, 0)) {
1061d514b0f3Smrg		goto fallback;
1062d514b0f3Smrg	}
1063d514b0f3Smrg
1064d514b0f3Smrg	ValidatePicture(pSrc);
1065d514b0f3Smrg	ValidatePicture(pDst);
1066d514b0f3Smrg
1067d514b0f3Smrg	if (!maskFormat) {
1068d514b0f3Smrg		/* If we don't have a mask format but all the glyphs have the same format,
1069d514b0f3Smrg		 * require ComponentAlpha and don't intersect, use the glyph format as mask
1070d514b0f3Smrg		 * format for the full benefits of the glyph cache.
1071d514b0f3Smrg		 */
1072d514b0f3Smrg		if (NeedsComponent(list[0].format->format)) {
1073d514b0f3Smrg			Bool sameFormat = TRUE;
1074d514b0f3Smrg			int i;
1075d514b0f3Smrg
1076d514b0f3Smrg			maskFormat = list[0].format;
1077d514b0f3Smrg
1078d514b0f3Smrg			for (i = 0; i < nlist; i++) {
1079d514b0f3Smrg				if (maskFormat->format != list[i].format->format) {
1080d514b0f3Smrg					sameFormat = FALSE;
1081d514b0f3Smrg					break;
1082d514b0f3Smrg				}
1083d514b0f3Smrg			}
1084d514b0f3Smrg
1085d514b0f3Smrg			if (!sameFormat ||
1086d514b0f3Smrg			    uxa_glyphs_intersect(nlist, list, glyphs))
1087d514b0f3Smrg				maskFormat = NULL;
1088d514b0f3Smrg		}
1089d514b0f3Smrg	}
1090d514b0f3Smrg
1091d514b0f3Smrg	if (!maskFormat &&
1092d514b0f3Smrg	    uxa_screen->info->check_composite_target &&
1093d514b0f3Smrg	    !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) {
1094d514b0f3Smrg		int depth = pDst->pDrawable->depth;
1095d514b0f3Smrg		PixmapPtr pixmap;
1096d514b0f3Smrg		int x, y, error;
1097d514b0f3Smrg		GCPtr gc;
1098d514b0f3Smrg
1099d514b0f3Smrg		pixmap = uxa_get_drawable_pixmap(pDst->pDrawable);
1100d514b0f3Smrg		if (uxa_screen->info->check_copy &&
1101d514b0f3Smrg		    !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES))
1102d514b0f3Smrg			goto fallback;
1103d514b0f3Smrg
1104d514b0f3Smrg		uxa_glyph_extents(nlist, list, glyphs, &extents);
1105d514b0f3Smrg
1106d514b0f3Smrg		/* clip against dst bounds */
1107d514b0f3Smrg		if (extents.x1 < 0)
1108d514b0f3Smrg			extents.x1 = 0;
1109d514b0f3Smrg		if (extents.y1 < 0)
1110d514b0f3Smrg			extents.y1 = 0;
1111d514b0f3Smrg		if (extents.x2 > pDst->pDrawable->width)
1112d514b0f3Smrg			extents.x2 = pDst->pDrawable->width;
1113d514b0f3Smrg		if (extents.y2 > pDst->pDrawable->height)
1114d514b0f3Smrg			extents.y2 = pDst->pDrawable->height;
1115d514b0f3Smrg
1116d514b0f3Smrg		if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
1117d514b0f3Smrg			return;
1118d514b0f3Smrg		width  = extents.x2 - extents.x1;
1119d514b0f3Smrg		height = extents.y2 - extents.y1;
1120d514b0f3Smrg		x = -extents.x1;
1121d514b0f3Smrg		y = -extents.y1;
1122d514b0f3Smrg		have_extents = TRUE;
1123d514b0f3Smrg
1124d514b0f3Smrg		xDst += x;
1125d514b0f3Smrg		yDst += y;
1126d514b0f3Smrg
1127d514b0f3Smrg		pixmap = screen->CreatePixmap(screen,
1128d514b0f3Smrg					      width, height, depth,
1129d514b0f3Smrg					      CREATE_PIXMAP_USAGE_SCRATCH);
1130d514b0f3Smrg		if (!pixmap)
1131d514b0f3Smrg			return;
1132d514b0f3Smrg
1133d514b0f3Smrg		gc = GetScratchGC(depth, screen);
1134d514b0f3Smrg		if (!gc) {
1135d514b0f3Smrg			screen->DestroyPixmap(pixmap);
1136d514b0f3Smrg			return;
1137d514b0f3Smrg		}
1138d514b0f3Smrg
1139d514b0f3Smrg		ValidateGC(&pixmap->drawable, gc);
1140d514b0f3Smrg		gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc,
1141d514b0f3Smrg				  extents.x1, extents.y1,
1142d514b0f3Smrg				  width, height,
1143d514b0f3Smrg				  0, 0);
1144d514b0f3Smrg		FreeScratchGC(gc);
1145d514b0f3Smrg
1146d514b0f3Smrg		localDst = CreatePicture(0, &pixmap->drawable,
1147d514b0f3Smrg					 PictureMatchFormat(screen, depth, pDst->format),
1148d514b0f3Smrg					 0, 0, serverClient, &error);
1149d514b0f3Smrg		screen->DestroyPixmap(pixmap);
1150d514b0f3Smrg
1151d514b0f3Smrg		if (!localDst)
1152d514b0f3Smrg			return;
1153d514b0f3Smrg
1154d514b0f3Smrg		ValidatePicture(localDst);
1155d514b0f3Smrg	}
1156d514b0f3Smrg
1157d514b0f3Smrg	if (maskFormat) {
1158d514b0f3Smrg		ret = uxa_glyphs_via_mask(op,
1159d514b0f3Smrg					  pSrc, localDst, maskFormat,
1160d514b0f3Smrg					  xSrc, ySrc,
1161d514b0f3Smrg					  xDst, yDst,
1162d514b0f3Smrg					  nlist, list, glyphs,
1163d514b0f3Smrg					  have_extents ? &extents : NULL);
1164d514b0f3Smrg	} else {
1165d514b0f3Smrg		ret = uxa_glyphs_to_dst(op,
1166d514b0f3Smrg					pSrc, localDst,
1167d514b0f3Smrg					xSrc, ySrc,
1168d514b0f3Smrg					xDst, yDst,
1169d514b0f3Smrg					nlist, list, glyphs,
1170d514b0f3Smrg					have_extents ? &extents : NULL);
1171d514b0f3Smrg	}
1172d514b0f3Smrg	if (ret) {
1173d514b0f3Smrg		if (localDst != pDst)
1174d514b0f3Smrg			FreePicture(localDst, 0);
1175d514b0f3Smrg
1176d514b0f3Smrg		goto fallback;
1177d514b0f3Smrg	}
1178d514b0f3Smrg
1179d514b0f3Smrg	if (localDst != pDst) {
1180d514b0f3Smrg		GCPtr gc;
1181d514b0f3Smrg
1182d514b0f3Smrg		gc = GetScratchGC(pDst->pDrawable->depth, screen);
1183d514b0f3Smrg		if (gc) {
1184d514b0f3Smrg			ValidateGC(pDst->pDrawable, gc);
1185d514b0f3Smrg			gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc,
1186d514b0f3Smrg					  0, 0,
1187d514b0f3Smrg					  width, height,
1188d514b0f3Smrg					  extents.x1, extents.y1);
1189d514b0f3Smrg			FreeScratchGC(gc);
1190d514b0f3Smrg		}
1191d514b0f3Smrg
1192d514b0f3Smrg		FreePicture(localDst, 0);
1193d514b0f3Smrg	}
1194d514b0f3Smrg}
1195