284 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			284 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright © 2007 Keith Packard
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that copyright
 | |
|  * notice and this permission notice appear in supporting documentation, and
 | |
|  * that the name of the copyright holders not be used in advertising or
 | |
|  * publicity pertaining to distribution of the software without specific,
 | |
|  * written prior permission.  The copyright holders make no representations
 | |
|  * about the suitability of this software for any purpose.  It is provided "as
 | |
|  * is" without express or implied warranty.
 | |
|  *
 | |
|  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | |
|  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
|  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | |
|  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | |
|  * OF THIS SOFTWARE.
 | |
|  */
 | |
| 
 | |
| #include "randrstr.h"
 | |
| #include "rrtransform.h"
 | |
| 
 | |
| void
 | |
| RRTransformInit (RRTransformPtr transform)
 | |
| {
 | |
|     pixman_transform_init_identity (&transform->transform);
 | |
|     pixman_f_transform_init_identity (&transform->f_transform);
 | |
|     pixman_f_transform_init_identity (&transform->f_inverse);
 | |
|     transform->filter = NULL;
 | |
|     transform->params = NULL;
 | |
|     transform->nparams = 0;
 | |
| }
 | |
| 
 | |
| void
 | |
| RRTransformFini (RRTransformPtr transform)
 | |
| {
 | |
|     free(transform->params);
 | |
| }
 | |
| 
 | |
| Bool
 | |
| RRTransformEqual (RRTransformPtr a, RRTransformPtr b)
 | |
