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	&center, 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