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(¢er, 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