Coverage Report

Created: 2026-10-13 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xpdf-4.06/xpdf/GfxState.cc
Line
Count
Source
1
//========================================================================
2
//
3
// GfxState.cc
4
//
5
// Copyright 1996-2016 Glyph & Cog, LLC
6
//
7
//========================================================================
8
9
#include <aconf.h>
10
11
#include <stddef.h>
12
#include <math.h>
13
#include <string.h>
14
#include "gmem.h"
15
#include "gmempp.h"
16
#include "Error.h"
17
#include "GlobalParams.h"
18
#include "LocalParams.h"
19
#include "Object.h"
20
#include "Array.h"
21
#include "Page.h"
22
#include "XRef.h"
23
#include "GfxState.h"
24
25
//------------------------------------------------------------------------
26
27
// Max depth of nested color spaces.  This is used to catch infinite
28
// loops in the color space object structure.
29
40.8k
#define colorSpaceRecursionLimit 8
30
31
32
//------------------------------------------------------------------------
33
34
11.5M
static inline GfxColorComp clip01(GfxColorComp x) {
35
11.5M
  return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x;
36
11.5M
}
37
38
16.2k
static inline double clip01(double x) {
39
16.2k
  return (x < 0) ? 0 : (x > 1) ? 1 : x;
40
16.2k
}
41
42
//------------------------------------------------------------------------
43
44
struct GfxBlendModeInfo {
45
  const char *name;
46
  GfxBlendMode mode;
47
};
48
49
static GfxBlendModeInfo gfxBlendModeNames[] = {
50
  { "Normal",     gfxBlendNormal },
51
  { "Compatible", gfxBlendNormal },
52
  { "Multiply",   gfxBlendMultiply },
53
  { "Screen",     gfxBlendScreen },
54
  { "Overlay",    gfxBlendOverlay },
55
  { "Darken",     gfxBlendDarken },
56
  { "Lighten",    gfxBlendLighten },
57
  { "ColorDodge", gfxBlendColorDodge },
58
  { "ColorBurn",  gfxBlendColorBurn },
59
  { "HardLight",  gfxBlendHardLight },
60
  { "SoftLight",  gfxBlendSoftLight },
61
  { "Difference", gfxBlendDifference },
62
  { "Exclusion",  gfxBlendExclusion },
63
  { "Hue",        gfxBlendHue },
64
  { "Saturation", gfxBlendSaturation },
65
  { "Color",      gfxBlendColor },
66
  { "Luminosity", gfxBlendLuminosity }
67
};
68
69
#define nGfxBlendModeNames \
70
13.8k
          ((int)((sizeof(gfxBlendModeNames) / sizeof(GfxBlendModeInfo))))
71
72
//------------------------------------------------------------------------
73
74
// NB: This must match the GfxColorSpaceMode enum defined in
75
// GfxState.h
76
static const char *gfxColorSpaceModeNames[] = {
77
  "DeviceGray",
78
  "CalGray",
79
  "DeviceRGB",
80
  "CalRGB",
81
  "DeviceCMYK",
82
  "Lab",
83
  "ICCBased",
84
  "Indexed",
85
  "Separation",
86
  "DeviceN",
87
  "Pattern"
88
};
89
90
0
#define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
91
92
93
94
95
//------------------------------------------------------------------------
96
// GfxColorSpace
97
//------------------------------------------------------------------------
98
99
4.00M
GfxColorSpace::GfxColorSpace() {
100
4.00M
  overprintMask = 0x0f;
101
4.00M
  defaultColorSpace = gFalse;
102
4.00M
}
103
104
4.00M
GfxColorSpace::~GfxColorSpace() {
105
4.00M
}
106
107
GfxColorSpace *GfxColorSpace::parse(Object *csObj,
108
40.8k
            int recursion) {
109
40.8k
  GfxColorSpace *cs;
110
40.8k
  Object obj1;
111
112
40.8k
  if (recursion > colorSpaceRecursionLimit) {
113
0
    error(errSyntaxError, -1, "Loop detected in color space objects");
114
0
    return NULL;
115
0
  }
116
40.8k
  cs = NULL;
117
40.8k
  if (csObj->isName()) {
118
30.3k
    if (csObj->isName("DeviceGray") || csObj->isName("G")) {
119
13.6k
      cs = GfxColorSpace::create(csDeviceGray);
120
16.6k
    } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
121
6.87k
      cs = GfxColorSpace::create(csDeviceRGB);
122
9.74k
    } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
123
695
      cs = GfxColorSpace::create(csDeviceCMYK);
124
9.05k
    } else if (csObj->isName("Pattern")) {
125
5.09k
      cs = new GfxPatternColorSpace(NULL);
126
5.09k
    } else {
127
3.95k
      error(errSyntaxError, -1, "Bad color space '{0:s}'", csObj->getName());
128
3.95k
    }
129
30.3k
  } else if (csObj->isArray() && csObj->arrayGetLength() > 0) {
130
9.97k
    csObj->arrayGet(0, &obj1);
131
9.97k
    if (obj1.isName("DeviceGray") || obj1.isName("G")) {
132
101
      cs = GfxColorSpace::create(csDeviceGray);
133
9.87k
    } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
134
0
      cs = GfxColorSpace::create(csDeviceRGB);
135
9.87k
    } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
136
0
      cs = GfxColorSpace::create(csDeviceCMYK);
137
9.87k
    } else if (obj1.isName("CalGray")) {
138
248
      cs = GfxCalGrayColorSpace::parse(csObj->getArray(), recursion);
139
9.62k
    } else if (obj1.isName("CalRGB")) {
140
8
      cs = GfxCalRGBColorSpace::parse(csObj->getArray(), recursion);
141
9.61k
    } else if (obj1.isName("Lab")) {
142
565
      cs = GfxLabColorSpace::parse(csObj->getArray(), recursion);
143
9.04k
    } else if (obj1.isName("ICCBased")) {
144
5.41k
      cs = GfxICCBasedColorSpace::parse(csObj->getArray(),
145
5.41k
          recursion);
146
5.41k
    } else if (obj1.isName("Indexed") || obj1.isName("I")) {
147
683
      cs = GfxIndexedColorSpace::parse(csObj->getArray(),
148
683
               recursion);
149
2.95k
    } else if (obj1.isName("Separation")) {
150
1.69k
      cs = GfxSeparationColorSpace::parse(csObj->getArray(),
151
1.69k
            recursion);
152
1.69k
    } else if (obj1.isName("DeviceN")) {
153
492
      cs = GfxDeviceNColorSpace::parse(csObj->getArray(),
154
492
               recursion);
155
769
    } else if (obj1.isName("Pattern")) {
156
298
      cs = GfxPatternColorSpace::parse(csObj->getArray(),
157
298
               recursion);
158
471
    } else {
159
471
      error(errSyntaxError, -1, "Bad color space");
160
471
    }
161
9.97k
    obj1.free();
162
9.97k
  } else {
163
535
    error(errSyntaxError, -1, "Bad color space - expected name or array");
164
535
  }
165
40.8k
  return cs;
166
40.8k
}
167
168
193k
GfxColorSpace *GfxColorSpace::create(GfxColorSpaceMode mode) {
169
193k
  GfxColorSpace *cs;
170
171
193k
  cs = NULL;
172
193k
  if (mode == csDeviceGray) {
173
130k
    cs = new GfxDeviceGrayColorSpace();
174
130k
  } else if (mode == csDeviceRGB) {
175
58.1k
    cs = new GfxDeviceRGBColorSpace();
176
58.1k
  } else if (mode == csDeviceCMYK) {
177
4.64k
    cs = new GfxDeviceCMYKColorSpace();
178
4.64k
  }
179
193k
  return cs;
180
193k
}
181
182
void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
183
16.6k
             int maxImgPixel) {
184
16.6k
  int i;
185
186
38.1k
  for (i = 0; i < getNComps(); ++i) {
187
21.5k
    decodeLow[i] = 0;
188
21.5k
    decodeRange[i] = 1;
189
21.5k
  }
190
16.6k
}
191
192
0
int GfxColorSpace::getNumColorSpaceModes() {
193
0
  return nGfxColorSpaceModes;
194
0
}
195
196
0
const char *GfxColorSpace::getColorSpaceModeName(int idx) {
197
0
  return gfxColorSpaceModeNames[idx];
198
0
}
199
200
//------------------------------------------------------------------------
201
// GfxDeviceGrayColorSpace
202
//------------------------------------------------------------------------
203
204
2.35M
GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
205
2.35M
}
206
207
GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
208
}
209
210
2.22M
GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
211
2.22M
  GfxDeviceGrayColorSpace *cs;
212
213
2.22M
  cs = new GfxDeviceGrayColorSpace();
214
2.22M
  return cs;
215
2.22M
}
216
217
218
void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray,
219
149k
              GfxRenderingIntent ri) {
220
149k
  *gray = clip01(color->c[0]);
221
149k
}
222
223
void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
224
1.45M
             GfxRenderingIntent ri) {
225
1.45M
  rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
226
1.45M
}
227
228
void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
229
7.46k
              GfxRenderingIntent ri) {
230
7.46k
  cmyk->c = cmyk->m = cmyk->y = 0;
231
7.46k
  cmyk->k = clip01(gfxColorComp1 - color->c[0]);
232
7.46k
}
233
234
235
236
2.30k
void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) {
237
2.30k
  color->c[0] = 0;
238
2.30k
}
239
240
//------------------------------------------------------------------------
241
// GfxCalGrayColorSpace
242
//------------------------------------------------------------------------
243
244
174
GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
245
174
  whiteX = whiteY = whiteZ = 1;
246
174
  blackX = blackY = blackZ = 0;
247
174
  gamma = 1;
248
174
}
249
250
GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
251
}
252
253
0
GfxColorSpace *GfxCalGrayColorSpace::copy() {
254
0
  GfxCalGrayColorSpace *cs;
255
256
0
  cs = new GfxCalGrayColorSpace();
257
0
  cs->whiteX = whiteX;
258
0
  cs->whiteY = whiteY;
259
0
  cs->whiteZ = whiteZ;
260
0
  cs->blackX = blackX;
261
0
  cs->blackY = blackY;
262
0
  cs->blackZ = blackZ;
263
0
  cs->gamma = gamma;
264
0
  return cs;
265
0
}
266
267
268
248
GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr, int recursion) {
269
248
  GfxCalGrayColorSpace *cs;
270
248
  Object obj1, obj2, obj3;
271
272
248
  if (arr->getLength() < 2) {
273
0
    error(errSyntaxError, -1, "Bad CalGray color space");
274
0
    return NULL;
275
0
  }
276
248
  arr->get(1, &obj1);
277
248
  if (!obj1.isDict()) {
278
74
    error(errSyntaxError, -1, "Bad CalGray color space");
279
74
    obj1.free();
280
74
    return NULL;
281
74
  }
282
174
  cs = new GfxCalGrayColorSpace();
283
174
  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
284
156
      obj2.arrayGetLength() == 3) {
285
83
    obj2.arrayGet(0, &obj3);
286
83
    cs->whiteX = obj3.getNum();
287
83
    obj3.free();
288
83
    obj2.arrayGet(1, &obj3);
289
83
    cs->whiteY = obj3.getNum();
290
83
    obj3.free();
291
83
    obj2.arrayGet(2, &obj3);
292
83
    cs->whiteZ = obj3.getNum();
293
83
    obj3.free();
294
83
  }
295
174
  obj2.free();
296
174
  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
297
156
      obj2.arrayGetLength() == 3) {
298
138
    obj2.arrayGet(0, &obj3);
299
138
    cs->blackX = obj3.getNum();
300
138
    obj3.free();
301
138
    obj2.arrayGet(1, &obj3);
302
138
    cs->blackY = obj3.getNum();
303
138
    obj3.free();
304
138
    obj2.arrayGet(2, &obj3);
305
138
    cs->blackZ = obj3.getNum();
306
138
    obj3.free();
307
138
  }
308
174
  obj2.free();
309
174
  if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
310
174
    cs->gamma = obj2.getNum();
311
174
  }
312
174
  obj2.free();
313
174
  obj1.free();
314
174
  return cs;
315
248
}
316
317
void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray,
318
0
           GfxRenderingIntent ri) {
319
0
  *gray = clip01(color->c[0]);
320
0
}
321
322
void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
323
349
          GfxRenderingIntent ri) {
324
349
  rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
325
349
}
326
327
void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
328
0
           GfxRenderingIntent ri) {
329
0
  cmyk->c = cmyk->m = cmyk->y = 0;
330
0
  cmyk->k = clip01(gfxColorComp1 - color->c[0]);
331
0
}
332
333
334
335
174
void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) {
336
174
  color->c[0] = 0;
337
174
}
338
339
//------------------------------------------------------------------------
340
// GfxDeviceRGBColorSpace
341
//------------------------------------------------------------------------
342
343
1.58M
GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
344
1.58M
}
345
346
GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
347
}
348
349
1.52M
GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
350
1.52M
  GfxDeviceRGBColorSpace *cs;
351
352
1.52M
  cs = new GfxDeviceRGBColorSpace();
353
1.52M
  return cs;
354
1.52M
}
355
356
357
void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray,
358
0
             GfxRenderingIntent ri) {
359
0
  *gray = clip01((GfxColorComp)(0.3  * color->c[0] +
360
0
        0.59 * color->c[1] +
361
0
        0.11 * color->c[2] + 0.5));
362
0
}
363
364
void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
365
2.00M
            GfxRenderingIntent ri) {
366
2.00M
  rgb->r = clip01(color->c[0]);
367
2.00M
  rgb->g = clip01(color->c[1]);
368
2.00M
  rgb->b = clip01(color->c[2]);
369
2.00M
}
370
371
void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
372
19
             GfxRenderingIntent ri) {
373
19
  GfxColorComp c, m, y, k;
374
375
19
  c = clip01(gfxColorComp1 - color->c[0]);
376
19
  m = clip01(gfxColorComp1 - color->c[1]);
377
19
  y = clip01(gfxColorComp1 - color->c[2]);
378
19
  k = c;
379
19
  if (m < k) {
380
10
    k = m;
381
10
  }
382
19
  if (y < k) {
383
10
    k = y;
384
10
  }
385
19
  cmyk->c = c - k;
386
19
  cmyk->m = m - k;
387
19
  cmyk->y = y - k;
388
19
  cmyk->k = k;
389
19
}
390
391
392
393
5
void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) {
394
5
  color->c[0] = 0;
395
5
  color->c[1] = 0;
396
5
  color->c[2] = 0;
397
5
}
398
399
//------------------------------------------------------------------------
400
// GfxCalRGBColorSpace
401
//------------------------------------------------------------------------
402
403
3
GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
404
3
  whiteX = whiteY = whiteZ = 1;
405
3
  blackX = blackY = blackZ = 0;
406
3
  gammaR = gammaG = gammaB = 1;
407
3
  mat[0] = 1; mat[1] = 0; mat[2] = 0;
408
3
  mat[3] = 0; mat[4] = 1; mat[5] = 0;
409
3
  mat[6] = 0; mat[7] = 0; mat[8] = 1;
410
3
}
411
412
GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
413
}
414
415
0
GfxColorSpace *GfxCalRGBColorSpace::copy() {
416
0
  GfxCalRGBColorSpace *cs;
417
0
  int i;
418
419
0
  cs = new GfxCalRGBColorSpace();
420
0
  cs->whiteX = whiteX;
421
0
  cs->whiteY = whiteY;
422
0
  cs->whiteZ = whiteZ;
423
0
  cs->blackX = blackX;
424
0
  cs->blackY = blackY;
425
0
  cs->blackZ = blackZ;
426
0
  cs->gammaR = gammaR;
427
0
  cs->gammaG = gammaG;
428
0
  cs->gammaB = gammaB;
429
0
  for (i = 0; i < 9; ++i) {
430
0
    cs->mat[i] = mat[i];
431
0
  }
432
0
  return cs;
433
0
}
434
435
8
GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr, int recursion) {
436
8
  GfxCalRGBColorSpace *cs;
437
8
  Object obj1, obj2, obj3;
438
8
  int i;
439
440
8
  if (arr->getLength() < 2) {
441
0
    error(errSyntaxError, -1, "Bad CalRGB color space");
442
0
    return NULL;
443
0
  }
444
8
  arr->get(1, &obj1);
445
8
  if (!obj1.isDict()) {
446
5
    error(errSyntaxError, -1, "Bad CalRGB color space");
447
5
    obj1.free();
448
5
    return NULL;
449
5
  }
450
3
  cs = new GfxCalRGBColorSpace();
451
3
  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
452
3
      obj2.arrayGetLength() == 3) {
453
3
    obj2.arrayGet(0, &obj3);
454
3
    cs->whiteX = obj3.getNum();
455
3
    obj3.free();
456
3
    obj2.arrayGet(1, &obj3);
457
3
    cs->whiteY = obj3.getNum();
458
3
    obj3.free();
459
3
    obj2.arrayGet(2, &obj3);
460
3
    cs->whiteZ = obj3.getNum();
461
3
    obj3.free();
462
3
  }
463
3
  obj2.free();
464
3
  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
465
0
      obj2.arrayGetLength() == 3) {
466
0
    obj2.arrayGet(0, &obj3);
467
0
    cs->blackX = obj3.getNum();
468
0
    obj3.free();
469
0
    obj2.arrayGet(1, &obj3);
470
0
    cs->blackY = obj3.getNum();
471
0
    obj3.free();
472
0
    obj2.arrayGet(2, &obj3);
473
0
    cs->blackZ = obj3.getNum();
474
0
    obj3.free();
475
0
  }
476
3
  obj2.free();
477
3
  if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
478
3
      obj2.arrayGetLength() == 3) {
479
3
    obj2.arrayGet(0, &obj3);
480
3
    cs->gammaR = obj3.getNum();
481
3
    obj3.free();
482
3
    obj2.arrayGet(1, &obj3);
483
3
    cs->gammaG = obj3.getNum();
484
3
    obj3.free();
485
3
    obj2.arrayGet(2, &obj3);
486
3
    cs->gammaB = obj3.getNum();
487
3
    obj3.free();
488
3
  }
489
3
  obj2.free();
490
3
  if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
491
3
      obj2.arrayGetLength() == 9) {
492
30
    for (i = 0; i < 9; ++i) {
493
27
      obj2.arrayGet(i, &obj3);
494
27
      cs->mat[i] = obj3.getNum();
495
27
      obj3.free();
496
27
    }
497
3
  }
498
3
  obj2.free();
499
3
  obj1.free();
500
3
  return cs;
501
8
}
502
503
504
void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray,
505
0
          GfxRenderingIntent ri) {
506
0
  *gray = clip01((GfxColorComp)(0.299 * color->c[0] +
507
0
        0.587 * color->c[1] +
508
0
        0.114 * color->c[2] + 0.5));
509
0
}
510
511
void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
512
6
         GfxRenderingIntent ri) {
513
6
  rgb->r = clip01(color->c[0]);
514
6
  rgb->g = clip01(color->c[1]);
515
6
  rgb->b = clip01(color->c[2]);
516
6
}
517
518
void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
519
0
          GfxRenderingIntent ri) {
520
0
  GfxColorComp c, m, y, k;
521
522
0
  c = clip01(gfxColorComp1 - color->c[0]);
523
0
  m = clip01(gfxColorComp1 - color->c[1]);
524
0
  y = clip01(gfxColorComp1 - color->c[2]);
525
0
  k = c;
526
0
  if (m < k) {
527
0
    k = m;
528
0
  }
529
0
  if (y < k) {
530
0
    k = y;
531
0
  }
532
0
  cmyk->c = c - k;
533
0
  cmyk->m = m - k;
534
0
  cmyk->y = y - k;
535
0
  cmyk->k = k;
536
0
}
537
538
539
540
3
void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) {
541
3
  color->c[0] = 0;
542
3
  color->c[1] = 0;
543
3
  color->c[2] = 0;
544
3
}
545
546
//------------------------------------------------------------------------
547
// GfxDeviceCMYKColorSpace
548
//------------------------------------------------------------------------
549
550
24.3k
GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
551
24.3k
}
552
553
GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
554
}
555
556
19.6k
GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
557
19.6k
  GfxDeviceCMYKColorSpace *cs;
558
559
19.6k
  cs = new GfxDeviceCMYKColorSpace();
560
19.6k
  return cs;
561
19.6k
}
562
563
564
void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray,
565
0
              GfxRenderingIntent ri) {
566
0
  *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3]
567
0
        - 0.3  * color->c[0]
568
0
        - 0.59 * color->c[1]
569
0
        - 0.11 * color->c[2] + 0.5));
570
0
}
571
572
void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
573
1.30M
             GfxRenderingIntent ri) {
574
1.30M
  double c, m, y, k, c1, m1, y1, k1, r, g, b, x;
575
576
1.30M
  c = colToDbl(color->c[0]);
577
1.30M
  m = colToDbl(color->c[1]);
578
1.30M
  y = colToDbl(color->c[2]);
579
1.30M
  k = colToDbl(color->c[3]);
580
1.30M
  c1 = 1 - c;
581
1.30M
  m1 = 1 - m;
582
1.30M
  y1 = 1 - y;
583
1.30M
  k1 = 1 - k;
584
  // this is a matrix multiplication, unrolled for performance
585
  //                        C M Y K
586
1.30M
  x = c1 * m1 * y1 * k1; // 0 0 0 0
587
1.30M
  r = g = b = x;
588
1.30M
  x = c1 * m1 * y1 * k;  // 0 0 0 1
589
1.30M
  r += 0.1373 * x;
590
1.30M
  g += 0.1216 * x;
591
1.30M
  b += 0.1255 * x;
592
1.30M
  x = c1 * m1 * y  * k1; // 0 0 1 0
593
1.30M
  r += x;
594
1.30M
  g += 0.9490 * x;
595
1.30M
  x = c1 * m1 * y  * k;  // 0 0 1 1
596
1.30M
  r += 0.1098 * x;
597
1.30M
  g += 0.1020 * x;
598
1.30M
  x = c1 * m  * y1 * k1; // 0 1 0 0
599
1.30M
  r += 0.9255 * x;
600
1.30M
  b += 0.5490 * x;
601
1.30M
  x = c1 * m  * y1 * k;  // 0 1 0 1
602
1.30M
  r += 0.1412 * x;
603
1.30M
  x = c1 * m  * y  * k1; // 0 1 1 0
604
1.30M
  r += 0.9294 * x;
605
1.30M
  g += 0.1098 * x;
606
1.30M
  b += 0.1412 * x;
607
1.30M
  x = c1 * m  * y  * k;  // 0 1 1 1
608
1.30M
  r += 0.1333 * x;
609
1.30M
  x = c  * m1 * y1 * k1; // 1 0 0 0
610
1.30M
  g += 0.6784 * x;
611
1.30M
  b += 0.9373 * x;
612
1.30M
  x = c  * m1 * y1 * k;  // 1 0 0 1
613
1.30M
  g += 0.0588 * x;
614
1.30M
  b += 0.1412 * x;
615
1.30M
  x = c  * m1 * y  * k1; // 1 0 1 0
616
1.30M
  g += 0.6510 * x;
617
1.30M
  b += 0.3137 * x;
618
1.30M
  x = c  * m1 * y  * k;  // 1 0 1 1
619
1.30M
  g += 0.0745 * x;
620
1.30M
  x = c  * m  * y1 * k1; // 1 1 0 0
621
1.30M
  r += 0.1804 * x;
622
1.30M
  g += 0.1922 * x;
623
1.30M
  b += 0.5725 * x;
624
1.30M
  x = c  * m  * y1 * k;  // 1 1 0 1
625
1.30M
  b += 0.0078 * x;
626
1.30M
  x = c  * m  * y  * k1; // 1 1 1 0
627
1.30M
  r += 0.2118 * x;
628
1.30M
  g += 0.2119 * x;
629
1.30M
  b += 0.2235 * x;
630
1.30M
  rgb->r = clip01(dblToCol(r));
631
1.30M
  rgb->g = clip01(dblToCol(g));
632
1.30M
  rgb->b = clip01(dblToCol(b));
633
1.30M
}
634
635
void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
636
33
              GfxRenderingIntent ri) {
637
33
  cmyk->c = clip01(color->c[0]);
638
33
  cmyk->m = clip01(color->c[1]);
639
33
  cmyk->y = clip01(color->c[2]);
640
33
  cmyk->k = clip01(color->c[3]);
641
33
}
642
643
644
645
1
void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor *color) {
646
1
  color->c[0] = 0;
647
1
  color->c[1] = 0;
648
1
  color->c[2] = 0;
649
1
  color->c[3] = gfxColorComp1;
650
1
}
651
652
653
//------------------------------------------------------------------------
654
// GfxLabColorSpace
655
//------------------------------------------------------------------------
656
657
// This is the inverse of MatrixLMN in Example 4.10 from the PostScript
658
// Language Reference, Third Edition.
659
static double xyzrgb[3][3] = {
660
  {  3.240449, -1.537136, -0.498531 },
661
  { -0.969265,  1.876011,  0.041556 },
662
  {  0.055643, -0.204026,  1.057229 }
663
};
664
665
924
GfxLabColorSpace::GfxLabColorSpace() {
666
924
  whiteX = whiteY = whiteZ = 1;
667
924
  blackX = blackY = blackZ = 0;
668
924
  aMin = bMin = -100;
669
924
  aMax = bMax = 100;
670
924
}
671
672
GfxLabColorSpace::~GfxLabColorSpace() {
673
}
674
675
406
GfxColorSpace *GfxLabColorSpace::copy() {
676
406
  GfxLabColorSpace *cs;
677
678
406
  cs = new GfxLabColorSpace();
679
406
  cs->whiteX = whiteX;
680
406
  cs->whiteY = whiteY;
681
406
  cs->whiteZ = whiteZ;
682
406
  cs->blackX = blackX;
683
406
  cs->blackY = blackY;
684
406
  cs->blackZ = blackZ;
685
406
  cs->aMin = aMin;
686
406
  cs->aMax = aMax;
687
406
  cs->bMin = bMin;
688
406
  cs->bMax = bMax;
689
406
  cs->kr = kr;
690
406
  cs->kg = kg;
691
406
  cs->kb = kb;
692
406
  return cs;
693
406
}
694
695
565
GfxColorSpace *GfxLabColorSpace::parse(Array *arr, int recursion) {
696
565
  GfxLabColorSpace *cs;
697
565
  Object obj1, obj2, obj3;
698
699
565
  if (arr->getLength() < 2) {
700
24
    error(errSyntaxError, -1, "Bad Lab color space");
701
24
    return NULL;
702
24
  }
703
541
  arr->get(1, &obj1);
704
541
  if (!obj1.isDict()) {
705
23
    error(errSyntaxError, -1, "Bad Lab color space");
706
23
    obj1.free();
707
23
    return NULL;
708
23
  }
709
518
  cs = new GfxLabColorSpace();
710
518
  if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
711
259
      obj2.arrayGetLength() == 3) {
712
204
    obj2.arrayGet(0, &obj3);
713
204
    cs->whiteX = obj3.getNum();
714
204
    obj3.free();
715
204
    obj2.arrayGet(1, &obj3);
716
204
    cs->whiteY = obj3.getNum();
717
204
    obj3.free();
718
204
    obj2.arrayGet(2, &obj3);
719
204
    cs->whiteZ = obj3.getNum();
720
204
    obj3.free();
721
204
  }
