~lfaraone/ubuntu/lucid/xpdf/lp556483

« back to all changes in this revision

Viewing changes to .pc/fix-462544.dpatch/xpdf/SplashOutputDev.cc

  • Committer: Luke Faraone
  • Date: 2010-04-06 13:38:25 UTC
  • mfrom: (6.1.3 sid)
  • Revision ID: luke@faraone.cc-20100406133825-bshu2k9svh5oje1f
* Merge from Debian unstable. (LP: #556483) Remaining changes: 
  - do-not-make-ps-arrays-bigger-than-64k-from-big-images-in-patterns.dpatch:
    pdftops produced wrong PostScript when a large image is in a
    pattern in the input file
  - Ubuntu maintainer field
[Michael Gilbert]
* Fix multiple security issues (closes: #551287, #575779).
  - CVE-2009-1188: Integer overflow in the JBIG2 decoding feature in the
    SplashBitmap::SplashBitmap function in SplashBitmap.cc.
  - CVE-2009-3603: Additional integer overflows in the
    SplashBitmap::SplashBitmap function.
  - CVE-2009-3604: Null pointer dereference in the Splash::drawImage
    function in Splash.cc.
  - CVE-2009-3606: Integer overflow in the PSOutputDev::doImageL1Sep
    function in PSOutputDev.cc.
  - CVE-2009-3608: Integer overflow in the ObjectStream::ObjectStream
    function in XRef.cc.
  - CVE-2009-3609: Integer overflow in the ImageStream::ImageStream
    function in Stream.cc.
* Bump standards version to 3.8.4 (no changes required).
* Use ${misc:Depends}.
* Adopt the package (closes: #535261, #527840).
[Rogério Brito]
* debian/copyright:
  + include versioned link to the GPL.
* debian/*
  + convert to source format "3.0 (quilt)".
* debian/{control,compat}:
  + bump compat to 5.
* debian/control:
  + remove dpatch build-dep and calls in debian/rules.
  + include Homepage field.
  + build-depend on unversioned automake.
  + build-depend on versioned lesstif.
  + wrap build-depends line to keep sanity.
  + change build-dependency on x-dev to x11proto-core-dev. (Closes: #515495).
  + remove debian revision from versioned build-deps.
  + update standards-version to 3.8.3, with no extra changes required.
* debian/rules:
  + remove commented lines.
  + fix the includes for lesstif. (See below).
  + remove deprecated dh_desktop helper.
  + don't ignore errors when calling "make -i distclean".
  + separate configuration from package compilation to keep things tidy.
  + don't remove recursively things that are only files.
* debian/patches:
  + rename 00list to series.
  + disable patches 40 and 41, lesstif is fixed. (Closes: #458763, #528807).
  + refresh enabled patches to avoid potential problems with buildds.
  + escape minus signs from manpages.
  + fix path to configuration files. Tks Andrew Price. (Closes: #424747).
  + flexibilize the print dialog. Tks Dmitry Oboukhov. (Closes: #408502).
  + implement "Fit to Height". Tks Josh Triplett. (Closes: #424178).
* debian/xpdf-common.postint:
  + don't use command with path in maintainer script.
* debian/watch:
  + create watch file.
* debian/xpdf.desktop:
  + remove obsolete indication of encoding.
  + remove custom category "PDFViewer".
* debian/xpdf-reader.menu:
  + update obsolete section Apps -> Applications.
* debian/xpdf-reader.dirs:
  + remove empty dir usr/lib/menu. Tks Nelson Oliveira. (Closes: #495150).
* avoid conflict with poppler-utils. Tks Luca Capello. (Closes: #558020).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//========================================================================
 
2
//
 
3
// SplashOutputDev.cc
 
4
//
 
5
// Copyright 2003 Glyph & Cog, LLC
 
6
//
 
7
//========================================================================
 
8
 
 
9
#include <aconf.h>
 
10
 
 
11
#ifdef USE_GCC_PRAGMAS
 
12
#pragma implementation
 
13
#endif
 
14
 
 
15
#include <string.h>
 
16
#include <math.h>
 
17
#include "gfile.h"
 
18
#include "GlobalParams.h"
 
19
#include "Error.h"
 
20
#include "Object.h"
 
21
#include "GfxFont.h"
 
22
#include "Link.h"
 
23
#include "CharCodeToUnicode.h"
 
24
#include "FontEncodingTables.h"
 
25
#include "FoFiTrueType.h"
 
26
#include "SplashBitmap.h"
 
27
#include "SplashGlyphBitmap.h"
 
28
#include "SplashPattern.h"
 
29
#include "SplashScreen.h"
 
30
#include "SplashPath.h"
 
31
#include "SplashState.h"
 
32
#include "SplashErrorCodes.h"
 
33
#include "SplashFontEngine.h"
 
34
#include "SplashFont.h"
 
35
#include "SplashFontFile.h"
 
36
#include "SplashFontFileID.h"
 
37
#include "Splash.h"
 
38
#include "SplashOutputDev.h"
 
39
 
 
40
#ifdef VMS
 
41
#if (__VMS_VER < 70000000)
 
42
extern "C" int unlink(char *filename);
 
43
#endif
 
44
#endif
 
45
 
 
46
//------------------------------------------------------------------------
 
47
 
 
48
// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
 
49
static inline Guchar div255(int x) {
 
50
  return (Guchar)((x + (x >> 8) + 0x80) >> 8);
 
51
}
 
52
 
 
53
//------------------------------------------------------------------------
 
54
// Blend functions
 
55
//------------------------------------------------------------------------
 
56
 
 
57
static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest,
 
58
                                   SplashColorPtr blend, SplashColorMode cm) {
 
59
  int i;
 
60
 
 
61
  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
 
62
    blend[i] = (dest[i] * src[i]) / 255;
 
63
  }
 
64
}
 
65
 
 
66
static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest,
 
67
                                 SplashColorPtr blend, SplashColorMode cm) {
 
68
  int i;
 
69
 
 
70
  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
 
71
    blend[i] = dest[i] + src[i] - (dest[i] * src[i]) / 255;
 
72
  }
 
73
}
 
74
 
 
75
static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest,
 
76
                                  SplashColorPtr blend, SplashColorMode cm) {
 
77
  int i;
 
78
 
 
79
  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
 
80
    blend[i] = dest[i] < 0x80
 
81
                 ? (src[i] * 2 * dest[i]) / 255
 
82
                 : 255 - 2 * ((255 - src[i]) * (255 - dest[i])) / 255;
 
83
  }
 
84
}
 
85
 
 
86
static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest,
 
87
                                 SplashColorPtr blend, SplashColorMode cm) {
 
88
  int i;
 
89
 
 
90
  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
 
91
    blend[i] = dest[i] < src[i] ? dest[i] : src[i];
 
92
  }
 
93
}
 
94
 
 
95
static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest,
 
96
                                  SplashColorPtr blend, SplashColorMode cm) {
 
97
  int i;
 
98
 
 
99
  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
 
100
    blend[i] = dest[i] > src[i] ? dest[i] : src[i];
 
101
  }
 
102
}
 
103
 
 
104
static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest,
 
105
                                     SplashColorPtr blend,
 
106
                                     SplashColorMode cm) {
 
107
  int i, x;
 
108
 
 
109
  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
 
110
    if (src[i] == 255) {
 
111
      blend[i] = 255;
 
112
    } else {
 
113
      x = (dest[i] * 255) / (255 - src[i]);
 
114
      blend[i] = x <= 255 ? x : 255;
 
115
    }
 
116
  }
 
117
}
 
118
 
 
119
static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest,
 
120
                                    SplashColorPtr blend, SplashColorMode cm) {
 
121
  int i, x;
 
122
 
 
123
  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
 
124
    if (src[i] == 0) {
 
125
      blend[i] = 0;
 
126
    } else {
 
127
      x = ((255 - dest[i]) * 255) / src[i];
 
128
      blend[i] = x <= 255 ? 255 - x : 0;
 
129
    }
 
130
  }
 
131
}
 
132
 
 
133
static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest,
 
134
                                    SplashColorPtr blend, SplashColorMode cm) {
 
135
  int i;
 
136
 
 
137
  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
 
138
    blend[i] = src[i] < 0x80
 
139
                 ? (dest[i] * 2 * src[i]) / 255
 
140
                 : 255 - 2 * ((255 - dest[i]) * (255 - src[i])) / 255;
 
141
  }
 
142
}
 
143
 
 
144
static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest,
 
145
                                    SplashColorPtr blend, SplashColorMode cm) {
 
146
  int i, x;
 
147
 
 
148
  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
 
149
    if (src[i] < 0x80) {
 
150
      blend[i] = dest[i] - (255 - 2 * src[i]) * dest[i] * (255 - dest[i]) /
 
151
                 (255 * 255);
 
152
    } else {
 
153
      if (dest[i] < 0x40) {
 
154
        x = (((((16 * dest[i] - 12 * 255) * dest[i]) / 255)
 
155
              + 4 * 255) * dest[i]) / 255;
 
156
      } else {
 
157
        x = (int)sqrt(255.0 * dest[i]);
 
158
      }
 
159
      blend[i] = dest[i] + (2 * src[i] - 255) * (x - dest[i]) / 255;
 
160
    }
 
161
  }
 
162
}
 
163
 
 
164
static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest,
 
165
                                     SplashColorPtr blend,
 
166
                                     SplashColorMode cm) {
 
167
  int i;
 
168
 
 
169
  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
 
170
    blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i];
 
171
  }
 
172
}
 
173
 
 
174
static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest,
 
175
                                    SplashColorPtr blend, SplashColorMode cm) {
 
176
  int i;
 
177
 
 
178
  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
 
179
    blend[i] = dest[i] + src[i] - (2 * dest[i] * src[i]) / 255;
 
180
  }
 
181
}
 
182
 
 
183
static void cvtRGBToHSV(Guchar r, Guchar g, Guchar b, int *h, int *s, int *v) {
 
184
  int cmax, cmid, cmin, x;
 
185
 
 
186
  if (r >= g) {
 
187
    if (g >= b)      { x = 0; cmax = r; cmid = g; cmin = b; }
 
188
    else if (b >= r) { x = 4; cmax = b; cmid = r; cmin = g; }
 
189
    else             { x = 5; cmax = r; cmid = b; cmin = g; }
 
190
  } else {
 
191
    if (r >= b)      { x = 1; cmax = g; cmid = r; cmin = b; }
 
192
    else if (g >= b) { x = 2; cmax = g; cmid = b; cmin = r; }
 
193
    else             { x = 3; cmax = b; cmid = g; cmin = r; }
 
194
  }
 
195
  if (cmax == cmin) {
 
196
    *h = *s = 0;
 
197
  } else {
 
198
    *h = x * 60;
 
199
    if (x & 1) {
 
200
      *h += ((cmax - cmid) * 60) / (cmax - cmin);
 
201
    } else {
 
202
      *h += ((cmid - cmin) * 60) / (cmax - cmin);
 
203
    }
 
204
    *s = (255 * (cmax - cmin)) / cmax;
 
205
  }
 
206
  *v = cmax;
 
207
}
 
208
 
 
209
static void cvtHSVToRGB(int h, int s, int v, Guchar *r, Guchar *g, Guchar *b) {
 
210
  int x, f, cmax, cmid, cmin;
 
211
 
 
212
  if (s == 0) {
 
213
    *r = *g = *b = v;
 
214
  } else {
 
215
    x = h / 60;
 
216
    f = h % 60;
 
217
    cmax = v;
 
218
    if (x & 1) {
 
219
      cmid = div255(v * 255 - ((s * f) / 60));
 
220
    } else {
 
221
      cmid = div255(v * (255 - ((s * (60 - f)) / 60)));
 
222
    }
 
223
    cmin = div255(v * (255 - s));
 
224
    switch (x) {
 
225
    case 0: *r = cmax; *g = cmid; *b = cmin; break;
 
226
    case 1: *g = cmax; *r = cmid; *b = cmin; break;
 
227
    case 2: *g = cmax; *b = cmid; *r = cmin; break;
 
228
    case 3: *b = cmax; *g = cmid; *r = cmin; break;
 
229
    case 4: *b = cmax; *r = cmid; *g = cmin; break;
 
230
    case 5: *r = cmax; *b = cmid; *g = cmin; break;
 
231
    }
 
232
  }
 
233
}
 
234
 
 
235
static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest,
 
236
                              SplashColorPtr blend, SplashColorMode cm) {
 
237
  int hs, ss, vs, hd, sd, vd;
 
238
#if SPLASH_CMYK
 
239
  Guchar r, g, b;
 
240
#endif
 
241
 
 
242
  switch (cm) {
 
243
  case splashModeMono1:
 
244
  case splashModeMono8:
 
245
    blend[0] = dest[0];
 
246
    break;
 
247
  case splashModeRGB8:
 
248
  case splashModeBGR8:
 
249
    cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
 
250
    cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
 
251
    cvtHSVToRGB(hs, sd, vd, &blend[0], &blend[1], &blend[2]);
 
252
    break;
 
253
#if SPLASH_CMYK
 
254
  case splashModeCMYK8:
 
255
    //~ (0xff - ...) should be clipped
 
256
    cvtRGBToHSV(0xff - (src[0] + src[3]),
 
257
                0xff - (src[1] + src[3]),
 
258
                0xff - (src[2] + src[3]), &hs, &ss, &vs);
 
259
    cvtRGBToHSV(0xff - (dest[0] + dest[3]),
 
260
                0xff - (dest[1] + dest[3]),
 
261
                0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
 
262
    cvtHSVToRGB(hs, sd, vd, &r, &g, &b);
 
263
    //~ should do black generation
 
264
    blend[0] = 0xff - r;
 
265
    blend[1] = 0xff - g;
 
266
    blend[2] = 0xff - b;
 
267
    blend[3] = 0;
 
268
    break;
 
269
#endif
 
270
  }
 
271
}
 
272
 
 
273
static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest,
 
274
                                     SplashColorPtr blend,
 
275
                                     SplashColorMode cm) {
 
276
  int hs, ss, vs, hd, sd, vd;
 
277
#if SPLASH_CMYK
 
278
  Guchar r, g, b;
 
279
#endif
 
280
 
 
281
  switch (cm) {
 
282
  case splashModeMono1:
 
283
  case splashModeMono8:
 
284
    blend[0] = dest[0];
 
285
    break;
 
286
  case splashModeRGB8:
 
287
  case splashModeBGR8:
 
288
    cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
 
289
    cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
 
290
    cvtHSVToRGB(hd, ss, vd, &blend[0], &blend[1], &blend[2]);
 
291
    break;
 
292
#if SPLASH_CMYK
 
293
  case splashModeCMYK8:
 
294
    //~ (0xff - ...) should be clipped
 
295
    cvtRGBToHSV(0xff - (src[0] + src[3]),
 
296
                0xff - (src[1] + src[3]),
 
297
                0xff - (src[2] + src[3]), &hs, &ss, &vs);
 
298
    cvtRGBToHSV(0xff - (dest[0] + dest[3]),
 
299
                0xff - (dest[1] + dest[3]),
 
300
                0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
 
301
    cvtHSVToRGB(hd, ss, vd, &r, &g, &b);
 
302
    //~ should do black generation
 
303
    blend[0] = 0xff - r;
 
304
    blend[1] = 0xff - g;
 
305
    blend[2] = 0xff - b;
 
306
    blend[3] = 0;
 
307
    break;
 
308
#endif
 
309
  }
 
310
}
 
311
 
 
312
static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest,
 
313
                                SplashColorPtr blend, SplashColorMode cm) {
 
314
  int hs, ss, vs, hd, sd, vd;
 
315
#if SPLASH_CMYK
 
316
  Guchar r, g, b;
 
317
#endif
 
318
 
 
319
  switch (cm) {
 
320
  case splashModeMono1:
 
321
  case splashModeMono8:
 
322
    blend[0] = dest[0];
 
323
    break;
 
324
  case splashModeRGB8:
 
325
  case splashModeBGR8:
 
326
    cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
 
327
    cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
 
328
    cvtHSVToRGB(hs, ss, vd, &blend[0], &blend[1], &blend[2]);
 
329
    break;
 
330
#if SPLASH_CMYK
 
331
  case splashModeCMYK8:
 
332
    //~ (0xff - ...) should be clipped
 
333
    cvtRGBToHSV(0xff - (src[0] + src[3]),
 
334
                0xff - (src[1] + src[3]),
 
335
                0xff - (src[2] + src[3]), &hs, &ss, &vs);
 
336
    cvtRGBToHSV(0xff - (dest[0] + dest[3]),
 
337
                0xff - (dest[1] + dest[3]),
 
338
                0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
 
339
    cvtHSVToRGB(hs, ss, vd, &r, &g, &b);
 
340
    //~ should do black generation
 
341
    blend[0] = 0xff - r;
 
342
    blend[1] = 0xff - g;
 
343
    blend[2] = 0xff - b;
 
344
    blend[3] = 0;
 
345
    break;
 
346
#endif
 
347
  }
 
348
}
 
349
 
 
350
static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest,
 
351
                                     SplashColorPtr blend,
 
352
                                     SplashColorMode cm) {
 
353
  int hs, ss, vs, hd, sd, vd;
 
354
#if SPLASH_CMYK
 
355
  Guchar r, g, b;
 
356
#endif
 
357
 
 
358
  switch (cm) {
 
359
  case splashModeMono1:
 
360
  case splashModeMono8:
 
361
    blend[0] = dest[0];
 
362
    break;
 
363
  case splashModeRGB8:
 
364
  case splashModeBGR8:
 
365
    cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
 
366
    cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
 
367
    cvtHSVToRGB(hd, sd, vs, &blend[0], &blend[1], &blend[2]);
 
368
    break;
 
369
#if SPLASH_CMYK
 
370
  case splashModeCMYK8:
 
371
    //~ (0xff - ...) should be clipped
 
372
    cvtRGBToHSV(0xff - (src[0] + src[3]),
 
373
                0xff - (src[1] + src[3]),
 
374
                0xff - (src[2] + src[3]), &hs, &ss, &vs);
 
375
    cvtRGBToHSV(0xff - (dest[0] + dest[3]),
 
376
                0xff - (dest[1] + dest[3]),
 
377
                0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
 
378
    cvtHSVToRGB(hd, sd, vs, &r, &g, &b);
 
379
    //~ should do black generation
 
380
    blend[0] = 0xff - r;
 
381
    blend[1] = 0xff - g;
 
382
    blend[2] = 0xff - b;
 
383
    blend[3] = 0;
 
384
    break;
 
385
#endif
 
386
  }
 
387
}
 
388
 
 
389
// NB: This must match the GfxBlendMode enum defined in GfxState.h.
 
390
SplashBlendFunc splashOutBlendFuncs[] = {
 
391
  NULL,
 
392
  &splashOutBlendMultiply,
 
393
  &splashOutBlendScreen,
 
394
  &splashOutBlendOverlay,
 
395
  &splashOutBlendDarken,
 
396
  &splashOutBlendLighten,
 
397
  &splashOutBlendColorDodge,
 
398
  &splashOutBlendColorBurn,
 
399
  &splashOutBlendHardLight,
 
400
  &splashOutBlendSoftLight,
 
401
  &splashOutBlendDifference,
 
402
  &splashOutBlendExclusion,
 
403
  &splashOutBlendHue,
 
404
  &splashOutBlendSaturation,
 
405
  &splashOutBlendColor,
 
406
  &splashOutBlendLuminosity
 
407
};
 
408
 
 
409
//------------------------------------------------------------------------
 
410
// Font substitutions
 
411
//------------------------------------------------------------------------
 
412
 
 
413
struct SplashOutFontSubst {
 
414
  char *name;
 
415
  double mWidth;
 
416
};
 
417
 
 
418
// index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic
 
419
static SplashOutFontSubst splashOutSubstFonts[16] = {
 
420
  {"Helvetica",             0.833},
 
421
  {"Helvetica-Oblique",     0.833},
 
422
  {"Helvetica-Bold",        0.889},
 
423
  {"Helvetica-BoldOblique", 0.889},
 
424
  {"Times-Roman",           0.788},
 
425
  {"Times-Italic",          0.722},
 
426
  {"Times-Bold",            0.833},
 
427
  {"Times-BoldItalic",      0.778},
 
428
  {"Courier",               0.600},
 
429
  {"Courier-Oblique",       0.600},
 
430
  {"Courier-Bold",          0.600},
 
431
  {"Courier-BoldOblique",   0.600},
 
432
  {"Symbol",                0.576},
 
433
  {"Symbol",                0.576},
 
434
  {"Symbol",                0.576},
 
435
  {"Symbol",                0.576}
 
436
};
 
437
 
 
438
//------------------------------------------------------------------------
 
439
// SplashOutFontFileID
 
440
//------------------------------------------------------------------------
 
441
 
 
442
class SplashOutFontFileID: public SplashFontFileID {
 
443
public:
 
444
 
 
445
  SplashOutFontFileID(Ref *rA) { r = *rA; substIdx = -1; }
 
446
 
 
447
  ~SplashOutFontFileID() {}
 
448
 
 
449
  GBool matches(SplashFontFileID *id) {
 
450
    return ((SplashOutFontFileID *)id)->r.num == r.num &&
 
451
           ((SplashOutFontFileID *)id)->r.gen == r.gen;
 
452
  }
 
453
 
 
454
  void setSubstIdx(int substIdxA) { substIdx = substIdxA; }
 
455
  int getSubstIdx() { return substIdx; }
 
456
 
 
457
private:
 
458
 
 
459
  Ref r;
 
460
  int substIdx;
 
461
};
 
462
 
 
463
//------------------------------------------------------------------------
 
464
// T3FontCache
 
465
//------------------------------------------------------------------------
 
466
 
 
467
struct T3FontCacheTag {
 
468
  Gushort code;
 
469
  Gushort mru;                  // valid bit (0x8000) and MRU index
 
470
};
 
471
 
 
472
class T3FontCache {
 
473
public:
 
474
 
 
475
  T3FontCache(Ref *fontID, double m11A, double m12A,
 
476
              double m21A, double m22A,
 
477
              int glyphXA, int glyphYA, int glyphWA, int glyphHA,
 
478
              GBool aa, GBool validBBoxA);
 
479
  ~T3FontCache();
 
480
  GBool matches(Ref *idA, double m11A, double m12A,
 
481
                double m21A, double m22A)
 
482
    { return fontID.num == idA->num && fontID.gen == idA->gen &&
 
483
             m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; }
 
484
 
 
485
  Ref fontID;                   // PDF font ID
 
486
  double m11, m12, m21, m22;    // transform matrix
 
487
  int glyphX, glyphY;           // pixel offset of glyph bitmaps
 
488
  int glyphW, glyphH;           // size of glyph bitmaps, in pixels
 
489
  GBool validBBox;              // false if the bbox was [0 0 0 0]
 
490
  int glyphSize;                // size of glyph bitmaps, in bytes
 
491
  int cacheSets;                // number of sets in cache
 
492
  int cacheAssoc;               // cache associativity (glyphs per set)
 
493
  Guchar *cacheData;            // glyph pixmap cache
 
494
  T3FontCacheTag *cacheTags;    // cache tags, i.e., char codes
 
495
};
 
496
 
 
497
T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A,
 
498
                         double m21A, double m22A,
 
499
                         int glyphXA, int glyphYA, int glyphWA, int glyphHA,
 
500
                         GBool validBBoxA, GBool aa) {
 
501
  int i;
 
502
 
 
503
  fontID = *fontIDA;
 
504
  m11 = m11A;
 
505
  m12 = m12A;
 
506
  m21 = m21A;
 
507
  m22 = m22A;
 
508
  glyphX = glyphXA;
 
509
  glyphY = glyphYA;
 
510
  glyphW = glyphWA;
 
511
  glyphH = glyphHA;
 
512
  validBBox = validBBoxA;
 
513
  if (aa) {
 
514
    glyphSize = glyphW * glyphH;
 
515
  } else {
 
516
    glyphSize = ((glyphW + 7) >> 3) * glyphH;
 
517
  }
 
518
  cacheAssoc = 8;
 
519
  if (glyphSize <= 256) {
 
520
    cacheSets = 8;
 
521
  } else if (glyphSize <= 512) {
 
522
    cacheSets = 4;
 
523
  } else if (glyphSize <= 1024) {
 
524
    cacheSets = 2;
 
525
  } else {
 
526
    cacheSets = 1;
 
527
  }
 
528
  cacheData = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize);
 
529
  cacheTags = (T3FontCacheTag *)gmallocn(cacheSets * cacheAssoc,
 
530
                                         sizeof(T3FontCacheTag));
 
531
  for (i = 0; i < cacheSets * cacheAssoc; ++i) {
 
532
    cacheTags[i].mru = i & (cacheAssoc - 1);
 
533
  }
 
534
}
 
535
 
 
536
T3FontCache::~T3FontCache() {
 
537
  gfree(cacheData);
 
538
  gfree(cacheTags);
 
539
}
 
540
 
 
541
struct T3GlyphStack {
 
542
  Gushort code;                 // character code
 
543
 
 
544
  //----- cache info
 
545
  T3FontCache *cache;           // font cache for the current font
 
546
  T3FontCacheTag *cacheTag;     // pointer to cache tag for the glyph
 
547
  Guchar *cacheData;            // pointer to cache data for the glyph
 
548
 
 
549
  //----- saved state
 
550
  SplashBitmap *origBitmap;
 
551
  Splash *origSplash;
 
552
  double origCTM4, origCTM5;
 
553
 
 
554
  T3GlyphStack *next;           // next object on stack
 
555
};
 
556
 
 
557
//------------------------------------------------------------------------
 
558
// SplashTransparencyGroup
 
559
//------------------------------------------------------------------------
 
560
 
 
561
struct SplashTransparencyGroup {
 
562
  int tx, ty;                   // translation coordinates
 
563
  SplashBitmap *tBitmap;        // bitmap for transparency group
 
564
  GfxColorSpace *blendingColorSpace;
 
565
  GBool isolated;
 
566
 
 
567
  //----- saved state
 
568
  SplashBitmap *origBitmap;
 
569
  Splash *origSplash;
 
570
 
 
571
  SplashTransparencyGroup *next;
 
572
};
 
573
 
 
574
//------------------------------------------------------------------------
 
575
// SplashOutputDev
 
576
//------------------------------------------------------------------------
 
577
 
 
578
SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA,
 
579
                                 int bitmapRowPadA,
 
580
                                 GBool reverseVideoA,
 
581
                                 SplashColorPtr paperColorA,
 
582
                                 GBool bitmapTopDownA,
 
583
                                 GBool allowAntialiasA) {
 
584
  colorMode = colorModeA;
 
585
  bitmapRowPad = bitmapRowPadA;
 
586
  bitmapTopDown = bitmapTopDownA;
 
587
  allowAntialias = allowAntialiasA;
 
588
  vectorAntialias = allowAntialias &&
 
589
                      globalParams->getVectorAntialias() &&
 
590
                      colorMode != splashModeMono1;
 
591
  setupScreenParams(72.0, 72.0);
 
592
  reverseVideo = reverseVideoA;
 
593
  splashColorCopy(paperColor, paperColorA);
 
594
 
 
595
  xref = NULL;
 
596
 
 
597
  bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode,
 
598
                            colorMode != splashModeMono1, bitmapTopDown);
 
599
  splash = new Splash(bitmap, vectorAntialias, &screenParams);
 
600
  splash->clear(paperColor, 0);
 
601
 
 
602
  fontEngine = NULL;
 
603
 
 
604
  nT3Fonts = 0;
 
605
  t3GlyphStack = NULL;
 
606
 
 
607
  font = NULL;
 
608
  needFontUpdate = gFalse;
 
609
  textClipPath = NULL;
 
610
 
 
611
  transpGroupStack = NULL;
 
612
}
 
613
 
 
614
void SplashOutputDev::setupScreenParams(double hDPI, double vDPI) {
 
615
  screenParams.size = globalParams->getScreenSize();
 
616
  screenParams.dotRadius = globalParams->getScreenDotRadius();
 
617
  screenParams.gamma = (SplashCoord)globalParams->getScreenGamma();
 
618
  screenParams.blackThreshold =
 
619
      (SplashCoord)globalParams->getScreenBlackThreshold();
 
620
  screenParams.whiteThreshold =
 
621
      (SplashCoord)globalParams->getScreenWhiteThreshold();
 
622
  switch (globalParams->getScreenType()) {
 
623
  case screenDispersed:
 
624
    screenParams.type = splashScreenDispersed;
 
625
    if (screenParams.size < 0) {
 
626
      screenParams.size = 4;
 
627
    }
 
628
    break;
 
629
  case screenClustered:
 
630
    screenParams.type = splashScreenClustered;
 
631
    if (screenParams.size < 0) {
 
632
      screenParams.size = 10;
 
633
    }
 
634
    break;
 
635
  case screenStochasticClustered:
 
636
    screenParams.type = splashScreenStochasticClustered;
 
637
    if (screenParams.size < 0) {
 
638
      screenParams.size = 100;
 
639
    }
 
640
    if (screenParams.dotRadius < 0) {
 
641
      screenParams.dotRadius = 2;
 
642
    }
 
643
    break;
 
644
  case screenUnset:
 
645
  default:
 
646
    // use clustered dithering for resolution >= 300 dpi
 
647
    // (compare to 299.9 to avoid floating point issues)
 
648
    if (hDPI > 299.9 && vDPI > 299.9) {
 
649
      screenParams.type = splashScreenStochasticClustered;
 
650
      if (screenParams.size < 0) {
 
651
        screenParams.size = 100;
 
652
      }
 
653
      if (screenParams.dotRadius < 0) {
 
654
        screenParams.dotRadius = 2;
 
655
      }
 
656
    } else {
 
657
      screenParams.type = splashScreenDispersed;
 
658
      if (screenParams.size < 0) {
 
659
        screenParams.size = 4;
 
660
      }
 
661
    }
 
662
  }
 
663
}
 
664
 
 
665
SplashOutputDev::~SplashOutputDev() {
 
666
  int i;
 
667
 
 
668
  for (i = 0; i < nT3Fonts; ++i) {
 
669
    delete t3FontCache[i];
 
670
  }
 
671
  if (fontEngine) {
 
672
    delete fontEngine;
 
673
  }
 
674
  if (splash) {
 
675
    delete splash;
 
676
  }
 
677
  if (bitmap) {
 
678
    delete bitmap;
 
679
  }
 
680
}
 
681
 
 
682
void SplashOutputDev::startDoc(XRef *xrefA) {
 
683
  int i;
 
684
 
 
685
  xref = xrefA;
 
686
  if (fontEngine) {
 
687
    delete fontEngine;
 
688
  }
 
689
  fontEngine = new SplashFontEngine(
 
690
#if HAVE_T1LIB_H
 
691
                                    globalParams->getEnableT1lib(),
 
692
#endif
 
693
#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
 
694
                                    globalParams->getEnableFreeType(),
 
695
#endif
 
696
                                    allowAntialias &&
 
697
                                      globalParams->getAntialias() &&
 
698
                                      colorMode != splashModeMono1);
 
699
  for (i = 0; i < nT3Fonts; ++i) {
 
700
    delete t3FontCache[i];
 
701
  }
 
702
  nT3Fonts = 0;
 
703
}
 
704
 
 
705
void SplashOutputDev::startPage(int pageNum, GfxState *state) {
 
706
  int w, h;
 
707
  double *ctm;
 
708
  SplashCoord mat[6];
 
709
  SplashColor color;
 
710
 
 
711
  if (state) {
 
712
    setupScreenParams(state->getHDPI(), state->getVDPI());
 
713
    w = (int)(state->getPageWidth() + 0.5);
 
714
    if (w <= 0) {
 
715
      w = 1;
 
716
    }
 
717
    h = (int)(state->getPageHeight() + 0.5);
 
718
    if (h <= 0) {
 
719
      h = 1;
 
720
    }
 
721
  } else {
 
722
    w = h = 1;
 
723
  }
 
724
  if (splash) {
 
725
    delete splash;
 
726
  }
 
727
  if (!bitmap || w != bitmap->getWidth() || h != bitmap->getHeight()) {
 
728
    if (bitmap) {
 
729
      delete bitmap;
 
730
    }
 
731
    bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode,
 
732
                              colorMode != splashModeMono1, bitmapTopDown);
 
733
  }
 
734
  splash = new Splash(bitmap, vectorAntialias, &screenParams);
 
735
  if (state) {
 
736
    ctm = state->getCTM();
 
737
    mat[0] = (SplashCoord)ctm[0];
 
738
    mat[1] = (SplashCoord)ctm[1];
 
739
    mat[2] = (SplashCoord)ctm[2];
 
740
    mat[3] = (SplashCoord)ctm[3];
 
741
    mat[4] = (SplashCoord)ctm[4];
 
742
    mat[5] = (SplashCoord)ctm[5];
 
743
    splash->setMatrix(mat);
 
744
  }
 
745
  switch (colorMode) {
 
746
  case splashModeMono1:
 
747
  case splashModeMono8:
 
748
    color[0] = 0;
 
749
    break;
 
750
  case splashModeRGB8:
 
751
  case splashModeBGR8:
 
752
    color[0] = color[1] = color[2] = 0;
 
753
    break;
 
754
#if SPLASH_CMYK
 
755
  case splashModeCMYK8:
 
756
    color[0] = color[1] = color[2] = color[3] = 0;
 
757
    break;
 
758
#endif
 
759
  }
 
760
  splash->setStrokePattern(new SplashSolidColor(color));
 
761
  splash->setFillPattern(new SplashSolidColor(color));
 
762
  splash->setLineCap(splashLineCapButt);
 
763
  splash->setLineJoin(splashLineJoinMiter);
 
764
  splash->setLineDash(NULL, 0, 0);
 
765
  splash->setMiterLimit(10);
 
766
  splash->setFlatness(1);
 
767
  // the SA parameter supposedly defaults to false, but Acrobat
 
768
  // apparently hardwires it to true
 
769
  splash->setStrokeAdjust(globalParams->getStrokeAdjust());
 
770
  splash->clear(paperColor, 0);
 
771
}
 
772
 
 
773
void SplashOutputDev::endPage() {
 
774
  if (colorMode != splashModeMono1) {
 
775
    splash->compositeBackground(paperColor);
 
776
  }
 
777
}
 
778
 
 
779
void SplashOutputDev::saveState(GfxState *state) {
 
780
  splash->saveState();
 
781
}
 
782
 
 
783
void SplashOutputDev::restoreState(GfxState *state) {
 
784
  splash->restoreState();
 
785
  needFontUpdate = gTrue;
 
786
}
 
787
 
 
788
void SplashOutputDev::updateAll(GfxState *state) {
 
789
  updateLineDash(state);
 
790
  updateLineJoin(state);
 
791
  updateLineCap(state);
 
792
  updateLineWidth(state);
 
793
  updateFlatness(state);
 
794
  updateMiterLimit(state);
 
795
  updateStrokeAdjust(state);
 
796
  updateFillColor(state);
 
797
  updateStrokeColor(state);
 
798
  needFontUpdate = gTrue;
 
799
}
 
800
 
 
801
void SplashOutputDev::updateCTM(GfxState *state, double m11, double m12,
 
802
                                double m21, double m22,
 
803
                                double m31, double m32) {
 
804
  double *ctm;
 
805
  SplashCoord mat[6];
 
806
 
 
807
  ctm = state->getCTM();
 
808
  mat[0] = (SplashCoord)ctm[0];
 
809
  mat[1] = (SplashCoord)ctm[1];
 
810
  mat[2] = (SplashCoord)ctm[2];
 
811
  mat[3] = (SplashCoord)ctm[3];
 
812
  mat[4] = (SplashCoord)ctm[4];
 
813
  mat[5] = (SplashCoord)ctm[5];
 
814
  splash->setMatrix(mat);
 
815
}
 
816
 
 
817
void SplashOutputDev::updateLineDash(GfxState *state) {
 
818
  double *dashPattern;
 
819
  int dashLength;
 
820
  double dashStart;
 
821
  SplashCoord dash[20];
 
822
  int i;
 
823
 
 
824
  state->getLineDash(&dashPattern, &dashLength, &dashStart);
 
825
  if (dashLength > 20) {
 
826
    dashLength = 20;
 
827
  }
 
828
  for (i = 0; i < dashLength; ++i) {
 
829
    dash[i] = (SplashCoord)dashPattern[i];
 
830
    if (dash[i] < 0) {
 
831
      dash[i] = 0;
 
832
    }
 
833
  }
 
834
  splash->setLineDash(dash, dashLength, (SplashCoord)dashStart);
 
835
}
 
836
 
 
837
void SplashOutputDev::updateFlatness(GfxState *state) {
 
838
  splash->setFlatness(state->getFlatness());
 
839
}
 
840
 
 
841
void SplashOutputDev::updateLineJoin(GfxState *state) {
 
842
  splash->setLineJoin(state->getLineJoin());
 
843
}
 
844
 
 
845
void SplashOutputDev::updateLineCap(GfxState *state) {
 
846
  splash->setLineCap(state->getLineCap());
 
847
}
 
848
 
 
849
void SplashOutputDev::updateMiterLimit(GfxState *state) {
 
850
  splash->setMiterLimit(state->getMiterLimit());
 
851
}
 
852
 
 
853
void SplashOutputDev::updateLineWidth(GfxState *state) {
 
854
  splash->setLineWidth(state->getLineWidth());
 
855
}
 
856
 
 
857
void SplashOutputDev::updateStrokeAdjust(GfxState *state) {
 
858
#if 0 // the SA parameter supposedly defaults to false, but Acrobat
 
859
      // apparently hardwires it to true
 
860
  splash->setStrokeAdjust(state->getStrokeAdjust());
 
861
#endif
 
862
}
 
863
 
 
864
void SplashOutputDev::updateFillColor(GfxState *state) {
 
865
  GfxGray gray;
 
866
  GfxRGB rgb;
 
867
#if SPLASH_CMYK
 
868
  GfxCMYK cmyk;
 
869
#endif
 
870
 
 
871
  state->getFillGray(&gray);
 
872
  state->getFillRGB(&rgb);
 
873
#if SPLASH_CMYK
 
874
  state->getFillCMYK(&cmyk);
 
875
  splash->setFillPattern(getColor(gray, &rgb, &cmyk));
 
876
#else
 
877
  splash->setFillPattern(getColor(gray, &rgb));
 
878
#endif
 
879
}
 
880
 
 
881
void SplashOutputDev::updateStrokeColor(GfxState *state) {
 
882
  GfxGray gray;
 
883
  GfxRGB rgb;
 
884
#if SPLASH_CMYK
 
885
  GfxCMYK cmyk;
 
886
#endif
 
887
 
 
888
  state->getStrokeGray(&gray);
 
889
  state->getStrokeRGB(&rgb);
 
890
#if SPLASH_CMYK
 
891
  state->getStrokeCMYK(&cmyk);
 
892
  splash->setStrokePattern(getColor(gray, &rgb, &cmyk));
 
893
#else
 
894
  splash->setStrokePattern(getColor(gray, &rgb));
 
895
#endif
 
896
}
 
897
 
 
898
#if SPLASH_CMYK
 
899
SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb,
 
900
                                         GfxCMYK *cmyk) {
 
901
#else
 
902
SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) {
 
903
#endif
 
904
  SplashPattern *pattern;
 
905
  SplashColor color;
 
906
  GfxColorComp r, g, b;
 
907
 
 
908
  if (reverseVideo) {
 
909
    gray = gfxColorComp1 - gray;
 
910
    r = gfxColorComp1 - rgb->r;
 
911
    g = gfxColorComp1 - rgb->g;
 
912
    b = gfxColorComp1 - rgb->b;
 
913
  } else {
 
914
    r = rgb->r;
 
915
    g = rgb->g;
 
916
    b = rgb->b;
 
917
  }
 
918
 
 
919
  pattern = NULL; // make gcc happy
 
920
  switch (colorMode) {
 
921
  case splashModeMono1:
 
922
  case splashModeMono8:
 
923
    color[0] = colToByte(gray);
 
924
    pattern = new SplashSolidColor(color);
 
925
    break;
 
926
  case splashModeRGB8:
 
927
  case splashModeBGR8:
 
928
    color[0] = colToByte(r);
 
929
    color[1] = colToByte(g);
 
930
    color[2] = colToByte(b);
 
931
    pattern = new SplashSolidColor(color);
 
932
    break;
 
933
#if SPLASH_CMYK
 
934
  case splashModeCMYK8:
 
935
    color[0] = colToByte(cmyk->c);
 
936
    color[1] = colToByte(cmyk->m);
 
937
    color[2] = colToByte(cmyk->y);
 
938
    color[3] = colToByte(cmyk->k);
 
939
    pattern = new SplashSolidColor(color);
 
940
    break;
 
941
#endif
 
942
  }
 
943
 
 
944
  return pattern;
 
945
}
 
946
 
 
947
void SplashOutputDev::updateBlendMode(GfxState *state) {
 
948
  splash->setBlendFunc(splashOutBlendFuncs[state->getBlendMode()]);
 
949
}
 
950
 
 
951
void SplashOutputDev::updateFillOpacity(GfxState *state) {
 
952
  splash->setFillAlpha((SplashCoord)state->getFillOpacity());
 
953
}
 
954
 
 
955
void SplashOutputDev::updateStrokeOpacity(GfxState *state) {
 
956
  splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity());
 
957
}
 
958
 
 
959
void SplashOutputDev::updateFont(GfxState *state) {
 
960
  needFontUpdate = gTrue;
 
961
}
 
962
 
 
963
void SplashOutputDev::doUpdateFont(GfxState *state) {
 
964
  GfxFont *gfxFont;
 
965
  GfxFontType fontType;
 
966
  SplashOutFontFileID *id;
 
967
  SplashFontFile *fontFile;
 
968
  FoFiTrueType *ff;
 
969
  Ref embRef;
 
970
  Object refObj, strObj;
 
971
  GString *tmpFileName, *fileName, *substName;
 
972
  FILE *tmpFile;
 
973
  Gushort *codeToGID;
 
974
  DisplayFontParam *dfp;
 
975
  CharCodeToUnicode *ctu;
 
976
  double *textMat;
 
977
  double m11, m12, m21, m22, w1, w2, fontSize;
 
978
  SplashCoord mat[4];
 
979
  char *name;
 
980
  Unicode uBuf[8];
 
981
  int c, substIdx, n, code, cmap;
 
982
 
 
983
  needFontUpdate = gFalse;
 
984
  font = NULL;
 
985
  tmpFileName = NULL;
 
986
  substIdx = -1;
 
987
  dfp = NULL;
 
988
 
 
989
  if (!(gfxFont = state->getFont())) {
 
990
    goto err1;
 
991
  }
 
992
  fontType = gfxFont->getType();
 
993
  if (fontType == fontType3) {
 
994
    goto err1;
 
995
  }
 
996
 
 
997
  // check the font file cache
 
998
  id = new SplashOutFontFileID(gfxFont->getID());
 
999
  if ((fontFile = fontEngine->getFontFile(id))) {
 
1000
    delete id;
 
1001
 
 
1002
  } else {
 
1003
 
 
1004
    // if there is an embedded font, write it to disk
 
1005
    if (gfxFont->getEmbeddedFontID(&embRef)) {
 
1006
      if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
 
1007
        error(-1, "Couldn't create temporary font file");
 
1008
        goto err2;
 
1009
      }
 
1010
      refObj.initRef(embRef.num, embRef.gen);
 
1011
      refObj.fetch(xref, &strObj);
 
1012
      refObj.free();
 
1013
      if (!strObj.isStream()) {
 
1014
        error(-1, "Embedded font object is wrong type");
 
1015
        strObj.free();
 
1016
        fclose(tmpFile);
 
1017
        goto err2;
 
1018
      }
 
1019
      strObj.streamReset();
 
1020
      while ((c = strObj.streamGetChar()) != EOF) {
 
1021
        fputc(c, tmpFile);
 
1022
      }
 
1023
      strObj.streamClose();
 
1024
      strObj.free();
 
1025
      fclose(tmpFile);
 
1026
      fileName = tmpFileName;
 
1027
 
 
1028
    // if there is an external font file, use it
 
1029
    } else if (!(fileName = gfxFont->getExtFontFile())) {
 
1030
 
 
1031
      // look for a display font mapping or a substitute font
 
1032
      if (gfxFont->isCIDFont()) {
 
1033
        if (((GfxCIDFont *)gfxFont)->getCollection()) {
 
1034
          dfp = globalParams->
 
1035
                  getDisplayCIDFont(gfxFont->getName(),
 
1036
                                    ((GfxCIDFont *)gfxFont)->getCollection());
 
1037
        }
 
1038
      } else {
 
1039
        if (gfxFont->getName()) {
 
1040
          dfp = globalParams->getDisplayFont(gfxFont->getName());
 
1041
        }
 
1042
        if (!dfp) {
 
1043
          // 8-bit font substitution
 
1044
          if (gfxFont->isFixedWidth()) {
 
1045
            substIdx = 8;
 
1046
          } else if (gfxFont->isSerif()) {
 
1047
            substIdx = 4;
 
1048
          } else {
 
1049
            substIdx = 0;
 
1050
          }
 
1051
          if (gfxFont->isBold()) {
 
1052
            substIdx += 2;
 
1053
          }
 
1054
          if (gfxFont->isItalic()) {
 
1055
            substIdx += 1;
 
1056
          }
 
1057
          substName = new GString(splashOutSubstFonts[substIdx].name);
 
1058
          dfp = globalParams->getDisplayFont(substName);
 
1059
          delete substName;
 
1060
          id->setSubstIdx(substIdx);
 
1061
        }
 
1062
      }
 
1063
      if (!dfp) {
 
1064
        error(-1, "Couldn't find a font for '%s'",
 
1065
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
1066
                                 : "(unnamed)");
 
1067
        goto err2;
 
1068
      }
 
1069
      switch (dfp->kind) {
 
1070
      case displayFontT1:
 
1071
        fileName = dfp->t1.fileName;
 
1072
        fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
 
1073
        break;
 
1074
      case displayFontTT:
 
1075
        fileName = dfp->tt.fileName;
 
1076
        fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
 
1077
        break;
 
1078
      }
 
1079
    }
 
1080
 
 
1081
    // load the font file
 
1082
    switch (fontType) {
 
1083
    case fontType1:
 
1084
      if (!(fontFile = fontEngine->loadType1Font(
 
1085
                           id,
 
1086
                           fileName->getCString(),
 
1087
                           fileName == tmpFileName,
 
1088
                           ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
 
1089
        error(-1, "Couldn't create a font for '%s'",
 
1090
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
1091
                                 : "(unnamed)");
 
1092
        goto err2;
 
1093
      }
 
1094
      break;
 
1095
    case fontType1C:
 
1096
      if (!(fontFile = fontEngine->loadType1CFont(
 
1097
                           id,
 
1098
                           fileName->getCString(),
 
1099
                           fileName == tmpFileName,
 
1100
                           ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
 
1101
        error(-1, "Couldn't create a font for '%s'",
 
1102
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
1103
                                 : "(unnamed)");
 
1104
        goto err2;
 
1105
      }
 
1106
      break;
 
1107
    case fontType1COT:
 
1108
      if (!(fontFile = fontEngine->loadOpenTypeT1CFont(
 
1109
                           id,
 
1110
                           fileName->getCString(),
 
1111
                           fileName == tmpFileName,
 
1112
                           ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
 
1113
        error(-1, "Couldn't create a font for '%s'",
 
1114
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
1115
                                 : "(unnamed)");
 
1116
        goto err2;
 
1117
      }
 
1118
      break;
 
1119
    case fontTrueType:
 
1120
    case fontTrueTypeOT:
 
1121
      if ((ff = FoFiTrueType::load(fileName->getCString()))) {
 
1122
        codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
 
1123
        n = 256;
 
1124
        delete ff;
 
1125
      } else {
 
1126
        codeToGID = NULL;
 
1127
        n = 0;
 
1128
      }
 
1129
      if (!(fontFile = fontEngine->loadTrueTypeFont(
 
1130
                           id,
 
1131
                           fileName->getCString(),
 
1132
                           fileName == tmpFileName,
 
1133
                           codeToGID, n))) {
 
1134
        error(-1, "Couldn't create a font for '%s'",
 
1135
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
1136
                                 : "(unnamed)");
 
1137
        goto err2;
 
1138
      }
 
1139
      break;
 
1140
    case fontCIDType0:
 
1141
    case fontCIDType0C:
 
1142
      if (!(fontFile = fontEngine->loadCIDFont(
 
1143
                           id,
 
1144
                           fileName->getCString(),
 
1145
                           fileName == tmpFileName))) {
 
1146
        error(-1, "Couldn't create a font for '%s'",
 
1147
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
1148
                                 : "(unnamed)");
 
1149
        goto err2;
 
1150
      }
 
1151
      break;
 
1152
    case fontCIDType0COT:
 
1153
      if (!(fontFile = fontEngine->loadOpenTypeCFFFont(
 
1154
                           id,
 
1155
                           fileName->getCString(),
 
1156
                           fileName == tmpFileName))) {
 
1157
        error(-1, "Couldn't create a font for '%s'",
 
1158
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
1159
                                 : "(unnamed)");
 
1160
        goto err2;
 
1161
      }
 
1162
      break;
 
1163
    case fontCIDType2:
 
1164
    case fontCIDType2OT:
 
1165
      codeToGID = NULL;
 
1166
      n = 0;
 
1167
      if (dfp) {
 
1168
        // create a CID-to-GID mapping, via Unicode
 
1169
        if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) {
 
1170
          if ((ff = FoFiTrueType::load(fileName->getCString()))) {
 
1171
            // look for a Unicode cmap
 
1172
            for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) {
 
1173
              if ((ff->getCmapPlatform(cmap) == 3 &&
 
1174
                   ff->getCmapEncoding(cmap) == 1) ||
 
1175
                  ff->getCmapPlatform(cmap) == 0) {
 
1176
                break;
 
1177
              }
 
1178
            }
 
1179
            if (cmap < ff->getNumCmaps()) {
 
1180
              // map CID -> Unicode -> GID
 
1181
              n = ctu->getLength();
 
1182
              codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
 
1183
              for (code = 0; code < n; ++code) {
 
1184
                if (ctu->mapToUnicode(code, uBuf, 8) > 0) {
 
1185
                  codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]);
 
1186
                } else {
 
1187
                  codeToGID[code] = 0;
 
1188
                }
 
1189
              }
 
1190
            }
 
1191
            delete ff;
 
1192
          }
 
1193
          ctu->decRefCnt();
 
1194
        } else {
 
1195
          error(-1, "Couldn't find a mapping to Unicode for font '%s'",
 
1196
                gfxFont->getName() ? gfxFont->getName()->getCString()
 
1197
                                   : "(unnamed)");
 
1198
        }
 
1199
      } else {
 
1200
        if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
 
1201
          n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
 
1202
          codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
 
1203
          memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
 
1204
                 n * sizeof(Gushort));
 
1205
        }
 
1206
      }
 
1207
      if (!(fontFile = fontEngine->loadTrueTypeFont(
 
1208
                           id,
 
1209
                           fileName->getCString(),
 
1210
                           fileName == tmpFileName,
 
1211
                           codeToGID, n))) {
 
1212
        error(-1, "Couldn't create a font for '%s'",
 
1213
              gfxFont->getName() ? gfxFont->getName()->getCString()
 
1214
                                 : "(unnamed)");
 
1215
        goto err2;
 
1216
      }
 
1217
      break;
 
1218
    default:
 
1219
      // this shouldn't happen
 
1220
      goto err2;
 
1221
    }
 
1222
  }
 
1223
 
 
1224
  // get the font matrix
 
1225
  textMat = state->getTextMat();
 
1226
  fontSize = state->getFontSize();
 
1227
  m11 = textMat[0] * fontSize * state->getHorizScaling();
 
1228
  m12 = textMat[1] * fontSize * state->getHorizScaling();
 
1229
  m21 = textMat[2] * fontSize;
 
1230
  m22 = textMat[3] * fontSize;
 
1231
 
 
1232
  // for substituted fonts: adjust the font matrix -- compare the
 
1233
  // width of 'm' in the original font and the substituted font
 
1234
  substIdx = ((SplashOutFontFileID *)fontFile->getID())->getSubstIdx();
 
1235
  if (substIdx >= 0) {
 
1236
    for (code = 0; code < 256; ++code) {
 
1237
      if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
 
1238
          name[0] == 'm' && name[1] == '\0') {
 
1239
        break;
 
1240
      }
 
1241
    }
 
1242
    if (code < 256) {
 
1243
      w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
 
1244
      w2 = splashOutSubstFonts[substIdx].mWidth;
 
1245
      if (!gfxFont->isSymbolic()) {
 
1246
        // if real font is substantially narrower than substituted
 
1247
        // font, reduce the font size accordingly
 
1248
        if (w1 > 0.01 && w1 < 0.9 * w2) {
 
1249
          w1 /= w2;
 
1250
          m11 *= w1;
 
1251
          m21 *= w1;
 
1252
        }
 
1253
      }
 
1254
    }
 
1255
  }
 
1256
 
 
1257
  // create the scaled font
 
1258
  mat[0] = m11;  mat[1] = m12;
 
1259
  mat[2] = m21;  mat[3] = m22;
 
1260
  font = fontEngine->getFont(fontFile, mat, splash->getMatrix());
 
1261
 
 
1262
  if (tmpFileName) {
 
1263
    delete tmpFileName;
 
1264
  }
 
1265
  return;
 
1266
 
 
1267
 err2:
 
1268
  delete id;
 
1269
 err1:
 
1270
  if (tmpFileName) {
 
1271
    unlink(tmpFileName->getCString());
 
1272
    delete tmpFileName;
 
1273
  }
 
1274
  return;
 
1275
}
 
1276
 
 
1277
void SplashOutputDev::stroke(GfxState *state) {
 
1278
  SplashPath *path;
 
1279
 
 
1280
  if (state->getStrokeColorSpace()->isNonMarking()) {
 
1281
    return;
 
1282
  }
 
1283
  path = convertPath(state, state->getPath());
 
1284
  splash->stroke(path);
 
1285
  delete path;
 
1286
}
 
1287
 
 
1288
void SplashOutputDev::fill(GfxState *state) {
 
1289
  SplashPath *path;
 
1290
 
 
1291
  if (state->getFillColorSpace()->isNonMarking()) {
 
1292
    return;
 
1293
  }
 
1294
  path = convertPath(state, state->getPath());
 
1295
  splash->fill(path, gFalse);
 
1296
  delete path;
 
1297
}
 
1298
 
 
1299
void SplashOutputDev::eoFill(GfxState *state) {
 
1300
  SplashPath *path;
 
1301
 
 
1302
  if (state->getFillColorSpace()->isNonMarking()) {
 
1303
    return;
 
1304
  }
 
1305
  path = convertPath(state, state->getPath());
 
1306
  splash->fill(path, gTrue);
 
1307
  delete path;
 
1308
}
 
1309
 
 
1310
void SplashOutputDev::clip(GfxState *state) {
 
1311
  SplashPath *path;
 
1312
 
 
1313
  path = convertPath(state, state->getPath());
 
1314
  splash->clipToPath(path, gFalse);
 
1315
  delete path;
 
1316
}
 
1317
 
 
1318
void SplashOutputDev::eoClip(GfxState *state) {
 
1319
  SplashPath *path;
 
1320
 
 
1321
  path = convertPath(state, state->getPath());
 
1322
  splash->clipToPath(path, gTrue);
 
1323
  delete path;
 
1324
}
 
1325
 
 
1326
void SplashOutputDev::clipToStrokePath(GfxState *state) {
 
1327
  SplashPath *path, *path2;
 
1328
 
 
1329
  path = convertPath(state, state->getPath());
 
1330
  path2 = splash->makeStrokePath(path);
 
1331
  delete path;
 
1332
  splash->clipToPath(path2, gFalse);
 
1333
  delete path2;
 
1334
}
 
1335
 
 
1336
SplashPath *SplashOutputDev::convertPath(GfxState *state, GfxPath *path) {
 
1337
  SplashPath *sPath;
 
1338
  GfxSubpath *subpath;
 
1339
  int i, j;
 
1340
 
 
1341
  sPath = new SplashPath();
 
1342
  for (i = 0; i < path->getNumSubpaths(); ++i) {
 
1343
    subpath = path->getSubpath(i);
 
1344
    if (subpath->getNumPoints() > 0) {
 
1345
      sPath->moveTo((SplashCoord)subpath->getX(0),
 
1346
                    (SplashCoord)subpath->getY(0));
 
1347
      j = 1;
 
1348
      while (j < subpath->getNumPoints()) {
 
1349
        if (subpath->getCurve(j)) {
 
1350
          sPath->curveTo((SplashCoord)subpath->getX(j),
 
1351
                         (SplashCoord)subpath->getY(j),
 
1352
                         (SplashCoord)subpath->getX(j+1),
 
1353
                         (SplashCoord)subpath->getY(j+1),
 
1354
                         (SplashCoord)subpath->getX(j+2),
 
1355
                         (SplashCoord)subpath->getY(j+2));
 
1356
          j += 3;
 
1357
        } else {
 
1358
          sPath->lineTo((SplashCoord)subpath->getX(j),
 
1359
                        (SplashCoord)subpath->getY(j));
 
1360
          ++j;
 
1361
        }
 
1362
      }
 
1363
      if (subpath->isClosed()) {
 
1364
        sPath->close();
 
1365
      }
 
1366
    }
 
1367
  }
 
1368
  return sPath;
 
1369
}
 
1370
 
 
1371
void SplashOutputDev::drawChar(GfxState *state, double x, double y,
 
1372
                               double dx, double dy,
 
1373
                               double originX, double originY,
 
1374
                               CharCode code, int nBytes,
 
1375
                               Unicode *u, int uLen) {
 
1376
  SplashPath *path;
 
1377
  int render;
 
1378
 
 
1379
  // check for invisible text -- this is used by Acrobat Capture
 
1380
  render = state->getRender();
 
1381
  if (render == 3) {
 
1382
    return;
 
1383
  }
 
1384
 
 
1385
  if (needFontUpdate) {
 
1386
    doUpdateFont(state);
 
1387
  }
 
1388
  if (!font) {
 
1389
    return;
 
1390
  }
 
1391
 
 
1392
  x -= originX;
 
1393
  y -= originY;
 
1394
 
 
1395
  // fill
 
1396
  if (!(render & 1)) {
 
1397
    if (!state->getFillColorSpace()->isNonMarking()) {
 
1398
      splash->fillChar((SplashCoord)x, (SplashCoord)y, code, font);
 
1399
    }
 
1400
  }
 
1401
 
 
1402
  // stroke
 
1403
  if ((render & 3) == 1 || (render & 3) == 2) {
 
1404
    if (!state->getStrokeColorSpace()->isNonMarking()) {
 
1405
      if ((path = font->getGlyphPath(code))) {
 
1406
        path->offset((SplashCoord)x, (SplashCoord)y);
 
1407
        splash->stroke(path);
 
1408
        delete path;
 
1409
      }
 
1410
    }
 
1411
  }
 
1412
 
 
1413
  // clip
 
1414
  if (render & 4) {
 
1415
    if ((path = font->getGlyphPath(code))) {
 
1416
      path->offset((SplashCoord)x, (SplashCoord)y);
 
1417
      if (textClipPath) {
 
1418
        textClipPath->append(path);
 
1419
        delete path;
 
1420
      } else {
 
1421
        textClipPath = path;
 
1422
      }
 
1423
    }
 
1424
  }
 
1425
}
 
1426
 
 
1427
GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y,
 
1428
                                      double dx, double dy,
 
1429
                                      CharCode code, Unicode *u, int uLen) {
 
1430
  GfxFont *gfxFont;
 
1431
  Ref *fontID;
 
1432
  double *ctm, *bbox;
 
1433
  T3FontCache *t3Font;
 
1434
  T3GlyphStack *t3gs;
 
1435
  GBool validBBox;
 
1436
  double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
 
1437
  int i, j;
 
1438
 
 
1439
  if (!(gfxFont = state->getFont())) {
 
1440
    return gFalse;
 
1441
  }
 
1442
  fontID = gfxFont->getID();
 
1443
  ctm = state->getCTM();
 
1444
  state->transform(0, 0, &xt, &yt);
 
1445
 
 
1446
  // is it the first (MRU) font in the cache?
 
1447
  if (!(nT3Fonts > 0 &&
 
1448
        t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) {
 
1449
 
 
1450
    // is the font elsewhere in the cache?
 
1451
    for (i = 1; i < nT3Fonts; ++i) {
 
1452
      if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) {
 
1453
        t3Font = t3FontCache[i];
 
1454
        for (j = i; j > 0; --j) {
 
1455
          t3FontCache[j] = t3FontCache[j - 1];
 
1456
        }
 
1457
        t3FontCache[0] = t3Font;
 
1458
        break;
 
1459
      }
 
1460
    }
 
1461
    if (i >= nT3Fonts) {
 
1462
 
 
1463
      // create new entry in the font cache
 
1464
      if (nT3Fonts == splashOutT3FontCacheSize) {
 
1465
        delete t3FontCache[nT3Fonts - 1];
 
1466
        --nT3Fonts;
 
1467
      }
 
1468
      for (j = nT3Fonts; j > 0; --j) {
 
1469
        t3FontCache[j] = t3FontCache[j - 1];
 
1470
      }
 
1471
      ++nT3Fonts;
 
1472
      bbox = gfxFont->getFontBBox();
 
1473
      if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) {
 
1474
        // unspecified bounding box -- just take a guess
 
1475
        xMin = xt - 5;
 
1476
        xMax = xMin + 30;
 
1477
        yMax = yt + 15;
 
1478
        yMin = yMax - 45;
 
1479
        validBBox = gFalse;
 
1480
      } else {
 
1481
        state->transform(bbox[0], bbox[1], &x1, &y1);
 
1482
        xMin = xMax = x1;
 
1483
        yMin = yMax = y1;
 
1484
        state->transform(bbox[0], bbox[3], &x1, &y1);
 
1485
        if (x1 < xMin) {
 
1486
          xMin = x1;
 
1487
        } else if (x1 > xMax) {
 
1488
          xMax = x1;
 
1489
        }
 
1490
        if (y1 < yMin) {
 
1491
          yMin = y1;
 
1492
        } else if (y1 > yMax) {
 
1493
          yMax = y1;
 
1494
        }
 
1495
        state->transform(bbox[2], bbox[1], &x1, &y1);
 
1496
        if (x1 < xMin) {
 
1497
          xMin = x1;
 
1498
        } else if (x1 > xMax) {
 
1499
          xMax = x1;
 
1500
        }
 
1501
        if (y1 < yMin) {
 
1502
          yMin = y1;
 
1503
        } else if (y1 > yMax) {
 
1504
          yMax = y1;
 
1505
        }
 
1506
        state->transform(bbox[2], bbox[3], &x1, &y1);
 
1507
        if (x1 < xMin) {
 
1508
          xMin = x1;
 
1509
        } else if (x1 > xMax) {
 
1510
          xMax = x1;
 
1511
        }
 
1512
        if (y1 < yMin) {
 
1513
          yMin = y1;
 
1514
        } else if (y1 > yMax) {
 
1515
          yMax = y1;
 
1516
        }
 
1517
        validBBox = gTrue;
 
1518
      }
 
1519
      t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3],
 
1520
                                       (int)floor(xMin - xt),
 
1521
                                       (int)floor(yMin - yt),
 
1522
                                       (int)ceil(xMax) - (int)floor(xMin) + 3,
 
1523
                                       (int)ceil(yMax) - (int)floor(yMin) + 3,
 
1524
                                       validBBox,
 
1525
                                       colorMode != splashModeMono1);
 
1526
    }
 
1527
  }
 
1528
  t3Font = t3FontCache[0];
 
1529
 
 
1530
  // is the glyph in the cache?
 
1531
  i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
 
1532
  for (j = 0; j < t3Font->cacheAssoc; ++j) {
 
1533
    if ((t3Font->cacheTags[i+j].mru & 0x8000) &&
 
1534
        t3Font->cacheTags[i+j].code == code) {
 
1535
      drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
 
1536
                     t3Font->cacheData + (i+j) * t3Font->glyphSize);
 
1537
      return gTrue;
 
1538
    }
 
1539
  }
 
1540
 
 
1541
  // push a new Type 3 glyph record
 
1542
  t3gs = new T3GlyphStack();
 
1543
  t3gs->next = t3GlyphStack;
 
1544
  t3GlyphStack = t3gs;
 
1545
  t3GlyphStack->code = code;
 
1546
  t3GlyphStack->cache = t3Font;
 
1547
  t3GlyphStack->cacheTag = NULL;
 
1548
  t3GlyphStack->cacheData = NULL;
 
1549
 
 
1550
  return gFalse;
 
1551
}
 
1552
 
 
1553
void SplashOutputDev::endType3Char(GfxState *state) {
 
1554
  T3GlyphStack *t3gs;
 
1555
  double *ctm;
 
1556
 
 
1557
  if (t3GlyphStack->cacheTag) {
 
1558
    memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(),
 
1559
           t3GlyphStack->cache->glyphSize);
 
1560
    delete bitmap;
 
1561
    delete splash;
 
1562
    bitmap = t3GlyphStack->origBitmap;
 
1563
    splash = t3GlyphStack->origSplash;
 
1564
    ctm = state->getCTM();
 
1565
    state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
 
1566
                  t3GlyphStack->origCTM4, t3GlyphStack->origCTM5);
 
1567
    updateCTM(state, 0, 0, 0, 0, 0, 0);
 
1568
    drawType3Glyph(t3GlyphStack->cache,
 
1569
                   t3GlyphStack->cacheTag, t3GlyphStack->cacheData);
 
1570
  }
 
1571
  t3gs = t3GlyphStack;
 
1572
  t3GlyphStack = t3gs->next;
 
1573
  delete t3gs;
 
1574
}
 
1575
 
 
1576
void SplashOutputDev::type3D0(GfxState *state, double wx, double wy) {
 
1577
}
 
1578
 
 
1579
void SplashOutputDev::type3D1(GfxState *state, double wx, double wy,
 
1580
                              double llx, double lly, double urx, double ury) {
 
1581
  double *ctm;
 
1582
  T3FontCache *t3Font;
 
1583
  SplashColor color;
 
1584
  double xt, yt, xMin, xMax, yMin, yMax, x1, y1;
 
1585
  int i, j;
 
1586
 
 
1587
  t3Font = t3GlyphStack->cache;
 
1588
 
 
1589
  // check for a valid bbox
 
1590
  state->transform(0, 0, &xt, &yt);
 
1591
  state->transform(llx, lly, &x1, &y1);
 
1592
  xMin = xMax = x1;
 
1593
  yMin = yMax = y1;
 
1594
  state->transform(llx, ury, &x1, &y1);
 
1595
  if (x1 < xMin) {
 
1596
    xMin = x1;
 
1597
  } else if (x1 > xMax) {
 
1598
    xMax = x1;
 
1599
  }
 
1600
  if (y1 < yMin) {
 
1601
    yMin = y1;
 
1602
  } else if (y1 > yMax) {
 
1603
    yMax = y1;
 
1604
  }
 
1605
  state->transform(urx, lly, &x1, &y1);
 
1606
  if (x1 < xMin) {
 
1607
    xMin = x1;
 
1608
  } else if (x1 > xMax) {
 
1609
    xMax = x1;
 
1610
  }
 
1611
  if (y1 < yMin) {
 
1612
    yMin = y1;
 
1613
  } else if (y1 > yMax) {
 
1614
    yMax = y1;
 
1615
  }
 
1616
  state->transform(urx, ury, &x1, &y1);
 
1617
  if (x1 < xMin) {
 
1618
    xMin = x1;
 
1619
  } else if (x1 > xMax) {
 
1620
    xMax = x1;
 
1621
  }
 
1622
  if (y1 < yMin) {
 
1623
    yMin = y1;
 
1624
  } else if (y1 > yMax) {
 
1625
    yMax = y1;
 
1626
  }
 
1627
  if (xMin - xt < t3Font->glyphX ||
 
1628
      yMin - yt < t3Font->glyphY ||
 
1629
      xMax - xt > t3Font->glyphX + t3Font->glyphW ||
 
1630
      yMax - yt > t3Font->glyphY + t3Font->glyphH) {
 
1631
    if (t3Font->validBBox) {
 
1632
      error(-1, "Bad bounding box in Type 3 glyph");
 
1633
    }
 
1634
    return;
 
1635
  }
 
1636
 
 
1637
  // allocate a cache entry
 
1638
  i = (t3GlyphStack->code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
 
1639
  for (j = 0; j < t3Font->cacheAssoc; ++j) {
 
1640
    if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) {
 
1641
      t3Font->cacheTags[i+j].mru = 0x8000;
 
1642
      t3Font->cacheTags[i+j].code = t3GlyphStack->code;
 
1643
      t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j];
 
1644
      t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize;
 
1645
    } else {
 
1646
      ++t3Font->cacheTags[i+j].mru;
 
1647
    }
 
1648
  }
 
1649
 
 
1650
  // save state
 
1651
  t3GlyphStack->origBitmap = bitmap;
 
1652
  t3GlyphStack->origSplash = splash;
 
1653
  ctm = state->getCTM();
 
1654
  t3GlyphStack->origCTM4 = ctm[4];
 
1655
  t3GlyphStack->origCTM5 = ctm[5];
 
1656
 
 
1657
  // create the temporary bitmap
 
1658
  if (colorMode == splashModeMono1) {
 
1659
    bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
 
1660
                              splashModeMono1, gFalse);
 
1661
    splash = new Splash(bitmap, gFalse,
 
1662
                        t3GlyphStack->origSplash->getScreen());
 
1663
    color[0] = 0;
 
1664
    splash->clear(color);
 
1665
    color[0] = 1;
 
1666
  } else {
 
1667
    bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
 
1668
                              splashModeMono8, gFalse);
 
1669
    splash = new Splash(bitmap, vectorAntialias,
 
1670
                        t3GlyphStack->origSplash->getScreen());
 
1671
    color[0] = 0x00;
 
1672
    splash->clear(color);
 
1673
    color[0] = 0xff;
 
1674
  }
 
1675
  splash->setFillPattern(new SplashSolidColor(color));
 
1676
  splash->setStrokePattern(new SplashSolidColor(color));
 
1677
  //~ this should copy other state from t3GlyphStack->origSplash?
 
1678
  state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
 
1679
                -t3Font->glyphX, -t3Font->glyphY);
 
1680
  updateCTM(state, 0, 0, 0, 0, 0, 0);
 
1681
}
 
1682
 
 
1683
void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font,
 
1684
                                     T3FontCacheTag *tag, Guchar *data) {
 
1685
  SplashGlyphBitmap glyph;
 
1686
 
 
1687
  glyph.x = -t3Font->glyphX;
 
1688
  glyph.y = -t3Font->glyphY;
 
1689
  glyph.w = t3Font->glyphW;
 
1690
  glyph.h = t3Font->glyphH;
 
1691
  glyph.aa = colorMode != splashModeMono1;
 
1692
  glyph.data = data;
 
1693
  glyph.freeData = gFalse;
 
1694
  splash->fillGlyph(0, 0, &glyph);
 
1695
}
 
1696
 
 
1697
void SplashOutputDev::endTextObject(GfxState *state) {
 
1698
  if (textClipPath) {
 
1699
    splash->clipToPath(textClipPath, gFalse);
 
1700
    delete textClipPath;
 
1701
    textClipPath = NULL;
 
1702
  }
 
1703
}
 
1704
 
 
1705
struct SplashOutImageMaskData {
 
1706
  ImageStream *imgStr;
 
1707
  GBool invert;
 
1708
  int width, height, y;
 
1709
};
 
1710
 
 
1711
GBool SplashOutputDev::imageMaskSrc(void *data, SplashColorPtr line) {
 
1712
  SplashOutImageMaskData *imgMaskData = (SplashOutImageMaskData *)data;
 
1713
  Guchar *p;
 
1714
  SplashColorPtr q;
 
1715
  int x;
 
1716
 
 
1717
  if (imgMaskData->y == imgMaskData->height) {
 
1718
    return gFalse;
 
1719
  }
 
1720
  for (x = 0, p = imgMaskData->imgStr->getLine(), q = line;
 
1721
       x < imgMaskData->width;
 
1722
       ++x) {
 
1723
    *q++ = *p++ ^ imgMaskData->invert;
 
1724
  }
 
1725
  ++imgMaskData->y;
 
1726
  return gTrue;
 
1727
}
 
1728
 
 
1729
void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
 
1730
                                    int width, int height, GBool invert,
 
1731
                                    GBool inlineImg) {
 
1732
  double *ctm;
 
1733
  SplashCoord mat[6];
 
1734
  SplashOutImageMaskData imgMaskData;
 
1735
 
 
1736
  if (state->getFillColorSpace()->isNonMarking()) {
 
1737
    return;
 
1738
  }
 
1739
 
 
1740
  ctm = state->getCTM();
 
1741
  mat[0] = ctm[0];
 
1742
  mat[1] = ctm[1];
 
1743
  mat[2] = -ctm[2];
 
1744
  mat[3] = -ctm[3];
 
1745
  mat[4] = ctm[2] + ctm[4];
 
1746
  mat[5] = ctm[3] + ctm[5];
 
1747
 
 
1748
  imgMaskData.imgStr = new ImageStream(str, width, 1, 1);
 
1749
  imgMaskData.imgStr->reset();
 
1750
  imgMaskData.invert = invert ? 0 : 1;
 
1751
  imgMaskData.width = width;
 
1752
  imgMaskData.height = height;
 
1753
  imgMaskData.y = 0;
 
1754
 
 
1755
  splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat,
 
1756
                        t3GlyphStack != NULL);
 
1757
  if (inlineImg) {
 
1758
    while (imgMaskData.y < height) {
 
1759
      imgMaskData.imgStr->getLine();
 
1760
      ++imgMaskData.y;
 
1761
    }
 
1762
  }
 
1763
 
 
1764
  delete imgMaskData.imgStr;
 
1765
  str->close();
 
1766
}
 
1767
 
 
1768
struct SplashOutImageData {
 
1769
  ImageStream *imgStr;
 
1770
  GfxImageColorMap *colorMap;
 
1771
  SplashColorPtr lookup;
 
1772
  int *maskColors;
 
1773
  SplashColorMode colorMode;
 
1774
  int width, height, y;
 
1775
};
 
1776
 
 
1777
GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine,
 
1778
                                Guchar *alphaLine) {
 
1779
  SplashOutImageData *imgData = (SplashOutImageData *)data;
 
1780
  Guchar *p;
 
1781
  SplashColorPtr q, col;
 
1782
  GfxRGB rgb;
 
1783
  GfxGray gray;
 
1784
#if SPLASH_CMYK
 
1785
  GfxCMYK cmyk;
 
1786
#endif
 
1787
  int nComps, x;
 
1788
 
 
1789
  if (imgData->y == imgData->height) {
 
1790
    return gFalse;
 
1791
  }
 
1792
 
 
1793
  nComps = imgData->colorMap->getNumPixelComps();
 
1794
 
 
1795
  if (imgData->lookup) {
 
1796
    switch (imgData->colorMode) {
 
1797
    case splashModeMono1:
 
1798
    case splashModeMono8:
 
1799
      for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
 
1800
           x < imgData->width;
 
1801
           ++x, ++p) {
 
1802
        *q++ = imgData->lookup[*p];
 
1803
      }
 
1804
      break;
 
1805
    case splashModeRGB8:
 
1806
    case splashModeBGR8:
 
1807
      for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
 
1808
           x < imgData->width;
 
1809
           ++x, ++p) {
 
1810
        col = &imgData->lookup[3 * *p];
 
1811
        *q++ = col[0];
 
1812
        *q++ = col[1];
 
1813
        *q++ = col[2];
 
1814
      }
 
1815
      break;
 
1816
#if SPLASH_CMYK
 
1817
    case splashModeCMYK8:
 
1818
      for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
 
1819
           x < imgData->width;
 
1820
           ++x, ++p) {
 
1821
        col = &imgData->lookup[4 * *p];
 
1822
        *q++ = col[0];
 
1823
        *q++ = col[1];
 
1824
        *q++ = col[2];
 
1825
        *q++ = col[3];
 
1826
      }
 
1827
      break;
 
1828
#endif
 
1829
    }
 
1830
  } else {
 
1831
    switch (imgData->colorMode) {
 
1832
    case splashModeMono1:
 
1833
    case splashModeMono8:
 
1834
      for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
 
1835
           x < imgData->width;
 
1836
           ++x, p += nComps) {
 
1837
        imgData->colorMap->getGray(p, &gray);
 
1838
        *q++ = colToByte(gray);
 
1839
      }
 
1840
      break;
 
1841
    case splashModeRGB8:
 
1842
    case splashModeBGR8:
 
1843
      for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
 
1844
           x < imgData->width;
 
1845
           ++x, p += nComps) {
 
1846
        imgData->colorMap->getRGB(p, &rgb);
 
1847
        *q++ = colToByte(rgb.r);
 
1848
        *q++ = colToByte(rgb.g);
 
1849
        *q++ = colToByte(rgb.b);
 
1850
      }
 
1851
      break;
 
1852
#if SPLASH_CMYK
 
1853
    case splashModeCMYK8:
 
1854
      for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
 
1855
           x < imgData->width;
 
1856
           ++x, p += nComps) {
 
1857
        imgData->colorMap->getCMYK(p, &cmyk);
 
1858
        *q++ = colToByte(cmyk.c);
 
1859
        *q++ = colToByte(cmyk.m);
 
1860
        *q++ = colToByte(cmyk.y);
 
1861
        *q++ = colToByte(cmyk.k);
 
1862
      }
 
1863
      break;
 
1864
#endif
 
1865
    }
 
1866
  }
 
1867
 
 
1868
  ++imgData->y;
 
1869
  return gTrue;
 
1870
}
 
1871
 
 
1872
GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine,
 
1873
                                     Guchar *alphaLine) {
 
1874
  SplashOutImageData *imgData = (SplashOutImageData *)data;
 
1875
  Guchar *p, *aq;
 
1876
  SplashColorPtr q, col;
 
1877
  GfxRGB rgb;
 
1878
  GfxGray gray;
 
1879
#if SPLASH_CMYK
 
1880
  GfxCMYK cmyk;
 
1881
#endif
 
1882
  Guchar alpha;
 
1883
  int nComps, x, i;
 
1884
 
 
1885
  if (imgData->y == imgData->height) {
 
1886
    return gFalse;
 
1887
  }
 
1888
 
 
1889
  nComps = imgData->colorMap->getNumPixelComps();
 
1890
 
 
1891
  for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine;
 
1892
       x < imgData->width;
 
1893
       ++x, p += nComps) {
 
1894
    alpha = 0;
 
1895
    for (i = 0; i < nComps; ++i) {
 
1896
      if (p[i] < imgData->maskColors[2*i] ||
 
1897
          p[i] > imgData->maskColors[2*i+1]) {
 
1898
        alpha = 0xff;
 
1899
        break;
 
1900
      }
 
1901
    }
 
1902
    if (imgData->lookup) {
 
1903
      switch (imgData->colorMode) {
 
1904
      case splashModeMono1:
 
1905
      case splashModeMono8:
 
1906
        *q++ = imgData->lookup[*p];
 
1907
        *aq++ = alpha;
 
1908
        break;
 
1909
      case splashModeRGB8:
 
1910
      case splashModeBGR8:
 
1911
        col = &imgData->lookup[3 * *p];
 
1912
        *q++ = col[0];
 
1913
        *q++ = col[1];
 
1914
        *q++ = col[2];
 
1915
        *aq++ = alpha;
 
1916
        break;
 
1917
#if SPLASH_CMYK
 
1918
      case splashModeCMYK8:
 
1919
        col = &imgData->lookup[4 * *p];
 
1920
        *q++ = col[0];
 
1921
        *q++ = col[1];
 
1922
        *q++ = col[2];
 
1923
        *q++ = col[3];
 
1924
        *aq++ = alpha;
 
1925
        break;
 
1926
#endif
 
1927
      }
 
1928
    } else {
 
1929
      switch (imgData->colorMode) {
 
1930
      case splashModeMono1:
 
1931
      case splashModeMono8:
 
1932
        imgData->colorMap->getGray(p, &gray);
 
1933
        *q++ = colToByte(gray);
 
1934
        *aq++ = alpha;
 
1935
        break;
 
1936
      case splashModeRGB8:
 
1937
      case splashModeBGR8:
 
1938
        imgData->colorMap->getRGB(p, &rgb);
 
1939
        *q++ = colToByte(rgb.r);
 
1940
        *q++ = colToByte(rgb.g);
 
1941
        *q++ = colToByte(rgb.b);
 
1942
        *aq++ = alpha;
 
1943
        break;
 
1944
#if SPLASH_CMYK
 
1945
      case splashModeCMYK8:
 
1946
        imgData->colorMap->getCMYK(p, &cmyk);
 
1947
        *q++ = colToByte(cmyk.c);
 
1948
        *q++ = colToByte(cmyk.m);
 
1949
        *q++ = colToByte(cmyk.y);
 
1950
        *q++ = colToByte(cmyk.k);
 
1951
        *aq++ = alpha;
 
1952
        break;
 
1953
#endif
 
1954
      }
 
1955
    }
 
1956
  }
 
1957
 
 
1958
  ++imgData->y;
 
1959
  return gTrue;
 
1960
}
 
1961
 
 
1962
void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
 
1963
                                int width, int height,
 
1964
                                GfxImageColorMap *colorMap,
 
1965
                                int *maskColors, GBool inlineImg) {
 
1966
  double *ctm;
 
1967
  SplashCoord mat[6];
 
1968
  SplashOutImageData imgData;
 
1969
  SplashColorMode srcMode;
 
1970
  SplashImageSource src;
 
1971
  GfxGray gray;
 
1972
  GfxRGB rgb;
 
1973
#if SPLASH_CMYK
 
1974
  GfxCMYK cmyk;
 
1975
#endif
 
1976
  Guchar pix;
 
1977
  int n, i;
 
1978
 
 
1979
  ctm = state->getCTM();
 
1980
  mat[0] = ctm[0];
 
1981
  mat[1] = ctm[1];
 
1982
  mat[2] = -ctm[2];
 
1983
  mat[3] = -ctm[3];
 
1984
  mat[4] = ctm[2] + ctm[4];
 
1985
  mat[5] = ctm[3] + ctm[5];
 
1986
 
 
1987
  imgData.imgStr = new ImageStream(str, width,
 
1988
                                   colorMap->getNumPixelComps(),
 
1989
                                   colorMap->getBits());
 
1990
  imgData.imgStr->reset();
 
1991
  imgData.colorMap = colorMap;
 
1992
  imgData.maskColors = maskColors;
 
1993
  imgData.colorMode = colorMode;
 
1994
  imgData.width = width;
 
1995
  imgData.height = height;
 
1996
  imgData.y = 0;
 
1997
 
 
1998
  // special case for one-channel (monochrome/gray/separation) images:
 
1999
  // build a lookup table here
 
2000
  imgData.lookup = NULL;
 
2001
  if (colorMap->getNumPixelComps() == 1) {
 
2002
    n = 1 << colorMap->getBits();
 
2003
    switch (colorMode) {
 
2004
    case splashModeMono1:
 
2005
    case splashModeMono8:
 
2006
      imgData.lookup = (SplashColorPtr)gmalloc(n);
 
2007
      for (i = 0; i < n; ++i) {
 
2008
        pix = (Guchar)i;
 
2009
        colorMap->getGray(&pix, &gray);
 
2010
        imgData.lookup[i] = colToByte(gray);
 
2011
      }
 
2012
      break;
 
2013
    case splashModeRGB8:
 
2014
    case splashModeBGR8:
 
2015
      imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
 
2016
      for (i = 0; i < n; ++i) {
 
2017
        pix = (Guchar)i;
 
2018
        colorMap->getRGB(&pix, &rgb);
 
2019
        imgData.lookup[3*i] = colToByte(rgb.r);
 
2020
        imgData.lookup[3*i+1] = colToByte(rgb.g);
 
2021
        imgData.lookup[3*i+2] = colToByte(rgb.b);
 
2022
      }
 
2023
      break;
 
2024
#if SPLASH_CMYK
 
2025
    case splashModeCMYK8:
 
2026
      imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
 
2027
      for (i = 0; i < n; ++i) {
 
2028
        pix = (Guchar)i;
 
2029
        colorMap->getCMYK(&pix, &cmyk);
 
2030
        imgData.lookup[4*i] = colToByte(cmyk.c);
 
2031
        imgData.lookup[4*i+1] = colToByte(cmyk.m);
 
2032
        imgData.lookup[4*i+2] = colToByte(cmyk.y);
 
2033
        imgData.lookup[4*i+3] = colToByte(cmyk.k);
 
2034
      }
 
2035
      break;
 
2036
#endif
 
2037
      break;
 
2038
    }
 
2039
  }
 
2040
 
 
2041
  if (colorMode == splashModeMono1) {
 
2042
    srcMode = splashModeMono8;
 
2043
  } else {
 
2044
    srcMode = colorMode;
 
2045
  }
 
2046
  src = maskColors ? &alphaImageSrc : &imageSrc;
 
2047
  splash->drawImage(src, &imgData, srcMode, maskColors ? gTrue : gFalse,
 
2048
                    width, height, mat);
 
2049
  if (inlineImg) {
 
2050
    while (imgData.y < height) {
 
2051
      imgData.imgStr->getLine();
 
2052
      ++imgData.y;
 
2053
    }
 
2054
  }
 
2055
 
 
2056
  gfree(imgData.lookup);
 
2057
  delete imgData.imgStr;
 
2058
  str->close();
 
2059
}
 
2060
 
 
2061
struct SplashOutMaskedImageData {
 
2062
  ImageStream *imgStr;
 
2063
  GfxImageColorMap *colorMap;
 
2064
  SplashBitmap *mask;
 
2065
  SplashColorPtr lookup;
 
2066
  SplashColorMode colorMode;
 
2067
  int width, height, y;
 
2068
};
 
2069
 
 
2070
GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine,
 
2071
                                      Guchar *alphaLine) {
 
2072
  SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data;
 
2073
  Guchar *p, *aq;
 
2074
  SplashColor maskColor;
 
2075
  SplashColorPtr q, col;
 
2076
  GfxRGB rgb;
 
2077
  GfxGray gray;
 
2078
#if SPLASH_CMYK
 
2079
  GfxCMYK cmyk;
 
2080
#endif
 
2081
  Guchar alpha;
 
2082
  int nComps, x;
 
2083
 
 
2084
  if (imgData->y == imgData->height) {
 
2085
    return gFalse;
 
2086
  }
 
2087
 
 
2088
  nComps = imgData->colorMap->getNumPixelComps();
 
2089
 
 
2090
  for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine;
 
2091
       x < imgData->width;
 
2092
       ++x, p += nComps) {
 
2093
    imgData->mask->getPixel(x, imgData->y, maskColor);
 
2094
    alpha = maskColor[0] ? 0xff : 0x00;
 
2095
    if (imgData->lookup) {
 
2096
      switch (imgData->colorMode) {
 
2097
      case splashModeMono1:
 
2098
      case splashModeMono8:
 
2099
        *q++ = imgData->lookup[*p];
 
2100
        *aq++ = alpha;
 
2101
        break;
 
2102
      case splashModeRGB8:
 
2103
      case splashModeBGR8:
 
2104
        col = &imgData->lookup[3 * *p];
 
2105
        *q++ = col[0];
 
2106
        *q++ = col[1];
 
2107
        *q++ = col[2];
 
2108
        *aq++ = alpha;
 
2109
        break;
 
2110
#if SPLASH_CMYK
 
2111
      case splashModeCMYK8:
 
2112
        col = &imgData->lookup[4 * *p];
 
2113
        *q++ = col[0];
 
2114
        *q++ = col[1];
 
2115
        *q++ = col[2];
 
2116
        *q++ = col[3];
 
2117
        *aq++ = alpha;
 
2118
        break;
 
2119
#endif
 
2120
      }
 
2121
    } else {
 
2122
      switch (imgData->colorMode) {
 
2123
      case splashModeMono1:
 
2124
      case splashModeMono8:
 
2125
        imgData->colorMap->getGray(p, &gray);
 
2126
        *q++ = colToByte(gray);
 
2127
        *aq++ = alpha;
 
2128
        break;
 
2129
      case splashModeRGB8:
 
2130
      case splashModeBGR8:
 
2131
        imgData->colorMap->getRGB(p, &rgb);
 
2132
        *q++ = colToByte(rgb.r);
 
2133
        *q++ = colToByte(rgb.g);
 
2134
        *q++ = colToByte(rgb.b);
 
2135
        *aq++ = alpha;
 
2136
        break;
 
2137
#if SPLASH_CMYK
 
2138
      case splashModeCMYK8:
 
2139
        imgData->colorMap->getCMYK(p, &cmyk);
 
2140
        *q++ = colToByte(cmyk.c);
 
2141
        *q++ = colToByte(cmyk.m);
 
2142
        *q++ = colToByte(cmyk.y);
 
2143
        *q++ = colToByte(cmyk.k);
 
2144
        *aq++ = alpha;
 
2145
        break;
 
2146
#endif
 
2147
      }
 
2148
    }
 
2149
  }
 
2150
 
 
2151
  ++imgData->y;
 
2152
  return gTrue;
 
2153
}
 
2154
 
 
2155
void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
 
2156
                                      Stream *str, int width, int height,
 
2157
                                      GfxImageColorMap *colorMap,
 
2158
                                      Stream *maskStr, int maskWidth,
 
2159
                                      int maskHeight, GBool maskInvert) {
 
2160
  GfxImageColorMap *maskColorMap;
 
2161
  Object maskDecode, decodeLow, decodeHigh;
 
2162
  double *ctm;
 
2163
  SplashCoord mat[6];
 
2164
  SplashOutMaskedImageData imgData;
 
2165
  SplashOutImageMaskData imgMaskData;
 
2166
  SplashColorMode srcMode;
 
2167
  SplashBitmap *maskBitmap;
 
2168
  Splash *maskSplash;
 
2169
  SplashColor maskColor;
 
2170
  GfxGray gray;
 
2171
  GfxRGB rgb;
 
2172
#if SPLASH_CMYK
 
2173
  GfxCMYK cmyk;
 
2174
#endif
 
2175
  Guchar pix;
 
2176
  int n, i;
 
2177
 
 
2178
  // If the mask is higher resolution than the image, use
 
2179
  // drawSoftMaskedImage() instead.
 
2180
  if (maskWidth > width || maskHeight > height) {
 
2181
    decodeLow.initInt(maskInvert ? 0 : 1);
 
2182
    decodeHigh.initInt(maskInvert ? 1 : 0);
 
2183
    maskDecode.initArray(xref);
 
2184
    maskDecode.arrayAdd(&decodeLow);
 
2185
    maskDecode.arrayAdd(&decodeHigh);
 
2186
    maskColorMap = new GfxImageColorMap(1, &maskDecode,
 
2187
                                        new GfxDeviceGrayColorSpace());
 
2188
    maskDecode.free();
 
2189
    drawSoftMaskedImage(state, ref, str, width, height, colorMap,
 
2190
                        maskStr, maskWidth, maskHeight, maskColorMap);
 
2191
    delete maskColorMap;
 
2192
 
 
2193
  } else {
 
2194
 
 
2195
    //----- scale the mask image to the same size as the source image
 
2196
 
 
2197
    mat[0] = (SplashCoord)width;
 
2198
    mat[1] = 0;
 
2199
    mat[2] = 0;
 
2200
    mat[3] = (SplashCoord)height;
 
2201
    mat[4] = 0;
 
2202
    mat[5] = 0;
 
2203
    imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
 
2204
    imgMaskData.imgStr->reset();
 
2205
    imgMaskData.invert = maskInvert ? 0 : 1;
 
2206
    imgMaskData.width = maskWidth;
 
2207
    imgMaskData.height = maskHeight;
 
2208
    imgMaskData.y = 0;
 
2209
    maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1, gFalse);
 
2210
    maskSplash = new Splash(maskBitmap, gFalse);
 
2211
    maskColor[0] = 0;
 
2212
    maskSplash->clear(maskColor);
 
2213
    maskColor[0] = 0xff;
 
2214
    maskSplash->setFillPattern(new SplashSolidColor(maskColor));
 
2215
    maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData,
 
2216
                              maskWidth, maskHeight, mat, gFalse);
 
2217
    delete imgMaskData.imgStr;
 
2218
    maskStr->close();
 
2219
    delete maskSplash;
 
2220
 
 
2221
    //----- draw the source image
 
2222
 
 
2223
    ctm = state->getCTM();
 
2224
    mat[0] = ctm[0];
 
2225
    mat[1] = ctm[1];
 
2226
    mat[2] = -ctm[2];
 
2227
    mat[3] = -ctm[3];
 
2228
    mat[4] = ctm[2] + ctm[4];
 
2229
    mat[5] = ctm[3] + ctm[5];
 
2230
 
 
2231
    imgData.imgStr = new ImageStream(str, width,
 
2232
                                     colorMap->getNumPixelComps(),
 
2233
                                     colorMap->getBits());
 
2234
    imgData.imgStr->reset();
 
2235
    imgData.colorMap = colorMap;
 
2236
    imgData.mask = maskBitmap;
 
2237
    imgData.colorMode = colorMode;
 
2238
    imgData.width = width;
 
2239
    imgData.height = height;
 
2240
    imgData.y = 0;
 
2241
 
 
2242
    // special case for one-channel (monochrome/gray/separation) images:
 
2243
    // build a lookup table here
 
2244
    imgData.lookup = NULL;
 
2245
    if (colorMap->getNumPixelComps() == 1) {
 
2246
      n = 1 << colorMap->getBits();
 
2247
      switch (colorMode) {
 
2248
      case splashModeMono1:
 
2249
      case splashModeMono8:
 
2250
        imgData.lookup = (SplashColorPtr)gmalloc(n);
 
2251
        for (i = 0; i < n; ++i) {
 
2252
          pix = (Guchar)i;
 
2253
          colorMap->getGray(&pix, &gray);
 
2254
          imgData.lookup[i] = colToByte(gray);
 
2255
        }
 
2256
        break;
 
2257
      case splashModeRGB8:
 
2258
      case splashModeBGR8:
 
2259
        imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
 
2260
        for (i = 0; i < n; ++i) {
 
2261
          pix = (Guchar)i;
 
2262
          colorMap->getRGB(&pix, &rgb);
 
2263
          imgData.lookup[3*i] = colToByte(rgb.r);
 
2264
          imgData.lookup[3*i+1] = colToByte(rgb.g);
 
2265
          imgData.lookup[3*i+2] = colToByte(rgb.b);
 
2266
        }
 
2267
        break;
 
2268
#if SPLASH_CMYK
 
2269
      case splashModeCMYK8:
 
2270
        imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
 
2271
        for (i = 0; i < n; ++i) {
 
2272
          pix = (Guchar)i;
 
2273
          colorMap->getCMYK(&pix, &cmyk);
 
2274
          imgData.lookup[4*i] = colToByte(cmyk.c);
 
2275
          imgData.lookup[4*i+1] = colToByte(cmyk.m);
 
2276
          imgData.lookup[4*i+2] = colToByte(cmyk.y);
 
2277
          imgData.lookup[4*i+3] = colToByte(cmyk.k);
 
2278
        }
 
2279
        break;
 
2280
#endif
 
2281
      }
 
2282
    }
 
2283
 
 
2284
    if (colorMode == splashModeMono1) {
 
2285
      srcMode = splashModeMono8;
 
2286
    } else {
 
2287
      srcMode = colorMode;
 
2288
    }
 
2289
    splash->drawImage(&maskedImageSrc, &imgData, srcMode, gTrue,
 
2290
                      width, height, mat);
 
2291
 
 
2292
    delete maskBitmap;
 
2293
    gfree(imgData.lookup);
 
2294
    delete imgData.imgStr;
 
2295
    str->close();
 
2296
  }
 
2297
}
 
2298
 
 
2299
void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref,
 
2300
                                          Stream *str, int width, int height,
 
2301
                                          GfxImageColorMap *colorMap,
 
2302
                                          Stream *maskStr,
 
2303
                                          int maskWidth, int maskHeight,
 
2304
                                          GfxImageColorMap *maskColorMap) {
 
2305
  double *ctm;
 
2306
  SplashCoord mat[6];
 
2307
  SplashOutImageData imgData;
 
2308
  SplashOutImageData imgMaskData;
 
2309
  SplashColorMode srcMode;
 
2310
  SplashBitmap *maskBitmap;
 
2311
  Splash *maskSplash;
 
2312
  SplashColor maskColor;
 
2313
  GfxGray gray;
 
2314
  GfxRGB rgb;
 
2315
#if SPLASH_CMYK
 
2316
  GfxCMYK cmyk;
 
2317
#endif
 
2318
  Guchar pix;
 
2319
  int n, i;
 
2320
 
 
2321
  ctm = state->getCTM();
 
2322
  mat[0] = ctm[0];
 
2323
  mat[1] = ctm[1];
 
2324
  mat[2] = -ctm[2];
 
2325
  mat[3] = -ctm[3];
 
2326
  mat[4] = ctm[2] + ctm[4];
 
2327
  mat[5] = ctm[3] + ctm[5];
 
2328
 
 
2329
  //----- set up the soft mask
 
2330
 
 
2331
  imgMaskData.imgStr = new ImageStream(maskStr, maskWidth,
 
2332
                                       maskColorMap->getNumPixelComps(),
 
2333
                                       maskColorMap->getBits());
 
2334
  imgMaskData.imgStr->reset();
 
2335
  imgMaskData.colorMap = maskColorMap;
 
2336
  imgMaskData.maskColors = NULL;
 
2337
  imgMaskData.colorMode = splashModeMono8;
 
2338
  imgMaskData.width = maskWidth;
 
2339
  imgMaskData.height = maskHeight;
 
2340
  imgMaskData.y = 0;
 
2341
  n = 1 << maskColorMap->getBits();
 
2342
  imgMaskData.lookup = (SplashColorPtr)gmalloc(n);
 
2343
  for (i = 0; i < n; ++i) {
 
2344
    pix = (Guchar)i;
 
2345
    maskColorMap->getGray(&pix, &gray);
 
2346
    imgMaskData.lookup[i] = colToByte(gray);
 
2347
  }
 
2348
  maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
 
2349
                                1, splashModeMono8, gFalse);
 
2350
  maskSplash = new Splash(maskBitmap, vectorAntialias);
 
2351
  maskColor[0] = 0;
 
2352
  maskSplash->clear(maskColor);
 
2353
  maskSplash->drawImage(&imageSrc, &imgMaskData, splashModeMono8, gFalse,
 
2354
                        maskWidth, maskHeight, mat);
 
2355
  delete imgMaskData.imgStr;
 
2356
  maskStr->close();
 
2357
  gfree(imgMaskData.lookup);
 
2358
  delete maskSplash;
 
2359
  splash->setSoftMask(maskBitmap);
 
2360
 
 
2361
  //----- draw the source image
 
2362
 
 
2363
  imgData.imgStr = new ImageStream(str, width,
 
2364
                                   colorMap->getNumPixelComps(),
 
2365
                                   colorMap->getBits());
 
2366
  imgData.imgStr->reset();
 
2367
  imgData.colorMap = colorMap;
 
2368
  imgData.maskColors = NULL;
 
2369
  imgData.colorMode = colorMode;
 
2370
  imgData.width = width;
 
2371
  imgData.height = height;
 
2372
  imgData.y = 0;
 
2373
 
 
2374
  // special case for one-channel (monochrome/gray/separation) images:
 
2375
  // build a lookup table here
 
2376
  imgData.lookup = NULL;
 
2377
  if (colorMap->getNumPixelComps() == 1) {
 
2378
    n = 1 << colorMap->getBits();
 
2379
    switch (colorMode) {
 
2380
    case splashModeMono1:
 
2381
    case splashModeMono8:
 
2382
      imgData.lookup = (SplashColorPtr)gmalloc(n);
 
2383
      for (i = 0; i < n; ++i) {
 
2384
        pix = (Guchar)i;
 
2385
        colorMap->getGray(&pix, &gray);
 
2386
        imgData.lookup[i] = colToByte(gray);
 
2387
      }
 
2388
      break;
 
2389
    case splashModeRGB8:
 
2390
    case splashModeBGR8:
 
2391
      imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
 
2392
      for (i = 0; i < n; ++i) {
 
2393
        pix = (Guchar)i;
 
2394
        colorMap->getRGB(&pix, &rgb);
 
2395
        imgData.lookup[3*i] = colToByte(rgb.r);
 
2396
        imgData.lookup[3*i+1] = colToByte(rgb.g);
 
2397
        imgData.lookup[3*i+2] = colToByte(rgb.b);
 
2398
      }
 
2399
      break;
 
2400
#if SPLASH_CMYK
 
2401
    case splashModeCMYK8:
 
2402
      imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
 
2403
      for (i = 0; i < n; ++i) {
 
2404
        pix = (Guchar)i;
 
2405
        colorMap->getCMYK(&pix, &cmyk);
 
2406
        imgData.lookup[4*i] = colToByte(cmyk.c);
 
2407
        imgData.lookup[4*i+1] = colToByte(cmyk.m);
 
2408
        imgData.lookup[4*i+2] = colToByte(cmyk.y);
 
2409
        imgData.lookup[4*i+3] = colToByte(cmyk.k);
 
2410
      }
 
2411
      break;
 
2412
#endif
 
2413
    }
 
2414
  }
 
2415
 
 
2416
  if (colorMode == splashModeMono1) {
 
2417
    srcMode = splashModeMono8;
 
2418
  } else {
 
2419
    srcMode = colorMode;
 
2420
  }
 
2421
  splash->drawImage(&imageSrc, &imgData, srcMode, gFalse, width, height, mat);
 
2422
 
 
2423
  splash->setSoftMask(NULL);
 
2424
  gfree(imgData.lookup);
 
2425
  delete imgData.imgStr;
 
2426
  str->close();
 
2427
}
 
2428
 
 
2429
void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
 
2430
                                             GfxColorSpace *blendingColorSpace,
 
2431
                                             GBool isolated, GBool knockout,
 
2432
                                             GBool forSoftMask) {
 
2433
  SplashTransparencyGroup *transpGroup;
 
2434
  SplashColor color;
 
2435
  double xMin, yMin, xMax, yMax, x, y;
 
2436
  int tx, ty, w, h;
 
2437
 
 
2438
  // transform the bbox
 
2439
  state->transform(bbox[0], bbox[1], &x, &y);
 
2440
  xMin = xMax = x;
 
2441
  yMin = yMax = y;
 
2442
  state->transform(bbox[0], bbox[3], &x, &y);
 
2443
  if (x < xMin) {
 
2444
    xMin = x;
 
2445
  } else if (x > xMax) {
 
2446
    xMax = x;
 
2447
  }
 
2448
  if (y < yMin) {
 
2449
    yMin = y;
 
2450
  } else if (y > yMax) {
 
2451
    yMax = y;
 
2452
  }
 
2453
  state->transform(bbox[2], bbox[1], &x, &y);
 
2454
  if (x < xMin) {
 
2455
    xMin = x;
 
2456
  } else if (x > xMax) {
 
2457
    xMax = x;
 
2458
  }
 
2459
  if (y < yMin) {
 
2460
    yMin = y;
 
2461
  } else if (y > yMax) {
 
2462
    yMax = y;
 
2463
  }
 
2464
  state->transform(bbox[2], bbox[3], &x, &y);
 
2465
  if (x < xMin) {
 
2466
    xMin = x;
 
2467
  } else if (x > xMax) {
 
2468
    xMax = x;
 
2469
  }
 
2470
  if (y < yMin) {
 
2471
    yMin = y;
 
2472
  } else if (y > yMax) {
 
2473
    yMax = y;
 
2474
  }
 
2475
  tx = (int)floor(xMin);
 
2476
  if (tx < 0) {
 
2477
    tx = 0;
 
2478
  } else if (tx > bitmap->getWidth()) {
 
2479
    tx = bitmap->getWidth();
 
2480
  }
 
2481
  ty = (int)floor(yMin);
 
2482
  if (ty < 0) {
 
2483
    ty = 0;
 
2484
  } else if (ty > bitmap->getHeight()) {
 
2485
    ty = bitmap->getHeight();
 
2486
  }
 
2487
  w = (int)ceil(xMax) - tx + 1;
 
2488
  if (tx + w > bitmap->getWidth()) {
 
2489
    w = bitmap->getWidth() - tx;
 
2490
  }
 
2491
  if (w < 1) {
 
2492
    w = 1;
 
2493
  }
 
2494
  h = (int)ceil(yMax) - ty + 1;
 
2495
  if (ty + h > bitmap->getHeight()) {
 
2496
    h = bitmap->getHeight() - ty;
 
2497
  }
 
2498
  if (h < 1) {
 
2499
    h = 1;
 
2500
  }
 
2501
 
 
2502
  // push a new stack entry
 
2503
  transpGroup = new SplashTransparencyGroup();
 
2504
  transpGroup->tx = tx;
 
2505
  transpGroup->ty = ty;
 
2506
  transpGroup->blendingColorSpace = blendingColorSpace;
 
2507
  transpGroup->isolated = isolated;
 
2508
  transpGroup->next = transpGroupStack;
 
2509
  transpGroupStack = transpGroup;
 
2510
 
 
2511
  // save state
 
2512
  transpGroup->origBitmap = bitmap;
 
2513
  transpGroup->origSplash = splash;
 
2514
 
 
2515
  //~ this ignores the blendingColorSpace arg
 
2516
 
 
2517
  // create the temporary bitmap
 
2518
  bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue,
 
2519
                            bitmapTopDown); 
 
2520
  splash = new Splash(bitmap, vectorAntialias,
 
2521
                      transpGroup->origSplash->getScreen());
 
2522
  if (isolated) {
 
2523
    switch (colorMode) {
 
2524
    case splashModeMono1:
 
2525
    case splashModeMono8:
 
2526
      color[0] = 0;
 
2527
      break;
 
2528
    case splashModeRGB8:
 
2529
    case splashModeBGR8:
 
2530
      color[0] = color[1] = color[2] = 0;
 
2531
      break;
 
2532
#if SPLASH_CMYK
 
2533
    case splashModeCMYK8:
 
2534
      color[0] = color[1] = color[2] = color[3] = 0;
 
2535
      break;
 
2536
#endif
 
2537
    default:
 
2538
      // make gcc happy
 
2539
      break;
 
2540
    }
 
2541
    splash->clear(color, 0);
 
2542
  } else {
 
2543
    splash->blitTransparent(transpGroup->origBitmap, tx, ty, 0, 0, w, h);
 
2544
    splash->setInNonIsolatedGroup(transpGroup->origBitmap, tx, ty);
 
2545
  }
 
2546
  transpGroup->tBitmap = bitmap;
 
2547
  state->shiftCTM(-tx, -ty);
 
2548
  updateCTM(state, 0, 0, 0, 0, 0, 0);
 
2549
}
 
2550
 
 
2551
void SplashOutputDev::endTransparencyGroup(GfxState *state) {
 
2552
  double *ctm;
 
2553
 
 
2554
  // restore state
 
2555
  delete splash;
 
2556
  bitmap = transpGroupStack->origBitmap;
 
2557
  splash = transpGroupStack->origSplash;
 
2558
  ctm = state->getCTM();
 
2559
  state->shiftCTM(transpGroupStack->tx, transpGroupStack->ty);
 
2560
  updateCTM(state, 0, 0, 0, 0, 0, 0);
 
2561
}
 
2562
 
 
2563
void SplashOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) {
 
2564
  SplashBitmap *tBitmap;
 
2565
  SplashTransparencyGroup *transpGroup;
 
2566
  GBool isolated;
 
2567
  int tx, ty;
 
2568
 
 
2569
  tx = transpGroupStack->tx;
 
2570
  ty = transpGroupStack->ty;
 
2571
  tBitmap = transpGroupStack->tBitmap;
 
2572
  isolated = transpGroupStack->isolated;
 
2573
 
 
2574
  // paint the transparency group onto the parent bitmap
 
2575
  // - the clip path was set in the parent's state)
 
2576
  splash->composite(tBitmap, 0, 0, tx, ty,
 
2577
                    tBitmap->getWidth(), tBitmap->getHeight(),
 
2578
                    gFalse, !isolated);
 
2579
 
 
2580
  // pop the stack
 
2581
  transpGroup = transpGroupStack;
 
2582
  transpGroupStack = transpGroup->next;
 
2583
  delete transpGroup;
 
2584
 
 
2585
  delete tBitmap;
 
2586
}
 
2587
 
 
2588
void SplashOutputDev::setSoftMask(GfxState *state, double *bbox,
 
2589
                                  GBool alpha, Function *transferFunc,
 
2590
                                  GfxColor *backdropColor) {
 
2591
  SplashBitmap *softMask, *tBitmap;
 
2592
  Splash *tSplash;
 
2593
  SplashTransparencyGroup *transpGroup;
 
2594
  SplashColor color;
 
2595
  SplashColorPtr p;
 
2596
  GfxGray gray;
 
2597
  GfxRGB rgb;
 
2598
#if SPLASH_CMYK
 
2599
  GfxCMYK cmyk;
 
2600
#endif
 
2601
  double lum, lum2;
 
2602
  int tx, ty, x, y;
 
2603
 
 
2604
  tx = transpGroupStack->tx;
 
2605
  ty = transpGroupStack->ty;
 
2606
  tBitmap = transpGroupStack->tBitmap;
 
2607
 
 
2608
  // composite with backdrop color
 
2609
  if (!alpha && colorMode != splashModeMono1) {
 
2610
    //~ need to correctly handle the case where no blending color
 
2611
    //~ space is given
 
2612
    tSplash = new Splash(tBitmap, vectorAntialias,
 
2613
                         transpGroupStack->origSplash->getScreen());
 
2614
    if (transpGroupStack->blendingColorSpace) {
 
2615
      switch (colorMode) {
 
2616
      case splashModeMono1:
 
2617
        // transparency is not supported in mono1 mode
 
2618
        break;
 
2619
      case splashModeMono8:
 
2620
        transpGroupStack->blendingColorSpace->getGray(backdropColor, &gray);
 
2621
        color[0] = colToByte(gray);
 
2622
        tSplash->compositeBackground(color);
 
2623
        break;
 
2624
      case splashModeRGB8:
 
2625
      case splashModeBGR8:
 
2626
        transpGroupStack->blendingColorSpace->getRGB(backdropColor, &rgb);
 
2627
        color[0] = colToByte(rgb.r);
 
2628
        color[1] = colToByte(rgb.g);
 
2629
        color[2] = colToByte(rgb.b);
 
2630
        tSplash->compositeBackground(color);
 
2631
        break;
 
2632
#if SPLASH_CMYK
 
2633
      case splashModeCMYK8:
 
2634
        transpGroupStack->blendingColorSpace->getCMYK(backdropColor, &cmyk);
 
2635
        color[0] = colToByte(cmyk.c);
 
2636
        color[1] = colToByte(cmyk.m);
 
2637
        color[2] = colToByte(cmyk.y);
 
2638
        color[3] = colToByte(cmyk.k);
 
2639
        tSplash->compositeBackground(color);
 
2640
        break;
 
2641
#endif
 
2642
      }
 
2643
      delete tSplash;
 
2644
    }
 
2645
  }
 
2646
 
 
2647
  softMask = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
 
2648
                              1, splashModeMono8, gFalse);
 
2649
  memset(softMask->getDataPtr(), 0,
 
2650
         softMask->getRowSize() * softMask->getHeight());
 
2651
  p = softMask->getDataPtr() + ty * softMask->getRowSize() + tx;
 
2652
  for (y = 0; y < tBitmap->getHeight(); ++y) {
 
2653
    for (x = 0; x < tBitmap->getWidth(); ++x) {
 
2654
      tBitmap->getPixel(x, y, color);
 
2655
      if (alpha) {
 
2656
        //~ unimplemented
 
2657
      } else {
 
2658
        // convert to luminosity
 
2659
        switch (colorMode) {
 
2660
        case splashModeMono1:
 
2661
        case splashModeMono8:
 
2662
          lum = color[0] / 255.0;
 
2663
          break;
 
2664
        case splashModeRGB8:
 
2665
        case splashModeBGR8:
 
2666
          lum = (0.3 / 255.0) * color[0] +
 
2667
                (0.59 / 255.0) * color[1] +
 
2668
                (0.11 / 255.0) * color[2];
 
2669
          break;
 
2670
#if SPLASH_CMYK
 
2671
        case splashModeCMYK8:
 
2672
          lum = (1 - color[4] / 255.0)
 
2673
                - (0.3 / 255.0) * color[0]
 
2674
                - (0.59 / 255.0) * color[1]
 
2675
                - (0.11 / 255.0) * color[2];
 
2676
          if (lum < 0) {
 
2677
            lum = 0;
 
2678
          }
 
2679
          break;
 
2680
#endif
 
2681
        }
 
2682
        if (transferFunc) {
 
2683
          transferFunc->transform(&lum, &lum2);
 
2684
        } else {
 
2685
          lum2 = lum;
 
2686
        }
 
2687
        p[x] = (int)(lum2 * 255.0 + 0.5);
 
2688
      }
 
2689
    }
 
2690
    p += softMask->getRowSize();
 
2691
  }
 
2692
  splash->setSoftMask(softMask);
 
2693
 
 
2694
  // pop the stack
 
2695
  transpGroup = transpGroupStack;
 
2696
  transpGroupStack = transpGroup->next;
 
2697
  delete transpGroup;
 
2698
 
 
2699
  delete tBitmap;
 
2700
}
 
2701
 
 
2702
void SplashOutputDev::clearSoftMask(GfxState *state) {
 
2703
  splash->setSoftMask(NULL);
 
2704
}
 
2705
 
 
2706
void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA) {
 
2707
  splashColorCopy(paperColor, paperColorA);
 
2708
}
 
2709
 
 
2710
int SplashOutputDev::getBitmapWidth() {
 
2711
  return bitmap->getWidth();
 
2712
}
 
2713
 
 
2714
int SplashOutputDev::getBitmapHeight() {
 
2715
  return bitmap->getHeight();
 
2716
}
 
2717
 
 
2718
SplashBitmap *SplashOutputDev::takeBitmap() {
 
2719
  SplashBitmap *ret;
 
2720
 
 
2721
  ret = bitmap;
 
2722
  bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode,
 
2723
                            colorMode != splashModeMono1, bitmapTopDown);
 
2724
  return ret;
 
2725
}
 
2726
 
 
2727
void SplashOutputDev::getModRegion(int *xMin, int *yMin,
 
2728
                                   int *xMax, int *yMax) {
 
2729
  splash->getModRegion(xMin, yMin, xMax, yMax);
 
2730
}
 
2731
 
 
2732
void SplashOutputDev::clearModRegion() {
 
2733
  splash->clearModRegion();
 
2734
}
 
2735
 
 
2736
void SplashOutputDev::setFillColor(int r, int g, int b) {
 
2737
  GfxRGB rgb;
 
2738
  GfxGray gray;
 
2739
#if SPLASH_CMYK
 
2740
  GfxCMYK cmyk;
 
2741
#endif
 
2742
 
 
2743
  rgb.r = byteToCol(r);
 
2744
  rgb.g = byteToCol(g);
 
2745
  rgb.b = byteToCol(b);
 
2746
  gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g + 0.5);
 
2747
  if (gray > gfxColorComp1) {
 
2748
    gray = gfxColorComp1;
 
2749
  }
 
2750
#if SPLASH_CMYK
 
2751
  cmyk.c = gfxColorComp1 - rgb.r;
 
2752
  cmyk.m = gfxColorComp1 - rgb.g;
 
2753
  cmyk.y = gfxColorComp1 - rgb.b;
 
2754
  cmyk.k = 0;
 
2755
  splash->setFillPattern(getColor(gray, &rgb, &cmyk));
 
2756
#else
 
2757
  splash->setFillPattern(getColor(gray, &rgb));
 
2758
#endif
 
2759
}
 
2760
 
 
2761
SplashFont *SplashOutputDev::getFont(GString *name, double *textMatA) {
 
2762
  DisplayFontParam *dfp;
 
2763
  Ref ref;
 
2764
  SplashOutFontFileID *id;
 
2765
  SplashFontFile *fontFile;
 
2766
  SplashFont *fontObj;
 
2767
  FoFiTrueType *ff;
 
2768
  Gushort *codeToGID;
 
2769
  Unicode u;
 
2770
  SplashCoord textMat[4];
 
2771
  int cmap, i;
 
2772
 
 
2773
  for (i = 0; i < 16; ++i) {
 
2774
    if (!name->cmp(splashOutSubstFonts[i].name)) {
 
2775
      break;
 
2776
    }
 
2777
  }
 
2778
  if (i == 16) {
 
2779
    return NULL;
 
2780
  }
 
2781
  ref.num = i;
 
2782
  ref.gen = -1;
 
2783
  id = new SplashOutFontFileID(&ref);
 
2784
 
 
2785
  // check the font file cache
 
2786
  if ((fontFile = fontEngine->getFontFile(id))) {
 
2787
    delete id;
 
2788
 
 
2789
  // load the font file
 
2790
  } else {
 
2791
    dfp = globalParams->getDisplayFont(name);
 
2792
    if (dfp && dfp->kind == displayFontT1) {
 
2793
      fontFile = fontEngine->loadType1Font(id, dfp->t1.fileName->getCString(),
 
2794
                                           gFalse, winAnsiEncoding);
 
2795
    } else if (dfp && dfp->kind == displayFontTT) {
 
2796
      if (!(ff = FoFiTrueType::load(dfp->tt.fileName->getCString()))) {
 
2797
        return NULL;
 
2798
      }
 
2799
      for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) {
 
2800
        if ((ff->getCmapPlatform(cmap) == 3 &&
 
2801
             ff->getCmapEncoding(cmap) == 1) ||
 
2802
            ff->getCmapPlatform(cmap) == 0) {
 
2803
          break;
 
2804
        }
 
2805
      }
 
2806
      if (cmap == ff->getNumCmaps()) {
 
2807
        delete ff;
 
2808
        return NULL;
 
2809
      }
 
2810
      codeToGID = (Gushort *)gmallocn(256, sizeof(Gushort));
 
2811
      for (i = 0; i < 256; ++i) {
 
2812
        codeToGID[i] = 0;
 
2813
        if (winAnsiEncoding[i] &&
 
2814
            (u = globalParams->mapNameToUnicode(winAnsiEncoding[i]))) {
 
2815
          codeToGID[i] = ff->mapCodeToGID(cmap, u);
 
2816
        }
 
2817
      }
 
2818
      delete ff;
 
2819
      fontFile = fontEngine->loadTrueTypeFont(id,
 
2820
                                              dfp->tt.fileName->getCString(),
 
2821
                                              gFalse, codeToGID, 256);
 
2822
    } else {
 
2823
      return NULL;
 
2824
    }
 
2825
  }
 
2826
 
 
2827
  // create the scaled font
 
2828
  textMat[0] = (SplashCoord)textMatA[0];
 
2829
  textMat[1] = (SplashCoord)textMatA[1];
 
2830
  textMat[2] = (SplashCoord)textMatA[2];
 
2831
  textMat[3] = (SplashCoord)textMatA[3];
 
2832
  fontObj = fontEngine->getFont(fontFile, textMat, splash->getMatrix());
 
2833
 
 
2834
  return fontObj;
 
2835
}
 
2836
 
 
2837
#if 1 //~tmp: turn off anti-aliasing temporarily
 
2838
GBool SplashOutputDev::getVectorAntialias() {
 
2839
  return splash->getVectorAntialias();
 
2840
}
 
2841
 
 
2842
void SplashOutputDev::setVectorAntialias(GBool vaa) {
 
2843
  splash->setVectorAntialias(vaa);
 
2844
}
 
2845
#endif