a patch for ttc fonts with bad index
[luatex.git] / source / libs / poppler / poppler-0.36.0 / poppler / CairoRescaleBox.cc
blob3c96f45e5d3cbaf6f452cb8b2369a499b80fe596
1 /* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
2 /*
3 * Copyright © 2009 Mozilla Corporation
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Mozilla Corporation not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission. Mozilla Corporation makes no
12 * representations about the suitability of this software for any purpose. It
13 * is provided "as is" without express or implied warranty.
15 * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
17 * SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 * OF THIS SOFTWARE.
23 * Author: Jeff Muizelaar, Mozilla Corp.
26 //========================================================================
28 // Modified under the Poppler project - http://poppler.freedesktop.org
30 // All changes made under the Poppler project to this file are licensed
31 // under GPL version 2 or later
33 // Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
34 // Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
36 // To see a description of the changes please see the Changelog file that
37 // came with your tarball or type make ChangeLog if you are building from git
39 //========================================================================
42 /* This implements a box filter that supports non-integer box sizes */
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif
48 #include <stdint.h>
49 #include <stdio.h>
50 #include <assert.h>
51 #include <stdlib.h>
52 #include <math.h>
53 #include "goo/gmem.h"
54 #include "goo/gtypes_p.h"
55 #include "CairoRescaleBox.h"
58 /* we work in fixed point where 1. == 1 << 24 */
59 #define FIXED_SHIFT 24
62 static void downsample_row_box_filter (
63 int start, int width,
64 uint32_t *src, uint32_t *dest,
65 int coverage[], int pixel_coverage)
67 /* we need an array of the pixel contribution of each destination pixel on the boundaries.
68 * we invert the value to get the value on the other size of the box */
71 value = a * contribution * 1/box_size
72 value += a * 1/box_size
73 value += a * 1/box_size
74 value += a * 1/box_size
75 value += a * (1 - contribution) * 1/box_size
76 a * (1/box_size - contribution * 1/box_size)
78 box size is constant
81 value = a * contribtion_a * 1/box_size + b * contribution_b * 1/box_size
82 contribution_b = (1 - contribution_a)
83 = (1 - contribution_a_next)
86 /* box size = ceil(src_width/dest_width) */
87 int x = 0;
89 /* skip to start */
90 /* XXX: it might be possible to do this directly instead of iteratively, however
91 * the iterative solution is simple */
92 while (x < start)
94 int box = 1 << FIXED_SHIFT;
95 int start_coverage = coverage[x];
96 box -= start_coverage;
97 src++;
98 while (box >= pixel_coverage)
100 src++;
101 box -= pixel_coverage;
103 x++;
106 while (x < start + width)
108 uint32_t a = 0;
109 uint32_t r = 0;
110 uint32_t g = 0;
111 uint32_t b = 0;
112 int box = 1 << FIXED_SHIFT;
113 int start_coverage = coverage[x];
115 a = ((*src >> 24) & 0xff) * start_coverage;
116 r = ((*src >> 16) & 0xff) * start_coverage;
117 g = ((*src >> 8) & 0xff) * start_coverage;
118 b = ((*src >> 0) & 0xff) * start_coverage;
119 src++;
120 x++;
121 box -= start_coverage;
123 while (box >= pixel_coverage)
125 a += ((*src >> 24) & 0xff) * pixel_coverage;
126 r += ((*src >> 16) & 0xff) * pixel_coverage;
127 g += ((*src >> 8) & 0xff) * pixel_coverage;
128 b += ((*src >> 0) & 0xff) * pixel_coverage;
129 src++;
131 box -= pixel_coverage;
134 /* multiply by whatever is leftover
135 * this ensures that we don't bias down.
136 * i.e. start_coverage + n*pixel_coverage + box == 1 << 24 */
137 if (box > 0)
139 a += ((*src >> 24) & 0xff) * box;
140 r += ((*src >> 16) & 0xff) * box;
141 g += ((*src >> 8) & 0xff) * box;
142 b += ((*src >> 0) & 0xff) * box;
145 a >>= FIXED_SHIFT;
146 r >>= FIXED_SHIFT;
147 g >>= FIXED_SHIFT;
148 b >>= FIXED_SHIFT;
150 *dest = (a << 24) | (r << 16) | (g << 8) | b;
151 dest++;
155 static void downsample_columns_box_filter (
156 int n,
157 int start_coverage,
158 int pixel_coverage,
159 uint32_t *src, uint32_t *dest)
161 int stride = n;
162 while (n--) {
163 uint32_t a = 0;
164 uint32_t r = 0;
165 uint32_t g = 0;
166 uint32_t b = 0;
167 uint32_t *column_src = src;
168 int box = 1 << FIXED_SHIFT;
170 a = ((*column_src >> 24) & 0xff) * start_coverage;
171 r = ((*column_src >> 16) & 0xff) * start_coverage;
172 g = ((*column_src >> 8) & 0xff) * start_coverage;
173 b = ((*column_src >> 0) & 0xff) * start_coverage;
174 column_src += stride;
175 box -= start_coverage;
177 while (box >= pixel_coverage)
179 a += ((*column_src >> 24) & 0xff) * pixel_coverage;
180 r += ((*column_src >> 16) & 0xff) * pixel_coverage;
181 g += ((*column_src >> 8) & 0xff) * pixel_coverage;
182 b += ((*column_src >> 0) & 0xff) * pixel_coverage;
183 column_src += stride;
184 box -= pixel_coverage;
187 if (box > 0) {
188 a += ((*column_src >> 24) & 0xff) * box;
189 r += ((*column_src >> 16) & 0xff) * box;
190 g += ((*column_src >> 8) & 0xff) * box;
191 b += ((*column_src >> 0) & 0xff) * box;
194 a >>= FIXED_SHIFT;
195 r >>= FIXED_SHIFT;
196 g >>= FIXED_SHIFT;
197 b >>= FIXED_SHIFT;
199 *dest = (a << 24) | (r << 16) | (g << 8) | b;
200 dest++;
201 src++;
205 static int compute_coverage (int coverage[], int src_length, int dest_length)
207 int i;
208 /* num = src_length/dest_length
209 total = sum(pixel) / num
211 pixel * 1/num == pixel * dest_length / src_length
213 /* the average contribution of each source pixel */
214 int ratio = ((1 << 24)*(long long int)dest_length)/src_length;
215 /* because ((1 << 24)*(long long int)dest_length) won't always be divisible by src_length
216 * we'll need someplace to put the other bits.
218 * We want to ensure a + n*ratio < 1<<24
220 * 1<<24
221 * */
223 double scale = (double)src_length/dest_length;
225 /* for each destination pixel compute the coverage of the left most pixel included in the box */
226 /* I have a proof of this, which this margin is too narrow to contain */
227 for (i=0; i<dest_length; i++)
229 float left_side = i*scale;
230 float right_side = (i+1)*scale;
231 float right_fract = right_side - floor (right_side);
232 float left_fract = ceil (left_side) - left_side;
233 int overage;
234 /* find out how many source pixels will be used to fill the box */
235 int count = floor (right_side) - ceil (left_side);
236 /* what's the maximum value this expression can become?
237 floor((i+1)*scale) - ceil(i*scale)
239 (i+1)*scale - i*scale == scale
241 since floor((i+1)*scale) <= (i+1)*scale
242 and ceil(i*scale) >= i*scale
244 floor((i+1)*scale) - ceil(i*scale) <= scale
246 further since: floor((i+1)*scale) - ceil(i*scale) is an integer
248 therefore:
249 floor((i+1)*scale) - ceil(i*scale) <= floor(scale)
252 if (left_fract == 0.)
253 count--;
255 /* compute how much the right-most pixel contributes */
256 overage = ratio*(right_fract);
258 /* the remainder is the the amount that the left-most pixel
259 * contributes */
260 coverage[i] = (1<<24) - (count * ratio + overage);
263 return ratio;
267 GBool CairoRescaleBox::downScaleImage(unsigned orig_width, unsigned orig_height,
268 signed scaled_width, signed scaled_height,
269 unsigned short int start_column, unsigned short int start_row,
270 unsigned short int width, unsigned short int height,
271 cairo_surface_t *dest_surface) {
272 int pixel_coverage_x, pixel_coverage_y;
273 int dest_y;
274 int src_y = 0;
275 uint32_t *scanline;
276 int *x_coverage = NULL;
277 int *y_coverage = NULL;
278 uint32_t *temp_buf = NULL;
279 GBool retval = gFalse;
280 unsigned int *dest;
281 int dst_stride;
283 dest = (unsigned int *)cairo_image_surface_get_data (dest_surface);
284 dst_stride = cairo_image_surface_get_stride (dest_surface);
286 scanline = (uint32_t*)gmallocn3 (orig_width, 1, sizeof(int));
288 x_coverage = (int *)gmallocn3 (orig_width, 1, sizeof(int));
289 y_coverage = (int *)gmallocn3 (orig_height, 1, sizeof(int));
291 /* we need to allocate enough room for ceil(src_height/dest_height)+1
292 Example:
293 src_height = 140
294 dest_height = 50
295 src_height/dest_height = 2.8
297 |-------------| 2.8 pixels
298 |----|----|----|----| 4 pixels
299 need to sample 3 pixels
301 |-------------| 2.8 pixels
302 |----|----|----|----| 4 pixels
303 need to sample 4 pixels
306 temp_buf = (uint32_t *)gmallocn3 ((orig_height + scaled_height-1)/scaled_height+1, scaled_width, sizeof(uint32_t));
308 if (!x_coverage || !y_coverage || !scanline || !temp_buf)
309 goto cleanup;
311 pixel_coverage_x = compute_coverage (x_coverage, orig_width, scaled_width);
312 pixel_coverage_y = compute_coverage (y_coverage, orig_height, scaled_height);
314 assert (width + start_column <= scaled_width);
318 /* skip the rows at the beginning */
319 for (dest_y = 0; dest_y < start_row; dest_y++)
321 int box = 1 << FIXED_SHIFT;
322 int start_coverage_y = y_coverage[dest_y];
323 box -= start_coverage_y;
324 src_y++;
325 while (box >= pixel_coverage_y)
327 box -= pixel_coverage_y;
328 src_y++;
332 for (; dest_y < start_row + height; dest_y++)
334 int columns = 0;
335 int box = 1 << FIXED_SHIFT;
336 int start_coverage_y = y_coverage[dest_y];
338 getRow(src_y, scanline);
339 downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
340 columns++;
341 src_y++;
342 box -= start_coverage_y;
344 while (box >= pixel_coverage_y)
346 getRow(src_y, scanline);
347 downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
348 columns++;
349 src_y++;
350 box -= pixel_coverage_y;
353 /* downsample any leftovers */
354 if (box > 0)
356 getRow(src_y, scanline);
357 downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
358 columns++;
361 /* now scale the rows we just downsampled in the y direction */
362 downsample_columns_box_filter (width, start_coverage_y, pixel_coverage_y, temp_buf, dest);
363 dest += dst_stride / 4;
365 // assert(width*columns <= ((orig_height + scaled_height-1)/scaled_height+1) * width);
367 // assert (src_y<=orig_height);
369 retval = gTrue;
371 cleanup:
372 free (x_coverage);
373 free (y_coverage);
374 free (temp_buf);
375 free (scanline);
377 return retval;