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 free(transform->params); 41} 42 43Bool 44RRTransformEqual (RRTransformPtr a, RRTransformPtr b) 45{ 46 if (a && pixman_transform_is_identity (&a->transform)) 47 a = NULL; 48 if (b && pixman_transform_is_identity (&b->transform)) 49 b = NULL; 50 if (a == NULL && b == NULL) 51 return TRUE; 52 if (a == NULL || b == NULL) 53 return FALSE; 54 if (memcmp (&a->transform, &b->transform, sizeof (a->transform)) != 0) 55 return FALSE; 56 if (a->filter != b->filter) 57 return FALSE; 58 if (a->nparams != b->nparams) 59 return FALSE; 60 if (memcmp (a->params, b->params, a->nparams * sizeof (xFixed)) != 0) 61 return FALSE; 62 return TRUE; 63} 64 65Bool 66RRTransformSetFilter (RRTransformPtr dst, 67 PictFilterPtr filter, 68 xFixed *params, 69 int nparams, 70 int width, 71 int height) 72{ 73 xFixed *new_params; 74 75 if (nparams) 76 { 77 new_params = malloc(nparams * sizeof (xFixed)); 78 if (!new_params) 79 return FALSE; 80 memcpy (new_params, params, nparams * sizeof (xFixed)); 81 } 82 else 83 new_params = NULL; 84 free(dst->params); 85 dst->filter = filter; 86 dst->params = new_params; 87 dst->nparams = nparams; 88 dst->width = width; 89 dst->height = height; 90 return TRUE; 91} 92 93Bool 94RRTransformCopy (RRTransformPtr dst, RRTransformPtr src) 95{ 96 if (src && pixman_transform_is_identity (&src->transform)) 97 src = NULL; 98 99 if (src) 100 { 101 if (!RRTransformSetFilter (dst, src->filter, 102 src->params, src->nparams, src->width, src->height)) 103 return FALSE; 104 dst->transform = src->transform; 105 dst->f_transform = src->f_transform; 106 dst->f_inverse = src->f_inverse; 107 } 108 else 109 { 110 if (!RRTransformSetFilter (dst, NULL, NULL, 0, 0, 0)) 111 return FALSE; 112 pixman_transform_init_identity (&dst->transform); 113 pixman_f_transform_init_identity (&dst->f_transform); 114 pixman_f_transform_init_identity (&dst->f_inverse); 115 } 116 return TRUE; 117} 118 119#define F(x) IntToxFixed(x) 120 121static void 122RRTransformRescale(struct pixman_f_transform *f_transform, double limit) 123{ 124 double max = 0, v, scale; 125 int i, j; 126 127 for (j = 0; j < 3; j++) 128 for (i = 0; i < 3; i++) 129 if ((v = fabs (f_transform->m[j][i])) > max) 130 max = v; 131 scale = limit / max; 132 for (j = 0; j < 3; j++) 133 for (i = 0; i < 3; i++) 134 f_transform->m[j][i] *= scale; 135} 136 137/* 138 * Compute the complete transformation matrix including 139 * client-specified transform, rotation/reflection values and the crtc 140 * offset. 141 * 142 * Return TRUE if the resulting transform is not a simple translation. 143 */ 144Bool 145RRTransformCompute (int x, 146 int y, 147 int width, 148 int height, 149 Rotation rotation, 150 RRTransformPtr rr_transform, 151 152 PictTransformPtr transform, 153 struct pixman_f_transform *f_transform, 154 struct pixman_f_transform *f_inverse) 155{ 156 PictTransform t_transform, inverse; 157 struct pixman_f_transform tf_transform, tf_inverse; 158 Bool overflow = FALSE; 159 160 if (!transform) transform = &t_transform; 161 if (!f_transform) f_transform = &tf_transform; 162 if (!f_inverse) f_inverse = &tf_inverse; 163 164 pixman_transform_init_identity (transform); 165 pixman_transform_init_identity (&inverse); 166 pixman_f_transform_init_identity (f_transform); 167 pixman_f_transform_init_identity (f_inverse); 168 if (rotation != RR_Rotate_0) 169 { 170 double f_rot_cos, f_rot_sin, f_rot_dx, f_rot_dy; 171 double f_scale_x, f_scale_y, f_scale_dx, f_scale_dy; 172 xFixed rot_cos, rot_sin, rot_dx, rot_dy; 173 xFixed scale_x, scale_y, scale_dx, scale_dy; 174 175 /* rotation */ 176 switch (rotation & 0xf) { 177 default: 178 case RR_Rotate_0: 179 f_rot_cos = 1; f_rot_sin = 0; 180 f_rot_dx = 0; f_rot_dy = 0; 181 rot_cos = F ( 1); rot_sin = F ( 0); 182 rot_dx = F ( 0); rot_dy = F ( 0); 183 break; 184 case RR_Rotate_90: 185 f_rot_cos = 0; f_rot_sin = 1; 186 f_rot_dx = height; f_rot_dy = 0; 187 rot_cos = F ( 0); rot_sin = F ( 1); 188 rot_dx = F ( height); rot_dy = F (0); 189 break; 190 case RR_Rotate_180: 191 f_rot_cos = -1; f_rot_sin = 0; 192 f_rot_dx = width; f_rot_dy = height; 193 rot_cos = F (-1); rot_sin = F ( 0); 194 rot_dx = F (width); rot_dy = F ( height); 195 break; 196 case RR_Rotate_270: 197 f_rot_cos = 0; f_rot_sin = -1; 198 f_rot_dx = 0; f_rot_dy = width; 199 rot_cos = F ( 0); rot_sin = F (-1); 200 rot_dx = F ( 0); rot_dy = F ( width); 201 break; 202 } 203 204 pixman_transform_rotate (transform, &inverse, rot_cos, rot_sin); 205 pixman_transform_translate (transform, &inverse, rot_dx, rot_dy); 206 pixman_f_transform_rotate (f_transform, f_inverse, f_rot_cos, f_rot_sin); 207 pixman_f_transform_translate (f_transform, f_inverse, f_rot_dx, f_rot_dy); 208 209 /* reflection */ 210 f_scale_x = 1; 211 f_scale_dx = 0; 212 f_scale_y = 1; 213 f_scale_dy = 0; 214 scale_x = F (1); 215 scale_dx = 0; 216 scale_y = F (1); 217 scale_dy = 0; 218 if (rotation & RR_Reflect_X) 219 { 220 f_scale_x = -1; 221 scale_x = F(-1); 222 if (rotation & (RR_Rotate_0|RR_Rotate_180)) { 223 f_scale_dx = width; 224 scale_dx = F(width); 225 } else { 226 f_scale_dx = height; 227 scale_dx = F(height); 228 } 229 } 230 if (rotation & RR_Reflect_Y) 231 { 232 f_scale_y = -1; 233 scale_y = F(-1); 234 if (rotation & (RR_Rotate_0|RR_Rotate_180)) { 235 f_scale_dy = height; 236 scale_dy = F(height); 237 } else { 238 f_scale_dy = width; 239 scale_dy = F(width); 240 } 241 } 242 243 pixman_transform_scale (transform, &inverse, scale_x, scale_y); 244 pixman_f_transform_scale (f_transform, f_inverse, f_scale_x, f_scale_y); 245 pixman_transform_translate (transform, &inverse, scale_dx, scale_dy); 246 pixman_f_transform_translate (f_transform, f_inverse, f_scale_dx, f_scale_dy); 247 } 248 249#ifdef RANDR_12_INTERFACE 250 if (rr_transform) 251 { 252 if (!pixman_transform_multiply (transform, &rr_transform->transform, transform)) 253 overflow = TRUE; 254 pixman_f_transform_multiply (f_transform, &rr_transform->f_transform, f_transform); 255 pixman_f_transform_multiply (f_inverse, f_inverse, &rr_transform->f_inverse); 256 } 257#endif 258 /* 259 * Compute the class of the resulting transform 260 */ 261 if (!overflow && pixman_transform_is_identity (transform)) 262 { 263 pixman_transform_init_translate (transform, F ( x), F ( y)); 264 265 pixman_f_transform_init_translate (f_transform, x, y); 266 pixman_f_transform_init_translate (f_inverse, -x, -y); 267 return FALSE; 268 } 269 else 270 { 271 pixman_f_transform_translate (f_transform, f_inverse, x, y); 272 if (!pixman_transform_translate (transform, &inverse, F(x), F(y))) 273 overflow = TRUE; 274 if (overflow) 275 { 276 struct pixman_f_transform f_scaled; 277 f_scaled = *f_transform; 278 RRTransformRescale(&f_scaled, 16384.0); 279 pixman_transform_from_pixman_f_transform(transform, &f_scaled); 280 } 281 return TRUE; 282 } 283} 284