fbpict.c revision 03b705cf
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
15903b705cfSriastradhstatic pixman_image_t *
16003b705cfSriastradhcreate_bits_picture(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
16103b705cfSriastradh{
16203b705cfSriastradh	PixmapPtr pixmap;
16303b705cfSriastradh	FbBits *bits;
16403b705cfSriastradh	FbStride stride;
16503b705cfSriastradh	int bpp;
16603b705cfSriastradh	pixman_image_t *image;
16703b705cfSriastradh
16803b705cfSriastradh	fbGetDrawablePixmap(pict->pDrawable, pixmap, *xoff, *yoff);
16903b705cfSriastradh	fbGetPixmapBitsData(pixmap, bits, stride, bpp);
17003b705cfSriastradh
17103b705cfSriastradh	image = pixman_image_create_bits((pixman_format_code_t) pict->format,
17203b705cfSriastradh					 pixmap->drawable.width,
17303b705cfSriastradh					 pixmap->drawable.height, (uint32_t *) bits,
17403b705cfSriastradh					 stride * sizeof(FbStride));
17503b705cfSriastradh
17603b705cfSriastradh	if (!image)
17703b705cfSriastradh		return NULL;
17803b705cfSriastradh
17903b705cfSriastradh	/* pCompositeClip is undefined for source pictures, so
18003b705cfSriastradh	 * only set the clip region for pictures with drawables
18103b705cfSriastradh	 */
18203b705cfSriastradh	if (has_clip) {
18303b705cfSriastradh		if (pict->clientClipType != CT_NONE)
18403b705cfSriastradh			pixman_image_set_has_client_clip(image, TRUE);
18503b705cfSriastradh
18603b705cfSriastradh		if (*xoff || *yoff)
18703b705cfSriastradh			pixman_region_translate(pict->pCompositeClip, *xoff, *yoff);
18803b705cfSriastradh
18903b705cfSriastradh		pixman_image_set_clip_region(image, pict->pCompositeClip);
19003b705cfSriastradh
19103b705cfSriastradh		if (*xoff || *yoff)
19203b705cfSriastradh			pixman_region_translate(pict->pCompositeClip, -*xoff, -*yoff);
19303b705cfSriastradh	}
19403b705cfSriastradh
19503b705cfSriastradh	/* Indexed table */
19603b705cfSriastradh	if (pict->pFormat->index.devPrivate)
19703b705cfSriastradh		pixman_image_set_indexed(image, pict->pFormat->index.devPrivate);
19803b705cfSriastradh
19903b705cfSriastradh	/* Add in drawable origin to position within the image */
20003b705cfSriastradh	*xoff += pict->pDrawable->x;
20103b705cfSriastradh	*yoff += pict->pDrawable->y;
20203b705cfSriastradh
20303b705cfSriastradh	return image;
20403b705cfSriastradh}
20503b705cfSriastradh
20603b705cfSriastradhstatic pixman_image_t *image_from_pict_internal(PicturePtr pict, Bool has_clip,
20703b705cfSriastradh                                                int *xoff, int *yoff,
20803b705cfSriastradh                                                Bool is_alpha_map);
20903b705cfSriastradh
21003b705cfSriastradhstatic void
21103b705cfSriastradhset_image_properties(pixman_image_t * image, PicturePtr pict, Bool has_clip,
21203b705cfSriastradh                     int *xoff, int *yoff, Bool is_alpha_map)
21303b705cfSriastradh{
21403b705cfSriastradh	pixman_repeat_t repeat;
21503b705cfSriastradh	pixman_filter_t filter;
21603b705cfSriastradh
21703b705cfSriastradh	if (pict->transform) {
21803b705cfSriastradh		/* For source images, adjust the transform to account
21903b705cfSriastradh		 * for the drawable offset within the pixman image,
22003b705cfSriastradh		 * then set the offset to 0 as it will be used
22103b705cfSriastradh		 * to compute positions within the transformed image.
22203b705cfSriastradh		 */
22303b705cfSriastradh		if (!has_clip) {
22403b705cfSriastradh			struct pixman_transform adjusted;
22503b705cfSriastradh
22603b705cfSriastradh			adjusted = *pict->transform;
22703b705cfSriastradh			pixman_transform_translate(&adjusted,
22803b705cfSriastradh						   NULL,
22903b705cfSriastradh						   pixman_int_to_fixed(*xoff),
23003b705cfSriastradh						   pixman_int_to_fixed(*yoff));
23103b705cfSriastradh			pixman_image_set_transform(image, &adjusted);
23203b705cfSriastradh			*xoff = 0;
23303b705cfSriastradh			*yoff = 0;
23403b705cfSriastradh		}
23503b705cfSriastradh		else
23603b705cfSriastradh			pixman_image_set_transform(image, pict->transform);
23703b705cfSriastradh	}
23803b705cfSriastradh
23903b705cfSriastradh	switch (pict->repeatType) {
24003b705cfSriastradh	default:
24103b705cfSriastradh	case RepeatNone:
24203b705cfSriastradh		repeat = PIXMAN_REPEAT_NONE;
24303b705cfSriastradh		break;
24403b705cfSriastradh
24503b705cfSriastradh	case RepeatPad:
24603b705cfSriastradh		repeat = PIXMAN_REPEAT_PAD;
24703b705cfSriastradh		break;
24803b705cfSriastradh
24903b705cfSriastradh	case RepeatNormal:
25003b705cfSriastradh		repeat = PIXMAN_REPEAT_NORMAL;
25103b705cfSriastradh		break;
25203b705cfSriastradh
25303b705cfSriastradh	case RepeatReflect:
25403b705cfSriastradh		repeat = PIXMAN_REPEAT_REFLECT;
25503b705cfSriastradh		break;
25603b705cfSriastradh	}
25703b705cfSriastradh
25803b705cfSriastradh	pixman_image_set_repeat(image, repeat);
25903b705cfSriastradh
26003b705cfSriastradh	/* Fetch alpha map unless 'pict' is being used
26103b705cfSriastradh	 * as the alpha map for this operation
26203b705cfSriastradh	 */
26303b705cfSriastradh	if (pict->alphaMap && !is_alpha_map) {
26403b705cfSriastradh		int alpha_xoff, alpha_yoff;
26503b705cfSriastradh		pixman_image_t *alpha_map =
26603b705cfSriastradh			image_from_pict_internal(pict->alphaMap, FALSE, &alpha_xoff,
26703b705cfSriastradh						 &alpha_yoff, TRUE);
26803b705cfSriastradh
26903b705cfSriastradh		pixman_image_set_alpha_map(image, alpha_map, pict->alphaOrigin.x,
27003b705cfSriastradh					   pict->alphaOrigin.y);
27103b705cfSriastradh
27203b705cfSriastradh		free_pixman_pict(pict->alphaMap, alpha_map);
27303b705cfSriastradh	}
27403b705cfSriastradh
27503b705cfSriastradh	pixman_image_set_component_alpha(image, pict->componentAlpha);
27603b705cfSriastradh
27703b705cfSriastradh	switch (pict->filter) {
27803b705cfSriastradh	default:
27903b705cfSriastradh	case PictFilterNearest:
28003b705cfSriastradh	case PictFilterFast:
28103b705cfSriastradh		filter = PIXMAN_FILTER_NEAREST;
28203b705cfSriastradh		break;
28303b705cfSriastradh
28403b705cfSriastradh	case PictFilterBilinear:
28503b705cfSriastradh	case PictFilterGood:
28603b705cfSriastradh		filter = PIXMAN_FILTER_BILINEAR;
28703b705cfSriastradh		break;
28803b705cfSriastradh
28903b705cfSriastradh	case PictFilterConvolution:
29003b705cfSriastradh		filter = PIXMAN_FILTER_CONVOLUTION;
29103b705cfSriastradh		break;
29203b705cfSriastradh	}
29303b705cfSriastradh
29403b705cfSriastradh	pixman_image_set_filter(image, filter,
29503b705cfSriastradh				(pixman_fixed_t *) pict->filter_params,
29603b705cfSriastradh				pict->filter_nparams);
29703b705cfSriastradh	pixman_image_set_source_clipping(image, TRUE);
29803b705cfSriastradh}
29903b705cfSriastradh
30003b705cfSriastradhstatic pixman_image_t *
30103b705cfSriastradhimage_from_pict_internal(PicturePtr pict, Bool has_clip, int *xoff, int *yoff,
30203b705cfSriastradh                         Bool is_alpha_map)
30303b705cfSriastradh{
30403b705cfSriastradh	pixman_image_t *image = NULL;
30503b705cfSriastradh
30603b705cfSriastradh	if (!pict)
30703b705cfSriastradh		return NULL;
30803b705cfSriastradh
30903b705cfSriastradh	if (pict->pDrawable) {
31003b705cfSriastradh		image = create_bits_picture(pict, has_clip, xoff, yoff);
31103b705cfSriastradh	}
31203b705cfSriastradh	else if (pict->pSourcePict) {
31303b705cfSriastradh		SourcePict *sp = pict->pSourcePict;
31403b705cfSriastradh
31503b705cfSriastradh		if (sp->type == SourcePictTypeSolidFill) {
31603b705cfSriastradh			image = create_solid_fill_image(pict);
31703b705cfSriastradh		}
31803b705cfSriastradh		else {
31903b705cfSriastradh			PictGradient *gradient = &pict->pSourcePict->gradient;
32003b705cfSriastradh
32103b705cfSriastradh			if (sp->type == SourcePictTypeLinear)
32203b705cfSriastradh				image = create_linear_gradient_image(gradient);
32303b705cfSriastradh			else if (sp->type == SourcePictTypeRadial)
32403b705cfSriastradh				image = create_radial_gradient_image(gradient);
32503b705cfSriastradh			else if (sp->type == SourcePictTypeConical)
32603b705cfSriastradh				image = create_conical_gradient_image(gradient);
32703b705cfSriastradh		}
32803b705cfSriastradh		*xoff = *yoff = 0;
32903b705cfSriastradh	}
33003b705cfSriastradh
33103b705cfSriastradh	if (image)
33203b705cfSriastradh		set_image_properties(image, pict, has_clip, xoff, yoff, is_alpha_map);
33303b705cfSriastradh
33403b705cfSriastradh	return image;
33503b705cfSriastradh}
33603b705cfSriastradh
33703b705cfSriastradhpixman_image_t *
33803b705cfSriastradhimage_from_pict(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
33903b705cfSriastradh{
34003b705cfSriastradh	return image_from_pict_internal(pict, has_clip, xoff, yoff, FALSE);
34103b705cfSriastradh}
34203b705cfSriastradh
34303b705cfSriastradhvoid
34403b705cfSriastradhfree_pixman_pict(PicturePtr pict, pixman_image_t * image)
34503b705cfSriastradh{
34603b705cfSriastradh	if (image)
34703b705cfSriastradh                pixman_image_unref(image);
34803b705cfSriastradh}
349