722
518
  obj2.free();
723
518
  if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
724
203
      obj2.arrayGetLength() == 3) {
725
203
    obj2.arrayGet(0, &obj3);
726
203
    cs->blackX = obj3.getNum();
727
203
    obj3.free();
728
203
    obj2.arrayGet(1, &obj3);
729
203
    cs->blackY = obj3.getNum();
730
203
    obj3.free();
731
203
    obj2.arrayGet(2, &obj3);
732
203
    cs->blackZ = obj3.getNum();
733
203
    obj3.free();
734
203
  }
735
518
  obj2.free();
736
518
  if (obj1.dictLookup("Range", &obj2)->isArray() &&
737
221
      obj2.arrayGetLength() == 4) {
738
221
    obj2.arrayGet(0, &obj3);
739
221
    cs->aMin = obj3.getNum();
740
221
    obj3.free();
741
221
    obj2.arrayGet(1, &obj3);
742
221
    cs->aMax = obj3.getNum();
743
221
    obj3.free();
744
221
    obj2.arrayGet(2, &obj3);
745
221
    cs->bMin = obj3.getNum();
746
221
    obj3.free();
747
221
    obj2.arrayGet(3, &obj3);
748
221
    cs->bMax = obj3.getNum();
749
221
    obj3.free();
750
221
  }
751
518
  obj2.free();
752
518
  obj1.free();
753
754
518
  cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
755
518
    xyzrgb[0][1] * cs->whiteY +
756
518
    xyzrgb[0][2] * cs->whiteZ);
757
518
  cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
758
518
    xyzrgb[1][1] * cs->whiteY +
759
518
    xyzrgb[1][2] * cs->whiteZ);
760
518
  cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
761
518
    xyzrgb[2][1] * cs->whiteY +
762
518
    xyzrgb[2][2] * cs->whiteZ);
763
764
518
  return cs;
765
541
}
766
767
768
void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray,
769
0
             GfxRenderingIntent ri) {
770
0
  GfxRGB rgb;
771
772
0
  getRGB(color, &rgb, ri);
773
0
  *gray = clip01((GfxColorComp)(0.299 * rgb.r +
774
0
        0.587 * rgb.g +
775
0
        0.114 * rgb.b + 0.5));
776
0
}
777
778
void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
779
5.40k
            GfxRenderingIntent ri) {
780
5.40k
  double X, Y, Z;
781
5.40k
  double t1, t2;
782
5.40k
  double r, g, b;
783
784
785
  // convert L*a*b* to CIE 1931 XYZ color space
786
5.40k
  t1 = (colToDbl(color->c[0]) + 16) / 116;
787
5.40k
  t2 = t1 + colToDbl(color->c[1]) / 500;
788
5.40k
  if (t2 >= (6.0 / 29.0)) {
789
2.37k
    X = t2 * t2 * t2;
790
3.02k
  } else {
791
3.02k
    X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
792
3.02k
  }
793
5.40k
  X *= whiteX;
794
5.40k
  if (t1 >= (6.0 / 29.0)) {
795
2.37k
    Y = t1 * t1 * t1;
796
3.02k
  } else {
797
3.02k
    Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
798
3.02k
  }
799
5.40k
  Y *= whiteY;
800
5.40k
  t2 = t1 - colToDbl(color->c[2]) / 200;
801
5.40k
  if (t2 >= (6.0 / 29.0)) {
802
5.22k
    Z = t2 * t2 * t2;
803
5.22k
  } else {
804
176
    Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
805
176
  }
806
5.40k
  Z *= whiteZ;
807
808
  // convert XYZ to RGB, including gamut mapping and gamma correction
809
5.40k
  r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
810
5.40k
  g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
811
5.40k
  b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
812
5.40k
  rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
813
5.40k
  rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
814
5.40k
  rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
815
5.40k
}
816
817
void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
818
0
             GfxRenderingIntent ri) {
819
0
  GfxRGB rgb;
820
0
  GfxColorComp c, m, y, k;
821
822
823
0
  getRGB(color, &rgb, ri);
824
0
  c = clip01(gfxColorComp1 - rgb.r);
825
0
  m = clip01(gfxColorComp1 - rgb.g);
826
0
  y = clip01(gfxColorComp1 - rgb.b);
827
0
  k = c;
828
0
  if (m < k) {
829
0
    k = m;
830
0
  }
831
0
  if (y < k) {
832
0
    k = y;
833
0
  }
834
0
  cmyk->c = c - k;
835
0
  cmyk->m = m - k;
836
0
  cmyk->y = y - k;
837
0
  cmyk->k = k;
838
0
}
839
840
841
842
174
void GfxLabColorSpace::getDefaultColor(GfxColor *color) {
843
174
  color->c[0] = 0;
844
174
  if (aMin > 0) {
845
35
    color->c[1] = dblToCol(aMin);
846
139
  } else if (aMax < 0) {
847
0
    color->c[1] = dblToCol(aMax);
848
139
  } else {
849
139
    color->c[1] = 0;
850
139
  }
851
174
  if (bMin > 0) {
852
36
    color->c[2] = dblToCol(bMin);
853
138
  } else if (bMax < 0) {
854
0
    color->c[2] = dblToCol(bMax);
855
138
  } else {
856
138
    color->c[2] = 0;
857
138
  }
858
174
}
859
860
void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
861
261
          int maxImgPixel) {
862
261
  decodeLow[0] = 0;
863
261
  decodeRange[0] = 100;
864
261
  decodeLow[1] = aMin;
865
261
  decodeRange[1] = aMax - aMin;
866
261
  decodeLow[2] = bMin;
867
261
  decodeRange[2] = bMax - bMin;
868
261
}
869
870
//------------------------------------------------------------------------
871
// GfxICCBasedColorSpace
872
//------------------------------------------------------------------------
873
874
GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
875
4.59k
               Ref *iccProfileStreamA) {
876
4.59k
  nComps = nCompsA;
877
4.59k
  alt = altA;
878
4.59k
  iccProfileStream = *iccProfileStreamA;
879
4.59k
  rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
880
4.59k
  rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
881
4.59k
}
882
883
4.59k
GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
884
4.59k
  delete alt;
885
4.59k
}
886
887
2.76k
GfxColorSpace *GfxICCBasedColorSpace::copy() {
888
2.76k
  GfxICCBasedColorSpace *cs;
889
2.76k
  int i;
890
891
2.76k
  cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
892
13.8k
  for (i = 0; i < 4; ++i) {
893
11.0k
    cs->rangeMin[i] = rangeMin[i];
894
11.0k
    cs->rangeMax[i] = rangeMax[i];
895
11.0k
  }
896
2.76k
  return cs;
897
2.76k
}
898
899
GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr,
900
5.41k
              int recursion) {
901
5.41k
  GfxICCBasedColorSpace *cs;
902
5.41k
  Ref iccProfileStreamA;
903
5.41k
  int nCompsA;
904
5.41k
  GfxColorSpace *altA;
905
5.41k
  Dict *dict;
906
5.41k
  Object obj1, obj2, obj3;
907
5.41k
  int i;
908
909
5.41k
  if (arr->getLength() < 2) {
910
21
    error(errSyntaxError, -1, "Bad ICCBased color space");
911
21
    return NULL;
912
21
  }
913
5.38k
  arr->getNF(1, &obj1);
914
5.38k
  if (obj1.isRef()) {
915
5.37k
    iccProfileStreamA = obj1.getRef();
916
5.37k
  } else {
917
19
    iccProfileStreamA.num = 0;
918
19
    iccProfileStreamA.gen = 0;
919
19
  }
920
5.38k
  obj1.free();
921
5.38k
  arr->get(1, &obj1);
922
5.38k
  if (!obj1.isStream()) {
923
3.40k
    error(errSyntaxError, -1, "Bad ICCBased color space (stream)");
924
3.40k
    obj1.free();
925
3.40k
    return NULL;
926
3.40k
  }
927
1.98k
  dict = obj1.streamGetDict();
928
1.98k
  if (!dict->lookup("N", &obj2)->isInt()) {
929
146
    error(errSyntaxError, -1, "Bad ICCBased color space (N)");
930
146
    obj2.free();
931
146
    obj1.free();
932
146
    return NULL;
933
146
  }
934
1.83k
  nCompsA = obj2.getInt();
935
1.83k
  obj2.free();
936
1.83k
  if (!dict->lookup("Alternate", &obj2)->isNull() &&
937
1.66k
      (altA = GfxColorSpace::parse(&obj2,
938
1.66k
           recursion + 1))) {
939
1.60k
    if (altA->getNComps() != nCompsA) {
940
0
      error(errSyntaxError, -1,
941
0
      "Number of components in ICCBased color space doesn't match alternate color space");
942
0
      nCompsA = altA->getNComps();
943
0
    }
944
1.60k
  } else {
945
236
    switch (nCompsA) {
946
0
    case 1:
947
0
      altA = GfxColorSpace::create(csDeviceGray);
948
0
      break;
949
202
    case 3:
950
202
      altA = GfxColorSpace::create(csDeviceRGB);
951
202
      break;
952
25
    case 4:
953
25
      altA = GfxColorSpace::create(csDeviceCMYK);
954
25
      break;
955
9
    default:
956
9
      error(errSyntaxError, -1, "Bad ICCBased color space - invalid N");
957
9
      obj2.free();
958
9
      obj1.free();
959
9
      return NULL;
960
236
    }
961
236
  }
962
1.82k
  obj2.free();
963
1.82k
  cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
964
1.82k
  if (dict->lookup("Range", &obj2)->isArray() &&
965
8
      obj2.arrayGetLength() == 2 * nCompsA) {
966
16
    for (i = 0; i < nCompsA; ++i) {
967
12
      obj2.arrayGet(2*i, &obj3);
968
12
      cs->rangeMin[i] = obj3.getNum();
969
12
      obj3.free();
970
12
      obj2.arrayGet(2*i+1, &obj3);
971
12
      cs->rangeMax[i] = obj3.getNum();
972
12
      obj3.free();
973
12
    }
974
4
  }
975
1.82k
  obj2.free();
976
1.82k
  obj1.free();
977
1.82k
  return cs;
978
1.83k
}
979
980
981
void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray,
982
0
            GfxRenderingIntent ri) {
983
0
  alt->getGray(color, gray, ri);
984
0
}
985
986
void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
987
1.79M
           GfxRenderingIntent ri) {
988
1.79M
  alt->getRGB(color, rgb, ri);
989
1.79M
}
990
991
void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
992
0
            GfxRenderingIntent ri) {
993
0
  alt->getCMYK(color, cmyk, ri);
994
0
}
995
996
997
998
903
void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) {
999
903
  int i;
1000
1001
3.44k
  for (i = 0; i < nComps; ++i) {
1002
2.54k
    if (rangeMin[i] > 0) {
1003
0
      color->c[i] = dblToCol(rangeMin[i]);
1004
2.54k
    } else if (rangeMax[i] < 0) {
1005
0
      color->c[i] = dblToCol(rangeMax[i]);
1006
2.54k
    } else {
1007
2.54k
      color->c[i] = 0;
1008
2.54k
    }
1009
2.54k
  }
1010
903
}
1011
1012
void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
1013
               double *decodeRange,
1014
158
               int maxImgPixel) {
1015
158
  alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
1016
1017
#if 0
1018
  // this is nominally correct, but some PDF files don't set the
1019
  // correct ranges in the ICCBased dict
1020
  int i;
1021
1022
  for (i = 0; i < nComps; ++i) {
1023
    decodeLow[i] = rangeMin[i];
1024
    decodeRange[i] = rangeMax[i] - rangeMin[i];
1025
  }
1026
#endif
1027
158
}
1028
1029
1030
//------------------------------------------------------------------------
1031
// GfxIndexedColorSpace
1032
//------------------------------------------------------------------------
1033
1034
GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
1035
703
             int indexHighA) {
1036
703
  base = baseA;
1037
703
  indexHigh = indexHighA;
1038
703
  lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(),
1039
703
            sizeof(Guchar));
1040
703
  overprintMask = base->getOverprintMask();
1041
703
}
1042
1043
703
GfxIndexedColorSpace::~GfxIndexedColorSpace() {
1044
703
  delete base;
1045
703
  gfree(lookup);
1046
703
}
1047
1048
242
GfxColorSpace *GfxIndexedColorSpace::copy() {
1049
242
  GfxIndexedColorSpace *cs;
1050
1051
242
  cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
1052
242
  memcpy(cs->lookup, lookup,
1053
242
   (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
1054
242
  return cs;
1055
242
}
1056
1057
GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr,
1058
683
             int recursion) {
1059
683
  GfxIndexedColorSpace *cs;
1060
683
  GfxColorSpace *baseA;
1061
683
  int indexHighA;
1062
683
  Object obj1;
1063
683
  int x;
1064
683
  char *s;
1065
683
  int n, i, j;
1066
1067
683
  if (arr->getLength() != 4) {
1068
53
    error(errSyntaxError, -1, "Bad Indexed color space");
1069
53
    goto err1;
1070
53
  }
1071
630
  arr->get(1, &obj1);
1072
630
  if (!(baseA = GfxColorSpace::parse(&obj1,
1073
630
             recursion + 1))) {
1074
55
    error(errSyntaxError, -1, "Bad Indexed color space (base color space)");
1075
55
    goto err2;
1076
55
  }
1077
575
  obj1.free();
1078
575
  if (!arr->get(2, &obj1)->isInt()) {
1079
112
    error(errSyntaxError, -1, "Bad Indexed color space (hival)");
1080
112
    delete baseA;
1081
112
    goto err2;
1082
112
  }
1083
463
  indexHighA = obj1.getInt();
1084
463
  if (indexHighA < 0 || indexHighA > 255) {
1085
    // the PDF spec requires indexHigh to be in [0,255] -- allowing
1086
    // values larger than 255 creates a security hole: if nComps *
1087
    // indexHigh is greater than 2^31, the loop below may overwrite
1088
    // past the end of the array
1089
2
    error(errSyntaxError, -1,
1090
2
    "Bad Indexed color space (invalid indexHigh value)");
1091
2
    delete baseA;
1092
2
    goto err2;
1093
2
  }
1094
461
  obj1.free();
1095
461
  cs = new GfxIndexedColorSpace(baseA, indexHighA);
1096
461
  arr->get(3, &obj1);
1097
461
  n = baseA->getNComps();
1098
461
  if (obj1.isStream()) {
1099
314
    obj1.streamReset();
1100
47.0k
    for (i = 0; i <= indexHighA; ++i) {
1101
186k
      for (j = 0; j < n; ++j) {
1102
139k
  if ((x = obj1.streamGetChar()) == EOF) {
1103
116
    error(errSyntaxError, -1,
1104
116
    "Bad Indexed color space (lookup table stream too short)");
1105
116
    cs->indexHigh = indexHighA = i - 1;
1106
116
    if (cs->indexHigh < 0) {
1107
2
      goto err3;
1108
2
    }
1109
116
  }
1110
139k
  cs->lookup[i*n + j] = (Guchar)x;
1111
139k
      }
1112
46.7k
    }
1113
312
    obj1.streamClose();
1114
312
  } else if (obj1.isString()) {
1115
62
    if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
1116
0
      error(errSyntaxError, -1,
1117
0
      "Bad Indexed color space (lookup table string too short)");
1118
0
      cs->indexHigh = indexHighA = obj1.getString()->getLength() / n - 1;
1119
0
      if (cs->indexHigh < 0) {
1120
0
  goto err3;
1121
0
      }
1122
0
    }
1123
62
    s = obj1.getString()->getCString();
1124
280
    for (i = 0; i <= indexHighA; ++i) {
1125
812
      for (j = 0; j < n; ++j) {
1126
594
  cs->lookup[i*n + j] = (Guchar)*s++;
1127
594
      }
1128
218
    }
1129
85
  } else {
1130
85
    error(errSyntaxError, -1, "Bad Indexed color space (lookup table)");
1131
85
    goto err3;
1132
85
  }
1133
374
  obj1.free();
1134
374
  return cs;
1135
1136
87
 err3:
1137
87
  delete cs;
1138
256
 err2:
1139
256
  obj1.free();
1140
309
 err1:
1141
309
  return NULL;
1142
256
}
1143
1144
1145
GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
1146
247
                 GfxColor *baseColor) {
1147
247
  Guchar *p;
1148
247
  double low[gfxColorMaxComps], range[gfxColorMaxComps];
1149
247
  int n, i, k;
1150
1151
247
  n = base->getNComps();
1152
247
  base->getDefaultRanges(low, range, indexHigh);
1153
247
  k = (int)(colToDbl(color->c[0]) + 0.5);
1154
247
  if (k < 0) {
1155
41
    k = 0;
1156
206
  } else if (k > indexHigh) {
1157
74
    k = indexHigh;
1158
74
  }
1159
247
  p = &lookup[k * n];
1160
496
  for (i = 0; i < n; ++i) {
1161
249
    baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]);
1162
249
  }
1163
247
  return baseColor;
1164
247
}
1165
1166
void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray,
1167
0
           GfxRenderingIntent ri) {
1168
0
  GfxColor color2;
1169
1170
0
  base->getGray(mapColorToBase(color, &color2), gray, ri);
1171
0
}
1172
1173
void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
1174
247
          GfxRenderingIntent ri) {
1175
247
  GfxColor color2;
1176
1177
247
  base->getRGB(mapColorToBase(color, &color2), rgb, ri);
1178
247
}
1179
1180
void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
1181
0
           GfxRenderingIntent ri) {
1182
0
  GfxColor color2;
1183
1184
0
  base->getCMYK(mapColorToBase(color, &color2), cmyk, ri);
1185
0
}
1186
1187
1188
1189
121
void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) {
1190
121
  color->c[0] = 0;
1191
121
}
1192
1193
void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
1194
              double *decodeRange,
1195
253
              int maxImgPixel) {
1196
253
  decodeLow[0] = 0;
1197
253
  decodeRange[0] = maxImgPixel;
1198
253
}
1199
1200
//------------------------------------------------------------------------
1201
// GfxSeparationColorSpace
1202
//------------------------------------------------------------------------
1203
1204
GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
1205
             GfxColorSpace *altA,
1206
629
             Function *funcA) {
1207
629
  name = nameA;
1208
629
  alt = altA;
1209
629
  func = funcA;
1210
629
  nonMarking = !name->cmp("None");
1211
629
  if (!name->cmp("Cyan")) {
1212
0
    overprintMask = 0x01;
1213
629
  } else if (!name->cmp("Magenta")) {
1214
0
    overprintMask = 0x02;
1215
629
  } else if (!name->cmp("Yellow")) {
1216
0
    overprintMask = 0x04;
1217
629
  } else if (!name->cmp("Black")) {
1218
350
    overprintMask = 0x08;
1219
350
  }
1220
629
}
1221
1222
GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
1223
             GfxColorSpace *altA,
1224
             Function *funcA,
1225
             GBool nonMarkingA,
1226
799
             Guint overprintMaskA) {
1227
799
  name = nameA;
1228
799
  alt = altA;
1229
799
  func = funcA;
1230
799
  nonMarking = nonMarkingA;
1231
799
  overprintMask = overprintMaskA;
1232
799
}
1233
1234
1.42k
GfxSeparationColorSpace::~GfxSeparationColorSpace() {
1235
1.42k
  delete name;
1236
1.42k
  delete alt;
1237
1.42k
  delete func;
1238
1.42k
}
1239
1240
799
GfxColorSpace *GfxSeparationColorSpace::copy() {
1241
799
  GfxSeparationColorSpace *cs;
1242
1243
799
  cs = new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy(),
1244
799
           nonMarking, overprintMask);
1245
799
  return cs;
1246
799
}
1247
1248
GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr,
1249
1.69k
                int recursion) {
1250
1.69k
  GfxSeparationColorSpace *cs;
1251
1.69k
  GString *nameA;
1252
1.69k
  GfxColorSpace *altA;
1253
1.69k
  Function *funcA;
1254
1.69k
  Object obj1, obj2;
1255
1256
1.69k
  if (arr->getLength() != 4) {
1257
26
    error(errSyntaxError, -1, "Bad Separation color space");
1258
26
    goto err1;
1259
26
  }
1260
1.66k
  if (!arr->get(1, &obj1)->isName()) {
1261
14
    error(errSyntaxError, -1, "Bad Separation color space (name)");
1262
14
    goto err2;
1263
14
  }
1264
1.65k
  nameA = new GString(obj1.getName());
1265
1.65k
  obj1.free();
1266
1.65k
  arr->get(2, &obj1);
1267
  // some PDF generators use an ICC profile stream here; Adobe
1268
  // apparently looks at the /Alternate entry in the stream dictionary
1269
1.65k
  if (obj1.isStream() &&
1270
18
      !obj1.streamGetDict()->lookup("Alternate", &obj2)->isNull()) {
1271
0
    obj1.free();
1272
0
    obj1 = obj2;
1273
0
  }
1274
1.65k
  if (!(altA = GfxColorSpace::parse(&obj1,
1275
1.65k
            recursion + 1))) {
1276
64
    error(errSyntaxError, -1,
1277
64
    "Bad Separation color space (alternate color space)");
1278
64
    goto err3;
1279
64
  }
1280
1.59k
  obj1.free();
1281
1.59k
  arr->get(3, &obj1);
1282
1.59k
  if (!(funcA = Function::parse(&obj1, 1, altA->getNComps()))) {
1283
962
    goto err4;
1284
962
  }
1285
629
  obj1.free();
1286
629
  cs = new GfxSeparationColorSpace(nameA, altA, funcA);
1287
629
  return cs;
1288
1289
962
 err4:
1290
962
  delete altA;
1291
1.02k
 err3:
1292
1.02k
  delete nameA;
1293
1.04k
 err2:
1294
1.04k
  obj1.free();
1295
1.06k
 err1:
1296
1.06k
  return NULL;
1297
1.04k
}
1298
1299
1300
void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray,
1301
0
              GfxRenderingIntent ri) {
1302
0
  double x;
1303
0
  double c[gfxColorMaxComps];
1304
0
  GfxColor color2;
1305
0
  int i;
1306
1307
0
  x = colToDbl(color->c[0]);
1308
0
  func->transform(&x, c);
1309
0
  for (i = 0; i < alt->getNComps(); ++i) {
1310
0
    color2.c[i] = dblToCol(c[i]);
1311
0
  }
1312
0
  alt->getGray(&color2, gray, ri);
1313
0
}
1314
1315
void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
1316
1.11k
             GfxRenderingIntent ri) {
1317
1.11k
  double x;
1318
1.11k
  double c[gfxColorMaxComps];
1319
1.11k
  GfxColor color2;
1320
1.11k
  int i;
1321
1322
1.11k
  x = colToDbl(color->c[0]);
1323
1.11k
  func->transform(&x, c);
1324
4.50k
  for (i = 0; i < alt->getNComps(); ++i) {
1325
3.38k
    color2.c[i] = dblToCol(c[i]);
1326
3.38k
  }
1327
1.11k
  alt->getRGB(&color2, rgb, ri);
1328
1.11k
}
1329
1330
void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
1331
10
              GfxRenderingIntent ri) {
1332
10
  double x;
1333
10
  double c[gfxColorMaxComps];
1334
10
  GfxColor color2;
1335
10
  int i;
1336
1337
10
  x = colToDbl(color->c[0]);
1338
10
  func->transform(&x, c);
1339
40
  for (i = 0; i < alt->getNComps(); ++i) {
1340
30
    color2.c[i] = dblToCol(c[i]);
1341
30
  }
1342
10
  alt->getCMYK(&color2, cmyk, ri);
1343
10
}
1344
1345
1346
1347
580
void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) {
1348
580
  color->c[0] = gfxColorComp1;
1349
580
}
1350
1351
//------------------------------------------------------------------------
1352
// GfxDeviceNColorSpace
1353
//------------------------------------------------------------------------
1354
1355
GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1356
             GString **namesA,
1357
             GfxColorSpace *altA,
1358
             Function *funcA,
1359
31
             Object *attrsA) {
1360
31
  int i;
1361
1362
31
  nComps = nCompsA;
1363
31
  alt = altA;
1364
31
  func = funcA;
1365
31
  attrsA->copy(&attrs);
1366
31
  nonMarking = gTrue;
1367
31
  overprintMask = 0;
1368
94
  for (i = 0; i < nComps; ++i) {
1369
63
    names[i] = namesA[i];
1370
63
    if (names[i]->cmp("None")) {
1371
63
      nonMarking = gFalse;
1372
63
    }
1373
63
    if (!names[i]->cmp("Cyan")) {
1374
0
      overprintMask |= 0x01;
1375
63
    } else if (!names[i]->cmp("Magenta")) {
1376
13
      overprintMask |= 0x02;
1377
50
    } else if (!names[i]->cmp("Yellow")) {
1378
14
      overprintMask |= 0x04;
1379
36
    } else if (!names[i]->cmp("Black")) {
1380
8
      overprintMask |= 0x08;
1381
28
    } else {
1382
28
      overprintMask = 0x0f;
1383
28
    }
1384
63
  }
1385
31
}
1386
1387
GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
1388
             GString **namesA,
1389
             GfxColorSpace *altA,
1390
             Function *funcA,
1391
             Object *attrsA,
1392
             GBool nonMarkingA,
1393
22
             Guint overprintMaskA) {
1394
22
  int i;
1395
1396
22
  nComps = nCompsA;
1397
22
  alt = altA;
1398
22
  func = funcA;
1399
22
  attrsA->copy(&attrs);
1400
22
  nonMarking = nonMarkingA;
1401
22
  overprintMask = overprintMaskA;
1402
58
  for (i = 0; i < nComps; ++i) {
1403
36
    names[i] = namesA[i]->copy();
1404
36
  }
1405
22
}
1406
1407
53
GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
1408
53
  int i;
1409
1410
152
  for (i = 0; i < nComps; ++i) {
1411
99
    delete names[i];
1412
99
  }
