1706f2543Smrg/*
2706f2543Smrg * Copyright © 2007 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
6706f2543Smrg * the above copyright notice appear in all copies and that both that copyright
7706f2543Smrg * notice and this permission notice appear in supporting documentation, and
8706f2543Smrg * that the name of the copyright holders not be used in advertising or
9706f2543Smrg * publicity pertaining to distribution of the software without specific,
10706f2543Smrg * written prior permission.  The copyright holders make no representations
11706f2543Smrg * about the suitability of this software for any purpose.  It is provided "as
12706f2543Smrg * is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16706f2543Smrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20706f2543Smrg * OF THIS SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#include "randrstr.h"
24706f2543Smrg#include "rrtransform.h"
25706f2543Smrg
26706f2543Smrgvoid
27706f2543SmrgRRTransformInit (RRTransformPtr transform)
28706f2543Smrg{
29706f2543Smrg    pixman_transform_init_identity (&transform->transform);
30706f2543Smrg    pixman_f_transform_init_identity (&transform->f_transform);
31706f2543Smrg    pixman_f_transform_init_identity (&transform->f_inverse);
32706f2543Smrg    transform->filter = NULL;
33706f2543Smrg    transform->params = NULL;
34706f2543Smrg    transform->nparams = 0;
35706f2543Smrg}
36706f2543Smrg
37706f2543Smrgvoid
38706f2543SmrgRRTransformFini (RRTransformPtr transform)
39706f2543Smrg{
40706f2543Smrg    free(transform->params);
41706f2543Smrg}
42706f2543Smrg
43706f2543SmrgBool
44706f2543SmrgRRTransformEqual (RRTransformPtr a, RRTransformPtr b)
45706f2543Smrg{
46706f2543Smrg    if (a && pixman_transform_is_identity (&a->transform))
47706f2543Smrg	a = NULL;
48706f2543Smrg    if (b && pixman_transform_is_identity (&b->transform))
49706f2543Smrg	b = NULL;
50706f2543Smrg    if (a == NULL && b == NULL)
51706f2543Smrg	return TRUE;
52706f2543Smrg    if (a == NULL || b == NULL)
53706f2543Smrg	return FALSE;
54706f2543Smrg    if (memcmp (&a->transform, &b->transform, sizeof (a->transform)) != 0)
55706f2543Smrg	return FALSE;
56706f2543Smrg    if (a->filter != b->filter)
57706f2543Smrg	return FALSE;
58706f2543Smrg    if (a->nparams != b->nparams)
59706f2543Smrg	return FALSE;
60706f2543Smrg    if (memcmp (a->params, b->params, a->nparams * sizeof (xFixed)) != 0)
61706f2543Smrg	return FALSE;
62706f2543Smrg    return TRUE;
63706f2543Smrg}
64706f2543Smrg
65706f2543SmrgBool
66706f2543SmrgRRTransformSetFilter (RRTransformPtr	dst,
67706f2543Smrg		      PictFilterPtr	filter,
68706f2543Smrg		      xFixed		*params,
69706f2543Smrg		      int		nparams,
70706f2543Smrg		      int		width,
71706f2543Smrg		      int		height)
72706f2543Smrg{
73706f2543Smrg    xFixed  *new_params;
74706f2543Smrg
75706f2543Smrg    if (nparams)
76706f2543Smrg    {
77706f2543Smrg	new_params = malloc(nparams * sizeof (xFixed));
78706f2543Smrg	if (!new_params)
79706f2543Smrg	    return FALSE;
80706f2543Smrg	memcpy (new_params, params, nparams * sizeof (xFixed));
81706f2543Smrg    }
82706f2543Smrg    else
83706f2543Smrg	new_params = NULL;
84706f2543Smrg    free(dst->params);
85706f2543Smrg    dst->filter = filter;
86706f2543Smrg    dst->params = new_params;
87706f2543Smrg    dst->nparams = nparams;
88706f2543Smrg    dst->width = width;
89706f2543Smrg    dst->height = height;
90706f2543Smrg    return TRUE;
91706f2543Smrg}
92706f2543Smrg
93706f2543SmrgBool
94706f2543SmrgRRTransformCopy (RRTransformPtr dst, RRTransformPtr src)
95706f2543Smrg{
96706f2543Smrg    if (src && pixman_transform_is_identity (&src->transform))
97706f2543Smrg	src = NULL;
98706f2543Smrg
99706f2543Smrg    if (src)
100706f2543Smrg    {
101706f2543Smrg	if (!RRTransformSetFilter (dst, src->filter,
102706f2543Smrg				   src->params, src->nparams, src->width, src->height))
103706f2543Smrg	    return FALSE;
104706f2543Smrg	dst->transform = src->transform;
105706f2543Smrg	dst->f_transform = src->f_transform;
106706f2543Smrg	dst->f_inverse = src->f_inverse;
107706f2543Smrg    }
108706f2543Smrg    else
109706f2543Smrg    {
110706f2543Smrg	if (!RRTransformSetFilter (dst, NULL, NULL, 0, 0, 0))
111706f2543Smrg	    return FALSE;
112706f2543Smrg	pixman_transform_init_identity (&dst->transform);
113706f2543Smrg	pixman_f_transform_init_identity (&dst->f_transform);
114706f2543Smrg	pixman_f_transform_init_identity (&dst->f_inverse);
115706f2543Smrg    }
116706f2543Smrg    return TRUE;
117706f2543Smrg}
118706f2543Smrg
119706f2543Smrg#define F(x)	IntToxFixed(x)
120706f2543Smrg
121706f2543Smrgstatic void
122706f2543SmrgRRTransformRescale(struct pixman_f_transform *f_transform, double limit)
123706f2543Smrg{
124706f2543Smrg    double max = 0, v, scale;
125706f2543Smrg    int i, j;
126706f2543Smrg
127706f2543Smrg    for (j = 0; j < 3; j++)
128706f2543Smrg	for (i = 0; i < 3; i++)
129706f2543Smrg	    if ((v = fabs (f_transform->m[j][i])) > max)
130706f2543Smrg		max = v;
131706f2543Smrg    scale = limit / max;
132706f2543Smrg    for (j = 0; j < 3; j++)
133706f2543Smrg	for (i = 0; i < 3; i++)
134706f2543Smrg	    f_transform->m[j][i] *= scale;
135706f2543Smrg}
136706f2543Smrg
137706f2543Smrg/*
138706f2543Smrg * Compute the complete transformation matrix including
139706f2543Smrg * client-specified transform, rotation/reflection values and the crtc
140706f2543Smrg * offset.
141706f2543Smrg *
142706f2543Smrg * Return TRUE if the resulting transform is not a simple translation.
143706f2543Smrg */
144706f2543SmrgBool
145706f2543SmrgRRTransformCompute (int			    x,
146706f2543Smrg		    int			    y,
147706f2543Smrg		    int			    width,
148706f2543Smrg		    int			    height,
149706f2543Smrg		    Rotation		    rotation,
150706f2543Smrg		    RRTransformPtr	    rr_transform,
151706f2543Smrg
152706f2543Smrg		    PictTransformPtr	    transform,
153706f2543Smrg		    struct pixman_f_transform *f_transform,
154706f2543Smrg		    struct pixman_f_transform *f_inverse)
155706f2543Smrg{
156706f2543Smrg    PictTransform	    t_transform, inverse;
157706f2543Smrg    struct pixman_f_transform tf_transform, tf_inverse;
158706f2543Smrg    Bool		    overflow = FALSE;
159706f2543Smrg
160706f2543Smrg    if (!transform) transform = &t_transform;
161706f2543Smrg    if (!f_transform) f_transform = &tf_transform;
162706f2543Smrg    if (!f_inverse) f_inverse = &tf_inverse;
163706f2543Smrg
164706f2543Smrg    pixman_transform_init_identity (transform);
165706f2543Smrg    pixman_transform_init_identity (&inverse);
166706f2543Smrg    pixman_f_transform_init_identity (f_transform);
167706f2543Smrg    pixman_f_transform_init_identity (f_inverse);
168706f2543Smrg    if (rotation != RR_Rotate_0)
169706f2543Smrg    {
170706f2543Smrg	double	f_rot_cos, f_rot_sin, f_rot_dx, f_rot_dy;
171706f2543Smrg	double	f_scale_x, f_scale_y, f_scale_dx, f_scale_dy;
172706f2543Smrg	xFixed	rot_cos, rot_sin, rot_dx, rot_dy;
173706f2543Smrg	xFixed	scale_x, scale_y, scale_dx, scale_dy;
174706f2543Smrg
175706f2543Smrg	/* rotation */
176706f2543Smrg	switch (rotation & 0xf) {
177706f2543Smrg	default:
178706f2543Smrg	case RR_Rotate_0:
179706f2543Smrg	    f_rot_cos = 1;	    f_rot_sin = 0;
180706f2543Smrg	    f_rot_dx  = 0;	    f_rot_dy  = 0;
181706f2543Smrg	    rot_cos = F ( 1);	    rot_sin = F ( 0);
182706f2543Smrg	    rot_dx  = F ( 0);	    rot_dy  = F ( 0);
183706f2543Smrg	    break;
184706f2543Smrg	case RR_Rotate_90:
185706f2543Smrg	    f_rot_cos = 0;	    f_rot_sin = 1;
186706f2543Smrg	    f_rot_dx  = height;	    f_rot_dy  = 0;
187706f2543Smrg	    rot_cos = F ( 0);	    rot_sin = F ( 1);
188706f2543Smrg	    rot_dx =  F ( height);  rot_dy  = F (0);
189706f2543Smrg	    break;
190706f2543Smrg	case RR_Rotate_180:
191706f2543Smrg	    f_rot_cos = -1;	    f_rot_sin = 0;
192706f2543Smrg	    f_rot_dx  = width;	    f_rot_dy  = height;
193706f2543Smrg	    rot_cos = F (-1);	    rot_sin = F ( 0);
194706f2543Smrg	    rot_dx  = F (width);   rot_dy  = F ( height);
195706f2543Smrg	    break;
196706f2543Smrg	case RR_Rotate_270:
197706f2543Smrg	    f_rot_cos = 0;	    f_rot_sin = -1;
198706f2543Smrg	    f_rot_dx  = 0;	    f_rot_dy  = width;
199706f2543Smrg	    rot_cos = F ( 0);	    rot_sin = F (-1);
200706f2543Smrg	    rot_dx  = F ( 0);	    rot_dy  = F ( width);
201706f2543Smrg	    break;
202706f2543Smrg	}
203706f2543Smrg
204706f2543Smrg	pixman_transform_rotate (transform, &inverse, rot_cos, rot_sin);
205706f2543Smrg	pixman_transform_translate (transform, &inverse, rot_dx, rot_dy);
206706f2543Smrg	pixman_f_transform_rotate (f_transform, f_inverse, f_rot_cos, f_rot_sin);
207706f2543Smrg	pixman_f_transform_translate (f_transform, f_inverse, f_rot_dx, f_rot_dy);
208706f2543Smrg
209706f2543Smrg	/* reflection */
210706f2543Smrg	f_scale_x = 1;
211706f2543Smrg	f_scale_dx = 0;
212706f2543Smrg	f_scale_y = 1;
213706f2543Smrg	f_scale_dy = 0;
214706f2543Smrg	scale_x = F (1);
215706f2543Smrg	scale_dx = 0;
216706f2543Smrg	scale_y = F (1);
217706f2543Smrg	scale_dy = 0;
218706f2543Smrg	if (rotation & RR_Reflect_X)
219706f2543Smrg	{
220706f2543Smrg	    f_scale_x = -1;
221706f2543Smrg	    scale_x = F(-1);
222706f2543Smrg	    if (rotation & (RR_Rotate_0|RR_Rotate_180)) {
223706f2543Smrg		f_scale_dx = width;
224706f2543Smrg		scale_dx = F(width);
225706f2543Smrg	    } else {
226706f2543Smrg		f_scale_dx = height;
227706f2543Smrg		scale_dx = F(height);
228706f2543Smrg	    }
229706f2543Smrg	}
230706f2543Smrg	if (rotation & RR_Reflect_Y)
231706f2543Smrg	{
232706f2543Smrg	    f_scale_y = -1;
233706f2543Smrg	    scale_y = F(-1);
234706f2543Smrg	    if (rotation & (RR_Rotate_0|RR_Rotate_180)) {
235706f2543Smrg		f_scale_dy = height;
236706f2543Smrg		scale_dy = F(height);
237706f2543Smrg	    } else {
238706f2543Smrg		f_scale_dy = width;
239706f2543Smrg		scale_dy = F(width);
240706f2543Smrg	    }
241706f2543Smrg	}
242706f2543Smrg
243706f2543Smrg	pixman_transform_scale (transform, &inverse, scale_x, scale_y);
244706f2543Smrg	pixman_f_transform_scale (f_transform, f_inverse, f_scale_x, f_scale_y);
245706f2543Smrg	pixman_transform_translate (transform, &inverse, scale_dx, scale_dy);
246706f2543Smrg	pixman_f_transform_translate (f_transform, f_inverse, f_scale_dx, f_scale_dy);
247706f2543Smrg    }
248706f2543Smrg
249706f2543Smrg#ifdef RANDR_12_INTERFACE
250706f2543Smrg    if (rr_transform)
251706f2543Smrg    {
252706f2543Smrg        if (!pixman_transform_multiply (transform, &rr_transform->transform, transform))
253706f2543Smrg	    overflow = TRUE;
254706f2543Smrg	pixman_f_transform_multiply (f_transform, &rr_transform->f_transform, f_transform);
255706f2543Smrg	pixman_f_transform_multiply (f_inverse, f_inverse, &rr_transform->f_inverse);
256706f2543Smrg    }
257706f2543Smrg#endif
258706f2543Smrg    /*
259706f2543Smrg     * Compute the class of the resulting transform
260706f2543Smrg     */
261706f2543Smrg    if (!overflow && pixman_transform_is_identity (transform))
262706f2543Smrg    {
263706f2543Smrg	pixman_transform_init_translate (transform, F ( x), F ( y));
264706f2543Smrg
265706f2543Smrg	pixman_f_transform_init_translate (f_transform,  x,  y);
266706f2543Smrg	pixman_f_transform_init_translate (f_inverse,   -x, -y);
267706f2543Smrg	return FALSE;
268706f2543Smrg    }
269706f2543Smrg    else
270706f2543Smrg    {
271706f2543Smrg	pixman_f_transform_translate (f_transform, f_inverse, x, y);
272706f2543Smrg	if (!pixman_transform_translate (transform, &inverse, F(x), F(y)))
273706f2543Smrg	    overflow = TRUE;
274706f2543Smrg	if (overflow)
275706f2543Smrg	{
276706f2543Smrg	    struct pixman_f_transform f_scaled;
277706f2543Smrg	    f_scaled = *f_transform;
278706f2543Smrg	    RRTransformRescale(&f_scaled, 16384.0);
279706f2543Smrg	    pixman_transform_from_pixman_f_transform(transform, &f_scaled);
280706f2543Smrg	}
281706f2543Smrg	return TRUE;
282706f2543Smrg    }
283706f2543Smrg}
284