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
38 void
fbComposite(CARD8 op,PicturePtr pSrc,PicturePtr pMask,PicturePtr pDst,INT16 xSrc,INT16 ySrc,INT16 xMask,INT16 yMask,INT16 xDst,INT16 yDst,CARD16 width,CARD16 height)39 fbComposite(CARD8 op,
40 PicturePtr pSrc,
41 PicturePtr pMask,
42 PicturePtr pDst,
43 INT16 xSrc,
44 INT16 ySrc,
45 INT16 xMask,
46 INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
47 {
48 pixman_image_t *src, *mask, *dest;
49 int src_xoff, src_yoff;
50 int msk_xoff, msk_yoff;
51 int dst_xoff, dst_yoff;
52
53 miCompositeSourceValidate(pSrc);
54 if (pMask)
55 miCompositeSourceValidate(pMask);
56
57 src = image_from_pict(pSrc, FALSE, &src_xoff, &src_yoff);
58 mask = image_from_pict(pMask, FALSE, &msk_xoff, &msk_yoff);
59 dest = image_from_pict(pDst, TRUE, &dst_xoff, &dst_yoff);
60
61 if (src && dest && !(pMask && !mask)) {
62 pixman_image_composite(op, src, mask, dest,
63 xSrc + src_xoff, ySrc + src_yoff,
64 xMask + msk_xoff, yMask + msk_yoff,
65 xDst + dst_xoff, yDst + dst_yoff, width, height);
66 }
67
68 free_pixman_pict(pSrc, src);
69 free_pixman_pict(pMask, mask);
70 free_pixman_pict(pDst, dest);
71 }
72
73 static pixman_glyph_cache_t *glyphCache;
74
75 void
fbDestroyGlyphCache(void)76 fbDestroyGlyphCache(void)
77 {
78 if (glyphCache)
79 {
80 pixman_glyph_cache_destroy (glyphCache);
81 glyphCache = NULL;
82 }
83 }
84
85 static void
fbUnrealizeGlyph(ScreenPtr pScreen,GlyphPtr pGlyph)86 fbUnrealizeGlyph(ScreenPtr pScreen,
87 GlyphPtr pGlyph)
88 {
89 if (glyphCache)
90 pixman_glyph_cache_remove (glyphCache, pGlyph, NULL);
91 }
92
93 void
fbGlyphs(CARD8 op,PicturePtr pSrc,PicturePtr pDst,PictFormatPtr maskFormat,INT16 xSrc,INT16 ySrc,int nlist,GlyphListPtr list,GlyphPtr * glyphs)94 fbGlyphs(CARD8 op,
95 PicturePtr pSrc,
96 PicturePtr pDst,
97 PictFormatPtr maskFormat,
98 INT16 xSrc,
99 INT16 ySrc, int nlist,
100 GlyphListPtr list,
101 GlyphPtr *glyphs)
102 {
103 #define N_STACK_GLYPHS 512
104 ScreenPtr pScreen = pDst->pDrawable->pScreen;
105 pixman_glyph_t stack_glyphs[N_STACK_GLYPHS];
106 pixman_glyph_t *pglyphs = stack_glyphs;
107 pixman_image_t *srcImage, *dstImage;
108 int srcXoff, srcYoff, dstXoff, dstYoff;
109 GlyphPtr glyph;
110 int n_glyphs;
111 int x, y;
112 int i, n;
113 int xDst = list->xOff, yDst = list->yOff;
114
115 miCompositeSourceValidate(pSrc);
116
117 n_glyphs = 0;
118 for (i = 0; i < nlist; ++i)
119 n_glyphs += list[i].len;
120
121 if (!glyphCache)
122 glyphCache = pixman_glyph_cache_create();
123
124 pixman_glyph_cache_freeze (glyphCache);
125
126 if (n_glyphs > N_STACK_GLYPHS) {
127 if (!(pglyphs = xallocarray(n_glyphs, sizeof(pixman_glyph_t))))
128 goto out;
129 }
130
131 i = 0;
132 x = y = 0;
133 while (nlist--) {
134 x += list->xOff;
135 y += list->yOff;
136 n = list->len;
137 while (n--) {
138 const void *g;
139
140 glyph = *glyphs++;
141
142 if (!(g = pixman_glyph_cache_lookup (glyphCache, glyph, NULL))) {
143 pixman_image_t *glyphImage;
144 PicturePtr pPicture;
145 int xoff, yoff;
146
147 pPicture = GetGlyphPicture(glyph, pScreen);
148 if (!pPicture) {
149 n_glyphs--;
150 goto next;
151 }
152
153 if (!(glyphImage = image_from_pict(pPicture, FALSE, &xoff, &yoff)))
154 goto out;
155
156 g = pixman_glyph_cache_insert(glyphCache, glyph, NULL,
157 glyph->info.x,
158 glyph->info.y,
159 glyphImage);
160
161 free_pixman_pict(pPicture, glyphImage);
162
163 if (!g)
164 goto out;
165 }
166
167 pglyphs[i].x = x;
168 pglyphs[i].y = y;
169 pglyphs[i].glyph = g;
170 i++;
171
172 next:
173 x += glyph->info.xOff;
174 y += glyph->info.yOff;
175 }
176 list++;
177 }
178
179 if (!(srcImage = image_from_pict(pSrc, FALSE, &srcXoff, &srcYoff)))
180 goto out;
181
182 if (!(dstImage = image_from_pict(pDst, TRUE, &dstXoff, &dstYoff)))
183 goto out_free_src;
184
185 if (maskFormat) {
186 pixman_format_code_t format;
187 pixman_box32_t extents;
188
189 format = maskFormat->format | (maskFormat->depth << 24);
190
191 pixman_glyph_get_extents(glyphCache, n_glyphs, pglyphs, &extents);
192
193 pixman_composite_glyphs(op, srcImage, dstImage, format,
194 xSrc + srcXoff + extents.x1 - xDst, ySrc + srcYoff + extents.y1 - yDst,
195 extents.x1, extents.y1,
196 extents.x1 + dstXoff, extents.y1 + dstYoff,
197 extents.x2 - extents.x1,
198 extents.y2 - extents.y1,
199 glyphCache, n_glyphs, pglyphs);
200 }
201 else {
202 pixman_composite_glyphs_no_mask(op, srcImage, dstImage,
203 xSrc + srcXoff - xDst, ySrc + srcYoff - yDst,
204 dstXoff, dstYoff,
205 glyphCache, n_glyphs, pglyphs);
206 }
207
208 free_pixman_pict(pDst, dstImage);
209
210 out_free_src:
211 free_pixman_pict(pSrc, srcImage);
212
213 out:
214 pixman_glyph_cache_thaw(glyphCache);
215 if (pglyphs != stack_glyphs)
216 free(pglyphs);
217 }
218
219 static pixman_image_t *
create_solid_fill_image(PicturePtr pict)220 create_solid_fill_image(PicturePtr pict)
221 {
222 PictSolidFill *solid = &pict->pSourcePict->solidFill;
223 /* pixman_color_t and xRenderColor have the same layout */
224 pixman_color_t *color = (pixman_color_t *)&solid->fullcolor;
225
226 return pixman_image_create_solid_fill(color);
227 }
228
229 static pixman_image_t *
create_linear_gradient_image(PictGradient * gradient)230 create_linear_gradient_image(PictGradient * gradient)
231 {
232 PictLinearGradient *linear = (PictLinearGradient *) gradient;
233 pixman_point_fixed_t p1;
234 pixman_point_fixed_t p2;
235
236 p1.x = linear->p1.x;
237 p1.y = linear->p1.y;
238 p2.x = linear->p2.x;
239 p2.y = linear->p2.y;
240
241 return pixman_image_create_linear_gradient(&p1, &p2,
242 (pixman_gradient_stop_t *)
243 gradient->stops,
244 gradient->nstops);
245 }
246
247 static pixman_image_t *
create_radial_gradient_image(PictGradient * gradient)248 create_radial_gradient_image(PictGradient * gradient)
249 {
250 PictRadialGradient *radial = (PictRadialGradient *) gradient;
251 pixman_point_fixed_t c1;
252 pixman_point_fixed_t c2;
253
254 c1.x = radial->c1.x;
255 c1.y = radial->c1.y;
256 c2.x = radial->c2.x;
257 c2.y = radial->c2.y;
258
259 return pixman_image_create_radial_gradient(&c1, &c2, radial->c1.radius,
260 radial->c2.radius,
261 (pixman_gradient_stop_t *)
262 gradient->stops,
263 gradient->nstops);
264 }
265
266 static pixman_image_t *
create_conical_gradient_image(PictGradient * gradient)267 create_conical_gradient_image(PictGradient * gradient)
268 {
269 PictConicalGradient *conical = (PictConicalGradient *) gradient;
270 pixman_point_fixed_t center;
271
272 center.x = conical->center.x;
273 center.y = conical->center.y;
274
275 return pixman_image_create_conical_gradient(¢er, conical->angle,
276 (pixman_gradient_stop_t *)
277 gradient->stops,
278 gradient->nstops);
279 }
280
281 static pixman_image_t *
create_bits_picture(PicturePtr pict,Bool has_clip,int * xoff,int * yoff)282 create_bits_picture(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
283 {
284 PixmapPtr pixmap;
285 FbBits *bits;
286 FbStride stride;
287 int bpp;
288 pixman_image_t *image;
289
290 fbGetDrawablePixmap(pict->pDrawable, pixmap, *xoff, *yoff);
291 fbGetPixmapBitsData(pixmap, bits, stride, bpp);
292
293 image = pixman_image_create_bits((pixman_format_code_t) pict->format,
294 pixmap->drawable.width,
295 pixmap->drawable.height, (uint32_t *) bits,
296 stride * sizeof(FbStride));
297
298 if (!image)
299 return NULL;
300
301 #ifdef FB_ACCESS_WRAPPER
302 pixman_image_set_accessors(image,
303 (pixman_read_memory_func_t) wfbReadMemory,
304 (pixman_write_memory_func_t) wfbWriteMemory);
305 #endif
306
307 /* pCompositeClip is undefined for source pictures, so
308 * only set the clip region for pictures with drawables
309 */
310 if (has_clip) {
311 if (pict->clientClip)
312 pixman_image_set_has_client_clip(image, TRUE);
313
314 if (*xoff || *yoff)
315 pixman_region_translate(pict->pCompositeClip, *xoff, *yoff);
316
317 pixman_image_set_clip_region(image, pict->pCompositeClip);
318
319 if (*xoff || *yoff)
320 pixman_region_translate(pict->pCompositeClip, -*xoff, -*yoff);
321 }
322
323 /* Indexed table */
324 if (pict->pFormat->index.devPrivate)
325 pixman_image_set_indexed(image, pict->pFormat->index.devPrivate);
326
327 /* Add in drawable origin to position within the image */
328 *xoff += pict->pDrawable->x;
329 *yoff += pict->pDrawable->y;
330
331 return image;
332 }
333
334 static pixman_image_t *image_from_pict_internal(PicturePtr pict, Bool has_clip,
335 int *xoff, int *yoff,
336 Bool is_alpha_map);
337
image_destroy(pixman_image_t * image,void * data)338 static void image_destroy(pixman_image_t *image, void *data)
339 {
340 fbFinishAccess((DrawablePtr)data);
341 }
342
343 static void
set_image_properties(pixman_image_t * image,PicturePtr pict,Bool has_clip,int * xoff,int * yoff,Bool is_alpha_map)344 set_image_properties(pixman_image_t * image, PicturePtr pict, Bool has_clip,
345 int *xoff, int *yoff, Bool is_alpha_map)
346 {
347 pixman_repeat_t repeat;
348 pixman_filter_t filter;
349
350 if (pict->transform) {
351 /* For source images, adjust the transform to account
352 * for the drawable offset within the pixman image,
353 * then set the offset to 0 as it will be used
354 * to compute positions within the transformed image.
355 */
356 if (!has_clip) {
357 struct pixman_transform adjusted;
358
359 adjusted = *pict->transform;
360 pixman_transform_translate(&adjusted,
361 NULL,
362 pixman_int_to_fixed(*xoff),
363 pixman_int_to_fixed(*yoff));
364 pixman_image_set_transform(image, &adjusted);
365 *xoff = 0;
366 *yoff = 0;
367 }
368 else
369 pixman_image_set_transform(image, pict->transform);
370 }
371
372 switch (pict->repeatType) {
373 default:
374 case RepeatNone:
375 repeat = PIXMAN_REPEAT_NONE;
376 break;
377
378 case RepeatPad:
379 repeat = PIXMAN_REPEAT_PAD;
380 break;
381
382 case RepeatNormal:
383 repeat = PIXMAN_REPEAT_NORMAL;
384 break;
385
386 case RepeatReflect:
387 repeat = PIXMAN_REPEAT_REFLECT;
388 break;
389 }
390
391 pixman_image_set_repeat(image, repeat);
392
393 /* Fetch alpha map unless 'pict' is being used
394 * as the alpha map for this operation
395 */
396 if (pict->alphaMap && !is_alpha_map) {
397 int alpha_xoff, alpha_yoff;
398 pixman_image_t *alpha_map =
399 image_from_pict_internal(pict->alphaMap, FALSE, &alpha_xoff,
400 &alpha_yoff, TRUE);
401
402 pixman_image_set_alpha_map(image, alpha_map, pict->alphaOrigin.x,
403 pict->alphaOrigin.y);
404
405 free_pixman_pict(pict->alphaMap, alpha_map);
406 }
407
408 pixman_image_set_component_alpha(image, pict->componentAlpha);
409
410 switch (pict->filter) {
411 default:
412 case PictFilterNearest:
413 case PictFilterFast:
414 filter = PIXMAN_FILTER_NEAREST;
415 break;
416
417 case PictFilterBilinear:
418 case PictFilterGood:
419 filter = PIXMAN_FILTER_BILINEAR;
420 break;
421
422 case PictFilterConvolution:
423 filter = PIXMAN_FILTER_CONVOLUTION;
424 break;
425 }
426
427 if (pict->pDrawable)
428 pixman_image_set_destroy_function(image, &image_destroy,
429 pict->pDrawable);
430
431 pixman_image_set_filter(image, filter,
432 (pixman_fixed_t *) pict->filter_params,
433 pict->filter_nparams);
434 pixman_image_set_source_clipping(image, TRUE);
435 }
436
437 static pixman_image_t *
image_from_pict_internal(PicturePtr pict,Bool has_clip,int * xoff,int * yoff,Bool is_alpha_map)438 image_from_pict_internal(PicturePtr pict, Bool has_clip, int *xoff, int *yoff,
439 Bool is_alpha_map)
440 {
441 pixman_image_t *image = NULL;
442
443 if (!pict)
444 return NULL;
445
446 if (pict->pDrawable) {
447 image = create_bits_picture(pict, has_clip, xoff, yoff);
448 }
449 else if (pict->pSourcePict) {
450 SourcePict *sp = pict->pSourcePict;
451
452 if (sp->type == SourcePictTypeSolidFill) {
453 image = create_solid_fill_image(pict);
454 }
455 else {
456 PictGradient *gradient = &pict->pSourcePict->gradient;
457
458 if (sp->type == SourcePictTypeLinear)
459 image = create_linear_gradient_image(gradient);
460 else if (sp->type == SourcePictTypeRadial)
461 image = create_radial_gradient_image(gradient);
462 else if (sp->type == SourcePictTypeConical)
463 image = create_conical_gradient_image(gradient);
464 }
465 *xoff = *yoff = 0;
466 }
467
468 if (image)
469 set_image_properties(image, pict, has_clip, xoff, yoff, is_alpha_map);
470
471 return image;
472 }
473
474 pixman_image_t *
image_from_pict(PicturePtr pict,Bool has_clip,int * xoff,int * yoff)475 image_from_pict(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
476 {
477 return image_from_pict_internal(pict, has_clip, xoff, yoff, FALSE);
478 }
479
480 void
free_pixman_pict(PicturePtr pict,pixman_image_t * image)481 free_pixman_pict(PicturePtr pict, pixman_image_t * image)
482 {
483 if (image)
484 pixman_image_unref(image);
485 }
486
487 Bool
fbPictureInit(ScreenPtr pScreen,PictFormatPtr formats,int nformats)488 fbPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats)
489 {
490
491 PictureScreenPtr ps;
492
493 if (!miPictureInit(pScreen, formats, nformats))
494 return FALSE;
495 ps = GetPictureScreen(pScreen);
496 ps->Composite = fbComposite;
497 ps->Glyphs = fbGlyphs;
498 ps->UnrealizeGlyph = fbUnrealizeGlyph;
499 ps->CompositeRects = miCompositeRects;
500 ps->RasterizeTrapezoid = fbRasterizeTrapezoid;
501 ps->Trapezoids = fbTrapezoids;
502 ps->AddTraps = fbAddTraps;
503 ps->AddTriangles = fbAddTriangles;
504 ps->Triangles = fbTriangles;
505
506 return TRUE;
507 }
508