1413
53
  delete alt;
1414
53
  delete func;
1415
53
  attrs.free();
1416
53
}
1417
1418
22
GfxColorSpace *GfxDeviceNColorSpace::copy() {
1419
22
  GfxDeviceNColorSpace *cs;
1420
1421
22
  cs = new GfxDeviceNColorSpace(nComps, names, alt->copy(), func->copy(),
1422
22
        &attrs, nonMarking, overprintMask);
1423
22
  return cs;
1424
22
}
1425
1426
GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr,
1427
492
             int recursion) {
1428
492
  GfxDeviceNColorSpace *cs;
1429
492
  int nCompsA;
1430
492
  GString *namesA[gfxColorMaxComps];
1431
492
  GfxColorSpace *altA;
1432
492
  Function *funcA;
1433
492
  Object attrsA, obj1, obj2;
1434
492
  int i;
1435
1436
492
  if (arr->getLength() != 4 && arr->getLength() != 5) {
1437
0
    error(errSyntaxError, -1, "Bad DeviceN color space");
1438
0
    goto err1;
1439
0
  }
1440
492
  if (!arr->get(1, &obj1)->isArray()) {
1441
0
    error(errSyntaxError, -1, "Bad DeviceN color space (names)");
1442
0
    goto err2;
1443
0
  }
1444
492
  nCompsA = obj1.arrayGetLength();
1445
492
  if (nCompsA > gfxColorMaxComps) {
1446
0
    error(errSyntaxError, -1,
1447
0
    "DeviceN color space with too many ({0:d} > {1:d}) components",
1448
0
    nCompsA, gfxColorMaxComps);
1449
0
    nCompsA = gfxColorMaxComps;
1450
0
  }
1451
2.24k
  for (i = 0; i < nCompsA; ++i) {
1452
1.75k
    if (!obj1.arrayGet(i, &obj2)->isName()) {
1453
0
      error(errSyntaxError, -1, "Bad DeviceN color space (names)");
1454
0
      obj2.free();
1455
0
      goto err2;
1456
0
    }
1457
1.75k
    namesA[i] = new GString(obj2.getName());
1458
1.75k
    obj2.free();
1459
1.75k
  }
1460
492
  obj1.free();
1461
492
  arr->get(2, &obj1);
1462
  // some PDF generators use an ICC profile stream here; Adobe
1463
  // apparently looks at the /Alternate entry in the stream dictionary
1464
492
  if (obj1.isStream() &&
1465
1
      !obj1.streamGetDict()->lookup("Alternate", &obj2)->isNull()) {
1466
0
    obj1.free();
1467
0
    obj1 = obj2;
1468
0
  }
1469
492
  if (!(altA = GfxColorSpace::parse(&obj1,
1470
492
            recursion + 1))) {
1471
151
    error(errSyntaxError, -1,
1472
151
    "Bad DeviceN color space (alternate color space)");
1473
151
    goto err3;
1474
151
  }
1475
341
  obj1.free();
1476
341
  arr->get(3, &obj1);
1477
341
  if (!(funcA = Function::parse(&obj1, nCompsA, altA->getNComps()))) {
1478
310
    goto err4;
1479
310
  }
1480
31
  obj1.free();
1481
31
  if (arr->getLength() == 5) {
1482
22
    arr->get(4, &attrsA);
1483
22
  } else {
1484
9
    attrsA.initNull();
1485
9
  }
1486
31
  cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA, &attrsA);
1487
31
  attrsA.free();
1488
31
  return cs;
1489
1490
310
 err4:
1491
310
  delete altA;
1492
461
 err3:
1493
2.15k
  for (i = 0; i < nCompsA; ++i) {
1494
1.69k
    delete namesA[i];
1495
1.69k
  }
1496
461
 err2:
1497
461
  obj1.free();
1498
461
 err1:
1499
461
  return NULL;
1500
461
}
1501
1502
1503
void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray,
1504
0
           GfxRenderingIntent ri) {
1505
0
  double x[gfxColorMaxComps], c[gfxColorMaxComps];
1506
0
  GfxColor color2;
1507
0
  int i;
1508
1509
0
  for (i = 0; i < nComps; ++i) {
1510
0
    x[i] = colToDbl(color->c[i]);
1511
0
  }
1512
0
  func->transform(x, c);
1513
0
  for (i = 0; i < alt->getNComps(); ++i) {
1514
0
    color2.c[i] = dblToCol(c[i]);
1515
0
  }
1516
0
  alt->getGray(&color2, gray, ri);
1517
0
}
1518
1519
void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
1520
108
          GfxRenderingIntent ri) {
1521
108
  double x[gfxColorMaxComps], c[gfxColorMaxComps];
1522
108
  GfxColor color2;
1523
108
  int i;
1524
1525
240
  for (i = 0; i < nComps; ++i) {
1526
132
    x[i] = colToDbl(color->c[i]);
1527
132
  }
1528
108
  func->transform(x, c);
1529
528
  for (i = 0; i < alt->getNComps(); ++i) {
1530
420
    color2.c[i] = dblToCol(c[i]);
1531
420
  }
1532
108
  alt->getRGB(&color2, rgb, ri);
1533
108
}
1534
1535
void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
1536
0
           GfxRenderingIntent ri) {
1537
0
  double x[gfxColorMaxComps], c[gfxColorMaxComps];
1538
0
  GfxColor color2;
1539
0
  int i;
1540
1541
0
  for (i = 0; i < nComps; ++i) {
1542
0
    x[i] = colToDbl(color->c[i]);
1543
0
  }
1544
0
  func->transform(x, c);
1545
0
  for (i = 0; i < alt->getNComps(); ++i) {
1546
0
    color2.c[i] = dblToCol(c[i]);
1547
0
  }
1548
0
  alt->getCMYK(&color2, cmyk, ri);
1549
0
}
1550
1551
1552
1553
9
void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) {
1554
9
  int i;
1555
1556
36
  for (i = 0; i < nComps; ++i) {
1557
27
    color->c[i] = gfxColorComp1;
1558
27
  }
1559
9
}
1560
1561
//------------------------------------------------------------------------
1562
// GfxPatternColorSpace
1563
//------------------------------------------------------------------------
1564
1565
33.4k
GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1566
33.4k
  under = underA;
1567
33.4k
}
1568
1569
33.3k
GfxPatternColorSpace::~GfxPatternColorSpace() {
1570
33.3k
  if (under) {
1571
248
    delete under;
1572
248
  }
1573
33.3k
}
1574
1575
28.0k
GfxColorSpace *GfxPatternColorSpace::copy() {
1576
28.0k
  GfxPatternColorSpace *cs;
1577
1578
28.0k
  cs = new GfxPatternColorSpace(under ? under->copy() :
1579
28.0k
                (GfxColorSpace *)NULL);
1580
28.0k
  return cs;
1581
28.0k
}
1582
1583
GfxColorSpace *GfxPatternColorSpace::parse(Array *arr,
1584
298
             int recursion) {
1585
298
  GfxPatternColorSpace *cs;
1586
298
  GfxColorSpace *underA;
1587
298
  Object obj1;
1588
1589
298
  if (arr->getLength() != 1 && arr->getLength() != 2) {
1590
0
    error(errSyntaxError, -1, "Bad Pattern color space");
1591
0
    return NULL;
1592
0
  }
1593
298
  underA = NULL;
1594
298
  if (arr->getLength() == 2) {
1595
120
    arr->get(1, &obj1);
1596
120
    if (!(underA = GfxColorSpace::parse(&obj1,
1597
120
          recursion + 1))) {
1598
2
      error(errSyntaxError, -1,
1599
2
      "Bad Pattern color space (underlying color space)");
1600
2
      obj1.free();
1601
2
      return NULL;
1602
2
    }
1603
118
    obj1.free();
1604
118
  }
1605
296
  cs = new GfxPatternColorSpace(underA);
1606
296
  return cs;
1607
298
}
1608
1609
1610
void GfxPatternColorSpace::getGray(GfxColor *color, GfxGray *gray,
1611
0
           GfxRenderingIntent ri) {
1612
0
  *gray = 0;
1613
0
}
1614
1615
void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb,
1616
5.80k
          GfxRenderingIntent ri) {
1617
5.80k
  rgb->r = rgb->g = rgb->b = 0;
1618
5.80k
}
1619
1620
void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk,
1621
0
           GfxRenderingIntent ri) {
1622
0
  cmyk->c = cmyk->m = cmyk->y = 0;
1623
0
  cmyk->k = 1;
1624
0
}
1625
1626
1627
1628
5.34k
void GfxPatternColorSpace::getDefaultColor(GfxColor *color) {
1629
  // not used
1630
5.34k
}
1631
1632
//------------------------------------------------------------------------
1633
// Pattern
1634
//------------------------------------------------------------------------
1635
1636
3.44k
GfxPattern::GfxPattern(int typeA) {
1637
3.44k
  type = typeA;
1638
3.44k
}
1639
1640
3.42k
GfxPattern::~GfxPattern() {
1641
3.42k
}
1642
1643
GfxPattern *GfxPattern::parse(Object *objRef, Object *obj
1644
2.22k
            ) {
1645
2.22k
  GfxPattern *pattern;
1646
2.22k
  Object typeObj;
1647
1648
2.22k
  if (obj->isDict()) {
1649
453
    obj->dictLookup("PatternType", &typeObj);
1650
1.77k
  } else if (obj->isStream()) {
1651
1.74k
    obj->streamGetDict()->lookup("PatternType", &typeObj);
1652
1.74k
  } else {
1653
30
    return NULL;
1654
30
  }
1655
2.19k
  pattern = NULL;
1656
2.19k
  if (typeObj.isInt() && typeObj.getInt() == 1) {
1657
1.72k
    pattern = GfxTilingPattern::parse(objRef, obj);
1658
1.72k
  } else if (typeObj.isInt() && typeObj.getInt() == 2) {
1659
377
    pattern = GfxShadingPattern::parse(obj
1660
377
               );
1661
377
  }
1662
2.19k
  typeObj.free();
1663
2.19k
  return pattern;
1664
2.22k
}
1665
1666
//------------------------------------------------------------------------
1667
// GfxTilingPattern
1668
//------------------------------------------------------------------------
1669
1670
1.72k
GfxTilingPattern *GfxTilingPattern::parse(Object *patObjRef, Object *patObj) {
1671
1.72k
  GfxTilingPattern *pat;
1672
1.72k
  Dict *dict;
1673
1.72k
  int paintTypeA, tilingTypeA;
1674
1.72k
  double bboxA[4], matrixA[6];
1675
1.72k
  double xStepA, yStepA;
1676
1.72k
  Object resDictA;
1677
1.72k
  Object obj1, obj2;
1678
1.72k
  int i;
1679
1680
1.72k
  if (!patObj->isStream()) {
1681
6
    return NULL;
1682
6
  }
1683
1.71k
  dict = patObj->streamGetDict();
1684
1685
1.71k
  if (dict->lookup("PaintType", &obj1)->isInt()) {
1686
1.70k
    paintTypeA = obj1.getInt();
1687
1.70k
  } else {
1688
16
    paintTypeA = 1;
1689
16
    error(errSyntaxWarning, -1, "Invalid or missing PaintType in pattern");
1690
16
  }
1691
1.71k
  obj1.free();
1692
1.71k
  if (dict->lookup("TilingType", &obj1)->isInt()) {
1693
412
    tilingTypeA = obj1.getInt();
1694
1.30k
  } else {
1695
1.30k
    tilingTypeA = 1;
1696
1.30k
    error(errSyntaxWarning, -1, "Invalid or missing TilingType in pattern");
1697
1.30k
  }
1698
1.71k
  obj1.free();
1699
1.71k
  bboxA[0] = bboxA[1] = 0;
1700
1.71k
  bboxA[2] = bboxA[3] = 1;
1701
1.71k
  if (dict->lookup("BBox", &obj1)->isArray() &&
1702
1.66k
      obj1.arrayGetLength() == 4) {
1703
8.27k
    for (i = 0; i < 4; ++i) {
1704
6.61k
      if (obj1.arrayGet(i, &obj2)->isNum()) {
1705
6.35k
  bboxA[i] = obj2.getNum();
1706
6.35k
      }
1707
6.61k
      obj2.free();
1708
6.61k
    }
1709
1.65k
  } else {
1710
63
    error(errSyntaxError, -1, "Invalid or missing BBox in pattern");
1711
63
  }
1712
1.71k
  obj1.free();
1713
1.71k
  if (dict->lookup("XStep", &obj1)->isNum()) {
1714
887
    xStepA = obj1.getNum();
1715
887
  } else {
1716
830
    xStepA = 1;
1717
830
    error(errSyntaxError, -1, "Invalid or missing XStep in pattern");
1718
830
  }
1719
1.71k
  obj1.free();
1720
1.71k
  if (dict->lookup("YStep", &obj1)->isNum()) {
1721
1.70k
    yStepA = obj1.getNum();
1722
1.70k
  } else {
1723
10
    yStepA = 1;
1724
10
    error(errSyntaxError, -1, "Invalid or missing YStep in pattern");
1725
10
  }
1726
1.71k
  obj1.free();
1727
1.71k
  if (!dict->lookup("Resources", &resDictA)->isDict()) {
1728
0
    resDictA.free();
1729
0
    resDictA.initNull();
1730
0
    error(errSyntaxError, -1, "Invalid or missing Resources in pattern");
1731
0
  }
1732
1.71k
  matrixA[0] = 1; matrixA[1] = 0;
1733
1.71k
  matrixA[2] = 0; matrixA[3] = 1;
1734
1.71k
  matrixA[4] = 0; matrixA[5] = 0;
1735
1.71k
  if (dict->lookup("Matrix", &obj1)->isArray() &&
1736
227
      obj1.arrayGetLength() == 6) {
1737
1.58k
    for (i = 0; i < 6; ++i) {
1738
1.35k
      if (obj1.arrayGet(i, &obj2)->isNum()) {
1739
1.33k
  matrixA[i] = obj2.getNum();
1740
1.33k
      }
1741
1.35k
      obj2.free();
1742
1.35k
    }
1743
226
  }
1744
1.71k
  obj1.free();
1745
1746
1.71k
  pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
1747
1.71k
           &resDictA, matrixA, patObjRef);
1748
1.71k
  resDictA.free();
1749
1.71k
  return pat;
1750
1.72k
}
1751
1752
GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
1753
           double *bboxA, double xStepA, double yStepA,
1754
           Object *resDictA, double *matrixA,
1755
           Object *contentStreamRefA):
1756
2.92k
  GfxPattern(1)
1757
2.92k
{
1758
2.92k
  int i;
1759
1760
2.92k
  paintType = paintTypeA;
1761
2.92k
  tilingType = tilingTypeA;
1762
14.6k
  for (i = 0; i < 4; ++i) {
1763
11.7k
    bbox[i] = bboxA[i];
1764
11.7k
  }
1765
2.92k
  xStep = xStepA;
1766
2.92k
  yStep = yStepA;
1767
2.92k
  resDictA->copy(&resDict);
1768
20.4k
  for (i = 0; i < 6; ++i) {
1769
17.5k
    matrix[i] = matrixA[i];
1770
17.5k
  }
1771
2.92k
  contentStreamRefA->copy(&contentStreamRef);
1772
2.92k
}
1773
1774
2.92k
GfxTilingPattern::~GfxTilingPattern() {
1775
2.92k
  resDict.free();
1776
2.92k
  contentStreamRef.free();
1777
2.92k
}
1778
1779
1.20k
GfxPattern *GfxTilingPattern::copy() {
1780
1.20k
  return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
1781
1.20k
            &resDict, matrix, &contentStreamRef);
1782
1.20k
}
1783
1784
840
GBool GfxTilingPattern::usesBlendMode(XRef *xref) {
1785
840
  char *scannedObjs = (char *)gmalloc(xref->getNumObjects());
1786
840
  memset(scannedObjs, 0, xref->getNumObjects());
1787
840
  GBool ret = scanResourcesForBlendMode(&resDict, scannedObjs, xref);
1788
840
  gfree(scannedObjs);
1789
840
  return ret;
1790
840
}
1791
1792
GBool GfxTilingPattern::scanResourcesForBlendMode(Object *resDict2,
1793
              char *scannedObjs,
1794
1.18k
              XRef *xref) {
1795
1.18k
  Object ref1, obj1, obj2;
1796
1797
1.18k
  if (!resDict2->isDict()) {
1798
0
    return gFalse;
1799
0
  }
1800
1801
  //----- ExtGStates
1802
1.18k
  resDict2->dictLookupNF("ExtGState", &ref1);
1803
1.18k
  if (!ref1.isRef() || (ref1.getRefNum() < xref->getNumObjects() &&
1804
1.18k
      !scannedObjs[ref1.getRefNum()])) {
1805
1.18k
    if (ref1.isRef()) {
1806
0
      scannedObjs[ref1.getRefNum()] = 1;
1807
0
      ref1.fetch(xref, &obj1);
1808
1.18k
    } else {
1809
1.18k
      ref1.copy(&obj1);
1810
1.18k
    }
1811
1.18k
    if (obj1.isDict()) {
1812
3.03k
      for (int i = 0; i < obj1.dictGetLength(); ++i) {
1813
2.02k
  if (scanExtGStateForBlendMode(obj1.dictGetValNF(i, &obj2),
1814
2.02k
              scannedObjs, xref)) {
1815
0
    obj2.free();
1816
0
    obj1.free();
1817
0
    ref1.free();
1818
0
    return gTrue;
1819
0
  }
1820
2.02k
  obj2.free();
1821
2.02k
      }
1822
1.01k
    }
1823
1.18k
    obj1.free();
1824
1.18k
  }
1825
1.18k
  ref1.free();
1826
1827
  //----- patterns
1828
1.18k
  resDict2->dictLookupNF("Pattern", &ref1);
1829
1.18k
  if (!ref1.isRef() || (ref1.getRefNum() < xref->getNumObjects() &&
1830
1.18k
      !scannedObjs[ref1.getRefNum()])) {
1831
1.18k
    if (ref1.isRef()) {
1832
0
      scannedObjs[ref1.getRefNum()] = 1;
1833
0
      ref1.fetch(xref, &obj1);
1834
1.18k
    } else {
1835
1.18k
      ref1.copy(&obj1);
1836
1.18k
    }
1837
1.18k
    if (obj1.isDict()) {
1838
1.89k
      for (int i = 0; i < obj1.dictGetLength(); ++i) {
1839
757
  if (scanPatternForBlendMode(obj1.dictGetValNF(i, &obj2),
1840
757
            scannedObjs, xref)) {
1841
0
    obj2.free();
1842
0
    obj1.free();
1843
0
    ref1.free();
1844
0
    return gTrue;
1845
0
  }
1846
757
  obj2.free();
1847
757
      }
1848
1.13k
    }
1849
1.18k
    obj1.free();
1850
1.18k
  }
1851
1.18k
  ref1.free();
1852
1853
  //----- XObjects
1854
1.18k
  resDict2->dictLookupNF("XObject", &ref1);
1855
1.18k
  if (!ref1.isRef() || (ref1.getRefNum() < xref->getNumObjects() &&
1856
1.18k
      !scannedObjs[ref1.getRefNum()])) {
1857
1.18k
    if (ref1.isRef()) {
1858
0
      scannedObjs[ref1.getRefNum()] = 1;
1859
0
      ref1.fetch(xref, &obj1);
1860
1.18k
    } else {
1861
1.18k
      ref1.copy(&obj1);
1862
1.18k
    }
1863
1.18k
    if (obj1.isDict()) {
1864
95
      for (int i = 0; i < obj1.dictGetLength(); ++i) {
1865
47
  if (scanXObjectForBlendMode(obj1.dictGetValNF(i, &obj2),
1866
47
            scannedObjs, xref)) {
1867
0
    obj2.free();
1868
0
    obj1.free();
1869
0
    ref1.free();
1870
0
    return gTrue;
1871
0
  }
1872
47
  obj2.free();
1873
47
      }
1874
48
    }
1875
1.18k
    obj1.free();
1876
1.18k
  }
1877
1.18k
  ref1.free();
1878
1879
1.18k
  return gFalse;
1880
1.18k
}
1881
1882
GBool GfxTilingPattern::scanExtGStateForBlendMode(Object *gsObj,
1883
              char *scannedObjs,
1884
2.02k
              XRef *xref) {
1885
2.02k
  Object gsDict, obj1;
1886
1887
2.02k
  if (gsObj->isRef()) {
1888
1.34k
    if (gsObj->getRefNum() >= xref->getNumObjects() ||
1889
1.33k
  scannedObjs[gsObj->getRefNum()]) {
1890
456
      return gFalse;
1891
456
    }
1892
889
    scannedObjs[gsObj->getRefNum()] = 1;
1893
889
    gsObj->fetch(xref, &gsDict);
1894
889
  } else {
1895
678
    gsObj->copy(&gsDict);
1896
678
  }
1897
1.56k
  if (!gsDict.isDict()) {
1898
794
    gsDict.free();
1899
794
    return gFalse;
1900
794
  }
1901
1902
773
  gsDict.dictLookup("BM", &obj1);
1903
773
  if (obj1.isName() && !obj1.isName("Normal")) {
1904
0
    obj1.free();
1905
0
    gsDict.free();
1906
0
    return gTrue;
1907
0
  }
1908
773
  obj1.free();
1909
1910
773
  if (!gsDict.dictLookupNF("SMask", &obj1)->isNull()) {
1911
542
    if (scanSoftMaskForBlendMode(&obj1, scannedObjs, xref)) {
1912
0
      obj1.free();
1913
0
      gsDict.free();
1914
0
      return gTrue;
1915
0
    }
1916
542
  }
1917
773
  obj1.free();
1918
1919
773
  gsDict.free();
1920
1921
773
  return gFalse;
1922
773
}
1923
1924
GBool GfxTilingPattern::scanSoftMaskForBlendMode(Object *softMaskObj,
1925
             char *scannedObjs,
1926
542
             XRef *xref) {
1927
542
  Object softMaskDict, obj1;
1928
1929
542
  if (softMaskObj->isRef()) {
1930
0
    if (softMaskObj->getRefNum() >= xref->getNumObjects() ||
1931
0
  scannedObjs[softMaskObj->getRefNum()]) {
1932
0
      return gFalse;
1933
0
    }
1934
0
    scannedObjs[softMaskObj->getRefNum()] = 1;
1935
0
    softMaskObj->fetch(xref, &softMaskDict);
1936
542
  } else {
1937
542
    softMaskObj->copy(&softMaskDict);
1938
542
  }
1939
542
  if (!softMaskDict.isDict()) {
1940
11
    softMaskDict.free();
1941
11
    return gFalse;
1942
11
  }
1943
1944
531
  if (!softMaskDict.dictLookupNF("G", &obj1)->isNull()) {
1945
123
    if (scanXObjectForBlendMode(&obj1, scannedObjs, xref)) {
1946
0
      obj1.free();
1947
0
      softMaskDict.free();
1948
0
      return gTrue;
1949
0
    }
1950
123
  }
1951
531
  obj1.free();
1952
1953
531
  softMaskDict.free();
1954
1955
531
  return gFalse;
1956
531
}
1957
1958
GBool GfxTilingPattern::scanPatternForBlendMode(Object *patternObj,
1959
            char *scannedObjs,
1960
757
            XRef *xref) {
1961
757
  Object patternObj2, obj1;
1962
757
  Dict *patternDict;
1963
1964
757
  if (patternObj->isRef()) {
1965
660
    if (patternObj->getRefNum() >= xref->getNumObjects() ||
1966
654
  scannedObjs[patternObj->getRefNum()]) {
1967
226
      return gFalse;
1968
226
    }
1969
434
    scannedObjs[patternObj->getRefNum()] = 1;
1970
434
    patternObj->fetch(xref, &patternObj2);
1971
434
  } else {
1972
97
    patternObj->copy(&patternObj2);
1973
97
  }
1974
531
  if (patternObj2.isDict()) {
1975
215
    patternDict = patternObj2.getDict();
1976
316
  } else if (patternObj2.isStream()) {
1977
219
    patternDict = patternObj2.streamGetDict();
1978
219
  } else {
1979
97
    patternObj2.free();
1980
97
    return gFalse;
1981
97
  }
1982
1983
434
  if (!patternDict->lookupNF("Resources", &obj1)->isNull()) {
1984
219
    if (scanResourcesForBlendMode(&obj1, scannedObjs, xref)) {
1985
0
      obj1.free();
1986
0
      patternObj2.free();
1987
0
      return gTrue;
1988
0
    }
1989
219
  }
1990
434
  obj1.free();
1991
1992
434
  patternObj2.free();
1993
1994
434
  return gFalse;
1995
434
}
1996
1997
GBool GfxTilingPattern::scanXObjectForBlendMode(Object *xObj,
1998
            char *scannedObjs,
1999
170
            XRef *xref) {
2000
170
  Object xObj2, obj1;
2001
170
  Dict *dict;
2002
2003
170
  if (xObj->isRef()) {
2004
164
    if (xObj->getRefNum() >= xref->getNumObjects() ||
2005
161
  scannedObjs[xObj->getRefNum()]) {
2006
11
      return gFalse;
2007
11
    }
2008
153
    scannedObjs[xObj->getRefNum()] = 1;
2009
153
    xObj->fetch(xref, &xObj2);
2010
153
  } else {
2011
6
    xObj->copy(&xObj2);
2012
6
  }
2013
159
  if (xObj2.isDict()) {
2014
12
    dict = xObj2.getDict();
2015
147
  } else if (xObj2.isStream()) {
2016
141
    dict = xObj2.streamGetDict();
2017
141
  } else {
2018
6
    xObj2.free();
2019
6
    return gFalse;
2020
6
  }
2021
2022
153
  if (!dict->lookupNF("Resources", &obj1)->isNull()) {
2023
126
    if (scanResourcesForBlendMode(&obj1, scannedObjs, xref)) {
2024
0
      obj1.free();
2025
0
      xObj2.free();
2026
0
      return gTrue;
2027
0
    }
2028
126
  }
2029
153
  obj1.free();
2030
2031
153
  xObj2.free();
2032
2033
153
  return gFalse;
2034
153
}
2035
2036
//------------------------------------------------------------------------
2037
// GfxShadingPattern
2038
//------------------------------------------------------------------------
2039
2040
GfxShadingPattern *GfxShadingPattern::parse(Object *patObj
2041
377
              ) {
2042
377
  Dict *dict;
2043
377
  GfxShading *shadingA;
2044
377
  double matrixA[6];
2045
377
  Object obj1, obj2;
2046
377
  int i;
2047
2048
377
  if (!patObj->isDict()) {
2049
0
    return NULL;
2050
0
  }
2051
377
  dict = patObj->getDict();
2052
2053
377
  dict->lookup("Shading", &obj1);
2054
377
  shadingA = GfxShading::parse(&obj1
2055
377
             );
2056
377
  obj1.free();
2057
377
  if (!shadingA) {
2058
106
    return NULL;
2059
106
  }
2060
2061
271
  matrixA[0] = 1; matrixA[1] = 0;
2062
271
  matrixA[2] = 0; matrixA[3] = 1;
2063
271
  matrixA[4] = 0; matrixA[5] = 0;
2064
271
  if (dict->lookup("Matrix", &obj1)->isArray() &&
2065
271
      obj1.arrayGetLength() == 6) {
2066
1.84k
    for (i = 0; i < 6; ++i) {
2067
1.58k
      if (obj1.arrayGet(i, &obj2)->isNum()) {
2068
1.33k
  matrixA[i] = obj2.getNum();
2069
1.33k
      }
2070
1.58k
      obj2.free();
2071
1.58k
    }
2072
264
  }
2073
271
  obj1.free();
2074
2075
271
  return new GfxShadingPattern(shadingA, matrixA);
2076
377
}
2077
2078
GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
2079
521
  GfxPattern(2)
