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