1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 2000 SuSE, Inc.
3428d7b3dSmrg * Copyright © 2007 Red Hat, Inc.
4428d7b3dSmrg * Copyright © 2012 Intel Corporation
5428d7b3dSmrg *
6428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
7428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that
8428d7b3dSmrg * the above copyright notice appear in all copies and that both that
9428d7b3dSmrg * copyright notice and this permission notice appear in supporting
10428d7b3dSmrg * documentation, and that the name of SuSE not be used in advertising or
11428d7b3dSmrg * publicity pertaining to distribution of the software without specific,
12428d7b3dSmrg * written prior permission.  SuSE makes no representations about the
13428d7b3dSmrg * suitability of this software for any purpose.  It is provided "as is"
14428d7b3dSmrg * without express or implied warranty.
15428d7b3dSmrg *
16428d7b3dSmrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17428d7b3dSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
18428d7b3dSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19428d7b3dSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20428d7b3dSmrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21428d7b3dSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22428d7b3dSmrg *
23428d7b3dSmrg * Author:  Keith Packard, SuSE, Inc.
24428d7b3dSmrg */
25428d7b3dSmrg
26428d7b3dSmrg#include <string.h>
27428d7b3dSmrg
28428d7b3dSmrg#include "fb.h"
29428d7b3dSmrg#include "fbpict.h"
30428d7b3dSmrg
31428d7b3dSmrgstatic void
32428d7b3dSmrgSourceValidateOnePicture(PicturePtr picture)
33428d7b3dSmrg{
34428d7b3dSmrg	DrawablePtr drawable = picture->pDrawable;
35428d7b3dSmrg
36428d7b3dSmrg	if (!drawable)
37428d7b3dSmrg		return;
38428d7b3dSmrg
39428d7b3dSmrg	SourceValidate(drawable,
40428d7b3dSmrg		       0, 0, drawable->width, drawable->height,
41428d7b3dSmrg		       picture->subWindowMode);
42428d7b3dSmrg}
43428d7b3dSmrg
44428d7b3dSmrgstatic void
45428d7b3dSmrgfbCompositeSourceValidate(PicturePtr picture)
46428d7b3dSmrg{
47428d7b3dSmrg	SourceValidateOnePicture(picture);
48428d7b3dSmrg	if (picture->alphaMap)
49428d7b3dSmrg		SourceValidateOnePicture(picture->alphaMap);
50428d7b3dSmrg}
51428d7b3dSmrg
52428d7b3dSmrgvoid
53428d7b3dSmrgfbComposite(CARD8 op,
54428d7b3dSmrg            PicturePtr pSrc,
55428d7b3dSmrg            PicturePtr pMask,
56428d7b3dSmrg            PicturePtr pDst,
57428d7b3dSmrg            INT16 xSrc,
58428d7b3dSmrg            INT16 ySrc,
59428d7b3dSmrg            INT16 xMask,
60428d7b3dSmrg            INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
61428d7b3dSmrg{
62428d7b3dSmrg	pixman_image_t *src, *mask, *dest;
63428d7b3dSmrg	int src_xoff, src_yoff;
64428d7b3dSmrg	int msk_xoff, msk_yoff;
65428d7b3dSmrg	int dst_xoff, dst_yoff;
66428d7b3dSmrg
67428d7b3dSmrg	fbCompositeSourceValidate(pSrc);
68428d7b3dSmrg	if (pMask)
69428d7b3dSmrg		fbCompositeSourceValidate(pMask);
70428d7b3dSmrg
71428d7b3dSmrg	src = image_from_pict(pSrc, FALSE, &src_xoff, &src_yoff);
72428d7b3dSmrg	mask = image_from_pict(pMask, FALSE, &msk_xoff, &msk_yoff);
73428d7b3dSmrg	dest = image_from_pict(pDst, TRUE, &dst_xoff, &dst_yoff);
74428d7b3dSmrg
75428d7b3dSmrg	if (src && dest && !(pMask && !mask)) {
76428d7b3dSmrg		pixman_image_composite(op, src, mask, dest,
77428d7b3dSmrg				       xSrc + src_xoff, ySrc + src_yoff,
78428d7b3dSmrg				       xMask + msk_xoff, yMask + msk_yoff,
79428d7b3dSmrg				       xDst + dst_xoff, yDst + dst_yoff, width, height);
80428d7b3dSmrg	}
81428d7b3dSmrg
82428d7b3dSmrg	free_pixman_pict(pSrc, src);
83428d7b3dSmrg	free_pixman_pict(pMask, mask);
84428d7b3dSmrg	free_pixman_pict(pDst, dest);
85428d7b3dSmrg}
86428d7b3dSmrg
87428d7b3dSmrgstatic pixman_image_t *
88428d7b3dSmrgcreate_solid_fill_image(PicturePtr pict)
89428d7b3dSmrg{
90428d7b3dSmrg	PictSolidFill *solid = &pict->pSourcePict->solidFill;
91428d7b3dSmrg	pixman_color_t color;
92428d7b3dSmrg	CARD32 a, r, g, b;
93428d7b3dSmrg
94428d7b3dSmrg	a = (solid->color & 0xff000000) >> 24;
95428d7b3dSmrg	r = (solid->color & 0x00ff0000) >> 16;
96428d7b3dSmrg	g = (solid->color & 0x0000ff00) >> 8;
97428d7b3dSmrg	b = (solid->color & 0x000000ff) >> 0;
98428d7b3dSmrg
99428d7b3dSmrg	color.alpha = (a << 8) | a;
100428d7b3dSmrg	color.red = (r << 8) | r;
101428d7b3dSmrg	color.green = (g << 8) | g;
102428d7b3dSmrg	color.blue = (b << 8) | b;
103428d7b3dSmrg
104428d7b3dSmrg	return pixman_image_create_solid_fill(&color);
105428d7b3dSmrg}
106428d7b3dSmrg
107428d7b3dSmrgstatic pixman_image_t *
108428d7b3dSmrgcreate_linear_gradient_image(PictGradient * gradient)
109428d7b3dSmrg{
110428d7b3dSmrg	PictLinearGradient *linear = (PictLinearGradient *) gradient;
111428d7b3dSmrg	pixman_point_fixed_t p1;
112428d7b3dSmrg	pixman_point_fixed_t p2;
113428d7b3dSmrg
114428d7b3dSmrg	p1.x = linear->p1.x;
115428d7b3dSmrg	p1.y = linear->p1.y;
116428d7b3dSmrg	p2.x = linear->p2.x;
117428d7b3dSmrg	p2.y = linear->p2.y;
118428d7b3dSmrg
119428d7b3dSmrg	return pixman_image_create_linear_gradient(&p1, &p2,
120428d7b3dSmrg						   (pixman_gradient_stop_t *)
121428d7b3dSmrg						   gradient->stops,
122428d7b3dSmrg						   gradient->nstops);
123428d7b3dSmrg}
124428d7b3dSmrg
125428d7b3dSmrgstatic pixman_image_t *
126428d7b3dSmrgcreate_radial_gradient_image(PictGradient * gradient)
127428d7b3dSmrg{
128428d7b3dSmrg	PictRadialGradient *radial = (PictRadialGradient *) gradient;
129428d7b3dSmrg	pixman_point_fixed_t c1;
130428d7b3dSmrg	pixman_point_fixed_t c2;
131428d7b3dSmrg
132428d7b3dSmrg	c1.x = radial->c1.x;
133428d7b3dSmrg	c1.y = radial->c1.y;
134428d7b3dSmrg	c2.x = radial->c2.x;
135428d7b3dSmrg	c2.y = radial->c2.y;
136428d7b3dSmrg
137428d7b3dSmrg	return pixman_image_create_radial_gradient(&c1, &c2, radial->c1.radius,
138428d7b3dSmrg						   radial->c2.radius,
139428d7b3dSmrg						   (pixman_gradient_stop_t *)
140428d7b3dSmrg						   gradient->stops,
141428d7b3dSmrg						   gradient->nstops);
142428d7b3dSmrg}
143428d7b3dSmrg
144428d7b3dSmrgstatic pixman_image_t *
145428d7b3dSmrgcreate_conical_gradient_image(PictGradient * gradient)
146428d7b3dSmrg{
147428d7b3dSmrg	PictConicalGradient *conical = (PictConicalGradient *) gradient;
148428d7b3dSmrg	pixman_point_fixed_t center;
149428d7b3dSmrg
150428d7b3dSmrg	center.x = conical->center.x;
151428d7b3dSmrg	center.y = conical->center.y;
152428d7b3dSmrg
153428d7b3dSmrg	return pixman_image_create_conical_gradient(&center, conical->angle,
154428d7b3dSmrg						    (pixman_gradient_stop_t *)
155428d7b3dSmrg						    gradient->stops,
156428d7b3dSmrg						    gradient->nstops);
157428d7b3dSmrg}
158428d7b3dSmrg
159428d7b3dSmrgstatic inline bool
160428d7b3dSmrgpicture_has_clip(PicturePtr p)
161428d7b3dSmrg{
162428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,16,99,1,0)
163428d7b3dSmrg	return p->clientClip;
164428d7b3dSmrg#else
165428d7b3dSmrg	return p->clientClipType != CT_NONE;
166428d7b3dSmrg#endif
167428d7b3dSmrg}
168428d7b3dSmrg
169428d7b3dSmrgstatic pixman_image_t *
170428d7b3dSmrgcreate_bits_picture(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
171428d7b3dSmrg{
172428d7b3dSmrg	PixmapPtr pixmap;
173428d7b3dSmrg	FbBits *bits;
174428d7b3dSmrg	FbStride stride;
175428d7b3dSmrg	int bpp;
176428d7b3dSmrg	pixman_image_t *image;
177428d7b3dSmrg
178428d7b3dSmrg	fbGetDrawablePixmap(pict->pDrawable, pixmap, *xoff, *yoff);
179428d7b3dSmrg	fbGetPixmapBitsData(pixmap, bits, stride, bpp);
180428d7b3dSmrg
181428d7b3dSmrg	image = pixman_image_create_bits((pixman_format_code_t) pict->format,
182428d7b3dSmrg					 pixmap->drawable.width,
183428d7b3dSmrg					 pixmap->drawable.height, (uint32_t *) bits,
184428d7b3dSmrg					 stride * sizeof(FbStride));
185428d7b3dSmrg
186428d7b3dSmrg	if (!image)
187428d7b3dSmrg		return NULL;
188428d7b3dSmrg
189428d7b3dSmrg	/* pCompositeClip is undefined for source pictures, so
190428d7b3dSmrg	 * only set the clip region for pictures with drawables
191428d7b3dSmrg	 */
192428d7b3dSmrg	if (has_clip) {
193428d7b3dSmrg		if (picture_has_clip(pict))
194428d7b3dSmrg			pixman_image_set_has_client_clip(image, TRUE);
195428d7b3dSmrg
196428d7b3dSmrg		if (*xoff || *yoff)
197428d7b3dSmrg			pixman_region_translate(pict->pCompositeClip, *xoff, *yoff);
198428d7b3dSmrg
199428d7b3dSmrg		pixman_image_set_clip_region(image, pict->pCompositeClip);
200428d7b3dSmrg
201428d7b3dSmrg		if (*xoff || *yoff)
202428d7b3dSmrg			pixman_region_translate(pict->pCompositeClip, -*xoff, -*yoff);
203428d7b3dSmrg	}
204428d7b3dSmrg
205428d7b3dSmrg	/* Indexed table */
206428d7b3dSmrg	if (pict->pFormat->index.devPrivate)
207428d7b3dSmrg		pixman_image_set_indexed(image, pict->pFormat->index.devPrivate);
208428d7b3dSmrg
209428d7b3dSmrg	/* Add in drawable origin to position within the image */
210428d7b3dSmrg	*xoff += pict->pDrawable->x;
211428d7b3dSmrg	*yoff += pict->pDrawable->y;
212428d7b3dSmrg
213428d7b3dSmrg	return image;
214428d7b3dSmrg}
215428d7b3dSmrg
216428d7b3dSmrgstatic pixman_image_t *image_from_pict_internal(PicturePtr pict, Bool has_clip,
217428d7b3dSmrg                                                int *xoff, int *yoff,
218428d7b3dSmrg                                                Bool is_alpha_map);
219428d7b3dSmrg
220428d7b3dSmrgstatic void
221428d7b3dSmrgset_image_properties(pixman_image_t * image, PicturePtr pict, Bool has_clip,
222428d7b3dSmrg                     int *xoff, int *yoff, Bool is_alpha_map)
223428d7b3dSmrg{
224428d7b3dSmrg	pixman_repeat_t repeat;
225428d7b3dSmrg	pixman_filter_t filter;
226428d7b3dSmrg
227428d7b3dSmrg	if (pict->transform) {
228428d7b3dSmrg		/* For source images, adjust the transform to account
229428d7b3dSmrg		 * for the drawable offset within the pixman image,
230428d7b3dSmrg		 * then set the offset to 0 as it will be used
231428d7b3dSmrg		 * to compute positions within the transformed image.
232428d7b3dSmrg		 */
233428d7b3dSmrg		if (!has_clip) {
234428d7b3dSmrg			struct pixman_transform adjusted;
235428d7b3dSmrg
236428d7b3dSmrg			adjusted = *pict->transform;
237428d7b3dSmrg			pixman_transform_translate(&adjusted,
238428d7b3dSmrg						   NULL,
239428d7b3dSmrg						   pixman_int_to_fixed(*xoff),
240428d7b3dSmrg						   pixman_int_to_fixed(*yoff));
241428d7b3dSmrg			pixman_image_set_transform(image, &adjusted);
242428d7b3dSmrg			*xoff = 0;
243428d7b3dSmrg			*yoff = 0;
244428d7b3dSmrg		}
245428d7b3dSmrg		else
246428d7b3dSmrg			pixman_image_set_transform(image, pict->transform);
247428d7b3dSmrg	}
248428d7b3dSmrg
249428d7b3dSmrg	switch (pict->repeatType) {
250428d7b3dSmrg	default:
251428d7b3dSmrg	case RepeatNone:
252428d7b3dSmrg		repeat = PIXMAN_REPEAT_NONE;
253428d7b3dSmrg		break;
254428d7b3dSmrg
255428d7b3dSmrg	case RepeatPad:
256428d7b3dSmrg		repeat = PIXMAN_REPEAT_PAD;
257428d7b3dSmrg		break;
258428d7b3dSmrg
259428d7b3dSmrg	case RepeatNormal:
260428d7b3dSmrg		repeat = PIXMAN_REPEAT_NORMAL;
261428d7b3dSmrg		break;
262428d7b3dSmrg
263428d7b3dSmrg	case RepeatReflect:
264428d7b3dSmrg		repeat = PIXMAN_REPEAT_REFLECT;
265428d7b3dSmrg		break;
266428d7b3dSmrg	}
267428d7b3dSmrg
268428d7b3dSmrg	pixman_image_set_repeat(image, repeat);
269428d7b3dSmrg
270428d7b3dSmrg	/* Fetch alpha map unless 'pict' is being used
271428d7b3dSmrg	 * as the alpha map for this operation
272428d7b3dSmrg	 */
273428d7b3dSmrg	if (pict->alphaMap && !is_alpha_map) {
274428d7b3dSmrg		int alpha_xoff, alpha_yoff;
275428d7b3dSmrg		pixman_image_t *alpha_map =
276428d7b3dSmrg			image_from_pict_internal(pict->alphaMap, FALSE, &alpha_xoff,
277428d7b3dSmrg						 &alpha_yoff, TRUE);
278428d7b3dSmrg
279428d7b3dSmrg		pixman_image_set_alpha_map(image, alpha_map, pict->alphaOrigin.x,
280428d7b3dSmrg					   pict->alphaOrigin.y);
281428d7b3dSmrg
282428d7b3dSmrg		free_pixman_pict(pict->alphaMap, alpha_map);
283428d7b3dSmrg	}
284428d7b3dSmrg
285428d7b3dSmrg	pixman_image_set_component_alpha(image, pict->componentAlpha);
286428d7b3dSmrg
287428d7b3dSmrg	switch (pict->filter) {
288428d7b3dSmrg	default:
289428d7b3dSmrg	case PictFilterNearest:
290428d7b3dSmrg	case PictFilterFast:
291428d7b3dSmrg		filter = PIXMAN_FILTER_NEAREST;
292428d7b3dSmrg		break;
293428d7b3dSmrg
294428d7b3dSmrg	case PictFilterBilinear:
295428d7b3dSmrg	case PictFilterGood:
296428d7b3dSmrg		filter = PIXMAN_FILTER_BILINEAR;
297428d7b3dSmrg		break;
298428d7b3dSmrg
299428d7b3dSmrg	case PictFilterConvolution:
300428d7b3dSmrg		filter = PIXMAN_FILTER_CONVOLUTION;
301428d7b3dSmrg		break;
302428d7b3dSmrg	}
303428d7b3dSmrg
304428d7b3dSmrg	pixman_image_set_filter(image, filter,
305428d7b3dSmrg				(pixman_fixed_t *) pict->filter_params,
306428d7b3dSmrg				pict->filter_nparams);
307428d7b3dSmrg	pixman_image_set_source_clipping(image, TRUE);
308428d7b3dSmrg}
309428d7b3dSmrg
310428d7b3dSmrgstatic pixman_image_t *
311428d7b3dSmrgimage_from_pict_internal(PicturePtr pict, Bool has_clip, int *xoff, int *yoff,
312428d7b3dSmrg                         Bool is_alpha_map)
313428d7b3dSmrg{
314428d7b3dSmrg	pixman_image_t *image = NULL;
315428d7b3dSmrg
316428d7b3dSmrg	if (!pict)
317428d7b3dSmrg		return NULL;
318428d7b3dSmrg
319428d7b3dSmrg	if (pict->pDrawable) {
320428d7b3dSmrg		image = create_bits_picture(pict, has_clip, xoff, yoff);
321428d7b3dSmrg	}
322428d7b3dSmrg	else if (pict->pSourcePict) {
323428d7b3dSmrg		SourcePict *sp = pict->pSourcePict;
324428d7b3dSmrg
325428d7b3dSmrg		if (sp->type == SourcePictTypeSolidFill) {
326428d7b3dSmrg			image = create_solid_fill_image(pict);
327428d7b3dSmrg		}
328428d7b3dSmrg		else {
329428d7b3dSmrg			PictGradient *gradient = &pict->pSourcePict->gradient;
330428d7b3dSmrg
331428d7b3dSmrg			if (sp->type == SourcePictTypeLinear)
332428d7b3dSmrg				image = create_linear_gradient_image(gradient);
333428d7b3dSmrg			else if (sp->type == SourcePictTypeRadial)
334428d7b3dSmrg				image = create_radial_gradient_image(gradient);
335428d7b3dSmrg			else if (sp->type == SourcePictTypeConical)
336428d7b3dSmrg				image = create_conical_gradient_image(gradient);
337428d7b3dSmrg		}
338428d7b3dSmrg		*xoff = *yoff = 0;
339428d7b3dSmrg	}
340428d7b3dSmrg
341428d7b3dSmrg	if (image)
342428d7b3dSmrg		set_image_properties(image, pict, has_clip, xoff, yoff, is_alpha_map);
343428d7b3dSmrg
344428d7b3dSmrg	return image;
345428d7b3dSmrg}
346428d7b3dSmrg
347428d7b3dSmrgpixman_image_t *
348428d7b3dSmrgimage_from_pict(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
349428d7b3dSmrg{
350428d7b3dSmrg	return image_from_pict_internal(pict, has_clip, xoff, yoff, FALSE);
351428d7b3dSmrg}
352428d7b3dSmrg
353428d7b3dSmrgvoid
354428d7b3dSmrgfree_pixman_pict(PicturePtr pict, pixman_image_t * image)
355428d7b3dSmrg{
356428d7b3dSmrg	if (image)
357428d7b3dSmrg                pixman_image_unref(image);
358428d7b3dSmrg}
359