2080
521
{
2081
521
  int i;
2082
2083
521
  shading = shadingA;
2084
3.64k
  for (i = 0; i < 6; ++i) {
2085
3.12k
    matrix[i] = matrixA[i];
2086
3.12k
  }
2087
521
}
2088
2089
503
GfxShadingPattern::~GfxShadingPattern() {
2090
503
  delete shading;
2091
503
}
2092
2093
250
GfxPattern *GfxShadingPattern::copy() {
2094
250
  return new GfxShadingPattern(shading->copy(), matrix);
2095
250
}
2096
2097
//------------------------------------------------------------------------
2098
// GfxShading
2099
//------------------------------------------------------------------------
2100
2101
2.73k
GfxShading::GfxShading(int typeA) {
2102
2.73k
  type = typeA;
2103
2.73k
  colorSpace = NULL;
2104
2.73k
}
2105
2106
250
GfxShading::GfxShading(GfxShading *shading) {
2107
250
  int i;
2108
2109
250
  type = shading->type;
2110
250
  colorSpace = shading->colorSpace->copy();
2111
8.25k
  for (i = 0; i < gfxColorMaxComps; ++i) {
2112
8.00k
    background.c[i] = shading->background.c[i];
2113
8.00k
  }
2114
250
  hasBackground = shading->hasBackground;
2115
250
  xMin = shading->xMin;
2116
250
  yMin = shading->yMin;
2117
250
  xMax = shading->xMax;
2118
250
  yMax = shading->yMax;
2119
250
  hasBBox = shading->hasBBox;
2120
250
}
2121
2122
2.96k
GfxShading::~GfxShading() {
2123
2.96k
  if (colorSpace) {
2124
2.63k
    delete colorSpace;
2125
2.63k
  }
2126
2.96k
}
2127
2128
GfxShading *GfxShading::parse(Object *obj
2129
4.01k
            ) {
2130
4.01k
  GfxShading *shading;
2131
4.01k
  Dict *dict;
2132
4.01k
  int typeA;
2133
4.01k
  Object obj1;
2134
2135
4.01k
  if (obj->isDict()) {
2136
3.05k
    dict = obj->getDict();
2137
3.05k
  } else if (obj->isStream()) {
2138
827
    dict = obj->streamGetDict();
2139
827
  } else {
2140
138
    return NULL;
2141
138
  }
2142
2143
3.88k
  if (!dict->lookup("ShadingType", &obj1)->isInt()) {
2144
63
    error(errSyntaxError, -1, "Invalid ShadingType in shading dictionary");
2145
63
    obj1.free();
2146
63
    return NULL;
2147
63
  }
2148
3.81k
  typeA = obj1.getInt();
2149
3.81k
  obj1.free();
2150
2151
3.81k
  switch (typeA) {
2152
4
  case 1:
2153
4
    shading = GfxFunctionShading::parse(dict
2154
4
          );
2155
4
    break;
2156
2.98k
  case 2:
2157
2.98k
    shading = GfxAxialShading::parse(dict
2158
2.98k
             );
2159
2.98k
    break;
2160
0
  case 3:
2161
0
    shading = GfxRadialShading::parse(dict
2162
0
              );
2163
0
    break;
2164
33
  case 4:
2165
33
    if (obj->isStream()) {
2166
33
      shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream()
2167
33
             );
2168
33
    } else {
2169
0
      error(errSyntaxError, -1, "Invalid Type 4 shading object");
2170
0
      goto err1;
2171
0
    }
2172
33
    break;
2173
324
  case 5:
2174
324
    if (obj->isStream()) {
2175
318
      shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream()
2176
318
             );
2177
318
    } else {
2178
6
      error(errSyntaxError, -1, "Invalid Type 5 shading object");
2179
6
      goto err1;
2180
6
    }
2181
318
    break;
2182
318
  case 6:
2183
0
    if (obj->isStream()) {
2184
0
      shading = GfxPatchMeshShading::parse(6, dict, obj->getStream()
2185
0
             );
2186
0
    } else {
2187
0
      error(errSyntaxError, -1, "Invalid Type 6 shading object");
2188
0
      goto err1;
2189
0
    }
2190
0
    break;
2191
474
  case 7:
2192
474
    if (obj->isStream()) {
2193
474
      shading = GfxPatchMeshShading::parse(7, dict, obj->getStream()
2194
474
             );
2195
474
    } else {
2196
0
      error(errSyntaxError, -1, "Invalid Type 7 shading object");
2197
0
      goto err1;
2198
0
    }
2199
474
    break;
2200
474
  default:
2201
2
    error(errSyntaxError, -1, "Unknown shading type {0:d}", typeA);
2202
2
    goto err1;
2203
3.81k
  }
2204
2205
3.81k
  return shading;
2206
2207
8
 err1:
2208
8
  return NULL;
2209
3.81k
}
2210
2211
GBool GfxShading::init(Dict *dict
2212
2.73k
           ) {
2213
2.73k
  Object obj1, obj2;
2214
2.73k
  int i;
2215
2216
2.73k
  dict->lookup("ColorSpace", &obj1);
2217
2.73k
  if (!(colorSpace = GfxColorSpace::parse(&obj1
2218
2.73k
            ))) {
2219
331
    error(errSyntaxError, -1, "Bad color space in shading dictionary");
2220
331
    obj1.free();
2221
331
    return gFalse;
2222
331
  }
2223
2.40k
  obj1.free();
2224
2225
79.4k
  for (i = 0; i < gfxColorMaxComps; ++i) {
2226
77.0k
    background.c[i] = 0;
2227
77.0k
  }
2228
2.40k
  hasBackground = gFalse;
2229
2.40k
  if (dict->lookup("Background", &obj1)->isArray()) {
2230
18
    if (obj1.arrayGetLength() == colorSpace->getNComps()) {
2231
0
      hasBackground = gTrue;
2232
0
      for (i = 0; i < colorSpace->getNComps(); ++i) {
2233
0
  background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum());
2234
0
  obj2.free();
2235
0
      }
2236
18
    } else {
2237
18
      error(errSyntaxError, -1, "Bad Background in shading dictionary");
2238
18
    }
2239
18
  }
2240
2.40k
  obj1.free();
2241
2242
2.40k
  xMin = yMin = xMax = yMax = 0;
2243
2.40k
  hasBBox = gFalse;
2244
2.40k
  if (dict->lookup("BBox", &obj1)->isArray()) {
2245
0
    if (obj1.arrayGetLength() == 4) {
2246
0
      hasBBox = gTrue;
2247
0
      xMin = obj1.arrayGet(0, &obj2)->getNum();
2248
0
      obj2.free();
2249
0
      yMin = obj1.arrayGet(1, &obj2)->getNum();
2250
0
      obj2.free();
2251
0
      xMax = obj1.arrayGet(2, &obj2)->getNum();
2252
0
      obj2.free();
2253
0
      yMax = obj1.arrayGet(3, &obj2)->getNum();
2254
0
      obj2.free();
2255
0
    } else {
2256
0
      error(errSyntaxError, -1, "Bad BBox in shading dictionary");
2257
0
    }
2258
0
  }
2259
2.40k
  obj1.free();
2260
2261
2.40k
  return gTrue;
2262
2.73k
}
2263
2264
//------------------------------------------------------------------------
2265
// GfxFunctionShading
2266
//------------------------------------------------------------------------
2267
2268
GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
2269
               double x1A, double y1A,
2270
               double *matrixA,
2271
               Function **funcsA, int nFuncsA):
2272
0
  GfxShading(1)
2273
0
{
2274
0
  int i;
2275
2276
0
  x0 = x0A;
2277
0
  y0 = y0A;
2278
0
  x1 = x1A;
2279
0
  y1 = y1A;
2280
0
  for (i = 0; i < 6; ++i) {
2281
0
    matrix[i] = matrixA[i];
2282
0
  }
2283
0
  nFuncs = nFuncsA;
2284
0
  for (i = 0; i < nFuncs; ++i) {
2285
0
    funcs[i] = funcsA[i];
2286
0
  }
2287
0
}
2288
2289
GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
2290
0
  GfxShading(shading)
2291
0
{
2292
0
  int i;
2293
2294
0
  x0 = shading->x0;
2295
0
  y0 = shading->y0;
2296
0
  x1 = shading->x1;
2297
0
  y1 = shading->y1;
2298
0
  for (i = 0; i < 6; ++i) {
2299
0
    matrix[i] = shading->matrix[i];
2300
0
  }
2301
0
  nFuncs = shading->nFuncs;
2302
0
  for (i = 0; i < nFuncs; ++i) {
2303
0
    funcs[i] = shading->funcs[i]->copy();
2304
0
  }
2305
0
}
2306
2307
0
GfxFunctionShading::~GfxFunctionShading() {
2308
0
  int i;
2309
2310
0
  for (i = 0; i < nFuncs; ++i) {
2311
0
    delete funcs[i];
2312
0
  }
2313
0
}
2314
2315
GfxFunctionShading *GfxFunctionShading::parse(Dict *dict
2316
4
                ) {
2317
4
  GfxFunctionShading *shading;
2318
4
  double x0A, y0A, x1A, y1A;
2319
4
  double matrixA[6];
2320
4
  Function *funcsA[gfxColorMaxComps];
2321
4
  int nFuncsA;
2322
4
  Object obj1, obj2;
2323
4
  GBool ok;
2324
4
  int i;
2325
2326
4
  x0A = y0A = 0;
2327
4
  x1A = y1A = 1;
2328
4
  if (dict->lookup("Domain", &obj1)->isArray() &&
2329
4
      obj1.arrayGetLength() == 4) {
2330
0
    x0A = obj1.arrayGet(0, &obj2)->getNum();
2331
0
    obj2.free();
2332
0
    x1A = obj1.arrayGet(1, &obj2)->getNum();
2333
0
    obj2.free();
2334
0
    y0A = obj1.arrayGet(2, &obj2)->getNum();
2335
0
    obj2.free();
2336
0
    y1A = obj1.arrayGet(3, &obj2)->getNum();
2337
0
    obj2.free();
2338
0
  }
2339
4
  obj1.free();
2340
2341
4
  matrixA[0] = 1; matrixA[1] = 0;
2342
4
  matrixA[2] = 0; matrixA[3] = 1;
2343
4
  matrixA[4] = 0; matrixA[5] = 0;
2344
4
  if (dict->lookup("Matrix", &obj1)->isArray() &&
2345
0
      obj1.arrayGetLength() == 6) {
2346
0
    matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
2347
0
    obj2.free();
2348
0
    matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
2349
0
    obj2.free();
2350
0
    matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
2351
0
    obj2.free();
2352
0
    matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
2353
0
    obj2.free();
2354
0
    matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
2355
0
    obj2.free();
2356
0
    matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
2357
0
    obj2.free();
2358
0
  }
2359
4
  obj1.free();
2360
2361
4
  dict->lookup("Function", &obj1);
2362
4
  if (obj1.isArray()) {
2363
0
    nFuncsA = obj1.arrayGetLength();
2364
0
    if (nFuncsA > gfxColorMaxComps) {
2365
0
      error(errSyntaxError, -1,
2366
0
      "Invalid Function array in shading dictionary");
2367
0
      goto err1;
2368
0
    }
2369
0
    for (i = 0; i < nFuncsA; ++i) {
2370
0
      obj1.arrayGet(i, &obj2);
2371
0
      if (!(funcsA[i] = Function::parse(&obj2, 2, 1))) {
2372
0
  goto err2;
2373
0
      }
2374
0
      obj2.free();
2375
0
    }
2376
4
  } else {
2377
4
    nFuncsA = 1;
2378
4
    if (!(funcsA[0] = Function::parse(&obj1, 2, -1))) {
2379
4
      goto err1;
2380
4
    }
2381
4
  }
2382
0
  obj1.free();
2383
2384
0
  shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
2385
0
           funcsA, nFuncsA);
2386
0
  if (!shading->init(dict
2387
0
         )) {
2388
0
    delete shading;
2389
0
    return NULL;
2390
0
  }
2391
2392
0
  ok = gFalse;
2393
0
  if (shading->nFuncs == 1) {
2394
0
    ok = shading->funcs[0]->getOutputSize()
2395
0
           == shading->getColorSpace()->getNComps();
2396
0
  } else if (shading->nFuncs == shading->getColorSpace()->getNComps()) {
2397
0
    ok = gTrue;
2398
0
    for (i = 0; i < shading->nFuncs; ++i) {
2399
0
      ok = ok && shading->funcs[i]->getOutputSize() == 1;
2400
0
    }
2401
0
  }
2402
0
  if (!ok) {
2403
0
    error(errSyntaxError, -1, "Invalid function in shading dictionary");
2404
0
    delete shading;
2405
0
    return NULL;
2406
0
  }
2407
2408
0
  return shading;
2409
2410
0
 err2:
2411
0
  obj2.free();
2412
4
 err1:
2413
4
  obj1.free();
2414
4
  return NULL;
2415
0
}
2416
2417
0
GfxShading *GfxFunctionShading::copy() {
2418
0
  return new GfxFunctionShading(this);
2419
0
}
2420
2421
0
void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
2422
0
  double in[2], out[gfxColorMaxComps];
2423
0
  int i;
2424
2425
  // NB: there can be one function with n outputs or n functions with
2426
  // one output each (where n = number of color components)
2427
0
  for (i = 0; i < gfxColorMaxComps; ++i) {
2428
0
    out[i] = 0;
2429
0
  }
2430
0
  in[0] = x;
2431
0
  in[1] = y;
2432
0
  for (i = 0; i < nFuncs; ++i) {
2433
0
    funcs[i]->transform(in, &out[i]);
2434
0
  }
2435
0
  for (i = 0; i < gfxColorMaxComps; ++i) {
2436
0
    color->c[i] = dblToCol(out[i]);
2437
0
  }
2438
0
}
2439
2440
//------------------------------------------------------------------------
2441
// GfxAxialShading
2442
//------------------------------------------------------------------------
2443
2444
GfxAxialShading::GfxAxialShading(double x0A, double y0A,
2445
         double x1A, double y1A,
2446
         double t0A, double t1A,
2447
         Function **funcsA, int nFuncsA,
2448
         GBool extend0A, GBool extend1A):
2449
2.03k
  GfxShading(2)
2450
2.03k
{
2451
2.03k
  int i;
2452
2453
2.03k
  x0 = x0A;
2454
2.03k
  y0 = y0A;
2455
2.03k
  x1 = x1A;
2456
2.03k
  y1 = y1A;
2457
2.03k
  t0 = t0A;
2458
2.03k
  t1 = t1A;
2459
2.03k
  nFuncs = nFuncsA;
2460
4.07k
  for (i = 0; i < nFuncs; ++i) {
2461
2.03k
    funcs[i] = funcsA[i];
2462
2.03k
  }
2463
2.03k
  extend0 = extend0A;
2464
2.03k
  extend1 = extend1A;
2465
2.03k
}
2466
2467
GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
2468
1
  GfxShading(shading)
2469
1
{
2470
1
  int i;
2471
2472
1
  x0 = shading->x0;
2473
1
  y0 = shading->y0;
2474
1
  x1 = shading->x1;
2475
1
  y1 = shading->y1;
2476
1
  t0 = shading->t0;
2477
1
  t1 = shading->t1;
2478
1
  nFuncs = shading->nFuncs;
2479
2
  for (i = 0; i < nFuncs; ++i) {
2480
1
    funcs[i] = shading->funcs[i]->copy();
2481
1
  }
2482
1
  extend0 = shading->extend0;
2483
1
  extend1 = shading->extend1;
2484
1
}
2485
2486
2.03k
GfxAxialShading::~GfxAxialShading() {
2487
2.03k
  int i;
2488
2489
4.07k
  for (i = 0; i < nFuncs; ++i) {
2490
2.03k
    delete funcs[i];
2491
2.03k
  }
2492
2.03k
}
2493
2494
GfxAxialShading *GfxAxialShading::parse(Dict *dict
2495
2.98k
          ) {
2496
2.98k
  GfxAxialShading *shading;
2497
2.98k
  double x0A, y0A, x1A, y1A;
2498
2.98k
  double t0A, t1A;
2499
2.98k
  Function *funcsA[gfxColorMaxComps];
2500
2.98k
  int nFuncsA;
2501
2.98k
  GBool extend0A, extend1A, ok;
2502
2.98k
  Object obj1, obj2;
2503
2.98k
  int i;
2504
2505
2.98k
  x0A = y0A = x1A = y1A = 0;
2506
2.98k
  if (dict->lookup("Coords", &obj1)->isArray() &&
2507
2.89k
      obj1.arrayGetLength() == 4) {
2508
2.82k
    x0A = obj1.arrayGet(0, &obj2)->getNum();
2509
2.82k
    obj2.free();
2510
2.82k
    y0A = obj1.arrayGet(1, &obj2)->getNum();
2511
2.82k
    obj2.free();
2512
2.82k
    x1A = obj1.arrayGet(2, &obj2)->getNum();
2513
2.82k
    obj2.free();
2514
2.82k
    y1A = obj1.arrayGet(3, &obj2)->getNum();
2515
2.82k
    obj2.free();
2516
2.82k
  } else {
2517
160
    error(errSyntaxError, -1,
2518
160
    "Missing or invalid Coords in shading dictionary");
2519
160
    obj1.free();
2520
160
    goto err1;
2521
160
  }
2522
2.82k
  obj1.free();
2523
2524
2.82k
  t0A = 0;
2525
2.82k
  t1A = 1;
2526
2.82k
  if (dict->lookup("Domain", &obj1)->isArray() &&
2527
482
      obj1.arrayGetLength() == 2) {
2528
482
    t0A = obj1.arrayGet(0, &obj2)->getNum();
2529
482
    obj2.free();
2530
482
    t1A = obj1.arrayGet(1, &obj2)->getNum();
2531
482
    obj2.free();
2532
482
  }
2533
2.82k
  obj1.free();
2534
2535
2.82k
  dict->lookup("Function", &obj1);
2536
2.82k
  if (obj1.isArray()) {
2537
0
    nFuncsA = obj1.arrayGetLength();
2538
0
    if (nFuncsA > gfxColorMaxComps) {
2539
0
      error(errSyntaxError, -1,
2540
0
      "Invalid Function array in shading dictionary");
2541
0
      goto err1;
2542
0
    }
2543
0
    for (i = 0; i < nFuncsA; ++i) {
2544
0
      obj1.arrayGet(i, &obj2);
2545
0
      if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) {
2546
0
  obj1.free();
2547
0
  obj2.free();
2548
0
  goto err1;
2549
0
      }
2550
0
      obj2.free();
2551
0
    }
2552
2.82k
  } else {
2553
2.82k
    nFuncsA = 1;
2554
2.82k
    if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) {
2555
782
      obj1.free();
2556
782
      goto err1;
2557
782
    }
2558
2.82k
  }
2559
2.03k
  obj1.free();
2560
2561
2.03k
  extend0A = extend1A = gFalse;
2562
2.03k
  if (dict->lookup("Extend", &obj1)->isArray() &&
2563
1.84k
      obj1.arrayGetLength() == 2) {
2564
1.64k
    extend0A = obj1.arrayGet(0, &obj2)->getBool();
2565
1.64k
    obj2.free();
2566
1.64k
    extend1A = obj1.arrayGet(1, &obj2)->getBool();
2567
1.64k
    obj2.free();
2568
1.64k
  }
2569
2.03k
  obj1.free();
2570
2571
2.03k
  shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
2572
2.03k
        funcsA, nFuncsA, extend0A, extend1A);
2573
2.03k
  if (!shading->init(dict
2574
2.03k
         )) {
2575
329
    delete shading;
2576
329
    return NULL;
2577
329
  }
2578
2579
1.71k
  ok = gFalse;
2580
1.71k
  if (shading->nFuncs == 1) {
2581
1.71k
    ok = shading->funcs[0]->getOutputSize()
2582
1.71k
           == shading->getColorSpace()->getNComps();
2583
1.71k
  } else if (shading->nFuncs == shading->getColorSpace()->getNComps()) {
2584
0
    ok = gTrue;
2585
0
    for (i = 0; i < shading->nFuncs; ++i) {
2586
0
      ok = ok && shading->funcs[i]->getOutputSize() == 1;
2587
0
    }
2588
0
  }
2589
1.71k
  if (!ok) {
2590
42
    error(errSyntaxError, -1, "Invalid function in shading dictionary");
2591
42
    delete shading;
2592
42
    return NULL;
2593
42
  }
2594
2595
1.66k
  return shading;
2596
2597
942
 err1:
2598
942
  return NULL;
2599
1.71k
}
2600
2601
1
GfxShading *GfxAxialShading::copy() {
2602
1
  return new GfxAxialShading(this);
2603
1
}
2604
2605
4.10k
void GfxAxialShading::getColor(double t, GfxColor *color) {
2606
4.10k
  double out[gfxColorMaxComps];
2607
4.10k
  int i;
2608
2609
  // NB: there can be one function with n outputs or n functions with
2610
  // one output each (where n = number of color components)
2611
135k
  for (i = 0; i < gfxColorMaxComps; ++i) {
2612
131k
    out[i] = 0;
2613
131k
  }
2614
8.20k
  for (i = 0; i < nFuncs; ++i) {
2615
4.10k
    funcs[i]->transform(&t, &out[i]);
2616
4.10k
  }
2617
135k
  for (i = 0; i < gfxColorMaxComps; ++i) {
2618
131k
    color->c[i] = dblToCol(out[i]);
2619
131k
  }
2620
4.10k
}
2621
2622
//------------------------------------------------------------------------
2623
// GfxRadialShading
2624
//------------------------------------------------------------------------
2625
2626
GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
2627
           double x1A, double y1A, double r1A,
2628
           double t0A, double t1A,
2629
           Function **funcsA, int nFuncsA,
2630
           GBool extend0A, GBool extend1A):
2631
0
  GfxShading(3)
2632
0
{
2633
0
  int i;
2634
2635
0
  x0 = x0A;
2636
0
  y0 = y0A;
2637
0
  r0 = r0A;
2638
0
  x1 = x1A;
2639
0
  y1 = y1A;
2640
0
  r1 = r1A;
2641
0
  t0 = t0A;
2642
0
  t1 = t1A;
2643
0
  nFuncs = nFuncsA;
2644
0
  for (i = 0; i < nFuncs; ++i) {
2645
0
    funcs[i] = funcsA[i];
2646
0
  }
2647
0
  extend0 = extend0A;
2648
0
  extend1 = extend1A;
2649
0
}
2650
2651
GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
2652
0
  GfxShading(shading)
2653
0
{
2654
0
  int i;
2655
2656
0
  x0 = shading->x0;
2657
0
  y0 = shading->y0;
2658
0
  r0 = shading->r0;
2659
0
  x1 = shading->x1;
2660
0
  y1 = shading->y1;
2661
0
  r1 = shading->r1;
2662
0
  t0 = shading->t0;
2663
0
  t1 = shading->t1;
2664
0
  nFuncs = shading->nFuncs;
2665
0
  for (i = 0; i < nFuncs; ++i) {
2666
0
    funcs[i] = shading->funcs[i]->copy();
2667
0
  }
2668
0
  extend0 = shading->extend0;
2669
0
  extend1 = shading->extend1;
2670
0
}
2671
2672
0
GfxRadialShading::~GfxRadialShading() {
2673
0
  int i;
2674
2675
0
  for (i = 0; i < nFuncs; ++i) {
2676
0
    delete funcs[i];
2677
0
  }
2678
0
}
2679
2680
GfxRadialShading *GfxRadialShading::parse(Dict *dict
2681
0
            ) {
2682
0
  GfxRadialShading *shading;
2683
0
  double x0A, y0A, r0A, x1A, y1A, r1A;
2684
0
  double t0A, t1A;
2685
0
  Function *funcsA[gfxColorMaxComps];
2686
0
  int nFuncsA;
2687
0
  GBool extend0A, extend1A, ok;
2688
0
  Object obj1, obj2;
2689
0
  int i;
2690
2691
0
  x0A = y0A = r0A = x1A = y1A = r1A = 0;
2692
0
  if (dict->lookup("Coords", &obj1)->isArray() &&
2693
0
      obj1.arrayGetLength() == 6) {
2694
0
    x0A = obj1.arrayGet(0, &obj2)->getNum();
2695
0
    obj2.free();
2696
0
    y0A = obj1.arrayGet(1, &obj2)->getNum();
2697
0
    obj2.free();
2698
0
    r0A = obj1.arrayGet(2, &obj2)->getNum();
2699
0
    obj2.free();
2700
0
    x1A = obj1.arrayGet(3, &obj2)->getNum();
2701
0
    obj2.free();
2702
0
    y1A = obj1.arrayGet(4, &obj2)->getNum();
2703
0
    obj2.free();
2704
0
    r1A = obj1.arrayGet(5, &obj2)->getNum();
2705
0
    obj2.free();
2706
0
  } else {
2707
0
    error(errSyntaxError, -1,
2708
0
    "Missing or invalid Coords in shading dictionary");
2709
0
    goto err1;
2710
0
  }
2711
0
  obj1.free();
2712
2713
0
  t0A = 0;
2714
0
  t1A = 1;
2715
0
  if (dict->lookup("Domain", &obj1)->isArray() &&
2716
0
      obj1.arrayGetLength() == 2) {
2717
0
    t0A = obj1.arrayGet(0, &obj2)->getNum();
2718
0
    obj2.free();
2719
0
    t1A = obj1.arrayGet(1, &obj2)->getNum();
2720
0
    obj2.free();
2721
0
  }
2722
0
  obj1.free();
2723
2724
0
  dict->lookup("Function", &obj1);
2725
0
  if (obj1.isArray()) {
2726
0
    nFuncsA = obj1.arrayGetLength();
2727
0
    if (nFuncsA > gfxColorMaxComps) {
2728
0
      error(errSyntaxError, -1,
2729
0
      "Invalid Function array in shading dictionary");
2730
0
      goto err1;
2731
0
    }
2732
0
    for (i = 0; i < nFuncsA; ++i) {
2733
0
      obj1.arrayGet(i, &obj2);
2734
0
      if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) {
2735
0
  obj1.free();
2736
0
  obj2.free();
2737
0
  goto err1;
2738
0
      }
2739
0
      obj2.free();
2740
0
    }
2741
0
  } else {
2742
0
    nFuncsA = 1;
2743
0
    if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) {
2744
0
      obj1.free();
2745
0
      goto err1;
2746
0
    }
