Edit

IABSD.fr/xenocara/xserver/randr/rrtransform.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2012-06-10 13:21:05
    Hash : e60da745
    Message : Update to xserver 1.12.2. tested by naddy@, krw@, mpi@.

  • xserver/randr/rrtransform.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;
        }
    }