xref: /OK3568_Linux_fs/external/xserver/fb/fbpict.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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(&center, 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