2747
0
  }
2748
0
  obj1.free();
2749
2750
0
  extend0A = extend1A = gFalse;
2751
0
  if (dict->lookup("Extend", &obj1)->isArray() &&
2752
0
      obj1.arrayGetLength() == 2) {
2753
0
    extend0A = obj1.arrayGet(0, &obj2)->getBool();
2754
0
    obj2.free();
2755
0
    extend1A = obj1.arrayGet(1, &obj2)->getBool();
2756
0
    obj2.free();
2757
0
  }
2758
0
  obj1.free();
2759
2760
0
  shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
2761
0
         funcsA, nFuncsA, extend0A, extend1A);
2762
0
  if (!shading->init(dict
2763
0
         )) {
2764
0
    delete shading;
2765
0
    return NULL;
2766
0
  }
2767
2768
0
  ok = gFalse;
2769
0
  if (shading->nFuncs == 1) {
2770
0
    ok = shading->funcs[0]->getOutputSize()
2771
0
           == shading->getColorSpace()->getNComps();
2772
0
  } else if (shading->nFuncs == shading->getColorSpace()->getNComps()) {
2773
0
    ok = gTrue;
2774
0
    for (i = 0; i < shading->nFuncs; ++i) {
2775
0
      ok = ok && shading->funcs[i]->getOutputSize() == 1;
2776
0
    }
2777
0
  }
2778
0
  if (!ok) {
2779
0
    error(errSyntaxError, -1, "Invalid function in shading dictionary");
2780
0
    delete shading;
2781
0
    return NULL;
2782
0
  }
2783
2784
0
  return shading;
2785
2786
0
 err1:
2787
0
  return NULL;
2788
0
}
2789
2790
0
GfxShading *GfxRadialShading::copy() {
2791
0
  return new GfxRadialShading(this);
2792
0
}
2793
2794
0
void GfxRadialShading::getColor(double t, GfxColor *color) {
2795
0
  double out[gfxColorMaxComps];
2796
0
  int i;
2797
2798
  // NB: there can be one function with n outputs or n functions with
2799
  // one output each (where n = number of color components)
2800
0
  for (i = 0; i < gfxColorMaxComps; ++i) {
2801
0
    out[i] = 0;
2802
0
  }
2803
0
  for (i = 0; i < nFuncs; ++i) {
2804
0
    funcs[i]->transform(&t, &out[i]);
2805
0
  }
2806
0
  for (i = 0; i < gfxColorMaxComps; ++i) {
2807
0
    color->c[i] = dblToCol(out[i]);
2808
0
  }
2809
0
}
2810
2811
//------------------------------------------------------------------------
2812
// GfxShadingBitBuf
2813
//------------------------------------------------------------------------
2814
2815
class GfxShadingBitBuf {
2816
public:
2817
2818
  GfxShadingBitBuf(Stream *strA);
2819
  ~GfxShadingBitBuf();
2820
  GBool getBits(int n, Guint *val);
2821
  void flushBits();
2822
2823
private:
2824
2825
  Stream *str;
2826
  int bitBuf;
2827
  int nBits;
2828
};
2829
2830
709
GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) {
2831
709
  str = strA;
2832
709
  str->reset();
2833
709
  bitBuf = 0;
2834
709
  nBits = 0;
2835
709
}
2836
2837
709
GfxShadingBitBuf::~GfxShadingBitBuf() {
2838
709
  str->close();
2839
709
}
2840
2841
1.21M
GBool GfxShadingBitBuf::getBits(int n, Guint *val) {
2842
1.21M
  int x;
2843
2844
1.21M
  if (nBits >= n) {
2845
68
    x = (bitBuf >> (nBits - n)) & ((1 << n) - 1);
2846
68
    nBits -= n;
2847
1.21M
  } else {
2848
1.21M
    x = 0;
2849
1.21M
    if (nBits > 0) {
2850
2.45k
      x = bitBuf & ((1 << nBits) - 1);
2851
2.45k
      n -= nBits;
2852
2.45k
      nBits = 0;
2853
2.45k
    }
2854
4.41M
    while (n > 0) {
2855
3.21M
      if ((bitBuf = str->getChar()) == EOF) {
2856
709
  nBits = 0;
2857
709
  return gFalse;
2858
709
      }
2859
3.20M
      if (n >= 8) {
2860
3.20M
  x = (x << 8) | bitBuf;
2861
3.20M
  n -= 8;
2862
3.20M
      } else {
2863
2.51k
  x = (x << n) | (bitBuf >> (8 - n));
2864
2.51k
  nBits = 8 - n;
2865
2.51k
  n = 0;
2866
2.51k
      }
2867
3.20M
    }
2868
1.21M
  }
2869
1.20M
  *val = x;
2870
1.20M
  return gTrue;
2871
1.21M
}
2872
2873
208k
void GfxShadingBitBuf::flushBits() {
2874
208k
  bitBuf = 0;
2875
208k
  nBits = 0;
2876
208k
}
2877
2878
//------------------------------------------------------------------------
2879
// GfxGouraudTriangleShading
2880
//------------------------------------------------------------------------
2881
2882
GfxGouraudTriangleShading::GfxGouraudTriangleShading(
2883
             int typeA,
2884
             GfxGouraudVertex *verticesA, int nVerticesA,
2885
             int (*trianglesA)[3], int nTrianglesA,
2886
             int nCompsA, Function **funcsA, int nFuncsA):
2887
277
  GfxShading(typeA)
2888
277
{
2889
277
  int i;
2890
2891
277
  vertices = verticesA;
2892
277
  nVertices = nVerticesA;
2893
277
  triangles = trianglesA;
2894
277
  nTriangles = nTrianglesA;
2895
277
  nComps = nCompsA;
2896
277
  nFuncs = nFuncsA;
2897
530
  for (i = 0; i < nFuncs; ++i) {
2898
253
    funcs[i] = funcsA[i];
2899
253
  }
2900
277
}
2901
2902
GfxGouraudTriangleShading::GfxGouraudTriangleShading(
2903
             GfxGouraudTriangleShading *shading):
2904
249
  GfxShading(shading)
2905
249
{
2906
249
  int i;
2907
2908
249
  nVertices = shading->nVertices;
2909
249
  vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex));
2910
249
  memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex));
2911
249
  nTriangles = shading->nTriangles;
2912
249
  triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int));
2913
249
  memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int));
2914
249
  nComps = shading->nComps;
2915
249
  nFuncs = shading->nFuncs;
2916
498
  for (i = 0; i < nFuncs; ++i) {
2917
249
    funcs[i] = shading->funcs[i]->copy();
2918
249
  }
2919
249
}
2920
2921
508
GfxGouraudTriangleShading::~GfxGouraudTriangleShading() {
2922
508
  int i;
2923
2924
508
  gfree(vertices);
2925
508
  gfree(triangles);
2926
992
  for (i = 0; i < nFuncs; ++i) {
2927
484
    delete funcs[i];
2928
484
  }
2929
508
}
2930
2931
GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(
2932
             int typeA, Dict *dict, Stream *str
2933
351
             ) {
2934
351
  GfxGouraudTriangleShading *shading;
2935
351
  Function *funcsA[gfxColorMaxComps];
2936
351
  int nFuncsA;
2937
351
  int coordBits, compBits, flagBits, vertsPerRow, nRows;
2938
351
  double xMin, xMax, yMin, yMax;
2939
351
  double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
2940
351
  double xMul, yMul;
2941
351
  double cMul[gfxColorMaxComps];
2942
351
  GfxGouraudVertex *verticesA;
2943
351
  int (*trianglesA)[3];
2944
351
  int nCompsA, nVerticesA, nTrianglesA, vertSize, triSize;
2945
351
  Guint x, y, flag;
2946
351
  Guint c[gfxColorMaxComps];
2947
351
  GfxShadingBitBuf *bitBuf;
2948
351
  Object obj1, obj2;
2949
351
  GBool ok;
2950
351
  int i, j, k, state;
2951
2952
351
  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
2953
351
    coordBits = obj1.getInt();
2954
351
  } else {
2955
0
    error(errSyntaxError, -1,
2956
0
    "Missing or invalid BitsPerCoordinate in shading dictionary");
2957
0
    goto err2;
2958
0
  }
2959
351
  if (coordBits <= 0 || coordBits > 32) {
2960
0
    error(errSyntaxError, -1,
2961
0
    "Invalid BitsPerCoordinate in shading dictionary");
2962
0
    goto err2;
2963
0
  }
2964
351
  obj1.free();
2965
351
  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
2966
351
    compBits = obj1.getInt();
2967
351
  } else {
2968
0
    error(errSyntaxError, -1,
2969
0
    "Missing or invalid BitsPerComponent in shading dictionary");
2970
0
    goto err2;
2971
0
  }
2972
351
  if (compBits <= 0 || compBits > 16) {
2973
0
    error(errSyntaxError, -1,
2974
0
    "Invalid BitsPerComponent in shading dictionary");
2975
0
    goto err2;
2976
0
  }
2977
351
  obj1.free();
2978
351
  flagBits = vertsPerRow = 0; // make gcc happy
2979
351
  if (typeA == 4) {
2980
33
    if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
2981
33
      flagBits = obj1.getInt();
2982
33
    } else {
2983
0
      error(errSyntaxError, -1,
2984
0
      "Missing or invalid BitsPerFlag in shading dictionary");
2985
0
      goto err2;
2986
0
    }
2987
33
    if (flagBits < 2 || flagBits > 8) {
2988
9
      error(errSyntaxError, -1, "Invalid BitsPerFlag in shading dictionary");
2989
9
      goto err2;
2990
9
    }
2991
24
    obj1.free();
2992
318
  } else {
2993
318
    if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
2994
315
      vertsPerRow = obj1.getInt();
2995
315
    } else {
2996
3
      error(errSyntaxError, -1,
2997
3
      "Missing or invalid VerticesPerRow in shading dictionary");
2998
3
      goto err2;
2999
3
    }
3000
315
    obj1.free();
3001
315
    if (vertsPerRow < 2) {
3002
5
      error(errSyntaxError, -1,
3003
5
      "Invalid VerticesPerRow in shading dictionary");
3004
5
      goto err2;
3005
5
    }
3006
315
  }
3007
334
  if (dict->lookup("Decode", &obj1)->isArray() &&
3008
329
      obj1.arrayGetLength() >= 6) {
3009
329
    xMin = obj1.arrayGet(0, &obj2)->getNum();
3010
329
    obj2.free();
3011
329
    xMax = obj1.arrayGet(1, &obj2)->getNum();
3012
329
    obj2.free();
3013
329
    xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
3014
329
    yMin = obj1.arrayGet(2, &obj2)->getNum();
3015
329
    obj2.free();
3016
329
    yMax = obj1.arrayGet(3, &obj2)->getNum();
3017
329
    obj2.free();
3018
329
    yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
3019
1.00k
    for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
3020
678
      cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
3021
678
      obj2.free();
3022
678
      cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
3023
678
      obj2.free();
3024
678
      cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
3025
678
    }
3026
329
    nCompsA = i;
3027
329
  } else {
3028
5
    error(errSyntaxError, -1,
3029
5
    "Missing or invalid Decode array in shading dictionary");
3030
5
    goto err2;
3031
5
  }
3032
329
  obj1.free();
3033
3034
329
  if (!dict->lookup("Function", &obj1)->isNull()) {
3035
305
    if (obj1.isArray()) {
3036
0
      nFuncsA = obj1.arrayGetLength();
3037
0
      if (nFuncsA > gfxColorMaxComps) {
3038
0
  error(errSyntaxError, -1,
3039
0
        "Invalid Function array in shading dictionary");
3040
0
  goto err1;
3041
0
      }
3042
0
      for (i = 0; i < nFuncsA; ++i) {
3043
0
  obj1.arrayGet(i, &obj2);
3044
0
  if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) {
3045
0
    obj1.free();
3046
0
    obj2.free();
3047
0
    goto err1;
3048
0
  }
3049
0
  obj2.free();
3050
0
      }
3051
305
    } else {
3052
305
      nFuncsA = 1;
3053
305
      if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) {
3054
42
  obj1.free();
3055
42
  goto err1;
3056
42
      }
3057
305
    }
3058
305
  } else {
3059
24
    nFuncsA = 0;
3060
24
  }
3061
287
  obj1.free();
3062
3063
287
  nVerticesA = nTrianglesA = 0;
3064
287
  verticesA = NULL;
3065
287
  trianglesA = NULL;
3066
287
  vertSize = triSize = 0;
3067
287
  state = 0;
3068
287
  flag = 0; // make gcc happy
3069
287
  bitBuf = new GfxShadingBitBuf(str);
3070
199k
  while (1) {
3071
199k
    if (typeA == 4) {
3072
10.6k
      if (!bitBuf->getBits(flagBits, &flag)) {
3073
0
  break;
3074
0
      }
3075
10.6k
    }
3076
199k
    if (!bitBuf->getBits(coordBits, &x) ||
3077
198k
  !bitBuf->getBits(coordBits, &y)) {
3078
203
      break;
3079
203
    }
3080
612k
    for (i = 0; i < nCompsA; ++i) {
3081
413k
      if (!bitBuf->getBits(compBits, &c[i])) {
3082
84
  break;
3083
84
      }
3084
413k
    }
3085
198k
    if (i < nCompsA) {
3086
84
      break;
3087
84
    }
3088
198k
    if (nVerticesA == vertSize) {
3089
1.54k
      vertSize = (vertSize == 0) ? 16 : 2 * vertSize;
3090
1.54k
      verticesA = (GfxGouraudVertex *)
3091
1.54k
                greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex));
3092
1.54k
    }
3093
198k
    verticesA[nVerticesA].x = xMin + xMul * (double)x;
3094
198k
    verticesA[nVerticesA].y = yMin + yMul * (double)y;
3095
612k
    for (i = 0; i < nCompsA; ++i) {
3096
413k
      verticesA[nVerticesA].color[i] = cMin[i] + cMul[i] * (double)c[i];
3097
413k
    }
3098
198k
    ++nVerticesA;
3099
198k
    bitBuf->flushBits();
3100
198k
    if (typeA == 4) {
3101
10.5k
      if (state == 0 || state == 1) {
3102
192
  ++state;
3103
10.3k
      } else if (state == 2 || flag > 0) {
3104
10.2k
  if (nTrianglesA == triSize) {
3105
144
    triSize = (triSize == 0) ? 16 : 2 * triSize;
3106
144
    trianglesA = (int (*)[3])
3107
144
                     greallocn(trianglesA, triSize * 3, sizeof(int));
3108
144
  }
3109
10.2k
  if (state == 2) {
3110
168
    trianglesA[nTrianglesA][0] = nVerticesA - 3;
3111
168
    trianglesA[nTrianglesA][1] = nVerticesA - 2;
3112
168
    trianglesA[nTrianglesA][2] = nVerticesA - 1;
3113
168
    ++state;
3114
10.0k
  } else if (flag == 1) {
3115
168
    trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1];
3116
168
    trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
3117
168
    trianglesA[nTrianglesA][2] = nVerticesA - 1;
3118
9.91k
  } else { // flag == 2
3119
9.91k
    trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0];
3120
9.91k
    trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
3121
9.91k
    trianglesA[nTrianglesA][2] = nVerticesA - 1;
3122
9.91k
  }
3123
10.2k
  ++nTrianglesA;
3124
10.2k
      } else { // state == 3 && flag == 0
3125
144
  state = 1;
3126
144
      }
3127
10.5k
    }
3128
198k
  }
3129
287
  delete bitBuf;
3130
287
  if (typeA == 5) {
3131
263
    nRows = nVerticesA / vertsPerRow;
3132
263
    if (nRows == 0) {
3133
10
      error(errSyntaxError, -1,
3134
10
      "Invalid VerticesPerRow in shading dictionary");
3135
10
      goto err3;
3136
10
    }
3137
253
    nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1);
3138
253
    trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int));
3139
253
    k = 0;
3140
11.6k
    for (i = 0; i < nRows - 1; ++i) {
3141
182k
      for (j = 0; j < vertsPerRow - 1; ++j) {
3142
171k
  trianglesA[k][0] = i * vertsPerRow + j;
3143
171k
  trianglesA[k][1] = i * vertsPerRow + j+1;
3144
171k
  trianglesA[k][2] = (i+1) * vertsPerRow + j;
3145
171k
  ++k;
3146
171k
  trianglesA[k][0] = i * vertsPerRow + j+1;
3147
171k
  trianglesA[k][1] = (i+1) * vertsPerRow + j;
3148
171k
  trianglesA[k][2] = (i+1) * vertsPerRow + j+1;
3149
171k
  ++k;
3150
171k
      }
3151
11.4k
    }
3152
253
  }
3153
3154
277
  shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA,
3155
277
            trianglesA, nTrianglesA,
3156
277
            nCompsA, funcsA, nFuncsA);
3157
277
  if (!shading->init(dict
3158
277
         )) {
3159
0
    delete shading;
3160
0
    return NULL;
3161
0
  }
3162
3163
277
  ok = gFalse;
3164
277
  if (shading->nFuncs == 0) {
3165
24
    ok = shading->nComps == shading->getColorSpace()->getNComps();
3166
253
  } else if (shading->nFuncs == 1) {
3167
253
    ok = shading->funcs[0]->getOutputSize()
3168
253
           == shading->getColorSpace()->getNComps();
3169
253
  } else if (shading->nFuncs == shading->getColorSpace()->getNComps()) {
3170
0
    ok = gTrue;
3171
0
    for (i = 0; i < shading->nFuncs; ++i) {
3172
0
      ok = ok && shading->funcs[i]->getOutputSize() == 1;
3173
0
    }
3174
0
  }
3175
277
  if (!ok) {
3176
0
    error(errSyntaxError, -1, "Invalid function in shading dictionary");
3177
0
    delete shading;
3178
0
    return NULL;
3179
0
  }
3180
3181
277
  return shading;
3182
3183
10
 err3:
3184
10
  gfree(trianglesA);
3185
10
  gfree(verticesA);
3186
20
  for (i = 0; i < nFuncsA; ++i) {
3187
10
    delete funcsA[i];
3188
10
  }
3189
32
 err2:
3190
32
  obj1.free();
3191
74
 err1:
3192
74
  return NULL;
3193
32
}
3194
3195
249
GfxShading *GfxGouraudTriangleShading::copy() {
3196
249
  return new GfxGouraudTriangleShading(this);
3197
249
}
3198
3199
void GfxGouraudTriangleShading::getTriangle(
3200
            int i,
3201
            double *x0, double *y0, double *color0,
3202
            double *x1, double *y1, double *color1,
3203
284k
            double *x2, double *y2, double *color2) {
3204
284k
  int v, j;
3205
3206
284k
  v = triangles[i][0];
3207
284k
  *x0 = vertices[v].x;
3208
284k
  *y0 = vertices[v].y;
3209
845k
  for (j = 0; j < nComps; ++j) {
3210
560k
    color0[j] = vertices[v].color[j];
3211
560k
  }
3212
284k
  v = triangles[i][1];
3213
284k
  *x1 = vertices[v].x;
3214
284k
  *y1 = vertices[v].y;
3215
845k
  for (j = 0; j < nComps; ++j) {
3216
560k
    color1[j] = vertices[v].color[j];
3217
560k
  }
3218
284k
  v = triangles[i][2];
3219
284k
  *x2 = vertices[v].x;
3220
284k
  *y2 = vertices[v].y;
3221
845k
  for (j = 0; j < nComps; ++j) {
3222
560k
    color2[j] = vertices[v].color[j];
3223
560k
  }
3224
284k
}
3225
3226
void GfxGouraudTriangleShading::getBBox(double *xMinA, double *yMinA,
3227
246
          double *xMaxA, double *yMaxA) {
3228
246
  double xxMin = 0;
3229
246
  double yyMin = 0;
3230
246
  double xxMax = 0;
3231
246
  double yyMax = 0;
3232
246
  if (nVertices > 0) {
3233
246
    xxMin = xxMax = vertices[0].x;
3234
246
    yyMin = yyMax = vertices[0].y;
3235
246
  }
3236
182k
  for (int i = 1; i < nVertices; ++i) {
3237
181k
    if (vertices[i].x < xxMin) {
3238
1.29k
      xxMin = vertices[i].x;
3239
180k
    } else if (vertices[i].x > xxMax) {
3240
708
      xxMax = vertices[i].x;
3241
708
    }
3242
181k
    if (vertices[i].y < yyMin) {
3243
399
      yyMin = vertices[i].y;
3244
181k
    } else if (vertices[i].y > yyMax) {
3245
646
      yyMax = vertices[i].y;
3246
646
    }
3247
181k
  }
3248
246
  *xMinA = xxMin;
3249
246
  *yMinA = yyMin;
3250
246
  *xMaxA = xxMax;
3251
246
  *yMaxA = yyMax;
3252
246
}
3253
3254
76.5k
void GfxGouraudTriangleShading::getColor(double *in, GfxColor *out) {
3255
76.5k
  double c[gfxColorMaxComps];
3256
76.5k
  int i;
3257
3258
76.5k
  if (nFuncs > 0) {
3259
153k
    for (i = 0; i < nFuncs; ++i) {
3260
76.5k
      funcs[i]->transform(in, &c[i]);
3261
76.5k
    }
3262
306k
    for (i = 0; i < colorSpace->getNComps(); ++i) {
3263
229k
      out->c[i] = dblToCol(c[i]);
3264
229k
    }
3265
76.5k
  } else {
3266
0
    for (i = 0; i < nComps; ++i) {
3267
0
      out->c[i] = dblToCol(in[i]);
3268
0
    }
3269
0
  }
3270
76.5k
}
3271
3272
//------------------------------------------------------------------------
3273
// GfxPatchMeshShading
3274
//------------------------------------------------------------------------
3275
3276
GfxPatchMeshShading::GfxPatchMeshShading(int typeA,
3277
           GfxPatch *patchesA, int nPatchesA,
3278
           int nCompsA,
3279
           Function **funcsA, int nFuncsA):
3280
422
  GfxShading(typeA)
3281
422
{
3282
422
  int i;
3283
3284
422
  patches = patchesA;
3285
422
  nPatches = nPatchesA;
3286
422
  nComps = nCompsA;
3287
422
  nFuncs = nFuncsA;
3288
422
  for (i = 0; i < nFuncs; ++i) {
3289
0
    funcs[i] = funcsA[i];
3290
0
  }
3291
422
}
3292
3293
GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading):
3294
0
  GfxShading(shading)
3295
0
{
3296
0
  int i;
3297
3298
0
  nPatches = shading->nPatches;
3299
0
  patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch));
3300
0
  memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch));
3301
0
  nComps = shading->nComps;
3302
0
  nFuncs = shading->nFuncs;
3303
0
  for (i = 0; i < nFuncs; ++i) {
3304
0
    funcs[i] = shading->funcs[i]->copy();
3305
0
  }
3306
0
}
3307
3308
416
GfxPatchMeshShading::~GfxPatchMeshShading() {
3309
416
  int i;
3310
3311
416
  gfree(patches);
3312
416
  for (i = 0; i < nFuncs; ++i) {
3313
0
    delete funcs[i];
3314
0
  }
3315
416
}
3316
3317
GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict,
3318
            Stream *str
3319
474
            ) {
3320
474
  GfxPatchMeshShading *shading;
3321
474
  Function *funcsA[gfxColorMaxComps];
3322
474
  int nFuncsA;
3323
474
  int coordBits, compBits, flagBits;
3324
474
  double xMin, xMax, yMin, yMax;
3325
474
  double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
3326
474
  double xMul, yMul;
3327
474
  double cMul[gfxColorMaxComps];
3328
474
  GfxPatch *patchesA, *p;
3329
474
  int nCompsA, nPatchesA, patchesSize, nPts, nColors;
3330
474
  Guint flag;
3331
474
  double x[16], y[16];
3332
474
  Guint xi, yi;
3333
474
  double c[4][gfxColorMaxComps];
3334
474
  Guint ci;
3335
474
  GfxShadingBitBuf *bitBuf;
3336
474
  Object obj1, obj2;
3337
474
  GBool ok;
3338
474
  int i, j;
3339
3340
474
  nPatchesA = 0;
3341
474
  patchesA = NULL;
3342
474
  patchesSize = 0;
3343
3344
474
  if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
3345
473
    coordBits = obj1.getInt();
3346
473
  } else {
3347
1
    error(errSyntaxError, -1,
3348
1
    "Missing or invalid BitsPerCoordinate in shading dictionary");
3349
1
    goto err2;
3350
1
  }
3351
473
  if (coordBits <= 0 || coordBits > 32) {
3352
3
    error(errSyntaxError, -1,
3353
3
    "Invalid BitsPerCoordinate in shading dictionary");
3354
3
    goto err2;
3355
3
  }
3356
470
  obj1.free();
3357
470
  if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
3358
470
    compBits = obj1.getInt();
3359
470
  } else {
3360
0
    error(errSyntaxError, -1,
3361
0
    "Missing or invalid BitsPerComponent in shading dictionary");
3362
0
    goto err2;
3363
0
  }
3364
470
  if (compBits <= 0 || compBits > 16) {
3365
17
    error(errSyntaxError, -1,
3366
17
    "Invalid BitsPerComponent in shading dictionary");
3367
17
    goto err2;
3368
17
  }
3369
453
  obj1.free();
3370
453
  if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
3371
447
    flagBits = obj1.getInt();
3372
447
  } else {
3373
6
    error(errSyntaxError, -1,
3374
6
    "Missing or invalid BitsPerFlag in shading dictionary");
3375
6
    goto err2;
3376
6
  }
