rrtransform.c revision b86d567b
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, &rr_transform->transform, transform)) 255 overflow = TRUE; 256 pixman_f_transform_multiply (f_transform, &rr_transform->f_transform, f_transform); 257 pixman_f_transform_multiply (f_inverse, f_inverse, &rr_transform->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