| {
 | |
|     if (a && pixman_transform_is_identity (&a->transform))
 | |
| 	a = NULL;
 | |
|     if (b && pixman_transform_is_identity (&b->transform))
 | |
| 	b = NULL;
 | |
|     if (a == NULL && b == NULL)
 | |
| 	return TRUE;
 | |
|     if (a == NULL || b == NULL)
 | |
| 	return FALSE;
 | |
|     if (memcmp (&a->transform, &b->transform, sizeof (a->transform)) != 0)
 | |
| 	return FALSE;
 | |
|     if (a->filter != b->filter)
 | |
| 	return FALSE;
 | |
|     if (a->nparams != b->nparams)
 | |
| 	return FALSE;
 | |
|     if (memcmp (a->params, b->params, a->nparams * sizeof (xFixed)) != 0)
 | |
| 	return FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| RRTransformSetFilter (RRTransformPtr	dst,
 | |
| 		      PictFilterPtr	filter,
 | |
| 		      xFixed		*params,
 | |
| 		      int		nparams,
 | |
| 		      int		width,
 | |
| 		      int		height)
 | |
| {
 | |
|     xFixed  *new_params;
 | |
| 
 | |
|     if (nparams)
 | |
|     {
 | |
| 	new_params = malloc(nparams * sizeof (xFixed));
 | |
| 	if (!new_params)
 | |
| 	    return FALSE;
 | |
| 	memcpy (new_params, params, nparams * sizeof (xFixed));
 | |
|     }
 | |
|     else
 | |
| 	new_params = NULL;
 | |
|     free(dst->params);
 | |
|     dst->filter = filter;
 | |
|     dst->params = new_params;
 | |
|     dst->nparams = nparams;
 | |
|     dst->width = width;
 | |
|     dst->height = height;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| RRTransformCopy (RRTransformPtr dst, RRTransformPtr src)
 | |
| {
 | |
|     if (src && pixman_transform_is_identity (&src->transform))
 | |
| 	src = NULL;
 | |
| 
 | |
|     if (src)
 | |
|     {
 | |
| 	if (!RRTransformSetFilter (dst, src->filter,
 | |
| 				   src->params, src->nparams, src->width, src->height))
 | |
| 	    return FALSE;
 | |
| 	dst->transform = src->transform;
 | |
| 	dst->f_transform = src->f_transform;
 | |
| 	dst->f_inverse = src->f_inverse;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	if (!RRTransformSetFilter (dst, NULL, NULL, 0, 0, 0))
 | |
| 	    return FALSE;
 | |
| 	pixman_transform_init_identity (&dst->transform);
 | |
| 	pixman_f_transform_init_identity (&dst->f_transform);
 | |
| 	pixman_f_transform_init_identity (&dst->f_inverse);
 | |
|     }
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| #define F(x)	IntToxFixed(x)
 | |
| 
 | |
| static void
 | |
| RRTransformRescale(struct pixman_f_transform *f_transform, double limit)
 | |
| {
 | |
|     double max = 0, v, scale;
 | |
|     int i, j;
 | |
| 
 | |
|     for (j = 0; j < 3; j++)
 | |
| 	for (i = 0; i < 3; i++)
 | |
| 	    if ((v = abs (f_transform->m[j][i])) > max)
 | |
| 		max = v;
 | |
|     scale = limit / max;
 | |
|     for (j = 0; j < 3; j++)
 | |
| 	for (i = 0; i < 3; i++)
 | |
| 	    f_transform->m[j][i] *= scale;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Compute the complete transformation matrix including
 | |
|  * client-specified transform, rotation/reflection values and the crtc 
 | |
|  * offset.
 | |
|  *
 | |
|  * Return TRUE if the resulting transform is not a simple translation.
 | |
|  */
 | |
| Bool
 | |
| RRTransformCompute (int			    x,
 | |
| 		    int			    y,
 | |
| 		    int			    width,
 | |
| 		    int			    height,
 | |
| 		    Rotation		    rotation,
 | |
| 		    RRTransformPtr	    rr_transform,
 | |
| 
 | |
| 		    PictTransformPtr	    transform,
 | |
| 		    struct pixman_f_transform *f_transform,
 | |
| 		    struct pixman_f_transform *f_inverse)
 | |
| {
 | |
|     PictTransform	    t_transform, inverse;
 | |
|     struct pixman_f_transform tf_transform, tf_inverse;
 | |
|     Bool		    overflow = FALSE;
 | |
| 
 | |
|     if (!transform) transform = &t_transform;
 | |
|     if (!f_transform) f_transform = &tf_transform;
 | |
|     if (!f_inverse) f_inverse = &tf_inverse;
 | |
| 
 | |
|     pixman_transform_init_identity (transform);
 | |
|     pixman_transform_init_identity (&inverse);
 | |
|     pixman_f_transform_init_identity (f_transform);
 | |
|     pixman_f_transform_init_identity (f_inverse);
 | |
|     if (rotation != RR_Rotate_0)
 | |
|     {
 | |
| 	double	f_rot_cos, f_rot_sin, f_rot_dx, f_rot_dy;
 | |
| 	double	f_scale_x, f_scale_y, f_scale_dx, f_scale_dy;
 | |
| 	xFixed	rot_cos, rot_sin, rot_dx, rot_dy;
 | |
| 	xFixed	scale_x, scale_y, scale_dx, scale_dy;
 | |
| 
 | |
| 	/* rotation */
 | |
| 	switch (rotation & 0xf) {
 | |
| 	default:
 | |
| 	case RR_Rotate_0:
 | |
| 	    f_rot_cos = 1;	    f_rot_sin = 0;
 | |
| 	    f_rot_dx  = 0;	    f_rot_dy  = 0;
 | |
| 	    rot_cos = F ( 1);	    rot_sin = F ( 0);
 | |
| 	    rot_dx  = F ( 0);	    rot_dy  = F ( 0);
 | |
| 	    break;
 | |
| 	case RR_Rotate_90:
 | |
| 	    f_rot_cos = 0;	    f_rot_sin = 1;
 | |
| 	    f_rot_dx  = height;	    f_rot_dy  = 0;
 | |
| 	    rot_cos = F ( 0);	    rot_sin = F ( 1);
 | |
| 	    rot_dx =  F ( height);  rot_dy  = F (0);
 | |
| 	    break;
 | |
| 	case RR_Rotate_180:
 | |
| 	    f_rot_cos = -1;	    f_rot_sin = 0;
 | |
| 	    f_rot_dx  = width;	    f_rot_dy  = height;
 | |
| 	    rot_cos = F (-1);	    rot_sin = F ( 0);
 | |
| 	    rot_dx  = F (width);   rot_dy  = F ( height);
 | |
| 	    break;
 | |
| 	case RR_Rotate_270:
 | |
| 	    f_rot_cos = 0;	    f_rot_sin = -1;
 | |
| 	    f_rot_dx  = 0;	    f_rot_dy  = width;
 | |
| 	    rot_cos = F ( 0);	    rot_sin = F (-1);
 | |
| 	    rot_dx  = F ( 0);	    rot_dy  = F ( width);
 | |
| 	    break;
 | |
| 	}
 | |
| 	
 | |
| 	pixman_transform_rotate (transform, &inverse, rot_cos, rot_sin);
 | |
| 	pixman_transform_translate (transform, &inverse, rot_dx, rot_dy);
 | |
| 	pixman_f_transform_rotate (f_transform, f_inverse, f_rot_cos, f_rot_sin);
 | |
| 	pixman_f_transform_translate (f_transform, f_inverse, f_rot_dx, f_rot_dy);
 | |
| 
 | |
| 	/* reflection */
 | |
| 	f_scale_x = 1;
 | |
| 	f_scale_dx = 0;
 | |
| 	f_scale_y = 1;
 | |
| 	f_scale_dy = 0;
 | |
| 	scale_x = F (1);
 | |
| 	scale_dx = 0;
 | |
| 	scale_y = F (1);
 | |
| 	scale_dy = 0;
 | |
| 	if (rotation & RR_Reflect_X)
 | |
| 	{
 | |
| 	    f_scale_x = -1;
 | |
| 	    scale_x = F(-1);
 | |
| 	    if (rotation & (RR_Rotate_0|RR_Rotate_180)) {
 | |
| 		f_scale_dx = width;
 | |
| 		scale_dx = F(width);
 | |
| 	    } else {
 | |
| 		f_scale_dx = height;
 | |
| 		scale_dx = F(height);
 | |
| 	    }
 | |
| 	}
 | |
| 	if (rotation & RR_Reflect_Y)
 | |
| 	{
 | |
| 	    f_scale_y = -1;
 | |
| 	    scale_y = F(-1);
 | |
| 	    if (rotation & (RR_Rotate_0|RR_Rotate_180)) {
 | |
| 		f_scale_dy = height;
 | |
| 		scale_dy = F(height);
 | |
| 	    } else {
 | |
| 		f_scale_dy = width;
 | |
| 		scale_dy = F(width);
 | |
| 	    }
 | |
| 	}
 | |
| 	
 | |
| 	pixman_transform_scale (transform, &inverse, scale_x, scale_y);
 | |
| 	pixman_f_transform_scale (f_transform, f_inverse, f_scale_x, f_scale_y);
 | |
| 	pixman_transform_translate (transform, &inverse, scale_dx, scale_dy);
 | |
| 	pixman_f_transform_translate (f_transform, f_inverse, f_scale_dx, f_scale_dy);
 | |
|     }
 | |
|     
 | |
| #ifdef RANDR_12_INTERFACE
 | |
|     if (rr_transform)
 | |
|     {
 | |
|         if (!pixman_transform_multiply (transform, &rr_transform->transform, transform))
 | |
| 	    overflow = TRUE;
 | |
| 	pixman_f_transform_multiply (f_transform, &rr_transform->f_transform, f_transform);
 | |
| 	pixman_f_transform_multiply (f_inverse, f_inverse, &rr_transform->f_inverse);
 | |
|     }
 | |
| #endif
 | |
|     /*
 | |
|      * Compute the class of the resulting transform
 | |
|      */
 | |
|     if (!overflow && pixman_transform_is_identity (transform))
 | |
|     {
 | |
| 	pixman_transform_init_translate (transform, F ( x), F ( y));
 | |
| 
 | |
| 	pixman_f_transform_init_translate (f_transform,  x,  y);
 | |
| 	pixman_f_transform_init_translate (f_inverse,   -x, -y);
 | |
| 	return FALSE;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	pixman_f_transform_translate (f_transform, f_inverse, x, y);
 | |
| 	if (!pixman_transform_translate (transform, &inverse, F(x), F(y)))
 | |
| 	    overflow = TRUE;
 | |
| 	if (overflow)
 | |
| 	{
 | |
| 	    struct pixman_f_transform f_scaled;
 | |
| 	    f_scaled = *f_transform;
 | |
| 	    RRTransformRescale(&f_scaled, 16384.0);
 | |
| 	    pixman_transform_from_pixman_f_transform(transform, &f_scaled);
 | |
| 	}
 | |
| 	return TRUE;
 | |
|     }
 | |
| }
 |