3377
447
  if (flagBits < 2 || flagBits > 8) {
3378
18
    error(errSyntaxError, -1, "Invalid BitsPerFlag in shading dictionary");
3379
18
    goto err2;
3380
18
  }
3381
429
  obj1.free();
3382
429
  if (dict->lookup("Decode", &obj1)->isArray() &&
3383
429
      obj1.arrayGetLength() >= 6) {
3384
422
    xMin = obj1.arrayGet(0, &obj2)->getNum();
3385
422
    obj2.free();
3386
422
    xMax = obj1.arrayGet(1, &obj2)->getNum();
3387
422
    obj2.free();
3388
422
    xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
3389
422
    yMin = obj1.arrayGet(2, &obj2)->getNum();
3390
422
    obj2.free();
3391
422
    yMax = obj1.arrayGet(3, &obj2)->getNum();
3392
422
    obj2.free();
3393
422
    yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
3394
2.11k
    for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
3395
1.68k
      cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
3396
1.68k
      obj2.free();
3397
1.68k
      cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
3398
1.68k
      obj2.free();
3399
1.68k
      cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
3400
1.68k
    }
3401
422
    nCompsA = i;
3402
422
  } else {
3403
7
    error(errSyntaxError, -1,
3404
7
    "Missing or invalid Decode array in shading dictionary");
3405
7
    goto err2;
3406
7
  }
3407
422
  obj1.free();
3408
3409
422
  if (!dict->lookup("Function", &obj1)->isNull()) {
3410
0
    if (obj1.isArray()) {
3411
0
      nFuncsA = obj1.arrayGetLength();
3412
0
      if (nFuncsA > gfxColorMaxComps) {
3413
0
  error(errSyntaxError, -1,
3414
0
        "Invalid Function array in shading dictionary");
3415
0
  goto err1;
3416
0
      }
3417
0
      for (i = 0; i < nFuncsA; ++i) {
3418
0
  obj1.arrayGet(i, &obj2);
3419
0
  if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) {
3420
0
    obj1.free();
3421
0
    obj2.free();
3422
0
    goto err1;
3423
0
  }
3424
0
  obj2.free();
3425
0
      }
3426
0
    } else {
3427
0
      nFuncsA = 1;
3428
0
      if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) {
3429
0
  obj1.free();
3430
0
  goto err1;
3431
0
      }
3432
0
    }
3433
422
  } else {
3434
422
    nFuncsA = 0;
3435
422
  }
3436
422
  obj1.free();
3437
3438
422
  bitBuf = new GfxShadingBitBuf(str);
3439
10.2k
  while (1) {
3440
10.2k
    if (!bitBuf->getBits(flagBits, &flag)) {
3441
16
      break;
3442
16
    }
3443
10.2k
    flag &= 3;
3444
10.2k
    if (flag != 0 && nPatchesA == 0) {
3445
0
      error(errSyntaxError, -1, "Invalid patch in patch mesh shading");
3446
0
      delete bitBuf;
3447
0
      goto err1;
3448
0
    }
3449
10.2k
    if (typeA == 6) {
3450
0
      switch (flag) {
3451
0
      case 0: nPts = 12; nColors = 4; break;
3452
0
      case 1:
3453
0
      case 2:
3454
0
      case 3:
3455
0
      default: nPts =  8; nColors = 2; break;
3456
0
      }
3457
10.2k
    } else {
3458
10.2k
      switch (flag) {
3459
3.75k
      case 0: nPts = 16; nColors = 4; break;
3460
2.61k
      case 1:
3461
4.23k
      case 2:
3462
6.44k
      case 3:
3463
6.44k
      default: nPts = 12; nColors = 2; break;
3464
10.2k
      }
3465
10.2k
    }
3466
145k
    for (i = 0; i < nPts; ++i) {
3467
135k
      if (!bitBuf->getBits(coordBits, &xi) ||
3468
135k
    !bitBuf->getBits(coordBits, &yi)) {
3469
384
  break;
3470
384
      }
3471
135k
      x[i] = xMin + xMul * (double)xi;
3472
135k
      y[i] = yMin + yMul * (double)yi;
3473
135k
    }
3474
10.2k
    if (i < nPts) {
3475
384
      break;
3476
384
    }
3477
36.5k
    for (i = 0; i < nColors; ++i) {
3478
133k
      for (j = 0; j < nCompsA; ++j) {
3479
106k
  if (!bitBuf->getBits(compBits, &ci)) {
3480
22
    break;
3481
22
  }
3482
106k
  c[i][j] = cMin[j] + cMul[j] * (double)ci;
3483
106k
      }
3484
26.7k
      if (j < nCompsA) {
3485
22
  break;
3486
22
      }
3487
26.7k
    }
3488
9.82k
    if (i < nColors) {
3489
22
      break;
3490
22
    }
3491
9.80k
    if (nPatchesA == patchesSize) {
3492
795
      patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize;
3493
795
      patchesA = (GfxPatch *)greallocn(patchesA,
3494
795
               patchesSize, sizeof(GfxPatch));
3495
795
    }
3496
9.80k
    p = &patchesA[nPatchesA];
3497
9.80k
    if (typeA == 6) {
3498
0
      switch (flag) {
3499
0
      case 0:
3500
0
  p->x[0][0] = x[0];
3501
0
  p->y[0][0] = y[0];
3502
0
  p->x[0][1] = x[1];
3503
0
  p->y[0][1] = y[1];
3504
0
  p->x[0][2] = x[2];
3505
0
  p->y[0][2] = y[2];
3506
0
  p->x[0][3] = x[3];
3507
0
  p->y[0][3] = y[3];
3508
0
  p->x[1][3] = x[4];
3509
0
  p->y[1][3] = y[4];
3510
0
  p->x[2][3] = x[5];
3511
0
  p->y[2][3] = y[5];
3512
0
  p->x[3][3] = x[6];
3513
0
  p->y[3][3] = y[6];
3514
0
  p->x[3][2] = x[7];
3515
0
  p->y[3][2] = y[7];
3516
0
  p->x[3][1] = x[8];
3517
0
  p->y[3][1] = y[8];
3518
0
  p->x[3][0] = x[9];
3519
0
  p->y[3][0] = y[9];
3520
0
  p->x[2][0] = x[10];
3521
0
  p->y[2][0] = y[10];
3522
0
  p->x[1][0] = x[11];
3523
0
  p->y[1][0] = y[11];
3524
0
  for (j = 0; j < nCompsA; ++j) {
3525
0
    p->color[0][0][j] = c[0][j];
3526
0
    p->color[0][1][j] = c[1][j];
3527
0
    p->color[1][1][j] = c[2][j];
3528
0
    p->color[1][0][j] = c[3][j];
3529
0
  }
3530
0
  break;
3531
0
      case 1:
3532
0
  p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
3533
0
  p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
3534
0
  p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
3535
0
  p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
3536
0
  p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
3537
0
  p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
3538
0
  p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
3539
0
  p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
3540
0
  p->x[1][3] = x[0];
3541
0
  p->y[1][3] = y[0];
3542
0
  p->x[2][3] = x[1];
3543
0
  p->y[2][3] = y[1];
3544
0
  p->x[3][3] = x[2];
3545
0
  p->y[3][3] = y[2];
3546
0
  p->x[3][2] = x[3];
3547
0
  p->y[3][2] = y[3];
3548
0
  p->x[3][1] = x[4];
3549
0
  p->y[3][1] = y[4];
3550
0
  p->x[3][0] = x[5];
3551
0
  p->y[3][0] = y[5];
3552
0
  p->x[2][0] = x[6];
3553
0
  p->y[2][0] = y[6];
3554
0
  p->x[1][0] = x[7];
3555
0
  p->y[1][0] = y[7];
3556
0
  for (j = 0; j < nCompsA; ++j) {
3557
0
    p->color[0][0][j] = patchesA[nPatchesA-1].color[0][1][j];
3558
0
    p->color[0][1][j] = patchesA[nPatchesA-1].color[1][1][j];
3559
0
    p->color[1][1][j] = c[0][j];
3560
0
    p->color[1][0][j] = c[1][j];
3561
0
  }
3562
0
  break;
3563
0
      case 2:
3564
0
  p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
3565
0
  p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
3566
0
  p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
3567
0
  p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
3568
0
  p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
3569
0
  p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
3570
0
  p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
3571
0
  p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
3572
0
  p->x[1][3] = x[0];
3573
0
  p->y[1][3] = y[0];
3574
0
  p->x[2][3] = x[1];
3575
0
  p->y[2][3] = y[1];
3576
0
  p->x[3][3] = x[2];
3577
0
  p->y[3][3] = y[2];
3578
0
  p->x[3][2] = x[3];
3579
0
  p->y[3][2] = y[3];
3580
0
  p->x[3][1] = x[4];
3581
0
  p->y[3][1] = y[4];
3582
0
  p->x[3][0] = x[5];
3583
0
  p->y[3][0] = y[5];
3584
0
  p->x[2][0] = x[6];
3585
0
  p->y[2][0] = y[6];
3586
0
  p->x[1][0] = x[7];
3587
0
  p->y[1][0] = y[7];
3588
0
  for (j = 0; j < nCompsA; ++j) {
3589
0
    p->color[0][0][j] = patchesA[nPatchesA-1].color[1][1][j];
3590
0
    p->color[0][1][j] = patchesA[nPatchesA-1].color[1][0][j];
3591
0
    p->color[1][1][j] = c[0][j];
3592
0
    p->color[1][0][j] = c[1][j];
3593
0
  }
3594
0
  break;
3595
0
      case 3:
3596
0
  p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
3597
0
  p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
3598
0
  p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
3599
0
  p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
3600
0
  p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
3601
0
  p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
3602
0
  p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
3603
0
  p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
3604
0
  p->x[1][3] = x[0];
3605
0
  p->y[1][3] = y[0];
3606
0
  p->x[2][3] = x[1];
3607
0
  p->y[2][3] = y[1];
3608
0
  p->x[3][3] = x[2];
3609
0
  p->y[3][3] = y[2];
3610
0
  p->x[3][2] = x[3];
3611
0
  p->y[3][2] = y[3];
3612
0
  p->x[3][1] = x[4];
3613
0
  p->y[3][1] = y[4];
3614
0
  p->x[3][0] = x[5];
3615
0
  p->y[3][0] = y[5];
3616
0
  p->x[2][0] = x[6];
3617
0
  p->y[2][0] = y[6];
3618
0
  p->x[1][0] = x[7];
3619
0
  p->y[1][0] = y[7];
3620
0
  for (j = 0; j < nCompsA; ++j) {
3621
0
    p->color[0][0][j] = patchesA[nPatchesA-1].color[1][0][j];
3622
0
    p->color[0][1][j] = patchesA[nPatchesA-1].color[0][0][j];
3623
0
    p->color[1][1][j] = c[0][j];
3624
0
    p->color[1][0][j] = c[1][j];
3625
0
  }
3626
0
  break;
3627
0
      }
3628
9.80k
    } else {
3629
9.80k
      switch (flag) {
3630
3.54k
      case 0:
3631
3.54k
  p->x[0][0] = x[0];
3632
3.54k
  p->y[0][0] = y[0];
3633
3.54k
  p->x[0][1] = x[1];
3634
3.54k
  p->y[0][1] = y[1];
3635
3.54k
  p->x[0][2] = x[2];
3636
3.54k
  p->y[0][2] = y[2];
3637
3.54k
  p->x[0][3] = x[3];
3638
3.54k
  p->y[0][3] = y[3];
3639
3.54k
  p->x[1][3] = x[4];
3640
3.54k
  p->y[1][3] = y[4];
3641
3.54k
  p->x[2][3] = x[5];
3642
3.54k
  p->y[2][3] = y[5];
3643
3.54k
  p->x[3][3] = x[6];
3644
3.54k
  p->y[3][3] = y[6];
3645
3.54k
  p->x[3][2] = x[7];
3646
3.54k
  p->y[3][2] = y[7];
3647
3.54k
  p->x[3][1] = x[8];
3648
3.54k
  p->y[3][1] = y[8];
3649
3.54k
  p->x[3][0] = x[9];
3650
3.54k
  p->y[3][0] = y[9];
3651
3.54k
  p->x[2][0] = x[10];
3652
3.54k
  p->y[2][0] = y[10];
3653
3.54k
  p->x[1][0] = x[11];
3654
3.54k
  p->y[1][0] = y[11];
3655
3.54k
  p->x[1][1] = x[12];
3656
3.54k
  p->y[1][1] = y[12];
3657
3.54k
  p->x[1][2] = x[13];
3658
3.54k
  p->y[1][2] = y[13];
3659
3.54k
  p->x[2][2] = x[14];
3660
3.54k
  p->y[2][2] = y[14];
3661
3.54k
  p->x[2][1] = x[15];
3662
3.54k
  p->y[2][1] = y[15];
3663
17.7k
  for (j = 0; j < nCompsA; ++j) {
3664
14.1k
    p->color[0][0][j] = c[0][j];
3665
14.1k
    p->color[0][1][j] = c[1][j];
3666
14.1k
    p->color[1][1][j] = c[2][j];
3667
14.1k
    p->color[1][0][j] = c[3][j];
3668
14.1k
  }
3669
3.54k
  break;
3670
2.53k
      case 1:
3671
2.53k
  p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
3672
2.53k
  p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
3673
2.53k
  p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
3674
2.53k
  p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
3675
2.53k
  p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
3676
2.53k
  p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
3677
2.53k
  p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
3678
2.53k
  p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
3679
2.53k
  p->x[1][3] = x[0];
3680
2.53k
  p->y[1][3] = y[0];
3681
2.53k
  p->x[2][3] = x[1];
3682
2.53k
  p->y[2][3] = y[1];
3683
2.53k
  p->x[3][3] = x[2];
3684
2.53k
  p->y[3][3] = y[2];
3685
2.53k
  p->x[3][2] = x[3];
3686
2.53k
  p->y[3][2] = y[3];
3687
2.53k
  p->x[3][1] = x[4];
3688
2.53k
  p->y[3][1] = y[4];
3689
2.53k
  p->x[3][0] = x[5];
3690
2.53k
  p->y[3][0] = y[5];
3691
2.53k
  p->x[2][0] = x[6];
3692
2.53k
  p->y[2][0] = y[6];
3693
2.53k
  p->x[1][0] = x[7];
3694
2.53k
  p->y[1][0] = y[7];
3695
2.53k
  p->x[1][1] = x[8];
3696
2.53k
  p->y[1][1] = y[8];
3697
2.53k
  p->x[1][2] = x[9];
3698
2.53k
  p->y[1][2] = y[9];
3699
2.53k
  p->x[2][2] = x[10];
3700
2.53k
  p->y[2][2] = y[10];
3701
2.53k
  p->x[2][1] = x[11];
3702
2.53k
  p->y[2][1] = y[11];
3703
12.6k
  for (j = 0; j < nCompsA; ++j) {
3704
10.1k
    p->color[0][0][j] = patchesA[nPatchesA-1].color[0][1][j];
3705
10.1k
    p->color[0][1][j] = patchesA[nPatchesA-1].color[1][1][j];
3706
10.1k
    p->color[1][1][j] = c[0][j];
3707
10.1k
    p->color[1][0][j] = c[1][j];
3708
10.1k
  }
3709
2.53k
  break;
3710
1.57k
      case 2:
3711
1.57k
  p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
3712
1.57k
  p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
3713
1.57k
  p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
3714
1.57k
  p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
3715
1.57k
  p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
3716
1.57k
  p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
3717
1.57k
  p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
3718
1.57k
  p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
3719
1.57k
  p->x[1][3] = x[0];
3720
1.57k
  p->y[1][3] = y[0];
3721
1.57k
  p->x[2][3] = x[1];
3722
1.57k
  p->y[2][3] = y[1];
3723
1.57k
  p->x[3][3] = x[2];
3724
1.57k
  p->y[3][3] = y[2];
3725
1.57k
  p->x[3][2] = x[3];
3726
1.57k
  p->y[3][2] = y[3];
3727
1.57k
  p->x[3][1] = x[4];
3728
1.57k
  p->y[3][1] = y[4];
3729
1.57k
  p->x[3][0] = x[5];
3730
1.57k
  p->y[3][0] = y[5];
3731
1.57k
  p->x[2][0] = x[6];
3732
1.57k
  p->y[2][0] = y[6];
3733
1.57k
  p->x[1][0] = x[7];
3734
1.57k
  p->y[1][0] = y[7];
3735
1.57k
  p->x[1][1] = x[8];
3736
1.57k
  p->y[1][1] = y[8];
3737
1.57k
  p->x[1][2] = x[9];
3738
1.57k
  p->y[1][2] = y[9];
3739
1.57k
  p->x[2][2] = x[10];
3740
1.57k
  p->y[2][2] = y[10];
3741
1.57k
  p->x[2][1] = x[11];
3742
1.57k
  p->y[2][1] = y[11];
3743
7.86k
  for (j = 0; j < nCompsA; ++j) {
3744
6.29k
    p->color[0][0][j] = patchesA[nPatchesA-1].color[1][1][j];
3745
6.29k
    p->color[0][1][j] = patchesA[nPatchesA-1].color[1][0][j];
3746
6.29k
    p->color[1][1][j] = c[0][j];
3747
6.29k
    p->color[1][0][j] = c[1][j];
3748
6.29k
  }
3749
1.57k
  break;
3750
2.14k
      case 3:
3751
2.14k
  p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
3752
2.14k
  p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
3753
2.14k
  p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
3754
2.14k
  p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
3755
2.14k
  p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
3756
2.14k
  p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
3757
2.14k
  p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
3758
2.14k
  p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
3759
2.14k
  p->x[1][3] = x[0];
3760
2.14k
  p->y[1][3] = y[0];
3761
2.14k
  p->x[2][3] = x[1];
3762
2.14k
  p->y[2][3] = y[1];
3763
2.14k
  p->x[3][3] = x[2];
3764
2.14k
  p->y[3][3] = y[2];
3765
2.14k
  p->x[3][2] = x[3];
3766
2.14k
  p->y[3][2] = y[3];
3767
2.14k
  p->x[3][1] = x[4];
3768
2.14k
  p->y[3][1] = y[4];
3769
2.14k
  p->x[3][0] = x[5];
3770
2.14k
  p->y[3][0] = y[5];
3771
2.14k
  p->x[2][0] = x[6];
3772
2.14k
  p->y[2][0] = y[6];
3773
2.14k
  p->x[1][0] = x[7];
3774
2.14k
  p->y[1][0] = y[7];
3775
2.14k
  p->x[1][1] = x[8];
3776
2.14k
  p->y[1][1] = y[8];
3777
2.14k
  p->x[1][2] = x[9];
3778
2.14k
  p->y[1][2] = y[9];
3779
2.14k
  p->x[2][2] = x[10];
3780
2.14k
  p->y[2][2] = y[10];
3781
2.14k
  p->x[2][1] = x[11];
3782
2.14k
  p->y[2][1] = y[11];
3783
10.7k
  for (j = 0; j < nCompsA; ++j) {
3784
8.57k
    p->color[0][0][j] = patchesA[nPatchesA-1].color[1][0][j];
3785
8.57k
    p->color[0][1][j] = patchesA[nPatchesA-1].color[0][0][j];
3786
8.57k
    p->color[1][1][j] = c[0][j];
3787
8.57k
    p->color[1][0][j] = c[1][j];
3788
8.57k
  }
3789
2.14k
  break;
3790
9.80k
      }
3791
9.80k
    }
3792
9.80k
    ++nPatchesA;
3793
9.80k
    bitBuf->flushBits();
3794
9.80k
  }
3795
422
  delete bitBuf;
3796
3797
422
  if (typeA == 6) {
3798
0
    for (i = 0; i < nPatchesA; ++i) {
3799
0
      p = &patchesA[i];
3800
0
      p->x[1][1] = (-4 * p->x[0][0]
3801
0
        +6 * (p->x[0][1] + p->x[1][0])
3802
0
        -2 * (p->x[0][3] + p->x[3][0])
3803
0
        +3 * (p->x[3][1] + p->x[1][3])
3804
0
        - p->x[3][3]) / 9;
3805
0
      p->y[1][1] = (-4 * p->y[0][0]
3806
0
        +6 * (p->y[0][1] + p->y[1][0])
3807
0
        -2 * (p->y[0][3] + p->y[3][0])
3808
0
        +3 * (p->y[3][1] + p->y[1][3])
3809
0
        - p->y[3][3]) / 9;
3810
0
      p->x[1][2] = (-4 * p->x[0][3]
3811
0
        +6 * (p->x[0][2] + p->x[1][3])
3812
0
        -2 * (p->x[0][0] + p->x[3][3])
3813
0
        +3 * (p->x[3][2] + p->x[1][0])
3814
0
        - p->x[3][0]) / 9;
3815
0
      p->y[1][2] = (-4 * p->y[0][3]
3816
0
        +6 * (p->y[0][2] + p->y[1][3])
3817
0
        -2 * (p->y[0][0] + p->y[3][3])
3818
0
        +3 * (p->y[3][2] + p->y[1][0])
3819
0
        - p->y[3][0]) / 9;
3820
0
      p->x[2][1] = (-4 * p->x[3][0]
3821
0
        +6 * (p->x[3][1] + p->x[2][0])
3822
0
        -2 * (p->x[3][3] + p->x[0][0])
3823
0
        +3 * (p->x[0][1] + p->x[2][3])
3824
0
        - p->x[0][3]) / 9;
3825
0
      p->y[2][1] = (-4 * p->y[3][0]
3826
0
        +6 * (p->y[3][1] + p->y[2][0])
3827
0
        -2 * (p->y[3][3] + p->y[0][0])
3828
0
        +3 * (p->y[0][1] + p->y[2][3])
3829
0
        - p->y[0][3]) / 9;
3830
0
      p->x[2][2] = (-4 * p->x[3][3]
3831
0
        +6 * (p->x[3][2] + p->x[2][3])
3832
0
        -2 * (p->x[3][0] + p->x[0][3])
3833
0
        +3 * (p->x[0][2] + p->x[2][0])
3834
0
        - p->x[0][0]) / 9;
3835
0
      p->y[2][2] = (-4 * p->y[3][3]
3836
0
        +6 * (p->y[3][2] + p->y[2][3])
3837
0
        -2 * (p->y[3][0] + p->y[0][3])
3838
0
        +3 * (p->y[0][2] + p->y[2][0])
3839
0
        - p->y[0][0]) / 9;
3840
0
    }
3841
0
  }
3842
3843
422
  shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA,
3844
422
            nCompsA, funcsA, nFuncsA);
3845
422
  if (!shading->init(dict
3846
422
         )) {
3847
2
    delete shading;
3848
2
    return NULL;
3849
2
  }
3850
3851
420
  ok = gFalse;
3852
420
  if (shading->nFuncs == 0) {
3853
420
    ok = shading->nComps == shading->getColorSpace()->getNComps();
3854
420
  } else if (shading->nFuncs == 1) {
3855
0
    ok = shading->funcs[0]->getOutputSize()
3856
0
           == shading->getColorSpace()->getNComps();
3857
0
  } else if (shading->nFuncs == shading->getColorSpace()->getNComps()) {
3858
0
    ok = gTrue;
3859
0
    for (i = 0; i < shading->nFuncs; ++i) {
3860
0
      ok = ok && shading->funcs[i]->getOutputSize() == 1;
3861
0
    }
3862
0
  }
3863
420
  if (!ok) {
3864
0
    error(errSyntaxError, -1, "Invalid function in shading dictionary");
3865
0
    delete shading;
3866
0
    return NULL;
3867
0
  }
3868
3869
420
  return shading;
3870
3871
52
 err2:
3872
52
  obj1.free();
3873
52
 err1:
3874
52
  if (patchesA) {
3875
0
    gfree(patchesA);
3876
0
  }
3877
52
  return NULL;
3878
52
}
3879
3880
0
GfxShading *GfxPatchMeshShading::copy() {
3881
0
  return new GfxPatchMeshShading(this);
3882
0
}
3883
3884
void GfxPatchMeshShading::getBBox(double *xMinA, double *yMinA,
3885
393
          double *xMaxA, double *yMaxA) {
3886
393
  double xxMin = 0;
3887
393
  double yyMin = 0;
3888
393
  double xxMax = 0;
3889
393
  double yyMax = 0;
3890
393
  if (nPatches > 0) {
3891
364
    xxMin = patches[0].x[0][0];
3892
364
    yyMin = patches[0].y[0][0];
3893
364
  }
3894
9.30k
  for (int i = 0; i < nPatches; ++i) {
3895
44.5k
    for (int j = 0; j < 4; ++j) {
3896
178k
      for (int k = 0; k < 4; ++k) {
3897
142k
  if (patches[i].x[j][k] < xxMin) {
3898
1.88k
    xxMin = patches[i].x[j][k];
3899
140k
  } else if (patches[i].x[j][k] > xxMax) {
3900
3.49k
    xxMax = patches[i].x[j][k];
3901
3.49k
  }
3902
142k
  if (patches[i].y[j][k] < yyMin) {
3903
1.98k
    yyMin = patches[i].y[j][k];
3904
140k
  } else if (patches[i].y[j][k] > yyMax) {
3905
723
    yyMax = patches[i].y[j][k];
3906
723
  }
3907
142k
      }
3908
35.6k
    }
3909
8.90k
  }
3910
393
  *xMinA = xxMin;
3911
393
  *yMinA = yyMin;
3912
393
  *xMaxA = xxMax;
3913
393
  *yMaxA = yyMax;
3914
393
}
3915
3916
6.91M
void GfxPatchMeshShading::getColor(double *in, GfxColor *out) {
3917
6.91M
  double c[gfxColorMaxComps];
3918
6.91M
  int i;
3919
3920
6.91M
  if (nFuncs > 0) {
3921
0
    for (i = 0; i < nFuncs; ++i) {
3922
0
      funcs[i]->transform(in, &c[i]);
3923
0
    }
3924
0
    for (i = 0; i < colorSpace->getNComps(); ++i) {
3925
0
      out->c[i] = dblToCol(c[i]);
3926
0
    }
3927
6.91M
  } else {
3928
34.5M
    for (i = 0; i < nComps; ++i) {
3929
27.6M
      out->c[i] = dblToCol(in[i]);
3930
27.6M
    }
3931
6.91M
  }
3932
6.91M
}
3933
3934
//------------------------------------------------------------------------
3935
// GfxImageColorMap
3936
//------------------------------------------------------------------------
3937
3938
GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
3939
           GfxColorSpace *colorSpaceA,
