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