Gentoo Archives: gentoo-commits

From: "Ben de Groot (yngwin)" <yngwin@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-x86 commit in app-text/poppler/files: poppler-0.12.3-cairo-downscale.patch
Date: Tue, 16 Feb 2010 15:42:21
Message-Id: E1NhP8j-0005ot-TF@stork.gentoo.org
1 yngwin 10/02/16 15:15:05
2
3 Added: poppler-0.12.3-cairo-downscale.patch
4 Log:
5 Take 2 for cairo downscale patch from upstream, fixes bug 303817.
6 (Portage version: 2.2_rc62/cvs/Linux x86_64)
7
8 Revision Changes Path
9 1.1 app-text/poppler/files/poppler-0.12.3-cairo-downscale.patch
10
11 file : http://sources.gentoo.org/viewcvs.py/gentoo-x86/app-text/poppler/files/poppler-0.12.3-cairo-downscale.patch?rev=1.1&view=markup
12 plain: http://sources.gentoo.org/viewcvs.py/gentoo-x86/app-text/poppler/files/poppler-0.12.3-cairo-downscale.patch?rev=1.1&content-type=text/plain
13
14 Index: poppler-0.12.3-cairo-downscale.patch
15 ===================================================================
16 diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
17 index 9a0f3be..42ac3a8 100644
18 --- a/poppler/CairoOutputDev.cc
19 +++ b/poppler/CairoOutputDev.cc
20 @@ -58,6 +58,7 @@
21 #include <splash/SplashBitmap.h>
22 #include "CairoOutputDev.h"
23 #include "CairoFontEngine.h"
24 +#include "CairoRescaleBox.h"
25 //------------------------------------------------------------------------
26
27 // #define LOG_CAIRO
28 @@ -1331,6 +1332,82 @@ void CairoOutputDev::endMaskClip(GfxState *state) {
29 clearSoftMask(state);
30 }
31
32 +cairo_surface_t *CairoOutputDev::downscaleSurface(cairo_surface_t *orig_surface) {
33 + cairo_surface_t *dest_surface;
34 + unsigned char *dest_buffer;
35 + int dest_stride;
36 + unsigned char *orig_buffer;
37 + int orig_width, orig_height;
38 + int orig_stride;
39 + GBool res;
40 +
41 + if (printing)
42 + return NULL;
43 +
44 + cairo_matrix_t matrix;
45 + cairo_get_matrix(cairo, &matrix);
46 +
47 + /* this whole computation should be factored out */
48 + double xScale = matrix.xx;
49 + double yScale = matrix.yy;
50 + int tx, tx2, ty, ty2; /* the integer co-oridinates of the resulting image */
51 + int scaledHeight;
52 + int scaledWidth;
53 + if (xScale >= 0) {
54 + tx = splashRound(matrix.x0 - 0.01);
55 + tx2 = splashRound(matrix.x0 + xScale + 0.01) - 1;
56 + } else {
57 + tx = splashRound(matrix.x0 + 0.01) - 1;
58 + tx2 = splashRound(matrix.x0 + xScale - 0.01);
59 + }
60 + scaledWidth = abs(tx2 - tx) + 1;
61 + //scaledWidth = splashRound(fabs(xScale));
62 + if (scaledWidth == 0) {
63 + // technically, this should draw nothing, but it generally seems
64 + // better to draw a one-pixel-wide stripe rather than throwing it
65 + // away
66 + scaledWidth = 1;
67 + }
68 + if (yScale >= 0) {
69 + ty = splashFloor(matrix.y0 + 0.01);
70 + ty2 = splashCeil(matrix.y0 + yScale - 0.01);
71 + } else {
72 + ty = splashCeil(matrix.y0 - 0.01);
73 + ty2 = splashFloor(matrix.y0 + yScale + 0.01);
74 + }
75 + scaledHeight = abs(ty2 - ty);
76 + if (scaledHeight == 0) {
77 + scaledHeight = 1;
78 + }
79 +
80 + orig_width = cairo_image_surface_get_width (orig_surface);
81 + orig_height = cairo_image_surface_get_height (orig_surface);
82 + if (scaledWidth >= orig_width || scaledHeight >= orig_height)
83 + return NULL;
84 +
85 + dest_surface = cairo_surface_create_similar (orig_surface,
86 + cairo_surface_get_content (orig_surface),
87 + scaledWidth, scaledHeight);
88 + dest_buffer = cairo_image_surface_get_data (dest_surface);
89 + dest_stride = cairo_image_surface_get_stride (dest_surface);
90 +
91 + orig_buffer = cairo_image_surface_get_data (orig_surface);
92 + orig_stride = cairo_image_surface_get_stride (orig_surface);
93 +
94 + res = downscale_box_filter((uint32_t *)orig_buffer,
95 + orig_stride, orig_width, orig_height,
96 + scaledWidth, scaledHeight, 0, 0,
97 + scaledWidth, scaledHeight,
98 + (uint32_t *)dest_buffer, dest_stride);
99 + if (!res) {
100 + cairo_surface_destroy (dest_surface);
101 + return NULL;
102 + }
103 +
104 + return dest_surface;
105 +
106 +}
107 +
108 void CairoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
109 int width, int height, GBool invert,
110 GBool interpolate, GBool inlineImg) {
111 @@ -2094,6 +2171,18 @@ void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
112 }
113 gfree(lookup);
114
115 + cairo_surface_t *scaled_surface;
116 +
117 + scaled_surface = downscaleSurface (image);
118 + if (scaled_surface) {
119 + if (cairo_surface_status (scaled_surface))
120 + goto cleanup;
121 + cairo_surface_destroy (image);
122 + image = scaled_surface;
123 + width = cairo_image_surface_get_width (image);
124 + height = cairo_image_surface_get_height (image);
125 + }
126 +
127 cairo_surface_mark_dirty (image);
128 pattern = cairo_pattern_create_for_surface (image);
129 cairo_surface_destroy (image);
130 diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
131 index fb9c0d7..266f0cb 100644
132 --- a/poppler/CairoOutputDev.h
133 +++ b/poppler/CairoOutputDev.h
134 @@ -268,6 +268,7 @@ public:
135
136 protected:
137 void doPath(cairo_t *cairo, GfxState *state, GfxPath *path);
138 + cairo_surface_t *downscaleSurface(cairo_surface_t *orig_surface);
139
140 GfxRGB fill_color, stroke_color;
141 cairo_pattern_t *fill_pattern, *stroke_pattern;
142 diff --git a/poppler/CairoRescaleBox.cc b/poppler/CairoRescaleBox.cc
143 new file mode 100644
144 index 0000000..dce5ddd
145 --- /dev/null
146 +++ b/poppler/CairoRescaleBox.cc
147 @@ -0,0 +1,352 @@
148 +/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */
149 +/*
150 + * Copyright © 2009 Mozilla Corporation
151 + *
152 + * Permission to use, copy, modify, distribute, and sell this software and its
153 + * documentation for any purpose is hereby granted without fee, provided that
154 + * the above copyright notice appear in all copies and that both that
155 + * copyright notice and this permission notice appear in supporting
156 + * documentation, and that the name of Mozilla Corporation not be used in
157 + * advertising or publicity pertaining to distribution of the software without
158 + * specific, written prior permission. Mozilla Corporation makes no
159 + * representations about the suitability of this software for any purpose. It
160 + * is provided "as is" without express or implied warranty.
161 + *
162 + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
163 + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
164 + * SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
165 + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
166 + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
167 + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
168 + * OF THIS SOFTWARE.
169 + *
170 + * Author: Jeff Muizelaar, Mozilla Corp.
171 + */
172 +
173 +/* This implements a box filter that supports non-integer box sizes */
174 +
175 +#ifdef HAVE_CONFIG_H
176 +#include <config.h>
177 +#endif
178 +
179 +#include <stdint.h>
180 +#include <stdio.h>
181 +#include <assert.h>
182 +#include <stdlib.h>
183 +#include <math.h>
184 +#include "goo/gmem.h"
185 +#include "CairoRescaleBox.h"
186 +
187 +typedef unsigned short int uint16_t;
188 +typedef unsigned int uint32_t;
189 +
190 +/* we work in fixed point where 1. == 1 << 24 */
191 +#define FIXED_SHIFT 24
192 +
193 +static void downsample_row_box_filter (
194 + int start, int width,
195 + uint32_t *src, uint32_t *dest,
196 + int coverage[], int pixel_coverage)
197 +{
198 + /* we need an array of the pixel contribution of each destination pixel on the boundaries.
199 + * we invert the value to get the value on the other size of the box */
200 + /*
201 +
202 + value = a * contribution * 1/box_size
203 + value += a * 1/box_size
204 + value += a * 1/box_size
205 + value += a * 1/box_size
206 + value += a * (1 - contribution) * 1/box_size
207 + a * (1/box_size - contribution * 1/box_size)
208 +
209 + box size is constant
210 +
211 +
212 + value = a * contribtion_a * 1/box_size + b * contribution_b * 1/box_size
213 + contribution_b = (1 - contribution_a)
214 + = (1 - contribution_a_next)
215 + */
216 +
217 + /* box size = ceil(src_width/dest_width) */
218 + int x = 0;
219 +
220 + /* skip to start */
221 + /* XXX: it might be possible to do this directly instead of iteratively, however
222 + * the iterative solution is simple */
223 + while (x < start)
224 + {
225 + int box = 1 << FIXED_SHIFT;
226 + int start_coverage = coverage[x];
227 + box -= start_coverage;
228 + src++;
229 + while (box >= pixel_coverage)
230 + {
231 + src++;
232 + box -= pixel_coverage;
233 + }
234 + x++;
235 + }
236 +
237 + while (x < start + width)
238 + {
239 + uint32_t a = 0;
240 + uint32_t r = 0;
241 + uint32_t g = 0;
242 + uint32_t b = 0;
243 + int box = 1 << FIXED_SHIFT;
244 + int start_coverage = coverage[x];
245 +
246 + a = ((*src >> 24) & 0xff) * start_coverage;
247 + r = ((*src >> 16) & 0xff) * start_coverage;
248 + g = ((*src >> 8) & 0xff) * start_coverage;
249 + b = ((*src >> 0) & 0xff) * start_coverage;
250 + src++;
251 + x++;
252 + box -= start_coverage;
253 +
254 + while (box >= pixel_coverage)
255 + {
256 + a += ((*src >> 24) & 0xff) * pixel_coverage;
257 + r += ((*src >> 16) & 0xff) * pixel_coverage;
258 + g += ((*src >> 8) & 0xff) * pixel_coverage;
259 + b += ((*src >> 0) & 0xff) * pixel_coverage;
260 + src++;
261 +
262 + box -= pixel_coverage;
263 + }
264 +
265 + /* multiply by whatever is leftover
266 + * this ensures that we don't bias down.
267 + * i.e. start_coverage + n*pixel_coverage + box == 1 << 24 */
268 + if (box > 0)
269 + {
270 + a += ((*src >> 24) & 0xff) * box;
271 + r += ((*src >> 16) & 0xff) * box;
272 + g += ((*src >> 8) & 0xff) * box;
273 + b += ((*src >> 0) & 0xff) * box;
274 + }
275 +
276 + a >>= FIXED_SHIFT;
277 + r >>= FIXED_SHIFT;
278 + g >>= FIXED_SHIFT;
279 + b >>= FIXED_SHIFT;
280 +
281 + *dest = (a << 24) | (r << 16) | (g << 8) | b;
282 + dest++;
283 + }
284 +}
285 +
286 +static void downsample_columns_box_filter (
287 + int n,
288 + int start_coverage,
289 + int pixel_coverage,
290 + uint32_t *src, uint32_t *dest)
291 +{
292 + int stride = n;
293 + while (n--) {
294 + uint32_t a = 0;
295 + uint32_t r = 0;
296 + uint32_t g = 0;
297 + uint32_t b = 0;
298 + uint32_t *column_src = src;
299 + int box = 1 << FIXED_SHIFT;
300 +
301 + a = ((*column_src >> 24) & 0xff) * start_coverage;
302 + r = ((*column_src >> 16) & 0xff) * start_coverage;
303 + g = ((*column_src >> 8) & 0xff) * start_coverage;
304 + b = ((*column_src >> 0) & 0xff) * start_coverage;
305 + column_src += stride;
306 + box -= start_coverage;
307 +
308 + while (box >= pixel_coverage)
309 + {
310 + a += ((*column_src >> 24) & 0xff) * pixel_coverage;
311 + r += ((*column_src >> 16) & 0xff) * pixel_coverage;
312 + g += ((*column_src >> 8) & 0xff) * pixel_coverage;
313 + b += ((*column_src >> 0) & 0xff) * pixel_coverage;
314 + column_src += stride;
315 + box -= pixel_coverage;
316 + }
317 +
318 + if (box > 0) {
319 + a += ((*column_src >> 24) & 0xff) * box;
320 + r += ((*column_src >> 16) & 0xff) * box;
321 + g += ((*column_src >> 8) & 0xff) * box;
322 + b += ((*column_src >> 0) & 0xff) * box;
323 + }
324 +
325 + a >>= FIXED_SHIFT;
326 + r >>= FIXED_SHIFT;
327 + g >>= FIXED_SHIFT;
328 + b >>= FIXED_SHIFT;
329 +
330 + *dest = (a << 24) | (r << 16) | (g << 8) | b;
331 + dest++;
332 + src++;
333 + }
334 +}
335 +
336 +static int compute_coverage (int coverage[], int src_length, int dest_length)
337 +{
338 + int i;
339 + /* num = src_length/dest_length
340 + total = sum(pixel) / num
341 +
342 + pixel * 1/num == pixel * dest_length / src_length
343 + */
344 + /* the average contribution of each source pixel */
345 + int ratio = ((1 << 24)*(long long int)dest_length)/src_length;
346 + /* because ((1 << 24)*(long long int)dest_length) won't always be divisible by src_length
347 + * we'll need someplace to put the other bits.
348 + *
349 + * We want to ensure a + n*ratio < 1<<24
350 + *
351 + * 1<<24
352 + * */
353 +
354 + double scale = (double)src_length/dest_length;
355 +
356 + /* for each destination pixel compute the coverage of the left most pixel included in the box */
357 + /* I have a proof of this, which this margin is too narrow to contain */
358 + for (i=0; i<dest_length; i++)
359 + {
360 + float left_side = i*scale;
361 + float right_side = (i+1)*scale;
362 + float right_fract = right_side - floor (right_side);
363 + float left_fract = ceil (left_side) - left_side;
364 + int overage;
365 + /* find out how many source pixels will be used to fill the box */
366 + int count = floor (right_side) - ceil (left_side);
367 + /* what's the maximum value this expression can become?
368 + floor((i+1)*scale) - ceil(i*scale)
369 +
370 + (i+1)*scale - i*scale == scale
371 +
372 + since floor((i+1)*scale) <= (i+1)*scale
373 + and ceil(i*scale) >= i*scale
374 +
375 + floor((i+1)*scale) - ceil(i*scale) <= scale
376 +
377 + further since: floor((i+1)*scale) - ceil(i*scale) is an integer
378 +
379 + therefore:
380 + floor((i+1)*scale) - ceil(i*scale) <= floor(scale)
381 + */
382 +
383 + if (left_fract == 0.)
384 + count--;
385 +
386 + /* compute how much the right-most pixel contributes */
387 + overage = ratio*(right_fract);
388 +
389 + /* the remainder is the the amount that the left-most pixel
390 + * contributes */
391 + coverage[i] = (1<<24) - (count * ratio + overage);
392 + }
393 +
394 + return ratio;
395 +}
396 +
397 +GBool downscale_box_filter(uint32_t *orig, int orig_stride, unsigned orig_width, unsigned orig_height,
398 + signed scaled_width, signed scaled_height,
399 + uint16_t start_column, uint16_t start_row,
400 + uint16_t width, uint16_t height,
401 + uint32_t *dest, int dst_stride)
402 +{
403 + int pixel_coverage_x, pixel_coverage_y;
404 + int dest_y;
405 + int src_y = 0;
406 + uint32_t *scanline = orig;
407 + int *x_coverage = NULL;
408 + int *y_coverage = NULL;
409 + uint32_t *temp_buf = NULL;
410 + GBool retval = gFalse;
411 +
412 + x_coverage = (int *)gmallocn3 (orig_width, 1, sizeof(int));
413 + y_coverage = (int *)gmallocn3 (orig_height, 1, sizeof(int));
414 +
415 + /* we need to allocate enough room for ceil(src_height/dest_height)+1
416 + Example:
417 + src_height = 140
418 + dest_height = 50
419 + src_height/dest_height = 2.8
420 +
421 + |-------------| 2.8 pixels
422 + |----|----|----|----| 4 pixels
423 + need to sample 3 pixels
424 +
425 + |-------------| 2.8 pixels
426 + |----|----|----|----| 4 pixels
427 + need to sample 4 pixels
428 + */
429 +
430 + temp_buf = (uint32_t *)gmallocn3 ((orig_height + scaled_height-1)/scaled_height+1, scaled_width, sizeof(uint32_t));
431 +
432 + if (!x_coverage || !y_coverage || !scanline || !temp_buf)
433 + goto cleanup;
434 +
435 + pixel_coverage_x = compute_coverage (x_coverage, orig_width, scaled_width);
436 + pixel_coverage_y = compute_coverage (y_coverage, orig_height, scaled_height);
437 +
438 + assert (width + start_column <= scaled_width);
439 +
440 + /* skip the rows at the beginning */
441 + for (dest_y = 0; dest_y < start_row; dest_y++)
442 + {
443 + int box = 1 << FIXED_SHIFT;
444 + int start_coverage_y = y_coverage[dest_y];
445 + box -= start_coverage_y;
446 + src_y++;
447 + while (box >= pixel_coverage_y)
448 + {
449 + box -= pixel_coverage_y;
450 + src_y++;
451 + }
452 + }
453 +
454 + for (; dest_y < start_row + height; dest_y++)
455 + {
456 + int columns = 0;
457 + int box = 1 << FIXED_SHIFT;
458 + int start_coverage_y = y_coverage[dest_y];
459 +
460 + scanline = orig + src_y * orig_stride / 4;
461 + downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
462 + columns++;
463 + src_y++;
464 + box -= start_coverage_y;
465 +
466 + while (box >= pixel_coverage_y)
467 + {
468 + scanline = orig + src_y * orig_stride / 4;
469 + downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
470 + columns++;
471 + src_y++;
472 + box -= pixel_coverage_y;
473 + }
474 +
475 + /* downsample any leftovers */
476 + if (box > 0)
477 + {
478 + scanline = orig + src_y * orig_stride / 4;
479 + downsample_row_box_filter (start_column, width, scanline, temp_buf + width * columns, x_coverage, pixel_coverage_x);
480 + columns++;
481 + }
482 +
483 + /* now scale the rows we just downsampled in the y direction */
484 + downsample_columns_box_filter (width, start_coverage_y, pixel_coverage_y, temp_buf, dest);
485 + dest += dst_stride / 4;
486 +
487 +// assert(width*columns <= ((orig_height + scaled_height-1)/scaled_height+1) * width);
488 + }
489 +// assert (src_y<=orig_height);
490 +
491 + retval = gTrue;
492 +
493 +cleanup:
494 + free (x_coverage);
495 + free (y_coverage);
496 + free (temp_buf);
497 +
498 + return gTrue;
499 +}
500 diff --git a/poppler/CairoRescaleBox.h b/poppler/CairoRescaleBox.h
501 new file mode 100644
502 index 0000000..5349c87
503 --- /dev/null
504 +++ b/poppler/CairoRescaleBox.h
505 @@ -0,0 +1,12 @@
506 +#ifndef CAIRO_RESCALE_BOX_H
507 +#define CAIRO_RESCALE_BOX_H
508 +
509 +#include "goo/gtypes.h"
510 +
511 +GBool downscale_box_filter(unsigned int *orig, int orig_stride, unsigned orig_width, unsigned orig_height,
512 + signed scaled_width, signed scaled_height,
513 + unsigned short int start_column, unsigned short int start_row,
514 + unsigned short int width, unsigned short int height,
515 + unsigned int *dest, int dst_stride);
516 +
517 +#endif /* CAIRO_RESCALE_BOX_H */
518 diff --git a/poppler/Makefile.am b/poppler/Makefile.am
519 index ec79e31..096ea76 100644
520 --- a/poppler/Makefile.am
521 +++ b/poppler/Makefile.am
522 @@ -47,7 +47,9 @@ libpoppler_cairo_la_SOURCES = \
523 CairoFontEngine.cc \
524 CairoFontEngine.h \
525 CairoOutputDev.cc \
526 - CairoOutputDev.h
527 + CairoOutputDev.h \
528 + CairoRescaleBox.cc \
529 + CairoRescaleBox.h
530
531 endif
532
533 diff --git a/glib/CMakeLists.txt b/glib/CMakeLists.txt
534 index 6ed9523..ceef25e 100644
535 --- a/glib/CMakeLists.txt
536 +++ b/glib/CMakeLists.txt
537 @@ -90,6 +90,7 @@ if (CAIRO_FOUND)
538 set(poppler_glib_SRCS ${poppler_glib_SRCS}
539 ${CMAKE_SOURCE_DIR}/poppler/CairoFontEngine.cc
540 ${CMAKE_SOURCE_DIR}/poppler/CairoOutputDev.cc
541 + ${CMAKE_SOURCE_DIR}/poppler/CairoRescaleBox.cc
542 )
543 endif (CAIRO_FOUND)
544 add_library(poppler-glib SHARED ${poppler_glib_SRCS})