103b705cfSriastradh/*
203b705cfSriastradh * Copyright © 2000 SuSE, Inc.
303b705cfSriastradh * Copyright © 2007 Red Hat, Inc.
403b705cfSriastradh * Copyright © 2012 Intel Corporation
503b705cfSriastradh *
603b705cfSriastradh * Permission to use, copy, modify, distribute, and sell this software and its
703b705cfSriastradh * documentation for any purpose is hereby granted without fee, provided that
803b705cfSriastradh * the above copyright notice appear in all copies and that both that
903b705cfSriastradh * copyright notice and this permission notice appear in supporting
1003b705cfSriastradh * documentation, and that the name of SuSE not be used in advertising or
1103b705cfSriastradh * publicity pertaining to distribution of the software without specific,
1203b705cfSriastradh * written prior permission.  SuSE makes no representations about the
1303b705cfSriastradh * suitability of this software for any purpose.  It is provided "as is"
1403b705cfSriastradh * without express or implied warranty.
1503b705cfSriastradh *
1603b705cfSriastradh * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
1703b705cfSriastradh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
1803b705cfSriastradh * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1903b705cfSriastradh * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
2003b705cfSriastradh * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
2103b705cfSriastradh * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2203b705cfSriastradh *
2303b705cfSriastradh * Author:  Keith Packard, SuSE, Inc.
2403b705cfSriastradh */
2503b705cfSriastradh
2603b705cfSriastradh#include <string.h>
2703b705cfSriastradh
2803b705cfSriastradh#include "fb.h"
2903b705cfSriastradh#include "fbpict.h"
3003b705cfSriastradh
3103b705cfSriastradhstatic void
3203b705cfSriastradhSourceValidateOnePicture(PicturePtr picture)
3303b705cfSriastradh{
3403b705cfSriastradh	DrawablePtr drawable = picture->pDrawable;
3503b705cfSriastradh
3603b705cfSriastradh	if (!drawable)
3703b705cfSriastradh		return;
3803b705cfSriastradh
3903b705cfSriastradh	SourceValidate(drawable,
4003b705cfSriastradh		       0, 0, drawable->width, drawable->height,
4103b705cfSriastradh		       picture->subWindowMode);
4203b705cfSriastradh}
4303b705cfSriastradh
4403b705cfSriastradhstatic void
4503b705cfSriastradhfbCompositeSourceValidate(PicturePtr picture)
4603b705cfSriastradh{
4703b705cfSriastradh	SourceValidateOnePicture(picture);
4803b705cfSriastradh	if (picture->alphaMap)
4903b705cfSriastradh		SourceValidateOnePicture(picture->alphaMap);
5003b705cfSriastradh}
5103b705cfSriastradh
5203b705cfSriastradhvoid
5303b705cfSriastradhfbComposite(CARD8 op,
5403b705cfSriastradh            PicturePtr pSrc,
5503b705cfSriastradh            PicturePtr pMask,
5603b705cfSriastradh            PicturePtr pDst,
5703b705cfSriastradh            INT16 xSrc,
5803b705cfSriastradh            INT16 ySrc,
5903b705cfSriastradh            INT16 xMask,
6003b705cfSriastradh            INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
6103b705cfSriastradh{
6203b705cfSriastradh	pixman_image_t *src, *mask, *dest;
6303b705cfSriastradh	int src_xoff, src_yoff;
6403b705cfSriastradh	int msk_xoff, msk_yoff;
6503b705cfSriastradh	int dst_xoff, dst_yoff;
6603b705cfSriastradh
6703b705cfSriastradh	fbCompositeSourceValidate(pSrc);
6803b705cfSriastradh	if (pMask)
6903b705cfSriastradh		fbCompositeSourceValidate(pMask);
7003b705cfSriastradh
7103b705cfSriastradh	src = image_from_pict(pSrc, FALSE, &src_xoff, &src_yoff);
7203b705cfSriastradh	mask = image_from_pict(pMask, FALSE, &msk_xoff, &msk_yoff);
7303b705cfSriastradh	dest = image_from_pict(pDst, TRUE, &dst_xoff, &dst_yoff);
7403b705cfSriastradh
7503b705cfSriastradh	if (src && dest && !(pMask && !mask)) {
7603b705cfSriastradh		pixman_image_composite(op, src, mask, dest,
7703b705cfSriastradh				       xSrc + src_xoff, ySrc + src_yoff,
7803b705cfSriastradh				       xMask + msk_xoff, yMask + msk_yoff,
7903b705cfSriastradh				       xDst + dst_xoff, yDst + dst_yoff, width, height);
8003b705cfSriastradh	}
8103b705cfSriastradh
8203b705cfSriastradh	free_pixman_pict(pSrc, src);
8303b705cfSriastradh	free_pixman_pict(pMask, mask);
8403b705cfSriastradh	free_pixman_pict(pDst, dest);
8503b705cfSriastradh}
8603b705cfSriastradh
8703b705cfSriastradhstatic pixman_image_t *
8803b705cfSriastradhcreate_solid_fill_image(PicturePtr pict)
8903b705cfSriastradh{
9003b705cfSriastradh	PictSolidFill *solid = &pict->pSourcePict->solidFill;
9103b705cfSriastradh	pixman_color_t color;
9203b705cfSriastradh	CARD32 a, r, g, b;
9303b705cfSriastradh
9403b705cfSriastradh	a = (solid->color & 0xff000000) >> 24;
9503b705cfSriastradh	r = (solid->color & 0x00ff0000) >> 16;
9603b705cfSriastradh	g = (solid->color & 0x0000ff00) >> 8;
9703b705cfSriastradh	b = (solid->color & 0x000000ff) >> 0;
9803b705cfSriastradh
9903b705cfSriastradh	color.alpha = (a << 8) | a;
10003b705cfSriastradh	color.red = (r << 8) | r;
10103b705cfSriastradh	color.green = (g << 8) | g;
10203b705cfSriastradh	color.blue = (b << 8) | b;
10303b705cfSriastradh
10403b705cfSriastradh	return pixman_image_create_solid_fill(&color);
10503b705cfSriastradh}
10603b705cfSriastradh
10703b705cfSriastradhstatic pixman_image_t *
10803b705cfSriastradhcreate_linear_gradient_image(PictGradient * gradient)
10903b705cfSriastradh{
11003b705cfSriastradh	PictLinearGradient *linear = (PictLinearGradient *) gradient;
11103b705cfSriastradh	pixman_point_fixed_t p1;
11203b705cfSriastradh	pixman_point_fixed_t p2;
11303b705cfSriastradh
11403b705cfSriastradh	p1.x = linear->p1.x;
11503b705cfSriastradh	p1.y = linear->p1.y;
11603b705cfSriastradh	p2.x = linear->p2.x;
11703b705cfSriastradh	p2.y = linear->p2.y;
11803b705cfSriastradh
11903b705cfSriastradh	return pixman_image_create_linear_gradient(&p1, &p2,
12003b705cfSriastradh						   (pixman_gradient_stop_t *)
12103b705cfSriastradh						   gradient->stops,
12203b705cfSriastradh						   gradient->nstops);
12303b705cfSriastradh}
12403b705cfSriastradh
12503b705cfSriastradhstatic pixman_image_t *
12603b705cfSriastradhcreate_radial_gradient_image(PictGradient * gradient)
12703b705cfSriastradh{
12803b705cfSriastradh	PictRadialGradient *radial = (PictRadialGradient *) gradient;
12903b705cfSriastradh	pixman_point_fixed_t c1;
13003b705cfSriastradh	pixman_point_fixed_t c2;
13103b705cfSriastradh
13203b705cfSriastradh	c1.x = radial->c1.x;
13303b705cfSriastradh	c1.y = radial->c1.y;
13403b705cfSriastradh	c2.x = radial->c2.x;
13503b705cfSriastradh	c2.y = radial->c2.y;
13603b705cfSriastradh
13703b705cfSriastradh	return pixman_image_create_radial_gradient(&c1, &c2, radial->c1.radius,
13803b705cfSriastradh						   radial->c2.radius,
13903b705cfSriastradh						   (pixman_gradient_stop_t *)
14003b705cfSriastradh						   gradient->stops,
14103b705cfSriastradh						   gradient->nstops);
14203b705cfSriastradh}
14303b705cfSriastradh
14403b705cfSriastradhstatic pixman_image_t *
14503b705cfSriastradhcreate_conical_gradient_image(PictGradient * gradient)
14603b705cfSriastradh{
14703b705cfSriastradh	PictConicalGradient *conical = (PictConicalGradient *) gradient;
14803b705cfSriastradh	pixman_point_fixed_t center;
14903b705cfSriastradh
15003b705cfSriastradh	center.x = conical->center.x;
15103b705cfSriastradh	center.y = conical->center.y;
15203b705cfSriastradh
15303b705cfSriastradh	return pixman_image_create_conical_gradient(&center, conical->angle,
15403b705cfSriastradh						    (pixman_gradient_stop_t *)
15503b705cfSriastradh						    gradient->stops,
15603b705cfSriastradh						    gradient->nstops);
15703b705cfSriastradh}
15803b705cfSriastradh
15913496ba1Ssnjstatic inline bool
16013496ba1Ssnjpicture_has_clip(PicturePtr p)
16113496ba1Ssnj{
16213496ba1Ssnj#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,16,99,1,0)
16313496ba1Ssnj	return p->clientClip;
16413496ba1Ssnj#else
16513496ba1Ssnj	return p->clientClipType != CT_NONE;
16613496ba1Ssnj#endif
16713496ba1Ssnj}
16813496ba1Ssnj
16903b705cfSriastradhstatic pixman_image_t *
17003b705cfSriastradhcreate_bits_picture(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
17103b705cfSriastradh{
17203b705cfSriastradh	PixmapPtr pixmap;
17303b705cfSriastradh	FbBits *bits;
17403b705cfSriastradh	FbStride stride;
17503b705cfSriastradh	int bpp;
17603b705cfSriastradh	pixman_image_t *image;
17703b705cfSriastradh
17803b705cfSriastradh	fbGetDrawablePixmap(pict->pDrawable, pixmap, *xoff, *yoff);
17903b705cfSriastradh	fbGetPixmapBitsData(pixmap, bits, stride, bpp);
18003b705cfSriastradh
18103b705cfSriastradh	image = pixman_image_create_bits((pixman_format_code_t) pict->format,
18203b705cfSriastradh					 pixmap->drawable.width,
18303b705cfSriastradh					 pixmap->drawable.height, (uint32_t *) bits,
18403b705cfSriastradh					 stride * sizeof(FbStride));
18503b705cfSriastradh
18603b705cfSriastradh	if (!image)
18703b705cfSriastradh		return NULL;
18803b705cfSriastradh
18903b705cfSriastradh	/* pCompositeClip is undefined for source pictures, so
19003b705cfSriastradh	 * only set the clip region for pictures with drawables
19103b705cfSriastradh	 */
19203b705cfSriastradh	if (has_clip) {
19313496ba1Ssnj		if (picture_has_clip(pict))
19403b705cfSriastradh			pixman_image_set_has_client_clip(image, TRUE);
19503b705cfSriastradh
19603b705cfSriastradh		if (*xoff || *yoff)
19703b705cfSriastradh			pixman_region_translate(pict->pCompositeClip, *xoff, *yoff);
19803b705cfSriastradh
19903b705cfSriastradh		pixman_image_set_clip_region(image, pict->pCompositeClip);
20003b705cfSriastradh
20103b705cfSriastradh		if (*xoff || *yoff)
20203b705cfSriastradh			pixman_region_translate(pict->pCompositeClip, -*xoff, -*yoff);
20303b705cfSriastradh	}
20403b705cfSriastradh
20503b705cfSriastradh	/* Indexed table */
20603b705cfSriastradh	if (pict->pFormat->index.devPrivate)
20703b705cfSriastradh		pixman_image_set_indexed(image, pict->pFormat->index.devPrivate);
20803b705cfSriastradh
20903b705cfSriastradh	/* Add in drawable origin to position within the image */
21003b705cfSriastradh	*xoff += pict->pDrawable->x;
21103b705cfSriastradh	*yoff += pict->pDrawable->y;
21203b705cfSriastradh
21303b705cfSriastradh	return image;
21403b705cfSriastradh}
21503b705cfSriastradh
21603b705cfSriastradhstatic pixman_image_t *image_from_pict_internal(PicturePtr pict, Bool has_clip,
21703b705cfSriastradh                                                int *xoff, int *yoff,
21803b705cfSriastradh                                                Bool is_alpha_map);
21903b705cfSriastradh
22003b705cfSriastradhstatic void
22103b705cfSriastradhset_image_properties(pixman_image_t * image, PicturePtr pict, Bool has_clip,
22203b705cfSriastradh                     int *xoff, int *yoff, Bool is_alpha_map)
22303b705cfSriastradh{
22403b705cfSriastradh	pixman_repeat_t repeat;
22503b705cfSriastradh	pixman_filter_t filter;
22603b705cfSriastradh
22703b705cfSriastradh	if (pict->transform) {
22803b705cfSriastradh		/* For source images, adjust the transform to account
22903b705cfSriastradh		 * for the drawable offset within the pixman image,
23003b705cfSriastradh		 * then set the offset to 0 as it will be used
23103b705cfSriastradh		 * to compute positions within the transformed image.
23203b705cfSriastradh		 */
23303b705cfSriastradh		if (!has_clip) {
23403b705cfSriastradh			struct pixman_transform adjusted;
23503b705cfSriastradh
23603b705cfSriastradh			adjusted = *pict->transform;
23703b705cfSriastradh			pixman_transform_translate(&adjusted,
23803b705cfSriastradh						   NULL,
23903b705cfSriastradh						   pixman_int_to_fixed(*xoff),
24003b705cfSriastradh						   pixman_int_to_fixed(*yoff));
24103b705cfSriastradh			pixman_image_set_transform(image, &adjusted);
24203b705cfSriastradh			*xoff = 0;
24303b705cfSriastradh			*yoff = 0;
24403b705cfSriastradh		}
24503b705cfSriastradh		else
24603b705cfSriastradh			pixman_image_set_transform(image, pict->transform);
24703b705cfSriastradh	}
24803b705cfSriastradh
24903b705cfSriastradh	switch (pict->repeatType) {
25003b705cfSriastradh	default:
25103b705cfSriastradh	case RepeatNone:
25203b705cfSriastradh		repeat = PIXMAN_REPEAT_NONE;
25303b705cfSriastradh		break;
25403b705cfSriastradh
25503b705cfSriastradh	case RepeatPad:
25603b705cfSriastradh		repeat = PIXMAN_REPEAT_PAD;
25703b705cfSriastradh		break;
25803b705cfSriastradh
25903b705cfSriastradh	case RepeatNormal:
26003b705cfSriastradh		repeat = PIXMAN_REPEAT_NORMAL;
26103b705cfSriastradh		break;
26203b705cfSriastradh
26303b705cfSriastradh	case RepeatReflect:
26403b705cfSriastradh		repeat = PIXMAN_REPEAT_REFLECT;
26503b705cfSriastradh		break;
26603b705cfSriastradh	}
26703b705cfSriastradh
26803b705cfSriastradh	pixman_image_set_repeat(image, repeat);
26903b705cfSriastradh
27003b705cfSriastradh	/* Fetch alpha map unless 'pict' is being used
27103b705cfSriastradh	 * as the alpha map for this operation
27203b705cfSriastradh	 */
27303b705cfSriastradh	if (pict->alphaMap && !is_alpha_map) {
27403b705cfSriastradh		int alpha_xoff, alpha_yoff;
27503b705cfSriastradh		pixman_image_t *alpha_map =
27603b705cfSriastradh			image_from_pict_internal(pict->alphaMap, FALSE, &alpha_xoff,
27703b705cfSriastradh						 &alpha_yoff, TRUE);
27803b705cfSriastradh
27903b705cfSriastradh		pixman_image_set_alpha_map(image, alpha_map, pict->alphaOrigin.x,
28003b705cfSriastradh					   pict->alphaOrigin.y);
28103b705cfSriastradh
28203b705cfSriastradh		free_pixman_pict(pict->alphaMap, alpha_map);
28303b705cfSriastradh	}
28403b705cfSriastradh
28503b705cfSriastradh	pixman_image_set_component_alpha(image, pict->componentAlpha);
28603b705cfSriastradh
28703b705cfSriastradh	switch (pict->filter) {
28803b705cfSriastradh	default:
28903b705cfSriastradh	case PictFilterNearest:
29003b705cfSriastradh	case PictFilterFast:
29103b705cfSriastradh		filter = PIXMAN_FILTER_NEAREST;
29203b705cfSriastradh		break;
29303b705cfSriastradh
29403b705cfSriastradh	case PictFilterBilinear:
29503b705cfSriastradh	case PictFilterGood:
29603b705cfSriastradh		filter = PIXMAN_FILTER_BILINEAR;
29703b705cfSriastradh		break;
29803b705cfSriastradh
29903b705cfSriastradh	case PictFilterConvolution:
30003b705cfSriastradh		filter = PIXMAN_FILTER_CONVOLUTION;
30103b705cfSriastradh		break;
30203b705cfSriastradh	}
30303b705cfSriastradh
30403b705cfSriastradh	pixman_image_set_filter(image, filter,
30503b705cfSriastradh				(pixman_fixed_t *) pict->filter_params,
30603b705cfSriastradh				pict->filter_nparams);
30703b705cfSriastradh	pixman_image_set_source_clipping(image, TRUE);
30803b705cfSriastradh}
30903b705cfSriastradh
31003b705cfSriastradhstatic pixman_image_t *
31103b705cfSriastradhimage_from_pict_internal(PicturePtr pict, Bool has_clip, int *xoff, int *yoff,
31203b705cfSriastradh                         Bool is_alpha_map)
31303b705cfSriastradh{
31403b705cfSriastradh	pixman_image_t *image = NULL;
31503b705cfSriastradh
31603b705cfSriastradh	if (!pict)
31703b705cfSriastradh		return NULL;
31803b705cfSriastradh
31903b705cfSriastradh	if (pict->pDrawable) {
32003b705cfSriastradh		image = create_bits_picture(pict, has_clip, xoff, yoff);
32103b705cfSriastradh	}
32203b705cfSriastradh	else if (pict->pSourcePict) {
32303b705cfSriastradh		SourcePict *sp = pict->pSourcePict;
32403b705cfSriastradh
32503b705cfSriastradh		if (sp->type == SourcePictTypeSolidFill) {
32603b705cfSriastradh			image = create_solid_fill_image(pict);
32703b705cfSriastradh		}
32803b705cfSriastradh		else {
32903b705cfSriastradh			PictGradient *gradient = &pict->pSourcePict->gradient;
33003b705cfSriastradh
33103b705cfSriastradh			if (sp->type == SourcePictTypeLinear)
33203b705cfSriastradh				image = create_linear_gradient_image(gradient);
33303b705cfSriastradh			else if (sp->type == SourcePictTypeRadial)
33403b705cfSriastradh				image = create_radial_gradient_image(gradient);
33503b705cfSriastradh			else if (sp->type == SourcePictTypeConical)
33603b705cfSriastradh				image = create_conical_gradient_image(gradient);
33703b705cfSriastradh		}
33803b705cfSriastradh		*xoff = *yoff = 0;
33903b705cfSriastradh	}
34003b705cfSriastradh
34103b705cfSriastradh	if (image)
34203b705cfSriastradh		set_image_properties(image, pict, has_clip, xoff, yoff, is_alpha_map);
34303b705cfSriastradh
34403b705cfSriastradh	return image;
34503b705cfSriastradh}
34603b705cfSriastradh
34703b705cfSriastradhpixman_image_t *
34803b705cfSriastradhimage_from_pict(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
34903b705cfSriastradh{
35003b705cfSriastradh	return image_from_pict_internal(pict, has_clip, xoff, yoff, FALSE);
35103b705cfSriastradh}
35203b705cfSriastradh
35303b705cfSriastradhvoid
35403b705cfSriastradhfree_pixman_pict(PicturePtr pict, pixman_image_t * image)
35503b705cfSriastradh{
35603b705cfSriastradh	if (image)
35703b705cfSriastradh                pixman_image_unref(image);
35803b705cfSriastradh}
359