11176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/* 21176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright 2012, Red Hat, Inc. 31176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Copyright 2012, Soren Sandmann 41176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 51176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Permission is hereby granted, free of charge, to any person obtaining a 61176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * copy of this software and associated documentation files (the "Software"), 71176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * to deal in the Software without restriction, including without limitation 81176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * the rights to use, copy, modify, merge, publish, distribute, sublicense, 91176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * and/or sell copies of the Software, and to permit persons to whom the 101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Software is furnished to do so, subject to the following conditions: 111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * The above copyright notice and this permission notice (including the next 131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * paragraph) shall be included in all copies or substantial portions of the 141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Software. 151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * DEALINGS IN THE SOFTWARE. 231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * Author: Soren Sandmann <soren.sandmann@gmail.com> 251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */ 261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <string.h> 271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <stdlib.h> 281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <stdio.h> 291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <math.h> 301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <assert.h> 311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include <config.h> 321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#include "pixman-private.h" 331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 341176bdada62cabc6ec4b0308a930e83b679d5d36John Recktypedef double (* kernel_func_t) (double x); 351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 361176bdada62cabc6ec4b0308a930e83b679d5d36John Recktypedef struct 371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_kernel_t kernel; 391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck kernel_func_t func; 401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double width; 411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} filter_info_t; 421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 431176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 441176bdada62cabc6ec4b0308a930e83b679d5d36John Reckimpulse_kernel (double x) 451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return (x == 0.0)? 1.0 : 0.0; 471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 491176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 501176bdada62cabc6ec4b0308a930e83b679d5d36John Reckbox_kernel (double x) 511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return 1; 531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 551176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 561176bdada62cabc6ec4b0308a930e83b679d5d36John Recklinear_kernel (double x) 571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return 1 - fabs (x); 591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 611176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 621176bdada62cabc6ec4b0308a930e83b679d5d36John Reckgaussian_kernel (double x) 631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define SQRT2 (1.4142135623730950488016887242096980785696718753769480) 651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define SIGMA (SQRT2 / 2.0) 661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return exp (- x * x / (2 * SIGMA * SIGMA)) / (SIGMA * sqrt (2.0 * M_PI)); 681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 701176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 711176bdada62cabc6ec4b0308a930e83b679d5d36John Recksinc (double x) 721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (x == 0.0) 741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return 1.0; 751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck else 761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return sin (M_PI * x) / (M_PI * x); 771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 791176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 801176bdada62cabc6ec4b0308a930e83b679d5d36John Recklanczos (double x, int n) 811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return sinc (x) * sinc (x * (1.0 / n)); 831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 851176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 861176bdada62cabc6ec4b0308a930e83b679d5d36John Recklanczos2_kernel (double x) 871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return lanczos (x, 2); 891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 911176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 921176bdada62cabc6ec4b0308a930e83b679d5d36John Recklanczos3_kernel (double x) 931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return lanczos (x, 3); 951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 971176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 981176bdada62cabc6ec4b0308a930e83b679d5d36John Recknice_kernel (double x) 991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return lanczos3_kernel (x * 0.75); 1011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 1021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1031176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 1041176bdada62cabc6ec4b0308a930e83b679d5d36John Reckgeneral_cubic (double x, double B, double C) 1051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double ax = fabs(x); 1071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (ax < 1) 1091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return ((12 - 9 * B - 6 * C) * ax * ax * ax + 1111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck (-18 + 12 * B + 6 * C) * ax * ax + (6 - 2 * B)) / 6; 1121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck else if (ax >= 1 && ax < 2) 1141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return ((-B - 6 * C) * ax * ax * ax + 1161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck (6 * B + 30 * C) * ax * ax + (-12 * B - 48 * C) * 1171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck ax + (8 * B + 24 * C)) / 6; 1181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck else 1201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return 0; 1221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 1241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1251176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 1261176bdada62cabc6ec4b0308a930e83b679d5d36John Reckcubic_kernel (double x) 1271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck /* This is the Mitchell-Netravali filter. 1291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 1301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * (0.0, 0.5) would give us the Catmull-Rom spline, 1311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * but that one seems to be indistinguishable from Lanczos2. 1321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */ 1331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return general_cubic (x, 1/3.0, 1/3.0); 1341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 1351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1361176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic const filter_info_t filters[] = 1371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { PIXMAN_KERNEL_IMPULSE, impulse_kernel, 0.0 }, 1391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { PIXMAN_KERNEL_BOX, box_kernel, 1.0 }, 1401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { PIXMAN_KERNEL_LINEAR, linear_kernel, 2.0 }, 1411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { PIXMAN_KERNEL_CUBIC, cubic_kernel, 4.0 }, 1421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { PIXMAN_KERNEL_GAUSSIAN, gaussian_kernel, 6 * SIGMA }, 1431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { PIXMAN_KERNEL_LANCZOS2, lanczos2_kernel, 4.0 }, 1441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { PIXMAN_KERNEL_LANCZOS3, lanczos3_kernel, 6.0 }, 1451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { PIXMAN_KERNEL_LANCZOS3_STRETCHED, nice_kernel, 8.0 }, 1461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck}; 1471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/* This function scales @kernel2 by @scale, then 1491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * aligns @x1 in @kernel1 with @x2 in @kernel2 and 1501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * and integrates the product of the kernels across @width. 1511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * 1521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * This function assumes that the intervals are within 1531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * the kernels in question. E.g., the caller must not 1541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * try to integrate a linear kernel ouside of [-1:1] 1551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */ 1561176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic double 1571176bdada62cabc6ec4b0308a930e83b679d5d36John Reckintegral (pixman_kernel_t kernel1, double x1, 1581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_kernel_t kernel2, double scale, double x2, 1591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double width) 1601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 1611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck /* If the integration interval crosses zero, break it into 1621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * two separate integrals. This ensures that filters such 1631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * as LINEAR that are not differentiable at 0 will still 1641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * integrate properly. 1651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */ 1661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (x1 < 0 && x1 + width > 0) 1671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return 1691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck integral (kernel1, x1, kernel2, scale, x2, - x1) + 1701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck integral (kernel1, 0, kernel2, scale, x2 - x1, width + x1); 1711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck else if (x2 < 0 && x2 + width > 0) 1731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return 1751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck integral (kernel1, x1, kernel2, scale, x2, - x2) + 1761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck integral (kernel1, x1 - x2, kernel2, scale, 0, width + x2); 1771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck else if (kernel1 == PIXMAN_KERNEL_IMPULSE) 1791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck assert (width == 0.0); 1811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return filters[kernel2].func (x2 * scale); 1821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck else if (kernel2 == PIXMAN_KERNEL_IMPULSE) 1841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck assert (width == 0.0); 1861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return filters[kernel1].func (x1); 1871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 1881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck else 1891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 1901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck /* Integration via Simpson's rule */ 1911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define N_SEGMENTS 128 1921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck#define SAMPLE(a1, a2) \ 1931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck (filters[kernel1].func ((a1)) * filters[kernel2].func ((a2) * scale)) 1941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double s = 0.0; 1961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double h = width / (double)N_SEGMENTS; 1971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int i; 1981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 1991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck s = SAMPLE (x1, x2); 2001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2011176bdada62cabc6ec4b0308a930e83b679d5d36John Reck for (i = 1; i < N_SEGMENTS; i += 2) 2021176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 2031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double a1 = x1 + h * i; 2041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double a2 = x2 + h * i; 2051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck s += 2 * SAMPLE (a1, a2); 2071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (i >= 2 && i < N_SEGMENTS - 1) 2091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck s += 4 * SAMPLE (a1, a2); 2101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 2111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck s += SAMPLE (x1 + width, x2 + width); 2131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return h * s * (1.0 / 3.0); 2151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 2161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 2171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2181176bdada62cabc6ec4b0308a930e83b679d5d36John Reckstatic pixman_fixed_t * 2191176bdada62cabc6ec4b0308a930e83b679d5d36John Reckcreate_1d_filter (int *width, 2201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_kernel_t reconstruct, 2211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_kernel_t sample, 2221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double scale, 2231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int n_phases) 2241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 2251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_fixed_t *params, *p; 2261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double step; 2271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double size; 2281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int i; 2291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck size = scale * filters[sample].width + filters[reconstruct].width; 2311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *width = ceil (size); 2321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck p = params = malloc (*width * n_phases * sizeof (pixman_fixed_t)); 2341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (!params) 2351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return NULL; 2361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck step = 1.0 / n_phases; 2381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck for (i = 0; i < n_phases; ++i) 2401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 2411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double frac = step / 2.0 + i * step; 2421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_fixed_t new_total; 2431176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int x, x1, x2; 2441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double total; 2451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck /* Sample convolution of reconstruction and sampling 2471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * filter. See rounding.txt regarding the rounding 2481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * and sample positions. 2491176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */ 2501176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2511176bdada62cabc6ec4b0308a930e83b679d5d36John Reck x1 = ceil (frac - *width / 2.0 - 0.5); 2521176bdada62cabc6ec4b0308a930e83b679d5d36John Reck x2 = x1 + *width; 2531176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2541176bdada62cabc6ec4b0308a930e83b679d5d36John Reck total = 0; 2551176bdada62cabc6ec4b0308a930e83b679d5d36John Reck for (x = x1; x < x2; ++x) 2561176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 2571176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double pos = x + 0.5 - frac; 2581176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double rlow = - filters[reconstruct].width / 2.0; 2591176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double rhigh = rlow + filters[reconstruct].width; 2601176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double slow = pos - scale * filters[sample].width / 2.0; 2611176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double shigh = slow + scale * filters[sample].width; 2621176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double c = 0.0; 2631176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double ilow, ihigh; 2641176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2651176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (rhigh >= slow && rlow <= shigh) 2661176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 2671176bdada62cabc6ec4b0308a930e83b679d5d36John Reck ilow = MAX (slow, rlow); 2681176bdada62cabc6ec4b0308a930e83b679d5d36John Reck ihigh = MIN (shigh, rhigh); 2691176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2701176bdada62cabc6ec4b0308a930e83b679d5d36John Reck c = integral (reconstruct, ilow, 2711176bdada62cabc6ec4b0308a930e83b679d5d36John Reck sample, 1.0 / scale, ilow - pos, 2721176bdada62cabc6ec4b0308a930e83b679d5d36John Reck ihigh - ilow); 2731176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 2741176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2751176bdada62cabc6ec4b0308a930e83b679d5d36John Reck total += c; 2761176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *p++ = (pixman_fixed_t)(c * 65535.0 + 0.5); 2771176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 2781176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2791176bdada62cabc6ec4b0308a930e83b679d5d36John Reck /* Normalize */ 2801176bdada62cabc6ec4b0308a930e83b679d5d36John Reck p -= *width; 2811176bdada62cabc6ec4b0308a930e83b679d5d36John Reck total = 1 / total; 2821176bdada62cabc6ec4b0308a930e83b679d5d36John Reck new_total = 0; 2831176bdada62cabc6ec4b0308a930e83b679d5d36John Reck for (x = x1; x < x2; ++x) 2841176bdada62cabc6ec4b0308a930e83b679d5d36John Reck { 2851176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_fixed_t t = (*p) * total + 0.5; 2861176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2871176bdada62cabc6ec4b0308a930e83b679d5d36John Reck new_total += t; 2881176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *p++ = t; 2891176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 2901176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2911176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (new_total != pixman_fixed_1) 2921176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *(p - *width / 2) += (pixman_fixed_1 - new_total); 2931176bdada62cabc6ec4b0308a930e83b679d5d36John Reck } 2941176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2951176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return params; 2961176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 2971176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 2981176bdada62cabc6ec4b0308a930e83b679d5d36John Reck/* Create the parameter list for a SEPARABLE_CONVOLUTION filter 2991176bdada62cabc6ec4b0308a930e83b679d5d36John Reck * with the given kernels and scale parameters 3001176bdada62cabc6ec4b0308a930e83b679d5d36John Reck */ 3011176bdada62cabc6ec4b0308a930e83b679d5d36John ReckPIXMAN_EXPORT pixman_fixed_t * 3021176bdada62cabc6ec4b0308a930e83b679d5d36John Reckpixman_filter_create_separable_convolution (int *n_values, 3031176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_fixed_t scale_x, 3041176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_fixed_t scale_y, 3051176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_kernel_t reconstruct_x, 3061176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_kernel_t reconstruct_y, 3071176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_kernel_t sample_x, 3081176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_kernel_t sample_y, 3091176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int subsample_bits_x, 3101176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int subsample_bits_y) 3111176bdada62cabc6ec4b0308a930e83b679d5d36John Reck{ 3121176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double sx = fabs (pixman_fixed_to_double (scale_x)); 3131176bdada62cabc6ec4b0308a930e83b679d5d36John Reck double sy = fabs (pixman_fixed_to_double (scale_y)); 3141176bdada62cabc6ec4b0308a930e83b679d5d36John Reck pixman_fixed_t *horz = NULL, *vert = NULL, *params = NULL; 3151176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int subsample_x, subsample_y; 3161176bdada62cabc6ec4b0308a930e83b679d5d36John Reck int width, height; 3171176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3181176bdada62cabc6ec4b0308a930e83b679d5d36John Reck subsample_x = (1 << subsample_bits_x); 3191176bdada62cabc6ec4b0308a930e83b679d5d36John Reck subsample_y = (1 << subsample_bits_y); 3201176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3211176bdada62cabc6ec4b0308a930e83b679d5d36John Reck horz = create_1d_filter (&width, reconstruct_x, sample_x, sx, subsample_x); 3221176bdada62cabc6ec4b0308a930e83b679d5d36John Reck vert = create_1d_filter (&height, reconstruct_y, sample_y, sy, subsample_y); 3231176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3241176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (!horz || !vert) 3251176bdada62cabc6ec4b0308a930e83b679d5d36John Reck goto out; 3261176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3271176bdada62cabc6ec4b0308a930e83b679d5d36John Reck *n_values = 4 + width * subsample_x + height * subsample_y; 3281176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3291176bdada62cabc6ec4b0308a930e83b679d5d36John Reck params = malloc (*n_values * sizeof (pixman_fixed_t)); 3301176bdada62cabc6ec4b0308a930e83b679d5d36John Reck if (!params) 3311176bdada62cabc6ec4b0308a930e83b679d5d36John Reck goto out; 3321176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3331176bdada62cabc6ec4b0308a930e83b679d5d36John Reck params[0] = pixman_int_to_fixed (width); 3341176bdada62cabc6ec4b0308a930e83b679d5d36John Reck params[1] = pixman_int_to_fixed (height); 3351176bdada62cabc6ec4b0308a930e83b679d5d36John Reck params[2] = pixman_int_to_fixed (subsample_bits_x); 3361176bdada62cabc6ec4b0308a930e83b679d5d36John Reck params[3] = pixman_int_to_fixed (subsample_bits_y); 3371176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3381176bdada62cabc6ec4b0308a930e83b679d5d36John Reck memcpy (params + 4, horz, 3391176bdada62cabc6ec4b0308a930e83b679d5d36John Reck width * subsample_x * sizeof (pixman_fixed_t)); 3401176bdada62cabc6ec4b0308a930e83b679d5d36John Reck memcpy (params + 4 + width * subsample_x, vert, 3411176bdada62cabc6ec4b0308a930e83b679d5d36John Reck height * subsample_y * sizeof (pixman_fixed_t)); 3421176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3431176bdada62cabc6ec4b0308a930e83b679d5d36John Reckout: 3441176bdada62cabc6ec4b0308a930e83b679d5d36John Reck free (horz); 3451176bdada62cabc6ec4b0308a930e83b679d5d36John Reck free (vert); 3461176bdada62cabc6ec4b0308a930e83b679d5d36John Reck 3471176bdada62cabc6ec4b0308a930e83b679d5d36John Reck return params; 3481176bdada62cabc6ec4b0308a930e83b679d5d36John Reck} 349