beta-0.89.2
[luatex.git] / source / libs / pixman / pixman-src / pixman / pixman-filter.c
blobb2bf53fed147b7cffab3c74f8922376ceac14977
1 /*
2 * Copyright 2012, Red Hat, Inc.
3 * Copyright 2012, Soren Sandmann
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
24 * Author: Soren Sandmann <soren.sandmann@gmail.com>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <math.h>
30 #include <assert.h>
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34 #include "pixman-private.h"
36 typedef double (* kernel_func_t) (double x);
38 typedef struct
40 pixman_kernel_t kernel;
41 kernel_func_t func;
42 double width;
43 } filter_info_t;
45 static double
46 impulse_kernel (double x)
48 return (x == 0.0)? 1.0 : 0.0;
51 static double
52 box_kernel (double x)
54 return 1;
57 static double
58 linear_kernel (double x)
60 return 1 - fabs (x);
63 static double
64 gaussian_kernel (double x)
66 #define SQRT2 (1.4142135623730950488016887242096980785696718753769480)
67 #define SIGMA (SQRT2 / 2.0)
69 return exp (- x * x / (2 * SIGMA * SIGMA)) / (SIGMA * sqrt (2.0 * M_PI));
72 static double
73 sinc (double x)
75 if (x == 0.0)
76 return 1.0;
77 else
78 return sin (M_PI * x) / (M_PI * x);
81 static double
82 lanczos (double x, int n)
84 return sinc (x) * sinc (x * (1.0 / n));
87 static double
88 lanczos2_kernel (double x)
90 return lanczos (x, 2);
93 static double
94 lanczos3_kernel (double x)
96 return lanczos (x, 3);
99 static double
100 nice_kernel (double x)
102 return lanczos3_kernel (x * 0.75);
105 static double
106 general_cubic (double x, double B, double C)
108 double ax = fabs(x);
110 if (ax < 1)
112 return ((12 - 9 * B - 6 * C) * ax * ax * ax +
113 (-18 + 12 * B + 6 * C) * ax * ax + (6 - 2 * B)) / 6;
115 else if (ax >= 1 && ax < 2)
117 return ((-B - 6 * C) * ax * ax * ax +
118 (6 * B + 30 * C) * ax * ax + (-12 * B - 48 * C) *
119 ax + (8 * B + 24 * C)) / 6;
121 else
123 return 0;
127 static double
128 cubic_kernel (double x)
130 /* This is the Mitchell-Netravali filter.
132 * (0.0, 0.5) would give us the Catmull-Rom spline,
133 * but that one seems to be indistinguishable from Lanczos2.
135 return general_cubic (x, 1/3.0, 1/3.0);
138 static const filter_info_t filters[] =
140 { PIXMAN_KERNEL_IMPULSE, impulse_kernel, 0.0 },
141 { PIXMAN_KERNEL_BOX, box_kernel, 1.0 },
142 { PIXMAN_KERNEL_LINEAR, linear_kernel, 2.0 },
143 { PIXMAN_KERNEL_CUBIC, cubic_kernel, 4.0 },
144 { PIXMAN_KERNEL_GAUSSIAN, gaussian_kernel, 6 * SIGMA },
145 { PIXMAN_KERNEL_LANCZOS2, lanczos2_kernel, 4.0 },
146 { PIXMAN_KERNEL_LANCZOS3, lanczos3_kernel, 6.0 },
147 { PIXMAN_KERNEL_LANCZOS3_STRETCHED, nice_kernel, 8.0 },
150 /* This function scales @kernel2 by @scale, then
151 * aligns @x1 in @kernel1 with @x2 in @kernel2 and
152 * and integrates the product of the kernels across @width.
154 * This function assumes that the intervals are within
155 * the kernels in question. E.g., the caller must not
156 * try to integrate a linear kernel ouside of [-1:1]
158 static double
159 integral (pixman_kernel_t kernel1, double x1,
160 pixman_kernel_t kernel2, double scale, double x2,
161 double width)
163 /* If the integration interval crosses zero, break it into
164 * two separate integrals. This ensures that filters such
165 * as LINEAR that are not differentiable at 0 will still
166 * integrate properly.
168 if (x1 < 0 && x1 + width > 0)
170 return
171 integral (kernel1, x1, kernel2, scale, x2, - x1) +
172 integral (kernel1, 0, kernel2, scale, x2 - x1, width + x1);
174 else if (x2 < 0 && x2 + width > 0)
176 return
177 integral (kernel1, x1, kernel2, scale, x2, - x2) +
178 integral (kernel1, x1 - x2, kernel2, scale, 0, width + x2);
180 else if (kernel1 == PIXMAN_KERNEL_IMPULSE)
182 assert (width == 0.0);
183 return filters[kernel2].func (x2 * scale);
185 else if (kernel2 == PIXMAN_KERNEL_IMPULSE)
187 assert (width == 0.0);
188 return filters[kernel1].func (x1);
190 else
192 /* Integration via Simpson's rule */
193 #define N_SEGMENTS 128
194 #define SAMPLE(a1, a2) \
195 (filters[kernel1].func ((a1)) * filters[kernel2].func ((a2) * scale))
197 double s = 0.0;
198 double h = width / (double)N_SEGMENTS;
199 int i;
201 s = SAMPLE (x1, x2);
203 for (i = 1; i < N_SEGMENTS; i += 2)
205 double a1 = x1 + h * i;
206 double a2 = x2 + h * i;
208 s += 2 * SAMPLE (a1, a2);
210 if (i >= 2 && i < N_SEGMENTS - 1)
211 s += 4 * SAMPLE (a1, a2);
214 s += SAMPLE (x1 + width, x2 + width);
216 return h * s * (1.0 / 3.0);
220 static pixman_fixed_t *
221 create_1d_filter (int *width,
222 pixman_kernel_t reconstruct,
223 pixman_kernel_t sample,
224 double scale,
225 int n_phases)
227 pixman_fixed_t *params, *p;
228 double step;
229 double size;
230 int i;
232 size = scale * filters[sample].width + filters[reconstruct].width;
233 *width = ceil (size);
235 p = params = malloc (*width * n_phases * sizeof (pixman_fixed_t));
236 if (!params)
237 return NULL;
239 step = 1.0 / n_phases;
241 for (i = 0; i < n_phases; ++i)
243 double frac = step / 2.0 + i * step;
244 pixman_fixed_t new_total;
245 int x, x1, x2;
246 double total;
248 /* Sample convolution of reconstruction and sampling
249 * filter. See rounding.txt regarding the rounding
250 * and sample positions.
253 x1 = ceil (frac - *width / 2.0 - 0.5);
254 x2 = x1 + *width;
256 total = 0;
257 for (x = x1; x < x2; ++x)
259 double pos = x + 0.5 - frac;
260 double rlow = - filters[reconstruct].width / 2.0;
261 double rhigh = rlow + filters[reconstruct].width;
262 double slow = pos - scale * filters[sample].width / 2.0;
263 double shigh = slow + scale * filters[sample].width;
264 double c = 0.0;
265 double ilow, ihigh;
267 if (rhigh >= slow && rlow <= shigh)
269 ilow = MAX (slow, rlow);
270 ihigh = MIN (shigh, rhigh);
272 c = integral (reconstruct, ilow,
273 sample, 1.0 / scale, ilow - pos,
274 ihigh - ilow);
277 total += c;
278 *p++ = (pixman_fixed_t)(c * 65536.0 + 0.5);
281 /* Normalize */
282 p -= *width;
283 total = 1 / total;
284 new_total = 0;
285 for (x = x1; x < x2; ++x)
287 pixman_fixed_t t = (*p) * total + 0.5;
289 new_total += t;
290 *p++ = t;
293 if (new_total != pixman_fixed_1)
294 *(p - *width / 2) += (pixman_fixed_1 - new_total);
297 return params;
300 /* Create the parameter list for a SEPARABLE_CONVOLUTION filter
301 * with the given kernels and scale parameters
303 PIXMAN_EXPORT pixman_fixed_t *
304 pixman_filter_create_separable_convolution (int *n_values,
305 pixman_fixed_t scale_x,
306 pixman_fixed_t scale_y,
307 pixman_kernel_t reconstruct_x,
308 pixman_kernel_t reconstruct_y,
309 pixman_kernel_t sample_x,
310 pixman_kernel_t sample_y,
311 int subsample_bits_x,
312 int subsample_bits_y)
314 double sx = fabs (pixman_fixed_to_double (scale_x));
315 double sy = fabs (pixman_fixed_to_double (scale_y));
316 pixman_fixed_t *horz = NULL, *vert = NULL, *params = NULL;
317 int subsample_x, subsample_y;
318 int width, height;
320 subsample_x = (1 << subsample_bits_x);
321 subsample_y = (1 << subsample_bits_y);
323 horz = create_1d_filter (&width, reconstruct_x, sample_x, sx, subsample_x);
324 vert = create_1d_filter (&height, reconstruct_y, sample_y, sy, subsample_y);
326 if (!horz || !vert)
327 goto out;
329 *n_values = 4 + width * subsample_x + height * subsample_y;
331 params = malloc (*n_values * sizeof (pixman_fixed_t));
332 if (!params)
333 goto out;
335 params[0] = pixman_int_to_fixed (width);
336 params[1] = pixman_int_to_fixed (height);
337 params[2] = pixman_int_to_fixed (subsample_bits_x);
338 params[3] = pixman_int_to_fixed (subsample_bits_y);
340 memcpy (params + 4, horz,
341 width * subsample_x * sizeof (pixman_fixed_t));
342 memcpy (params + 4 + width * subsample_x, vert,
343 height * subsample_y * sizeof (pixman_fixed_t));
345 out:
346 free (horz);
347 free (vert);
349 return params;