1/* 2 * 3 * Copyright © 2000 SuSE, Inc. 4 * Copyright © 2007 Red Hat, Inc. 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#ifdef HAVE_DIX_CONFIG_H 27#include <dix-config.h> 28#endif 29 30#include <string.h> 31 32#include "fb.h" 33 34#include "picturestr.h" 35#include "mipict.h" 36#include "fbpict.h" 37 38void 39fbComposite (CARD8 op, 40 PicturePtr pSrc, 41 PicturePtr pMask, 42 PicturePtr pDst, 43 INT16 xSrc, 44 INT16 ySrc, 45 INT16 xMask, 46 INT16 yMask, 47 INT16 xDst, 48 INT16 yDst, 49 CARD16 width, 50 CARD16 height) 51{ 52 pixman_image_t *src, *mask, *dest; 53 int src_xoff, src_yoff; 54 int msk_xoff, msk_yoff; 55 int dst_xoff, dst_yoff; 56 57 miCompositeSourceValidate (pSrc, xSrc - xDst, ySrc - yDst, width, height); 58 if (pMask) 59 miCompositeSourceValidate (pMask, xMask - xDst, yMask - yDst, width, height); 60 61 src = image_from_pict (pSrc, FALSE, &src_xoff, &src_yoff); 62 mask = image_from_pict (pMask, FALSE, &msk_xoff, &msk_yoff); 63 dest = image_from_pict (pDst, TRUE, &dst_xoff, &dst_yoff); 64 65 if (src && dest && !(pMask && !mask)) 66 { 67 pixman_image_composite (op, src, mask, dest, 68 xSrc + src_xoff, ySrc + src_yoff, 69 xMask + msk_xoff, yMask + msk_yoff, 70 xDst + dst_xoff, yDst + dst_yoff, 71 width, height); 72 } 73 74 free_pixman_pict (pSrc, src); 75 free_pixman_pict (pMask, mask); 76 free_pixman_pict (pDst, dest); 77} 78 79static pixman_image_t * 80create_solid_fill_image (PicturePtr pict) 81{ 82 PictSolidFill *solid = &pict->pSourcePict->solidFill; 83 pixman_color_t color; 84 CARD32 a, r, g, b; 85 86 a = (solid->color & 0xff000000) >> 24; 87 r = (solid->color & 0x00ff0000) >> 16; 88 g = (solid->color & 0x0000ff00) >> 8; 89 b = (solid->color & 0x000000ff) >> 0; 90 91 color.alpha = (a << 8) | a; 92 color.red = (r << 8) | r; 93 color.green = (g << 8) | g; 94 color.blue = (b << 8) | b; 95 96 return pixman_image_create_solid_fill (&color); 97} 98 99static pixman_image_t * 100create_linear_gradient_image (PictGradient *gradient) 101{ 102 PictLinearGradient *linear = (PictLinearGradient *)gradient; 103 pixman_point_fixed_t p1; 104 pixman_point_fixed_t p2; 105 106 p1.x = linear->p1.x; 107 p1.y = linear->p1.y; 108 p2.x = linear->p2.x; 109 p2.y = linear->p2.y; 110 111 return pixman_image_create_linear_gradient ( 112 &p1, &p2, (pixman_gradient_stop_t *)gradient->stops, gradient->nstops); 113} 114 115static pixman_image_t * 116create_radial_gradient_image (PictGradient *gradient) 117{ 118 PictRadialGradient *radial = (PictRadialGradient *)gradient; 119 pixman_point_fixed_t c1; 120 pixman_point_fixed_t c2; 121 122 c1.x = radial->c1.x; 123 c1.y = radial->c1.y; 124 c2.x = radial->c2.x; 125 c2.y = radial->c2.y; 126 127 return pixman_image_create_radial_gradient ( 128 &c1, &c2, radial->c1.radius, 129 radial->c2.radius, 130 (pixman_gradient_stop_t *)gradient->stops, gradient->nstops); 131} 132 133static pixman_image_t * 134create_conical_gradient_image (PictGradient *gradient) 135{ 136 PictConicalGradient *conical = (PictConicalGradient *)gradient; 137 pixman_point_fixed_t center; 138 139 center.x = conical->center.x; 140 center.y = conical->center.y; 141 142 return pixman_image_create_conical_gradient ( 143 ¢er, conical->angle, (pixman_gradient_stop_t *)gradient->stops, 144 gradient->nstops); 145} 146 147static pixman_image_t * 148create_bits_picture (PicturePtr pict, 149 Bool has_clip, 150 int *xoff, 151 int *yoff) 152{ 153 PixmapPtr pixmap; 154 FbBits *bits; 155 FbStride stride; 156 int bpp; 157 pixman_image_t *image; 158 159 fbGetDrawablePixmap (pict->pDrawable, pixmap, *xoff, *yoff); 160 fbGetPixmapBitsData(pixmap, bits, stride, bpp); 161 162 image = pixman_image_create_bits ( 163 pict->format, 164 pixmap->drawable.width, pixmap->drawable.height, 165 (uint32_t *)bits, stride * sizeof (FbStride)); 166 167 if (!image) 168 return NULL; 169 170#ifdef FB_ACCESS_WRAPPER 171#if FB_SHIFT==5 172 173 pixman_image_set_accessors (image, 174 (pixman_read_memory_func_t)wfbReadMemory, 175 (pixman_write_memory_func_t)wfbWriteMemory); 176 177#else 178 179#error The pixman library only works when FbBits is 32 bits wide 180 181#endif 182#endif 183 184 /* pCompositeClip is undefined for source pictures, so 185 * only set the clip region for pictures with drawables 186 */ 187 if (has_clip) 188 { 189 if (pict->clientClipType != CT_NONE) 190 pixman_image_set_has_client_clip (image, TRUE); 191 192 if (*xoff || *yoff) 193 pixman_region_translate (pict->pCompositeClip, *xoff, *yoff); 194 195 pixman_image_set_clip_region (image, pict->pCompositeClip); 196 197 if (*xoff || *yoff) 198 pixman_region_translate (pict->pCompositeClip, -*xoff, -*yoff); 199 } 200 201 /* Indexed table */ 202 if (pict->pFormat->index.devPrivate) 203 pixman_image_set_indexed (image, pict->pFormat->index.devPrivate); 204 205 /* Add in drawable origin to position within the image */ 206 *xoff += pict->pDrawable->x; 207 *yoff += pict->pDrawable->y; 208 209 return image; 210} 211 212static pixman_image_t * 213image_from_pict_internal (PicturePtr pict, Bool has_clip, int *xoff, int *yoff, Bool is_alpha_map); 214 215static void 216set_image_properties (pixman_image_t *image, PicturePtr pict, Bool has_clip, int *xoff, int *yoff, Bool is_alpha_map) 217{ 218 pixman_repeat_t repeat; 219 pixman_filter_t filter; 220 221 if (pict->transform) 222 { 223 /* For source images, adjust the transform to account 224 * for the drawable offset within the pixman image, 225 * then set the offset to 0 as it will be used 226 * to compute positions within the transformed image. 227 */ 228 if (!has_clip) { 229 struct pixman_transform adjusted; 230 231 adjusted = *pict->transform; 232 pixman_transform_translate(&adjusted, 233 NULL, 234 pixman_int_to_fixed(*xoff), 235 pixman_int_to_fixed(*yoff)); 236 pixman_image_set_transform (image, &adjusted); 237 *xoff = 0; 238 *yoff = 0; 239 } else 240 pixman_image_set_transform (image, pict->transform); 241 } 242 243 switch (pict->repeatType) 244 { 245 default: 246 case RepeatNone: 247 repeat = PIXMAN_REPEAT_NONE; 248 break; 249 250 case RepeatPad: 251 repeat = PIXMAN_REPEAT_PAD; 252 break; 253 254 case RepeatNormal: 255 repeat = PIXMAN_REPEAT_NORMAL; 256 break; 257 258 case RepeatReflect: 259 repeat = PIXMAN_REPEAT_REFLECT; 260 break; 261 } 262 263 pixman_image_set_repeat (image, repeat); 264 265 /* Fetch alpha map unless 'pict' is being used 266 * as the alpha map for this operation 267 */ 268 if (pict->alphaMap && !is_alpha_map) 269 { 270 int alpha_xoff, alpha_yoff; 271 pixman_image_t *alpha_map = image_from_pict_internal (pict->alphaMap, FALSE, &alpha_xoff, &alpha_yoff, TRUE); 272 273 pixman_image_set_alpha_map ( 274 image, alpha_map, pict->alphaOrigin.x, pict->alphaOrigin.y); 275 276 free_pixman_pict (pict->alphaMap, alpha_map); 277 } 278 279 pixman_image_set_component_alpha (image, pict->componentAlpha); 280 281 switch (pict->filter) 282 { 283 default: 284 case PictFilterNearest: 285 case PictFilterFast: 286 filter = PIXMAN_FILTER_NEAREST; 287 break; 288 289 case PictFilterBilinear: 290 case PictFilterGood: 291 filter = PIXMAN_FILTER_BILINEAR; 292 break; 293 294 case PictFilterConvolution: 295 filter = PIXMAN_FILTER_CONVOLUTION; 296 break; 297 } 298 299 pixman_image_set_filter (image, filter, (pixman_fixed_t *)pict->filter_params, pict->filter_nparams); 300 pixman_image_set_source_clipping (image, TRUE); 301} 302 303static pixman_image_t * 304image_from_pict_internal (PicturePtr pict, Bool has_clip, int *xoff, int *yoff, Bool is_alpha_map) 305{ 306 pixman_image_t *image = NULL; 307 308 if (!pict) 309 return NULL; 310 311 if (pict->pDrawable) 312 { 313 image = create_bits_picture (pict, has_clip, xoff, yoff); 314 } 315 else if (pict->pSourcePict) 316 { 317 SourcePict *sp = pict->pSourcePict; 318 319 if (sp->type == SourcePictTypeSolidFill) 320 { 321 image = create_solid_fill_image (pict); 322 } 323 else 324 { 325 PictGradient *gradient = &pict->pSourcePict->gradient; 326 327 if (sp->type == SourcePictTypeLinear) 328 image = create_linear_gradient_image (gradient); 329 else if (sp->type == SourcePictTypeRadial) 330 image = create_radial_gradient_image (gradient); 331 else if (sp->type == SourcePictTypeConical) 332 image = create_conical_gradient_image (gradient); 333 } 334 *xoff = *yoff = 0; 335 } 336 337 if (image) 338 set_image_properties (image, pict, has_clip, xoff, yoff, is_alpha_map); 339 340 return image; 341} 342 343pixman_image_t * 344image_from_pict (PicturePtr pict, Bool has_clip, int *xoff, int *yoff) 345{ 346 return image_from_pict_internal (pict, has_clip, xoff, yoff, FALSE); 347} 348 349void 350free_pixman_pict (PicturePtr pict, pixman_image_t *image) 351{ 352 if (image && pixman_image_unref (image) && pict->pDrawable) 353 fbFinishAccess (pict->pDrawable); 354} 355 356Bool 357fbPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats) 358{ 359 360 PictureScreenPtr ps; 361 362 if (!miPictureInit (pScreen, formats, nformats)) 363 return FALSE; 364 ps = GetPictureScreen(pScreen); 365 ps->Composite = fbComposite; 366 ps->Glyphs = miGlyphs; 367 ps->CompositeRects = miCompositeRects; 368 ps->RasterizeTrapezoid = fbRasterizeTrapezoid; 369 ps->AddTraps = fbAddTraps; 370 ps->AddTriangles = fbAddTriangles; 371 372 return TRUE; 373} 374