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