Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | ||
26 | void | |
27 | RRTransformInit(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 | ||
37 | void | |
38 | RRTransformFini(RRTransformPtr transform) | |
39 | { | |
40 | free(transform->params); | |
41 | } | |
42 | ||
43 | Bool | |
44 | RRTransformEqual(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 | ||
65 | Bool | |
66 | RRTransformSetFilter(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 = malloc(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 | ||
89 | Bool | |
90 | RRTransformCopy(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 | ||
116 | static void | |
117 | RRTransformRescale(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 = abs(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 | */ | |
139 | Bool | |
140 | RRTransformCompute(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(-1); | |
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(-1); | |
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(-1); | |
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(-1); | |
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 | } |