3940
16.6k
           int maxAllowedBits) {
3941
16.6k
  GfxIndexedColorSpace *indexedCS;
3942
16.6k
  GfxSeparationColorSpace *sepCS;
3943
16.6k
  int maxPixel, indexHigh;
3944
16.6k
  Guchar *indexedLookup;
3945
16.6k
  Function *sepFunc;
3946
16.6k
  Object obj;
3947
16.6k
  double defaultLow[gfxColorMaxComps], defaultRange[gfxColorMaxComps];
3948
16.6k
  double x[gfxColorMaxComps], y[gfxColorMaxComps];
3949
16.6k
  int i, j, k;
3950
3951
16.6k
  ok = gTrue;
3952
3953
  // bits per component and color space
3954
16.6k
  bits = bitsA;
3955
16.6k
  if (bits <= maxAllowedBits) {
3956
16.5k
    maxPixel = (1 << bits) - 1;
3957
16.5k
  } else {
3958
134
    maxPixel = (1 << maxAllowedBits) - 1;
3959
134
  }
3960
16.6k
  colorSpace = colorSpaceA;
3961
3962
  // initialize
3963
549k
  for (k = 0; k < gfxColorMaxComps; ++k) {
3964
532k
    lookup[k] = NULL;
3965
532k
    lookup2[k] = NULL;
3966
532k
  }
3967
3968
  // get decode map
3969
16.6k
  colorSpace->getDefaultRanges(defaultLow, defaultRange, maxPixel);
3970
16.6k
  if (decode->isNull()) {
3971
11.0k
    nComps = colorSpace->getNComps();
3972
26.6k
    for (i = 0; i < nComps; ++i) {
3973
15.5k
      decodeLow[i] = defaultLow[i];
3974
15.5k
      decodeRange[i] = defaultRange[i];
3975
15.5k
    }
3976
11.0k
  } else if (decode->isArray()) {
3977
5.02k
    nComps = decode->arrayGetLength() / 2;
3978
5.02k
    if (nComps < colorSpace->getNComps()) {
3979
469
      goto err1;
3980
469
    }
3981
4.55k
    if (nComps > colorSpace->getNComps()) {
3982
157
      error(errSyntaxWarning, -1, "Too many elements in Decode array");
3983
157
      nComps = colorSpace->getNComps();
3984
157
    }
3985
8.36k
    for (i = 0; i < nComps; ++i) {
3986
4.61k
      decode->arrayGet(2*i, &obj);
3987
4.61k
      if (!obj.isNum()) {
3988
193
  goto err2;
3989
193
      }
3990
4.42k
      decodeLow[i] = obj.getNum();
3991
4.42k
      obj.free();
3992
4.42k
      decode->arrayGet(2*i+1, &obj);
3993
4.42k
      if (!obj.isNum()) {
3994
607
  goto err2;
3995
607
      }
3996
3.81k
      decodeRange[i] = obj.getNum() - decodeLow[i];
3997
3.81k
      obj.free();
3998
3.81k
    }
3999
4.55k
  } else {
4000
545
    goto err1;
4001
545
  }
4002
4003
  // Construct a lookup table -- this stores pre-computed decoded
4004
  // values for each component, i.e., the result of applying the
4005
  // decode mapping to each possible image pixel component value.
4006
34.2k
  for (k = 0; k < nComps; ++k) {
4007
19.3k
    lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
4008
19.3k
           sizeof(GfxColorComp));
4009
3.23M
    for (i = 0; i <= maxPixel; ++i) {
4010
3.21M
      double t = decodeLow[k] + (i * decodeRange[k]) / maxPixel;
4011
3.21M
      if (t < defaultLow[k]) {
4012
63
  t = defaultLow[k];
4013
3.21M
      } else if (t > defaultLow[k] + defaultRange[k]) {
4014
1
  t = defaultLow[k] + defaultRange[k];
4015
1
      }
4016
3.21M
      lookup[k][i] = dblToCol(t);
4017
3.21M
    }
4018
19.3k
  }
4019
4020
  // Optimization: for Indexed and Separation color spaces (which have
4021
  // only one component), we pre-compute a second lookup table with
4022
  // color values
4023
14.8k
  colorSpace2 = NULL;
4024
14.8k
  nComps2 = 0;
4025
14.8k
  if (colorSpace->getMode() == csIndexed) {
4026
    // Note that indexHigh may not be the same as maxPixel --
4027
    // Distiller will remove unused palette entries, resulting in
4028
    // indexHigh < maxPixel.
4029
253
    indexedCS = (GfxIndexedColorSpace *)colorSpace;
4030
253
    colorSpace2 = indexedCS->getBase();
4031
253
    indexHigh = indexedCS->getIndexHigh();
4032
253
    nComps2 = colorSpace2->getNComps();
4033
253
    indexedLookup = indexedCS->getLookup();
4034
253
    colorSpace2->getDefaultRanges(x, y, indexHigh);
4035
1.01k
    for (k = 0; k < nComps2; ++k) {
4036
759
      lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
4037
759
              sizeof(GfxColorComp));
4038
759
    }
4039
53.1k
    for (i = 0; i <= maxPixel; ++i) {
4040
52.9k
      j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
4041
52.9k
      if (j < 0) {
4042
0
  j = 0;
4043
52.9k
      } else if (j > indexHigh) {
4044
6.44k
  j = indexHigh;
4045
6.44k
      }
4046
211k
      for (k = 0; k < nComps2; ++k) {
4047
158k
  lookup2[k][i] =
4048
158k
      dblToCol(x[k] + (indexedLookup[j*nComps2 + k] / 255.0) * y[k]);
4049
158k
      }
4050
52.9k
    }
4051
14.5k
  } else if (colorSpace->getMode() == csSeparation) {
4052
29
    sepCS = (GfxSeparationColorSpace *)colorSpace;
4053
29
    colorSpace2 = sepCS->getAlt();
4054
29
    nComps2 = colorSpace2->getNComps();
4055
29
    sepFunc = sepCS->getFunc();
4056
116
    for (k = 0; k < nComps2; ++k) {
4057
87
      lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
4058
87
              sizeof(GfxColorComp));
4059
87
    }
4060
7.45k
    for (i = 0; i <= maxPixel; ++i) {
4061
7.42k
      double t = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
4062
7.42k
      if (t < defaultLow[0]) {
4063
0
  t = defaultLow[0];
4064
7.42k
      } else if (t > defaultLow[0] + defaultRange[0]) {
4065
0
  t = defaultLow[0] + defaultRange[0];
4066
0
      }
4067
7.42k
      x[0] = t;
4068
7.42k
      sepFunc->transform(x, y);
4069
29.6k
      for (k = 0; k < nComps2; ++k) {
4070
22.2k
  lookup2[k][i] = dblToCol(y[k]);
4071
22.2k
      }
4072
7.42k
    }
4073
29
  }
4074
4075
14.8k
  return;
4076
4077
800
 err2:
4078
800
  obj.free();
4079
1.81k
 err1:
4080
1.81k
  ok = gFalse;
4081
1.81k
}
4082
4083
0
GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
4084
0
  int n, i, k;
4085
4086
0
  colorSpace = colorMap->colorSpace->copy();
4087
0
  bits = colorMap->bits;
4088
0
  nComps = colorMap->nComps;
4089
0
  nComps2 = colorMap->nComps2;
4090
0
  colorSpace2 = NULL;
4091
0
  for (k = 0; k < gfxColorMaxComps; ++k) {
4092
0
    lookup[k] = NULL;
4093
0
    lookup2[k] = NULL;
4094
0
  }
4095
0
  if (bits <= 8) {
4096
0
    n = 1 << bits;
4097
0
  } else {
4098
0
    n = 256;
4099
0
  }
4100
0
  for (k = 0; k < nComps; ++k) {
4101
0
    lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
4102
0
    memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
4103
0
  }
4104
0
  if (colorSpace->getMode() == csIndexed) {
4105
0
    colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
4106
0
    for (k = 0; k < nComps2; ++k) {
4107
0
      lookup2[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
4108
0
      memcpy(lookup2[k], colorMap->lookup2[k], n * sizeof(GfxColorComp));
4109
0
    }
4110
0
  } else if (colorSpace->getMode() == csSeparation) {
4111
0
    colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
4112
0
    for (k = 0; k < nComps2; ++k) {
4113
0
      lookup2[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
4114
0
      memcpy(lookup2[k], colorMap->lookup2[k], n * sizeof(GfxColorComp));
4115
0
    }
4116
0
  }
4117
0
  for (i = 0; i < nComps; ++i) {
4118
0
    decodeLow[i] = colorMap->decodeLow[i];
4119
0
    decodeRange[i] = colorMap->decodeRange[i];
4120
0
  }
4121
0
  ok = gTrue;
4122
0
}
4123
4124
16.6k
GfxImageColorMap::~GfxImageColorMap() {
4125
16.6k
  int i;
4126
4127
16.6k
  delete colorSpace;
4128
549k
  for (i = 0; i < gfxColorMaxComps; ++i) {
4129
532k
    gfree(lookup[i]);
4130
532k
    gfree(lookup2[i]);
4131
532k
  }
4132
16.6k
}
4133
4134
void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray,
4135
148k
             GfxRenderingIntent ri) {
4136
148k
  GfxColor color;
4137
148k
  int i;
4138
4139
148k
  if (colorSpace2) {
4140
0
    for (i = 0; i < nComps2; ++i) {
4141
0
      color.c[i] = lookup2[i][x[0]];
4142
0
    }
4143
0
    colorSpace2->getGray(&color, gray, ri);
4144
148k
  } else {
4145
297k
    for (i = 0; i < nComps; ++i) {
4146
148k
      color.c[i] = lookup[i][x[i]];
4147
148k
    }
4148
148k
    colorSpace->getGray(&color, gray, ri);
4149
148k
  }
4150
148k
}
4151
4152
1.39M
void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb, GfxRenderingIntent ri) {
4153
1.39M
  GfxColor color;
4154
1.39M
  int i;
4155
4156
1.39M
  if (colorSpace2) {
4157
241k
    for (i = 0; i < nComps2; ++i) {
4158
180k
      color.c[i] = lookup2[i][x[0]];
4159
180k
    }
4160
60.2k
    colorSpace2->getRGB(&color, rgb, ri);
4161
1.33M
  } else {
4162
2.67M
    for (i = 0; i < nComps; ++i) {
4163
1.33M
      color.c[i] = lookup[i][x[i]];
4164
1.33M
    }
4165
1.33M
    colorSpace->getRGB(&color, rgb, ri);
4166
1.33M
  }
4167
1.39M
}
4168
4169
void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk,
4170
7.42k
             GfxRenderingIntent ri) {
4171
7.42k
  GfxColor color;
4172
7.42k
  int i;
4173
4174
7.42k
  if (colorSpace2) {
4175
0
    for (i = 0; i < nComps2; ++i) {
4176
0
      color.c[i] = lookup2[i][x[0]];
4177
0
    }
4178
0
    colorSpace2->getCMYK(&color, cmyk, ri);
4179
7.42k
  } else {
4180
14.8k
    for (i = 0; i < nComps; ++i) {
4181
7.42k
      color.c[i] = lookup[i][x[i]];
4182
7.42k
    }
4183
7.42k
    colorSpace->getCMYK(&color, cmyk, ri);
4184
7.42k
  }
4185
7.42k
}
4186
4187
4188
0
void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
4189
0
  int i;
4190
4191
0
  for (i = 0; i < nComps; ++i) {
4192
0
    color->c[i] = lookup[i][x[i]];
4193
0
  }
4194
0
}
4195
4196
void GfxImageColorMap::getGrayByteLine(Guchar *in, Guchar *out, int n,
4197
0
               GfxRenderingIntent ri) {
4198
0
  GfxColor color;
4199
0
  GfxGray gray;
4200
0
  int i, j;
4201
4202
0
  if (colorSpace2) {
4203
0
    for (j = 0; j < n; ++j) {
4204
0
      for (i = 0; i < nComps2; ++i) {
4205
0
  color.c[i] = lookup2[i][in[j]];
4206
0
      }
4207
0
      colorSpace2->getGray(&color, &gray, ri);
4208
0
      out[j] = colToByte(gray);
4209
0
    }
4210
0
  } else {
4211
0
    for (j = 0; j < n; ++j) {
4212
0
      for (i = 0; i < nComps; ++i) {
4213
0
  color.c[i] = lookup[i][in[j * nComps + i]];
4214
0
      }
4215
0
      colorSpace->getGray(&color, &gray, ri);
4216
0
      out[j] = colToByte(gray);
4217
0
    }
4218
0
  }
4219
0
}
4220
4221
void GfxImageColorMap::getRGBByteLine(Guchar *in, Guchar *out, int n,
4222
1.49k
              GfxRenderingIntent ri) {
4223
1.49k
  GfxColor color;
4224
1.49k
  GfxRGB rgb;
4225
1.49k
  int i, j;
4226
4227
1.49k
  if (colorSpace2) {
4228
0
    for (j = 0; j < n; ++j) {
4229
0
      for (i = 0; i < nComps2; ++i) {
4230
0
  color.c[i] = lookup2[i][in[j]];
4231
0
      }
4232
0
      colorSpace2->getRGB(&color, &rgb, ri);
4233
0
      out[j*3] = colToByte(rgb.r);
4234
0
      out[j*3 + 1] = colToByte(rgb.g);
4235
0
      out[j*3 + 2] = colToByte(rgb.b);
4236
0
    }
4237
1.49k
  } else {
4238
1.81M
    for (j = 0; j < n; ++j) {
4239
7.25M
      for (i = 0; i < nComps; ++i) {
4240
5.44M
  color.c[i] = lookup[i][in[j * nComps + i]];
4241
5.44M
      }
4242
1.81M
      colorSpace->getRGB(&color, &rgb, ri);
4243
1.81M
      out[j*3] = colToByte(rgb.r);
4244
1.81M
      out[j*3 + 1] = colToByte(rgb.g);
4245
1.81M
      out[j*3 + 2] = colToByte(rgb.b);
4246
1.81M
    }
4247
1.49k
  }
4248
1.49k
}
4249
4250
void GfxImageColorMap::getCMYKByteLine(Guchar *in, Guchar *out, int n,
4251
0
               GfxRenderingIntent ri) {
4252
0
  GfxColor color;
4253
0
  GfxCMYK cmyk;
4254
0
  int i, j;
4255
4256
0
  if (colorSpace2) {
4257
0
    for (j = 0; j < n; ++j) {
4258
0
      for (i = 0; i < nComps2; ++i) {
4259
0
  color.c[i] = lookup2[i][in[j]];
4260
0
      }
4261
0
      colorSpace2->getCMYK(&color, &cmyk, ri);
4262
0
      out[j*4] = colToByte(cmyk.c);
4263
0
      out[j*4 + 1] = colToByte(cmyk.m);
4264
0
      out[j*4 + 2] = colToByte(cmyk.y);
4265
0
      out[j*4 + 3] = colToByte(cmyk.k);
4266
0
    }
4267
0
  } else {
4268
0
    for (j = 0; j < n; ++j) {
4269
0
      for (i = 0; i < nComps; ++i) {
4270
0
  color.c[i] = lookup[i][in[j * nComps + i]];
4271
0
      }
4272
0
      colorSpace->getCMYK(&color, &cmyk, ri);
4273
0
      out[j*4] = colToByte(cmyk.c);
4274
0
      out[j*4 + 1] = colToByte(cmyk.m);
4275
0
      out[j*4 + 2] = colToByte(cmyk.y);
4276
0
      out[j*4 + 3] = colToByte(cmyk.k);
4277
0
    }
4278
0
  }
4279
0
}
4280
4281
4282
//------------------------------------------------------------------------
4283
// GfxSubpath and GfxPath
4284
//------------------------------------------------------------------------
4285
4286
168k
GfxSubpath::GfxSubpath(double x1, double y1) {
4287
168k
  size = 16;
4288
168k
  x = (double *)gmallocn(size, sizeof(double));
4289
168k
  y = (double *)gmallocn(size, sizeof(double));
4290
168k
  curve = (GBool *)gmallocn(size, sizeof(GBool));
4291
168k
  n = 1;
4292
168k
  x[0] = x1;
4293
168k
  y[0] = y1;
4294
168k
  curve[0] = gFalse;
4295
168k
  closed = gFalse;
4296
168k
}
4297
4298
261k
GfxSubpath::~GfxSubpath() {
4299
261k
  gfree(x);
4300
261k
  gfree(y);
4301
261k
  gfree(curve);
4302
261k
}
4303
4304
// Used for copy().
4305
92.5k
GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
4306
92.5k
  size = subpath->size;
4307
92.5k
  n = subpath->n;
4308
92.5k
  x = (double *)gmallocn(size, sizeof(double));
4309
92.5k
  y = (double *)gmallocn(size, sizeof(double));
4310
92.5k
  curve = (GBool *)gmallocn(size, sizeof(GBool));
4311
92.5k
  memcpy(x, subpath->x, n * sizeof(double));
4312
92.5k
  memcpy(y, subpath->y, n * sizeof(double));
4313
92.5k
  memcpy(curve, subpath->curve, n * sizeof(GBool));
4314
92.5k
  closed = subpath->closed;
4315
92.5k
}
4316
4317
629k
void GfxSubpath::lineTo(double x1, double y1) {
4318
629k
  if (n >= size) {
4319
301
    size *= 2;
4320
301
    x = (double *)greallocn(x, size, sizeof(double));
4321
301
    y = (double *)greallocn(y, size, sizeof(double));
4322
301
    curve = (GBool *)greallocn(curve, size, sizeof(GBool));
4323
301
  }
4324
629k
  x[n] = x1;
4325
629k
  y[n] = y1;
4326
629k
  curve[n] = gFalse;
4327
629k
  ++n;
4328
629k
}
4329
4330
void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
4331
31.2k
       double x3, double y3) {
4332
31.2k
  if (n+3 > size) {
4333
2.04k
    size *= 2;
4334
2.04k
    x = (double *)greallocn(x, size, sizeof(double));
4335
2.04k
    y = (double *)greallocn(y, size, sizeof(double));
4336
2.04k
    curve = (GBool *)greallocn(curve, size, sizeof(GBool));
4337
2.04k
  }
4338
31.2k
  x[n] = x1;
4339
31.2k
  y[n] = y1;
4340
31.2k
  x[n+1] = x2;
4341
31.2k
  y[n+1] = y2;
4342
31.2k
  x[n+2] = x3;
4343
31.2k
  y[n+2] = y3;
4344
31.2k
  curve[n] = curve[n+1] = gTrue;
4345
31.2k
  curve[n+2] = gFalse;
4346
31.2k
  n += 3;
4347
31.2k
}
4348
4349
160k
void GfxSubpath::close() {
4350
160k
  if (x[n-1] != x[0] || y[n-1] != y[0]) {
4351
146k
    lineTo(x[0], y[0]);
4352
146k
  }
4353
160k
  closed = gTrue;
4354
160k
}
4355
4356
0
void GfxSubpath::offset(double dx, double dy) {
4357
0
  int i;
4358
4359
0
  for (i = 0; i < n; ++i) {
4360
0
    x[i] += dx;
4361
0
    y[i] += dy;
4362
0
  }
4363
0
}
4364
4365
362k
GfxPath::GfxPath() {
4366
362k
  justMoved = gFalse;
4367
362k
  size = 16;
4368
362k
  n = 0;
4369
362k
  firstX = firstY = 0;
4370
362k
  subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
4371
362k
}
4372
4373
1.91M
GfxPath::~GfxPath() {
4374
1.91M
  int i;
4375
4376
2.17M
  for (i = 0; i < n; ++i)
4377
261k
    delete subpaths[i];
4378
1.91M
  gfree(subpaths);
4379
1.91M
}
4380
4381
// Used for copy().
4382
GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
4383
1.54M
     GfxSubpath **subpaths1, int n1, int size1) {
4384
1.54M
  int i;
4385
4386
1.54M
  justMoved = justMoved1;
4387
1.54M
  firstX = firstX1;
4388
1.54M
  firstY = firstY1;
4389
1.54M
  size = size1;
4390
1.54M
  n = n1;
4391
1.54M
  subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
4392
1.64M
  for (i = 0; i < n; ++i)
4393
92.5k
    subpaths[i] = subpaths1[i]->copy();
4394
1.54M
}
4395
4396
0
double GfxPath::getCurX() {
4397
0
  if (justMoved) {
4398
0
    return firstX;
4399
0
  } else if (n > 0) {
4400
0
    return subpaths[n-1]->getLastX();
4401
0
  } else {
4402
0
    return 0;
4403
0
  }
4404
0
}
4405
4406
0
double GfxPath::getCurY() {
4407
0
  if (justMoved) {
4408
0
    return firstY;
4409
0
  } else if (n > 0) {
4410
0
    return subpaths[n-1]->getLastY();
4411
0
  } else {
4412
0
    return 0;
4413
0
  }
4414
0
}
4415
4416
1.68M
void GfxPath::moveTo(double x, double y) {
4417
1.68M
  justMoved = gTrue;
4418
1.68M
  firstX = x;
4419
1.68M
  firstY = y;
4420
1.68M
}
4421
4422
482k
void GfxPath::lineTo(double x, double y) {
4423
482k
  if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
4424
159k
    if (n >= size) {
4425
121
      size *= 2;
4426
121
      subpaths = (GfxSubpath **)
4427
121
             greallocn(subpaths, size, sizeof(GfxSubpath *));
4428
121
    }
4429
159k
    if (justMoved) {
4430
158k
      subpaths[n] = new GfxSubpath(firstX, firstY);
4431
158k
    } else {
4432
1.06k
      subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
4433
1.06k
           subpaths[n-1]->getLastY());
4434
1.06k
    }
4435
159k
    ++n;
4436
159k
    justMoved = gFalse;
4437
159k
  }
4438
482k
  subpaths[n-1]->lineTo(x, y);
4439
482k
}
4440
4441
void GfxPath::curveTo(double x1, double y1, double x2, double y2,
4442
31.2k
       double x3, double y3) {
4443
31.2k
  if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) {
4444
4.20k
    if (n >= size) {
4445
31
      size *= 2;
4446
31
      subpaths = (GfxSubpath **)
4447
31
             greallocn(subpaths, size, sizeof(GfxSubpath *));
4448
31
    }
4449
4.20k
    if (justMoved) {
4450
3.76k
      subpaths[n] = new GfxSubpath(firstX, firstY);
4451
3.76k
    } else {
4452
439
      subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(),
4453
439
           subpaths[n-1]->getLastY());
4454
439
    }
4455
4.20k
    ++n;
4456
4.20k
    justMoved = gFalse;
4457
4.20k
  }
4458
31.2k
  subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
