rrtransform.c revision 4642e01f
1/*
2 * Copyright © 2007 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  The copyright holders make no representations
11 * about the suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include "randrstr.h"
24#include "rrtransform.h"
25
26void
27RRTransformInit (RRTransformPtr transform)
28{
29    pixman_transform_init_identity (&transform->transform);
30    pixman_f_transform_init_identity (&transform->f_transform);
31    pixman_f_transform_init_identity (&transform->f_inverse);
32    transform->filter = NULL;
33    transform->params = NULL;
34    transform->nparams = 0;
35}
36
37void
38RRTransformFini (RRTransformPtr transform)
39{
40    if (transform->params)
41	xfree (transform->params);
42}
43
44Bool
45RRTransformEqual (RRTransformPtr a, RRTransformPtr b)
46{
47    if (a && pixman_transform_is_identity (&a->transform))
48	a = NULL;
49    if (b && pixman_transform_is_identity (&b->transform))
50	b = NULL;
51    if (a == NULL && b == NULL)
52	return TRUE;
53    if (a == NULL || b == NULL)
54	return FALSE;
55    if (memcmp (&a->transform, &b->transform, sizeof (a->transform)) != 0)
56	return FALSE;
57    if (a->filter != b->filter)
58	return FALSE;
59    if (a->nparams != b->nparams)
60	return FALSE;
61    if (memcmp (a->params, b->params, a->nparams * sizeof (xFixed)) != 0)
62	return FALSE;
63    return TRUE;
64}
65
66Bool
67RRTransformSetFilter (RRTransformPtr	dst,
68		      PictFilterPtr	filter,
69		      xFixed		*params,
70		      int		nparams,
71		      int		width,
72		      int		height)
73{
74    xFixed  *new_params;
75
76    if (nparams)
77    {
78	new_params = xalloc (nparams * sizeof (xFixed));
79	if (!new_params)
80	    return FALSE;
81	memcpy (new_params, params, nparams * sizeof (xFixed));
82    }
83    else
84	new_params = NULL;
85    if (dst->params)
86	xfree (dst->params);
87    dst->filter = filter;
88    dst->params = new_params;
89    dst->nparams = nparams;
90    dst->width = width;
91    dst->height = height;
92    return TRUE;
93}
94
95Bool
96RRTransformCopy (RRTransformPtr dst, RRTransformPtr src)
97{
98    if (src && pixman_transform_is_identity (&src->transform))
99	src = NULL;
100
101    if (src)
102    {
103	if (!RRTransformSetFilter (dst, src->filter,
104				   src->params, src->nparams, src->width, src->height))
105	    return FALSE;
106	dst->transform = src->transform;
107	dst->f_transform = src->f_transform;
108	dst->f_inverse = src->f_inverse;
109    }
110    else
111    {
112	if (!RRTransformSetFilter (dst, NULL, NULL, 0, 0, 0))
113	    return FALSE;
114	pixman_transform_init_identity (&dst->transform);
115	pixman_f_transform_init_identity (&dst->f_transform);
116	pixman_f_transform_init_identity (&dst->f_inverse);
117    }
118    return TRUE;
119}
120
121#define F(x)	IntToxFixed(x)
122
123static void
124RRTransformRescale(struct pixman_f_transform *f_transform, double limit)
125{
126    double max = 0, v, scale;
127    int i, j;
128
129    for (j = 0; j < 3; j++)
130	for (i = 0; i < 3; i++)
131	    if ((v = abs (f_transform->m[j][i])) > max)
132		max = v;
133    scale = limit / max;
134    for (j = 0; j < 3; j++)
135	for (i = 0; i < 3; i++)
136	    f_transform->m[j][i] *= scale;
137}
138
139/*
140 * Compute the complete transformation matrix including
141 * client-specified transform, rotation/reflection values and the crtc
142 * offset.
143 *
144 * Return TRUE if the resulting transform is not a simple translation.
145 */
146Bool
147RRTransformCompute (int			    x,
148		    int			    y,
149		    int			    width,
150		    int			    height,
151		    Rotation		    rotation,
152		    RRTransformPtr	    rr_transform,
153
154		    PictTransformPtr	    transform,
155		    struct pixman_f_transform *f_transform,
156		    struct pixman_f_transform *f_inverse)
157{
158    PictTransform	    t_transform, inverse;
159    struct pixman_f_transform tf_transform, tf_inverse;
160    Bool		    overflow = FALSE;
161
162    if (!transform) transform = &t_transform;
163    if (!f_transform) f_transform = &tf_transform;
164    if (!f_inverse) f_inverse = &tf_inverse;
165
166    pixman_transform_init_identity (transform);
167    pixman_transform_init_identity (&inverse);
168    pixman_f_transform_init_identity (f_transform);
169    pixman_f_transform_init_identity (f_inverse);
170    if (rotation != RR_Rotate_0)
171    {
172	double	f_rot_cos, f_rot_sin, f_rot_dx, f_rot_dy;
173	double	f_scale_x, f_scale_y, f_scale_dx, f_scale_dy;
174	xFixed	rot_cos, rot_sin, rot_dx, rot_dy;
175	xFixed	scale_x, scale_y, scale_dx, scale_dy;
176
177	/* rotation */
178	switch (rotation & 0xf) {
179	default:
180	case RR_Rotate_0:
181	    f_rot_cos = 1;	    f_rot_sin = 0;
182	    f_rot_dx  = 0;	    f_rot_dy  = 0;
183	    rot_cos = F ( 1);	    rot_sin = F ( 0);
184	    rot_dx  = F ( 0);	    rot_dy  = F ( 0);
185	    break;
186	case RR_Rotate_90:
187	    f_rot_cos = 0;	    f_rot_sin = 1;
188	    f_rot_dx  = height-1;   f_rot_dy  = 0;
189	    rot_cos = F ( 0);	    rot_sin = F ( 1);
190	    rot_dx =  F (height-1); rot_dy  = F (0);
191	    break;
192	case RR_Rotate_180:
193	    f_rot_cos = -1;	    f_rot_sin = 0;
194	    f_rot_dx  = width - 1;  f_rot_dy  = height - 1;
195	    rot_cos = F (-1);	    rot_sin = F ( 0);
196	    rot_dx  = F (width-1);  rot_dy  = F ( height-1);
197	    break;
198	case RR_Rotate_270:
199	    f_rot_cos = 0;	    f_rot_sin = -1;
200	    f_rot_dx  = 0;	    f_rot_dy  = width-1;
201	    rot_cos = F ( 0);	    rot_sin = F (-1);
202	    rot_dx  = F ( 0);	    rot_dy  = F ( width-1);
203	    break;
204	}
205
206	pixman_transform_rotate (transform, &inverse, rot_cos, rot_sin);
207	pixman_transform_translate (transform, &inverse, rot_dx, rot_dy);
208	pixman_f_transform_rotate (f_transform, f_inverse, f_rot_cos, f_rot_sin);
209	pixman_f_transform_translate (f_transform, f_inverse, f_rot_dx, f_rot_dy);
210
211	/* reflection */
212	f_scale_x = 1;
213	f_scale_dx = 0;
214	f_scale_y = 1;
215	f_scale_dy = 0;
216	scale_x = F (1);
217	scale_dx = 0;
218	scale_y = F (1);
219	scale_dy = 0;
220	if (rotation & RR_Reflect_X)
221	{
222	    f_scale_x = -1;
223	    scale_x = F(-1);
224	    if (rotation & (RR_Rotate_0|RR_Rotate_180)) {
225		f_scale_dx = width-1;
226		scale_dx = F(width-1);
227	    } else {
228		f_scale_dx = height-1;
229		scale_dx = F(height-1);
230	    }
231	}
232	if (rotation & RR_Reflect_Y)
233	{
234	    f_scale_y = -1;
235	    scale_y = F(-1);
236	    if (rotation & (RR_Rotate_0|RR_Rotate_180)) {
237		f_scale_dy = height-1;
238		scale_dy = F(height-1);
239	    } else {
240		f_scale_dy = width-1;
241		scale_dy = F(width-1);
242	    }
243	}
244
245	pixman_transform_scale (transform, &inverse, scale_x, scale_y);
246	pixman_f_transform_scale (f_transform, f_inverse, f_scale_x, f_scale_y);
247	pixman_transform_translate (transform, &inverse, scale_dx, scale_dy);
248	pixman_f_transform_translate (f_transform, f_inverse, f_scale_dx, f_scale_dy);
249    }
250
251#ifdef RANDR_12_INTERFACE
252    if (rr_transform)
253    {
254        if (!pixman_transform_multiply (transform, transform, &rr_transform->transform))
255	    overflow = TRUE;
256	pixman_f_transform_multiply (f_transform, f_transform, &rr_transform->f_transform);
257	pixman_f_transform_multiply (f_inverse, &rr_transform->f_inverse, f_inverse);
258    }
259#endif
260    /*
261     * Compute the class of the resulting transform
262     */
263    if (!overflow && pixman_transform_is_identity (transform))
264    {
265	pixman_transform_init_translate (transform, F ( x), F ( y));
266
267	pixman_f_transform_init_translate (f_transform,  x,  y);
268	pixman_f_transform_init_translate (f_inverse,   -x, -y);
269	return FALSE;
270    }
271    else
272    {
273	pixman_f_transform_translate (f_transform, f_inverse, x, y);
274	if (!pixman_transform_translate (transform, &inverse, F(x), F(y)))
275	    overflow = TRUE;
276	if (overflow)
277	{
278	    struct pixman_f_transform f_scaled;
279	    f_scaled = *f_transform;
280	    RRTransformRescale(&f_scaled, 16384.0);
281	    pixman_transform_from_pixman_f_transform(transform, &f_scaled);
282	}
283	return TRUE;
284    }
285}
286