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