--- /tmp/config.h.in 2006-12-23 00:00:38.000000000 +0100 +++ gtk+-2.10.6/config.h.in 2006-12-23 00:01:05.632227000 +0100 @@ -253,3 +253,7 @@ /* Define to `int' if doesn't define. */ #undef uid_t + +/* Define to use integer math rather than floating point where possible. */ +#undef ENABLE_INTEGER_PIXOPS + --- /tmp/configure.in 2006-12-23 00:02:16.000000000 +0100 +++ gtk+-2.10.6/configure.in 2006-12-23 00:05:11.172227000 +0100 @@ -203,6 +203,15 @@ [AC_HELP_STRING([--disable-rebuilds], [disable all source autogeneration rules])],, [enable_rebuilds=yes]) +AC_ARG_ENABLE(integer-pixops, + [AC_HELP_STRING([--enable-integer-pixops], + [use integer math where possible])],, + [enable_integer_pixops=no]) + +if test "x$enable_integer_pixops" = "xyes"; then + AC_DEFINE(ENABLE_INTEGER_PIXOPS) +fi + AC_ARG_ENABLE(visibility, [AC_HELP_STRING([--disable-visibility], [don't use ELF visibility attributes])],, --- /tmp/pixops.c 2006-12-23 10:04:02.000000000 +0100 +++ gtk+-2.10.6/gdk-pixbuf/pixops/pixops.c 2006-12-23 10:04:21.772227000 +0100 @@ -28,6 +28,10 @@ #define SUBSAMPLE_MASK ((1 << SUBSAMPLE_BITS)-1) #define SCALE_SHIFT 16 +#ifdef ENABLE_INTEGER_PIXOPS +#define FRAC 0x10000ULL +#endif + typedef struct _PixopsFilter PixopsFilter; typedef struct _PixopsFilterDimension PixopsFilterDimension; @@ -972,6 +976,29 @@ (*pixel_func) (dest, dest_x, dest_channels, dest_has_alpha, src_has_alpha, check_size, color1, color2, r, g, b, a); } +#ifdef ENABLE_INTEGER_PIXOPS + +static void +correct_total (int *weights, + int n_x, + int n_y, + int total, + unsigned long overall_alpha) +{ + int correction = (int)(overall_alpha - total); + int i; + for (i = n_x * n_y - 1; i >= 0; i--) + { + if (*(weights + i) + correction >= 0) + { + *(weights + i) += correction; + break; + } + } +} + +#else + static void correct_total (int *weights, int n_x, @@ -998,6 +1025,8 @@ } } +#endif + static int * make_filter_table (PixopsFilter *filter) { @@ -1026,7 +1055,11 @@ *(pixel_weights + n_x * i + j) = weight; } - correct_total (pixel_weights, n_x, n_y, total, filter->overall_alpha); +#ifdef ENABLE_INTEGER_PIXOPS + correct_total (pixel_weights, n_x, n_y, total, overall_alpha * FRAC); +#else + correct_total (pixel_weights, n_x, n_y, total, overall_alpha); +#endif } return weights; @@ -1178,6 +1211,93 @@ /* Compute weights for reconstruction by replication followed by * sampling with a box filter */ +#ifdef ENABLE_INTEGER_PIXOPS + +static void +tile_make_weights (PixopsFilter *filter, double x_scale_d, double y_scale_d, double overall_alpha_d) +{ + int i_offset, j_offset; + unsigned long x_scale = x_scale_d * FRAC; + unsigned long y_scale = y_scale_d * FRAC; + unsigned long overall_alpha = overall_alpha_d * FRAC; + unsigned long x_scale_r = FRAC / x_scale; + unsigned long y_scale_r = FRAC / y_scale; + + int n_x = ceil(1/x_scale_d + 1); + int n_y = ceil(1/y_scale_d + 1); + + filter->x_offset = 0; + filter->y_offset = 0; + filter->n_x = n_x; + filter->n_y = n_y; + filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y); + + for (i_offset=0; i_offsetweights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y; + unsigned long x = j_offset * FRAC / SUBSAMPLE; + unsigned long y = i_offset * FRAC / SUBSAMPLE; + int i,j; + int total = 0; + + for (i = 0; i < n_y; i++) + { + unsigned long tw, th; + + if (i < y) + { + + if (i + FRAC > y) + th = MIN(i+FRAC, y + y_scale_r) - y; + else + th = 0; + } + else + { + if (y + FRAC/y_scale > i) + th = MIN(i+FRAC, y + y_scale_r) - i; + else + th = 0; + } + + for (j = 0; j < n_x; j++) + { + int weight; + + if (j < x) + { + if (j + FRAC > x) + tw = MIN(j+FRAC, x + x_scale_r) - x; + else + tw = 0; + } + else + { + if (x + FRAC/x_scale > j) + tw = MIN(j+FRAC, x + x_scale_r) - j; + else + tw = 0; + } + + { + unsigned long lweight = (tw * x_scale) / FRAC; + lweight = (lweight * th) / FRAC; + lweight = (lweight * y_scale) / FRAC; + lweight = (lweight * overall_alpha) / FRAC; + weight = lweight; + } + total += weight; + *(pixel_weights + n_x * i + j) = weight; + } + } + + correct_total (pixel_weights, n_x, n_y, total, overall_alpha); + } +} + +#else + static void tile_make_weights (PixopsFilterDimension *dim, double scale) @@ -1216,10 +1336,151 @@ } } +#endif + /* Compute weights for a filter that, for minification * is the same as 'tiles', and for magnification, is bilinear * reconstruction followed by a sampling with a delta function. */ +#ifdef ENABLE_INTEGER_PIXOPS + +static void +bilinear_magnify_make_weights (PixopsFilter *filter, double x_scale_d, double y_scale_d, double overall_alpha_d) +{ + int i_offset, j_offset; + unsigned long *x_weights, *y_weights; + int n_x, n_y; + unsigned long x_scale = x_scale_d * FRAC; + unsigned long y_scale = y_scale_d * FRAC; + unsigned long overall_alpha = overall_alpha_d * FRAC; + unsigned long x_scale_r = (FRAC / x_scale_d); + unsigned long y_scale_r = (FRAC / y_scale_d); + + if (x_scale > FRAC) /* Bilinear */ + { + n_x = 2; + filter->x_offset = 0.5 * (1/x_scale_d - 1); + } + else /* Tile */ + { + n_x = ceil(1.0 + 1.0/x_scale_d); + filter->x_offset = 0.0; + } + + if (y_scale > FRAC) /* Bilinear */ + { + n_y = 2; + filter->y_offset = 0.5 * (1/y_scale_d - 1); + } + else /* Tile */ + { + n_y = ceil(1.0 + 1.0/y_scale_d); + filter->y_offset = 0.0; + } + + filter->n_y = n_y; + filter->n_x = n_x; + filter->weights = g_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y); + + x_weights = g_new (unsigned long, n_x); + y_weights = g_new (unsigned long, n_y); + + for (i_offset=0; i_offsetweights + ((i_offset*SUBSAMPLE) + j_offset) * n_x * n_y; + unsigned long x = j_offset * FRAC / SUBSAMPLE; + unsigned long y = i_offset * FRAC / SUBSAMPLE; + int i,j; + int total = 0; + + if (x_scale > FRAC) /* Bilinear */ + { + for (i = 0; i < n_x; i++) + { + /* x_weights[i] = ((i == 0) ? (1 - x) : x) / x_scale; */ + unsigned long w = (((i == 0) ? (FRAC - x) : x) * x_scale_r); + x_weights[i] = w / FRAC; + } + } + else /* Tile */ + { + /* x + * ---------|--.-|----|--.-|------- SRC + * ------------|---------|--------- DEST + */ + for (i = 0; i < n_x; i++) + { + if (i < x) + { + if (i + 1 > x) + x_weights[i] = MIN(FRAC*(i+1), FRAC * x + (((unsigned long long)(FRAC * FRAC)) / (unsigned long)x_scale)) - (x * FRAC); + else + x_weights[i] = 0; + } + else + { + if (x + 1/x_scale > i) + x_weights[i] = MIN(FRAC*(i+1), FRAC * x + (((unsigned long long)(FRAC * FRAC)) / (unsigned long)x_scale)) - (i * FRAC); + else + x_weights[i] = 0; + } + } + } + + if (y_scale > FRAC) /* Bilinear */ + { + for (i = 0; i < n_y; i++) + { + unsigned long w = ((unsigned long)((i == 0) ? (FRAC - y) : y) * y_scale_r); + y_weights[i] = w / FRAC; + } + } + else /* Tile */ + { + /* y + * ---------|--.-|----|--.-|------- SRC + * ------------|---------|--------- DEST + */ + for (i = 0; i < n_y; i++) + { + if (i < y) + { + if (i + 1 > y) + y_weights[i] = MIN(FRAC*(i+1), FRAC * y + (FRAC * FRAC / (unsigned long)y_scale)) - (y * FRAC); + else + y_weights[i] = 0; + } + else + { + if (y + 1/y_scale > i) + y_weights[i] = MIN(FRAC*(i+1), FRAC * y + (FRAC * FRAC / (unsigned long)y_scale)) - (i * FRAC); + else + y_weights[i] = 0; + } + } + } + + for (i = 0; i < n_y; i++) + for (j = 0; j < n_x; j++) + { + unsigned long long weight = (x_weights[j] * x_scale) / FRAC; + weight = (weight * y_weights[i]) / FRAC; + weight = (weight * y_scale) / FRAC; + weight = (weight * overall_alpha) / FRAC; + *(pixel_weights + n_x * i + j) = (unsigned long)weight; + total += (unsigned long)weight; + } + + correct_total (pixel_weights, n_x, n_y, total, overall_alpha); + } + + g_free (x_weights); + g_free (y_weights); +} + +#else + static void bilinear_magnify_make_weights (PixopsFilterDimension *dim, double scale) @@ -1283,6 +1544,8 @@ } } +#endif + /* Computes the integral from b0 to b1 of * * f(x) = x; 0 <= x < 1