103b705cfSriastradh/*
203b705cfSriastradh * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.  All Rights Reserved.
303b705cfSriastradh * Copyright (c) 2005 Jesse Barnes <jbarnes@virtuousgeek.org>
403b705cfSriastradh * Copyright © 2010 Intel Corporation
503b705cfSriastradh *
603b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a
703b705cfSriastradh * copy of this software and associated documentation files (the "Software"),
803b705cfSriastradh * to deal in the Software without restriction, including without limitation
903b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1003b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the
1103b705cfSriastradh * Software is furnished to do so, subject to the following conditions:
1203b705cfSriastradh *
1303b705cfSriastradh * The above copyright notice and this permission notice (including the next
1403b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the
1503b705cfSriastradh * Software.
1603b705cfSriastradh *
1703b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1803b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1903b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2003b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2103b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2203b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2303b705cfSriastradh * SOFTWARE.
2403b705cfSriastradh *
2503b705cfSriastradh * Authors:
2603b705cfSriastradh *    Jesse Barns <jbarnes@virtuousgeek.org>
2703b705cfSriastradh *    Chris Wilson <chris@chris-wilson.co.uk>
2803b705cfSriastradh */
2903b705cfSriastradh
3003b705cfSriastradh#ifdef HAVE_CONFIG_H
3103b705cfSriastradh#include "config.h"
3203b705cfSriastradh#endif
3303b705cfSriastradh
3403b705cfSriastradh#include "sna.h"
3503b705cfSriastradh
3603b705cfSriastradh/**
3703b705cfSriastradh * Returns whether the provided transform is affine.
3803b705cfSriastradh *
3903b705cfSriastradh * transform may be null.
4003b705cfSriastradh */
4103b705cfSriastradhbool sna_transform_is_affine(const PictTransform *t)
4203b705cfSriastradh{
4303b705cfSriastradh	if (t == NULL)
4403b705cfSriastradh		return true;
4503b705cfSriastradh
4603b705cfSriastradh	return t->matrix[2][0] == 0 && t->matrix[2][1] == 0;
4703b705cfSriastradh}
4803b705cfSriastradh
4903b705cfSriastradhbool
5003b705cfSriastradhsna_transform_is_translation(const PictTransform *t,
5103b705cfSriastradh			     pixman_fixed_t *tx,
5203b705cfSriastradh			     pixman_fixed_t *ty)
5303b705cfSriastradh{
5403b705cfSriastradh	if (t == NULL) {
5503b705cfSriastradh		*tx = *ty = 0;
5603b705cfSriastradh		return true;
5703b705cfSriastradh	}
5803b705cfSriastradh
5903b705cfSriastradh	if (t->matrix[0][0] != IntToxFixed(1) ||
6003b705cfSriastradh	    t->matrix[0][1] != 0 ||
6103b705cfSriastradh	    t->matrix[1][0] != 0 ||
6203b705cfSriastradh	    t->matrix[1][1] != IntToxFixed(1) ||
6303b705cfSriastradh	    t->matrix[2][0] != 0 ||
6403b705cfSriastradh	    t->matrix[2][1] != 0 ||
6503b705cfSriastradh	    t->matrix[2][2] != IntToxFixed(1))
6603b705cfSriastradh		return false;
6703b705cfSriastradh
6803b705cfSriastradh	*tx = t->matrix[0][2];
6903b705cfSriastradh	*ty = t->matrix[1][2];
7003b705cfSriastradh	return true;
7103b705cfSriastradh}
7203b705cfSriastradh
7303b705cfSriastradhbool
7403b705cfSriastradhsna_transform_is_integer_translation(const PictTransform *t, int16_t *tx, int16_t *ty)
7503b705cfSriastradh{
7603b705cfSriastradh	if (t == NULL) {
7703b705cfSriastradh		*tx = *ty = 0;
7803b705cfSriastradh		return true;
7903b705cfSriastradh	}
8003b705cfSriastradh
8103b705cfSriastradh	if (t->matrix[0][0] != IntToxFixed(1) ||
8203b705cfSriastradh	    t->matrix[0][1] != 0 ||
8303b705cfSriastradh	    t->matrix[1][0] != 0 ||
8403b705cfSriastradh	    t->matrix[1][1] != IntToxFixed(1) ||
8503b705cfSriastradh	    t->matrix[2][0] != 0 ||
8603b705cfSriastradh	    t->matrix[2][1] != 0 ||
8703b705cfSriastradh	    t->matrix[2][2] != IntToxFixed(1))
8803b705cfSriastradh		return false;
8903b705cfSriastradh
9003b705cfSriastradh	if (pixman_fixed_fraction(t->matrix[0][2]) ||
9103b705cfSriastradh	    pixman_fixed_fraction(t->matrix[1][2]))
9203b705cfSriastradh		return false;
9303b705cfSriastradh
9403b705cfSriastradh	*tx = pixman_fixed_to_int(t->matrix[0][2]);
9503b705cfSriastradh	*ty = pixman_fixed_to_int(t->matrix[1][2]);
9603b705cfSriastradh	return true;
9703b705cfSriastradh}
9803b705cfSriastradh
9942542f5fSchristosbool
10042542f5fSchristossna_transform_is_imprecise_integer_translation(const PictTransform *t,
10142542f5fSchristos					       int filter, bool precise,
10242542f5fSchristos					       int16_t *tx, int16_t *ty)
10342542f5fSchristos{
10442542f5fSchristos	if (t == NULL) {
10542542f5fSchristos		DBG(("%s: no transform\n", __FUNCTION__));
10642542f5fSchristos		*tx = *ty = 0;
10742542f5fSchristos		return true;
10842542f5fSchristos	}
10942542f5fSchristos
11042542f5fSchristos	DBG(("%s: FilterNearest?=%d, precise?=%d, transform=[%f %f %f, %f %f %f, %f %f %f]\n",
11142542f5fSchristos	     __FUNCTION__, filter==PictFilterNearest, precise,
11242542f5fSchristos	     t->matrix[0][0]/65536., t->matrix[0][1]/65536., t->matrix[0][2]/65536.,
11342542f5fSchristos	     t->matrix[1][0]/65536., t->matrix[1][1]/65536., t->matrix[1][2]/65536.,
11442542f5fSchristos	     t->matrix[2][0]/65536., t->matrix[2][1]/65536., t->matrix[2][2]/65536.));
11542542f5fSchristos
11642542f5fSchristos	if (t->matrix[0][0] != IntToxFixed(1) ||
11742542f5fSchristos	    t->matrix[0][1] != 0 ||
11842542f5fSchristos	    t->matrix[1][0] != 0 ||
11942542f5fSchristos	    t->matrix[1][1] != IntToxFixed(1) ||
12042542f5fSchristos	    t->matrix[2][0] != 0 ||
12142542f5fSchristos	    t->matrix[2][1] != 0 ||
12242542f5fSchristos	    t->matrix[2][2] != IntToxFixed(1)) {
12342542f5fSchristos		DBG(("%s: not unity scaling\n", __FUNCTION__));
12442542f5fSchristos		return false;
12542542f5fSchristos	}
12642542f5fSchristos
12742542f5fSchristos	if (filter != PictFilterNearest) {
12842542f5fSchristos		if (precise) {
12942542f5fSchristos			if (pixman_fixed_fraction(t->matrix[0][2]) ||
13042542f5fSchristos			    pixman_fixed_fraction(t->matrix[1][2])) {
13142542f5fSchristos				DBG(("%s: precise, fractional translation\n", __FUNCTION__));
13242542f5fSchristos				return false;
13342542f5fSchristos			}
13442542f5fSchristos		} else {
13542542f5fSchristos			int f;
13642542f5fSchristos
13742542f5fSchristos			f = pixman_fixed_fraction(t->matrix[0][2]);
13813496ba1Ssnj			if (f > IntToxFixed(1)/4 && f < IntToxFixed(3)/4) {
13913496ba1Ssnj				DBG(("%s: imprecise, fractional translation X: %x\n", __FUNCTION__, f));
14042542f5fSchristos				return false;
14142542f5fSchristos			}
14242542f5fSchristos
14342542f5fSchristos			f = pixman_fixed_fraction(t->matrix[1][2]);
14413496ba1Ssnj			if (f > IntToxFixed(1)/4 && f < IntToxFixed(3)/4) {
14513496ba1Ssnj				DBG(("%s: imprecise, fractional translation Y: %x\n", __FUNCTION__, f));
14642542f5fSchristos				return false;
14742542f5fSchristos			}
14842542f5fSchristos		}
14942542f5fSchristos	}
15042542f5fSchristos
15142542f5fSchristos	*tx = pixman_fixed_to_int(t->matrix[0][2] + IntToxFixed(1)/2);
15242542f5fSchristos	*ty = pixman_fixed_to_int(t->matrix[1][2] + IntToxFixed(1)/2);
15342542f5fSchristos	return true;
15442542f5fSchristos}
15542542f5fSchristos
15603b705cfSriastradh/**
15703b705cfSriastradh * Returns the floating-point coordinates transformed by the given transform.
15803b705cfSriastradh */
15903b705cfSriastradhvoid
16003b705cfSriastradhsna_get_transformed_coordinates(int x, int y,
16103b705cfSriastradh			       	const PictTransform *transform,
16203b705cfSriastradh				float *x_out, float *y_out)
16303b705cfSriastradh{
16403b705cfSriastradh	if (transform == NULL) {
16503b705cfSriastradh		*x_out = x;
16603b705cfSriastradh		*y_out = y;
16703b705cfSriastradh	} else
16803b705cfSriastradh		_sna_get_transformed_coordinates(x, y, transform, x_out, y_out);
16903b705cfSriastradh}
17003b705cfSriastradh
17103b705cfSriastradh/**
17203b705cfSriastradh * Returns the un-normalized floating-point coordinates transformed by the given transform.
17303b705cfSriastradh */
17403b705cfSriastradhvoid
17503b705cfSriastradhsna_get_transformed_coordinates_3d(int x, int y,
17603b705cfSriastradh				   const PictTransform *transform,
17703b705cfSriastradh				   float *x_out, float *y_out, float *w_out)
17803b705cfSriastradh{
17903b705cfSriastradh	if (transform == NULL) {
18003b705cfSriastradh		*x_out = x;
18103b705cfSriastradh		*y_out = y;
18203b705cfSriastradh		*w_out = 1;
18303b705cfSriastradh	} else {
18403b705cfSriastradh		int64_t result[3];
18503b705cfSriastradh
18603b705cfSriastradh		if (_sna_transform_point(transform, x, y, result)) {
18703b705cfSriastradh			*x_out = result[0] / 65536.;
18803b705cfSriastradh			*y_out = result[1] / 65536.;
18903b705cfSriastradh			*w_out = result[2] / 65536.;
19003b705cfSriastradh		} else {
19103b705cfSriastradh			*x_out = *y_out = 0;
19203b705cfSriastradh			*w_out = 1.;
19303b705cfSriastradh		}
19403b705cfSriastradh	}
19503b705cfSriastradh}
196