Merge lp:~matttbe/ubuntu/raring/poppler/lp1072129 into lp:ubuntu/raring/poppler

Proposed by Matthieu Baerts
Status: Merged
Merged at revision: 120
Proposed branch: lp:~matttbe/ubuntu/raring/poppler/lp1072129
Merge into: lp:ubuntu/raring/poppler
Diff against target: 3231 lines (+3184/-4)
6 files modified
.pc/applied-patches (+1/-0)
.pc/git_gouraud_shading_support.patch/poppler/CairoOutputDev.cc (+3121/-0)
debian/changelog (+8/-0)
debian/patches/git_gouraud_shading_support.patch (+38/-0)
debian/patches/series (+1/-0)
poppler/CairoOutputDev.cc (+15/-4)
To merge this branch: bzr merge lp:~matttbe/ubuntu/raring/poppler/lp1072129
Reviewer Review Type Date Requested Status
Ubuntu Sponsors Pending
Review via email: mp+134177@code.launchpad.net

Description of the change

Hello,

Due to a bug in poppler, Evince crash when loading some PDF files (LP: #1072129).
This new version simply adds the upstream patch in order to fix this bug.

For more details about this new version, please have a look at this bug #1072129.

Thank you for your help! :)

PS: You can easily test the new version by using these packages:
  - Ubuntu Raring 13.04: https://launchpad.net/~matttbe/+archive/ppa/+sourcepub/2781218/+listing-archive-extra
  - Ubuntu Quantal 12.10: https://launchpad.net/~matttbe/+archive/ppa/+sourcepub/2781220/+listing-archive-extra

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.pc/applied-patches'
--- .pc/applied-patches 2012-08-14 13:11:05 +0000
+++ .pc/applied-patches 2012-11-13 19:26:27 +0000
@@ -1,2 +1,3 @@
1ltmain-as-needed.diff1ltmain-as-needed.diff
2qt4-visibility.diff2qt4-visibility.diff
3git_gouraud_shading_support.patch
34
=== added directory '.pc/git_gouraud_shading_support.patch'
=== added directory '.pc/git_gouraud_shading_support.patch/poppler'
=== added file '.pc/git_gouraud_shading_support.patch/poppler/CairoOutputDev.cc'
--- .pc/git_gouraud_shading_support.patch/poppler/CairoOutputDev.cc 1970-01-01 00:00:00 +0000
+++ .pc/git_gouraud_shading_support.patch/poppler/CairoOutputDev.cc 2012-11-13 19:26:27 +0000
@@ -0,0 +1,3121 @@
1//========================================================================
2//
3// CairoOutputDev.cc
4//
5// Copyright 2003 Glyph & Cog, LLC
6// Copyright 2004 Red Hat, Inc
7//
8//========================================================================
9
10//========================================================================
11//
12// Modified under the Poppler project - http://poppler.freedesktop.org
13//
14// All changes made under the Poppler project to this file are licensed
15// under GPL version 2 or later
16//
17// Copyright (C) 2005-2008 Jeff Muizelaar <jeff@infidigm.net>
18// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
19// Copyright (C) 2005, 2009, 2012 Albert Astals Cid <aacid@kde.org>
20// Copyright (C) 2005 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
21// Copyright (C) 2006-2011 Carlos Garcia Campos <carlosgc@gnome.org>
22// Copyright (C) 2008 Carl Worth <cworth@cworth.org>
23// Copyright (C) 2008-2012 Adrian Johnson <ajohnson@redneon.com>
24// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
25// Copyright (C) 2008, 2009 Chris Wilson <chris@chris-wilson.co.uk>
26// Copyright (C) 2008 Hib Eris <hib@hiberis.nl>
27// Copyright (C) 2009, 2010 David Benjamin <davidben@mit.edu>
28// Copyright (C) 2011, 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
29// Copyright (C) 2012 Patrick Pfeifer <p2000@mailinator.com>
30//
31// To see a description of the changes please see the Changelog file that
32// came with your tarball or type make ChangeLog if you are building from git
33//
34//========================================================================
35
36#include <config.h>
37
38#ifdef USE_GCC_PRAGMAS
39#pragma implementation
40#endif
41
42#include <string.h>
43#include <math.h>
44#include <assert.h>
45#include <cairo.h>
46
47#include "goo/gfile.h"
48#include "goo/gtypes_p.h"
49#include "GlobalParams.h"
50#include "Error.h"
51#include "Object.h"
52#include "Gfx.h"
53#include "GfxState.h"
54#include "GfxFont.h"
55#include "Page.h"
56#include "Link.h"
57#include "FontEncodingTables.h"
58#include "PDFDocEncoding.h"
59#include <fofi/FoFiTrueType.h>
60#include <splash/SplashBitmap.h>
61#include "CairoOutputDev.h"
62#include "CairoFontEngine.h"
63#include "CairoRescaleBox.h"
64#include "UTF8.h"
65//------------------------------------------------------------------------
66
67// #define LOG_CAIRO
68
69#ifdef LOG_CAIRO
70#define LOG(x) (x)
71#else
72#define LOG(x)
73#endif
74
75static inline void printMatrix(cairo_matrix_t *matrix){
76 printf("%f %f, %f %f (%f %f)\n", matrix->xx, matrix->yx,
77 matrix->xy, matrix->yy,
78 matrix->x0, matrix->y0);
79}
80
81
82#define MIN(a,b) (((a) < (b)) ? (a) : (b))
83#define MAX(a,b) (((a) > (b)) ? (a) : (b))
84
85
86//------------------------------------------------------------------------
87// CairoImage
88//------------------------------------------------------------------------
89
90CairoImage::CairoImage (double x1, double y1, double x2, double y2) {
91 this->image = NULL;
92 this->x1 = x1;
93 this->y1 = y1;
94 this->x2 = x2;
95 this->y2 = y2;
96}
97
98CairoImage::~CairoImage () {
99 if (image)
100 cairo_surface_destroy (image);
101}
102
103void CairoImage::setImage (cairo_surface_t *image) {
104 if (this->image)
105 cairo_surface_destroy (this->image);
106 this->image = cairo_surface_reference (image);
107}
108
109//------------------------------------------------------------------------
110// CairoOutputDev
111//------------------------------------------------------------------------
112
113// We cannot tie the lifetime of an FT_Library object to that of
114// CairoOutputDev, since any FT_Faces created with it may end up with a
115// reference by Cairo which can be held long after the CairoOutputDev is
116// deleted. The simplest way to avoid problems is to never tear down the
117// FT_Library instance; to avoid leaks, just use a single global instance
118// initialized the first time it is needed.
119FT_Library CairoOutputDev::ft_lib;
120GBool CairoOutputDev::ft_lib_initialized = gFalse;
121
122CairoOutputDev::CairoOutputDev() {
123 doc = NULL;
124
125 if (!ft_lib_initialized) {
126 FT_Init_FreeType(&ft_lib);
127 ft_lib_initialized = gTrue;
128 }
129
130 fontEngine = NULL;
131 fontEngine_owner = gFalse;
132 glyphs = NULL;
133 fill_pattern = NULL;
134 fill_color.r = fill_color.g = fill_color.b = 0;
135 stroke_pattern = NULL;
136 stroke_color.r = stroke_color.g = stroke_color.b = 0;
137 stroke_opacity = 1.0;
138 fill_opacity = 1.0;
139 textClipPath = NULL;
140 strokePathClip = NULL;
141 cairo = NULL;
142 currentFont = NULL;
143 prescaleImages = gTrue;
144 printing = gTrue;
145 use_show_text_glyphs = gFalse;
146 inType3Char = gFalse;
147 t3_glyph_has_bbox = gFalse;
148
149 groupColorSpaceStack = NULL;
150 maskStack = NULL;
151 group = NULL;
152 mask = NULL;
153 shape = NULL;
154 cairo_shape = NULL;
155 knockoutCount = 0;
156
157 text = NULL;
158 actualText = NULL;
159
160 // the SA parameter supposedly defaults to false, but Acrobat
161 // apparently hardwires it to true
162 stroke_adjust = globalParams->getStrokeAdjust();
163 align_stroke_coords = gFalse;
164 adjusted_stroke_width = gFalse;
165}
166
167CairoOutputDev::~CairoOutputDev() {
168 if (fontEngine_owner && fontEngine) {
169 delete fontEngine;
170 }
171
172 if (cairo)
173 cairo_destroy (cairo);
174 cairo_pattern_destroy (stroke_pattern);
175 cairo_pattern_destroy (fill_pattern);
176 if (group)
177 cairo_pattern_destroy (group);
178 if (mask)
179 cairo_pattern_destroy (mask);
180 if (shape)
181 cairo_pattern_destroy (shape);
182 if (text)
183 text->decRefCnt();
184 if (actualText)
185 delete actualText;
186}
187
188void CairoOutputDev::setCairo(cairo_t *cairo)
189{
190 if (this->cairo != NULL) {
191 cairo_status_t status = cairo_status (this->cairo);
192 if (status) {
193 error(errInternal, -1, "cairo context error: {0:s}\n", cairo_status_to_string(status));
194 }
195 cairo_destroy (this->cairo);
196 assert(!cairo_shape);
197 }
198 if (cairo != NULL) {
199 this->cairo = cairo_reference (cairo);
200 /* save the initial matrix so that we can use it for type3 fonts. */
201 //XXX: is this sufficient? could we miss changes to the matrix somehow?
202 cairo_get_matrix(cairo, &orig_matrix);
203 } else {
204 this->cairo = NULL;
205 this->cairo_shape = NULL;
206 }
207}
208
209void CairoOutputDev::setTextPage(TextPage *text)
210{
211 if (this->text)
212 this->text->decRefCnt();
213 if (actualText)
214 delete actualText;
215 if (text) {
216 this->text = text;
217 this->text->incRefCnt();
218 actualText = new ActualText(text);
219 } else {
220 this->text = NULL;
221 actualText = NULL;
222 }
223}
224
225void CairoOutputDev::startDoc(PDFDoc *docA,
226 CairoFontEngine *parentFontEngine) {
227 doc = docA;
228 if (parentFontEngine) {
229 fontEngine = parentFontEngine;
230 } else {
231 if (fontEngine) {
232 delete fontEngine;
233 }
234 fontEngine = new CairoFontEngine(ft_lib);
235 fontEngine_owner = gTrue;
236 }
237}
238
239void CairoOutputDev::startPage(int pageNum, GfxState *state) {
240 /* set up some per page defaults */
241 cairo_pattern_destroy(fill_pattern);
242 cairo_pattern_destroy(stroke_pattern);
243
244 fill_pattern = cairo_pattern_create_rgb(0., 0., 0.);
245 stroke_pattern = cairo_pattern_reference(fill_pattern);
246
247 if (text)
248 text->startPage(state);
249}
250
251void CairoOutputDev::endPage() {
252 if (text) {
253 text->endPage();
254 text->coalesce(gTrue, 0, gFalse);
255 }
256}
257
258void CairoOutputDev::saveState(GfxState *state) {
259 LOG(printf ("save\n"));
260 cairo_save (cairo);
261 if (cairo_shape)
262 cairo_save (cairo_shape);
263
264 MaskStack *ms = new MaskStack;
265 ms->mask = cairo_pattern_reference(mask);
266 ms->mask_matrix = mask_matrix;
267 ms->next = maskStack;
268 maskStack = ms;
269}
270
271void CairoOutputDev::restoreState(GfxState *state) {
272 LOG(printf ("restore\n"));
273 cairo_restore (cairo);
274 if (cairo_shape)
275 cairo_restore (cairo_shape);
276
277 /* These aren't restored by cairo_restore() since we keep them in
278 * the output device. */
279 updateFillColor(state);
280 updateStrokeColor(state);
281 updateFillOpacity(state);
282 updateStrokeOpacity(state);
283 updateBlendMode(state);
284
285 MaskStack* ms = maskStack;
286 if (ms) {
287 if (mask)
288 cairo_pattern_destroy(mask);
289 mask = ms->mask;
290 mask_matrix = ms->mask_matrix;
291 maskStack = ms->next;
292 delete ms;
293 }
294}
295
296void CairoOutputDev::updateAll(GfxState *state) {
297 updateLineDash(state);
298 updateLineJoin(state);
299 updateLineCap(state);
300 updateLineWidth(state);
301 updateFlatness(state);
302 updateMiterLimit(state);
303 updateFillColor(state);
304 updateStrokeColor(state);
305 updateFillOpacity(state);
306 updateStrokeOpacity(state);
307 updateBlendMode(state);
308 needFontUpdate = gTrue;
309 if (text)
310 text->updateFont(state);
311}
312
313void CairoOutputDev::setDefaultCTM(double *ctm) {
314 cairo_matrix_t matrix;
315 matrix.xx = ctm[0];
316 matrix.yx = ctm[1];
317 matrix.xy = ctm[2];
318 matrix.yy = ctm[3];
319 matrix.x0 = ctm[4];
320 matrix.y0 = ctm[5];
321
322 cairo_transform (cairo, &matrix);
323 if (cairo_shape)
324 cairo_transform (cairo_shape, &matrix);
325
326 OutputDev::setDefaultCTM(ctm);
327}
328
329void CairoOutputDev::updateCTM(GfxState *state, double m11, double m12,
330 double m21, double m22,
331 double m31, double m32) {
332 cairo_matrix_t matrix, invert_matrix;
333 matrix.xx = m11;
334 matrix.yx = m12;
335 matrix.xy = m21;
336 matrix.yy = m22;
337 matrix.x0 = m31;
338 matrix.y0 = m32;
339
340 /* Make sure the matrix is invertible before setting it.
341 * cairo will blow up if we give it a matrix that's not
342 * invertible, so we need to check before passing it
343 * to cairo_transform. Ignoring it is likely to give better
344 * results than not rendering anything at all. See #14398
345 *
346 * Ideally, we could do the cairo_transform
347 * and then check if anything went wrong and fix it then
348 * instead of having to invert the matrix. */
349 invert_matrix = matrix;
350 if (cairo_matrix_invert(&invert_matrix)) {
351 error(errSyntaxWarning, -1, "matrix not invertible\n");
352 return;
353 }
354
355 cairo_transform (cairo, &matrix);
356 if (cairo_shape)
357 cairo_transform (cairo_shape, &matrix);
358 updateLineDash(state);
359 updateLineJoin(state);
360 updateLineCap(state);
361 updateLineWidth(state);
362}
363
364void CairoOutputDev::updateLineDash(GfxState *state) {
365 double *dashPattern;
366 int dashLength;
367 double dashStart;
368
369 state->getLineDash(&dashPattern, &dashLength, &dashStart);
370 cairo_set_dash (cairo, dashPattern, dashLength, dashStart);
371 if (cairo_shape)
372 cairo_set_dash (cairo_shape, dashPattern, dashLength, dashStart);
373}
374
375void CairoOutputDev::updateFlatness(GfxState *state) {
376 // cairo_set_tolerance (cairo, state->getFlatness());
377}
378
379void CairoOutputDev::updateLineJoin(GfxState *state) {
380 switch (state->getLineJoin()) {
381 case 0:
382 cairo_set_line_join (cairo, CAIRO_LINE_JOIN_MITER);
383 break;
384 case 1:
385 cairo_set_line_join (cairo, CAIRO_LINE_JOIN_ROUND);
386 break;
387 case 2:
388 cairo_set_line_join (cairo, CAIRO_LINE_JOIN_BEVEL);
389 break;
390 }
391 if (cairo_shape)
392 cairo_set_line_join (cairo_shape, cairo_get_line_join(cairo));
393}
394
395void CairoOutputDev::updateLineCap(GfxState *state) {
396 switch (state->getLineCap()) {
397 case 0:
398 cairo_set_line_cap (cairo, CAIRO_LINE_CAP_BUTT);
399 break;
400 case 1:
401 cairo_set_line_cap (cairo, CAIRO_LINE_CAP_ROUND);
402 break;
403 case 2:
404 cairo_set_line_cap (cairo, CAIRO_LINE_CAP_SQUARE);
405 break;
406 }
407 if (cairo_shape)
408 cairo_set_line_cap (cairo_shape, cairo_get_line_cap(cairo));
409}
410
411void CairoOutputDev::updateMiterLimit(GfxState *state) {
412 cairo_set_miter_limit (cairo, state->getMiterLimit());
413 if (cairo_shape)
414 cairo_set_miter_limit (cairo_shape, state->getMiterLimit());
415}
416
417void CairoOutputDev::updateLineWidth(GfxState *state) {
418 LOG(printf ("line width: %f\n", state->getLineWidth()));
419 adjusted_stroke_width = gFalse;
420 double width = state->getLineWidth();
421 if (stroke_adjust && !printing) {
422 double x, y;
423 x = y = width;
424
425 /* find out line width in device units */
426 cairo_user_to_device_distance(cairo, &x, &y);
427 if (fabs(x) <= 1.0 && fabs(y) <= 1.0) {
428 /* adjust width to at least one device pixel */
429 x = y = 1.0;
430 cairo_device_to_user_distance(cairo, &x, &y);
431 width = MIN(fabs(x),fabs(y));
432 adjusted_stroke_width = gTrue;
433 }
434 } else if (width == 0.0) {
435 /* Cairo does not support 0 line width == 1 device pixel. Find out
436 * how big pixels (device unit) are in the x and y
437 * directions. Choose the smaller of the two as our line width.
438 */
439 double x = 1.0, y = 1.0;
440 if (printing) {
441 // assume printer pixel size is 1/600 inch
442 x = 72.0/600;
443 y = 72.0/600;
444 }
445 cairo_device_to_user_distance(cairo, &x, &y);
446 width = MIN(fabs(x),fabs(y));
447 }
448 cairo_set_line_width (cairo, width);
449 if (cairo_shape)
450 cairo_set_line_width (cairo_shape, cairo_get_line_width (cairo));
451}
452
453void CairoOutputDev::updateFillColor(GfxState *state) {
454 GfxRGB color = fill_color;
455
456 state->getFillRGB(&fill_color);
457 if (cairo_pattern_get_type (fill_pattern) != CAIRO_PATTERN_TYPE_SOLID ||
458 color.r != fill_color.r ||
459 color.g != fill_color.g ||
460 color.b != fill_color.b)
461 {
462 cairo_pattern_destroy(fill_pattern);
463 fill_pattern = cairo_pattern_create_rgba(colToDbl(fill_color.r),
464 colToDbl(fill_color.g),
465 colToDbl(fill_color.b),
466 fill_opacity);
467
468 LOG(printf ("fill color: %d %d %d\n",
469 fill_color.r, fill_color.g, fill_color.b));
470 }
471}
472
473void CairoOutputDev::updateStrokeColor(GfxState *state) {
474 GfxRGB color = stroke_color;
475
476 state->getStrokeRGB(&stroke_color);
477 if (cairo_pattern_get_type (fill_pattern) != CAIRO_PATTERN_TYPE_SOLID ||
478 color.r != stroke_color.r ||
479 color.g != stroke_color.g ||
480 color.b != stroke_color.b)
481 {
482 cairo_pattern_destroy(stroke_pattern);
483 stroke_pattern = cairo_pattern_create_rgba(colToDbl(stroke_color.r),
484 colToDbl(stroke_color.g),
485 colToDbl(stroke_color.b),
486 stroke_opacity);
487
488 LOG(printf ("stroke color: %d %d %d\n",
489 stroke_color.r, stroke_color.g, stroke_color.b));
490 }
491}
492
493void CairoOutputDev::updateFillOpacity(GfxState *state) {
494 double opacity = fill_opacity;
495
496 fill_opacity = state->getFillOpacity();
497 if (opacity != fill_opacity) {
498 cairo_pattern_destroy(fill_pattern);
499 fill_pattern = cairo_pattern_create_rgba(colToDbl(fill_color.r),
500 colToDbl(fill_color.g),
501 colToDbl(fill_color.b),
502 fill_opacity);
503
504 LOG(printf ("fill opacity: %f\n", fill_opacity));
505 }
506}
507
508void CairoOutputDev::updateStrokeOpacity(GfxState *state) {
509 double opacity = stroke_opacity;
510
511 stroke_opacity = state->getStrokeOpacity();
512 if (opacity != stroke_opacity) {
513 cairo_pattern_destroy(stroke_pattern);
514 stroke_pattern = cairo_pattern_create_rgba(colToDbl(stroke_color.r),
515 colToDbl(stroke_color.g),
516 colToDbl(stroke_color.b),
517 stroke_opacity);
518
519 LOG(printf ("stroke opacity: %f\n", stroke_opacity));
520 }
521}
522
523void CairoOutputDev::updateFillColorStop(GfxState *state, double offset) {
524 state->getFillRGB(&fill_color);
525
526 cairo_pattern_add_color_stop_rgba(fill_pattern, offset,
527 colToDbl(fill_color.r),
528 colToDbl(fill_color.g),
529 colToDbl(fill_color.b),
530 fill_opacity);
531 LOG(printf ("fill color stop: %f (%d, %d, %d)\n",
532 offset, fill_color.r, fill_color.g, fill_color.b));
533}
534
535void CairoOutputDev::updateBlendMode(GfxState *state) {
536 switch (state->getBlendMode()) {
537 default:
538 case gfxBlendNormal:
539 cairo_set_operator (cairo, CAIRO_OPERATOR_OVER);
540 break;
541 case gfxBlendMultiply:
542 cairo_set_operator (cairo, CAIRO_OPERATOR_MULTIPLY);
543 break;
544 case gfxBlendScreen:
545 cairo_set_operator (cairo, CAIRO_OPERATOR_SCREEN);
546 break;
547 case gfxBlendOverlay:
548 cairo_set_operator (cairo, CAIRO_OPERATOR_OVERLAY);
549 break;
550 case gfxBlendDarken:
551 cairo_set_operator (cairo, CAIRO_OPERATOR_DARKEN);
552 break;
553 case gfxBlendLighten:
554 cairo_set_operator (cairo, CAIRO_OPERATOR_LIGHTEN);
555 break;
556 case gfxBlendColorDodge:
557 cairo_set_operator (cairo, CAIRO_OPERATOR_COLOR_DODGE);
558 break;
559 case gfxBlendColorBurn:
560 cairo_set_operator (cairo, CAIRO_OPERATOR_COLOR_BURN);
561 break;
562 case gfxBlendHardLight:
563 cairo_set_operator (cairo, CAIRO_OPERATOR_HARD_LIGHT);
564 break;
565 case gfxBlendSoftLight:
566 cairo_set_operator (cairo, CAIRO_OPERATOR_SOFT_LIGHT);
567 break;
568 case gfxBlendDifference:
569 cairo_set_operator (cairo, CAIRO_OPERATOR_DIFFERENCE);
570 break;
571 case gfxBlendExclusion:
572 cairo_set_operator (cairo, CAIRO_OPERATOR_EXCLUSION);
573 break;
574 case gfxBlendHue:
575 cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_HUE);
576 break;
577 case gfxBlendSaturation:
578 cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_SATURATION);
579 break;
580 case gfxBlendColor:
581 cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_COLOR);
582 break;
583 case gfxBlendLuminosity:
584 cairo_set_operator (cairo, CAIRO_OPERATOR_HSL_LUMINOSITY);
585 break;
586 }
587 LOG(printf ("blend mode: %d\n", (int)state->getBlendMode()));
588}
589
590void CairoOutputDev::updateFont(GfxState *state) {
591 cairo_font_face_t *font_face;
592 cairo_matrix_t matrix, invert_matrix;
593
594 LOG(printf ("updateFont() font=%s\n", state->getFont()->getName()->getCString()));
595
596 needFontUpdate = gFalse;
597
598 //FIXME: use cairo font engine?
599 if (text)
600 text->updateFont(state);
601
602 currentFont = fontEngine->getFont (state->getFont(), doc, printing);
603
604 if (!currentFont)
605 return;
606
607 font_face = currentFont->getFontFace();
608 cairo_set_font_face (cairo, font_face);
609
610 use_show_text_glyphs = state->getFont()->hasToUnicodeCMap() &&
611 cairo_surface_has_show_text_glyphs (cairo_get_target (cairo));
612
613 double fontSize = state->getFontSize();
614 double *m = state->getTextMat();
615 /* NOTE: adjusting by a constant is hack. The correct solution
616 * is probably to use user-fonts and compute the scale on a per
617 * glyph basis instead of for the entire font */
618 double w = currentFont->getSubstitutionCorrection(state->getFont());
619 matrix.xx = m[0] * fontSize * state->getHorizScaling() * w;
620 matrix.yx = m[1] * fontSize * state->getHorizScaling() * w;
621 matrix.xy = -m[2] * fontSize;
622 matrix.yy = -m[3] * fontSize;
623 matrix.x0 = 0;
624 matrix.y0 = 0;
625
626 LOG(printf ("font matrix: %f %f %f %f\n", matrix.xx, matrix.yx, matrix.xy, matrix.yy));
627
628 /* Make sure the font matrix is invertible before setting it. cairo
629 * will blow up if we give it a matrix that's not invertible, so we
630 * need to check before passing it to cairo_set_font_matrix. Ignoring it
631 * is likely to give better results than not rendering anything at
632 * all. See #18254.
633 */
634 invert_matrix = matrix;
635 if (cairo_matrix_invert(&invert_matrix)) {
636 error(errSyntaxWarning, -1, "font matrix not invertible\n");
637 return;
638 }
639
640 cairo_set_font_matrix (cairo, &matrix);
641}
642
643/* Tolerance in pixels for checking if strokes are horizontal or vertical
644 * lines in device space */
645#define STROKE_COORD_TOLERANCE 0.5
646
647/* Align stroke coordinate i if the point is the start or end of a
648 * horizontal or vertical line */
649void CairoOutputDev::alignStrokeCoords(GfxSubpath *subpath, int i, double *x, double *y)
650{
651 double x1, y1, x2, y2;
652 GBool align = gFalse;
653
654 x1 = subpath->getX(i);
655 y1 = subpath->getY(i);
656 cairo_user_to_device (cairo, &x1, &y1);
657
658 // Does the current coord and prev coord form a horiz or vert line?
659 if (i > 0 && !subpath->getCurve(i - 1)) {
660 x2 = subpath->getX(i - 1);
661 y2 = subpath->getY(i - 1);
662 cairo_user_to_device (cairo, &x2, &y2);
663 if (fabs(x2 - x1) < STROKE_COORD_TOLERANCE || fabs(y2 - y1) < STROKE_COORD_TOLERANCE)
664 align = gTrue;
665 }
666
667 // Does the current coord and next coord form a horiz or vert line?
668 if (i < subpath->getNumPoints() - 1 && !subpath->getCurve(i + 1)) {
669 x2 = subpath->getX(i + 1);
670 y2 = subpath->getY(i + 1);
671 cairo_user_to_device (cairo, &x2, &y2);
672 if (fabs(x2 - x1) < STROKE_COORD_TOLERANCE || fabs(y2 - y1) < STROKE_COORD_TOLERANCE)
673 align = gTrue;
674 }
675
676 *x = subpath->getX(i);
677 *y = subpath->getY(i);
678 if (align) {
679 /* see http://www.cairographics.org/FAQ/#sharp_lines */
680 cairo_user_to_device (cairo, x, y);
681 *x = floor(*x) + 0.5;
682 *y = floor(*y) + 0.5;
683 cairo_device_to_user (cairo, x, y);
684 }
685}
686
687#undef STROKE_COORD_TOLERANCE
688
689void CairoOutputDev::doPath(cairo_t *cairo, GfxState *state, GfxPath *path) {
690 GfxSubpath *subpath;
691 int i, j;
692 double x, y;
693 cairo_new_path (cairo);
694 for (i = 0; i < path->getNumSubpaths(); ++i) {
695 subpath = path->getSubpath(i);
696 if (subpath->getNumPoints() > 0) {
697 if (align_stroke_coords) {
698 alignStrokeCoords(subpath, 0, &x, &y);
699 } else {
700 x = subpath->getX(0);
701 y = subpath->getY(0);
702 }
703 cairo_move_to (cairo, x, y);
704 j = 1;
705 while (j < subpath->getNumPoints()) {
706 if (subpath->getCurve(j)) {
707 if (align_stroke_coords) {
708 alignStrokeCoords(subpath, j + 2, &x, &y);
709 } else {
710 x = subpath->getX(j+2);
711 y = subpath->getY(j+2);
712 }
713 cairo_curve_to( cairo,
714 subpath->getX(j), subpath->getY(j),
715 subpath->getX(j+1), subpath->getY(j+1),
716 x, y);
717
718 j += 3;
719 } else {
720 if (align_stroke_coords) {
721 alignStrokeCoords(subpath, j, &x, &y);
722 } else {
723 x = subpath->getX(j);
724 y = subpath->getY(j);
725 }
726 cairo_line_to (cairo, x, y);
727 ++j;
728 }
729 }
730 if (subpath->isClosed()) {
731 LOG (printf ("close\n"));
732 cairo_close_path (cairo);
733 }
734 }
735 }
736}
737
738void CairoOutputDev::stroke(GfxState *state) {
739 if (inType3Char) {
740 GfxGray gray;
741 state->getFillGray(&gray);
742 if (colToDbl(gray) > 0.5)
743 return;
744 }
745
746 if (adjusted_stroke_width)
747 align_stroke_coords = gTrue;
748 doPath (cairo, state, state->getPath());
749 align_stroke_coords = gFalse;
750 cairo_set_source (cairo, stroke_pattern);
751 LOG(printf ("stroke\n"));
752 cairo_stroke (cairo);
753 if (cairo_shape) {
754 doPath (cairo_shape, state, state->getPath());
755 cairo_stroke (cairo_shape);
756 }
757}
758
759void CairoOutputDev::fill(GfxState *state) {
760 if (inType3Char) {
761 GfxGray gray;
762 state->getFillGray(&gray);
763 if (colToDbl(gray) > 0.5)
764 return;
765 }
766
767 doPath (cairo, state, state->getPath());
768 cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING);
769 cairo_set_source (cairo, fill_pattern);
770 LOG(printf ("fill\n"));
771 //XXX: how do we get the path
772 if (mask) {
773 cairo_save (cairo);
774 cairo_clip (cairo);
775 cairo_set_matrix (cairo, &mask_matrix);
776 cairo_mask (cairo, mask);
777 cairo_restore (cairo);
778 } else if (strokePathClip) {
779 fillToStrokePathClip(state);
780 } else {
781 cairo_fill (cairo);
782 }
783 if (cairo_shape) {
784 cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_WINDING);
785 doPath (cairo_shape, state, state->getPath());
786 cairo_fill (cairo_shape);
787 }
788}
789
790void CairoOutputDev::eoFill(GfxState *state) {
791 doPath (cairo, state, state->getPath());
792 cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD);
793 cairo_set_source (cairo, fill_pattern);
794 LOG(printf ("fill-eo\n"));
795 cairo_fill (cairo);
796
797 if (cairo_shape) {
798 cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_EVEN_ODD);
799 doPath (cairo_shape, state, state->getPath());
800 cairo_fill (cairo_shape);
801 }
802
803}
804
805GBool CairoOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx1, Catalog *cat, Object *str,
806 double *pmat, int paintType, int /*tilingType*/, Dict *resDict,
807 double *mat, double *bbox,
808 int x0, int y0, int x1, int y1,
809 double xStep, double yStep)
810{
811 PDFRectangle box;
812 Gfx *gfx;
813 cairo_pattern_t *pattern;
814 cairo_surface_t *surface;
815 cairo_matrix_t matrix;
816 cairo_t *old_cairo;
817 double xMin, yMin, xMax, yMax;
818 double width, height;
819 int surface_width, surface_height;
820 StrokePathClip *strokePathTmp;
821
822 width = bbox[2] - bbox[0];
823 height = bbox[3] - bbox[1];
824
825 if (xStep != width || yStep != height)
826 return gFalse;
827 /* TODO: implement the other cases here too */
828
829 surface_width = (int) ceil (width);
830 surface_height = (int) ceil (height);
831
832 surface = cairo_surface_create_similar (cairo_get_target (cairo),
833 CAIRO_CONTENT_COLOR_ALPHA,
834 surface_width, surface_height);
835 if (cairo_surface_status (surface))
836 return gFalse;
837
838 old_cairo = cairo;
839 cairo = cairo_create (surface);
840 cairo_surface_destroy (surface);
841
842 box.x1 = bbox[0]; box.y1 = bbox[1];
843 box.x2 = bbox[2]; box.y2 = bbox[3];
844 strokePathTmp = strokePathClip;
845 strokePathClip = NULL;
846 gfx = new Gfx(doc, this, resDict, &box, NULL);
847 gfx->display(str);
848 delete gfx;
849 strokePathClip = strokePathTmp;
850
851 pattern = cairo_pattern_create_for_surface (cairo_get_target (cairo));
852 cairo_destroy (cairo);
853 cairo = old_cairo;
854 if (cairo_pattern_status (pattern))
855 return gFalse;
856
857 state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
858 cairo_rectangle (cairo, xMin, yMin, xMax - xMin, yMax - yMin);
859
860 cairo_matrix_init_scale (&matrix, surface_width / width, surface_height / height);
861 cairo_pattern_set_matrix (pattern, &matrix);
862
863 cairo_matrix_init (&matrix, mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
864 cairo_transform (cairo, &matrix);
865 cairo_set_source (cairo, pattern);
866 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
867 if (strokePathClip) {
868 fillToStrokePathClip(state);
869 } else {
870 cairo_fill (cairo);
871 }
872
873 cairo_pattern_destroy (pattern);
874
875 return gTrue;
876}
877
878GBool CairoOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax) {
879 double x0, y0, x1, y1;
880 double dx, dy;
881
882 shading->getCoords(&x0, &y0, &x1, &y1);
883 dx = x1 - x0;
884 dy = y1 - y0;
885
886 cairo_pattern_destroy(fill_pattern);
887 fill_pattern = cairo_pattern_create_linear (x0 + tMin * dx, y0 + tMin * dy,
888 x0 + tMax * dx, y0 + tMax * dy);
889 if (!shading->getExtend0() && !shading->getExtend1())
890 cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_NONE);
891 else
892 cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_PAD);
893
894 LOG (printf ("axial-sh\n"));
895
896 // TODO: use the actual stops in the shading in the case
897 // of linear interpolation (Type 2 Exponential functions with N=1)
898 return gFalse;
899}
900
901GBool CairoOutputDev::axialShadedSupportExtend(GfxState *state, GfxAxialShading *shading)
902{
903 return (shading->getExtend0() == shading->getExtend1());
904}
905
906GBool CairoOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax) {
907 double x0, y0, r0, x1, y1, r1;
908 double dx, dy, dr;
909
910 shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
911 dx = x1 - x0;
912 dy = y1 - y0;
913 dr = r1 - r0;
914 cairo_pattern_destroy(fill_pattern);
915 fill_pattern = cairo_pattern_create_radial (x0 + sMin * dx,
916 y0 + sMin * dy,
917 r0 + sMin * dr,
918 x0 + sMax * dx,
919 y0 + sMax * dy,
920 r0 + sMax * dr);
921 if (shading->getExtend0() && shading->getExtend1())
922 cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_PAD);
923 else
924 cairo_pattern_set_extend (fill_pattern, CAIRO_EXTEND_NONE);
925
926 LOG (printf ("radial-sh\n"));
927
928 return gFalse;
929}
930
931GBool CairoOutputDev::radialShadedSupportExtend(GfxState *state, GfxRadialShading *shading)
932{
933 return (shading->getExtend0() == shading->getExtend1());
934}
935
936#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
937GBool CairoOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
938{
939 double x0, y0, x1, y1, x2, y2;
940 GfxColor color[3];
941 int i, j;
942 GfxRGB rgb;
943
944 cairo_pattern_destroy(fill_pattern);
945 fill_pattern = cairo_pattern_create_mesh ();
946
947 for (i = 0; i < shading->getNTriangles(); i++) {
948 shading->getTriangle(i,
949 &x0, &y0, &color[0],
950 &x1, &y1, &color[1],
951 &x2, &y2, &color[2]);
952
953 cairo_mesh_pattern_begin_patch (fill_pattern);
954
955 cairo_mesh_pattern_move_to (fill_pattern, x0, y0);
956 cairo_mesh_pattern_line_to (fill_pattern, x1, y1);
957 cairo_mesh_pattern_line_to (fill_pattern, x2, y2);
958
959 for (j = 0; j < 3; j++) {
960 shading->getColorSpace()->getRGB(&color[j], &rgb);
961 cairo_mesh_pattern_set_corner_color_rgb (fill_pattern, j,
962 colToDbl(rgb.r),
963 colToDbl(rgb.g),
964 colToDbl(rgb.b));
965 }
966
967 cairo_mesh_pattern_end_patch (fill_pattern);
968 }
969
970 double xMin, yMin, xMax, yMax;
971 // get the clip region bbox
972 state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
973 state->moveTo(xMin, yMin);
974 state->lineTo(xMin, yMax);
975 state->lineTo(xMax, yMax);
976 state->lineTo(xMax, yMin);
977 state->closePath();
978 fill(state);
979 state->clearPath();
980
981 return gTrue;
982}
983
984GBool CairoOutputDev::patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading)
985{
986 int i, j, k;
987
988 cairo_pattern_destroy(fill_pattern);
989 fill_pattern = cairo_pattern_create_mesh ();
990
991 for (i = 0; i < shading->getNPatches(); i++) {
992 GfxPatch *patch = shading->getPatch(i);
993 GfxColor color;
994 GfxRGB rgb;
995
996 cairo_mesh_pattern_begin_patch (fill_pattern);
997
998 cairo_mesh_pattern_move_to (fill_pattern, patch->x[0][0], patch->y[0][0]);
999 cairo_mesh_pattern_curve_to (fill_pattern,
1000 patch->x[0][1], patch->y[0][1],
1001 patch->x[0][2], patch->y[0][2],
1002 patch->x[0][3], patch->y[0][3]);
1003
1004 cairo_mesh_pattern_curve_to (fill_pattern,
1005 patch->x[1][3], patch->y[1][3],
1006 patch->x[2][3], patch->y[2][3],
1007 patch->x[3][3], patch->y[3][3]);
1008
1009 cairo_mesh_pattern_curve_to (fill_pattern,
1010 patch->x[3][2], patch->y[3][2],
1011 patch->x[3][1], patch->y[3][1],
1012 patch->x[3][0], patch->y[3][0]);
1013
1014 cairo_mesh_pattern_curve_to (fill_pattern,
1015 patch->x[2][0], patch->y[2][0],
1016 patch->x[1][0], patch->y[1][0],
1017 patch->x[0][0], patch->y[0][0]);
1018
1019 cairo_mesh_pattern_set_control_point (fill_pattern, 0, patch->x[1][1], patch->y[1][1]);
1020 cairo_mesh_pattern_set_control_point (fill_pattern, 1, patch->x[1][2], patch->y[1][2]);
1021 cairo_mesh_pattern_set_control_point (fill_pattern, 2, patch->x[2][2], patch->y[2][2]);
1022 cairo_mesh_pattern_set_control_point (fill_pattern, 3, patch->x[2][1], patch->y[2][1]);
1023
1024 for (j = 0; j < 4; j++) {
1025 int u, v;
1026
1027 switch (j) {
1028 case 0:
1029 u = 0; v = 0;
1030 break;
1031 case 1:
1032 u = 0; v = 1;
1033 break;
1034 case 2:
1035 u = 1; v = 1;
1036 break;
1037 case 3:
1038 u = 1; v = 0;
1039 break;
1040 }
1041
1042 if (shading->isParameterized()) {
1043 shading->getParameterizedColor (patch->color[u][v].c[0], &color);
1044 } else {
1045 for (k = 0; k < shading->getColorSpace()->getNComps(); k++) {
1046 // simply cast to the desired type; that's all what is needed.
1047 color.c[k] = GfxColorComp (patch->color[u][v].c[k]);
1048 }
1049 }
1050
1051 shading->getColorSpace()->getRGB(&color, &rgb);
1052 cairo_mesh_pattern_set_corner_color_rgb (fill_pattern, j,
1053 colToDbl(rgb.r),
1054 colToDbl(rgb.g),
1055 colToDbl(rgb.b));
1056 }
1057 cairo_mesh_pattern_end_patch (fill_pattern);
1058 }
1059
1060 double xMin, yMin, xMax, yMax;
1061 // get the clip region bbox
1062 state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
1063 state->moveTo(xMin, yMin);
1064 state->lineTo(xMin, yMax);
1065 state->lineTo(xMax, yMax);
1066 state->lineTo(xMax, yMin);
1067 state->closePath();
1068 fill(state);
1069 state->clearPath();
1070
1071 return gTrue;
1072}
1073#endif /* CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) */
1074
1075void CairoOutputDev::clip(GfxState *state) {
1076 doPath (cairo, state, state->getPath());
1077 cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_WINDING);
1078 cairo_clip (cairo);
1079 LOG (printf ("clip\n"));
1080 if (cairo_shape) {
1081 doPath (cairo_shape, state, state->getPath());
1082 cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_WINDING);
1083 cairo_clip (cairo_shape);
1084 }
1085}
1086
1087void CairoOutputDev::eoClip(GfxState *state) {
1088 doPath (cairo, state, state->getPath());
1089 cairo_set_fill_rule (cairo, CAIRO_FILL_RULE_EVEN_ODD);
1090 cairo_clip (cairo);
1091 LOG (printf ("clip-eo\n"));
1092 if (cairo_shape) {
1093 doPath (cairo_shape, state, state->getPath());
1094 cairo_set_fill_rule (cairo_shape, CAIRO_FILL_RULE_EVEN_ODD);
1095 cairo_clip (cairo_shape);
1096 }
1097
1098}
1099
1100void CairoOutputDev::clipToStrokePath(GfxState *state) {
1101 LOG(printf("clip-to-stroke-path\n"));
1102 strokePathClip = (StrokePathClip*)gmalloc (sizeof(*strokePathClip));
1103 strokePathClip->path = state->getPath()->copy();
1104 cairo_get_matrix (cairo, &strokePathClip->ctm);
1105 strokePathClip->line_width = cairo_get_line_width (cairo);
1106 strokePathClip->dash_count = cairo_get_dash_count (cairo);
1107 if (strokePathClip->dash_count) {
1108 strokePathClip->dashes = (double*) gmallocn (sizeof(double), strokePathClip->dash_count);
1109 cairo_get_dash (cairo, strokePathClip->dashes, &strokePathClip->dash_offset);
1110 } else {
1111 strokePathClip->dashes = NULL;
1112 }
1113 strokePathClip->cap = cairo_get_line_cap (cairo);
1114 strokePathClip->join = cairo_get_line_join (cairo);
1115 strokePathClip->miter = cairo_get_miter_limit (cairo);
1116}
1117
1118void CairoOutputDev::fillToStrokePathClip(GfxState *state) {
1119 cairo_save (cairo);
1120
1121 cairo_set_matrix (cairo, &strokePathClip->ctm);
1122 cairo_set_line_width (cairo, strokePathClip->line_width);
1123 strokePathClip->dash_count = cairo_get_dash_count (cairo);
1124 cairo_set_dash (cairo, strokePathClip->dashes, strokePathClip->dash_count, strokePathClip->dash_offset);
1125 cairo_set_line_cap (cairo, strokePathClip->cap);
1126 cairo_set_line_join (cairo, strokePathClip->join);
1127 cairo_set_miter_limit (cairo, strokePathClip->miter);
1128 doPath (cairo, state, strokePathClip->path);
1129 cairo_stroke (cairo);
1130
1131 cairo_restore (cairo);
1132
1133 delete strokePathClip->path;
1134 if (strokePathClip->dashes)
1135 gfree (strokePathClip->dashes);
1136 gfree (strokePathClip);
1137 strokePathClip = NULL;
1138}
1139
1140void CairoOutputDev::beginString(GfxState *state, GooString *s)
1141{
1142 int len = s->getLength();
1143
1144 if (needFontUpdate)
1145 updateFont(state);
1146
1147 if (!currentFont)
1148 return;
1149
1150 glyphs = (cairo_glyph_t *) gmallocn (len, sizeof (cairo_glyph_t));
1151 glyphCount = 0;
1152 if (use_show_text_glyphs) {
1153 clusters = (cairo_text_cluster_t *) gmallocn (len, sizeof (cairo_text_cluster_t));
1154 clusterCount = 0;
1155 utf8Max = len*2; // start with twice the number of glyphs. we will realloc if we need more.
1156 utf8 = (char *) gmalloc (utf8Max);
1157 utf8Count = 0;
1158 }
1159}
1160
1161void CairoOutputDev::drawChar(GfxState *state, double x, double y,
1162 double dx, double dy,
1163 double originX, double originY,
1164 CharCode code, int nBytes, Unicode *u, int uLen)
1165{
1166 if (currentFont) {
1167 glyphs[glyphCount].index = currentFont->getGlyph (code, u, uLen);
1168 glyphs[glyphCount].x = x - originX;
1169 glyphs[glyphCount].y = y - originY;
1170 glyphCount++;
1171 if (use_show_text_glyphs) {
1172 if (utf8Max - utf8Count < uLen*6) {
1173 // utf8 encoded characters can be up to 6 bytes
1174 if (utf8Max > uLen*6)
1175 utf8Max *= 2;
1176 else
1177 utf8Max += 2*uLen*6;
1178 utf8 = (char *) grealloc (utf8, utf8Max);
1179 }
1180 clusters[clusterCount].num_bytes = 0;
1181 for (int i = 0; i < uLen; i++) {
1182 int size = mapUTF8 (u[i], utf8 + utf8Count, utf8Max - utf8Count);
1183 utf8Count += size;
1184 clusters[clusterCount].num_bytes += size;
1185 }
1186 clusters[clusterCount].num_glyphs = 1;
1187 clusterCount++;
1188 }
1189 }
1190
1191 if (!text)
1192 return;
1193 actualText->addChar (state, x, y, dx, dy, code, nBytes, u, uLen);
1194}
1195
1196void CairoOutputDev::endString(GfxState *state)
1197{
1198 int render;
1199
1200 if (!currentFont)
1201 return;
1202
1203 // endString can be called without a corresponding beginString. If this
1204 // happens glyphs will be null so don't draw anything, just return.
1205 // XXX: OutputDevs should probably not have to deal with this...
1206 if (!glyphs)
1207 return;
1208
1209 // ignore empty strings and invisible text -- this is used by
1210 // Acrobat Capture
1211 render = state->getRender();
1212 if (render == 3 || glyphCount == 0) {
1213 gfree(glyphs);
1214 glyphs = NULL;
1215 return;
1216 }
1217
1218 if (!(render & 1)) {
1219 LOG (printf ("fill string\n"));
1220 cairo_set_source (cairo, fill_pattern);
1221 if (use_show_text_glyphs)
1222 cairo_show_text_glyphs (cairo, utf8, utf8Count, glyphs, glyphCount, clusters, clusterCount, (cairo_text_cluster_flags_t)0);
1223 else
1224 cairo_show_glyphs (cairo, glyphs, glyphCount);
1225 if (cairo_shape)
1226 cairo_show_glyphs (cairo_shape, glyphs, glyphCount);
1227 }
1228
1229 // stroke
1230 if ((render & 3) == 1 || (render & 3) == 2) {
1231 LOG (printf ("stroke string\n"));
1232 cairo_set_source (cairo, stroke_pattern);
1233 cairo_glyph_path (cairo, glyphs, glyphCount);
1234 cairo_stroke (cairo);
1235 if (cairo_shape) {
1236 cairo_glyph_path (cairo_shape, glyphs, glyphCount);
1237 cairo_stroke (cairo_shape);
1238 }
1239 }
1240
1241 // clip
1242 if ((render & 4)) {
1243 LOG (printf ("clip string\n"));
1244 // append the glyph path to textClipPath.
1245
1246 // set textClipPath as the currentPath
1247 if (textClipPath) {
1248 cairo_append_path (cairo, textClipPath);
1249 if (cairo_shape) {
1250 cairo_append_path (cairo_shape, textClipPath);
1251 }
1252 cairo_path_destroy (textClipPath);
1253 }
1254
1255 // append the glyph path
1256 cairo_glyph_path (cairo, glyphs, glyphCount);
1257
1258 // move the path back into textClipPath
1259 // and clear the current path
1260 textClipPath = cairo_copy_path (cairo);
1261 cairo_new_path (cairo);
1262 if (cairo_shape) {
1263 cairo_new_path (cairo_shape);
1264 }
1265 }
1266
1267 gfree (glyphs);
1268 glyphs = NULL;
1269 if (use_show_text_glyphs) {
1270 gfree (clusters);
1271 clusters = NULL;
1272 gfree (utf8);
1273 utf8 = NULL;
1274 }
1275}
1276
1277
1278GBool CairoOutputDev::beginType3Char(GfxState *state, double x, double y,
1279 double dx, double dy,
1280 CharCode code, Unicode *u, int uLen) {
1281
1282 cairo_save (cairo);
1283 double *ctm;
1284 cairo_matrix_t matrix;
1285
1286 ctm = state->getCTM();
1287 matrix.xx = ctm[0];
1288 matrix.yx = ctm[1];
1289 matrix.xy = ctm[2];
1290 matrix.yy = ctm[3];
1291 matrix.x0 = ctm[4];
1292 matrix.y0 = ctm[5];
1293 /* Restore the original matrix and then transform to matrix needed for the
1294 * type3 font. This is ugly but seems to work. Perhaps there is a better way to do it?*/
1295 cairo_set_matrix(cairo, &orig_matrix);
1296 cairo_transform(cairo, &matrix);
1297 if (cairo_shape) {
1298 cairo_save (cairo_shape);
1299 cairo_set_matrix(cairo_shape, &orig_matrix);
1300 cairo_transform(cairo_shape, &matrix);
1301 }
1302 cairo_pattern_destroy(stroke_pattern);
1303 cairo_pattern_reference(fill_pattern);
1304 stroke_pattern = fill_pattern;
1305 return gFalse;
1306}
1307
1308void CairoOutputDev::endType3Char(GfxState *state) {
1309 cairo_restore (cairo);
1310 if (cairo_shape) {
1311 cairo_restore (cairo_shape);
1312 }
1313}
1314
1315void CairoOutputDev::type3D0(GfxState *state, double wx, double wy) {
1316 t3_glyph_wx = wx;
1317 t3_glyph_wy = wy;
1318}
1319
1320void CairoOutputDev::type3D1(GfxState *state, double wx, double wy,
1321 double llx, double lly, double urx, double ury) {
1322 t3_glyph_wx = wx;
1323 t3_glyph_wy = wy;
1324 t3_glyph_bbox[0] = llx;
1325 t3_glyph_bbox[1] = lly;
1326 t3_glyph_bbox[2] = urx;
1327 t3_glyph_bbox[3] = ury;
1328 t3_glyph_has_bbox = gTrue;
1329}
1330
1331void CairoOutputDev::beginTextObject(GfxState *state) {
1332}
1333
1334void CairoOutputDev::endTextObject(GfxState *state) {
1335 if (textClipPath) {
1336 // clip the accumulated text path
1337 cairo_append_path (cairo, textClipPath);
1338 cairo_clip (cairo);
1339 if (cairo_shape) {
1340 cairo_append_path (cairo_shape, textClipPath);
1341 cairo_clip (cairo_shape);
1342 }
1343 cairo_path_destroy (textClipPath);
1344 textClipPath = NULL;
1345 }
1346}
1347
1348void CairoOutputDev::beginActualText(GfxState *state, GooString *text)
1349{
1350 if (this->text)
1351 actualText->begin(state, text);
1352}
1353
1354void CairoOutputDev::endActualText(GfxState *state)
1355{
1356 if (text)
1357 actualText->end(state);
1358}
1359
1360static inline int splashRound(SplashCoord x) {
1361 return (int)floor(x + 0.5);
1362}
1363
1364static inline int splashCeil(SplashCoord x) {
1365 return (int)ceil(x);
1366}
1367
1368static inline int splashFloor(SplashCoord x) {
1369 return (int)floor(x);
1370}
1371
1372static
1373cairo_surface_t *cairo_surface_create_similar_clip (cairo_t *cairo, cairo_content_t content)
1374{
1375 double x1, y1, x2, y2;
1376 int width, height;
1377 cairo_clip_extents (cairo, &x1, &y1, &x2, &y2);
1378 cairo_matrix_t matrix;
1379 cairo_get_matrix (cairo, &matrix);
1380 //cairo_matrix_transform_point(&matrix, &x1, &y1);
1381 //cairo_matrix_transform_point(&matrix, &x2, &y2);*/
1382 cairo_user_to_device(cairo, &x1, &y1);
1383 cairo_user_to_device(cairo, &x2, &y2);
1384 width = splashCeil(x2) - splashFloor(x1);
1385 //XXX: negative matrix
1386 ////height = splashCeil(y2) - splashFloor(y1);
1387 height = splashFloor(y1) - splashCeil(y2);
1388 cairo_surface_t *target = cairo_get_target (cairo);
1389 cairo_surface_t *result;
1390
1391 result = cairo_surface_create_similar (target, content, width, height);
1392 double x_offset, y_offset;
1393 cairo_surface_get_device_offset(target, &x_offset, &y_offset);
1394 cairo_surface_set_device_offset(result, x_offset, y_offset);
1395
1396
1397 return result;
1398}
1399
1400
1401
1402void CairoOutputDev::beginTransparencyGroup(GfxState * /*state*/, double * /*bbox*/,
1403 GfxColorSpace * blendingColorSpace,
1404 GBool /*isolated*/, GBool knockout,
1405 GBool forSoftMask) {
1406 /* push color space */
1407 ColorSpaceStack* css = new ColorSpaceStack;
1408 css->cs = blendingColorSpace;
1409 css->knockout = knockout;
1410 cairo_get_matrix(cairo, &css->group_matrix);
1411 css->next = groupColorSpaceStack;
1412 groupColorSpaceStack = css;
1413
1414 LOG(printf ("begin transparency group. knockout: %s\n", knockout ? "yes":"no"));
1415
1416 if (knockout) {
1417 knockoutCount++;
1418 if (!cairo_shape) {
1419 /* create a surface for tracking the shape */
1420 cairo_surface_t *cairo_shape_surface = cairo_surface_create_similar_clip (cairo, CAIRO_CONTENT_ALPHA);
1421 cairo_shape = cairo_create (cairo_shape_surface);
1422 cairo_surface_destroy (cairo_shape_surface);
1423
1424 /* the color doesn't matter as long as it is opaque */
1425 cairo_set_source_rgb (cairo_shape, 0, 0, 0);
1426 cairo_matrix_t matrix;
1427 cairo_get_matrix (cairo, &matrix);
1428 //printMatrix(&matrix);
1429 cairo_set_matrix (cairo_shape, &matrix);
1430 } else {
1431 cairo_reference (cairo_shape);
1432 }
1433 }
1434 if (groupColorSpaceStack->next && groupColorSpaceStack->next->knockout) {
1435 /* we need to track the shape */
1436 cairo_push_group (cairo_shape);
1437 }
1438 if (0 && forSoftMask)
1439 cairo_push_group_with_content (cairo, CAIRO_CONTENT_ALPHA);
1440 else
1441 cairo_push_group (cairo);
1442
1443 /* push_group has an implicit cairo_save() */
1444 if (knockout) {
1445 /*XXX: let's hope this matches the semantics needed */
1446 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
1447 } else {
1448 cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
1449 }
1450}
1451
1452void CairoOutputDev::endTransparencyGroup(GfxState * /*state*/) {
1453 if (group)
1454 cairo_pattern_destroy(group);
1455 group = cairo_pop_group (cairo);
1456
1457 LOG(printf ("end transparency group\n"));
1458
1459 if (groupColorSpaceStack->next && groupColorSpaceStack->next->knockout) {
1460 if (shape)
1461 cairo_pattern_destroy(shape);
1462 shape = cairo_pop_group (cairo_shape);
1463 }
1464}
1465
1466void CairoOutputDev::paintTransparencyGroup(GfxState * /*state*/, double * /*bbox*/) {
1467 LOG(printf ("paint transparency group\n"));
1468
1469 cairo_save (cairo);
1470 cairo_set_matrix (cairo, &groupColorSpaceStack->group_matrix);
1471 cairo_set_source (cairo, group);
1472
1473 if (!mask) {
1474 //XXX: deal with mask && shape case
1475 if (shape) {
1476 cairo_save (cairo);
1477
1478 /* OPERATOR_SOURCE w/ a mask is defined as (src IN mask) ADD (dest OUT mask)
1479 * however our source has already been clipped to mask so we only need to
1480 * do ADD and OUT */
1481
1482 /* clear the shape mask */
1483 cairo_set_source (cairo, shape);
1484 cairo_set_operator (cairo, CAIRO_OPERATOR_DEST_OUT);
1485 cairo_paint (cairo);
1486
1487 cairo_set_operator (cairo, CAIRO_OPERATOR_ADD);
1488 cairo_set_source (cairo, group);
1489 cairo_paint (cairo);
1490
1491 cairo_restore (cairo);
1492
1493 cairo_pattern_destroy (shape);
1494 shape = NULL;
1495 } else {
1496 cairo_paint_with_alpha (cairo, fill_opacity);
1497 }
1498 cairo_status_t status = cairo_status(cairo);
1499 if (status)
1500 printf("BAD status: %s\n", cairo_status_to_string(status));
1501 } else {
1502 if (fill_opacity < 1.0) {
1503 cairo_push_group(cairo);
1504 }
1505 cairo_save(cairo);
1506 cairo_set_matrix(cairo, &mask_matrix);
1507 cairo_mask(cairo, mask);
1508 cairo_restore(cairo);
1509 if (fill_opacity < 1.0) {
1510 cairo_pop_group_to_source(cairo);
1511 cairo_paint_with_alpha (cairo, fill_opacity);
1512 }
1513 cairo_pattern_destroy(mask);
1514 mask = NULL;
1515 }
1516
1517 popTransparencyGroup();
1518 cairo_restore(cairo);
1519}
1520
1521static int luminocity(uint32_t x)
1522{
1523 int r = (x >> 16) & 0xff;
1524 int g = (x >> 8) & 0xff;
1525 int b = (x >> 0) & 0xff;
1526 // an arbitrary integer approximation of .3*r + .59*g + .11*b
1527 int y = (r*19661+g*38666+b*7209 + 32829)>>16;
1528 return y;
1529}
1530
1531
1532/* XXX: do we need to deal with shape here? */
1533void CairoOutputDev::setSoftMask(GfxState * state, double * bbox, GBool alpha,
1534 Function * transferFunc, GfxColor * backdropColor) {
1535 cairo_pattern_destroy(mask);
1536
1537 LOG(printf ("set softMask\n"));
1538
1539 if (alpha == false) {
1540 /* We need to mask according to the luminocity of the group.
1541 * So we paint the group to an image surface convert it to a luminocity map
1542 * and then use that as the mask. */
1543
1544 /* Get clip extents in device space */
1545 double x1, y1, x2, y2, x_min, y_min, x_max, y_max;
1546 cairo_clip_extents(cairo, &x1, &y1, &x2, &y2);
1547 cairo_user_to_device(cairo, &x1, &y1);
1548 cairo_user_to_device(cairo, &x2, &y2);
1549 x_min = MIN(x1, x2);
1550 y_min = MIN(y1, y2);
1551 x_max = MAX(x1, x2);
1552 y_max = MAX(y1, y2);
1553 cairo_clip_extents(cairo, &x1, &y1, &x2, &y2);
1554 cairo_user_to_device(cairo, &x1, &y2);
1555 cairo_user_to_device(cairo, &x2, &y1);
1556 x_min = MIN(x_min,MIN(x1, x2));
1557 y_min = MIN(y_min,MIN(y1, y2));
1558 x_max = MAX(x_max,MAX(x1, x2));
1559 y_max = MAX(y_max,MAX(y1, y2));
1560
1561 int width = (int)(ceil(x_max) - floor(x_min));
1562 int height = (int)(ceil(y_max) - floor(y_min));
1563
1564 /* Get group device offset */
1565 double x_offset, y_offset;
1566 if (cairo_get_group_target(cairo) == cairo_get_target(cairo)) {
1567 cairo_surface_get_device_offset(cairo_get_group_target(cairo), &x_offset, &y_offset);
1568 } else {
1569 cairo_surface_t *pats;
1570 cairo_pattern_get_surface(group, &pats);
1571 cairo_surface_get_device_offset(pats, &x_offset, &y_offset);
1572 }
1573
1574 /* Adjust extents by group offset */
1575 x_min += x_offset;
1576 y_min += y_offset;
1577
1578 cairo_surface_t *source = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
1579 cairo_t *maskCtx = cairo_create(source);
1580
1581 //XXX: hopefully this uses the correct color space */
1582 GfxRGB backdropColorRGB;
1583 groupColorSpaceStack->cs->getRGB(backdropColor, &backdropColorRGB);
1584 /* paint the backdrop */
1585 cairo_set_source_rgb(maskCtx,
1586 colToDbl(backdropColorRGB.r),
1587 colToDbl(backdropColorRGB.g),
1588 colToDbl(backdropColorRGB.b));
1589 cairo_paint(maskCtx);
1590
1591 /* Copy source ctm to mask ctm and translate origin so that the
1592 * mask appears it the same location on the source surface. */
1593 cairo_matrix_t mat, tmat;
1594 cairo_matrix_init_translate(&tmat, -x_min, -y_min);
1595 cairo_get_matrix(cairo, &mat);
1596 cairo_matrix_multiply(&mat, &mat, &tmat);
1597 cairo_set_matrix(maskCtx, &mat);
1598
1599 /* make the device offset of the new mask match that of the group */
1600 cairo_surface_set_device_offset(source, x_offset, y_offset);
1601
1602 /* paint the group */
1603 cairo_set_source(maskCtx, group);
1604 cairo_paint(maskCtx);
1605
1606 /* XXX status = cairo_status(maskCtx); */
1607 cairo_destroy(maskCtx);
1608
1609 /* convert to a luminocity map */
1610 uint32_t *source_data = (uint32_t*)cairo_image_surface_get_data(source);
1611 /* get stride in units of 32 bits */
1612 int stride = cairo_image_surface_get_stride(source)/4;
1613 for (int y=0; y<height; y++) {
1614 for (int x=0; x<width; x++) {
1615 int lum;
1616 lum = luminocity(source_data[y*stride + x]);
1617 if (transferFunc) {
1618 double lum_in, lum_out;
1619 lum_in = lum/256.0;
1620 transferFunc->transform(&lum_in, &lum_out);
1621 lum = (int)(lum_out * 255.0 + 0.5);
1622 }
1623 source_data[y*stride + x] = lum << 24;
1624 }
1625 }
1626 cairo_surface_mark_dirty (source);
1627
1628 /* setup the new mask pattern */
1629 mask = cairo_pattern_create_for_surface(source);
1630 cairo_get_matrix(cairo, &mask_matrix);
1631
1632 if (cairo_get_group_target(cairo) == cairo_get_target(cairo)) {
1633 cairo_pattern_set_matrix(mask, &mat);
1634 } else {
1635 cairo_matrix_t patMatrix;
1636 cairo_pattern_get_matrix(group, &patMatrix);
1637 /* Apply x_min, y_min offset to it appears in the same location as source. */
1638 cairo_matrix_multiply(&patMatrix, &patMatrix, &tmat);
1639 cairo_pattern_set_matrix(mask, &patMatrix);
1640 }
1641
1642 cairo_surface_destroy(source);
1643 } else {
1644 mask = cairo_pattern_reference(group);
1645 cairo_get_matrix(cairo, &mask_matrix);
1646 }
1647
1648 popTransparencyGroup();
1649}
1650
1651void CairoOutputDev::popTransparencyGroup() {
1652 /* pop color space */
1653 ColorSpaceStack *css = groupColorSpaceStack;
1654 if (css->knockout) {
1655 knockoutCount--;
1656 if (!knockoutCount) {
1657 /* we don't need to track the shape anymore because
1658 * we are not above any knockout groups */
1659 cairo_destroy(cairo_shape);
1660 cairo_shape = NULL;
1661 }
1662 }
1663 groupColorSpaceStack = css->next;
1664 delete css;
1665}
1666
1667
1668void CairoOutputDev::clearSoftMask(GfxState * /*state*/) {
1669 if (mask)
1670 cairo_pattern_destroy(mask);
1671 mask = NULL;
1672}
1673
1674/* Taken from cairo/doc/tutorial/src/singular.c */
1675static void
1676get_singular_values (const cairo_matrix_t *matrix,
1677 double *major,
1678 double *minor)
1679{
1680 double xx = matrix->xx, xy = matrix->xy;
1681 double yx = matrix->yx, yy = matrix->yy;
1682
1683 double a = xx*xx+yx*yx;
1684 double b = xy*xy+yy*yy;
1685 double k = xx*xy+yx*yy;
1686
1687 double f = (a+b) * .5;
1688 double g = (a-b) * .5;
1689 double delta = sqrt (g*g + k*k);
1690
1691 if (major)
1692 *major = sqrt (f + delta);
1693 if (minor)
1694 *minor = sqrt (f - delta);
1695}
1696
1697void CairoOutputDev::getScaledSize(int orig_width,
1698 int orig_height,
1699 int *scaledWidth,
1700 int *scaledHeight) {
1701 cairo_matrix_t matrix;
1702 cairo_get_matrix(cairo, &matrix);
1703
1704 double xScale;
1705 double yScale;
1706 if (orig_width > orig_height)
1707 get_singular_values (&matrix, &xScale, &yScale);
1708 else
1709 get_singular_values (&matrix, &yScale, &xScale);
1710
1711 int tx, tx2, ty, ty2; /* the integer co-oridinates of the resulting image */
1712 if (xScale >= 0) {
1713 tx = splashRound(matrix.x0 - 0.01);
1714 tx2 = splashRound(matrix.x0 + xScale + 0.01) - 1;
1715 } else {
1716 tx = splashRound(matrix.x0 + 0.01) - 1;
1717 tx2 = splashRound(matrix.x0 + xScale - 0.01);
1718 }
1719 *scaledWidth = abs(tx2 - tx) + 1;
1720 //scaledWidth = splashRound(fabs(xScale));
1721 if (*scaledWidth == 0) {
1722 // technically, this should draw nothing, but it generally seems
1723 // better to draw a one-pixel-wide stripe rather than throwing it
1724 // away
1725 *scaledWidth = 1;
1726 }
1727 if (yScale >= 0) {
1728 ty = splashFloor(matrix.y0 + 0.01);
1729 ty2 = splashCeil(matrix.y0 + yScale - 0.01);
1730 } else {
1731 ty = splashCeil(matrix.y0 - 0.01);
1732 ty2 = splashFloor(matrix.y0 + yScale + 0.01);
1733 }
1734 *scaledHeight = abs(ty2 - ty);
1735 if (*scaledHeight == 0) {
1736 *scaledHeight = 1;
1737 }
1738}
1739
1740cairo_surface_t *CairoOutputDev::downscaleSurface(cairo_surface_t *orig_surface) {
1741 cairo_surface_t *dest_surface;
1742 unsigned char *dest_buffer;
1743 int dest_stride;
1744 unsigned char *orig_buffer;
1745 int orig_width, orig_height;
1746 int orig_stride;
1747 int scaledHeight;
1748 int scaledWidth;
1749 GBool res;
1750
1751 if (printing)
1752 return NULL;
1753
1754 orig_width = cairo_image_surface_get_width (orig_surface);
1755 orig_height = cairo_image_surface_get_height (orig_surface);
1756 getScaledSize (orig_width, orig_height, &scaledWidth, &scaledHeight);
1757 if (scaledWidth >= orig_width || scaledHeight >= orig_height)
1758 return NULL;
1759
1760 dest_surface = cairo_surface_create_similar (orig_surface,
1761 cairo_surface_get_content (orig_surface),
1762 scaledWidth, scaledHeight);
1763 dest_buffer = cairo_image_surface_get_data (dest_surface);
1764 dest_stride = cairo_image_surface_get_stride (dest_surface);
1765
1766 orig_buffer = cairo_image_surface_get_data (orig_surface);
1767 orig_stride = cairo_image_surface_get_stride (orig_surface);
1768
1769 res = downscale_box_filter((uint32_t *)orig_buffer,
1770 orig_stride, orig_width, orig_height,
1771 scaledWidth, scaledHeight, 0, 0,
1772 scaledWidth, scaledHeight,
1773 (uint32_t *)dest_buffer, dest_stride);
1774 if (!res) {
1775 cairo_surface_destroy (dest_surface);
1776 return NULL;
1777 }
1778
1779 return dest_surface;
1780
1781}
1782
1783cairo_filter_t
1784CairoOutputDev::getFilterForSurface(cairo_surface_t *image,
1785 GBool interpolate)
1786{
1787 if (interpolate)
1788 return CAIRO_FILTER_BILINEAR;
1789
1790 int orig_width = cairo_image_surface_get_width (image);
1791 int orig_height = cairo_image_surface_get_height (image);
1792 if (orig_width == 0 || orig_height == 0)
1793 return CAIRO_FILTER_NEAREST;
1794
1795 int scaled_width, scaled_height;
1796 getScaledSize (orig_width, orig_height, &scaled_width, &scaled_height);
1797
1798 /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */
1799 if (scaled_width / orig_width >= 4 || scaled_height / orig_height >= 4)
1800 return CAIRO_FILTER_NEAREST;
1801
1802 return CAIRO_FILTER_BILINEAR;
1803}
1804
1805void CairoOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
1806 int width, int height, GBool invert,
1807 GBool interpolate, GBool inlineImg) {
1808
1809 /* FIXME: Doesn't the image mask support any colorspace? */
1810 cairo_set_source (cairo, fill_pattern);
1811
1812 /* work around a cairo bug when scaling 1x1 surfaces */
1813 if (width == 1 && height == 1) {
1814 ImageStream *imgStr;
1815 Guchar pix;
1816 int invert_bit;
1817
1818 imgStr = new ImageStream(str, width, 1, 1);
1819 imgStr->reset();
1820 imgStr->getPixel(&pix);
1821 imgStr->close();
1822 delete imgStr;
1823
1824 invert_bit = invert ? 1 : 0;
1825 if (pix ^ invert_bit)
1826 return;
1827
1828 cairo_save (cairo);
1829 cairo_rectangle (cairo, 0., 0., width, height);
1830 cairo_fill (cairo);
1831 cairo_restore (cairo);
1832 if (cairo_shape) {
1833 cairo_save (cairo_shape);
1834 cairo_rectangle (cairo_shape, 0., 0., width, height);
1835 cairo_fill (cairo_shape);
1836 cairo_restore (cairo_shape);
1837 }
1838 return;
1839 }
1840
1841 /* shape is 1.0 for painted areas, 0.0 for unpainted ones */
1842
1843 cairo_matrix_t matrix;
1844 cairo_get_matrix (cairo, &matrix);
1845 //XXX: it is possible that we should only do sub pixel positioning if
1846 // we are rendering fonts */
1847 if (!printing && prescaleImages
1848 /* not rotated */
1849 && matrix.xy == 0 && matrix.yx == 0
1850 /* axes not flipped / not 180 deg rotated */
1851 && matrix.xx > 0 && (upsideDown() ? -1 : 1) * matrix.yy > 0) {
1852 drawImageMaskPrescaled(state, ref, str, width, height, invert, interpolate, inlineImg);
1853 } else {
1854 drawImageMaskRegular(state, ref, str, width, height, invert, interpolate, inlineImg);
1855 }
1856
1857}
1858
1859void CairoOutputDev::setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str,
1860 int width, int height, GBool invert,
1861 GBool inlineImg, double *baseMatrix) {
1862
1863 /* FIXME: Doesn't the image mask support any colorspace? */
1864 cairo_set_source (cairo, fill_pattern);
1865
1866 /* work around a cairo bug when scaling 1x1 surfaces */
1867 if (width == 1 && height == 1) {
1868 ImageStream *imgStr;
1869 Guchar pix;
1870 int invert_bit;
1871
1872 imgStr = new ImageStream(str, width, 1, 1);
1873 imgStr->reset();
1874 imgStr->getPixel(&pix);
1875 imgStr->close();
1876 delete imgStr;
1877
1878 invert_bit = invert ? 1 : 0;
1879 if (pix ^ invert_bit)
1880 return;
1881
1882 cairo_save (cairo);
1883 cairo_rectangle (cairo, 0., 0., width, height);
1884 cairo_fill (cairo);
1885 cairo_restore (cairo);
1886 if (cairo_shape) {
1887 cairo_save (cairo_shape);
1888 cairo_rectangle (cairo_shape, 0., 0., width, height);
1889 cairo_fill (cairo_shape);
1890 cairo_restore (cairo_shape);
1891 }
1892 return;
1893 }
1894
1895 cairo_push_group_with_content (cairo, CAIRO_CONTENT_ALPHA);
1896
1897 /* shape is 1.0 for painted areas, 0.0 for unpainted ones */
1898
1899 cairo_matrix_t matrix;
1900 cairo_get_matrix (cairo, &matrix);
1901 //XXX: it is possible that we should only do sub pixel positioning if
1902 // we are rendering fonts */
1903 if (!printing && prescaleImages && matrix.xy == 0.0 && matrix.yx == 0.0) {
1904 drawImageMaskPrescaled(state, ref, str, width, height, invert, gFalse, inlineImg);
1905 } else {
1906 drawImageMaskRegular(state, ref, str, width, height, invert, gFalse, inlineImg);
1907 }
1908
1909 if (state->getFillColorSpace()->getMode() == csPattern) {
1910 cairo_set_source_rgb (cairo, 1, 1, 1);
1911 cairo_set_matrix (cairo, &mask_matrix);
1912 cairo_mask (cairo, mask);
1913 }
1914
1915 if (mask)
1916 cairo_pattern_destroy (mask);
1917 mask = cairo_pop_group (cairo);
1918
1919 saveState(state);
1920 double bbox[4] = {0,0,1,1}; // dummy
1921 beginTransparencyGroup(state, bbox, state->getFillColorSpace(),
1922 gTrue, gFalse, gFalse);
1923}
1924
1925void CairoOutputDev::unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) {
1926 double bbox[4] = {0,0,1,1}; // dummy
1927
1928 endTransparencyGroup(state);
1929 restoreState(state);
1930 paintTransparencyGroup(state, bbox);
1931 clearSoftMask(state);
1932}
1933
1934void CairoOutputDev::drawImageMaskRegular(GfxState *state, Object *ref, Stream *str,
1935 int width, int height, GBool invert,
1936 GBool interpolate, GBool inlineImg) {
1937 unsigned char *buffer;
1938 unsigned char *dest;
1939 cairo_surface_t *image;
1940 cairo_pattern_t *pattern;
1941 int x, y, i, bit;
1942 ImageStream *imgStr;
1943 Guchar *pix;
1944 cairo_matrix_t matrix;
1945 int invert_bit;
1946 int row_stride;
1947 cairo_filter_t filter;
1948
1949 /* TODO: Do we want to cache these? */
1950 imgStr = new ImageStream(str, width, 1, 1);
1951 imgStr->reset();
1952
1953 image = cairo_image_surface_create (CAIRO_FORMAT_A1, width, height);
1954 if (cairo_surface_status (image))
1955 goto cleanup;
1956
1957 buffer = cairo_image_surface_get_data (image);
1958 row_stride = cairo_image_surface_get_stride (image);
1959
1960 invert_bit = invert ? 1 : 0;
1961
1962 for (y = 0; y < height; y++) {
1963 pix = imgStr->getLine();
1964 dest = buffer + y * row_stride;
1965 i = 0;
1966 bit = 0;
1967 for (x = 0; x < width; x++) {
1968 if (bit == 0)
1969 dest[i] = 0;
1970 if (!(pix[x] ^ invert_bit)) {
1971#ifdef WORDS_BIGENDIAN
1972 dest[i] |= (1 << (7 - bit));
1973#else
1974 dest[i] |= (1 << bit);
1975#endif
1976 }
1977 bit++;
1978 if (bit > 7) {
1979 bit = 0;
1980 i++;
1981 }
1982 }
1983 }
1984
1985 filter = getFilterForSurface (image, interpolate);
1986
1987 cairo_surface_mark_dirty (image);
1988 pattern = cairo_pattern_create_for_surface (image);
1989 cairo_surface_destroy (image);
1990 if (cairo_pattern_status (pattern))
1991 goto cleanup;
1992
1993 LOG (printf ("drawImageMask %dx%d\n", width, height));
1994
1995 cairo_pattern_set_filter (pattern, filter);
1996
1997 if (!printing)
1998 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
1999
2000 cairo_matrix_init_translate (&matrix, 0, height);
2001 cairo_matrix_scale (&matrix, width, -height);
2002 cairo_pattern_set_matrix (pattern, &matrix);
2003 if (cairo_pattern_status (pattern)) {
2004 cairo_pattern_destroy (pattern);
2005 goto cleanup;
2006 }
2007
2008 if (state->getFillColorSpace()->getMode() == csPattern) {
2009 mask = cairo_pattern_reference (pattern);
2010 cairo_get_matrix (cairo, &mask_matrix);
2011 } else if (!printing) {
2012 cairo_save (cairo);
2013 cairo_rectangle (cairo, 0., 0., 1., 1.);
2014 cairo_clip (cairo);
2015 cairo_mask (cairo, pattern);
2016 cairo_restore (cairo);
2017 } else {
2018 cairo_mask (cairo, pattern);
2019 }
2020
2021 if (cairo_shape) {
2022 cairo_save (cairo_shape);
2023 cairo_set_source (cairo_shape, pattern);
2024 if (!printing) {
2025 cairo_rectangle (cairo_shape, 0., 0., 1., 1.);
2026 cairo_fill (cairo_shape);
2027 } else {
2028 cairo_mask (cairo_shape, pattern);
2029 }
2030 cairo_restore (cairo_shape);
2031 }
2032
2033 cairo_pattern_destroy (pattern);
2034
2035cleanup:
2036 imgStr->close();
2037 delete imgStr;
2038}
2039
2040
2041void CairoOutputDev::drawImageMaskPrescaled(GfxState *state, Object *ref, Stream *str,
2042 int width, int height, GBool invert,
2043 GBool interpolate, GBool inlineImg) {
2044 unsigned char *buffer;
2045 cairo_surface_t *image;
2046 cairo_pattern_t *pattern;
2047 ImageStream *imgStr;
2048 Guchar *pix;
2049 cairo_matrix_t matrix;
2050 int invert_bit;
2051 int row_stride;
2052
2053 /* cairo does a very poor job of scaling down images so we scale them ourselves */
2054
2055 LOG (printf ("drawImageMaskPrescaled %dx%d\n", width, height));
2056
2057 /* this scaling code is adopted from the splash image scaling code */
2058 cairo_get_matrix(cairo, &matrix);
2059#if 0
2060 printf("[%f %f], [%f %f], %f %f\n", matrix.xx, matrix.xy, matrix.yx, matrix.yy, matrix.x0, matrix.y0);
2061#endif
2062 /* this whole computation should be factored out */
2063 double xScale = matrix.xx;
2064 double yScale = matrix.yy;
2065 int tx, tx2, ty, ty2; /* the integer co-oridinates of the resulting image */
2066 int scaledHeight;
2067 int scaledWidth;
2068 if (xScale >= 0) {
2069 tx = splashRound(matrix.x0 - 0.01);
2070 tx2 = splashRound(matrix.x0 + xScale + 0.01) - 1;
2071 } else {
2072 tx = splashRound(matrix.x0 + 0.01) - 1;
2073 tx2 = splashRound(matrix.x0 + xScale - 0.01);
2074 }
2075 scaledWidth = abs(tx2 - tx) + 1;
2076 //scaledWidth = splashRound(fabs(xScale));
2077 if (scaledWidth == 0) {
2078 // technically, this should draw nothing, but it generally seems
2079 // better to draw a one-pixel-wide stripe rather than throwing it
2080 // away
2081 scaledWidth = 1;
2082 }
2083 if (yScale >= 0) {
2084 ty = splashFloor(matrix.y0 + 0.01);
2085 ty2 = splashCeil(matrix.y0 + yScale - 0.01);
2086 } else {
2087 ty = splashCeil(matrix.y0 - 0.01);
2088 ty2 = splashFloor(matrix.y0 + yScale + 0.01);
2089 }
2090 scaledHeight = abs(ty2 - ty);
2091 if (scaledHeight == 0) {
2092 scaledHeight = 1;
2093 }
2094#if 0
2095 printf("xscale: %g, yscale: %g\n", xScale, yScale);
2096 printf("width: %d, height: %d\n", width, height);
2097 printf("scaledWidth: %d, scaledHeight: %d\n", scaledWidth, scaledHeight);
2098#endif
2099
2100 /* compute the required padding */
2101 /* Padding is used to preserve the aspect ratio.
2102 We compute total_pad to make (height+total_pad)/scaledHeight as close to height/yScale as possible */
2103 int head_pad = 0;
2104 int tail_pad = 0;
2105 int total_pad = splashRound(height*(scaledHeight/fabs(yScale)) - height);
2106
2107 /* compute the two pieces of padding */
2108 if (total_pad > 0) {
2109 //XXX: i'm not positive fabs() is correct
2110 float tail_error = fabs(matrix.y0 - ty);
2111 float head_error = fabs(ty2 - (matrix.y0 + yScale));
2112 float tail_fraction = tail_error/(tail_error + head_error);
2113 tail_pad = splashRound(total_pad*tail_fraction);
2114 head_pad = total_pad - tail_pad;
2115 } else {
2116 tail_pad = 0;
2117 head_pad = 0;
2118 }
2119 int origHeight = height;
2120 height += tail_pad;
2121 height += head_pad;
2122#if 0
2123 printf("head_pad: %d tail_pad: %d\n", head_pad, tail_pad);
2124 printf("origHeight: %d height: %d\n", origHeight, height);
2125 printf("ty: %d, ty2: %d\n", ty, ty2);
2126#endif
2127
2128 /* TODO: Do we want to cache these? */
2129 imgStr = new ImageStream(str, width, 1, 1);
2130 imgStr->reset();
2131
2132 invert_bit = invert ? 1 : 0;
2133
2134 image = cairo_image_surface_create (CAIRO_FORMAT_A8, scaledWidth, scaledHeight);
2135 if (cairo_surface_status (image)) {
2136 imgStr->close();
2137 delete imgStr;
2138 return;
2139 }
2140
2141 buffer = cairo_image_surface_get_data (image);
2142 row_stride = cairo_image_surface_get_stride (image);
2143
2144 int yp = height / scaledHeight;
2145 int yq = height % scaledHeight;
2146 int xp = width / scaledWidth;
2147 int xq = width % scaledWidth;
2148 int yt = 0;
2149 int origHeight_c = origHeight;
2150 /* use MIN() because yp might be > origHeight because of padding */
2151 unsigned char *pixBuf = (unsigned char *)malloc(MIN(yp+1, origHeight)*width);
2152 int lastYStep = 1;
2153 int total = 0;
2154 for (int y = 0; y < scaledHeight; y++) {
2155 // y scale Bresenham
2156 int yStep = yp;
2157 yt += yq;
2158
2159 if (yt >= scaledHeight) {
2160 yt -= scaledHeight;
2161 ++yStep;
2162 }
2163
2164 // read row (s) from image ignoring the padding as appropriate
2165 {
2166 int n = (yp > 0) ? yStep : lastYStep;
2167 total += n;
2168 if (n > 0) {
2169 unsigned char *p = pixBuf;
2170 int head_pad_count = head_pad;
2171 int origHeight_count = origHeight;
2172 int tail_pad_count = tail_pad;
2173 for (int i=0; i<n; i++) {
2174 // get row
2175 if (head_pad_count) {
2176 head_pad_count--;
2177 } else if (origHeight_count) {
2178 pix = imgStr->getLine();
2179 for (int j=0; j<width; j++) {
2180 if (pix[j] ^ invert_bit)
2181 p[j] = 0;
2182 else
2183 p[j] = 255;
2184 }
2185 origHeight_count--;
2186 p += width;
2187 } else if (tail_pad_count) {
2188 tail_pad_count--;
2189 } else {
2190 printf("%d %d\n", n, total);
2191 assert(0 && "over run\n");
2192 }
2193 }
2194 }
2195 }
2196
2197 lastYStep = yStep;
2198 int k1 = y;
2199
2200 int xt = 0;
2201 int xSrc = 0;
2202 int x1 = k1;
2203 int n = yStep > 0 ? yStep : 1;
2204 int origN = n;
2205
2206 /* compute the size of padding and pixels that will be used for this row */
2207 int head_pad_size = MIN(n, head_pad);
2208 n -= head_pad_size;
2209 head_pad -= MIN(head_pad_size, yStep);
2210
2211 int pix_size = MIN(n, origHeight);
2212 n -= pix_size;
2213 origHeight -= MIN(pix_size, yStep);
2214
2215 int tail_pad_size = MIN(n, tail_pad);
2216 n -= tail_pad_size;
2217 tail_pad -= MIN(tail_pad_size, yStep);
2218 if (n != 0) {
2219 printf("n = %d (%d %d %d)\n", n, head_pad_size, pix_size, tail_pad_size);
2220 assert(n == 0);
2221 }
2222
2223 for (int x = 0; x < scaledWidth; ++x) {
2224 int xStep = xp;
2225 xt += xq;
2226 if (xt >= scaledWidth) {
2227 xt -= scaledWidth;
2228 ++xStep;
2229 }
2230 int m = xStep > 0 ? xStep : 1;
2231 float pixAcc0 = 0;
2232 /* could m * head_pad_size * tail_pad_size overflow? */
2233 if (invert_bit) {
2234 pixAcc0 += m * head_pad_size * tail_pad_size * 255;
2235 } else {
2236 pixAcc0 += m * head_pad_size * tail_pad_size * 0;
2237 }
2238 /* Accumulate all of the source pixels for the destination pixel */
2239 for (int i = 0; i < pix_size; ++i) {
2240 for (int j = 0; j< m; ++j) {
2241 if (xSrc + i*width + j > MIN(yp + 1, origHeight_c)*width) {
2242 printf("%d > %d (%d %d %d %d) (%d %d %d)\n", xSrc + i*width + j, MIN(yp + 1, origHeight_c)*width, xSrc, i , width, j, yp, origHeight_c, width);
2243 printf("%d %d %d\n", head_pad_size, pix_size, tail_pad_size);
2244 assert(0 && "bad access\n");
2245 }
2246 pixAcc0 += pixBuf[xSrc + i*width + j];
2247 }
2248 }
2249 buffer[y * row_stride + x] = splashFloor(pixAcc0 / (origN*m));
2250 xSrc += xStep;
2251 x1 += 1;
2252 }
2253
2254 }
2255 free(pixBuf);
2256
2257 cairo_surface_mark_dirty (image);
2258 pattern = cairo_pattern_create_for_surface (image);
2259 cairo_surface_destroy (image);
2260 if (cairo_pattern_status (pattern)) {
2261 imgStr->close();
2262 delete imgStr;
2263 return;
2264 }
2265
2266 /* we should actually be using CAIRO_FILTER_NEAREST here. However,
2267 * cairo doesn't yet do minifaction filtering causing scaled down
2268 * images with CAIRO_FILTER_NEAREST to look really bad */
2269 cairo_pattern_set_filter (pattern,
2270 interpolate ? CAIRO_FILTER_BEST : CAIRO_FILTER_FAST);
2271 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
2272
2273 if (state->getFillColorSpace()->getMode() == csPattern) {
2274 cairo_matrix_init_translate (&matrix, 0, scaledHeight);
2275 cairo_matrix_scale (&matrix, scaledWidth, -scaledHeight);
2276 cairo_pattern_set_matrix (pattern, &matrix);
2277 if (cairo_pattern_status (pattern)) {
2278 cairo_pattern_destroy (pattern);
2279 imgStr->close();
2280 delete imgStr;
2281 return;
2282 }
2283
2284 mask = cairo_pattern_reference (pattern);
2285 cairo_get_matrix (cairo, &mask_matrix);
2286 } else {
2287 cairo_save (cairo);
2288
2289 /* modify our current transformation so that the prescaled image
2290 * goes where it is supposed to */
2291 cairo_get_matrix(cairo, &matrix);
2292 cairo_scale(cairo, 1.0/matrix.xx, 1.0/matrix.yy);
2293 // get integer co-ords
2294 cairo_translate (cairo, tx - matrix.x0, ty2 - matrix.y0);
2295 if (yScale > 0)
2296 cairo_scale(cairo, 1, -1);
2297
2298 cairo_rectangle (cairo, 0., 0., scaledWidth, scaledHeight);
2299 cairo_clip (cairo);
2300 cairo_mask (cairo, pattern);
2301
2302 //cairo_get_matrix(cairo, &matrix);
2303 //printf("mask at: [%f %f], [%f %f], %f %f\n\n", matrix.xx, matrix.xy, matrix.yx, matrix.yy, matrix.x0, matrix.y0);
2304 cairo_restore(cairo);
2305 }
2306
2307 if (cairo_shape) {
2308 cairo_save (cairo_shape);
2309
2310 /* modify our current transformation so that the prescaled image
2311 * goes where it is supposed to */
2312 cairo_get_matrix(cairo_shape, &matrix);
2313 cairo_scale(cairo_shape, 1.0/matrix.xx, 1.0/matrix.yy);
2314 // get integer co-ords
2315 cairo_translate (cairo_shape, tx - matrix.x0, ty2 - matrix.y0);
2316 if (yScale > 0)
2317 cairo_scale(cairo_shape, 1, -1);
2318
2319 cairo_rectangle (cairo_shape, 0., 0., scaledWidth, scaledHeight);
2320 cairo_fill (cairo_shape);
2321
2322 cairo_restore(cairo_shape);
2323 }
2324
2325 cairo_pattern_destroy (pattern);
2326
2327 imgStr->close();
2328 delete imgStr;
2329}
2330
2331void CairoOutputDev::drawMaskedImage(GfxState *state, Object *ref,
2332 Stream *str, int width, int height,
2333 GfxImageColorMap *colorMap,
2334 GBool interpolate,
2335 Stream *maskStr, int maskWidth,
2336 int maskHeight, GBool maskInvert,
2337 GBool maskInterpolate)
2338{
2339 ImageStream *maskImgStr, *imgStr;
2340 int row_stride;
2341 unsigned char *maskBuffer, *buffer;
2342 unsigned char *maskDest;
2343 unsigned int *dest;
2344 cairo_surface_t *maskImage, *image;
2345 cairo_pattern_t *maskPattern, *pattern;
2346 cairo_matrix_t matrix;
2347 cairo_matrix_t maskMatrix;
2348 Guchar *pix;
2349 int x, y;
2350 int invert_bit;
2351 cairo_filter_t filter;
2352 cairo_filter_t maskFilter;
2353
2354 maskImgStr = new ImageStream(maskStr, maskWidth, 1, 1);
2355 maskImgStr->reset();
2356
2357 maskImage = cairo_image_surface_create (CAIRO_FORMAT_A8, maskWidth, maskHeight);
2358 if (cairo_surface_status (maskImage)) {
2359 maskImgStr->close();
2360 delete maskImgStr;
2361 return;
2362 }
2363
2364 maskBuffer = cairo_image_surface_get_data (maskImage);
2365 row_stride = cairo_image_surface_get_stride (maskImage);
2366
2367 invert_bit = maskInvert ? 1 : 0;
2368
2369 for (y = 0; y < maskHeight; y++) {
2370 pix = maskImgStr->getLine();
2371 maskDest = maskBuffer + y * row_stride;
2372 for (x = 0; x < maskWidth; x++) {
2373 if (pix[x] ^ invert_bit)
2374 *maskDest++ = 0;
2375 else
2376 *maskDest++ = 255;
2377 }
2378 }
2379
2380 maskImgStr->close();
2381 delete maskImgStr;
2382
2383 maskFilter = getFilterForSurface (maskImage, maskInterpolate);
2384
2385 cairo_surface_mark_dirty (maskImage);
2386 maskPattern = cairo_pattern_create_for_surface (maskImage);
2387 cairo_surface_destroy (maskImage);
2388 if (cairo_pattern_status (maskPattern))
2389 return;
2390
2391#if 0
2392 /* ICCBased color space doesn't do any color correction
2393 * so check its underlying color space as well */
2394 int is_identity_transform;
2395 is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
2396 (colorMap->getColorSpace()->getMode() == csICCBased &&
2397 ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB);
2398#endif
2399
2400 /* TODO: Do we want to cache these? */
2401 imgStr = new ImageStream(str, width,
2402 colorMap->getNumPixelComps(),
2403 colorMap->getBits());
2404 imgStr->reset();
2405
2406 image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
2407 if (cairo_surface_status (image))
2408 goto cleanup;
2409
2410 buffer = cairo_image_surface_get_data (image);
2411 row_stride = cairo_image_surface_get_stride (image);
2412 for (y = 0; y < height; y++) {
2413 dest = (unsigned int *) (buffer + y * row_stride);
2414 pix = imgStr->getLine();
2415 colorMap->getRGBLine (pix, dest, width);
2416 }
2417
2418 filter = getFilterForSurface (image, interpolate);
2419
2420 cairo_surface_mark_dirty (image);
2421 pattern = cairo_pattern_create_for_surface (image);
2422 cairo_surface_destroy (image);
2423 if (cairo_pattern_status (pattern))
2424 goto cleanup;
2425
2426 LOG (printf ("drawMaskedImage %dx%d\n", width, height));
2427
2428 cairo_pattern_set_filter (pattern, filter);
2429 cairo_pattern_set_filter (maskPattern, maskFilter);
2430
2431 if (!printing) {
2432 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
2433 cairo_pattern_set_extend (maskPattern, CAIRO_EXTEND_PAD);
2434 }
2435
2436 cairo_matrix_init_translate (&matrix, 0, height);
2437 cairo_matrix_scale (&matrix, width, -height);
2438 cairo_pattern_set_matrix (pattern, &matrix);
2439 if (cairo_pattern_status (pattern)) {
2440 cairo_pattern_destroy (pattern);
2441 cairo_pattern_destroy (maskPattern);
2442 goto cleanup;
2443 }
2444
2445 cairo_matrix_init_translate (&maskMatrix, 0, maskHeight);
2446 cairo_matrix_scale (&maskMatrix, maskWidth, -maskHeight);
2447 cairo_pattern_set_matrix (maskPattern, &maskMatrix);
2448 if (cairo_pattern_status (maskPattern)) {
2449 cairo_pattern_destroy (maskPattern);
2450 cairo_pattern_destroy (pattern);
2451 goto cleanup;
2452 }
2453
2454 if (!printing) {
2455 cairo_save (cairo);
2456 cairo_set_source (cairo, pattern);
2457 cairo_rectangle (cairo, 0., 0., 1., 1.);
2458 cairo_clip (cairo);
2459 cairo_mask (cairo, maskPattern);
2460 cairo_restore (cairo);
2461 } else {
2462 cairo_set_source (cairo, pattern);
2463 cairo_mask (cairo, maskPattern);
2464 }
2465
2466 if (cairo_shape) {
2467 cairo_save (cairo_shape);
2468 cairo_set_source (cairo_shape, pattern);
2469 if (!printing) {
2470 cairo_rectangle (cairo_shape, 0., 0., 1., 1.);
2471 cairo_fill (cairo_shape);
2472 } else {
2473 cairo_mask (cairo_shape, pattern);
2474 }
2475 cairo_restore (cairo_shape);
2476 }
2477
2478 cairo_pattern_destroy (maskPattern);
2479 cairo_pattern_destroy (pattern);
2480
2481cleanup:
2482 imgStr->close();
2483 delete imgStr;
2484}
2485
2486
2487//XXX: is this affect by AIS(alpha is shape)?
2488void CairoOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
2489 int width, int height,
2490 GfxImageColorMap *colorMap,
2491 GBool interpolate,
2492 Stream *maskStr,
2493 int maskWidth, int maskHeight,
2494 GfxImageColorMap *maskColorMap,
2495 GBool maskInterpolate)
2496{
2497 ImageStream *maskImgStr, *imgStr;
2498 int row_stride;
2499 unsigned char *maskBuffer, *buffer;
2500 unsigned char *maskDest;
2501 unsigned int *dest;
2502 cairo_surface_t *maskImage, *image;
2503 cairo_pattern_t *maskPattern, *pattern;
2504 cairo_matrix_t maskMatrix, matrix;
2505 Guchar *pix;
2506 int y;
2507 cairo_filter_t filter;
2508 cairo_filter_t maskFilter;
2509
2510 maskImgStr = new ImageStream(maskStr, maskWidth,
2511 maskColorMap->getNumPixelComps(),
2512 maskColorMap->getBits());
2513 maskImgStr->reset();
2514
2515 maskImage = cairo_image_surface_create (CAIRO_FORMAT_A8, maskWidth, maskHeight);
2516 if (cairo_surface_status (maskImage)) {
2517 maskImgStr->close();
2518 delete maskImgStr;
2519 return;
2520 }
2521
2522 maskBuffer = cairo_image_surface_get_data (maskImage);
2523 row_stride = cairo_image_surface_get_stride (maskImage);
2524 for (y = 0; y < maskHeight; y++) {
2525 maskDest = (unsigned char *) (maskBuffer + y * row_stride);
2526 pix = maskImgStr->getLine();
2527 maskColorMap->getGrayLine (pix, maskDest, maskWidth);
2528 }
2529
2530 maskImgStr->close();
2531 delete maskImgStr;
2532
2533 maskFilter = getFilterForSurface (maskImage, maskInterpolate);
2534
2535 cairo_surface_mark_dirty (maskImage);
2536 maskPattern = cairo_pattern_create_for_surface (maskImage);
2537 cairo_surface_destroy (maskImage);
2538 if (cairo_pattern_status (maskPattern))
2539 return;
2540
2541#if 0
2542 /* ICCBased color space doesn't do any color correction
2543 * so check its underlying color space as well */
2544 int is_identity_transform;
2545 is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
2546 (colorMap->getColorSpace()->getMode() == csICCBased &&
2547 ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB);
2548#endif
2549
2550 /* TODO: Do we want to cache these? */
2551 imgStr = new ImageStream(str, width,
2552 colorMap->getNumPixelComps(),
2553 colorMap->getBits());
2554 imgStr->reset();
2555
2556 image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
2557 if (cairo_surface_status (image))
2558 goto cleanup;
2559
2560 buffer = cairo_image_surface_get_data (image);
2561 row_stride = cairo_image_surface_get_stride (image);
2562 for (y = 0; y < height; y++) {
2563 dest = (unsigned int *) (buffer + y * row_stride);
2564 pix = imgStr->getLine();
2565 colorMap->getRGBLine (pix, dest, width);
2566 }
2567
2568 filter = getFilterForSurface (image, interpolate);
2569
2570 cairo_surface_mark_dirty (image);
2571
2572 setMimeData(str, ref, image);
2573
2574 pattern = cairo_pattern_create_for_surface (image);
2575 cairo_surface_destroy (image);
2576 if (cairo_pattern_status (pattern))
2577 goto cleanup;
2578
2579 LOG (printf ("drawSoftMaskedImage %dx%d\n", width, height));
2580
2581 cairo_pattern_set_filter (pattern, filter);
2582 cairo_pattern_set_filter (maskPattern, maskFilter);
2583
2584 if (!printing) {
2585 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
2586 cairo_pattern_set_extend (maskPattern, CAIRO_EXTEND_PAD);
2587 }
2588
2589 cairo_matrix_init_translate (&matrix, 0, height);
2590 cairo_matrix_scale (&matrix, width, -height);
2591 cairo_pattern_set_matrix (pattern, &matrix);
2592 if (cairo_pattern_status (pattern)) {
2593 cairo_pattern_destroy (pattern);
2594 cairo_pattern_destroy (maskPattern);
2595 goto cleanup;
2596 }
2597
2598 cairo_matrix_init_translate (&maskMatrix, 0, maskHeight);
2599 cairo_matrix_scale (&maskMatrix, maskWidth, -maskHeight);
2600 cairo_pattern_set_matrix (maskPattern, &maskMatrix);
2601 if (cairo_pattern_status (maskPattern)) {
2602 cairo_pattern_destroy (maskPattern);
2603 cairo_pattern_destroy (pattern);
2604 goto cleanup;
2605 }
2606
2607 if (fill_opacity != 1.0)
2608 cairo_push_group (cairo);
2609 else
2610 cairo_save (cairo);
2611
2612 cairo_set_source (cairo, pattern);
2613 if (!printing) {
2614 cairo_rectangle (cairo, 0., 0.,
2615 MIN (width, maskWidth) / (double)width,
2616 MIN (height, maskHeight) / (double)height);
2617 cairo_clip (cairo);
2618 }
2619 cairo_mask (cairo, maskPattern);
2620
2621 if (fill_opacity != 1.0) {
2622 cairo_pop_group_to_source (cairo);
2623 cairo_save (cairo);
2624 if (!printing) {
2625 cairo_rectangle (cairo, 0., 0.,
2626 MIN (width, maskWidth) / (double)width,
2627 MIN (height, maskHeight) / (double)height);
2628 cairo_clip (cairo);
2629 }
2630 cairo_paint_with_alpha (cairo, fill_opacity);
2631 }
2632 cairo_restore (cairo);
2633
2634 if (cairo_shape) {
2635 cairo_save (cairo_shape);
2636 cairo_set_source (cairo_shape, pattern);
2637 if (!printing) {
2638 cairo_rectangle (cairo_shape, 0., 0.,
2639 MIN (width, maskWidth) / (double)width,
2640 MIN (height, maskHeight) / (double)height);
2641 cairo_fill (cairo_shape);
2642 } else {
2643 cairo_mask (cairo_shape, pattern);
2644 }
2645 cairo_restore (cairo_shape);
2646 }
2647
2648 cairo_pattern_destroy (maskPattern);
2649 cairo_pattern_destroy (pattern);
2650
2651cleanup:
2652 imgStr->close();
2653 delete imgStr;
2654}
2655
2656GBool CairoOutputDev::getStreamData (Stream *str, char **buffer, int *length)
2657{
2658 int len, i;
2659 char *strBuffer;
2660
2661 len = 0;
2662 str->close();
2663 str->reset();
2664 while (str->getChar() != EOF) len++;
2665 if (len == 0)
2666 return gFalse;
2667
2668 strBuffer = (char *)gmalloc (len);
2669
2670 str->close();
2671 str->reset();
2672 for (i = 0; i < len; ++i)
2673 strBuffer[i] = str->getChar();
2674
2675 *buffer = strBuffer;
2676 *length = len;
2677
2678 return gTrue;
2679}
2680
2681void CairoOutputDev::setMimeData(Stream *str, Object *ref, cairo_surface_t *image)
2682{
2683 char *strBuffer;
2684 int len;
2685 Object obj;
2686
2687 if (!printing || !(str->getKind() == strDCT || str->getKind() == strJPX))
2688 return;
2689
2690 // colorspace in stream dict may be different from colorspace in jpx
2691 // data
2692 if (str->getKind() == strJPX) {
2693 GBool hasColorSpace = !str->getDict()->lookup("ColorSpace", &obj)->isNull();
2694 obj.free();
2695 if (hasColorSpace)
2696 return;
2697 }
2698
2699 if (getStreamData (str->getNextStream(), &strBuffer, &len)) {
2700 cairo_status_t st;
2701
2702#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2)
2703 if (ref && ref->isRef()) {
2704 Ref imgRef = ref->getRef();
2705 GooString *surfaceId = new GooString("poppler-surface-");
2706 surfaceId->appendf("{0:d}-{1:d}", imgRef.gen, imgRef.num);
2707 char *idBuffer = copyString(surfaceId->getCString());
2708 st = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_UNIQUE_ID,
2709 (const unsigned char *)idBuffer,
2710 surfaceId->getLength(),
2711 gfree, idBuffer);
2712 if (st)
2713 gfree(idBuffer);
2714 delete surfaceId;
2715 }
2716#endif
2717
2718 st = cairo_surface_set_mime_data (image,
2719 str->getKind() == strDCT ?
2720 CAIRO_MIME_TYPE_JPEG : CAIRO_MIME_TYPE_JP2,
2721 (const unsigned char *)strBuffer, len,
2722 gfree, strBuffer);
2723 if (st)
2724 gfree (strBuffer);
2725 }
2726}
2727
2728void CairoOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2729 int width, int height,
2730 GfxImageColorMap *colorMap,
2731 GBool interpolate,
2732 int *maskColors, GBool inlineImg)
2733{
2734 cairo_surface_t *image;
2735 cairo_pattern_t *pattern, *maskPattern;
2736 ImageStream *imgStr;
2737 cairo_matrix_t matrix;
2738 unsigned char *buffer;
2739 int stride, i;
2740 GfxRGB *lookup = NULL;
2741 cairo_filter_t filter = CAIRO_FILTER_BILINEAR;
2742
2743 /* TODO: Do we want to cache these? */
2744 imgStr = new ImageStream(str, width,
2745 colorMap->getNumPixelComps(),
2746 colorMap->getBits());
2747 imgStr->reset();
2748
2749#if 0
2750 /* ICCBased color space doesn't do any color correction
2751 * so check its underlying color space as well */
2752 int is_identity_transform;
2753 is_identity_transform = colorMap->getColorSpace()->getMode() == csDeviceRGB ||
2754 (colorMap->getColorSpace()->getMode() == csICCBased &&
2755 ((GfxICCBasedColorSpace*)colorMap->getColorSpace())->getAlt()->getMode() == csDeviceRGB);
2756#endif
2757
2758 image = cairo_image_surface_create (maskColors ?
2759 CAIRO_FORMAT_ARGB32 :
2760 CAIRO_FORMAT_RGB24,
2761 width, height);
2762 if (cairo_surface_status (image))
2763 goto cleanup;
2764
2765 // special case for one-channel (monochrome/gray/separation) images:
2766 // build a lookup table here
2767 if (colorMap->getNumPixelComps() == 1) {
2768 int n;
2769 Guchar pix;
2770
2771 n = 1 << colorMap->getBits();
2772 lookup = (GfxRGB *)gmallocn(n, sizeof(GfxRGB));
2773 for (i = 0; i < n; ++i) {
2774 pix = (Guchar)i;
2775
2776 colorMap->getRGB(&pix, &lookup[i]);
2777 }
2778 }
2779
2780 buffer = cairo_image_surface_get_data (image);
2781 stride = cairo_image_surface_get_stride (image);
2782 for (int y = 0; y < height; y++) {
2783 uint32_t *dest = (uint32_t *) (buffer + y * stride);
2784 Guchar *pix = imgStr->getLine();
2785
2786 if (lookup) {
2787 Guchar *p = pix;
2788 GfxRGB rgb;
2789
2790 for (i = 0; i < width; i++) {
2791 rgb = lookup[*p];
2792 dest[i] =
2793 ((int) colToByte(rgb.r) << 16) |
2794 ((int) colToByte(rgb.g) << 8) |
2795 ((int) colToByte(rgb.b) << 0);
2796 p++;
2797 }
2798 } else {
2799 colorMap->getRGBLine (pix, dest, width);
2800 }
2801
2802 if (maskColors) {
2803 for (int x = 0; x < width; x++) {
2804 bool is_opaque = false;
2805 for (int i = 0; i < colorMap->getNumPixelComps(); ++i) {
2806 if (pix[i] < maskColors[2*i] ||
2807 pix[i] > maskColors[2*i+1]) {
2808 is_opaque = true;
2809 break;
2810 }
2811 }
2812 if (is_opaque)
2813 *dest |= 0xff000000;
2814 else
2815 *dest = 0;
2816 dest++;
2817 pix += colorMap->getNumPixelComps();
2818 }
2819 }
2820 }
2821 gfree(lookup);
2822
2823 LOG (printf ("drawImage %dx%d\n", width, height));
2824
2825 cairo_surface_t *scaled_surface;
2826
2827 scaled_surface = downscaleSurface (image);
2828 if (scaled_surface) {
2829 if (cairo_surface_status (scaled_surface))
2830 goto cleanup;
2831 cairo_surface_destroy (image);
2832 image = scaled_surface;
2833 width = cairo_image_surface_get_width (image);
2834 height = cairo_image_surface_get_height (image);
2835 } else {
2836 filter = getFilterForSurface (image, interpolate);
2837 }
2838
2839 cairo_surface_mark_dirty (image);
2840
2841 if (!inlineImg) /* don't read stream twice if it is an inline image */
2842 setMimeData(str, ref, image);
2843
2844 pattern = cairo_pattern_create_for_surface (image);
2845 cairo_surface_destroy (image);
2846 if (cairo_pattern_status (pattern))
2847 goto cleanup;
2848
2849 cairo_pattern_set_filter (pattern, filter);
2850
2851 if (!printing)
2852 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
2853
2854 cairo_matrix_init_translate (&matrix, 0, height);
2855 cairo_matrix_scale (&matrix, width, -height);
2856 cairo_pattern_set_matrix (pattern, &matrix);
2857 if (cairo_pattern_status (pattern)) {
2858 cairo_pattern_destroy (pattern);
2859 goto cleanup;
2860 }
2861
2862 if (!mask && fill_opacity != 1.0) {
2863 maskPattern = cairo_pattern_create_rgba (1., 1., 1., fill_opacity);
2864 } else if (mask) {
2865 maskPattern = cairo_pattern_reference (mask);
2866 } else {
2867 maskPattern = NULL;
2868 }
2869
2870 cairo_save (cairo);
2871 cairo_set_source (cairo, pattern);
2872 if (!printing)
2873 cairo_rectangle (cairo, 0., 0., 1., 1.);
2874 if (maskPattern) {
2875 if (!printing)
2876 cairo_clip (cairo);
2877 cairo_set_matrix (cairo, &mask_matrix);
2878 cairo_mask (cairo, maskPattern);
2879 } else {
2880 if (printing)
2881 cairo_paint (cairo);
2882 else
2883 cairo_fill (cairo);
2884 }
2885 cairo_restore (cairo);
2886
2887 cairo_pattern_destroy (maskPattern);
2888
2889 if (cairo_shape) {
2890 cairo_save (cairo_shape);
2891 cairo_set_source (cairo_shape, pattern);
2892 if (printing) {
2893 cairo_paint (cairo_shape);
2894 } else {
2895 cairo_rectangle (cairo_shape, 0., 0., 1., 1.);
2896 cairo_fill (cairo_shape);
2897 }
2898 cairo_restore (cairo_shape);
2899 }
2900
2901 cairo_pattern_destroy (pattern);
2902
2903cleanup:
2904 imgStr->close();
2905 delete imgStr;
2906}
2907
2908
2909//------------------------------------------------------------------------
2910// ImageOutputDev
2911//------------------------------------------------------------------------
2912
2913CairoImageOutputDev::CairoImageOutputDev()
2914{
2915 images = NULL;
2916 numImages = 0;
2917 size = 0;
2918 imgDrawCbk = NULL;
2919 imgDrawCbkData = NULL;
2920}
2921
2922CairoImageOutputDev::~CairoImageOutputDev()
2923{
2924 int i;
2925
2926 for (i = 0; i < numImages; i++)
2927 delete images[i];
2928 gfree (images);
2929}
2930
2931void CairoImageOutputDev::saveImage(CairoImage *image)
2932{
2933 if (numImages >= size) {
2934 size += 16;
2935 images = (CairoImage **) greallocn (images, size, sizeof (CairoImage *));
2936 }
2937 images[numImages++] = image;
2938}
2939
2940void CairoImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2941 int width, int height, GBool invert,
2942 GBool interpolate, GBool inlineImg)
2943{
2944 cairo_t *cr;
2945 cairo_surface_t *surface;
2946 double x1, y1, x2, y2;
2947 double *ctm;
2948 double mat[6];
2949 CairoImage *image;
2950
2951 ctm = state->getCTM();
2952
2953 mat[0] = ctm[0];
2954 mat[1] = ctm[1];
2955 mat[2] = -ctm[2];
2956 mat[3] = -ctm[3];
2957 mat[4] = ctm[2] + ctm[4];
2958 mat[5] = ctm[3] + ctm[5];
2959 x1 = mat[4];
2960 y1 = mat[5];
2961 x2 = x1 + width;
2962 y2 = y1 + height;
2963
2964 image = new CairoImage (x1, y1, x2, y2);
2965 saveImage (image);
2966
2967 if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) {
2968 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
2969 cr = cairo_create (surface);
2970 setCairo (cr);
2971 cairo_translate (cr, 0, height);
2972 cairo_scale (cr, width, -height);
2973
2974 CairoOutputDev::drawImageMask(state, ref, str, width, height, invert, interpolate, inlineImg);
2975 image->setImage (surface);
2976
2977 setCairo (NULL);
2978 cairo_surface_destroy (surface);
2979 cairo_destroy (cr);
2980 }
2981}
2982
2983void CairoImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
2984 int width, int height, GfxImageColorMap *colorMap,
2985 GBool interpolate, int *maskColors, GBool inlineImg)
2986{
2987 cairo_t *cr;
2988 cairo_surface_t *surface;
2989 double x1, y1, x2, y2;
2990 double *ctm;
2991 double mat[6];
2992 CairoImage *image;
2993
2994 ctm = state->getCTM();
2995
2996 mat[0] = ctm[0];
2997 mat[1] = ctm[1];
2998 mat[2] = -ctm[2];
2999 mat[3] = -ctm[3];
3000 mat[4] = ctm[2] + ctm[4];
3001 mat[5] = ctm[3] + ctm[5];
3002 x1 = mat[4];
3003 y1 = mat[5];
3004 x2 = x1 + width;
3005 y2 = y1 + height;
3006
3007 image = new CairoImage (x1, y1, x2, y2);
3008 saveImage (image);
3009
3010 if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) {
3011 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
3012 cr = cairo_create (surface);
3013 setCairo (cr);
3014 cairo_translate (cr, 0, height);
3015 cairo_scale (cr, width, -height);
3016
3017 CairoOutputDev::drawImage(state, ref, str, width, height, colorMap, interpolate, maskColors, inlineImg);
3018 image->setImage (surface);
3019
3020 setCairo (NULL);
3021 cairo_surface_destroy (surface);
3022 cairo_destroy (cr);
3023 }
3024}
3025
3026void CairoImageOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
3027 int width, int height,
3028 GfxImageColorMap *colorMap,
3029 GBool interpolate,
3030 Stream *maskStr,
3031 int maskWidth, int maskHeight,
3032 GfxImageColorMap *maskColorMap,
3033 GBool maskInterpolate)
3034{
3035 cairo_t *cr;
3036 cairo_surface_t *surface;
3037 double x1, y1, x2, y2;
3038 double *ctm;
3039 double mat[6];
3040 CairoImage *image;
3041
3042 ctm = state->getCTM();
3043
3044 mat[0] = ctm[0];
3045 mat[1] = ctm[1];
3046 mat[2] = -ctm[2];
3047 mat[3] = -ctm[3];
3048 mat[4] = ctm[2] + ctm[4];
3049 mat[5] = ctm[3] + ctm[5];
3050 x1 = mat[4];
3051 y1 = mat[5];
3052 x2 = x1 + width;
3053 y2 = y1 + height;
3054
3055 image = new CairoImage (x1, y1, x2, y2);
3056 saveImage (image);
3057
3058 if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) {
3059 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
3060 cr = cairo_create (surface);
3061 setCairo (cr);
3062 cairo_translate (cr, 0, height);
3063 cairo_scale (cr, width, -height);
3064
3065 CairoOutputDev::drawSoftMaskedImage(state, ref, str, width, height, colorMap, interpolate,
3066 maskStr, maskWidth, maskHeight, maskColorMap, maskInterpolate);
3067 image->setImage (surface);
3068
3069 setCairo (NULL);
3070 cairo_surface_destroy (surface);
3071 cairo_destroy (cr);
3072 }
3073}
3074
3075void CairoImageOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
3076 int width, int height,
3077 GfxImageColorMap *colorMap,
3078 GBool interpolate,
3079 Stream *maskStr,
3080 int maskWidth, int maskHeight,
3081 GBool maskInvert, GBool maskInterpolate)
3082{
3083 cairo_t *cr;
3084 cairo_surface_t *surface;
3085 double x1, y1, x2, y2;
3086 double *ctm;
3087 double mat[6];
3088 CairoImage *image;
3089
3090 ctm = state->getCTM();
3091
3092 mat[0] = ctm[0];
3093 mat[1] = ctm[1];
3094 mat[2] = -ctm[2];
3095 mat[3] = -ctm[3];
3096 mat[4] = ctm[2] + ctm[4];
3097 mat[5] = ctm[3] + ctm[5];
3098 x1 = mat[4];
3099 y1 = mat[5];
3100 x2 = x1 + width;
3101 y2 = y1 + height;
3102
3103 image = new CairoImage (x1, y1, x2, y2);
3104 saveImage (image);
3105
3106 if (imgDrawCbk && imgDrawCbk (numImages - 1, imgDrawCbkData)) {
3107 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
3108 cr = cairo_create (surface);
3109 setCairo (cr);
3110 cairo_translate (cr, 0, height);
3111 cairo_scale (cr, width, -height);
3112
3113 CairoOutputDev::drawMaskedImage(state, ref, str, width, height, colorMap, interpolate,
3114 maskStr, maskWidth, maskHeight, maskInvert, maskInterpolate);
3115 image->setImage (surface);
3116
3117 setCairo (NULL);
3118 cairo_surface_destroy (surface);
3119 cairo_destroy (cr);
3120 }
3121}
03122
=== modified file 'debian/changelog'
--- debian/changelog 2012-09-12 10:53:15 +0000
+++ debian/changelog 2012-11-13 19:26:27 +0000
@@ -1,3 +1,11 @@
1poppler (0.20.4-0ubuntu2) raring; urgency=low
2
3 * debian/patches/git_gouraud_shading_support.patch: (LP: #1072129)
4 - Evince crashes after opening certain PDF file because parameterized
5 Gouraud shading is not supported.
6
7 -- Matthieu Baerts (matttbe) <matttbe@ubuntu.com> Sat, 10 Nov 2012 16:51:12 +0100
8
1poppler (0.20.4-0ubuntu1) quantal; urgency=low9poppler (0.20.4-0ubuntu1) quantal; urgency=low
210
3 * New upstream bugfix release11 * New upstream bugfix release
412
=== added file 'debian/patches/git_gouraud_shading_support.patch'
--- debian/patches/git_gouraud_shading_support.patch 1970-01-01 00:00:00 +0000
+++ debian/patches/git_gouraud_shading_support.patch 2012-11-13 19:26:27 +0000
@@ -0,0 +1,38 @@
1From ae8fc0cbfc6123189e17b3cf1286e0540f181646 Mon Sep 17 00:00:00 2001
2From: Adrian Johnson <ajohnson@redneon.com>
3Date: Tue, 30 Oct 2012 10:52:04 +0000
4Subject: cairo: support parameterized Gouraud shading
5Bug: https://bugs.freedesktop.org/show_bug.cgi?id=56463
6Bug-Ubuntu: https://bugs.launchpad.net/poppler/+bug/1072129
7
8---
9Index: poppler/poppler/CairoOutputDev.cc
10===================================================================
11--- poppler.orig/poppler/CairoOutputDev.cc 2012-11-10 16:49:31.178020000 +0100
12+++ poppler/poppler/CairoOutputDev.cc 2012-11-10 16:50:44.513164938 +0100
13@@ -945,10 +945,21 @@
14 fill_pattern = cairo_pattern_create_mesh ();
15
16 for (i = 0; i < shading->getNTriangles(); i++) {
17- shading->getTriangle(i,
18- &x0, &y0, &color[0],
19- &x1, &y1, &color[1],
20- &x2, &y2, &color[2]);
21+ if (shading->isParameterized()) {
22+ double color0, color1, color2;
23+ shading->getTriangle(i, &x0, &y0, &color0,
24+ &x1, &y1, &color1,
25+ &x2, &y2, &color2);
26+ shading->getParameterizedColor(color0, &color[0]);
27+ shading->getParameterizedColor(color1, &color[1]);
28+ shading->getParameterizedColor(color2, &color[2]);
29+ } else {
30+ shading->getTriangle(i,
31+ &x0, &y0, &color[0],
32+ &x1, &y1, &color[1],
33+ &x2, &y2, &color[2]);
34+
35+ }
36
37 cairo_mesh_pattern_begin_patch (fill_pattern);
38
039
=== modified file 'debian/patches/series'
--- debian/patches/series 2012-08-14 13:11:05 +0000
+++ debian/patches/series 2012-11-13 19:26:27 +0000
@@ -1,2 +1,3 @@
1ltmain-as-needed.diff1ltmain-as-needed.diff
2qt4-visibility.diff2qt4-visibility.diff
3git_gouraud_shading_support.patch
34
=== modified file 'poppler/CairoOutputDev.cc'
--- poppler/CairoOutputDev.cc 2012-06-22 14:50:04 +0000
+++ poppler/CairoOutputDev.cc 2012-11-13 19:26:27 +0000
@@ -945,10 +945,21 @@
945 fill_pattern = cairo_pattern_create_mesh ();945 fill_pattern = cairo_pattern_create_mesh ();
946946
947 for (i = 0; i < shading->getNTriangles(); i++) {947 for (i = 0; i < shading->getNTriangles(); i++) {
948 shading->getTriangle(i,948 if (shading->isParameterized()) {
949 &x0, &y0, &color[0],949 double color0, color1, color2;
950 &x1, &y1, &color[1],950 shading->getTriangle(i, &x0, &y0, &color0,
951 &x2, &y2, &color[2]);951 &x1, &y1, &color1,
952 &x2, &y2, &color2);
953 shading->getParameterizedColor(color0, &color[0]);
954 shading->getParameterizedColor(color1, &color[1]);
955 shading->getParameterizedColor(color2, &color[2]);
956 } else {
957 shading->getTriangle(i,
958 &x0, &y0, &color[0],
959 &x1, &y1, &color[1],
960 &x2, &y2, &color[2]);
961
962 }
952963
953 cairo_mesh_pattern_begin_patch (fill_pattern);964 cairo_mesh_pattern_begin_patch (fill_pattern);
954965

Subscribers

People subscribed via source and target branches