1706f2543Smrg/*
2706f2543Smrg *
3706f2543Smrg * Copyright © 2000 SuSE, Inc.
4706f2543Smrg * Copyright © 2007 Red Hat, Inc.
5706f2543Smrg *
6706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
7706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
8706f2543Smrg * the above copyright notice appear in all copies and that both that
9706f2543Smrg * copyright notice and this permission notice appear in supporting
10706f2543Smrg * documentation, and that the name of SuSE not be used in advertising or
11706f2543Smrg * publicity pertaining to distribution of the software without specific,
12706f2543Smrg * written prior permission.  SuSE makes no representations about the
13706f2543Smrg * suitability of this software for any purpose.  It is provided "as is"
14706f2543Smrg * without express or implied warranty.
15706f2543Smrg *
16706f2543Smrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17706f2543Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
18706f2543Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19706f2543Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20706f2543Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21706f2543Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22706f2543Smrg *
23706f2543Smrg * Author:  Keith Packard, SuSE, Inc.
24706f2543Smrg */
25706f2543Smrg
26706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
27706f2543Smrg#include <dix-config.h>
28706f2543Smrg#endif
29706f2543Smrg
30706f2543Smrg#include <string.h>
31706f2543Smrg
32706f2543Smrg#include "fb.h"
33706f2543Smrg
34706f2543Smrg#include "picturestr.h"
35706f2543Smrg#include "mipict.h"
36706f2543Smrg#include "fbpict.h"
37706f2543Smrg
38706f2543Smrgvoid
39706f2543SmrgfbComposite (CARD8      op,
40706f2543Smrg	     PicturePtr pSrc,
41706f2543Smrg	     PicturePtr pMask,
42706f2543Smrg	     PicturePtr pDst,
43706f2543Smrg	     INT16      xSrc,
44706f2543Smrg	     INT16      ySrc,
45706f2543Smrg	     INT16      xMask,
46706f2543Smrg	     INT16      yMask,
47706f2543Smrg	     INT16      xDst,
48706f2543Smrg	     INT16      yDst,
49706f2543Smrg	     CARD16     width,
50706f2543Smrg	     CARD16     height)
51706f2543Smrg{
52706f2543Smrg    pixman_image_t *src, *mask, *dest;
53706f2543Smrg    int src_xoff, src_yoff;
54706f2543Smrg    int msk_xoff, msk_yoff;
55706f2543Smrg    int dst_xoff, dst_yoff;
56706f2543Smrg
57706f2543Smrg    miCompositeSourceValidate (pSrc, xSrc - xDst, ySrc - yDst, width, height);
58706f2543Smrg    if (pMask)
59706f2543Smrg	miCompositeSourceValidate (pMask, xMask - xDst, yMask - yDst, width, height);
60706f2543Smrg
61706f2543Smrg    src = image_from_pict (pSrc, FALSE, &src_xoff, &src_yoff);
62706f2543Smrg    mask = image_from_pict (pMask, FALSE, &msk_xoff, &msk_yoff);
63706f2543Smrg    dest = image_from_pict (pDst, TRUE, &dst_xoff, &dst_yoff);
64706f2543Smrg
65706f2543Smrg    if (src && dest && !(pMask && !mask))
66706f2543Smrg    {
67706f2543Smrg	pixman_image_composite (op, src, mask, dest,
68706f2543Smrg				xSrc + src_xoff, ySrc + src_yoff,
69706f2543Smrg				xMask + msk_xoff, yMask + msk_yoff,
70706f2543Smrg				xDst + dst_xoff, yDst + dst_yoff,
71706f2543Smrg				width, height);
72706f2543Smrg    }
73706f2543Smrg
74706f2543Smrg    free_pixman_pict (pSrc, src);
75706f2543Smrg    free_pixman_pict (pMask, mask);
76706f2543Smrg    free_pixman_pict (pDst, dest);
77706f2543Smrg}
78706f2543Smrg
79706f2543Smrgstatic pixman_image_t *
80706f2543Smrgcreate_solid_fill_image (PicturePtr pict)
81706f2543Smrg{
82706f2543Smrg    PictSolidFill *solid = &pict->pSourcePict->solidFill;
83706f2543Smrg    pixman_color_t color;
84706f2543Smrg    CARD32 a, r, g, b;
85706f2543Smrg
86706f2543Smrg    a = (solid->color & 0xff000000) >> 24;
87706f2543Smrg    r = (solid->color & 0x00ff0000) >> 16;
88706f2543Smrg    g = (solid->color & 0x0000ff00) >>  8;
89706f2543Smrg    b = (solid->color & 0x000000ff) >>  0;
90706f2543Smrg
91706f2543Smrg    color.alpha = (a << 8) | a;
92706f2543Smrg    color.red =   (r << 8) | r;
93706f2543Smrg    color.green = (g << 8) | g;
94706f2543Smrg    color.blue =  (b << 8) | b;
95706f2543Smrg
96706f2543Smrg    return pixman_image_create_solid_fill (&color);
97706f2543Smrg}
98706f2543Smrg
99706f2543Smrgstatic pixman_image_t *
100706f2543Smrgcreate_linear_gradient_image (PictGradient *gradient)
101706f2543Smrg{
102706f2543Smrg    PictLinearGradient *linear = (PictLinearGradient *)gradient;
103706f2543Smrg    pixman_point_fixed_t p1;
104706f2543Smrg    pixman_point_fixed_t p2;
105706f2543Smrg
106706f2543Smrg    p1.x = linear->p1.x;
107706f2543Smrg    p1.y = linear->p1.y;
108706f2543Smrg    p2.x = linear->p2.x;
109706f2543Smrg    p2.y = linear->p2.y;
110706f2543Smrg
111706f2543Smrg    return pixman_image_create_linear_gradient (
112706f2543Smrg	&p1, &p2, (pixman_gradient_stop_t *)gradient->stops, gradient->nstops);
113706f2543Smrg}
114706f2543Smrg
115706f2543Smrgstatic pixman_image_t *
116706f2543Smrgcreate_radial_gradient_image (PictGradient *gradient)
117706f2543Smrg{
118706f2543Smrg    PictRadialGradient *radial = (PictRadialGradient *)gradient;
119706f2543Smrg    pixman_point_fixed_t c1;
120706f2543Smrg    pixman_point_fixed_t c2;
121706f2543Smrg
122706f2543Smrg    c1.x = radial->c1.x;
123706f2543Smrg    c1.y = radial->c1.y;
124706f2543Smrg    c2.x = radial->c2.x;
125706f2543Smrg    c2.y = radial->c2.y;
126706f2543Smrg
127706f2543Smrg    return pixman_image_create_radial_gradient (
128706f2543Smrg	&c1, &c2, radial->c1.radius,
129706f2543Smrg	radial->c2.radius,
130706f2543Smrg	(pixman_gradient_stop_t *)gradient->stops, gradient->nstops);
131706f2543Smrg}
132706f2543Smrg
133706f2543Smrgstatic pixman_image_t *
134706f2543Smrgcreate_conical_gradient_image (PictGradient *gradient)
135706f2543Smrg{
136706f2543Smrg    PictConicalGradient *conical = (PictConicalGradient *)gradient;
137706f2543Smrg    pixman_point_fixed_t center;
138706f2543Smrg
139706f2543Smrg    center.x = conical->center.x;
140706f2543Smrg    center.y = conical->center.y;
141706f2543Smrg
142706f2543Smrg    return pixman_image_create_conical_gradient (
143706f2543Smrg	&center, conical->angle, (pixman_gradient_stop_t *)gradient->stops,
144706f2543Smrg	gradient->nstops);
145706f2543Smrg}
146706f2543Smrg
147706f2543Smrgstatic pixman_image_t *
148706f2543Smrgcreate_bits_picture (PicturePtr pict,
149706f2543Smrg		     Bool       has_clip,
150706f2543Smrg		     int	*xoff,
151706f2543Smrg		     int	*yoff)
152706f2543Smrg{
153706f2543Smrg    PixmapPtr pixmap;
154706f2543Smrg    FbBits *bits;
155706f2543Smrg    FbStride stride;
156706f2543Smrg    int bpp;
157706f2543Smrg    pixman_image_t *image;
158706f2543Smrg
159706f2543Smrg    fbGetDrawablePixmap (pict->pDrawable, pixmap, *xoff, *yoff);
160706f2543Smrg    fbGetPixmapBitsData(pixmap, bits, stride, bpp);
161706f2543Smrg
162706f2543Smrg    image = pixman_image_create_bits (
163706f2543Smrg	pict->format,
164706f2543Smrg	pixmap->drawable.width, pixmap->drawable.height,
165706f2543Smrg	(uint32_t *)bits, stride * sizeof (FbStride));
166706f2543Smrg
167706f2543Smrg    if (!image)
168706f2543Smrg	return NULL;
169706f2543Smrg
170706f2543Smrg#ifdef FB_ACCESS_WRAPPER
171706f2543Smrg#if FB_SHIFT==5
172706f2543Smrg
173706f2543Smrg    pixman_image_set_accessors (image,
174706f2543Smrg				(pixman_read_memory_func_t)wfbReadMemory,
175706f2543Smrg				(pixman_write_memory_func_t)wfbWriteMemory);
176706f2543Smrg
177706f2543Smrg#else
178706f2543Smrg
179706f2543Smrg#error The pixman library only works when FbBits is 32 bits wide
180706f2543Smrg
181706f2543Smrg#endif
182706f2543Smrg#endif
183706f2543Smrg
184706f2543Smrg    /* pCompositeClip is undefined for source pictures, so
185706f2543Smrg     * only set the clip region for pictures with drawables
186706f2543Smrg     */
187706f2543Smrg    if (has_clip)
188706f2543Smrg    {
189706f2543Smrg	if (pict->clientClipType != CT_NONE)
190706f2543Smrg	    pixman_image_set_has_client_clip (image, TRUE);
191706f2543Smrg
192706f2543Smrg	if (*xoff || *yoff)
193706f2543Smrg	    pixman_region_translate (pict->pCompositeClip, *xoff, *yoff);
194706f2543Smrg
195706f2543Smrg	pixman_image_set_clip_region (image, pict->pCompositeClip);
196706f2543Smrg
197706f2543Smrg	if (*xoff || *yoff)
198706f2543Smrg	    pixman_region_translate (pict->pCompositeClip, -*xoff, -*yoff);
199706f2543Smrg    }
200706f2543Smrg
201706f2543Smrg    /* Indexed table */
202706f2543Smrg    if (pict->pFormat->index.devPrivate)
203706f2543Smrg	pixman_image_set_indexed (image, pict->pFormat->index.devPrivate);
204706f2543Smrg
205706f2543Smrg    /* Add in drawable origin to position within the image */
206706f2543Smrg    *xoff += pict->pDrawable->x;
207706f2543Smrg    *yoff += pict->pDrawable->y;
208706f2543Smrg
209706f2543Smrg    return image;
210706f2543Smrg}
211706f2543Smrg
212706f2543Smrgstatic pixman_image_t *
213706f2543Smrgimage_from_pict_internal (PicturePtr pict, Bool has_clip, int *xoff, int *yoff, Bool is_alpha_map);
214706f2543Smrg
215706f2543Smrgstatic void
216706f2543Smrgset_image_properties (pixman_image_t *image, PicturePtr pict, Bool has_clip, int *xoff, int *yoff, Bool is_alpha_map)
217706f2543Smrg{
218706f2543Smrg    pixman_repeat_t repeat;
219706f2543Smrg    pixman_filter_t filter;
220706f2543Smrg
221706f2543Smrg    if (pict->transform)
222706f2543Smrg    {
223706f2543Smrg	/* For source images, adjust the transform to account
224706f2543Smrg	 * for the drawable offset within the pixman image,
225706f2543Smrg	 * then set the offset to 0 as it will be used
226706f2543Smrg	 * to compute positions within the transformed image.
227706f2543Smrg	 */
228706f2543Smrg	if (!has_clip) {
229706f2543Smrg	    struct pixman_transform	adjusted;
230706f2543Smrg
231706f2543Smrg	    adjusted = *pict->transform;
232706f2543Smrg	    pixman_transform_translate(&adjusted,
233706f2543Smrg				       NULL,
234706f2543Smrg				       pixman_int_to_fixed(*xoff),
235706f2543Smrg				       pixman_int_to_fixed(*yoff));
236706f2543Smrg	    pixman_image_set_transform (image, &adjusted);
237706f2543Smrg	    *xoff = 0;
238706f2543Smrg	    *yoff = 0;
239706f2543Smrg	} else
240706f2543Smrg	    pixman_image_set_transform (image, pict->transform);
241706f2543Smrg    }
242706f2543Smrg
243706f2543Smrg    switch (pict->repeatType)
244706f2543Smrg    {
245706f2543Smrg    default:
246706f2543Smrg    case RepeatNone:
247706f2543Smrg	repeat = PIXMAN_REPEAT_NONE;
248706f2543Smrg	break;
249706f2543Smrg
250706f2543Smrg    case RepeatPad:
251706f2543Smrg	repeat = PIXMAN_REPEAT_PAD;
252706f2543Smrg	break;
253706f2543Smrg
254706f2543Smrg    case RepeatNormal:
255706f2543Smrg	repeat = PIXMAN_REPEAT_NORMAL;
256706f2543Smrg	break;
257706f2543Smrg
258706f2543Smrg    case RepeatReflect:
259706f2543Smrg	repeat = PIXMAN_REPEAT_REFLECT;
260706f2543Smrg	break;
261706f2543Smrg    }
262706f2543Smrg
263706f2543Smrg    pixman_image_set_repeat (image, repeat);
264706f2543Smrg
265706f2543Smrg    /* Fetch alpha map unless 'pict' is being used
266706f2543Smrg     * as the alpha map for this operation
267706f2543Smrg     */
268706f2543Smrg    if (pict->alphaMap && !is_alpha_map)
269706f2543Smrg    {
270706f2543Smrg	int alpha_xoff, alpha_yoff;
271706f2543Smrg	pixman_image_t *alpha_map = image_from_pict_internal (pict->alphaMap, FALSE, &alpha_xoff, &alpha_yoff, TRUE);
272706f2543Smrg
273706f2543Smrg	pixman_image_set_alpha_map (
274706f2543Smrg	    image, alpha_map, pict->alphaOrigin.x, pict->alphaOrigin.y);
275706f2543Smrg
276706f2543Smrg	free_pixman_pict (pict->alphaMap, alpha_map);
277706f2543Smrg    }
278706f2543Smrg
279706f2543Smrg    pixman_image_set_component_alpha (image, pict->componentAlpha);
280706f2543Smrg
281706f2543Smrg    switch (pict->filter)
282706f2543Smrg    {
283706f2543Smrg    default:
284706f2543Smrg    case PictFilterNearest:
285706f2543Smrg    case PictFilterFast:
286706f2543Smrg	filter = PIXMAN_FILTER_NEAREST;
287706f2543Smrg	break;
288706f2543Smrg
289706f2543Smrg    case PictFilterBilinear:
290706f2543Smrg    case PictFilterGood:
291706f2543Smrg	filter = PIXMAN_FILTER_BILINEAR;
292706f2543Smrg	break;
293706f2543Smrg
294706f2543Smrg    case PictFilterConvolution:
295706f2543Smrg	filter = PIXMAN_FILTER_CONVOLUTION;
296706f2543Smrg	break;
297706f2543Smrg    }
298706f2543Smrg
299706f2543Smrg    pixman_image_set_filter (image, filter, (pixman_fixed_t *)pict->filter_params, pict->filter_nparams);
300706f2543Smrg    pixman_image_set_source_clipping (image, TRUE);
301706f2543Smrg}
302706f2543Smrg
303706f2543Smrgstatic pixman_image_t *
304706f2543Smrgimage_from_pict_internal (PicturePtr pict, Bool has_clip, int *xoff, int *yoff, Bool is_alpha_map)
305706f2543Smrg{
306706f2543Smrg    pixman_image_t *image = NULL;
307706f2543Smrg
308706f2543Smrg    if (!pict)
309706f2543Smrg	return NULL;
310706f2543Smrg
311706f2543Smrg    if (pict->pDrawable)
312706f2543Smrg    {
313706f2543Smrg	image = create_bits_picture (pict, has_clip, xoff, yoff);
314706f2543Smrg    }
315706f2543Smrg    else if (pict->pSourcePict)
316706f2543Smrg    {
317706f2543Smrg	SourcePict *sp = pict->pSourcePict;
318706f2543Smrg
319706f2543Smrg	if (sp->type == SourcePictTypeSolidFill)
320706f2543Smrg	{
321706f2543Smrg	    image = create_solid_fill_image (pict);
322706f2543Smrg	}
323706f2543Smrg	else
324706f2543Smrg	{
325706f2543Smrg	    PictGradient *gradient = &pict->pSourcePict->gradient;
326706f2543Smrg
327706f2543Smrg	    if (sp->type == SourcePictTypeLinear)
328706f2543Smrg		image = create_linear_gradient_image (gradient);
329706f2543Smrg	    else if (sp->type == SourcePictTypeRadial)
330706f2543Smrg		image = create_radial_gradient_image (gradient);
331706f2543Smrg	    else if (sp->type == SourcePictTypeConical)
332706f2543Smrg		image = create_conical_gradient_image (gradient);
333706f2543Smrg	}
334706f2543Smrg	*xoff = *yoff = 0;
335706f2543Smrg    }
336706f2543Smrg
337706f2543Smrg    if (image)
338706f2543Smrg	set_image_properties (image, pict, has_clip, xoff, yoff, is_alpha_map);
339706f2543Smrg
340706f2543Smrg    return image;
341706f2543Smrg}
342706f2543Smrg
343706f2543Smrgpixman_image_t *
344706f2543Smrgimage_from_pict (PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
345706f2543Smrg{
346706f2543Smrg    return image_from_pict_internal (pict, has_clip, xoff, yoff, FALSE);
347706f2543Smrg}
348706f2543Smrg
349706f2543Smrgvoid
350706f2543Smrgfree_pixman_pict (PicturePtr pict, pixman_image_t *image)
351706f2543Smrg{
352706f2543Smrg    if (image && pixman_image_unref (image) && pict->pDrawable)
353706f2543Smrg	fbFinishAccess (pict->pDrawable);
354706f2543Smrg}
355706f2543Smrg
356706f2543SmrgBool
357706f2543SmrgfbPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats)
358706f2543Smrg{
359706f2543Smrg
360706f2543Smrg    PictureScreenPtr    ps;
361706f2543Smrg
362706f2543Smrg    if (!miPictureInit (pScreen, formats, nformats))
363706f2543Smrg	return FALSE;
364706f2543Smrg    ps = GetPictureScreen(pScreen);
365706f2543Smrg    ps->Composite = fbComposite;
366706f2543Smrg    ps->Glyphs = miGlyphs;
367706f2543Smrg    ps->CompositeRects = miCompositeRects;
368706f2543Smrg    ps->RasterizeTrapezoid = fbRasterizeTrapezoid;
369706f2543Smrg    ps->AddTraps = fbAddTraps;
370706f2543Smrg    ps->AddTriangles = fbAddTriangles;
371706f2543Smrg
372706f2543Smrg    return TRUE;
373706f2543Smrg}
374