fbpict.c revision 428d7b3d
1/*
2 * Copyright © 2000 SuSE, Inc.
3 * Copyright © 2007 Red Hat, Inc.
4 * Copyright © 2012 Intel Corporation
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 SuSE not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission.  SuSE 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 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
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 * Author:  Keith Packard, SuSE, Inc.
24 */
25
26#include <string.h>
27
28#include "fb.h"
29#include "fbpict.h"
30
31static void
32SourceValidateOnePicture(PicturePtr picture)
33{
34	DrawablePtr drawable = picture->pDrawable;
35
36	if (!drawable)
37		return;
38
39	SourceValidate(drawable,
40		       0, 0, drawable->width, drawable->height,
41		       picture->subWindowMode);
42}
43
44static void
45fbCompositeSourceValidate(PicturePtr picture)
46{
47	SourceValidateOnePicture(picture);
48	if (picture->alphaMap)
49		SourceValidateOnePicture(picture->alphaMap);
50}
51
52void
53fbComposite(CARD8 op,
54            PicturePtr pSrc,
55            PicturePtr pMask,
56            PicturePtr pDst,
57            INT16 xSrc,
58            INT16 ySrc,
59            INT16 xMask,
60            INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
61{
62	pixman_image_t *src, *mask, *dest;
63	int src_xoff, src_yoff;
64	int msk_xoff, msk_yoff;
65	int dst_xoff, dst_yoff;
66
67	fbCompositeSourceValidate(pSrc);
68	if (pMask)
69		fbCompositeSourceValidate(pMask);
70
71	src = image_from_pict(pSrc, FALSE, &src_xoff, &src_yoff);
72	mask = image_from_pict(pMask, FALSE, &msk_xoff, &msk_yoff);
73	dest = image_from_pict(pDst, TRUE, &dst_xoff, &dst_yoff);
74
75	if (src && dest && !(pMask && !mask)) {
76		pixman_image_composite(op, src, mask, dest,
77				       xSrc + src_xoff, ySrc + src_yoff,
78				       xMask + msk_xoff, yMask + msk_yoff,
79				       xDst + dst_xoff, yDst + dst_yoff, width, height);
80	}
81
82	free_pixman_pict(pSrc, src);
83	free_pixman_pict(pMask, mask);
84	free_pixman_pict(pDst, dest);
85}
86
87static pixman_image_t *
88create_solid_fill_image(PicturePtr pict)
89{
90	PictSolidFill *solid = &pict->pSourcePict->solidFill;
91	pixman_color_t color;
92	CARD32 a, r, g, b;
93
94	a = (solid->color & 0xff000000) >> 24;
95	r = (solid->color & 0x00ff0000) >> 16;
96	g = (solid->color & 0x0000ff00) >> 8;
97	b = (solid->color & 0x000000ff) >> 0;
98
99	color.alpha = (a << 8) | a;
100	color.red = (r << 8) | r;
101	color.green = (g << 8) | g;
102	color.blue = (b << 8) | b;
103
104	return pixman_image_create_solid_fill(&color);
105}
106
107static pixman_image_t *
108create_linear_gradient_image(PictGradient * gradient)
109{
110	PictLinearGradient *linear = (PictLinearGradient *) gradient;
111	pixman_point_fixed_t p1;
112	pixman_point_fixed_t p2;
113
114	p1.x = linear->p1.x;
115	p1.y = linear->p1.y;
116	p2.x = linear->p2.x;
117	p2.y = linear->p2.y;
118
119	return pixman_image_create_linear_gradient(&p1, &p2,
120						   (pixman_gradient_stop_t *)
121						   gradient->stops,
122						   gradient->nstops);
123}
124
125static pixman_image_t *
126create_radial_gradient_image(PictGradient * gradient)
127{
128	PictRadialGradient *radial = (PictRadialGradient *) gradient;
129	pixman_point_fixed_t c1;
130	pixman_point_fixed_t c2;
131
132	c1.x = radial->c1.x;
133	c1.y = radial->c1.y;
134	c2.x = radial->c2.x;
135	c2.y = radial->c2.y;
136
137	return pixman_image_create_radial_gradient(&c1, &c2, radial->c1.radius,
138						   radial->c2.radius,
139						   (pixman_gradient_stop_t *)
140						   gradient->stops,
141						   gradient->nstops);
142}
143
144static pixman_image_t *
145create_conical_gradient_image(PictGradient * gradient)
146{
147	PictConicalGradient *conical = (PictConicalGradient *) gradient;
148	pixman_point_fixed_t center;
149
150	center.x = conical->center.x;
151	center.y = conical->center.y;
152
153	return pixman_image_create_conical_gradient(&center, conical->angle,
154						    (pixman_gradient_stop_t *)
155						    gradient->stops,
156						    gradient->nstops);
157}
158
159static inline bool
160picture_has_clip(PicturePtr p)
161{
162#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,16,99,1,0)
163	return p->clientClip;
164#else
165	return p->clientClipType != CT_NONE;
166#endif
167}
168
169static pixman_image_t *
170create_bits_picture(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
171{
172	PixmapPtr pixmap;
173	FbBits *bits;
174	FbStride stride;
175	int bpp;
176	pixman_image_t *image;
177
178	fbGetDrawablePixmap(pict->pDrawable, pixmap, *xoff, *yoff);
179	fbGetPixmapBitsData(pixmap, bits, stride, bpp);
180
181	image = pixman_image_create_bits((pixman_format_code_t) pict->format,
182					 pixmap->drawable.width,
183					 pixmap->drawable.height, (uint32_t *) bits,
184					 stride * sizeof(FbStride));
185
186	if (!image)
187		return NULL;
188
189	/* pCompositeClip is undefined for source pictures, so
190	 * only set the clip region for pictures with drawables
191	 */
192	if (has_clip) {
193		if (picture_has_clip(pict))
194			pixman_image_set_has_client_clip(image, TRUE);
195
196		if (*xoff || *yoff)
197			pixman_region_translate(pict->pCompositeClip, *xoff, *yoff);
198
199		pixman_image_set_clip_region(image, pict->pCompositeClip);
200
201		if (*xoff || *yoff)
202			pixman_region_translate(pict->pCompositeClip, -*xoff, -*yoff);
203	}
204
205	/* Indexed table */
206	if (pict->pFormat->index.devPrivate)
207		pixman_image_set_indexed(image, pict->pFormat->index.devPrivate);
208
209	/* Add in drawable origin to position within the image */
210	*xoff += pict->pDrawable->x;
211	*yoff += pict->pDrawable->y;
212
213	return image;
214}
215
216static pixman_image_t *image_from_pict_internal(PicturePtr pict, Bool has_clip,
217                                                int *xoff, int *yoff,
218                                                Bool is_alpha_map);
219
220static void
221set_image_properties(pixman_image_t * image, PicturePtr pict, Bool has_clip,
222                     int *xoff, int *yoff, Bool is_alpha_map)
223{
224	pixman_repeat_t repeat;
225	pixman_filter_t filter;
226
227	if (pict->transform) {
228		/* For source images, adjust the transform to account
229		 * for the drawable offset within the pixman image,
230		 * then set the offset to 0 as it will be used
231		 * to compute positions within the transformed image.
232		 */
233		if (!has_clip) {
234			struct pixman_transform adjusted;
235
236			adjusted = *pict->transform;
237			pixman_transform_translate(&adjusted,
238						   NULL,
239						   pixman_int_to_fixed(*xoff),
240						   pixman_int_to_fixed(*yoff));
241			pixman_image_set_transform(image, &adjusted);
242			*xoff = 0;
243			*yoff = 0;
244		}
245		else
246			pixman_image_set_transform(image, pict->transform);
247	}
248
249	switch (pict->repeatType) {
250	default:
251	case RepeatNone:
252		repeat = PIXMAN_REPEAT_NONE;
253		break;
254
255	case RepeatPad:
256		repeat = PIXMAN_REPEAT_PAD;
257		break;
258
259	case RepeatNormal:
260		repeat = PIXMAN_REPEAT_NORMAL;
261		break;
262
263	case RepeatReflect:
264		repeat = PIXMAN_REPEAT_REFLECT;
265		break;
266	}
267
268	pixman_image_set_repeat(image, repeat);
269
270	/* Fetch alpha map unless 'pict' is being used
271	 * as the alpha map for this operation
272	 */
273	if (pict->alphaMap && !is_alpha_map) {
274		int alpha_xoff, alpha_yoff;
275		pixman_image_t *alpha_map =
276			image_from_pict_internal(pict->alphaMap, FALSE, &alpha_xoff,
277						 &alpha_yoff, TRUE);
278
279		pixman_image_set_alpha_map(image, alpha_map, pict->alphaOrigin.x,
280					   pict->alphaOrigin.y);
281
282		free_pixman_pict(pict->alphaMap, alpha_map);
283	}
284
285	pixman_image_set_component_alpha(image, pict->componentAlpha);
286
287	switch (pict->filter) {
288	default:
289	case PictFilterNearest:
290	case PictFilterFast:
291		filter = PIXMAN_FILTER_NEAREST;
292		break;
293
294	case PictFilterBilinear:
295	case PictFilterGood:
296		filter = PIXMAN_FILTER_BILINEAR;
297		break;
298
299	case PictFilterConvolution:
300		filter = PIXMAN_FILTER_CONVOLUTION;
301		break;
302	}
303
304	pixman_image_set_filter(image, filter,
305				(pixman_fixed_t *) pict->filter_params,
306				pict->filter_nparams);
307	pixman_image_set_source_clipping(image, TRUE);
308}
309
310static pixman_image_t *
311image_from_pict_internal(PicturePtr pict, Bool has_clip, int *xoff, int *yoff,
312                         Bool is_alpha_map)
313{
314	pixman_image_t *image = NULL;
315
316	if (!pict)
317		return NULL;
318
319	if (pict->pDrawable) {
320		image = create_bits_picture(pict, has_clip, xoff, yoff);
321	}
322	else if (pict->pSourcePict) {
323		SourcePict *sp = pict->pSourcePict;
324
325		if (sp->type == SourcePictTypeSolidFill) {
326			image = create_solid_fill_image(pict);
327		}
328		else {
329			PictGradient *gradient = &pict->pSourcePict->gradient;
330
331			if (sp->type == SourcePictTypeLinear)
332				image = create_linear_gradient_image(gradient);
333			else if (sp->type == SourcePictTypeRadial)
334				image = create_radial_gradient_image(gradient);
335			else if (sp->type == SourcePictTypeConical)
336				image = create_conical_gradient_image(gradient);
337		}
338		*xoff = *yoff = 0;
339	}
340
341	if (image)
342		set_image_properties(image, pict, has_clip, xoff, yoff, is_alpha_map);
343
344	return image;
345}
346
347pixman_image_t *
348image_from_pict(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
349{
350	return image_from_pict_internal(pict, has_clip, xoff, yoff, FALSE);
351}
352
353void
354free_pixman_pict(PicturePtr pict, pixman_image_t * image)
355{
356	if (image)
357                pixman_image_unref(image);
358}
359