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