4459
31.2k
}
4460
4461
160k
void GfxPath::close() {
4462
  // this is necessary to handle the pathological case of
4463
  // moveto/closepath/clip, which defines an empty clipping region
4464
160k
  if (justMoved) {
4465
4.66k
    if (n >= size) {
4466
9
      size *= 2;
4467
9
      subpaths = (GfxSubpath **)
4468
9
             greallocn(subpaths, size, sizeof(GfxSubpath *));
4469
9
    }
4470
4.66k
    subpaths[n] = new GfxSubpath(firstX, firstY);
4471
4.66k
    ++n;
4472
4.66k
    justMoved = gFalse;
4473
4.66k
  }
4474
160k
  subpaths[n-1]->close();
4475
160k
}
4476
4477
0
void GfxPath::append(GfxPath *path) {
4478
0
  int i;
4479
4480
0
  if (n + path->n > size) {
4481
0
    size = n + path->n;
4482
0
    subpaths = (GfxSubpath **)
4483
0
                 greallocn(subpaths, size, sizeof(GfxSubpath *));
4484
0
  }
4485
0
  for (i = 0; i < path->n; ++i) {
4486
0
    subpaths[n++] = path->subpaths[i]->copy();
4487
0
  }
4488
0
  justMoved = gFalse;
4489
0
}
4490
4491
0
void GfxPath::offset(double dx, double dy) {
4492
0
  int i;
4493
4494
0
  for (i = 0; i < n; ++i) {
4495
0
    subpaths[i]->offset(dx, dy);
4496
0
  }
4497
0
}
4498
4499
//------------------------------------------------------------------------
4500
// GfxState
4501
//------------------------------------------------------------------------
4502
4503
GfxState::GfxState(LocalParams *localParamsA,
4504
       double hDPIA, double vDPIA, PDFRectangle *pageBox,
4505
       int rotateA, GBool upsideDown
4506
37.1k
       ) {
4507
37.1k
  double kx, ky;
4508
4509
37.1k
  localParams = localParamsA;
4510
37.1k
  hDPI = hDPIA;
4511
37.1k
  vDPI = vDPIA;
4512
37.1k
  rotate = rotateA;
4513
37.1k
  px1 = pageBox->x1;
4514
37.1k
  py1 = pageBox->y1;
4515
37.1k
  px2 = pageBox->x2;
4516
37.1k
  py2 = pageBox->y2;
4517
37.1k
  kx = hDPI / 72.0;
4518
37.1k
  ky = vDPI / 72.0;
4519
37.1k
  if (rotate == 90) {
4520
0
    ctm[0] = 0;
4521
0
    ctm[1] = upsideDown ? ky : -ky;
4522
0
    ctm[2] = kx;
4523
0
    ctm[3] = 0;
4524
0
    ctm[4] = -kx * py1;
4525
0
    ctm[5] = ky * (upsideDown ? -px1 : px2);
4526
0
    pageWidth = kx * (py2 - py1);
4527
0
    pageHeight = ky * (px2 - px1);
4528
37.1k
  } else if (rotate == 180) {
4529
0
    ctm[0] = -kx;
4530
0
    ctm[1] = 0;
4531
0
    ctm[2] = 0;
4532
0
    ctm[3] = upsideDown ? ky : -ky;
4533
0
    ctm[4] = kx * px2;
4534
0
    ctm[5] = ky * (upsideDown ? -py1 : py2);
4535
0
    pageWidth = kx * (px2 - px1);
4536
0
    pageHeight = ky * (py2 - py1);
4537
37.1k
  } else if (rotate == 270) {
4538
0
    ctm[0] = 0;
4539
0
    ctm[1] = upsideDown ? -ky : ky;
4540
0
    ctm[2] = -kx;
4541
0
    ctm[3] = 0;
4542
0
    ctm[4] = kx * py2;
4543
0
    ctm[5] = ky * (upsideDown ? px2 : -px1);
4544
0
    pageWidth = kx * (py2 - py1);
4545
0
    pageHeight = ky * (px2 - px1);
4546
37.1k
  } else {
4547
37.1k
    ctm[0] = kx;
4548
37.1k
    ctm[1] = 0;
4549
37.1k
    ctm[2] = 0;
4550
37.1k
    ctm[3] = upsideDown ? -ky : ky;
4551
37.1k
    ctm[4] = -kx * px1;
4552
37.1k
    ctm[5] = ky * (upsideDown ? py2 : -py1);
4553
37.1k
    pageWidth = kx * (px2 - px1);
4554
37.1k
    pageHeight = ky * (py2 - py1);
4555
37.1k
  }
4556
4557
37.1k
  fillColorSpace = GfxColorSpace::create(csDeviceGray);
4558
37.1k
  strokeColorSpace = GfxColorSpace::create(csDeviceGray);
4559
37.1k
  fillColor.c[0] = 0;
4560
37.1k
  strokeColor.c[0] = 0;
4561
37.1k
  fillPattern = NULL;
4562
37.1k
  strokePattern = NULL;
4563
37.1k
  blendMode = gfxBlendNormal;
4564
37.1k
  fillOpacity = 1;
4565
37.1k
  strokeOpacity = 1;
4566
37.1k
  fillOverprint = gFalse;
4567
37.1k
  strokeOverprint = gFalse;
4568
37.1k
  if (localParams) {
4569
0
    renderingIntent = localParams->getDefaultRenderingIntent();
4570
37.1k
  } else {
4571
37.1k
    renderingIntent = gfxRenderingIntentRelativeColorimetric;
4572
37.1k
  }
4573
37.1k
  overprintMode = 0;
4574
37.1k
  transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL;
4575
4576
37.1k
  lineWidth = 1;
4577
37.1k
  lineDash = NULL;
4578
37.1k
  lineDashLength = 0;
4579
37.1k
  lineDashStart = 0;
4580
37.1k
  flatness = 1;
4581
37.1k
  lineJoin = 0;
4582
37.1k
  lineCap = 0;
4583
37.1k
  miterLimit = 10;
4584
37.1k
  strokeAdjust = gFalse;
4585
37.1k
  alphaIsShape = gFalse;
4586
4587
37.1k
  font = NULL;
4588
37.1k
  fontSize = 0;
4589
37.1k
  textMat[0] = 1; textMat[1] = 0;
4590
37.1k
  textMat[2] = 0; textMat[3] = 1;
4591
37.1k
  textMat[4] = 0; textMat[5] = 0;
4592
37.1k
  charSpace = 0;
4593
37.1k
  wordSpace = 0;
4594
37.1k
  horizScaling = 1;
4595
37.1k
  leading = 0;
4596
37.1k
  rise = 0;
4597
37.1k
  render = 0;
4598
4599
37.1k
  path = new GfxPath();
4600
37.1k
  curX = curY = 0;
4601
37.1k
  lineX = lineY = 0;
4602
4603
37.1k
  clipXMin = 0;
4604
37.1k
  clipYMin = 0;
4605
37.1k
  clipXMax = pageWidth;
4606
37.1k
  clipYMax = pageHeight;
4607
4608
37.1k
  ignoreColorOps = gFalse;
4609
4610
37.1k
  saved = NULL;
4611
37.1k
}
4612
4613
1.93M
GfxState::~GfxState() {
4614
1.93M
  int i;
4615
4616
1.93M
  if (fillColorSpace) {
4617
1.93M
    delete fillColorSpace;
4618
1.93M
  }
4619
1.93M
  if (strokeColorSpace) {
4620
1.93M
    delete strokeColorSpace;
4621
1.93M
  }
4622
1.93M
  if (fillPattern) {
4623
1.67k
    delete fillPattern;
4624
1.67k
  }
4625
1.93M
  if (strokePattern) {
4626
0
    delete strokePattern;
4627
0
  }
4628
9.66M
  for (i = 0; i < 4; ++i) {
4629
7.73M
    if (transfer[i]) {
4630
273
      delete transfer[i];
4631
273
    }
4632
7.73M
  }
4633
1.93M
  gfree(lineDash);
4634
1.93M
  if (path) {
4635
    // this gets set to NULL by restore()
4636
1.58M
    delete path;
4637
1.58M
  }
4638
1.93M
}
4639
4640
// Used for copy();
4641
1.89M
GfxState::GfxState(GfxState *state, GBool copyPath) {
4642
1.89M
  int i;
4643
4644
1.89M
  memcpy(this, state, sizeof(GfxState));
4645
1.89M
  if (fillColorSpace) {
4646
1.89M
    fillColorSpace = state->fillColorSpace->copy();
4647
1.89M
  }
4648
1.89M
  if (strokeColorSpace) {
4649
1.89M
    strokeColorSpace = state->strokeColorSpace->copy();
4650
1.89M
  }
4651
1.89M
  if (fillPattern) {
4652
1.45k
    fillPattern = state->fillPattern->copy();
4653
1.45k
  }
4654
1.89M
  if (strokePattern) {
4655
0
    strokePattern = state->strokePattern->copy();
4656
0
  }
4657
9.47M
  for (i = 0; i < 4; ++i) {
4658
7.58M
    if (transfer[i]) {
4659
216
      transfer[i] = state->transfer[i]->copy();
4660
216
    }
4661
7.58M
  }
4662
1.89M
  if (lineDashLength > 0) {
4663
1.67k
    lineDash = (double *)gmallocn(lineDashLength, sizeof(double));
4664
1.67k
    memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
4665
1.67k
  }
4666
1.89M
  if (copyPath) {
4667
1.54M
    path = state->path->copy();
4668
1.54M
  }
4669
1.89M
  saved = NULL;
4670
1.89M
}
4671
4672
0
void GfxState::setPath(GfxPath *pathA) {
4673
0
  delete path;
4674
0
  path = pathA;
4675
0
}
4676
4677
void GfxState::getUserClipBBox(double *xMin, double *yMin,
4678
0
             double *xMax, double *yMax) {
4679
0
  double ictm[6];
4680
0
  double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
4681
4682
  // invert the CTM
4683
0
  det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
4684
0
  ictm[0] = ctm[3] * det;
4685
0
  ictm[1] = -ctm[1] * det;
4686
0
  ictm[2] = -ctm[2] * det;
4687
0
  ictm[3] = ctm[0] * det;
4688
0
  ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
4689
0
  ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
4690
4691
  // transform all four corners of the clip bbox; find the min and max
4692
  // x and y values
4693
0
  xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
4694
0
  yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
4695
0
  tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
4696
0
  ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
4697
0
  if (tx < xMin1) {
4698
0
    xMin1 = tx;
4699
0
  } else if (tx > xMax1) {
4700
0
    xMax1 = tx;
4701
0
  }
4702
0
  if (ty < yMin1) {
4703
0
    yMin1 = ty;
4704
0
  } else if (ty > yMax1) {
4705
0
    yMax1 = ty;
4706
0
  }
4707
0
  tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
4708
0
  ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
4709
0
  if (tx < xMin1) {
4710
0
    xMin1 = tx;
4711
0
  } else if (tx > xMax1) {
4712
0
    xMax1 = tx;
4713
0
  }
4714
0
  if (ty < yMin1) {
4715
0
    yMin1 = ty;
4716
0
  } else if (ty > yMax1) {
4717
0
    yMax1 = ty;
4718
0
  }
4719
0
  tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
4720
0
  ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
4721
0
  if (tx < xMin1) {
4722
0
    xMin1 = tx;
4723
0
  } else if (tx > xMax1) {
4724
0
    xMax1 = tx;
4725
0
  }
4726
0
  if (ty < yMin1) {
4727
0
    yMin1 = ty;
4728
0
  } else if (ty > yMax1) {
4729
0
    yMax1 = ty;
4730
0
  }
4731
4732
0
  *xMin = xMin1;
4733
0
  *yMin = yMin1;
4734
0
  *xMax = xMax1;
4735
0
  *yMax = yMax1;
4736
0
}
4737
4738
0
double GfxState::transformWidth(double w) {
4739
0
  double x, y;
4740
4741
0
  x = ctm[0] + ctm[2];
4742
0
  y = ctm[1] + ctm[3];
4743
0
  return w * sqrt(0.5 * (x * x + y * y));
4744
0
}
4745
4746
0
double GfxState::getTransformedFontSize() {
4747
0
  double x1, y1, x2, y2;
4748
4749
0
  x1 = textMat[2] * fontSize;
4750
0
  y1 = textMat[3] * fontSize;
4751
0
  x2 = ctm[0] * x1 + ctm[2] * y1;
4752
0
  y2 = ctm[1] * x1 + ctm[3] * y1;
4753
0
  return sqrt(x2 * x2 + y2 * y2);
4754
0
}
4755
4756
void GfxState::getFontTransMat(double *m11, double *m12,
4757
0
             double *m21, double *m22) {
4758
0
  *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize * horizScaling;
4759
0
  *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize * horizScaling;
4760
0
  *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
4761
0
  *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
4762
0
}
4763
4764
void GfxState::setCTM(double a, double b, double c,
4765
1.47M
          double d, double e, double f) {
4766
1.47M
  int i;
4767
4768
1.47M
  ctm[0] = a;
4769
1.47M
  ctm[1] = b;
4770
1.47M
  ctm[2] = c;
4771
1.47M
  ctm[3] = d;
4772
1.47M
  ctm[4] = e;
4773
1.47M
  ctm[5] = f;
4774
4775
  // avoid FP exceptions on badly messed up PDF files
4776
10.3M
  for (i = 0; i < 6; ++i) {
4777
8.86M
    if (ctm[i] > 1e10) {
4778
1.74M
      ctm[i] = 1e10;
4779
7.11M
    } else if (ctm[i] < -1e10) {
4780
1.31M
      ctm[i] = -1e10;
4781
1.31M
    }
4782
8.86M
  }
4783
1.47M
}
4784
4785
void GfxState::concatCTM(double a, double b, double c,
4786
170k
       double d, double e, double f) {
4787
170k
  double a1 = ctm[0];
4788
170k
  double b1 = ctm[1];
4789
170k
  double c1 = ctm[2];
4790
170k
  double d1 = ctm[3];
4791
170k
  int i;
4792
4793
170k
  ctm[0] = a * a1 + b * c1;
4794
170k
  ctm[1] = a * b1 + b * d1;
4795
170k
  ctm[2] = c * a1 + d * c1;
4796
170k
  ctm[3] = c * b1 + d * d1;
4797
170k
  ctm[4] = e * a1 + f * c1 + ctm[4];
4798
170k
  ctm[5] = e * b1 + f * d1 + ctm[5];
4799
4800
  // avoid FP exceptions on badly messed up PDF files
4801
1.19M
  for (i = 0; i < 6; ++i) {
4802
1.02M
    if (ctm[i] > 1e10) {
4803
132k
      ctm[i] = 1e10;
4804
891k
    } else if (ctm[i] < -1e10) {
4805
263k
      ctm[i] = -1e10;
4806
263k
    }
4807
1.02M
  }
4808
170k
}
4809
4810
1.11k
void GfxState::shiftCTM(double tx, double ty) {
4811
1.11k
  ctm[4] += tx;
4812
1.11k
  ctm[5] += ty;
4813
1.11k
  clipXMin += tx;
4814
1.11k
  clipYMin += ty;
4815
1.11k
  clipXMax += tx;
4816
1.11k
  clipYMax += ty;
4817
1.11k
}
4818
4819
83.0k
void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
4820
83.0k
  if (fillColorSpace) {
4821
83.0k
    delete fillColorSpace;
4822
83.0k
  }
4823
83.0k
  fillColorSpace = colorSpace;
4824
83.0k
}
4825
4826
24.0k
void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
4827
24.0k
  if (strokeColorSpace) {
4828
24.0k
    delete strokeColorSpace;
4829
24.0k
  }
4830
24.0k
  strokeColorSpace = colorSpace;
4831
24.0k
}
4832
4833
94.0k
void GfxState::setFillPattern(GfxPattern *pattern) {
4834
94.0k
  if (fillPattern) {
4835
1.75k
    delete fillPattern;
4836
1.75k
  }
4837
94.0k
  fillPattern = pattern;
4838
94.0k
}
4839
4840
24.6k
void GfxState::setStrokePattern(GfxPattern *pattern) {
4841
24.6k
  if (strokePattern) {
4842
0
    delete strokePattern;
4843
0
  }
4844
24.6k
  strokePattern = pattern;
4845
24.6k
}
4846
4847
2.35k
void GfxState::setRenderingIntent(GfxRenderingIntent ri) {
4848
2.35k
  if (!(localParams && localParams->getForceRenderingIntent())) {
4849
2.35k
    renderingIntent = ri;
4850
2.35k
  }
4851
2.35k
}
4852
4853
550
void GfxState::setTransfer(Function **funcs) {
4854
550
  int i;
4855
4856
2.75k
  for (i = 0; i < 4; ++i) {
4857
2.20k
    if (transfer[i]) {
4858
96
      delete transfer[i];
4859
96
    }
4860
2.20k
    transfer[i] = funcs[i];
4861
2.20k
  }
4862
550
}
4863
4864
5.17k
void GfxState::setLineDash(double *dash, int length, double start) {
4865
5.17k
  if (lineDash)
4866
657
    gfree(lineDash);
4867
5.17k
  lineDash = dash;
4868
5.17k
  lineDashLength = length;
4869
5.17k
  lineDashStart = start;
4870
5.17k
}
4871
4872
325k
void GfxState::clearPath() {
4873
325k
  delete path;
4874
325k
  path = new GfxPath();
4875
325k
}
4876
4877
98.4k
void GfxState::clip() {
4878
98.4k
  double xMin, yMin, xMax, yMax, x, y;
4879
98.4k
  GfxSubpath *subpath;
4880
98.4k
  int i, j;
4881
4882
98.4k
  xMin = xMax = yMin = yMax = 0; // make gcc happy
4883
196k
  for (i = 0; i < path->getNumSubpaths(); ++i) {
4884
98.0k
    subpath = path->getSubpath(i);
4885
587k
    for (j = 0; j < subpath->getNumPoints(); ++j) {
4886
489k
      transform(subpath->getX(j), subpath->getY(j), &x, &y);
4887
489k
      if (i == 0 && j == 0) {
4888
96.3k
  xMin = xMax = x;
4889
96.3k
  yMin = yMax = y;
4890
392k
      } else {
4891
392k
  if (x < xMin) {
4892
53.0k
    xMin = x;
4893
339k
  } else if (x > xMax) {
4894
54.3k
    xMax = x;
4895
54.3k
  }
4896
392k
  if (y < yMin) {
4897
65.7k
    yMin = y;
4898
327k
  } else if (y > yMax) {
4899
23.5k
    yMax = y;
4900
23.5k
  }
4901
392k
      }
4902
489k
    }
4903
98.0k
  }
4904
98.4k
  if (xMin > clipXMin) {
4905
15.1k
    clipXMin = xMin;
4906
15.1k
  }
4907
98.4k
  if (yMin > clipYMin) {
4908
17.0k
    clipYMin = yMin;
4909
17.0k
  }
4910
98.4k
  if (xMax < clipXMax) {
4911
16.5k
    clipXMax = xMax;
4912
16.5k
  }
4913
98.4k
  if (yMax < clipYMax) {
4914
8.85k
    clipYMax = yMax;
4915
8.85k
  }
4916
98.4k
}
4917
4918
0
void GfxState::clipToStrokePath() {
4919
  // We compute the stroke path bbox in user space (line width and
4920
  // miter limt are handled in user space), and then transform the
4921
  // bbox to device space.  This can result in a larger-than-needed
4922
  // bbox if the matrix isn't "square", but that's ok.
4923
  //
4924
  // There are two cases for each point on the path:
4925
  // (1) miter join, under miter limit => compute the miter point
4926
  // (2) all other joins and caps => use the path point +/- 0.5 * line width
4927
0
  double uxMin = 0, uyMin = 0, uxMax = 0, uyMax = 0;
4928
0
  double w = 0.5 * lineWidth;
4929
0
  for (int i = 0; i < path->getNumSubpaths(); ++i) {
4930
0
    GfxSubpath *subpath = path->getSubpath(i);
4931
0
    int nPoints;
4932
0
    if (subpath->isClosed()) {
4933
0
      nPoints = subpath->getNumPoints() - 1;
4934
0
    } else {
4935
0
      nPoints = subpath->getNumPoints();
4936
0
    }
4937
0
    for (int j = 0; j < nPoints; ++j) {
4938
0
      double x1 = subpath->getX(j);
4939
0
      double y1 = subpath->getY(j);
4940
0
      if (i == 0 && j == 0) {
4941
0
  uxMin = uxMax = x1;
4942
0
  uyMin = uyMax = y1;
4943
0
      }
4944
0
      GBool useMiter = gFalse;
4945
0
      if (lineJoin == 0 &&  // miter join
4946
0
    (subpath->isClosed() || (j > 0 && j < subpath->getNumPoints() - 1))) {
4947
0
  double x0, y0, x2, y2;
4948
0
  if (j == 0) {
4949
0
    x0 = subpath->getX(nPoints - 1);
4950
0
    y0 = subpath->getY(nPoints - 1);
4951
0
  } else {
4952
0
    x0 = subpath->getX(j - 1);
4953
0
    y0 = subpath->getY(j - 1);
4954
0
  }
4955
0
  x2 = subpath->getX(j + 1);
4956
0
  y2 = subpath->getY(j + 1);
4957
0
  if ((fabs(x1 - x0) > 0.0001 || fabs(y1 - y0) > 0.0001) &&
4958
0
      (fabs(x2 - x1) > 0.0001 || fabs(y2 - y1) > 0.0001)) {
4959
0
    double d01 = 1 / sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
4960
0
    double ux = (x1 - x0) * d01;
4961
0
    double uy = (y1 - y0) * d01;
4962
0
    double d12 = 1 / sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
4963
0
    double vx = (x2 - x1) * d12;
4964
0
    double vy = (y2 - y1) * d12;
4965
0
    double dot = -ux * vx - uy * vy;
4966
0
    if (dot < 0.9999) {
4967
0
      double miter = sqrt(2 / (1 - dot));
4968
0
      if (miter <= miterLimit) {
4969
0
        double cross = ux * vy - uy * vx;
4970
0
        double m = sqrt(2 / (1 - dot) - 1);
4971
0
        double ax, ay;
4972
0
        if (cross >= 0) {
4973
0
    ax = x1 + w * uy;
4974
0
    ay = y1 - w * ux;
4975
0
        } else {
4976
0
    ax = x1 - w * uy;
4977
0
    ay = y1 + w * ux;
4978
0
        }
4979
0
        double mx = ax + m * w * ux;
4980
0
        double my = ay + m * w * uy;
4981
0
        if (mx < uxMin) {
4982
0
    uxMin = mx;
4983
0
        } else if (mx > uxMax) {
4984
0
    uxMax = mx;
4985
0
        }
4986
0
        if (my < uyMin) {
4987
0
    uyMin = my;
4988
0
        } else if (my > uyMax) {
4989
0
    uyMax = my;
4990
0
        }
4991
0
        useMiter = gTrue;
4992
0
      }
4993
0
    }
4994
0
  }
4995
0
      }
4996
0
      if (!useMiter) {
4997
0
  if (x1 - w < uxMin) {
4998
0
    uxMin = x1 - w;
4999
0
  }
5000
0
  if (x1 + w > uxMax) {
5001
0
    uxMax = x1 + w;
5002
0
  }
5003
0
  if (y1 - w < uyMin) {
5004
0
    uyMin = y1 - w;
5005
0
  }
5006
0
  if (y1 + w > uyMax) {
5007
0
    uyMax = y1 + w;
5008
0
  }
5009
0
      }
5010
0
    }
5011
0
  }
5012
5013
0
  double dxMin, dyMin, dxMax, dyMax, xx, yy;
5014
0
  transform(uxMin, uyMin, &xx, &yy);
5015
0
  dxMin = dxMax = xx;
5016
0
  dyMin = dyMax = yy;
5017
0
  transform(uxMin, uyMax, &xx, &yy);
5018
0
  if (xx < dxMin) {
5019
0
    dxMin = xx;
5020
0
  } else if (xx > dxMax) {
5021
0
    dxMax = xx;
5022
0
  }
5023
0
  if (yy < dyMin) {
5024
0
    dyMin = yy;
5025
0
  } else if (yy > dyMax) {
5026
0
    dyMax = yy;
5027
0
  }
5028
0
  transform(uxMax, uyMin, &xx, &yy);
5029
0
  if (xx < dxMin) {
5030
0
    dxMin = xx;
5031
0
  } else if (xx > dxMax) {
5032
0
    dxMax = xx;
5033
0
  }
5034
0
  if (yy < dyMin) {
5035
0
    dyMin = yy;
5036
0
  } else if (yy > dyMax) {
5037
0
    dyMax = yy;
5038
0
  }
5039
0
  transform(uxMax, uyMax, &xx, &yy);
5040
0
  if (xx < dxMin) {
5041
0
    dxMin = xx;
5042
0
  } else if (xx > dxMax) {
5043
0
    dxMax = xx;
5044
0
  }
5045
0
  if (yy < dyMin) {
5046
0
    dyMin = yy;
5047
0
  } else if (yy > dyMax) {
5048
0
    dyMax = yy;
5049
0
  }
5050
5051
0
  if (dxMin > clipXMin) {
5052
0
    clipXMin = dxMin;
5053
0
  }
5054
0
  if (dyMin > clipYMin) {
5055
0
    clipYMin = dyMin;
5056
0
  }
5057
0
  if (dxMax < clipXMax) {
5058
0
    clipXMax = dxMax;
5059
0
  }
5060
0
  if (dyMax < clipYMax) {
5061
0
    clipYMax = dyMax;
5062
0
  }
5063
0
}
5064
5065
19.7k
void GfxState::clipToRect(double xMin, double yMin, double xMax, double yMax) {
5066
19.7k
  double x, y, xMin1, yMin1, xMax1, yMax1;
5067
5068
19.7k
  transform(xMin, yMin, &x, &y);
5069
19.7k
  xMin1 = xMax1 = x;
5070
19.7k
  yMin1 = yMax1 = y;
5071
19.7k
  transform(xMax, yMin, &x, &y);
5072
19.7k
  if (x < xMin1) {
5073
3.48k
    xMin1 = x;
5074
16.2k
  } else if (x > xMax1) {
5075
44
    xMax1 = x;
5076
44
  }
5077
19.7k
  if (y < yMin1) {
5078
3.21k
    yMin1 = y;
5079
16.5k
  } else if (y > yMax1) {
5080
37
    yMax1 = y;
5081
37
  }
5082
19.7k
  transform(xMax, yMax, &x, &y);
5083
19.7k
  if (x < xMin1) {
5084
109
    xMin1 = x;
5085
19.6k
  } else if (x > xMax1) {
5086
17
    xMax1 = x;
5087
17
  }
5088
19.7k
  if (y < yMin1) {
5089
52
    yMin1 = y;
5090
19.7k
  } else if (y > yMax1) {
5091
485
    yMax1 = y;
5092
485
  }
5093
19.7k
  transform(xMin, yMax, &x, &y);
5094
19.7k
  if (x < xMin1) {
5095
0
    xMin1 = x;
5096
19.7k
  } else if (x > xMax1) {
5097
0
    xMax1 = x;
5098
0
  }
5099
19.7k
  if (y < yMin1) {
5100
0
    yMin1 = y;
5101
19.7k
  } else if (y > yMax1) {
5102
50
    yMax1 = y;
5103
50
  }
5104
5105
19.7k
  if (xMin1 > clipXMin) {
5106
51
    clipXMin = xMin1;
5107
51
  }
5108
19.7k
  if (yMin1 > clipYMin) {
5109
918
    clipYMin = yMin1;
5110
918
  }
5111
19.7k
  if (xMax1 < clipXMax) {
5112
81
    clipXMax = xMax1;
5113
81
  }
5114
19.7k
  if (yMax1 < clipYMax) {
5115
7.98k
    clipYMax = yMax1;
5116
7.98k
  }
5117
19.7k
}
5118
5119
492k
void GfxState::textShift(double tx, double ty) {
5120
492k
  double dx, dy;
5121
5122
492k
  textTransformDelta(tx, ty, &dx, &dy);
5123
492k
  curX += dx;
5124
492k
  curY += dy;
5125
492k
}
5126
5127
3.43M
void GfxState::shift(double dx, double dy) {
5128
3.43M
  curX += dx;
5129
3.43M
  curY += dy;
5130
3.43M
}
5131
5132
346k
GfxState *GfxState::save() {
5133
346k
  GfxState *newState;
5134
5135
346k
  newState = copy();
5136
346k
  newState->saved = this;
5137
346k
  return newState;
5138
346k
}
5139
5140
392k
GfxState *GfxState::restore() {
5141
392k
  GfxState *oldState;
5142
5143
392k
  if (saved) {
5144
346k
    oldState = saved;
5145
5146
    // these attributes aren't saved/restored by the q/Q operators
5147
346k
    oldState->path = path;
5148
346k
    oldState->curX = curX;
5149
346k
    oldState->curY = curY;
5150
346k
    oldState->lineX = lineX;
5151
346k
    oldState->lineY = lineY;
5152
5153
346k
    path = NULL;
5154
346k
    saved = NULL;
5155
346k
    delete this;
5156
5157
346k
  } else {
5158
45.5k
    oldState = this;
5159
45.5k
  }
5160
5161
392k
  return oldState;
5162
392k
}
5163
5164
2.68k
GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) {
5165
2.68k
  Object obj2;
5166
2.68k
  int i, j;
5167
5168
2.68k
  if (obj->isName()) {
5169
13.8k
    for (i = 0; i < nGfxBlendModeNames; ++i) {
5170
13.5k
      if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) {
5171
2.10k
  *mode = gfxBlendModeNames[i].mode;
5172
2.10k
  return gTrue;
5173
2.10k
      }
5174
13.5k
    }
5175
329
    return gFalse;
5176
2.43k
  } else if (obj->isArray()) {
5177
0
    for (i = 0; i < obj->arrayGetLength(); ++i) {
5178
0
      obj->arrayGet(i, &obj2);
5179
0
      if (!obj2.isName()) {
5180
0
  obj2.free();
5181
0
  return gFalse;
5182
0
      }
5183
0
      for (j = 0; j < nGfxBlendModeNames; ++j) {
5184
0
  if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) {
5185
0
    obj2.free();
5186
0
    *mode = gfxBlendModeNames[j].mode;
5187
0
    return gTrue;
5188
0
  }
5189
0
      }
5190
0
      obj2.free();
5191
0
    }
5192
0
    *mode = gfxBlendNormal;
5193
0
    return gTrue;
5194
253
  } else {
5195
253
    return gFalse;
5196
253
  }
5197
2.68k
}