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#include "common.h"
69
70/* Width of the pixmaps we use for the caches; this should be less than
71 * max texture size of the driver; this may need to actually come from
72 * the driver.
73 */
74#define CACHE_PICTURE_SIZE 1024
75#define GLYPH_MIN_SIZE 8
76#define GLYPH_MAX_SIZE 64
77#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE))
78
79struct uxa_glyph {
80	uxa_glyph_cache_t *cache;
81	uint16_t x, y;
82	uint16_t size, pos;
83};
84
85#if HAS_DEVPRIVATEKEYREC
86static DevPrivateKeyRec uxa_glyph_key;
87#else
88static int uxa_glyph_key;
89#endif
90
91static inline struct uxa_glyph *uxa_glyph_get_private(GlyphPtr glyph)
92{
93#if HAS_DEVPRIVATEKEYREC
94	return dixGetPrivate(&glyph->devPrivates, &uxa_glyph_key);
95#else
96	return dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_key);
97#endif
98}
99
100static inline void uxa_glyph_set_private(GlyphPtr glyph, struct uxa_glyph *priv)
101{
102	dixSetPrivate(&glyph->devPrivates, &uxa_glyph_key, priv);
103}
104
105#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0)
106
107static void uxa_unrealize_glyph_caches(ScreenPtr pScreen)
108{
109	uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
110	int i;
111
112	if (!uxa_screen->glyph_cache_initialized)
113		return;
114
115	for (i = 0; i < UXA_NUM_GLYPH_CACHE_FORMATS; i++) {
116		uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
117
118		if (cache->picture)
119			FreePicture(cache->picture, 0);
120
121		if (cache->glyphs)
122			free(cache->glyphs);
123	}
124	uxa_screen->glyph_cache_initialized = FALSE;
125}
126
127void uxa_glyphs_fini(ScreenPtr pScreen)
128{
129	uxa_unrealize_glyph_caches(pScreen);
130}
131
132/* All caches for a single format share a single pixmap for glyph storage,
133 * allowing mixing glyphs of different sizes without paying a penalty
134 * for switching between source pixmaps. (Note that for a size of font
135 * right at the border between two sizes, we might be switching for almost
136 * every glyph.)
137 *
138 * This function allocates the storage pixmap, and then fills in the
139 * rest of the allocated structures for all caches with the given format.
140 */
141static Bool uxa_realize_glyph_caches(ScreenPtr pScreen)
142{
143	uxa_screen_t *uxa_screen = uxa_get_screen(pScreen);
144	unsigned int formats[] = {
145		PIXMAN_a8,
146		PIXMAN_a8r8g8b8,
147	};
148	unsigned i;
149
150	if (uxa_screen->glyph_cache_initialized)
151		return TRUE;
152
153	uxa_screen->glyph_cache_initialized = TRUE;
154	memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches));
155
156	for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
157		uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i];
158		PixmapPtr pixmap;
159		PicturePtr picture;
160		CARD32 component_alpha;
161		int depth = PIXMAN_FORMAT_DEPTH(formats[i]);
162		int error;
163		PictFormatPtr pPictFormat = PictureMatchFormat(pScreen, depth, formats[i]);
164		if (!pPictFormat)
165			goto bail;
166
167		/* Now allocate the pixmap and picture */
168		pixmap = pScreen->CreatePixmap(pScreen,
169					       CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE, depth,
170					       INTEL_CREATE_PIXMAP_TILING_X);
171		if (!pixmap)
172			goto bail;
173		if (!uxa_pixmap_is_offscreen(pixmap)) {
174			/* Presume shadow is in-effect */
175			pScreen->DestroyPixmap(pixmap);
176			uxa_unrealize_glyph_caches(pScreen);
177			return TRUE;
178		}
179
180		component_alpha = NeedsComponent(pPictFormat->format);
181		picture = CreatePicture(0, &pixmap->drawable, pPictFormat,
182					CPComponentAlpha, &component_alpha,
183					serverClient, &error);
184
185		pScreen->DestroyPixmap(pixmap);
186
187		if (!picture)
188			goto bail;
189
190		ValidatePicture(picture);
191
192		cache->picture = picture;
193		cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE);
194		if (!cache->glyphs)
195			goto bail;
196
197		cache->evict = rand() % GLYPH_CACHE_SIZE;
198	}
199	assert(i == UXA_NUM_GLYPH_CACHE_FORMATS);
200
201	return TRUE;
202
203bail:
204	uxa_unrealize_glyph_caches(pScreen);
205	return FALSE;
206}
207
208
209Bool uxa_glyphs_init(ScreenPtr pScreen)
210{
211
212#if HAS_DIXREGISTERPRIVATEKEY
213	if (!dixRegisterPrivateKey(&uxa_glyph_key, PRIVATE_GLYPH, 0))
214		return FALSE;
215#else
216	if (!dixRequestPrivate(&uxa_glyph_key, 0))
217		return FALSE;
218#endif
219
220	/* Skip pixmap creation if we don't intend to use it. */
221	if (uxa_get_screen(pScreen)->force_fallback)
222		return TRUE;
223
224	return uxa_realize_glyph_caches(pScreen);
225}
226
227/* The most efficient thing to way to upload the glyph to the screen
228 * is to use CopyArea; uxa pixmaps are always offscreen.
229 */
230static void
231uxa_glyph_cache_upload_glyph(ScreenPtr screen,
232			     uxa_glyph_cache_t * cache,
233			     GlyphPtr glyph,
234			     int x, int y)
235{
236	PicturePtr pGlyphPicture = GetGlyphPicture(glyph, screen);
237	PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable;
238	PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable;
239	PixmapPtr scratch;
240	GCPtr gc;
241
242	gc = GetScratchGC(pCachePixmap->drawable.depth, screen);
243	if (!gc)
244		return;
245
246	ValidateGC(&pCachePixmap->drawable, gc);
247
248	scratch = pGlyphPixmap;
249	/* Create a temporary bo to stream the updates to the cache */
250	if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth ||
251	    !uxa_pixmap_is_offscreen(scratch)) {
252		scratch = screen->CreatePixmap(screen,
253					       glyph->info.width,
254					       glyph->info.height,
255					       pCachePixmap->drawable.depth,
256					       UXA_CREATE_PIXMAP_FOR_MAP);
257		if (scratch) {
258			if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) {
259				PicturePtr picture;
260				int error;
261
262				picture = CreatePicture(0, &scratch->drawable,
263							PictureMatchFormat(screen,
264									   pCachePixmap->drawable.depth,
265									   cache->picture->format),
266							0, NULL,
267							serverClient, &error);
268				if (picture) {
269					ValidatePicture(picture);
270					uxa_composite(PictOpSrc, pGlyphPicture, NULL, picture,
271						      0, 0,
272						      0, 0,
273						      0, 0,
274						      glyph->info.width, glyph->info.height);
275					FreePicture(picture, 0);
276				}
277			} else {
278				uxa_copy_area(&pGlyphPixmap->drawable,
279					      &scratch->drawable,
280					      gc,
281					      0, 0,
282					      glyph->info.width, glyph->info.height,
283					      0, 0);
284			}
285		} else {
286			scratch = pGlyphPixmap;
287		}
288	}
289
290	uxa_copy_area(&scratch->drawable, &pCachePixmap->drawable, gc,
291		      0, 0,
292		      glyph->info.width, glyph->info.height,
293		      x, y);
294
295	if (scratch != pGlyphPixmap)
296		screen->DestroyPixmap(scratch);
297
298	FreeScratchGC(gc);
299}
300
301void
302uxa_glyph_unrealize(ScreenPtr screen,
303		    GlyphPtr glyph)
304{
305	struct uxa_glyph *priv;
306
307	/* Use Lookup in case we have not attached to this glyph. */
308	priv = dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_key);
309	if (priv == NULL)
310		return;
311
312	priv->cache->glyphs[priv->pos] = NULL;
313
314	uxa_glyph_set_private(glyph, NULL);
315	free(priv);
316}
317
318/* Cut and paste from render/glyph.c - probably should export it instead */
319static void
320uxa_glyph_extents(int nlist,
321		  GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents)
322{
323	int x1, x2, y1, y2;
324	int x, y, n;
325
326	x1 = y1 = MAXSHORT;
327	x2 = y2 = MINSHORT;
328	x = y = 0;
329	while (nlist--) {
330		x += list->xOff;
331		y += list->yOff;
332		n = list->len;
333		list++;
334		while (n--) {
335			GlyphPtr glyph = *glyphs++;
336			int v;
337
338			v = x - glyph->info.x;
339			if (v < x1)
340			    x1 = v;
341			v += glyph->info.width;
342			if (v > x2)
343			    x2 = v;
344
345			v = y - glyph->info.y;
346			if (v < y1)
347			    y1 = v;
348			v += glyph->info.height;
349			if (v > y2)
350			    y2 = v;
351
352			x += glyph->info.xOff;
353			y += glyph->info.yOff;
354		}
355	}
356
357	extents->x1 = x1 < MINSHORT ? MINSHORT : x1;
358	extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2;
359	extents->y1 = y1 < MINSHORT ? MINSHORT : y1;
360	extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2;
361}
362
363/**
364 * Returns TRUE if the glyphs in the lists intersect.  Only checks based on
365 * bounding box, which appears to be good enough to catch most cases at least.
366 */
367static Bool
368uxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs)
369{
370	int x1, x2, y1, y2;
371	int n;
372	int x, y;
373	BoxRec extents;
374	Bool first = TRUE;
375
376	x = 0;
377	y = 0;
378	extents.x1 = 0;
379	extents.y1 = 0;
380	extents.x2 = 0;
381	extents.y2 = 0;
382	while (nlist--) {
383		x += list->xOff;
384		y += list->yOff;
385		n = list->len;
386		list++;
387		while (n--) {
388			GlyphPtr glyph = *glyphs++;
389
390			if (glyph->info.width == 0 || glyph->info.height == 0) {
391				x += glyph->info.xOff;
392				y += glyph->info.yOff;
393				continue;
394			}
395
396			x1 = x - glyph->info.x;
397			if (x1 < MINSHORT)
398				x1 = MINSHORT;
399			y1 = y - glyph->info.y;
400			if (y1 < MINSHORT)
401				y1 = MINSHORT;
402			x2 = x1 + glyph->info.width;
403			if (x2 > MAXSHORT)
404				x2 = MAXSHORT;
405			y2 = y1 + glyph->info.height;
406			if (y2 > MAXSHORT)
407				y2 = MAXSHORT;
408
409			if (first) {
410				extents.x1 = x1;
411				extents.y1 = y1;
412				extents.x2 = x2;
413				extents.y2 = y2;
414				first = FALSE;
415			} else {
416				if (x1 < extents.x2 && x2 > extents.x1 &&
417				    y1 < extents.y2 && y2 > extents.y1) {
418					return TRUE;
419				}
420
421				if (x1 < extents.x1)
422					extents.x1 = x1;
423				if (x2 > extents.x2)
424					extents.x2 = x2;
425				if (y1 < extents.y1)
426					extents.y1 = y1;
427				if (y2 > extents.y2)
428					extents.y2 = y2;
429			}
430			x += glyph->info.xOff;
431			y += glyph->info.yOff;
432		}
433	}
434
435	return FALSE;
436}
437
438static void
439uxa_check_glyphs(CARD8 op,
440		 PicturePtr src,
441		 PicturePtr dst,
442		 PictFormatPtr maskFormat,
443		 INT16 xSrc,
444		 INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs)
445{
446	pixman_image_t *image;
447	PixmapPtr scratch;
448	PicturePtr mask, mask_src = NULL, mask_dst = NULL, white = NULL;
449	int width = 0, height = 0;
450	int x, y, n;
451	int xDst = list->xOff, yDst = list->yOff;
452	BoxRec extents = { 0, 0, 0, 0 };
453	CARD8 mask_op = 0;
454
455	if (maskFormat) {
456		pixman_format_code_t format;
457		CARD32 component_alpha;
458		xRenderColor color;
459		int error;
460
461		uxa_glyph_extents(nlist, list, glyphs, &extents);
462		if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
463			return;
464
465		width = extents.x2 - extents.x1;
466		height = extents.y2 - extents.y1;
467
468		format = maskFormat->format |
469			(BitsPerPixel(maskFormat->depth) << 24);
470		image =
471			pixman_image_create_bits(format, width, height, NULL, 0);
472		if (!image)
473			return;
474
475		scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height,
476						 PIXMAN_FORMAT_DEPTH(format),
477						 PIXMAN_FORMAT_BPP(format),
478						 pixman_image_get_stride(image),
479						 pixman_image_get_data(image));
480
481		if (!scratch) {
482			pixman_image_unref(image);
483			return;
484		}
485
486		component_alpha = NeedsComponent(maskFormat->format);
487		mask = CreatePicture(0, &scratch->drawable,
488				     maskFormat, CPComponentAlpha,
489				     &component_alpha, serverClient, &error);
490		if (!mask) {
491			FreeScratchPixmapHeader(scratch);
492			pixman_image_unref(image);
493			return;
494		}
495		ValidatePicture(mask);
496
497		x = -extents.x1;
498		y = -extents.y1;
499
500		color.red = color.green = color.blue = color.alpha = 0xffff;
501		white = CreateSolidPicture(0, &color, &error);
502
503		mask_op = op;
504		op = PictOpAdd;
505
506		mask_src = src;
507		src = white;
508
509		mask_dst = dst;
510		dst = mask;
511	} else {
512		mask = dst;
513		x = 0;
514		y = 0;
515	}
516
517	while (nlist--) {
518		x += list->xOff;
519		y += list->yOff;
520		n = list->len;
521		while (n--) {
522			GlyphPtr glyph = *glyphs++;
523			PicturePtr g = GetGlyphPicture(glyph, dst->pDrawable->pScreen);
524			if (g) {
525				CompositePicture(op, src, g, dst,
526						 xSrc + (x - glyph->info.x) - xDst,
527						 ySrc + (y - glyph->info.y) - yDst,
528						 0, 0,
529						 x - glyph->info.x,
530						 y - glyph->info.y,
531						 glyph->info.width,
532						 glyph->info.height);
533			}
534
535			x += glyph->info.xOff;
536			y += glyph->info.yOff;
537		}
538		list++;
539	}
540
541	if (white)
542		FreePicture(white, 0);
543
544	if (maskFormat) {
545		x = extents.x1;
546		y = extents.y1;
547		CompositePicture(mask_op, mask_src, mask, mask_dst,
548				 xSrc + x - xDst,
549				 ySrc + y - yDst,
550				 0, 0,
551				 x, y,
552				 width, height);
553		FreePicture(mask, 0);
554		FreeScratchPixmapHeader(scratch);
555		pixman_image_unref(image);
556	}
557}
558
559static inline unsigned int
560uxa_glyph_size_to_count(int size)
561{
562	size /= GLYPH_MIN_SIZE;
563	return size * size;
564}
565
566static inline unsigned int
567uxa_glyph_count_to_mask(int count)
568{
569	return ~(count - 1);
570}
571
572static inline unsigned int
573uxa_glyph_size_to_mask(int size)
574{
575	return uxa_glyph_count_to_mask(uxa_glyph_size_to_count(size));
576}
577
578static PicturePtr
579uxa_glyph_cache(ScreenPtr screen, GlyphPtr glyph, int *out_x, int *out_y)
580{
581	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
582	PicturePtr glyph_picture = GetGlyphPicture(glyph, screen);
583	uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0];
584	struct uxa_glyph *priv = NULL;
585	int size, mask, pos, s;
586
587	if (glyph->info.width > GLYPH_MAX_SIZE || glyph->info.height > GLYPH_MAX_SIZE)
588		return NULL;
589
590	for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2)
591		if (glyph->info.width <= size && glyph->info.height <= size)
592			break;
593
594	s = uxa_glyph_size_to_count(size);
595	mask = uxa_glyph_count_to_mask(s);
596	pos = (cache->count + s - 1) & mask;
597	if (pos < GLYPH_CACHE_SIZE) {
598		cache->count = pos + s;
599	} else {
600		for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) {
601			int i = cache->evict & uxa_glyph_size_to_mask(s);
602			GlyphPtr evicted = cache->glyphs[i];
603			if (evicted == NULL)
604				continue;
605
606			priv = uxa_glyph_get_private(evicted);
607			if (priv->size >= s) {
608				cache->glyphs[i] = NULL;
609				uxa_glyph_set_private(evicted, NULL);
610				pos = cache->evict & uxa_glyph_size_to_mask(size);
611			} else
612				priv = NULL;
613			break;
614		}
615		if (priv == NULL) {
616			int count = uxa_glyph_size_to_count(size);
617			mask = uxa_glyph_count_to_mask(count);
618			pos = cache->evict & mask;
619			for (s = 0; s < count; s++) {
620				GlyphPtr evicted = cache->glyphs[pos + s];
621				if (evicted != NULL) {
622					if (priv != NULL)
623						free(priv);
624
625					priv = uxa_glyph_get_private(evicted);
626					uxa_glyph_set_private(evicted, NULL);
627					cache->glyphs[pos + s] = NULL;
628				}
629			}
630		}
631
632		/* And pick a new eviction position */
633		cache->evict = rand() % GLYPH_CACHE_SIZE;
634	}
635
636	if (priv == NULL) {
637		priv = malloc(sizeof(struct uxa_glyph));
638		if (priv == NULL)
639			return NULL;
640	}
641
642	uxa_glyph_set_private(glyph, priv);
643	cache->glyphs[pos] = glyph;
644
645	priv->cache = cache;
646	priv->size = size;
647	priv->pos = pos;
648	s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE));
649	priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE;
650	priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE;
651	for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) {
652		if (pos & 1)
653			priv->x += s;
654		if (pos & 2)
655			priv->y += s;
656		pos >>= 2;
657	}
658
659	uxa_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y);
660
661	*out_x = priv->x;
662	*out_y = priv->y;
663	return cache->picture;
664}
665
666static void
667uxa_clear_pixmap(ScreenPtr screen,
668		 uxa_screen_t *uxa_screen,
669		 PixmapPtr pixmap)
670{
671	if (uxa_screen->info->check_solid &&
672	    !uxa_screen->info->check_solid(&pixmap->drawable, GXcopy, FB_ALLONES))
673		goto fallback;
674
675	if (!uxa_screen->info->prepare_solid(pixmap, GXcopy, FB_ALLONES, 0))
676		goto fallback;
677
678	uxa_screen->info->solid(pixmap,
679				0, 0,
680				pixmap->drawable.width,
681				pixmap->drawable.height);
682
683	uxa_screen->info->done_solid(pixmap);
684	return;
685
686fallback:
687	{
688		GCPtr gc;
689
690		gc = GetScratchGC(pixmap->drawable.depth, screen);
691		if (gc) {
692			xRectangle rect;
693
694			ValidateGC(&pixmap->drawable, gc);
695
696			rect.x = 0;
697			rect.y = 0;
698			rect.width  = pixmap->drawable.width;
699			rect.height = pixmap->drawable.height;
700			gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect);
701
702			FreeScratchGC(gc);
703		}
704	}
705}
706
707static PicturePtr
708create_white_solid(ScreenPtr screen)
709{
710	PicturePtr white, ret = NULL;
711	xRenderColor color;
712	int error;
713
714	color.red = color.green = color.blue = color.alpha = 0xffff;
715	white = CreateSolidPicture(0, &color, &error);
716	if (white) {
717		ret = uxa_acquire_solid(screen, white->pSourcePict);
718		FreePicture(white, 0);
719	}
720
721	return ret;
722}
723
724static int
725uxa_glyphs_via_mask(CARD8 op,
726		    PicturePtr pSrc,
727		    PicturePtr pDst,
728		    PictFormatPtr maskFormat,
729		    INT16 xSrc, INT16 ySrc,
730		    int nlist, GlyphListPtr list, GlyphPtr * glyphs)
731{
732	ScreenPtr screen = pDst->pDrawable->pScreen;
733	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
734	CARD32 component_alpha;
735	PixmapPtr pixmap, white_pixmap;
736	PicturePtr glyph_atlas, mask, white;
737	int xDst = list->xOff, yDst = list->yOff;
738	int x, y, width, height;
739	int dst_off_x, dst_off_y;
740	int n, error;
741	BoxRec box;
742
743	uxa_glyph_extents(nlist, list, glyphs, &box);
744	if (box.x2 <= box.x1 || box.y2 <= box.y1)
745		return 0;
746
747	dst_off_x = box.x1;
748	dst_off_y = box.y1;
749
750	width  = box.x2 - box.x1;
751	height = box.y2 - box.y1;
752	x = -box.x1;
753	y = -box.y1;
754
755	if (maskFormat->depth == 1) {
756		PictFormatPtr a8Format =
757			PictureMatchFormat(screen, 8, PICT_a8);
758
759		if (!a8Format)
760			return -1;
761
762		maskFormat = a8Format;
763	}
764
765	pixmap = screen->CreatePixmap(screen, width, height,
766				      maskFormat->depth,
767				      CREATE_PIXMAP_USAGE_SCRATCH);
768	if (!pixmap)
769		return 1;
770
771	if (!uxa_pixmap_is_offscreen(pixmap)) {
772		screen->DestroyPixmap(pixmap);
773		return -1;
774	}
775
776	white_pixmap = NULL;
777	white = create_white_solid(screen);
778	if (white)
779		white_pixmap = uxa_get_drawable_pixmap(white->pDrawable);
780	if (!white_pixmap) {
781		if (white)
782			FreePicture(white, 0);
783		screen->DestroyPixmap(pixmap);
784		return -1;
785	}
786
787	uxa_clear_pixmap(screen, uxa_screen, pixmap);
788
789	component_alpha = NeedsComponent(maskFormat->format);
790	mask = CreatePicture(0, &pixmap->drawable,
791			      maskFormat, CPComponentAlpha,
792			      &component_alpha, serverClient, &error);
793	screen->DestroyPixmap(pixmap);
794
795	if (!mask) {
796		FreePicture(white, 0);
797		return 1;
798	}
799
800	ValidatePicture(mask);
801
802	glyph_atlas = NULL;
803	while (nlist--) {
804		x += list->xOff;
805		y += list->yOff;
806		n = list->len;
807		while (n--) {
808			GlyphPtr glyph = *glyphs++;
809			PicturePtr this_atlas;
810			int glyph_x, glyph_y;
811			struct uxa_glyph *priv;
812
813			if (glyph->info.width == 0 || glyph->info.height == 0)
814				goto next_glyph;
815
816			priv = uxa_glyph_get_private(glyph);
817			if (priv != NULL) {
818				glyph_x = priv->x;
819				glyph_y = priv->y;
820				this_atlas = priv->cache->picture;
821			} else {
822				if (glyph_atlas) {
823					uxa_screen->info->done_composite(pixmap);
824					glyph_atlas = NULL;
825				}
826				this_atlas = uxa_glyph_cache(screen, glyph, &glyph_x, &glyph_y);
827				if (this_atlas == NULL) {
828					/* no cache for this glyph */
829					this_atlas = GetGlyphPicture(glyph, screen);
830					glyph_x = glyph_y = 0;
831				}
832			}
833
834			if (this_atlas != glyph_atlas) {
835				PixmapPtr glyph_pixmap;
836
837				if (glyph_atlas)
838					uxa_screen->info->done_composite(pixmap);
839
840				glyph_pixmap =
841					uxa_get_drawable_pixmap(this_atlas->pDrawable);
842				if (!uxa_pixmap_is_offscreen(glyph_pixmap) ||
843				    !uxa_screen->info->prepare_composite(PictOpAdd,
844									 white, this_atlas, mask,
845									 white_pixmap, glyph_pixmap, pixmap)) {
846					FreePicture(white, 0);
847					FreePicture(mask, 0);
848					return -1;
849				}
850
851				glyph_atlas = this_atlas;
852			}
853
854			uxa_screen->info->composite(pixmap,
855						    0, 0,
856						    glyph_x, glyph_y,
857						    x - glyph->info.x,
858						    y - glyph->info.y,
859						    glyph->info.width,
860						    glyph->info.height);
861
862next_glyph:
863			x += glyph->info.xOff;
864			y += glyph->info.yOff;
865		}
866		list++;
867	}
868	if (glyph_atlas)
869		uxa_screen->info->done_composite(pixmap);
870
871	uxa_composite(op,
872		      pSrc, mask, pDst,
873		      dst_off_x + xSrc - xDst,
874		      dst_off_y + ySrc - yDst,
875		      0, 0,
876		      dst_off_x, dst_off_y,
877		      width, height);
878
879	FreePicture(white, 0);
880	FreePicture(mask, 0);
881	return 0;
882}
883
884static int
885uxa_glyphs_to_dst(CARD8 op,
886		  PicturePtr pSrc,
887		  PicturePtr pDst,
888		  INT16 xSrc, INT16 ySrc,
889		  int nlist, GlyphListPtr list, GlyphPtr * glyphs)
890{
891	ScreenPtr screen = pDst->pDrawable->pScreen;
892	int x, y, n;
893
894	xSrc -= list->xOff;
895	ySrc -= list->yOff;
896	x = y = 0;
897	while (nlist--) {
898		x += list->xOff;
899		y += list->yOff;
900		n = list->len;
901		while (n--) {
902			GlyphPtr glyph = *glyphs++;
903			PicturePtr glyph_atlas;
904			int glyph_x, glyph_y;
905			struct uxa_glyph *priv;
906
907			if (glyph->info.width == 0 || glyph->info.height == 0)
908				goto next_glyph;
909
910			priv = uxa_glyph_get_private(glyph);
911			if (priv != NULL) {
912				glyph_x = priv->x;
913				glyph_y = priv->y;
914				glyph_atlas = priv->cache->picture;
915			} else {
916				glyph_atlas = uxa_glyph_cache(screen, glyph, &glyph_x, &glyph_y);
917				if (glyph_atlas == NULL) {
918					/* no cache for this glyph */
919					glyph_atlas = GetGlyphPicture(glyph, screen);
920					glyph_x = glyph_y = 0;
921				}
922			}
923
924			uxa_composite(op,
925				      pSrc, glyph_atlas, pDst,
926				      xSrc + x - glyph->info.x,
927				      ySrc + y - glyph->info.y,
928				      glyph_x, glyph_y,
929				      x - glyph->info.x,
930				      y - glyph->info.y,
931				      glyph->info.width, glyph->info.height);
932
933next_glyph:
934			x += glyph->info.xOff;
935			y += glyph->info.yOff;
936		}
937		list++;
938	}
939
940	return 0;
941}
942
943static Bool
944is_solid(PicturePtr picture)
945{
946	if (picture->pSourcePict) {
947		SourcePict *source = picture->pSourcePict;
948		return source->type == SourcePictTypeSolidFill;
949	} else {
950		return (picture->repeat &&
951			picture->pDrawable->width  == 1 &&
952			picture->pDrawable->height == 1);
953	}
954}
955
956void
957uxa_glyphs(CARD8 op,
958	   PicturePtr pSrc,
959	   PicturePtr pDst,
960	   PictFormatPtr maskFormat,
961	   INT16 xSrc, INT16 ySrc,
962	   int nlist, GlyphListPtr list, GlyphPtr * glyphs)
963{
964	ScreenPtr screen = pDst->pDrawable->pScreen;
965	uxa_screen_t *uxa_screen = uxa_get_screen(screen);
966
967	if (!uxa_screen->info->prepare_composite ||
968	    uxa_screen->force_fallback ||
969	    !uxa_drawable_is_offscreen(pDst->pDrawable) ||
970	    pDst->alphaMap || pSrc->alphaMap ||
971	    /* XXX we fail to handle (rare) non-solid sources correctly. */
972	    !is_solid(pSrc)) {
973fallback:
974	    uxa_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs);
975	    return;
976	}
977
978	/* basic sanity check */
979	if (uxa_screen->info->check_composite &&
980	    !uxa_screen->info->check_composite(op, pSrc, NULL, pDst, 0, 0)) {
981		goto fallback;
982	}
983
984	ValidatePicture(pSrc);
985	ValidatePicture(pDst);
986
987	if (!maskFormat) {
988		/* If we don't have a mask format but all the glyphs have the same format,
989		 * require ComponentAlpha and don't intersect, use the glyph format as mask
990		 * format for the full benefits of the glyph cache.
991		 */
992		if (NeedsComponent(list[0].format->format)) {
993			Bool sameFormat = TRUE;
994			int i;
995
996			maskFormat = list[0].format;
997
998			for (i = 0; i < nlist; i++) {
999				if (maskFormat->format != list[i].format->format) {
1000					sameFormat = FALSE;
1001					break;
1002				}
1003			}
1004
1005			if (!sameFormat ||
1006			    uxa_glyphs_intersect(nlist, list, glyphs))
1007				maskFormat = NULL;
1008		}
1009	}
1010
1011	if (!maskFormat) {
1012		if (uxa_glyphs_to_dst(op, pSrc, pDst,
1013				      xSrc, ySrc,
1014				      nlist, list, glyphs))
1015			goto fallback;
1016	} else {
1017		if (uxa_glyphs_via_mask(op,
1018					pSrc, pDst, maskFormat,
1019					xSrc, ySrc,
1020					nlist, list, glyphs))
1021			goto fallback;
1022	}
1023}
1024